diff options
Diffstat (limited to 'drivers/net/wireless')
417 files changed, 15112 insertions, 60730 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7555af5195..c6599594dc 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -22,7 +22,6 @@ source "drivers/net/wireless/admtek/Kconfig" source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/atmel/Kconfig" source "drivers/net/wireless/broadcom/Kconfig" -source "drivers/net/wireless/cisco/Kconfig" source "drivers/net/wireless/intel/Kconfig" source "drivers/net/wireless/intersil/Kconfig" source "drivers/net/wireless/marvell/Kconfig" @@ -38,8 +37,6 @@ source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/zydas/Kconfig" source "drivers/net/wireless/quantenna/Kconfig" -source "drivers/net/wireless/legacy/Kconfig" - source "drivers/net/wireless/virtual/Kconfig" endif # WLAN diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 4d7374d567..e1c4141c60 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_WLAN_VENDOR_ADMTEK) += admtek/ obj-$(CONFIG_WLAN_VENDOR_ATH) += ath/ obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/ obj-$(CONFIG_WLAN_VENDOR_BROADCOM) += broadcom/ -obj-$(CONFIG_WLAN_VENDOR_CISCO) += cisco/ obj-$(CONFIG_WLAN_VENDOR_INTEL) += intel/ obj-$(CONFIG_WLAN_VENDOR_INTERSIL) += intersil/ obj-$(CONFIG_WLAN_VENDOR_MARVELL) += marvell/ @@ -23,5 +22,4 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/ obj-$(CONFIG_WLAN_VENDOR_TI) += ti/ obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/ -obj-$(CONFIG_WLAN) += legacy/ obj-$(CONFIG_WLAN) += virtual/ diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 43e0db78d4..a742cec44e 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1803,5 +1803,6 @@ static struct usb_driver ar5523_driver = { module_usb_driver(ar5523_driver); +MODULE_DESCRIPTION("Atheros AR5523 wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_FIRMWARE(AR5523_FIRMWARE_FILE); diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index af6546572d..9a4f8e8154 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2014,2016-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "bmi.h" diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index c27b820471..afae4a8027 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "hif.h" diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 6cdb225b7e..0032f8aa89 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/module.h> @@ -100,6 +101,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA988X_HW_2_0_VERSION, @@ -140,6 +142,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9887_HW_1_0_VERSION, @@ -181,6 +184,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -217,6 +221,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -257,6 +262,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -297,6 +303,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA6174_HW_3_0_VERSION, @@ -337,6 +344,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -381,6 +389,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = true, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -427,6 +436,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -480,6 +490,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -530,6 +541,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -570,6 +582,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -612,6 +625,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -645,6 +659,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -692,6 +707,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = false, .use_fw_tx_credits = true, .delay_unmap_buffer = false, + .mcast_frame_registration = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -725,6 +741,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_restart_disconnect = true, .use_fw_tx_credits = false, .delay_unmap_buffer = true, + .mcast_frame_registration = false, }, }; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 4b5239de40..c110d15528 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CORE_H_ @@ -607,7 +608,7 @@ struct ath10k_vif { u8 tim_bitmap[64]; u8 tim_len; u32 ssid_len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN] __nonstring; bool hidden_ssid; /* P2P_IE with NoA attribute for P2P_GO case */ u32 noa_len; diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index 2d1634a890..bb3a276b7e 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "coredump.h" diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index 437b9759f0..e5ef0352e3 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _COREDUMP_H_ diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index ad9cf953a2..b93a64bf81 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/module.h> diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 87a3365330..394bf3c32a 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 5bfeecb95f..a6e21ce90b 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 0d180faf3b..7ff6650200 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -246,26 +246,12 @@ struct ath10k_htc_lookahead_bundle { struct ath10k_htc_record { struct ath10k_ath10k_htc_record_hdr hdr; union { - struct ath10k_htc_credit_report credit_report[0]; - struct ath10k_htc_lookahead_report lookahead_report[0]; - struct ath10k_htc_lookahead_bundle lookahead_bundle[0]; - u8 pauload[0]; + DECLARE_FLEX_ARRAY(struct ath10k_htc_credit_report, credit_report); + DECLARE_FLEX_ARRAY(struct ath10k_htc_lookahead_report, lookahead_report); + DECLARE_FLEX_ARRAY(struct ath10k_htc_lookahead_bundle, lookahead_bundle); }; } __packed __aligned(4); -/* - * note: the trailer offset is dynamic depending - * on payload length. this is only a struct layout draft - */ -struct ath10k_htc_frame { - struct ath10k_htc_hdr hdr; - union { - struct ath10k_htc_msg msg; - u8 payload[0]; - }; - struct ath10k_htc_record trailer[0]; -} __packed __aligned(4); - /*******************/ /* Host-side stuff */ /*******************/ diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index c80470e888..4a9270e2a4 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _HTT_H_ diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index b261d6371c..7d28ae5453 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" @@ -1294,7 +1295,7 @@ static void ath10k_htt_rx_h_ppdu(struct ath10k *ar, status->encoding = RX_ENC_LEGACY; status->bw = RATE_INFO_BW_20; - status->flag &= ~RX_FLAG_MACTIME_END; + status->flag &= ~RX_FLAG_MACTIME; status->flag |= RX_FLAG_NO_SIGNAL_VAL; status->flag &= ~(RX_FLAG_AMPDU_IS_LAST); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index be4d4536aa..9725feecef 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/etherdevice.h> @@ -40,7 +41,6 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_sta *arsta; struct ath10k_vif *arvif = (void *)txq->vif->drv_priv; - unsigned long frame_cnt; unsigned long byte_cnt; int idx; u32 bit; @@ -67,7 +67,7 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw, bit = BIT(peer_id % 32); idx = peer_id / 32; - ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt); + ieee80211_txq_get_depth(txq, NULL, &byte_cnt); count = ath10k_htt_tx_txq_calc_size(byte_cnt); if (unlikely(peer_id >= ar->htt.tx_q_state.num_peers) || diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 6d32b43a4d..8fafe096ad 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/types.h> diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 9643031a44..93c0730919 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _HW_H_ @@ -639,6 +640,9 @@ struct ath10k_hw_params { bool use_fw_tx_credits; bool delay_unmap_buffer; + + /* The hardware support multicast frame registrations */ + bool mcast_frame_registration; }; struct htt_resp; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2cf693f3fe..090bcf148d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "mac.h" @@ -1242,7 +1243,7 @@ static bool ath10k_mac_monitor_vdev_is_needed(struct ath10k *ar) return ar->monitor || (!test_bit(ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST, ar->running_fw->fw_file.fw_features) && - (ar->filter_flags & FIF_OTHER_BSS)) || + (ar->filter_flags & (FIF_OTHER_BSS | FIF_MCAST_ACTION))) || test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); } @@ -6025,10 +6026,15 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; int ret; + unsigned int supported = SUPPORTED_FILTERS; mutex_lock(&ar->conf_mutex); - *total_flags &= SUPPORTED_FILTERS; + if (ar->hw_params.mcast_frame_registration) + supported |= FIF_MCAST_ACTION; + + *total_flags &= supported; + ar->filter_flags = *total_flags; ret = ath10k_monitor_recalc(ar); @@ -6121,9 +6127,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, if (ieee80211_vif_is_mesh(vif)) { /* mesh doesn't use SSID but firmware needs it */ - strncpy(arvif->u.ap.ssid, "mesh", - sizeof(arvif->u.ap.ssid)); arvif->u.ap.ssid_len = 4; + memcpy(arvif->u.ap.ssid, "mesh", arvif->u.ap.ssid_len); } } @@ -10118,6 +10123,10 @@ int ath10k_mac_register(struct ath10k *ar) NL80211_EXT_FEATURE_SET_SCAN_DWELL); wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_AQL); + if (ar->hw_params.mcast_frame_registration) + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); + if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map) || test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, ar->wmi.svc_map)) wiphy_ext_feature_set(ar->hw->wiphy, diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 2f8c785277..3de2de6d44 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/pci.h> diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 480cd97ab7..27bb4cf2df 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _PCI_H_ diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 52c1a3de8d..38e939f572 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ISC /* * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/completion.h> diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c index 1c81e454f9..0e85c75d22 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ISC /* * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/soc/qcom/qmi.h> diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h index f0db991408..9f311f3bc9 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef WCN3990_QMI_SVC_V01_H diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 777e53aa69..564293df1e 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _RX_DESC_H_ diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 56fbcfb80b..0ab5433f6c 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -3,6 +3,7 @@ * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011-2012,2017 Qualcomm Atheros, Inc. * Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com> + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/module.h> diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index cefd97323d..31c8d7fbb0 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/device.h> diff --git a/drivers/net/wireless/ath/ath10k/usb.h b/drivers/net/wireless/ath/ath10k/usb.h index 48e066ba81..7e4cfbb673 100644 --- a/drivers/net/wireless/ath/ath10k/usb.h +++ b/drivers/net/wireless/ath/ath10k/usb.h @@ -3,6 +3,7 @@ * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com> + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _USB_H_ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index dbb48d70f2..83a8f07a68 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _WMI_TLV_H #define _WMI_TLV_H diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 05fa7d4c0e..88befe92f9 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/skbuff.h> diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b112e88260..9146df98fc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _WMI_H_ diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index 20b9aa8ddf..aa7b2e703f 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2015-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "mac.h" diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig index ad5cc6cac0..27f0523bf9 100644 --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -2,7 +2,7 @@ config ATH11K tristate "Qualcomm Technologies 802.11ax chipset support" depends on MAC80211 && HAS_DMA - depends on CRYPTO_MICHAEL_MIC + select CRYPTO_MICHAEL_MIC select ATH_COMMON select QCOM_QMI_HELPERS help diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index f8f5e653cd..7c0a235179 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -1251,7 +1251,7 @@ static void ath11k_ahb_free_resources(struct ath11k_base *ab) platform_set_drvdata(pdev, NULL); } -static int ath11k_ahb_remove(struct platform_device *pdev) +static void ath11k_ahb_remove(struct platform_device *pdev) { struct ath11k_base *ab = platform_get_drvdata(pdev); @@ -1267,8 +1267,6 @@ static int ath11k_ahb_remove(struct platform_device *pdev) qmi_fail: ath11k_ahb_free_resources(ab); - - return 0; } static void ath11k_ahb_shutdown(struct platform_device *pdev) @@ -1296,7 +1294,7 @@ static struct platform_driver ath11k_ahb_driver = { .of_match_table = ath11k_ahb_of_match, }, .probe = ath11k_ahb_probe, - .remove = ath11k_ahb_remove, + .remove_new = ath11k_ahb_remove, .shutdown = ath11k_ahb_shutdown, }; diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 289d47ae92..e66e86bdec 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "dp_rx.h" diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index c0f6a0ba86..69946fc700 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_CE_H diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 667d55e261..cd829ec70d 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -595,7 +595,6 @@ struct ath11k { struct ath11k_base *ab; struct ath11k_pdev *pdev; struct ieee80211_hw *hw; - struct ieee80211_ops *ops; struct ath11k_pdev_wmi *wmi; struct ath11k_pdev_dp dp; u8 mac_addr[ETH_ALEN]; @@ -919,6 +918,7 @@ struct ath11k_base { * This may or may not be used during the runtime */ struct ieee80211_regdomain *new_regd[MAX_RADIOS]; + struct cur_regulatory_info *reg_info_store; /* Current DFS Regulatory */ enum ath11k_dfs_region dfs_region; diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c index 5536e86423..fbb6e8d8a4 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.c +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/dbring.h b/drivers/net/wireless/ath/ath11k/dbring.h index ef906c687b..2f93b78a50 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.h +++ b/drivers/net/wireless/ath/ath11k/dbring.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_DBRING_H diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c index f5c8a34c88..2b8544355f 100644 --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/vmalloc.h> diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index 9c52804ef8..cc8934d156 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_DEBUG_H_ diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index 0796f4d92b..a48e737ef3 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/vmalloc.h> diff --git a/drivers/net/wireless/ath/ath11k/debugfs.h b/drivers/net/wireless/ath/ath11k/debugfs.h index 6f630b42e9..a39e458637 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.h +++ b/drivers/net/wireless/ath/ath11k/debugfs.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_DEBUGFS_H_ diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c index 0207fc4910..870e86a31b 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/vmalloc.h> diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h index 96219301f0..476689bbd4 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef DEBUG_HTT_STATS_H diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c index 8c177fba6f..f56a24b6c8 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/vmalloc.h> diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.h b/drivers/net/wireless/ath/ath11k/debugfs_sta.h index e6c11b3a40..ace877e192 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.h +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_DEBUGFS_STA_H_ diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index a7252b5255..8975dc57ad 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <crypto/hash.h> diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index 15815af453..2f6dd69d3b 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_DP_H diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 7eac93ce7a..afd481f585 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/ieee80211.h> diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index a5fa08bc62..c1072e66e3 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.h b/drivers/net/wireless/ath/ath11k/dp_tx.h index 68a21ea9b9..61be2265e0 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.h +++ b/drivers/net/wireless/ath/ath11k/dp_tx.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_DP_TX_H diff --git a/drivers/net/wireless/ath/ath11k/fw.c b/drivers/net/wireless/ath/ath11k/fw.c index 8f84fba298..4e36292a79 100644 --- a/drivers/net/wireless/ath/ath11k/fw.c +++ b/drivers/net/wireless/ath/ath11k/fw.c @@ -133,7 +133,7 @@ static int ath11k_fw_request_firmware_api_n(struct ath11k_base *ab, len -= ie_len; data += ie_len; - }; + } return 0; diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 23f3af8e37..c060c4b5c0 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/dma-mapping.h> #include "hal_tx.h" diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 1942d41d6d..80447f4889 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HAL_H diff --git a/drivers/net/wireless/ath/ath11k/hal_desc.h b/drivers/net/wireless/ath/ath11k/hal_desc.h index d895ea878d..b2fd180bd2 100644 --- a/drivers/net/wireless/ath/ath11k/hal_desc.h +++ b/drivers/net/wireless/ath/ath11k/hal_desc.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c index 41946795d6..e758ee8e17 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.c +++ b/drivers/net/wireless/ath/ath11k/hal_rx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "debug.h" diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.h b/drivers/net/wireless/ath/ath11k/hal_rx.h index 472a52cf58..0fa9aef9d5 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.h +++ b/drivers/net/wireless/ath/ath11k/hal_rx.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HAL_RX_H diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h index d68ed4214d..877a4073fe 100644 --- a/drivers/net/wireless/ath/ath11k/hif.h +++ b/drivers/net/wireless/ath/ath11k/hif.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _HIF_H_ diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index 2c2e425c86..23054ab29a 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/skbuff.h> #include <linux/ctype.h> diff --git a/drivers/net/wireless/ath/ath11k/htc.h b/drivers/net/wireless/ath/ath11k/htc.h index d31e501c80..86f77eacae 100644 --- a/drivers/net/wireless/ath/ath11k/htc.h +++ b/drivers/net/wireless/ath/ath11k/htc.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HTC_H @@ -150,10 +151,7 @@ struct ath11k_htc_credit_report { struct ath11k_htc_record { struct ath11k_htc_record_hdr hdr; - union { - struct ath11k_htc_credit_report credit_report[0]; - u8 pauload[0]; - }; + struct ath11k_htc_credit_report credit_report[]; } __packed __aligned(4); enum ath11k_htc_svc_gid { diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index d7b5ec6e69..77d8f92376 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/types.h> diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index d51a99669d..1b070747a5 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HW_H diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 1c4613b1bd..cc80310088 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -4659,6 +4659,14 @@ static int ath11k_station_disassoc(struct ath11k *ar, return 0; } +static u32 ath11k_mac_max_nss(const u8 *ht_mcs_mask, const u16 *vht_mcs_mask, + const u16 *he_mcs_mask) +{ + return max3(ath11k_mac_max_ht_nss(ht_mcs_mask), + ath11k_mac_max_vht_nss(vht_mcs_mask), + ath11k_mac_max_he_nss(he_mcs_mask)); +} + static void ath11k_sta_rc_update_wk(struct work_struct *wk) { struct ath11k *ar; @@ -4704,9 +4712,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) mutex_lock(&ar->conf_mutex); nss = max_t(u32, 1, nss); - nss = min(nss, max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), - ath11k_mac_max_vht_nss(vht_mcs_mask)), - ath11k_mac_max_he_nss(he_mcs_mask))); + nss = min(nss, ath11k_mac_max_nss(ht_mcs_mask, vht_mcs_mask, he_mcs_mask)); if (changed & IEEE80211_RC_BW_CHANGED) { /* Get the peer phymode */ @@ -8385,9 +8391,7 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, ath11k_warn(ar->ab, "could not update fixed rate settings to all peers due to mcs/nss incompatibility\n"); nss = min_t(u32, ar->num_tx_chains, - max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), - ath11k_mac_max_vht_nss(vht_mcs_mask)), - ath11k_mac_max_he_nss(he_mcs_mask))); + ath11k_mac_max_nss(ht_mcs_mask, vht_mcs_mask, he_mcs_mask)); /* If multiple rates across different preambles are given * we can reconfigure this info with all peers using PEER_ASSOC diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h index 0231783ad7..0dfdeed517 100644 --- a/drivers/net/wireless/ath/ath11k/mac.h +++ b/drivers/net/wireless/ath/ath11k/mac.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_MAC_H diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index afeabd6ecc..3375902364 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/msi.h> @@ -106,7 +106,7 @@ static struct mhi_controller_config ath11k_mhi_config_qca6390 = { .max_channels = 128, .timeout_ms = 2000, .use_bounce_buf = false, - .buf_len = 0, + .buf_len = 8192, .num_channels = ARRAY_SIZE(ath11k_mhi_channels_qca6390), .ch_cfg = ath11k_mhi_channels_qca6390, .num_events = ARRAY_SIZE(ath11k_mhi_events_qca6390), diff --git a/drivers/net/wireless/ath/ath11k/mhi.h b/drivers/net/wireless/ath/ath11k/mhi.h index 8d9f852da6..f81fba2644 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.h +++ b/drivers/net/wireless/ath/ath11k/mhi.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_MHI_H #define _ATH11K_MHI_H diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index e602d41301..15e2ceb22a 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c index 1c79a932d1..6d0126c393 100644 --- a/drivers/net/wireless/ath/ath11k/peer.c +++ b/drivers/net/wireless/ath/ath11k/peer.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h index 9bd385d0a3..3ad2f3355b 100644 --- a/drivers/net/wireless/ath/ath11k/peer.h +++ b/drivers/net/wireless/ath/ath11k/peer.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_PEER_H diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index c270dc46d5..2c7cab62b9 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/elf.h> diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index d477e2be81..7e06d100af 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_QMI_H diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 3c7debae80..d4fd3509e6 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/rtnetlink.h> @@ -617,25 +618,68 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, *rule_idx = i; } +enum wmi_reg_6ghz_ap_type +ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type) +{ + switch (power_type) { + case IEEE80211_REG_LPI_AP: + return WMI_REG_INDOOR_AP; + case IEEE80211_REG_SP_AP: + return WMI_REG_STANDARD_POWER_AP; + case IEEE80211_REG_VLP_AP: + return WMI_REG_VERY_LOW_POWER_AP; + default: + return WMI_REG_MAX_AP_TYPE; + } +} + struct ieee80211_regdomain * ath11k_reg_build_regd(struct ath11k_base *ab, - struct cur_regulatory_info *reg_info, bool intersect) + struct cur_regulatory_info *reg_info, bool intersect, + enum wmi_vdev_type vdev_type, + enum ieee80211_ap_reg_power power_type) { struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL; - struct cur_reg_rule *reg_rule; + struct cur_reg_rule *reg_rule, *reg_rule_6ghz; u8 i = 0, j = 0, k = 0; u8 num_rules; u16 max_bw; - u32 flags; + u32 flags, reg_6ghz_number, max_bw_6ghz; char alpha2[3]; num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules; - /* FIXME: Currently taking reg rules for 6 GHz only from Indoor AP mode list. - * This can be updated after complete 6 GHz regulatory support is added. - */ - if (reg_info->is_ext_reg_event) - num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP]; + if (reg_info->is_ext_reg_event) { + if (vdev_type == WMI_VDEV_TYPE_STA) { + enum wmi_reg_6ghz_ap_type ap_type; + + ap_type = ath11k_reg_ap_pwr_convert(power_type); + + if (ap_type == WMI_REG_MAX_AP_TYPE) + ap_type = WMI_REG_INDOOR_AP; + + reg_6ghz_number = reg_info->num_6ghz_rules_client + [ap_type][WMI_REG_DEFAULT_CLIENT]; + + if (reg_6ghz_number == 0) { + ap_type = WMI_REG_INDOOR_AP; + reg_6ghz_number = reg_info->num_6ghz_rules_client + [ap_type][WMI_REG_DEFAULT_CLIENT]; + } + + reg_rule_6ghz = reg_info->reg_rules_6ghz_client_ptr + [ap_type][WMI_REG_DEFAULT_CLIENT]; + max_bw_6ghz = reg_info->max_bw_6ghz_client + [ap_type][WMI_REG_DEFAULT_CLIENT]; + } else { + reg_6ghz_number = reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP]; + reg_rule_6ghz = + reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP]; + max_bw_6ghz = reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]; + } + + num_rules += reg_6ghz_number; + } if (!num_rules) goto ret; @@ -682,13 +726,10 @@ ath11k_reg_build_regd(struct ath11k_base *ab, * per other BW rule flags we pass from here */ flags = NL80211_RRF_AUTO_BW; - } else if (reg_info->is_ext_reg_event && - reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] && - (k < reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP])) { - reg_rule = reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP] + - k++; - max_bw = min_t(u16, reg_rule->max_bw, - reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]); + } else if (reg_info->is_ext_reg_event && reg_6ghz_number && + k < reg_6ghz_number) { + reg_rule = reg_rule_6ghz + k++; + max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz); flags = NL80211_RRF_AUTO_BW; } else { break; @@ -757,6 +798,159 @@ ret: return new_regd; } +static bool ath11k_reg_is_world_alpha(char *alpha) +{ + if (alpha[0] == '0' && alpha[1] == '0') + return true; + + if (alpha[0] == 'n' && alpha[1] == 'a') + return true; + + return false; +} + +static enum wmi_vdev_type ath11k_reg_get_ar_vdev_type(struct ath11k *ar) +{ + struct ath11k_vif *arvif; + + /* Currently each struct ath11k maps to one struct ieee80211_hw/wiphy + * and one struct ieee80211_regdomain, so it could only store one group + * reg rules. It means multi-interface concurrency in the same ath11k is + * not support for the regdomain. So get the vdev type of the first entry + * now. After concurrency support for the regdomain, this should change. + */ + arvif = list_first_entry_or_null(&ar->arvifs, struct ath11k_vif, list); + if (arvif) + return arvif->vdev_type; + + return WMI_VDEV_TYPE_UNSPEC; +} + +int ath11k_reg_handle_chan_list(struct ath11k_base *ab, + struct cur_regulatory_info *reg_info, + enum ieee80211_ap_reg_power power_type) +{ + struct ieee80211_regdomain *regd; + bool intersect = false; + int pdev_idx; + struct ath11k *ar; + enum wmi_vdev_type vdev_type; + + ath11k_dbg(ab, ATH11K_DBG_WMI, "event reg handle chan list"); + + if (reg_info->status_code != REG_SET_CC_STATUS_PASS) { + /* In case of failure to set the requested ctry, + * fw retains the current regd. We print a failure info + * and return from here. + */ + ath11k_warn(ab, "Failed to set the requested Country regulatory setting\n"); + return -EINVAL; + } + + pdev_idx = reg_info->phy_id; + + /* Avoid default reg rule updates sent during FW recovery if + * it is already available + */ + spin_lock_bh(&ab->base_lock); + if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) && + ab->default_regd[pdev_idx]) { + spin_unlock_bh(&ab->base_lock); + goto retfail; + } + spin_unlock_bh(&ab->base_lock); + + if (pdev_idx >= ab->num_radios) { + /* Process the event for phy0 only if single_pdev_only + * is true. If pdev_idx is valid but not 0, discard the + * event. Otherwise, it goes to fallback. In either case + * ath11k_reg_reset_info() needs to be called to avoid + * memory leak issue. + */ + ath11k_reg_reset_info(reg_info); + + if (ab->hw_params.single_pdev_only && + pdev_idx < ab->hw_params.num_rxmda_per_pdev) + return 0; + goto fallback; + } + + /* Avoid multiple overwrites to default regd, during core + * stop-start after mac registration. + */ + if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && + !memcmp((char *)ab->default_regd[pdev_idx]->alpha2, + (char *)reg_info->alpha2, 2)) + goto retfail; + + /* Intersect new rules with default regd if a new country setting was + * requested, i.e a default regd was already set during initialization + * and the regd coming from this event has a valid country info. + */ + if (ab->default_regd[pdev_idx] && + !ath11k_reg_is_world_alpha((char *) + ab->default_regd[pdev_idx]->alpha2) && + !ath11k_reg_is_world_alpha((char *)reg_info->alpha2)) + intersect = true; + + ar = ab->pdevs[pdev_idx].ar; + vdev_type = ath11k_reg_get_ar_vdev_type(ar); + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "wmi handle chan list power type %d vdev type %d intersect %d\n", + power_type, vdev_type, intersect); + + regd = ath11k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type); + if (!regd) { + ath11k_warn(ab, "failed to build regd from reg_info\n"); + goto fallback; + } + + if (power_type == IEEE80211_REG_UNSET_AP) { + ath11k_reg_reset_info(&ab->reg_info_store[pdev_idx]); + ab->reg_info_store[pdev_idx] = *reg_info; + } + + spin_lock_bh(&ab->base_lock); + if (ab->default_regd[pdev_idx]) { + /* The initial rules from FW after WMI Init is to build + * the default regd. From then on, any rules updated for + * the pdev could be due to user reg changes. + * Free previously built regd before assigning the newly + * generated regd to ar. NULL pointer handling will be + * taken care by kfree itself. + */ + ar = ab->pdevs[pdev_idx].ar; + kfree(ab->new_regd[pdev_idx]); + ab->new_regd[pdev_idx] = regd; + queue_work(ab->workqueue, &ar->regd_update_work); + } else { + /* This regd would be applied during mac registration and is + * held constant throughout for regd intersection purpose + */ + ab->default_regd[pdev_idx] = regd; + } + ab->dfs_region = reg_info->dfs_region; + spin_unlock_bh(&ab->base_lock); + + return 0; + +fallback: + /* Fallback to older reg (by sending previous country setting + * again if fw has succeeded and we failed to process here. + * The Regdomain should be uniform across driver and fw. Since the + * FW has processed the command and sent a success status, we expect + * this function to succeed as well. If it doesn't, CTRY needs to be + * reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent. + */ + /* TODO: This is rare, but still should also be handled */ + WARN_ON(1); + +retfail: + + return -EINVAL; +} + void ath11k_regd_update_work(struct work_struct *work) { struct ath11k *ar = container_of(work, struct ath11k, @@ -780,10 +974,36 @@ void ath11k_reg_init(struct ath11k *ar) ar->hw->wiphy->reg_notifier = ath11k_reg_notifier; } +void ath11k_reg_reset_info(struct cur_regulatory_info *reg_info) +{ + int i, j; + + if (!reg_info) + return; + + kfree(reg_info->reg_rules_2ghz_ptr); + kfree(reg_info->reg_rules_5ghz_ptr); + + for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) { + kfree(reg_info->reg_rules_6ghz_ap_ptr[i]); + + for (j = 0; j < WMI_REG_MAX_CLIENT_TYPE; j++) + kfree(reg_info->reg_rules_6ghz_client_ptr[i][j]); + } + + memset(reg_info, 0, sizeof(*reg_info)); +} + void ath11k_reg_free(struct ath11k_base *ab) { int i; + for (i = 0; i < ab->num_radios; i++) + ath11k_reg_reset_info(&ab->reg_info_store[i]); + + kfree(ab->reg_info_store); + ab->reg_info_store = NULL; + for (i = 0; i < ab->hw_params.max_radios; i++) { kfree(ab->default_regd[i]); kfree(ab->new_regd[i]); diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h index 84daa6543b..64edb79426 100644 --- a/drivers/net/wireless/ath/ath11k/reg.h +++ b/drivers/net/wireless/ath/ath11k/reg.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_REG_H @@ -29,11 +30,20 @@ enum ath11k_dfs_region { /* ATH11K Regulatory API's */ void ath11k_reg_init(struct ath11k *ar); +void ath11k_reg_reset_info(struct cur_regulatory_info *reg_info); void ath11k_reg_free(struct ath11k_base *ab); void ath11k_regd_update_work(struct work_struct *work); struct ieee80211_regdomain * ath11k_reg_build_regd(struct ath11k_base *ab, - struct cur_regulatory_info *reg_info, bool intersect); + struct cur_regulatory_info *reg_info, bool intersect, + enum wmi_vdev_type vdev_type, + enum ieee80211_ap_reg_power power_type); int ath11k_regd_update(struct ath11k *ar); int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait); +enum wmi_reg_6ghz_ap_type +ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type); +int ath11k_reg_handle_chan_list(struct ath11k_base *ab, + struct cur_regulatory_info *reg_info, + enum ieee80211_ap_reg_power power_type); + #endif diff --git a/drivers/net/wireless/ath/ath11k/rx_desc.h b/drivers/net/wireless/ath/ath11k/rx_desc.h index 786d5f36f5..2da6da7272 100644 --- a/drivers/net/wireless/ath/ath11k/rx_desc.h +++ b/drivers/net/wireless/ath/ath11k/rx_desc.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_RX_DESC_H #define ATH11K_RX_DESC_H diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c index 0b7b7122cc..79e0911345 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.c +++ b/drivers/net/wireless/ath/ath11k/spectral.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/relay.h> diff --git a/drivers/net/wireless/ath/ath11k/spectral.h b/drivers/net/wireless/ath/ath11k/spectral.h index 96bfa16e18..789cff7c64 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.h +++ b/drivers/net/wireless/ath/ath11k/spectral.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_SPECTRAL_H diff --git a/drivers/net/wireless/ath/ath11k/thermal.c b/drivers/net/wireless/ath/ath11k/thermal.c index c9b012f97b..c29b11ab5b 100644 --- a/drivers/net/wireless/ath/ath11k/thermal.c +++ b/drivers/net/wireless/ath/ath11k/thermal.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/device.h> diff --git a/drivers/net/wireless/ath/ath11k/thermal.h b/drivers/net/wireless/ath/ath11k/thermal.h index 83cb676867..cdaf4e01d9 100644 --- a/drivers/net/wireless/ath/ath11k/thermal.h +++ b/drivers/net/wireless/ath/ath11k/thermal.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_THERMAL_ diff --git a/drivers/net/wireless/ath/ath11k/trace.h b/drivers/net/wireless/ath/ath11k/trace.h index 9535745fe0..235ab8ea71 100644 --- a/drivers/net/wireless/ath/ath11k/trace.h +++ b/drivers/net/wireless/ath/ath11k/trace.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 2845b4313d..442afda7ec 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/skbuff.h> #include <linux/ctype.h> @@ -4749,6 +4749,14 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, soc->pdevs[0].pdev_id = 0; } + if (!soc->reg_info_store) { + soc->reg_info_store = kcalloc(soc->num_radios, + sizeof(*soc->reg_info_store), + GFP_ATOMIC); + if (!soc->reg_info_store) + return -ENOMEM; + } + return 0; } @@ -7060,32 +7068,15 @@ static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, wake_up(&wmi->tx_ce_desc_wq); } -static bool ath11k_reg_is_world_alpha(char *alpha) -{ - if (alpha[0] == '0' && alpha[1] == '0') - return true; - - if (alpha[0] == 'n' && alpha[1] == 'a') - return true; - - return false; -} - -static int ath11k_reg_chan_list_event(struct ath11k_base *ab, - struct sk_buff *skb, +static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb, enum wmi_reg_chan_list_cmd_type id) { - struct cur_regulatory_info *reg_info = NULL; - struct ieee80211_regdomain *regd = NULL; - bool intersect = false; - int ret = 0, pdev_idx, i, j; - struct ath11k *ar; + struct cur_regulatory_info *reg_info; + int ret; reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC); - if (!reg_info) { - ret = -ENOMEM; - goto fallback; - } + if (!reg_info) + return -ENOMEM; if (id == WMI_REG_CHAN_LIST_CC_ID) ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info); @@ -7093,118 +7084,22 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, ret = ath11k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info); if (ret) { - ath11k_warn(ab, "failed to extract regulatory info from received event\n"); - goto fallback; - } - - ath11k_dbg(ab, ATH11K_DBG_WMI, "event reg chan list id %d", id); - - if (reg_info->status_code != REG_SET_CC_STATUS_PASS) { - /* In case of failure to set the requested ctry, - * fw retains the current regd. We print a failure info - * and return from here. - */ - ath11k_warn(ab, "Failed to set the requested Country regulatory setting\n"); - goto mem_free; - } - - pdev_idx = reg_info->phy_id; - - /* Avoid default reg rule updates sent during FW recovery if - * it is already available - */ - spin_lock(&ab->base_lock); - if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) && - ab->default_regd[pdev_idx]) { - spin_unlock(&ab->base_lock); + ath11k_warn(ab, "failed to extract regulatory info\n"); goto mem_free; } - spin_unlock(&ab->base_lock); - if (pdev_idx >= ab->num_radios) { - /* Process the event for phy0 only if single_pdev_only - * is true. If pdev_idx is valid but not 0, discard the - * event. Otherwise, it goes to fallback. - */ - if (ab->hw_params.single_pdev_only && - pdev_idx < ab->hw_params.num_rxmda_per_pdev) - goto mem_free; - else - goto fallback; - } - - /* Avoid multiple overwrites to default regd, during core - * stop-start after mac registration. - */ - if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && - !memcmp((char *)ab->default_regd[pdev_idx]->alpha2, - (char *)reg_info->alpha2, 2)) + ret = ath11k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_UNSET_AP); + if (ret) { + ath11k_warn(ab, "failed to process regulatory info %d\n", ret); goto mem_free; - - /* Intersect new rules with default regd if a new country setting was - * requested, i.e a default regd was already set during initialization - * and the regd coming from this event has a valid country info. - */ - if (ab->default_regd[pdev_idx] && - !ath11k_reg_is_world_alpha((char *) - ab->default_regd[pdev_idx]->alpha2) && - !ath11k_reg_is_world_alpha((char *)reg_info->alpha2)) - intersect = true; - - regd = ath11k_reg_build_regd(ab, reg_info, intersect); - if (!regd) { - ath11k_warn(ab, "failed to build regd from reg_info\n"); - goto fallback; - } - - spin_lock(&ab->base_lock); - if (ab->default_regd[pdev_idx]) { - /* The initial rules from FW after WMI Init is to build - * the default regd. From then on, any rules updated for - * the pdev could be due to user reg changes. - * Free previously built regd before assigning the newly - * generated regd to ar. NULL pointer handling will be - * taken care by kfree itself. - */ - ar = ab->pdevs[pdev_idx].ar; - kfree(ab->new_regd[pdev_idx]); - ab->new_regd[pdev_idx] = regd; - queue_work(ab->workqueue, &ar->regd_update_work); - } else { - /* This regd would be applied during mac registration and is - * held constant throughout for regd intersection purpose - */ - ab->default_regd[pdev_idx] = regd; } - ab->dfs_region = reg_info->dfs_region; - spin_unlock(&ab->base_lock); - goto mem_free; + kfree(reg_info); + return 0; -fallback: - /* Fallback to older reg (by sending previous country setting - * again if fw has succeeded and we failed to process here. - * The Regdomain should be uniform across driver and fw. Since the - * FW has processed the command and sent a success status, we expect - * this function to succeed as well. If it doesn't, CTRY needs to be - * reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent. - */ - /* TODO: This is rare, but still should also be handled */ - WARN_ON(1); mem_free: - if (reg_info) { - kfree(reg_info->reg_rules_2ghz_ptr); - kfree(reg_info->reg_rules_5ghz_ptr); - if (reg_info->is_ext_reg_event) { - for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) - kfree(reg_info->reg_rules_6ghz_ap_ptr[i]); - - for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) - for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) - kfree(reg_info->reg_rules_6ghz_client_ptr[j][i]); - } - kfree(reg_info); - } + ath11k_reg_reset_info(reg_info); + kfree(reg_info); return ret; } diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 100bb816b5..cd2098d78e 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_WMI_H @@ -1096,25 +1096,27 @@ enum wmi_tlv_vdev_param { }; enum wmi_tlv_peer_flags { - WMI_TLV_PEER_AUTH = 0x00000001, - WMI_TLV_PEER_QOS = 0x00000002, - WMI_TLV_PEER_NEED_PTK_4_WAY = 0x00000004, - WMI_TLV_PEER_NEED_GTK_2_WAY = 0x00000010, - WMI_TLV_PEER_APSD = 0x00000800, - WMI_TLV_PEER_HT = 0x00001000, - WMI_TLV_PEER_40MHZ = 0x00002000, - WMI_TLV_PEER_STBC = 0x00008000, - WMI_TLV_PEER_LDPC = 0x00010000, - WMI_TLV_PEER_DYN_MIMOPS = 0x00020000, - WMI_TLV_PEER_STATIC_MIMOPS = 0x00040000, - WMI_TLV_PEER_SPATIAL_MUX = 0x00200000, - WMI_TLV_PEER_VHT = 0x02000000, - WMI_TLV_PEER_80MHZ = 0x04000000, - WMI_TLV_PEER_PMF = 0x08000000, + WMI_PEER_AUTH = 0x00000001, + WMI_PEER_QOS = 0x00000002, + WMI_PEER_NEED_PTK_4_WAY = 0x00000004, + WMI_PEER_NEED_GTK_2_WAY = 0x00000010, + WMI_PEER_HE = 0x00000400, + WMI_PEER_APSD = 0x00000800, + WMI_PEER_HT = 0x00001000, + WMI_PEER_40MHZ = 0x00002000, + WMI_PEER_STBC = 0x00008000, + WMI_PEER_LDPC = 0x00010000, + WMI_PEER_DYN_MIMOPS = 0x00020000, + WMI_PEER_STATIC_MIMOPS = 0x00040000, + WMI_PEER_SPATIAL_MUX = 0x00200000, + WMI_PEER_TWT_REQ = 0x00400000, + WMI_PEER_TWT_RESP = 0x00800000, + WMI_PEER_VHT = 0x02000000, + WMI_PEER_80MHZ = 0x04000000, + WMI_PEER_PMF = 0x08000000, WMI_PEER_IS_P2P_CAPABLE = 0x20000000, WMI_PEER_160MHZ = 0x40000000, WMI_PEER_SAFEMODE_EN = 0x80000000, - }; /** Enum list of TLV Tags for each parameter structure type. */ @@ -2580,7 +2582,6 @@ struct wmi_service_available_event { struct ath11k_pdev_wmi { struct ath11k_wmi_base *wmi_ab; enum ath11k_htc_ep_id eid; - const struct wmi_peer_flags_map *peer_flags; u32 rx_decap_mode; wait_queue_head_t tx_ce_desc_wq; }; @@ -4062,31 +4063,6 @@ struct wmi_unit_test_cmd { #define MAX_SUPPORTED_RATES 128 -#define WMI_PEER_AUTH 0x00000001 -#define WMI_PEER_QOS 0x00000002 -#define WMI_PEER_NEED_PTK_4_WAY 0x00000004 -#define WMI_PEER_NEED_GTK_2_WAY 0x00000010 -#define WMI_PEER_HE 0x00000400 -#define WMI_PEER_APSD 0x00000800 -#define WMI_PEER_HT 0x00001000 -#define WMI_PEER_40MHZ 0x00002000 -#define WMI_PEER_STBC 0x00008000 -#define WMI_PEER_LDPC 0x00010000 -#define WMI_PEER_DYN_MIMOPS 0x00020000 -#define WMI_PEER_STATIC_MIMOPS 0x00040000 -#define WMI_PEER_SPATIAL_MUX 0x00200000 -#define WMI_PEER_TWT_REQ 0x00400000 -#define WMI_PEER_TWT_RESP 0x00800000 -#define WMI_PEER_VHT 0x02000000 -#define WMI_PEER_80MHZ 0x04000000 -#define WMI_PEER_PMF 0x08000000 -/* TODO: Place holder for WLAN_PEER_F_PS_PRESEND_REQUIRED = 0x10000000. - * Need to be cleaned up - */ -#define WMI_PEER_IS_P2P_CAPABLE 0x20000000 -#define WMI_PEER_160MHZ 0x40000000 -#define WMI_PEER_SAFEMODE_EN 0x80000000 - struct beacon_tmpl_params { u8 vdev_id; u32 tim_ie_offset; @@ -4975,6 +4951,7 @@ struct ath11k_targ_cap { }; enum wmi_vdev_type { + WMI_VDEV_TYPE_UNSPEC = 0, WMI_VDEV_TYPE_AP = 1, WMI_VDEV_TYPE_STA = 2, WMI_VDEV_TYPE_IBSS = 3, @@ -5754,7 +5731,6 @@ struct ath11k_wmi_base { struct completion unified_ready; DECLARE_BITMAP(svc_map, WMI_MAX_EXT2_SERVICE); wait_queue_head_t tx_credits_wq; - const struct wmi_peer_flags_map *peer_flags; u32 num_mem_chunks; u32 rx_decap_mode; struct wmi_host_mem_chunk mem_chunks[WMI_MAX_MEM_REQS]; diff --git a/drivers/net/wireless/ath/ath11k/wow.h b/drivers/net/wireless/ath/ath11k/wow.h index 553ba850d9..c85811e3f4 100644 --- a/drivers/net/wireless/ath/ath11k/wow.h +++ b/drivers/net/wireless/ath/ath11k/wow.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _WOW_H_ diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig index 4f9c514c13..e135d2b1b6 100644 --- a/drivers/net/wireless/ath/ath12k/Kconfig +++ b/drivers/net/wireless/ath/ath12k/Kconfig @@ -2,7 +2,7 @@ config ATH12K tristate "Qualcomm Technologies Wi-Fi 7 support (ath12k)" depends on MAC80211 && HAS_DMA && PCI - depends on CRYPTO_MICHAEL_MIC + select CRYPTO_MICHAEL_MIC select QCOM_QMI_HELPERS select MHI_BUS select QRTR diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index d67494de44..01fb9b2ae4 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_CORE_H @@ -199,6 +199,8 @@ enum ath12k_dev_flags { ATH12K_FLAG_REGISTERED, ATH12K_FLAG_QMI_FAIL, ATH12K_FLAG_HTC_SUSPEND_COMPLETE, + ATH12K_FLAG_CE_IRQ_ENABLED, + ATH12K_FLAG_EXT_IRQ_ENABLED, }; enum ath12k_monitor_flags { @@ -467,7 +469,6 @@ struct ath12k { struct ath12k_base *ab; struct ath12k_pdev *pdev; struct ieee80211_hw *hw; - struct ieee80211_ops *ops; struct ath12k_wmi_pdev *wmi; struct ath12k_pdev_dp dp; u8 mac_addr[ETH_ALEN]; diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 6893466f61..a6f81f2f97 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <crypto/hash.h> @@ -961,9 +961,7 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, struct ath12k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; - ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, 0, - ab->hw_params->hal_params->rx_buf_rbm, - true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, 0); } /* TODO: Implement handler for other interrupts */ diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 61f7654325..1df3cdd461 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_DP_H @@ -31,7 +31,7 @@ struct dp_srng { u32 ring_id; }; -struct dp_rxdma_ring { +struct dp_rxdma_mon_ring { struct dp_srng refill_buf_ring; struct idr bufs_idr; /* Protects bufs_idr */ @@ -39,6 +39,11 @@ struct dp_rxdma_ring { int bufs_max; }; +struct dp_rxdma_ring { + struct dp_srng refill_buf_ring; + int bufs_max; +}; + #define ATH12K_TX_COMPL_NEXT(x) (((x) + 1) % DP_TX_COMP_RING_SIZE) struct dp_tx_ring { @@ -353,8 +358,8 @@ struct ath12k_dp { struct dp_rxdma_ring rx_refill_buf_ring; struct dp_srng rx_mac_buf_ring[MAX_RXDMA_PER_PDEV]; struct dp_srng rxdma_err_dst_ring[MAX_RXDMA_PER_PDEV]; - struct dp_rxdma_ring rxdma_mon_buf_ring; - struct dp_rxdma_ring tx_mon_buf_ring; + struct dp_rxdma_mon_ring rxdma_mon_buf_ring; + struct dp_rxdma_mon_ring tx_mon_buf_ring; struct ath12k_reo_q_addr_lut reoq_lut; }; diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index f44bc5494c..be4b39f5fa 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "dp_mon.h" @@ -797,7 +797,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, /* TODO: add msdu start parsing logic */ break; case HAL_MON_BUF_ADDR: { - struct dp_rxdma_ring *buf_ring = &ab->dp.rxdma_mon_buf_ring; + struct dp_rxdma_mon_ring *buf_ring = &ab->dp.rxdma_mon_buf_ring; struct dp_mon_packet_info *packet_info = (struct dp_mon_packet_info *)tlv_data; int buf_id = u32_get_bits(packet_info->cookie, @@ -1091,7 +1091,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct spin_unlock_bh(&ar->ab->base_lock); ath12k_dbg(ar->ab, ATH12K_DBG_DATA, - "rx skb %pK len %u peer %pM %u %s %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", + "rx skb %pK len %u peer %pM %u %s %s%s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", msdu, msdu->len, peer ? peer->addr : NULL, @@ -1104,6 +1104,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct (status->bw == RATE_INFO_BW_40) ? "40" : "", (status->bw == RATE_INFO_BW_80) ? "80" : "", (status->bw == RATE_INFO_BW_160) ? "160" : "", + (status->bw == RATE_INFO_BW_320) ? "320" : "", status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "", status->rate_idx, status->nss, @@ -1259,7 +1260,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar, } int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab, - struct dp_rxdma_ring *buf_ring, + struct dp_rxdma_mon_ring *buf_ring, int req_entries) { struct hal_mon_buf_ring *mon_buf; @@ -1902,7 +1903,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, } case HAL_MON_BUF_ADDR: { - struct dp_rxdma_ring *buf_ring = &ab->dp.tx_mon_buf_ring; + struct dp_rxdma_mon_ring *buf_ring = &ab->dp.tx_mon_buf_ring; struct dp_mon_packet_info *packet_info = (struct dp_mon_packet_info *)tlv_data; int buf_id = u32_get_bits(packet_info->cookie, @@ -2067,7 +2068,7 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int mac_id, int *budget, struct ath12k_skb_rxcb *rxcb; struct dp_srng *mon_dst_ring; struct hal_srng *srng; - struct dp_rxdma_ring *buf_ring; + struct dp_rxdma_mon_ring *buf_ring; u64 cookie; u32 ppdu_id; int num_buffs_reaped = 0, srng_id, buf_id; @@ -2480,7 +2481,7 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id, struct ath12k_skb_rxcb *rxcb; struct dp_srng *mon_dst_ring; struct hal_srng *srng; - struct dp_rxdma_ring *buf_ring; + struct dp_rxdma_mon_ring *buf_ring; struct ath12k_sta *arsta = NULL; struct ath12k_peer *peer; u64 cookie; diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.h b/drivers/net/wireless/ath/ath12k/dp_mon.h index c18c385798..fb9e9c176c 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.h +++ b/drivers/net/wireless/ath/ath12k/dp_mon.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_DP_MON_H @@ -80,7 +80,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar, int mac_id, struct sk_buff *skb, struct napi_struct *napi); int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab, - struct dp_rxdma_ring *buf_ring, + struct dp_rxdma_mon_ring *buf_ring, int req_entries); int ath12k_dp_mon_srng_process(struct ath12k *ar, int mac_id, int *budget, enum dp_monitor_mode monitor_mode, diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 3543fadac4..1ee83f7659 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/ieee80211.h> @@ -256,22 +256,20 @@ static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) } /* Returns number of Rx buffers replenished */ -int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id, +int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring, - int req_entries, - enum hal_rx_buf_return_buf_manager mgr, - bool hw_cc) + int req_entries) { struct ath12k_buffer_addr *desc; struct hal_srng *srng; struct sk_buff *skb; int num_free; int num_remain; - int buf_id; u32 cookie; dma_addr_t paddr; struct ath12k_dp *dp = &ab->dp; struct ath12k_rx_desc_info *rx_desc; + enum hal_rx_buf_return_buf_manager mgr = ab->hw_params->hal_params->rx_buf_rbm; req_entries = min(req_entries, rx_ring->bufs_max); @@ -307,42 +305,29 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id, if (dma_mapping_error(ab->dev, paddr)) goto fail_free_skb; - if (hw_cc) { - spin_lock_bh(&dp->rx_desc_lock); - - /* Get desc from free list and store in used list - * for cleanup purposes - * - * TODO: pass the removed descs rather than - * add/read to optimize - */ - rx_desc = list_first_entry_or_null(&dp->rx_desc_free_list, - struct ath12k_rx_desc_info, - list); - if (!rx_desc) { - spin_unlock_bh(&dp->rx_desc_lock); - goto fail_dma_unmap; - } - - rx_desc->skb = skb; - cookie = rx_desc->cookie; - list_del(&rx_desc->list); - list_add_tail(&rx_desc->list, &dp->rx_desc_used_list); + spin_lock_bh(&dp->rx_desc_lock); + /* Get desc from free list and store in used list + * for cleanup purposes + * + * TODO: pass the removed descs rather than + * add/read to optimize + */ + rx_desc = list_first_entry_or_null(&dp->rx_desc_free_list, + struct ath12k_rx_desc_info, + list); + if (!rx_desc) { spin_unlock_bh(&dp->rx_desc_lock); - } else { - spin_lock_bh(&rx_ring->idr_lock); - buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0, - rx_ring->bufs_max * 3, GFP_ATOMIC); - spin_unlock_bh(&rx_ring->idr_lock); - if (buf_id < 0) - goto fail_dma_unmap; - cookie = u32_encode_bits(mac_id, - DP_RXDMA_BUF_COOKIE_PDEV_ID) | - u32_encode_bits(buf_id, - DP_RXDMA_BUF_COOKIE_BUF_ID); + goto fail_dma_unmap; } + rx_desc->skb = skb; + cookie = rx_desc->cookie; + list_del(&rx_desc->list); + list_add_tail(&rx_desc->list, &dp->rx_desc_used_list); + + spin_unlock_bh(&dp->rx_desc_lock); + desc = ath12k_hal_srng_src_get_next_entry(ab, srng); if (!desc) goto fail_buf_unassign; @@ -361,17 +346,11 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id, return req_entries - num_remain; fail_buf_unassign: - if (hw_cc) { - spin_lock_bh(&dp->rx_desc_lock); - list_del(&rx_desc->list); - list_add_tail(&rx_desc->list, &dp->rx_desc_free_list); - rx_desc->skb = NULL; - spin_unlock_bh(&dp->rx_desc_lock); - } else { - spin_lock_bh(&rx_ring->idr_lock); - idr_remove(&rx_ring->bufs_idr, buf_id); - spin_unlock_bh(&rx_ring->idr_lock); - } + spin_lock_bh(&dp->rx_desc_lock); + list_del(&rx_desc->list); + list_add_tail(&rx_desc->list, &dp->rx_desc_free_list); + rx_desc->skb = NULL; + spin_unlock_bh(&dp->rx_desc_lock); fail_dma_unmap: dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); @@ -385,8 +364,8 @@ fail_free_skb: return req_entries - num_remain; } -static int ath12k_dp_rxdma_buf_ring_free(struct ath12k_base *ab, - struct dp_rxdma_ring *rx_ring) +static int ath12k_dp_rxdma_mon_buf_ring_free(struct ath12k_base *ab, + struct dp_rxdma_mon_ring *rx_ring) { struct sk_buff *skb; int buf_id; @@ -411,46 +390,49 @@ static int ath12k_dp_rxdma_buf_ring_free(struct ath12k_base *ab, static int ath12k_dp_rxdma_buf_free(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; - struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; - ath12k_dp_rxdma_buf_ring_free(ab, rx_ring); + ath12k_dp_rxdma_mon_buf_ring_free(ab, &dp->rxdma_mon_buf_ring); + + ath12k_dp_rxdma_mon_buf_ring_free(ab, &dp->tx_mon_buf_ring); + + return 0; +} - rx_ring = &dp->rxdma_mon_buf_ring; - ath12k_dp_rxdma_buf_ring_free(ab, rx_ring); +static int ath12k_dp_rxdma_mon_ring_buf_setup(struct ath12k_base *ab, + struct dp_rxdma_mon_ring *rx_ring, + u32 ringtype) +{ + int num_entries; - rx_ring = &dp->tx_mon_buf_ring; - ath12k_dp_rxdma_buf_ring_free(ab, rx_ring); + num_entries = rx_ring->refill_buf_ring.size / + ath12k_hal_srng_get_entrysize(ab, ringtype); + + rx_ring->bufs_max = num_entries; + ath12k_dp_mon_buf_replenish(ab, rx_ring, num_entries); return 0; } static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab, - struct dp_rxdma_ring *rx_ring, - u32 ringtype) + struct dp_rxdma_ring *rx_ring) { int num_entries; num_entries = rx_ring->refill_buf_ring.size / - ath12k_hal_srng_get_entrysize(ab, ringtype); + ath12k_hal_srng_get_entrysize(ab, HAL_RXDMA_BUF); rx_ring->bufs_max = num_entries; - if ((ringtype == HAL_RXDMA_MONITOR_BUF) || (ringtype == HAL_TX_MONITOR_BUF)) - ath12k_dp_mon_buf_replenish(ab, rx_ring, num_entries); - else - ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_entries, - ab->hw_params->hal_params->rx_buf_rbm, - ringtype == HAL_RXDMA_BUF); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_entries); + return 0; } static int ath12k_dp_rxdma_buf_setup(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; - struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; int ret; - ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring, - HAL_RXDMA_BUF); + ret = ath12k_dp_rxdma_ring_buf_setup(ab, &dp->rx_refill_buf_ring); if (ret) { ath12k_warn(ab, "failed to setup HAL_RXDMA_BUF\n"); @@ -458,18 +440,18 @@ static int ath12k_dp_rxdma_buf_setup(struct ath12k_base *ab) } if (ab->hw_params->rxdma1_enable) { - rx_ring = &dp->rxdma_mon_buf_ring; - ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring, - HAL_RXDMA_MONITOR_BUF); + ret = ath12k_dp_rxdma_mon_ring_buf_setup(ab, + &dp->rxdma_mon_buf_ring, + HAL_RXDMA_MONITOR_BUF); if (ret) { ath12k_warn(ab, "failed to setup HAL_RXDMA_MONITOR_BUF\n"); return ret; } - rx_ring = &dp->tx_mon_buf_ring; - ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring, - HAL_TX_MONITOR_BUF); + ret = ath12k_dp_rxdma_mon_ring_buf_setup(ab, + &dp->tx_mon_buf_ring, + HAL_TX_MONITOR_BUF); if (ret) { ath12k_warn(ab, "failed to setup HAL_TX_MONITOR_BUF\n"); @@ -1339,9 +1321,6 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, u8 tid = HTT_PPDU_STATS_NON_QOS_TID; bool is_ampdu = false; - if (!usr_stats) - return; - if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) return; @@ -2438,7 +2417,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap spin_unlock_bh(&ab->base_lock); ath12k_dbg(ab, ATH12K_DBG_DATA, - "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", + "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", msdu, msdu->len, peer ? peer->addr : NULL, @@ -2452,6 +2431,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap (status->bw == RATE_INFO_BW_40) ? "40" : "", (status->bw == RATE_INFO_BW_80) ? "80" : "", (status->bw == RATE_INFO_BW_160) ? "160" : "", + (status->bw == RATE_INFO_BW_320) ? "320" : "", status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "", status->rate_idx, status->nss, @@ -2714,9 +2694,7 @@ try_again: if (!total_msdu_reaped) goto exit; - /* TODO: Move to implicit BM? */ - ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_buffs_reaped, - ab->hw_params->hal_params->rx_buf_rbm, true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped); ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list, ring_id); @@ -3494,8 +3472,7 @@ exit: rx_ring = &dp->rx_refill_buf_ring; - ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, tot_n_bufs_reaped, - ab->hw_params->hal_params->rx_buf_rbm, true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, tot_n_bufs_reaped); return tot_n_bufs_reaped; } @@ -3808,8 +3785,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, if (!num_buffs_reaped) goto done; - ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_buffs_reaped, - ab->hw_params->hal_params->rx_buf_rbm, true); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped); rcu_read_lock(); for (i = 0; i < ab->num_radios; i++) { @@ -4090,9 +4066,6 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) struct ath12k_dp *dp = &ab->dp; int i, ret; - idr_init(&dp->rx_refill_buf_ring.bufs_idr); - spin_lock_init(&dp->rx_refill_buf_ring.idr_lock); - idr_init(&dp->rxdma_mon_buf_ring.bufs_idr); spin_lock_init(&dp->rxdma_mon_buf_ring.idr_lock); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index c955b5c859..05b3d5581d 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_DP_RX_H #define ATH12K_DP_RX_H @@ -116,11 +116,9 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, int ath12k_dp_rx_process(struct ath12k_base *ab, int mac_id, struct napi_struct *napi, int budget); -int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id, +int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring, - int req_entries, - enum hal_rx_buf_return_buf_manager mgr, - bool hw_cc); + int req_entries); int ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar); int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id); diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h index fcfb6c8190..095216eabc 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.h +++ b/drivers/net/wireless/ath/ath12k/hal_rx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HAL_RX_H @@ -61,6 +61,7 @@ enum hal_rx_bw { HAL_RX_BW_40MHZ, HAL_RX_BW_80MHZ, HAL_RX_BW_160MHZ, + HAL_RX_BW_320MHZ, HAL_RX_BW_MAX, }; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 237fb8e7cf..b965fc46ad 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -343,6 +343,9 @@ ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw) case ATH12K_BW_160: ret = RATE_INFO_BW_160; break; + case ATH12K_BW_320: + ret = RATE_INFO_BW_320; + break; } return ret; @@ -359,6 +362,8 @@ enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw b return ATH12K_BW_80; case RATE_INFO_BW_160: return ATH12K_BW_160; + case RATE_INFO_BW_320: + return ATH12K_BW_320; default: return ATH12K_BW_20; } @@ -3726,6 +3731,9 @@ static u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar, case IEEE80211_STA_RX_BW_160: bw = WMI_PEER_CHWIDTH_160MHZ; break; + case IEEE80211_STA_RX_BW_320: + bw = WMI_PEER_CHWIDTH_320MHZ; + break; default: ath12k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n", sta->deflink.bandwidth, sta->addr); @@ -4987,7 +4995,7 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, if (ret) { ath12k_warn(ar->ab, "failed to queue management frame %d\n", ret); - ieee80211_free_txskb(ar->hw, skb); + ieee80211_free_txskb(hw, skb); } return; } @@ -4995,7 +5003,7 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, ret = ath12k_dp_tx(ar, arvif, skb); if (ret) { ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret); - ieee80211_free_txskb(ar->hw, skb); + ieee80211_free_txskb(hw, skb); } } @@ -5596,7 +5604,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, goto err_peer_del; param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; - param_value = ar->hw->wiphy->rts_threshold; + param_value = hw->wiphy->rts_threshold; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param_id, param_value); if (ret) { @@ -6258,10 +6266,11 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar, struct ieee80211_chanctx_conf *ctx) { struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx }; + struct ieee80211_hw *hw = ar->hw; lockdep_assert_held(&ar->conf_mutex); - ieee80211_iterate_active_interfaces_atomic(ar->hw, + ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_NORMAL, ath12k_mac_change_chanctx_cnt_iter, &arg); @@ -6272,7 +6281,7 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar, if (!arg.vifs) return; - ieee80211_iterate_active_interfaces_atomic(ar->hw, + ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_NORMAL, ath12k_mac_change_chanctx_fill_iter, &arg); @@ -6836,7 +6845,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, arvif->vdev_id, ret); return ret; } - ieee80211_iterate_stations_atomic(ar->hw, + ieee80211_iterate_stations_atomic(hw, ath12k_mac_disable_peer_fixed_rate, arvif); } else if (ath12k_mac_bitrate_mask_get_single_nss(ar, band, mask, @@ -6882,14 +6891,14 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, return -EINVAL; } - ieee80211_iterate_stations_atomic(ar->hw, + ieee80211_iterate_stations_atomic(hw, ath12k_mac_disable_peer_fixed_rate, arvif); mutex_lock(&ar->conf_mutex); arvif->bitrate_mask = *mask; - ieee80211_iterate_stations_atomic(ar->hw, + ieee80211_iterate_stations_atomic(hw, ath12k_mac_set_bitrate_mask_iter, arvif); @@ -6927,7 +6936,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ath12k_warn(ar->ab, "pdev %d successfully recovered\n", ar->pdev->pdev_id); ar->state = ATH12K_STATE_ON; - ieee80211_wake_queues(ar->hw); + ieee80211_wake_queues(hw); if (ab->is_reset) { recovery_count = atomic_inc_return(&ab->recovery_count); @@ -7151,6 +7160,7 @@ static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band) static int ath12k_mac_setup_channels_rates(struct ath12k *ar, u32 supported_bands) { + struct ieee80211_hw *hw = ar->hw; struct ieee80211_supported_band *band; struct ath12k_wmi_hal_reg_capabilities_ext_arg *reg_cap; void *channels; @@ -7176,7 +7186,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_g_rates_size; band->bitrates = ath12k_g_rates; - ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band; + hw->wiphy->bands[NL80211_BAND_2GHZ] = band; if (ar->ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP); @@ -7203,7 +7213,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_a_rates_size; band->bitrates = ath12k_a_rates; - ar->hw->wiphy->bands[NL80211_BAND_6GHZ] = band; + hw->wiphy->bands[NL80211_BAND_6GHZ] = band; ath12k_mac_update_ch_list(ar, band, reg_cap->low_5ghz_chan, reg_cap->high_5ghz_chan); @@ -7225,7 +7235,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_a_rates_size; band->bitrates = ath12k_a_rates; - ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; + hw->wiphy->bands[NL80211_BAND_5GHZ] = band; if (ar->ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); @@ -7244,6 +7254,8 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, static int ath12k_mac_setup_iface_combinations(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; + struct ieee80211_hw *hw = ar->hw; + struct wiphy *wiphy = hw->wiphy; struct ieee80211_iface_combination *combinations; struct ieee80211_iface_limit *limits; int n_limits, max_interfaces; @@ -7294,8 +7306,8 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k *ar) BIT(NL80211_CHAN_WIDTH_40) | BIT(NL80211_CHAN_WIDTH_80); - ar->hw->wiphy->iface_combinations = combinations; - ar->hw->wiphy->n_iface_combinations = 1; + wiphy->iface_combinations = combinations; + wiphy->n_iface_combinations = 1; return 0; } @@ -7339,9 +7351,12 @@ static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { static void __ath12k_mac_unregister(struct ath12k *ar) { + struct ieee80211_hw *hw = ar->hw; + struct wiphy *wiphy = hw->wiphy; + cancel_work_sync(&ar->regd_update_work); - ieee80211_unregister_hw(ar->hw); + ieee80211_unregister_hw(hw); idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar); idr_destroy(&ar->txmgmt_idr); @@ -7350,10 +7365,10 @@ static void __ath12k_mac_unregister(struct ath12k *ar) kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); - kfree(ar->hw->wiphy->iface_combinations[0].limits); - kfree(ar->hw->wiphy->iface_combinations); + kfree(wiphy->iface_combinations[0].limits); + kfree(wiphy->iface_combinations); - SET_IEEE80211_DEV(ar->hw, NULL); + SET_IEEE80211_DEV(hw, NULL); } void ath12k_mac_unregister(struct ath12k_base *ab) @@ -7375,6 +7390,8 @@ void ath12k_mac_unregister(struct ath12k_base *ab) static int __ath12k_mac_register(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; + struct ieee80211_hw *hw = ar->hw; + struct wiphy *wiphy = hw->wiphy; struct ath12k_pdev_cap *cap = &ar->pdev->cap; static const u32 cipher_suites[] = { WLAN_CIPHER_SUITE_TKIP, @@ -7392,9 +7409,9 @@ static int __ath12k_mac_register(struct ath12k *ar) ath12k_pdev_caps_update(ar); - SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr); + SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); - SET_IEEE80211_DEV(ar->hw, ab->dev); + SET_IEEE80211_DEV(hw, ab->dev); ret = ath12k_mac_setup_channels_rates(ar, cap->supported_bands); @@ -7410,103 +7427,102 @@ static int __ath12k_mac_register(struct ath12k *ar) goto err_free_channels; } - ar->hw->wiphy->available_antennas_rx = cap->rx_chain_mask; - ar->hw->wiphy->available_antennas_tx = cap->tx_chain_mask; + wiphy->available_antennas_rx = cap->rx_chain_mask; + wiphy->available_antennas_tx = cap->tx_chain_mask; - ar->hw->wiphy->interface_modes = ab->hw_params->interface_modes; + wiphy->interface_modes = ab->hw_params->interface_modes; - if (ar->hw->wiphy->bands[NL80211_BAND_2GHZ] && - ar->hw->wiphy->bands[NL80211_BAND_5GHZ] && - ar->hw->wiphy->bands[NL80211_BAND_6GHZ]) - ieee80211_hw_set(ar->hw, SINGLE_SCAN_ON_ALL_BANDS); + if (wiphy->bands[NL80211_BAND_2GHZ] && + wiphy->bands[NL80211_BAND_5GHZ] && + wiphy->bands[NL80211_BAND_6GHZ]) + ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); - ieee80211_hw_set(ar->hw, SIGNAL_DBM); - ieee80211_hw_set(ar->hw, SUPPORTS_PS); - ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS); - ieee80211_hw_set(ar->hw, MFP_CAPABLE); - ieee80211_hw_set(ar->hw, REPORTS_TX_ACK_STATUS); - ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL); - ieee80211_hw_set(ar->hw, AP_LINK_PS); - ieee80211_hw_set(ar->hw, SPECTRUM_MGMT); - ieee80211_hw_set(ar->hw, CONNECTION_MONITOR); - ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK); - ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA); - ieee80211_hw_set(ar->hw, QUEUE_CONTROL); - ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); - ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); + ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + ieee80211_hw_set(hw, MFP_CAPABLE); + ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(hw, HAS_RATE_CONTROL); + ieee80211_hw_set(hw, AP_LINK_PS); + ieee80211_hw_set(hw, SPECTRUM_MGMT); + ieee80211_hw_set(hw, CONNECTION_MONITOR); + ieee80211_hw_set(hw, SUPPORTS_PER_STA_GTK); + ieee80211_hw_set(hw, CHANCTX_STA_CSA); + ieee80211_hw_set(hw, QUEUE_CONTROL); + ieee80211_hw_set(hw, SUPPORTS_TX_FRAG); + ieee80211_hw_set(hw, REPORTS_LOW_ACK); if (ht_cap & WMI_HT_CAP_ENABLED) { - ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION); - ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); - ieee80211_hw_set(ar->hw, SUPPORTS_REORDERING_BUFFER); - ieee80211_hw_set(ar->hw, SUPPORTS_AMSDU_IN_AMPDU); - ieee80211_hw_set(ar->hw, USES_RSS); + ieee80211_hw_set(hw, AMPDU_AGGREGATION); + ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); + ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); + ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); + ieee80211_hw_set(hw, USES_RSS); } - ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; - ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + wiphy->features |= NL80211_FEATURE_STATIC_SMPS; + wiphy->flags |= WIPHY_FLAG_IBSS_RSN; /* TODO: Check if HT capability advertised from firmware is different * for each band for a dual band capable radio. It will be tricky to * handle it when the ht capability different for each band. */ if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS) - ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; + wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; - ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; - ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; + wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; + wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; - ar->hw->max_listen_interval = ATH12K_MAX_HW_LISTEN_INTERVAL; + hw->max_listen_interval = ATH12K_MAX_HW_LISTEN_INTERVAL; - ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - ar->hw->wiphy->max_remain_on_channel_duration = 5000; + wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy->max_remain_on_channel_duration = 5000; - ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; - ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; ar->max_num_stations = TARGET_NUM_STATIONS; ar->max_num_peers = TARGET_NUM_PEERS_PDEV; - ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; + wiphy->max_ap_assoc_sta = ar->max_num_stations; - ar->hw->queues = ATH12K_HW_MAX_QUEUES; - ar->hw->wiphy->tx_queue_len = ATH12K_QUEUE_LEN; - ar->hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; - ar->hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; + hw->queues = ATH12K_HW_MAX_QUEUES; + wiphy->tx_queue_len = ATH12K_QUEUE_LEN; + hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; - ar->hw->vif_data_size = sizeof(struct ath12k_vif); - ar->hw->sta_data_size = sizeof(struct ath12k_sta); + hw->vif_data_size = sizeof(struct ath12k_vif); + hw->sta_data_size = sizeof(struct ath12k_sta); - wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); - wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); - ar->hw->wiphy->cipher_suites = cipher_suites; - ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + wiphy->cipher_suites = cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - ar->hw->wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa; - ar->hw->wiphy->num_iftype_ext_capab = - ARRAY_SIZE(ath12k_iftypes_ext_capa); + wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa; + wiphy->num_iftype_ext_capab = ARRAY_SIZE(ath12k_iftypes_ext_capa); if (ar->supports_6ghz) { - wiphy_ext_feature_set(ar->hw->wiphy, + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY); - wiphy_ext_feature_set(ar->hw->wiphy, + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); } - wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_PUNCT); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PUNCT); - ath12k_reg_init(ar); + ath12k_reg_init(hw); if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) { - ar->hw->netdev_features = NETIF_F_HW_CSUM; - ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); - ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT); + hw->netdev_features = NETIF_F_HW_CSUM; + ieee80211_hw_set(hw, SW_CRYPTO_CONTROL); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); } - ret = ieee80211_register_hw(ar->hw); + ret = ieee80211_register_hw(hw); if (ret) { ath12k_err(ar->ab, "ieee80211 registration failed: %d\n", ret); goto err_free_if_combs; @@ -7518,7 +7534,7 @@ static int __ath12k_mac_register(struct ath12k *ar) * while. But that time is so short and in practise it make * a difference in real life. */ - ar->hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); + wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); /* Apply the regd received during initialization */ ret = ath12k_regd_update(ar, true); @@ -7530,11 +7546,11 @@ static int __ath12k_mac_register(struct ath12k *ar) return 0; err_unregister_hw: - ieee80211_unregister_hw(ar->hw); + ieee80211_unregister_hw(hw); err_free_if_combs: - kfree(ar->hw->wiphy->iface_combinations[0].limits); - kfree(ar->hw->wiphy->iface_combinations); + kfree(wiphy->iface_combinations[0].limits); + kfree(wiphy->iface_combinations); err_free_channels: kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); @@ -7542,7 +7558,7 @@ err_free_channels: kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); err: - SET_IEEE80211_DEV(ar->hw, NULL); + SET_IEEE80211_DEV(hw, NULL); return ret; } diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 7d71ae1aba..7c63bb628a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -43,6 +43,7 @@ enum ath12k_supported_bw { ATH12K_BW_40 = 1, ATH12K_BW_80 = 2, ATH12K_BW_160 = 3, + ATH12K_BW_320 = 4, }; extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default; diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index 27eb38b2b1..d5441ddb37 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -251,6 +251,7 @@ static int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci) u32 user_base_data, base_vector; int ret, num_vectors, i; int *irq; + unsigned int msi_data; ret = ath12k_pci_get_user_msi_assignment(ab, "MHI", &num_vectors, @@ -265,9 +266,15 @@ static int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci) if (!irq) return -ENOMEM; - for (i = 0; i < num_vectors; i++) - irq[i] = ath12k_pci_get_msi_irq(ab->dev, - base_vector + i); + msi_data = base_vector; + for (i = 0; i < num_vectors; i++) { + if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + irq[i] = ath12k_pci_get_msi_irq(ab->dev, + msi_data++); + else + irq[i] = ath12k_pci_get_msi_irq(ab->dev, + msi_data); + } ab_pci->mhi_ctrl->irq = irq; ab_pci->mhi_ctrl->nr_irqs = num_vectors; @@ -374,6 +381,9 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) goto free_controller; } + if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + mhi_ctrl->iova_start = 0; mhi_ctrl->iova_stop = 0xffffffff; mhi_ctrl->sbl_size = SZ_512K; diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index a6a5f9bcff..f0d2e2d871 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -60,6 +60,17 @@ static const struct ath12k_msi_config ath12k_msi_config[] = { }, }; +static const struct ath12k_msi_config msi_config_one_msi = { + .total_vectors = 1, + .total_users = 4, + .users = (struct ath12k_msi_user[]) { + { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, + { .name = "CE", .num_vectors = 1, .base_vector = 0 }, + { .name = "WAKE", .num_vectors = 1, .base_vector = 0 }, + { .name = "DP", .num_vectors = 1, .base_vector = 0 }, + }, +}; + static const char *irq_name[ATH12K_IRQ_NUM_MAX] = { "bhi", "mhi-er0", @@ -355,16 +366,30 @@ static void ath12k_pci_free_irq(struct ath12k_base *ab) static void ath12k_pci_ce_irq_enable(struct ath12k_base *ab, u16 ce_id) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); u32 irq_idx; + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ + if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_id; enable_irq(ab->irq_num[irq_idx]); } static void ath12k_pci_ce_irq_disable(struct ath12k_base *ab, u16 ce_id) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); u32 irq_idx; + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ + if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_id; disable_irq_nosync(ab->irq_num[irq_idx]); } @@ -373,6 +398,8 @@ static void ath12k_pci_ce_irqs_disable(struct ath12k_base *ab) { int i; + clear_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ab->hw_params->ce_count; i++) { if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; @@ -397,20 +424,27 @@ static void ath12k_pci_sync_ce_irqs(struct ath12k_base *ab) static void ath12k_pci_ce_tasklet(struct tasklet_struct *t) { struct ath12k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); + int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; ath12k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); - ath12k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); + enable_irq(ce_pipe->ab->irq_num[irq_idx]); } static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg) { struct ath12k_ce_pipe *ce_pipe = arg; + struct ath12k_base *ab = ce_pipe->ab; + int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; + + if (!test_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) + return IRQ_HANDLED; /* last interrupt received for this CE */ ce_pipe->timestamp = jiffies; - ath12k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); + disable_irq_nosync(ab->irq_num[irq_idx]); + tasklet_schedule(&ce_pipe->intr_tq); return IRQ_HANDLED; @@ -418,8 +452,15 @@ static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg) static void ath12k_pci_ext_grp_disable(struct ath12k_ext_irq_grp *irq_grp) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(irq_grp->ab); int i; + /* In case of one MSI vector, we handle irq enable/disable + * in a uniform way since we only have one irq + */ + if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + for (i = 0; i < irq_grp->num_irq; i++) disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); } @@ -428,6 +469,8 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab) { int i; + clear_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; @@ -440,8 +483,15 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab) static void ath12k_pci_ext_grp_enable(struct ath12k_ext_irq_grp *irq_grp) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(irq_grp->ab); int i; + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ + if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + for (i = 0; i < irq_grp->num_irq; i++) enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); } @@ -467,11 +517,13 @@ static int ath12k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) napi); struct ath12k_base *ab = irq_grp->ab; int work_done; + int i; work_done = ath12k_dp_service_srng(ab, irq_grp, budget); if (work_done < budget) { napi_complete_done(napi, work_done); - ath12k_pci_ext_grp_enable(irq_grp); + for (i = 0; i < irq_grp->num_irq; i++) + enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); } if (work_done > budget) @@ -483,13 +535,19 @@ static int ath12k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg) { struct ath12k_ext_irq_grp *irq_grp = arg; + struct ath12k_base *ab = irq_grp->ab; + int i; + + if (!test_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) + return IRQ_HANDLED; ath12k_dbg(irq_grp->ab, ATH12K_DBG_PCI, "ext irq:%d\n", irq); /* last interrupt received for this group */ irq_grp->timestamp = jiffies; - ath12k_pci_ext_grp_disable(irq_grp); + for (i = 0; i < irq_grp->num_irq; i++) + disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); napi_schedule(&irq_grp->napi); @@ -498,6 +556,7 @@ static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg) static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); int i, j, ret, num_vectors = 0; u32 user_base_data = 0, base_vector = 0, base_idx; @@ -544,23 +603,32 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); ret = request_irq(irq, ath12k_pci_ext_interrupt_handler, - IRQF_SHARED, + ab_pci->irq_flags, "DP_EXT_IRQ", irq_grp); if (ret) { ath12k_err(ab, "failed request irq %d: %d\n", vector, ret); return ret; } - - disable_irq_nosync(ab->irq_num[irq_idx]); } + ath12k_pci_ext_grp_disable(irq_grp); } return 0; } +static int ath12k_pci_set_irq_affinity_hint(struct ath12k_pci *ab_pci, + const struct cpumask *m) +{ + if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return 0; + + return irq_set_affinity_hint(ab_pci->pdev->irq, m); +} + static int ath12k_pci_config_irq(struct ath12k_base *ab) { + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); struct ath12k_ce_pipe *ce_pipe; u32 msi_data_start; u32 msi_data_count, msi_data_idx; @@ -589,7 +657,7 @@ static int ath12k_pci_config_irq(struct ath12k_base *ab) tasklet_setup(&ce_pipe->intr_tq, ath12k_pci_ce_tasklet); ret = request_irq(irq, ath12k_pci_ce_interrupt_handler, - IRQF_SHARED, irq_name[irq_idx], + ab_pci->irq_flags, irq_name[irq_idx], ce_pipe); if (ret) { ath12k_err(ab, "failed to request irq %d: %d\n", @@ -626,6 +694,8 @@ static void ath12k_pci_ce_irqs_enable(struct ath12k_base *ab) { int i; + set_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ab->hw_params->ce_count; i++) { if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; @@ -670,16 +740,27 @@ static int ath12k_pci_msi_alloc(struct ath12k_pci *ab_pci) msi_config->total_vectors, msi_config->total_vectors, PCI_IRQ_MSI); - if (num_vectors != msi_config->total_vectors) { - ath12k_err(ab, "failed to get %d MSI vectors, only %d available", - msi_config->total_vectors, num_vectors); - if (num_vectors >= 0) - return -EINVAL; - else - return num_vectors; + if (num_vectors == msi_config->total_vectors) { + set_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); + ab_pci->irq_flags = IRQF_SHARED; + } else { + num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, + 1, + 1, + PCI_IRQ_MSI); + if (num_vectors < 0) { + ret = -EINVAL; + goto reset_msi_config; + } + clear_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); + ab_pci->msi_config = &msi_config_one_msi; + ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + ath12k_dbg(ab, ATH12K_DBG_PCI, "request MSI one vector\n"); } + ath12k_info(ab, "MSI vectors: %d\n", num_vectors); + ath12k_pci_msi_disable(ab_pci); msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); @@ -700,6 +781,7 @@ static int ath12k_pci_msi_alloc(struct ath12k_pci *ab_pci) free_msi_vector: pci_free_irq_vectors(ab_pci->pdev); +reset_msi_config: return ret; } @@ -708,6 +790,25 @@ static void ath12k_pci_msi_free(struct ath12k_pci *ab_pci) pci_free_irq_vectors(ab_pci->pdev); } +static int ath12k_pci_config_msi_data(struct ath12k_pci *ab_pci) +{ + struct msi_desc *msi_desc; + + msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); + if (!msi_desc) { + ath12k_err(ab_pci->ab, "msi_desc is NULL!\n"); + pci_free_irq_vectors(ab_pci->pdev); + return -EINVAL; + } + + ab_pci->msi_ep_base_data = msi_desc->msg.data; + + ath12k_dbg(ab_pci->ab, ATH12K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", + ab_pci->msi_ep_base_data); + + return 0; +} + static int ath12k_pci_claim(struct ath12k_pci *ab_pci, struct pci_dev *pdev) { struct ath12k_base *ab = ab_pci->ab; @@ -891,11 +992,11 @@ int ath12k_pci_get_user_msi_assignment(struct ath12k_base *ab, char *user_name, for (idx = 0; idx < msi_config->total_users; idx++) { if (strcmp(user_name, msi_config->users[idx].name) == 0) { *num_vectors = msi_config->users[idx].num_vectors; - *user_base_data = msi_config->users[idx].base_vector - + ab_pci->msi_ep_base_data; - *base_vector = msi_config->users[idx].base_vector; + *base_vector = msi_config->users[idx].base_vector; + *user_base_data = *base_vector + ab_pci->msi_ep_base_data; - ath12k_dbg(ab, ATH12K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", + ath12k_dbg(ab, ATH12K_DBG_PCI, + "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", user_name, *num_vectors, *user_base_data, *base_vector); @@ -956,6 +1057,8 @@ void ath12k_pci_ext_irq_enable(struct ath12k_base *ab) { int i; + set_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; @@ -1000,7 +1103,10 @@ int ath12k_pci_start(struct ath12k_base *ab) set_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags); - ath12k_pci_aspm_restore(ab_pci); + if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + ath12k_pci_aspm_restore(ab_pci); + else + ath12k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); ath12k_pci_ce_irqs_enable(ab); ath12k_ce_rx_post_buf(ab); @@ -1262,10 +1368,16 @@ static int ath12k_pci_probe(struct pci_dev *pdev, if (ret) goto err_pci_msi_free; + ret = ath12k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); + if (ret) { + ath12k_err(ab, "failed to set irq affinity %d\n", ret); + goto err_pci_msi_free; + } + ret = ath12k_mhi_register(ab_pci); if (ret) { ath12k_err(ab, "failed to register mhi: %d\n", ret); - goto err_pci_msi_free; + goto err_irq_affinity_cleanup; } ret = ath12k_hal_srng_init(ab); @@ -1286,6 +1398,17 @@ static int ath12k_pci_probe(struct pci_dev *pdev, goto err_ce_free; } + /* kernel may allocate a dummy vector before request_irq and + * then allocate a real vector when request_irq is called. + * So get msi_data here again to avoid spurious interrupt + * as msi_data will configured to srngs. + */ + ret = ath12k_pci_config_msi_data(ab_pci); + if (ret) { + ath12k_err(ab, "failed to config msi_data: %d\n", ret); + goto err_free_irq; + } + ret = ath12k_core_init(ab); if (ret) { ath12k_err(ab, "failed to init core: %d\n", ret); @@ -1308,6 +1431,9 @@ err_mhi_unregister: err_pci_msi_free: ath12k_pci_msi_free(ab_pci); +err_irq_affinity_cleanup: + ath12k_pci_set_irq_affinity_hint(ab_pci, NULL); + err_pci_free_region: ath12k_pci_free_region(ab_pci); @@ -1322,6 +1448,8 @@ static void ath12k_pci_remove(struct pci_dev *pdev) struct ath12k_base *ab = pci_get_drvdata(pdev); struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + ath12k_pci_set_irq_affinity_hint(ab_pci, NULL); + if (test_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags)) { ath12k_pci_power_down(ab); ath12k_qmi_deinit_service(ab); @@ -1348,7 +1476,9 @@ qmi_fail: static void ath12k_pci_shutdown(struct pci_dev *pdev) { struct ath12k_base *ab = pci_get_drvdata(pdev); + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + ath12k_pci_set_irq_affinity_hint(ab_pci, NULL); ath12k_pci_power_down(ab); } diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index 9a17a7dcdd..b2edf32ada 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -84,6 +84,7 @@ enum ath12k_pci_flags { ATH12K_PCI_FLAG_INIT_DONE, ATH12K_PCI_FLAG_IS_MSI_64, ATH12K_PCI_ASPM_RESTORE, + ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, }; struct ath12k_pci_ops { @@ -108,6 +109,7 @@ struct ath12k_pci { /* enum ath12k_pci_flags */ unsigned long flags; u16 link_ctl; + unsigned long irq_flags; const struct ath12k_pci_ops *pci_ops; }; diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 1dac843980..29542c46b0 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -28,11 +28,11 @@ static const struct ieee80211_regdomain ath12k_world_regd = { } }; -static bool ath12k_regdom_changes(struct ath12k *ar, char *alpha2) +static bool ath12k_regdom_changes(struct ieee80211_hw *hw, char *alpha2) { const struct ieee80211_regdomain *regd; - regd = rcu_dereference_rtnl(ar->hw->wiphy->regd); + regd = rcu_dereference_rtnl(hw->wiphy->regd); /* This can happen during wiphy registration where the previous * user request is received before we update the regd received * from firmware. @@ -71,7 +71,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) return; } - if (!ath12k_regdom_changes(ar, request->alpha2)) { + if (!ath12k_regdom_changes(hw, request->alpha2)) { ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Country is already set\n"); return; } @@ -199,6 +199,7 @@ static void ath12k_copy_regd(struct ieee80211_regdomain *regd_orig, int ath12k_regd_update(struct ath12k *ar, bool init) { + struct ieee80211_hw *hw = ar->hw; struct ieee80211_regdomain *regd, *regd_copy = NULL; int ret, regd_len, pdev_id; struct ath12k_base *ab; @@ -246,9 +247,9 @@ int ath12k_regd_update(struct ath12k *ar, bool init) } rtnl_lock(); - wiphy_lock(ar->hw->wiphy); - ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy); - wiphy_unlock(ar->hw->wiphy); + wiphy_lock(hw->wiphy); + ret = regulatory_set_wiphy_regd_sync(hw->wiphy, regd_copy); + wiphy_unlock(hw->wiphy); rtnl_unlock(); kfree(regd_copy); @@ -729,10 +730,10 @@ void ath12k_regd_update_work(struct work_struct *work) } } -void ath12k_reg_init(struct ath12k *ar) +void ath12k_reg_init(struct ieee80211_hw *hw) { - ar->hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED; - ar->hw->wiphy->reg_notifier = ath12k_reg_notifier; + hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED; + hw->wiphy->reg_notifier = ath12k_reg_notifier; } void ath12k_reg_free(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h index d4a0776e10..29c7ec3260 100644 --- a/drivers/net/wireless/ath/ath12k/reg.h +++ b/drivers/net/wireless/ath/ath12k/reg.h @@ -89,7 +89,7 @@ enum ath12k_reg_phy_bitmap { ATH12K_REG_PHY_BITMAP_NO11BE = BIT(6), }; -void ath12k_reg_init(struct ath12k *ar); +void ath12k_reg_init(struct ieee80211_hw *hw); void ath12k_reg_free(struct ath12k_base *ab); void ath12k_regd_update_work(struct work_struct *work); struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab, diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 629373d674..06e5b9b404 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_WMI_H @@ -1146,25 +1146,27 @@ enum wmi_tlv_vdev_param { }; enum wmi_tlv_peer_flags { - WMI_TLV_PEER_AUTH = 0x00000001, - WMI_TLV_PEER_QOS = 0x00000002, - WMI_TLV_PEER_NEED_PTK_4_WAY = 0x00000004, - WMI_TLV_PEER_NEED_GTK_2_WAY = 0x00000010, - WMI_TLV_PEER_APSD = 0x00000800, - WMI_TLV_PEER_HT = 0x00001000, - WMI_TLV_PEER_40MHZ = 0x00002000, - WMI_TLV_PEER_STBC = 0x00008000, - WMI_TLV_PEER_LDPC = 0x00010000, - WMI_TLV_PEER_DYN_MIMOPS = 0x00020000, - WMI_TLV_PEER_STATIC_MIMOPS = 0x00040000, - WMI_TLV_PEER_SPATIAL_MUX = 0x00200000, - WMI_TLV_PEER_VHT = 0x02000000, - WMI_TLV_PEER_80MHZ = 0x04000000, - WMI_TLV_PEER_PMF = 0x08000000, + WMI_PEER_AUTH = 0x00000001, + WMI_PEER_QOS = 0x00000002, + WMI_PEER_NEED_PTK_4_WAY = 0x00000004, + WMI_PEER_NEED_GTK_2_WAY = 0x00000010, + WMI_PEER_HE = 0x00000400, + WMI_PEER_APSD = 0x00000800, + WMI_PEER_HT = 0x00001000, + WMI_PEER_40MHZ = 0x00002000, + WMI_PEER_STBC = 0x00008000, + WMI_PEER_LDPC = 0x00010000, + WMI_PEER_DYN_MIMOPS = 0x00020000, + WMI_PEER_STATIC_MIMOPS = 0x00040000, + WMI_PEER_SPATIAL_MUX = 0x00200000, + WMI_PEER_TWT_REQ = 0x00400000, + WMI_PEER_TWT_RESP = 0x00800000, + WMI_PEER_VHT = 0x02000000, + WMI_PEER_80MHZ = 0x04000000, + WMI_PEER_PMF = 0x08000000, WMI_PEER_IS_P2P_CAPABLE = 0x20000000, WMI_PEER_160MHZ = 0x40000000, WMI_PEER_SAFEMODE_EN = 0x80000000, - }; enum wmi_tlv_peer_flags_ext { @@ -2220,6 +2222,7 @@ enum wmi_peer_chwidth { WMI_PEER_CHWIDTH_40MHZ = 1, WMI_PEER_CHWIDTH_80MHZ = 2, WMI_PEER_CHWIDTH_160MHZ = 3, + WMI_PEER_CHWIDTH_320MHZ = 4, }; enum wmi_beacon_gen_mode { @@ -3844,31 +3847,6 @@ struct wmi_unit_test_cmd { #define MAX_SUPPORTED_RATES 128 -#define WMI_PEER_AUTH 0x00000001 -#define WMI_PEER_QOS 0x00000002 -#define WMI_PEER_NEED_PTK_4_WAY 0x00000004 -#define WMI_PEER_NEED_GTK_2_WAY 0x00000010 -#define WMI_PEER_HE 0x00000400 -#define WMI_PEER_APSD 0x00000800 -#define WMI_PEER_HT 0x00001000 -#define WMI_PEER_40MHZ 0x00002000 -#define WMI_PEER_STBC 0x00008000 -#define WMI_PEER_LDPC 0x00010000 -#define WMI_PEER_DYN_MIMOPS 0x00020000 -#define WMI_PEER_STATIC_MIMOPS 0x00040000 -#define WMI_PEER_SPATIAL_MUX 0x00200000 -#define WMI_PEER_TWT_REQ 0x00400000 -#define WMI_PEER_TWT_RESP 0x00800000 -#define WMI_PEER_VHT 0x02000000 -#define WMI_PEER_80MHZ 0x04000000 -#define WMI_PEER_PMF 0x08000000 -/* TODO: Place holder for WLAN_PEER_F_PS_PRESEND_REQUIRED = 0x10000000. - * Need to be cleaned up - */ -#define WMI_PEER_IS_P2P_CAPABLE 0x20000000 -#define WMI_PEER_160MHZ 0x40000000 -#define WMI_PEER_SAFEMODE_EN 0x80000000 - struct ath12k_wmi_vht_rate_set_params { __le32 tlv_header; __le32 rx_max_rate; @@ -4770,7 +4748,6 @@ struct wmi_probe_tmpl_cmd { struct ath12k_wmi_pdev { struct ath12k_wmi_base *wmi_ab; enum ath12k_htc_ep_id eid; - const struct wmi_peer_flags_map *peer_flags; u32 rx_decap_mode; }; @@ -4784,7 +4761,6 @@ struct ath12k_wmi_base { struct completion unified_ready; DECLARE_BITMAP(svc_map, WMI_MAX_EXT2_SERVICE); wait_queue_head_t tx_credits_wq; - const struct wmi_peer_flags_map *peer_flags; u32 num_mem_chunks; u32 rx_decap_mode; struct ath12k_wmi_host_mem_chunk_arg mem_chunks[WMI_MAX_MEM_REQS]; diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 08bd5d3b00..f27308ccb2 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -185,7 +185,7 @@ static int ath_ahb_probe(struct platform_device *pdev) return ret; } -static int ath_ahb_remove(struct platform_device *pdev) +static void ath_ahb_remove(struct platform_device *pdev) { struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev); struct ieee80211_hw *hw = platform_get_drvdata(pdev); @@ -193,7 +193,7 @@ static int ath_ahb_remove(struct platform_device *pdev) u32 reg; if (!hw) - return 0; + return; ah = hw->priv; @@ -215,13 +215,11 @@ static int ath_ahb_remove(struct platform_device *pdev) ath5k_deinit_ah(ah); iounmap(ah->iobase); ieee80211_free_hw(hw); - - return 0; } static struct platform_driver ath_ahb_driver = { .probe = ath_ahb_probe, - .remove = ath_ahb_remove, + .remove_new = ath_ahb_remove, .driver = { .name = "ar231x-wmac", }, diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 693296ee96..e85b713950 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -489,7 +489,4 @@ struct ath5k_eeprom_info { /* Spur mitigation data (fbin values for spur channels) */ u16 ee_spur_chans[AR5K_EEPROM_N_SPUR_CHANS][AR5K_EEPROM_N_FREQ_BANDS]; - - /* Antenna raw switch tables */ - u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; }; diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 988222cea9..acc84e6711 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -643,7 +643,7 @@ static void ath_ant_try_scan(struct ath_ant_comb *antcomb, conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; } else if (antcomb->rssi_sub > - antcomb->rssi_lna1) { + antcomb->rssi_lna2) { /* set to A-B */ conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; diff --git a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c index 708c8969b5..a5eb43f303 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c +++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c @@ -125,7 +125,7 @@ static void owl_rescan(struct pci_dev *pdev) static void owl_fw_cb(const struct firmware *fw, void *context) { - struct owl_ctx *ctx = (struct owl_ctx *)context; + struct owl_ctx *ctx = context; complete(&ctx->eeprom_load); diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c index 82de0fadbc..7c13a1deb3 100644 --- a/drivers/net/wireless/ath/ath9k/common-init.c +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -124,7 +124,7 @@ static struct ieee80211_rate ath9k_legacy_rates[] = { int ath9k_cmn_init_channels_rates(struct ath_common *common) { - struct ath_hw *ah = (struct ath_hw *)common->ah; + struct ath_hw *ah = common->ah; void *channels; BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index a5349c72c3..4b27445a5f 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -471,7 +471,7 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0}; struct ath_hw *ah = spec_priv->ah; struct ath_common *common = ath9k_hw_common(spec_priv->ah); - struct ath_softc *sc = (struct ath_softc *)common->priv; + struct ath_softc *sc = common->priv; u8 num_bins, *vdata = (u8 *)hdr; struct ath_radar_info *radar_info; int len = rs->rs_datalen; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index a0376a6787..d84e3ee7b5 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1376,7 +1376,7 @@ void ath9k_deinit_debug(struct ath_softc *sc) int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; sc->debug.debugfs_phy = debugfs_create_dir("ath9k", sc->hw->wiphy->debugfsdir); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 90cfe39aa4..0c7841f952 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -70,7 +70,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev); static void hif_usb_regout_cb(struct urb *urb) { - struct cmd_buf *cmd = (struct cmd_buf *)urb->context; + struct cmd_buf *cmd = urb->context; switch (urb->status) { case 0: @@ -134,7 +134,7 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev, static void hif_usb_mgmt_cb(struct urb *urb) { - struct cmd_buf *cmd = (struct cmd_buf *)urb->context; + struct cmd_buf *cmd = urb->context; struct hif_device_usb *hif_dev; unsigned long flags; bool txok = true; @@ -252,7 +252,7 @@ static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev, static void hif_usb_tx_cb(struct urb *urb) { - struct tx_buf *tx_buf = (struct tx_buf *) urb->context; + struct tx_buf *tx_buf = urb->context; struct hif_device_usb *hif_dev; bool txok = true; @@ -687,7 +687,7 @@ invalid_pkt: static void ath9k_hif_usb_rx_cb(struct urb *urb) { - struct rx_buf *rx_buf = (struct rx_buf *)urb->context; + struct rx_buf *rx_buf = urb->context; struct hif_device_usb *hif_dev = rx_buf->hif_dev; struct sk_buff *skb = rx_buf->skb; int ret; @@ -734,7 +734,7 @@ free: static void ath9k_hif_usb_reg_in_cb(struct urb *urb) { - struct rx_buf *rx_buf = (struct rx_buf *)urb->context; + struct rx_buf *rx_buf = urb->context; struct hif_device_usb *hif_dev = rx_buf->hif_dev; struct sk_buff *skb = rx_buf->skb; int ret; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 278ddc713f..f7c6d9bc93 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -482,7 +482,7 @@ void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) int ath9k_htc_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, priv->hw->wiphy->debugfsdir); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index fc339079ee..3633f9eb2c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -63,12 +63,12 @@ static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { static void ath9k_htc_op_ps_wakeup(struct ath_common *common) { - ath9k_htc_ps_wakeup((struct ath9k_htc_priv *) common->priv); + ath9k_htc_ps_wakeup(common->priv); } static void ath9k_htc_op_ps_restore(struct ath_common *common) { - ath9k_htc_ps_restore((struct ath9k_htc_priv *) common->priv); + ath9k_htc_ps_restore(common->priv); } static const struct ath_ps_ops ath9k_htc_ps_ops = { @@ -235,7 +235,7 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; __be32 val, reg = cpu_to_be32(reg_offset); int r; @@ -257,7 +257,7 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr, { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; __be32 tmpaddr[8]; __be32 tmpval[8]; int i, ret; @@ -282,7 +282,7 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr, static void ath9k_regwrite_multi(struct ath_common *common) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; u32 rsp_status; int r; @@ -303,7 +303,7 @@ static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; const __be32 buf[2] = { cpu_to_be32(reg_offset), cpu_to_be32(val), @@ -324,7 +324,7 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; mutex_lock(&priv->wmi->multi_write_mutex); @@ -347,7 +347,7 @@ static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; if (atomic_read(&priv->wmi->mwrite_cnt)) ath9k_regwrite_buffer(hw_priv, val, reg_offset); @@ -359,7 +359,7 @@ static void ath9k_enable_regwrite_buffer(void *hw_priv) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; atomic_inc(&priv->wmi->mwrite_cnt); } @@ -368,7 +368,7 @@ static void ath9k_regwrite_flush(void *hw_priv) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; atomic_dec(&priv->wmi->mwrite_cnt); @@ -385,7 +385,7 @@ static void ath9k_reg_rmw_buffer(void *hw_priv, { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; u32 rsp_status; int r; @@ -423,7 +423,7 @@ static void ath9k_reg_rmw_flush(void *hw_priv) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; u32 rsp_status; int r; @@ -455,7 +455,7 @@ static void ath9k_enable_rmw_buffer(void *hw_priv) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) return; @@ -468,7 +468,7 @@ static void ath9k_reg_rmw_single(void *hw_priv, { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; struct register_rmw buf, buf_ret; int ret; @@ -490,7 +490,7 @@ static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) { u32 val; @@ -518,7 +518,7 @@ static void ath_usb_read_cachesize(struct ath_common *common, int *csz) static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_hw *ah = (struct ath_hw *) common->ah; + struct ath_hw *ah = common->ah; (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); @@ -974,7 +974,7 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, err_init: ath9k_stop_wmi(priv); - hif_dev = (struct hif_device_usb *)htc_handle->hif_dev; + hif_dev = htc_handle->hif_dev; ath9k_hif_usb_dealloc_urbs(hif_dev); ath9k_destroy_wmi(priv); err_free: @@ -992,7 +992,7 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug) ath9k_deinit_device(htc_handle->drv_priv); ath9k_stop_wmi(htc_handle->drv_priv); - ath9k_hif_usb_dealloc_urbs((struct hif_device_usb *)htc_handle->hif_dev); + ath9k_hif_usb_dealloc_urbs(htc_handle->hif_dev); ath9k_destroy_wmi(htc_handle->drv_priv); ieee80211_free_hw(htc_handle->drv_priv->hw); } diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 99667aba28..eb631fd333 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -89,7 +89,7 @@ static void htc_process_target_rdy(struct htc_target *target, void *buf) { struct htc_endpoint *endpoint; - struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf; + struct htc_ready_msg *htc_ready_msg = buf; target->credit_size = be16_to_cpu(htc_ready_msg->credit_size); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 4f00400c7f..7fad7e75af 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -151,12 +151,12 @@ static void ath9k_deinit_softc(struct ath_softc *sc); static void ath9k_op_ps_wakeup(struct ath_common *common) { - ath9k_ps_wakeup((struct ath_softc *) common->priv); + ath9k_ps_wakeup(common->priv); } static void ath9k_op_ps_restore(struct ath_common *common) { - ath9k_ps_restore((struct ath_softc *) common->priv); + ath9k_ps_restore(common->priv); } static const struct ath_ps_ops ath9k_ps_ops = { @@ -174,7 +174,7 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { unsigned long flags; @@ -189,7 +189,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; u32 val; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { @@ -229,7 +229,7 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl { struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; unsigned long flags; u32 val; @@ -608,7 +608,7 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc) } /* devres manages the calibration values release on shutdown */ - ah->nvmem_blob = (u16 *)devm_kmemdup(sc->dev, buf, len, GFP_KERNEL); + ah->nvmem_blob = devm_kmemdup(sc->dev, buf, len, GFP_KERNEL); kfree(buf); if (!ah->nvmem_blob) return -ENOMEM; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 9d84003db8..d1e5767aab 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -304,7 +304,7 @@ fail_paprd: void ath_ani_calibrate(struct timer_list *t) { struct ath_common *common = from_timer(common, t, ani.timer); - struct ath_softc *sc = (struct ath_softc *)common->priv; + struct ath_softc *sc = common->priv; struct ath_hw *ah = sc->sc_ah; bool longcal = false; bool shortcal = false; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1494feedb2..c48ff0ffbf 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2383,7 +2383,22 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct cfg80211_chan_def *chandef = &sc->cur_chan->chandef; + struct ieee80211_channel *chan = chandef->chan; + int pos = chan->hw_value; set_bit(ATH_OP_SCANNING, &common->op_flags); + + /* Reset current survey */ + if (!sc->cur_chan->offchannel) { + if (sc->cur_survey != &sc->survey[pos]) { + if (sc->cur_survey) + sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; + sc->cur_survey = &sc->survey[pos]; + } + + memset(sc->cur_survey, 0, sizeof(struct survey_info)); + sc->cur_survey->filled |= SURVEY_INFO_IN_USE; + } } static void ath9k_sw_scan_complete(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 0633589b85..e655cd8bbf 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -781,7 +781,7 @@ static const struct pci_device_id ath_pci_id_table[] = { /* return bus cachesize in 4B word units */ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) { - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; u8 u8tmp; pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp); @@ -799,7 +799,7 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_hw *ah = (struct ath_hw *) common->ah; + struct ath_hw *ah = common->ah; common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); @@ -820,7 +820,7 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) /* Need to be called after we discover btcoex capabilities */ static void ath_pci_aspm_init(struct ath_common *common) { - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; struct ath_hw *ah = sc->sc_ah; struct pci_dev *pdev = to_pci_dev(sc->dev); struct pci_dev *parent; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 2bd1163177..4e6b4df856 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1644,7 +1644,7 @@ out_err: return ret; } -static int wcn36xx_remove(struct platform_device *pdev) +static void wcn36xx_remove(struct platform_device *pdev) { struct ieee80211_hw *hw = platform_get_drvdata(pdev); struct wcn36xx *wcn = hw->priv; @@ -1666,8 +1666,6 @@ static int wcn36xx_remove(struct platform_device *pdev) mutex_destroy(&wcn->hal_mutex); ieee80211_free_hw(hw); - - return 0; } static const struct of_device_id wcn36xx_of_match[] = { @@ -1678,7 +1676,7 @@ MODULE_DEVICE_TABLE(of, wcn36xx_of_match); static struct platform_driver wcn36xx_driver = { .probe = wcn36xx_probe, - .remove = wcn36xx_remove, + .remove_new = wcn36xx_remove, .driver = { .name = "wcn36xx", .of_match_table = wcn36xx_of_match, @@ -1687,6 +1685,7 @@ static struct platform_driver wcn36xx_driver = { module_platform_driver(wcn36xx_driver); +MODULE_DESCRIPTION("Qualcomm Atheros WCN3660/3680 wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com"); MODULE_FIRMWARE(WLAN_NV_FILE); diff --git a/drivers/net/wireless/atmel/Kconfig b/drivers/net/wireless/atmel/Kconfig index bafdd57b04..7a2bb7a58a 100644 --- a/drivers/net/wireless/atmel/Kconfig +++ b/drivers/net/wireless/atmel/Kconfig @@ -12,41 +12,6 @@ config WLAN_VENDOR_ATMEL if WLAN_VENDOR_ATMEL -config ATMEL - tristate "Atmel at76c50x chipset 802.11b support" - depends on CFG80211 && (PCI || PCMCIA) && HAS_IOPORT - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - select CRC32 - help - A driver 802.11b wireless cards based on the Atmel fast-vnet - chips. This driver supports standard Linux wireless extensions. - - Many cards based on this chipset do not have flash memory - and need their firmware loaded at start-up. If yours is - one of these, you will need to provide a firmware image - to be loaded into the card by the driver. The Atmel - firmware package can be downloaded from - <http://www.thekelleys.org.uk/atmel> - -config PCI_ATMEL - tristate "Atmel at76c506 PCI cards" - depends on ATMEL && PCI - help - Enable support for PCI and mini-PCI cards containing the - Atmel at76c506 chip. - -config PCMCIA_ATMEL - tristate "Atmel at76c502/at76c504 PCMCIA cards" - depends on ATMEL && PCMCIA - select WIRELESS_EXT - select FW_LOADER - select CRC32 - help - Enable support for PCMCIA cards containing the - Atmel at76c502 and at76c504 chips. - config AT76C50X_USB tristate "Atmel at76c503/at76c505/at76c505a USB cards" depends on MAC80211 && USB diff --git a/drivers/net/wireless/atmel/Makefile b/drivers/net/wireless/atmel/Makefile index 17e6280567..8338d7098b 100644 --- a/drivers/net/wireless/atmel/Makefile +++ b/drivers/net/wireless/atmel/Makefile @@ -1,6 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_ATMEL) += atmel.o -obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o -obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o - obj-$(CONFIG_AT76C50X_USB) += at76c50x-usb.o diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c deleted file mode 100644 index 461dce21de..0000000000 --- a/drivers/net/wireless/atmel/atmel.c +++ /dev/null @@ -1,4452 +0,0 @@ -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2000-2001 ATMEL Corporation. - Copyright 2003-2004 Simon Kelley. - - This code was developed from version 2.1.1 of the Atmel drivers, - released by Atmel corp. under the GPL in December 2002. It also - includes code from the Linux aironet drivers (C) Benjamin Reed, - and the Linux PCMCIA package, (C) David Hinds and the Linux wireless - extensions, (C) Jean Tourrilhes. - - The firmware module for reading the MAC address of the card comes from - net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright - by him. net.russotto.AtmelMACFW is used under the GPL license version 2. - This file contains the module in binary form and, under the terms - of the GPL, in source form. The source is located at the end of the file. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This software is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Atmel wireless lan drivers; if not, see - <http://www.gnu.org/licenses/>. - - For all queries about this code, please contact the current author, - Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation. - - Credit is due to HP UK and Cambridge Online Systems Ltd for supplying - hardware used during development of this driver. - -******************************************************************************/ - -#include <linux/interrupt.h> - -#include <linux/kernel.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <asm/byteorder.h> -#include <asm/io.h> -#include <linux/uaccess.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/if_arp.h> -#include <linux/ioport.h> -#include <linux/fcntl.h> -#include <linux/delay.h> -#include <linux/wireless.h> -#include <net/iw_handler.h> -#include <linux/crc32.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/device.h> -#include <linux/moduleparam.h> -#include <linux/firmware.h> -#include <linux/jiffies.h> -#include <net/cfg80211.h> -#include "atmel.h" - -#define DRIVER_MAJOR 0 -#define DRIVER_MINOR 98 - -MODULE_AUTHOR("Simon Kelley"); -MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); -MODULE_LICENSE("GPL"); - -/* The name of the firmware file to be loaded - over-rides any automatic selection */ -static char *firmware = NULL; -module_param(firmware, charp, 0); - -/* table of firmware file names */ -static struct { - AtmelFWType fw_type; - const char *fw_file; - const char *fw_file_ext; -} fw_table[] = { - { ATMEL_FW_TYPE_502, "atmel_at76c502", "bin" }, - { ATMEL_FW_TYPE_502D, "atmel_at76c502d", "bin" }, - { ATMEL_FW_TYPE_502E, "atmel_at76c502e", "bin" }, - { ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" }, - { ATMEL_FW_TYPE_504, "atmel_at76c504", "bin" }, - { ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" }, - { ATMEL_FW_TYPE_504A_2958, "atmel_at76c504a_2958", "bin" }, - { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, - { ATMEL_FW_TYPE_NONE, NULL, NULL } -}; -MODULE_FIRMWARE("atmel_at76c502-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502.bin"); -MODULE_FIRMWARE("atmel_at76c502d-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502d.bin"); -MODULE_FIRMWARE("atmel_at76c502e-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502e.bin"); -MODULE_FIRMWARE("atmel_at76c502_3com-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c502_3com.bin"); -MODULE_FIRMWARE("atmel_at76c504-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c504.bin"); -MODULE_FIRMWARE("atmel_at76c504_2958-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c504_2958.bin"); -MODULE_FIRMWARE("atmel_at76c504a_2958-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c504a_2958.bin"); -MODULE_FIRMWARE("atmel_at76c506-wpa.bin"); -MODULE_FIRMWARE("atmel_at76c506.bin"); - -#define MAX_SSID_LENGTH 32 -#define MGMT_JIFFIES (256 * HZ / 100) - -#define MAX_BSS_ENTRIES 64 - -/* registers */ -#define GCR 0x00 /* (SIR0) General Configuration Register */ -#define BSR 0x02 /* (SIR1) Bank Switching Select Register */ -#define AR 0x04 -#define DR 0x08 -#define MR1 0x12 /* Mirror Register 1 */ -#define MR2 0x14 /* Mirror Register 2 */ -#define MR3 0x16 /* Mirror Register 3 */ -#define MR4 0x18 /* Mirror Register 4 */ - -#define GPR1 0x0c -#define GPR2 0x0e -#define GPR3 0x10 -/* - * Constants for the GCR register. - */ -#define GCR_REMAP 0x0400 /* Remap internal SRAM to 0 */ -#define GCR_SWRES 0x0080 /* BIU reset (ARM and PAI are NOT reset) */ -#define GCR_CORES 0x0060 /* Core Reset (ARM and PAI are reset) */ -#define GCR_ENINT 0x0002 /* Enable Interrupts */ -#define GCR_ACKINT 0x0008 /* Acknowledge Interrupts */ - -#define BSS_SRAM 0x0200 /* AMBA module selection --> SRAM */ -#define BSS_IRAM 0x0100 /* AMBA module selection --> IRAM */ -/* - *Constants for the MR registers. - */ -#define MAC_INIT_COMPLETE 0x0001 /* MAC init has been completed */ -#define MAC_BOOT_COMPLETE 0x0010 /* MAC boot has been completed */ -#define MAC_INIT_OK 0x0002 /* MAC boot has been completed */ - -#define MIB_MAX_DATA_BYTES 212 -#define MIB_HEADER_SIZE 4 /* first four fields */ - -struct get_set_mib { - u8 type; - u8 size; - u8 index; - u8 reserved; - u8 data[MIB_MAX_DATA_BYTES]; -}; - -struct rx_desc { - u32 Next; - u16 MsduPos; - u16 MsduSize; - - u8 State; - u8 Status; - u8 Rate; - u8 Rssi; - u8 LinkQuality; - u8 PreambleType; - u16 Duration; - u32 RxTime; -}; - -#define RX_DESC_FLAG_VALID 0x80 -#define RX_DESC_FLAG_CONSUMED 0x40 -#define RX_DESC_FLAG_IDLE 0x00 - -#define RX_STATUS_SUCCESS 0x00 - -#define RX_DESC_MSDU_POS_OFFSET 4 -#define RX_DESC_MSDU_SIZE_OFFSET 6 -#define RX_DESC_FLAGS_OFFSET 8 -#define RX_DESC_STATUS_OFFSET 9 -#define RX_DESC_RSSI_OFFSET 11 -#define RX_DESC_LINK_QUALITY_OFFSET 12 -#define RX_DESC_PREAMBLE_TYPE_OFFSET 13 -#define RX_DESC_DURATION_OFFSET 14 -#define RX_DESC_RX_TIME_OFFSET 16 - -struct tx_desc { - u32 NextDescriptor; - u16 TxStartOfFrame; - u16 TxLength; - - u8 TxState; - u8 TxStatus; - u8 RetryCount; - - u8 TxRate; - - u8 KeyIndex; - u8 ChiperType; - u8 ChipreLength; - u8 Reserved1; - - u8 Reserved; - u8 PacketType; - u16 HostTxLength; -}; - -#define TX_DESC_NEXT_OFFSET 0 -#define TX_DESC_POS_OFFSET 4 -#define TX_DESC_SIZE_OFFSET 6 -#define TX_DESC_FLAGS_OFFSET 8 -#define TX_DESC_STATUS_OFFSET 9 -#define TX_DESC_RETRY_OFFSET 10 -#define TX_DESC_RATE_OFFSET 11 -#define TX_DESC_KEY_INDEX_OFFSET 12 -#define TX_DESC_CIPHER_TYPE_OFFSET 13 -#define TX_DESC_CIPHER_LENGTH_OFFSET 14 -#define TX_DESC_PACKET_TYPE_OFFSET 17 -#define TX_DESC_HOST_LENGTH_OFFSET 18 - -/* - * Host-MAC interface - */ - -#define TX_STATUS_SUCCESS 0x00 - -#define TX_FIRM_OWN 0x80 -#define TX_DONE 0x40 - -#define TX_ERROR 0x01 - -#define TX_PACKET_TYPE_DATA 0x01 -#define TX_PACKET_TYPE_MGMT 0x02 - -#define ISR_EMPTY 0x00 /* no bits set in ISR */ -#define ISR_TxCOMPLETE 0x01 /* packet transmitted */ -#define ISR_RxCOMPLETE 0x02 /* packet received */ -#define ISR_RxFRAMELOST 0x04 /* Rx Frame lost */ -#define ISR_FATAL_ERROR 0x08 /* Fatal error */ -#define ISR_COMMAND_COMPLETE 0x10 /* command completed */ -#define ISR_OUT_OF_RANGE 0x20 /* command completed */ -#define ISR_IBSS_MERGE 0x40 /* (4.1.2.30): IBSS merge */ -#define ISR_GENERIC_IRQ 0x80 - -#define Local_Mib_Type 0x01 -#define Mac_Address_Mib_Type 0x02 -#define Mac_Mib_Type 0x03 -#define Statistics_Mib_Type 0x04 -#define Mac_Mgmt_Mib_Type 0x05 -#define Mac_Wep_Mib_Type 0x06 -#define Phy_Mib_Type 0x07 -#define Multi_Domain_MIB 0x08 - -#define MAC_MGMT_MIB_CUR_BSSID_POS 14 -#define MAC_MIB_FRAG_THRESHOLD_POS 8 -#define MAC_MIB_RTS_THRESHOLD_POS 10 -#define MAC_MIB_SHORT_RETRY_POS 16 -#define MAC_MIB_LONG_RETRY_POS 17 -#define MAC_MIB_SHORT_RETRY_LIMIT_POS 16 -#define MAC_MGMT_MIB_BEACON_PER_POS 0 -#define MAC_MGMT_MIB_STATION_ID_POS 6 -#define MAC_MGMT_MIB_CUR_PRIVACY_POS 11 -#define MAC_MGMT_MIB_CUR_BSSID_POS 14 -#define MAC_MGMT_MIB_PS_MODE_POS 53 -#define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54 -#define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56 -#define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57 -#define PHY_MIB_CHANNEL_POS 14 -#define PHY_MIB_RATE_SET_POS 20 -#define PHY_MIB_REG_DOMAIN_POS 26 -#define LOCAL_MIB_AUTO_TX_RATE_POS 3 -#define LOCAL_MIB_SSID_SIZE 5 -#define LOCAL_MIB_TX_PROMISCUOUS_POS 6 -#define LOCAL_MIB_TX_MGMT_RATE_POS 7 -#define LOCAL_MIB_TX_CONTROL_RATE_POS 8 -#define LOCAL_MIB_PREAMBLE_TYPE 9 -#define MAC_ADDR_MIB_MAC_ADDR_POS 0 - -#define CMD_Set_MIB_Vars 0x01 -#define CMD_Get_MIB_Vars 0x02 -#define CMD_Scan 0x03 -#define CMD_Join 0x04 -#define CMD_Start 0x05 -#define CMD_EnableRadio 0x06 -#define CMD_DisableRadio 0x07 -#define CMD_SiteSurvey 0x0B - -#define CMD_STATUS_IDLE 0x00 -#define CMD_STATUS_COMPLETE 0x01 -#define CMD_STATUS_UNKNOWN 0x02 -#define CMD_STATUS_INVALID_PARAMETER 0x03 -#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 -#define CMD_STATUS_TIME_OUT 0x07 -#define CMD_STATUS_IN_PROGRESS 0x08 -#define CMD_STATUS_REJECTED_RADIO_OFF 0x09 -#define CMD_STATUS_HOST_ERROR 0xFF -#define CMD_STATUS_BUSY 0xFE - -#define CMD_BLOCK_COMMAND_OFFSET 0 -#define CMD_BLOCK_STATUS_OFFSET 1 -#define CMD_BLOCK_PARAMETERS_OFFSET 4 - -#define SCAN_OPTIONS_SITE_SURVEY 0x80 - -#define MGMT_FRAME_BODY_OFFSET 24 -#define MAX_AUTHENTICATION_RETRIES 3 -#define MAX_ASSOCIATION_RETRIES 3 - -#define AUTHENTICATION_RESPONSE_TIME_OUT 1000 - -#define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */ -#define LOOP_RETRY_LIMIT 500000 - -#define ACTIVE_MODE 1 -#define PS_MODE 2 - -#define MAX_ENCRYPTION_KEYS 4 -#define MAX_ENCRYPTION_KEY_SIZE 40 - -/* - * 802.11 related definitions - */ - -/* - * Regulatory Domains - */ - -#define REG_DOMAIN_FCC 0x10 /* Channels 1-11 USA */ -#define REG_DOMAIN_DOC 0x20 /* Channel 1-11 Canada */ -#define REG_DOMAIN_ETSI 0x30 /* Channel 1-13 Europe (ex Spain/France) */ -#define REG_DOMAIN_SPAIN 0x31 /* Channel 10-11 Spain */ -#define REG_DOMAIN_FRANCE 0x32 /* Channel 10-13 France */ -#define REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ -#define REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan(MKK1) */ -#define REG_DOMAIN_ISRAEL 0x50 /* Channel 3-9 ISRAEL */ - -#define BSS_TYPE_AD_HOC 1 -#define BSS_TYPE_INFRASTRUCTURE 2 - -#define SCAN_TYPE_ACTIVE 0 -#define SCAN_TYPE_PASSIVE 1 - -#define LONG_PREAMBLE 0 -#define SHORT_PREAMBLE 1 -#define AUTO_PREAMBLE 2 - -#define DATA_FRAME_WS_HEADER_SIZE 30 - -/* promiscuous mode control */ -#define PROM_MODE_OFF 0x0 -#define PROM_MODE_UNKNOWN 0x1 -#define PROM_MODE_CRC_FAILED 0x2 -#define PROM_MODE_DUPLICATED 0x4 -#define PROM_MODE_MGMT 0x8 -#define PROM_MODE_CTRL 0x10 -#define PROM_MODE_BAD_PROTOCOL 0x20 - -#define IFACE_INT_STATUS_OFFSET 0 -#define IFACE_INT_MASK_OFFSET 1 -#define IFACE_LOCKOUT_HOST_OFFSET 2 -#define IFACE_LOCKOUT_MAC_OFFSET 3 -#define IFACE_FUNC_CTRL_OFFSET 28 -#define IFACE_MAC_STAT_OFFSET 30 -#define IFACE_GENERIC_INT_TYPE_OFFSET 32 - -#define CIPHER_SUITE_NONE 0 -#define CIPHER_SUITE_WEP_64 1 -#define CIPHER_SUITE_TKIP 2 -#define CIPHER_SUITE_AES 3 -#define CIPHER_SUITE_CCX 4 -#define CIPHER_SUITE_WEP_128 5 - -/* - * IFACE MACROS & definitions - */ - -/* - * FuncCtrl field: - */ -#define FUNC_CTRL_TxENABLE 0x10 -#define FUNC_CTRL_RxENABLE 0x20 -#define FUNC_CTRL_INIT_COMPLETE 0x01 - -/* A stub firmware image which reads the MAC address from NVRAM on the card. - For copyright information and source see the end of this file. */ -static u8 mac_reader[] = { - 0x06, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea, - 0x01, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, - 0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x0e, 0x04, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, - 0x81, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x81, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x90, 0xe5, - 0x10, 0x10, 0xc1, 0xe3, 0x1c, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5, - 0x02, 0x03, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xb0, 0x10, 0xc0, 0xe1, 0xb4, 0x10, 0xc0, 0xe1, - 0xb8, 0x10, 0xc0, 0xe1, 0xbc, 0x10, 0xc0, 0xe1, 0x56, 0xdc, 0xa0, 0xe3, 0x21, 0x00, 0x00, 0xeb, - 0x0a, 0x00, 0xa0, 0xe3, 0x1a, 0x00, 0x00, 0xeb, 0x10, 0x00, 0x00, 0xeb, 0x07, 0x00, 0x00, 0xeb, - 0x02, 0x03, 0xa0, 0xe3, 0x02, 0x14, 0xa0, 0xe3, 0xb4, 0x10, 0xc0, 0xe1, 0x4c, 0x10, 0x9f, 0xe5, - 0xbc, 0x10, 0xc0, 0xe1, 0x10, 0x10, 0xa0, 0xe3, 0xb8, 0x10, 0xc0, 0xe1, 0xfe, 0xff, 0xff, 0xea, - 0x00, 0x40, 0x2d, 0xe9, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x3c, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, - 0x28, 0x00, 0x9f, 0xe5, 0x37, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, - 0x00, 0x40, 0x2d, 0xe9, 0x12, 0x2e, 0xa0, 0xe3, 0x06, 0x30, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, - 0x02, 0x04, 0xa0, 0xe3, 0x2f, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, - 0x00, 0x02, 0x00, 0x02, 0x80, 0x01, 0x90, 0xe0, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe2, - 0xfc, 0xff, 0xff, 0xea, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x10, 0xa0, 0xe3, 0xf3, 0x06, 0xa0, 0xe3, - 0x00, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, - 0x04, 0x10, 0x80, 0xe5, 0x00, 0x10, 0x80, 0xe5, 0x0e, 0x34, 0xa0, 0xe3, 0x1c, 0x10, 0x93, 0xe5, - 0x02, 0x1a, 0x81, 0xe3, 0x1c, 0x10, 0x83, 0xe5, 0x58, 0x11, 0x9f, 0xe5, 0x30, 0x10, 0x80, 0xe5, - 0x54, 0x11, 0x9f, 0xe5, 0x34, 0x10, 0x80, 0xe5, 0x38, 0x10, 0x80, 0xe5, 0x3c, 0x10, 0x80, 0xe5, - 0x10, 0x10, 0x90, 0xe5, 0x08, 0x00, 0x90, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf3, 0x16, 0xa0, 0xe3, - 0x08, 0x00, 0x91, 0xe5, 0x05, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, 0x10, 0x00, 0x91, 0xe5, - 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0xff, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, - 0x10, 0x00, 0x91, 0xe5, 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, - 0x10, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, - 0xff, 0x00, 0x00, 0xe2, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1, - 0x03, 0x40, 0xa0, 0xe1, 0xa2, 0x02, 0xa0, 0xe1, 0x08, 0x00, 0x00, 0xe2, 0x03, 0x00, 0x80, 0xe2, - 0xd8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0xc1, 0xe5, 0x01, 0x20, 0xc1, 0xe5, 0xe2, 0xff, 0xff, 0xeb, - 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x1a, 0x14, 0x00, 0xa0, 0xe3, 0xc4, 0xff, 0xff, 0xeb, - 0x04, 0x20, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xeb, - 0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x70, 0x40, 0x2d, 0xe9, 0xf3, 0x46, 0xa0, 0xe3, - 0x00, 0x30, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x08, 0x00, 0x00, 0x9a, 0x8c, 0x50, 0x9f, 0xe5, - 0x03, 0x60, 0xd5, 0xe7, 0x0c, 0x60, 0x84, 0xe5, 0x10, 0x60, 0x94, 0xe5, 0x02, 0x00, 0x16, 0xe3, - 0xfc, 0xff, 0xff, 0x0a, 0x01, 0x30, 0x83, 0xe2, 0x00, 0x00, 0x53, 0xe1, 0xf7, 0xff, 0xff, 0x3a, - 0xff, 0x30, 0xa0, 0xe3, 0x0c, 0x30, 0x84, 0xe5, 0x08, 0x00, 0x94, 0xe5, 0x10, 0x00, 0x94, 0xe5, - 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x94, 0xe5, 0x00, 0x00, 0xa0, 0xe3, - 0x00, 0x00, 0x52, 0xe3, 0x0b, 0x00, 0x00, 0x9a, 0x10, 0x50, 0x94, 0xe5, 0x02, 0x00, 0x15, 0xe3, - 0xfc, 0xff, 0xff, 0x0a, 0x0c, 0x30, 0x84, 0xe5, 0x10, 0x50, 0x94, 0xe5, 0x01, 0x00, 0x15, 0xe3, - 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x50, 0x94, 0xe5, 0x01, 0x50, 0xc1, 0xe4, 0x01, 0x00, 0x80, 0xe2, - 0x02, 0x00, 0x50, 0xe1, 0xf3, 0xff, 0xff, 0x3a, 0xc8, 0x00, 0xa0, 0xe3, 0x98, 0xff, 0xff, 0xeb, - 0x70, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x0c, 0x00, 0x02, 0x01, 0x02, 0x00, 0x02, - 0x00, 0x01, 0x00, 0x02 -}; - -struct atmel_private { - void *card; /* Bus dependent structure varies for PCcard */ - int (*present_callback)(void *); /* And callback which uses it */ - char firmware_id[32]; - AtmelFWType firmware_type; - u8 *firmware; - int firmware_length; - struct timer_list management_timer; - struct net_device *dev; - struct device *sys_dev; - struct iw_statistics wstats; - spinlock_t irqlock, timerlock; /* spinlocks */ - enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; - enum { - CARD_TYPE_PARALLEL_FLASH, - CARD_TYPE_SPI_FLASH, - CARD_TYPE_EEPROM - } card_type; - int do_rx_crc; /* If we need to CRC incoming packets */ - int probe_crc; /* set if we don't yet know */ - int crc_ok_cnt, crc_ko_cnt; /* counters for probing */ - u16 rx_desc_head; - u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous; - u16 tx_free_mem, tx_buff_head, tx_buff_tail; - - u16 frag_seq, frag_len, frag_no; - u8 frag_source[6]; - - u8 wep_is_on, default_key, exclude_unencrypted, encryption_level; - u8 group_cipher_suite, pairwise_cipher_suite; - u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; - int wep_key_len[MAX_ENCRYPTION_KEYS]; - int use_wpa, radio_on_broken; /* firmware dependent stuff. */ - - u16 host_info_base; - struct host_info_struct { - /* NB this is matched to the hardware, don't change. */ - u8 volatile int_status; - u8 volatile int_mask; - u8 volatile lockout_host; - u8 volatile lockout_mac; - - u16 tx_buff_pos; - u16 tx_buff_size; - u16 tx_desc_pos; - u16 tx_desc_count; - - u16 rx_buff_pos; - u16 rx_buff_size; - u16 rx_desc_pos; - u16 rx_desc_count; - - u16 build_version; - u16 command_pos; - - u16 major_version; - u16 minor_version; - - u16 func_ctrl; - u16 mac_status; - u16 generic_IRQ_type; - u8 reserved[2]; - } host_info; - - enum { - STATION_STATE_SCANNING, - STATION_STATE_JOINNING, - STATION_STATE_AUTHENTICATING, - STATION_STATE_ASSOCIATING, - STATION_STATE_READY, - STATION_STATE_REASSOCIATING, - STATION_STATE_DOWN, - STATION_STATE_MGMT_ERROR - } station_state; - - int operating_mode, power_mode; - unsigned long last_qual; - int beacons_this_sec; - int channel; - int reg_domain, config_reg_domain; - int tx_rate; - int auto_tx_rate; - int rts_threshold; - int frag_threshold; - int long_retry, short_retry; - int preamble; - int default_beacon_period, beacon_period, listen_interval; - int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum; - int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt; - enum { - SITE_SURVEY_IDLE, - SITE_SURVEY_IN_PROGRESS, - SITE_SURVEY_COMPLETED - } site_survey_state; - unsigned long last_survey; - - int station_was_associated, station_is_associated; - int fast_scan; - - struct bss_info { - int channel; - int SSIDsize; - int RSSI; - int UsingWEP; - int preamble; - int beacon_period; - int BSStype; - u8 BSSID[6]; - u8 SSID[MAX_SSID_LENGTH]; - } BSSinfo[MAX_BSS_ENTRIES]; - int BSS_list_entries, current_BSS; - int connect_to_any_BSS; - int SSID_size, new_SSID_size; - u8 CurrentBSSID[6], BSSID[6]; - u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH]; - u64 last_beacon_timestamp; - u8 rx_buf[MAX_WIRELESS_BODY]; -}; - -static u8 atmel_basic_rates[4] = {0x82, 0x84, 0x0b, 0x16}; - -static const struct { - int reg_domain; - int min, max; - char *name; -} channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" }, - { REG_DOMAIN_DOC, 1, 11, "Canada" }, - { REG_DOMAIN_ETSI, 1, 13, "Europe" }, - { REG_DOMAIN_SPAIN, 10, 11, "Spain" }, - { REG_DOMAIN_FRANCE, 10, 13, "France" }, - { REG_DOMAIN_MKK, 14, 14, "MKK" }, - { REG_DOMAIN_MKK1, 1, 14, "MKK1" }, - { REG_DOMAIN_ISRAEL, 3, 9, "Israel"} }; - -static void build_wpa_mib(struct atmel_private *priv); -static void atmel_copy_to_card(struct net_device *dev, u16 dest, - const unsigned char *src, u16 len); -static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, - u16 src, u16 len); -static void atmel_set_gcr(struct net_device *dev, u16 mask); -static void atmel_clear_gcr(struct net_device *dev, u16 mask); -static int atmel_lock_mac(struct atmel_private *priv); -static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); -static void atmel_command_irq(struct atmel_private *priv); -static int atmel_validate_channel(struct atmel_private *priv, int channel); -static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 frame_len, u8 rssi); -static void atmel_management_timer(struct timer_list *t); -static void atmel_send_command(struct atmel_private *priv, int command, - void *cmd, int cmd_size); -static int atmel_send_command_wait(struct atmel_private *priv, int command, - void *cmd, int cmd_size); -static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u8 *body, int body_len); - -static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); -static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, - u8 data); -static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, - u16 data); -static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, - const u8 *data, int data_len); -static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, - u8 *data, int data_len); -static void atmel_scan(struct atmel_private *priv, int specific_ssid); -static void atmel_join_bss(struct atmel_private *priv, int bss_index); -static void atmel_smooth_qual(struct atmel_private *priv); -static void atmel_writeAR(struct net_device *dev, u16 data); -static int probe_atmel_card(struct net_device *dev); -static int reset_atmel_card(struct net_device *dev); -static void atmel_enter_state(struct atmel_private *priv, int new_state); -int atmel_open (struct net_device *dev); - -static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) -{ - return priv->host_info_base + offset; -} - -static inline u16 atmel_co(struct atmel_private *priv, u16 offset) -{ - return priv->host_info.command_pos + offset; -} - -static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc) -{ - return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset; -} - -static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc) -{ - return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset; -} - -static inline u8 atmel_read8(struct net_device *dev, u16 offset) -{ - return inb(dev->base_addr + offset); -} - -static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data) -{ - outb(data, dev->base_addr + offset); -} - -static inline u16 atmel_read16(struct net_device *dev, u16 offset) -{ - return inw(dev->base_addr + offset); -} - -static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data) -{ - outw(data, dev->base_addr + offset); -} - -static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) -{ - atmel_writeAR(priv->dev, pos); - return atmel_read8(priv->dev, DR); -} - -static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data) -{ - atmel_writeAR(priv->dev, pos); - atmel_write8(priv->dev, DR, data); -} - -static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos) -{ - atmel_writeAR(priv->dev, pos); - return atmel_read16(priv->dev, DR); -} - -static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data) -{ - atmel_writeAR(priv->dev, pos); - atmel_write16(priv->dev, DR, data); -} - -static const struct iw_handler_def atmel_handler_def; - -static void tx_done_irq(struct atmel_private *priv) -{ - int i; - - for (i = 0; - atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE && - i < priv->host_info.tx_desc_count; - i++) { - u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head)); - u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head)); - u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head)); - - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0); - - priv->tx_free_mem += msdu_size; - priv->tx_desc_free++; - - if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size)) - priv->tx_buff_head = 0; - else - priv->tx_buff_head += msdu_size; - - if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1)) - priv->tx_desc_head++ ; - else - priv->tx_desc_head = 0; - - if (type == TX_PACKET_TYPE_DATA) { - if (status == TX_STATUS_SUCCESS) - priv->dev->stats.tx_packets++; - else - priv->dev->stats.tx_errors++; - netif_wake_queue(priv->dev); - } - } -} - -static u16 find_tx_buff(struct atmel_private *priv, u16 len) -{ - u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail; - - if (priv->tx_desc_free == 3 || priv->tx_free_mem < len) - return 0; - - if (bottom_free >= len) - return priv->host_info.tx_buff_pos + priv->tx_buff_tail; - - if (priv->tx_free_mem - bottom_free >= len) { - priv->tx_buff_tail = 0; - return priv->host_info.tx_buff_pos; - } - - return 0; -} - -static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, - u16 len, u16 buff, u8 type) -{ - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff); - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len); - if (!priv->use_wpa) - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0); - if (priv->use_wpa) { - int cipher_type, cipher_length; - if (is_bcast) { - cipher_type = priv->group_cipher_suite; - if (cipher_type == CIPHER_SUITE_WEP_64 || - cipher_type == CIPHER_SUITE_WEP_128) - cipher_length = 8; - else if (cipher_type == CIPHER_SUITE_TKIP) - cipher_length = 12; - else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 || - priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) { - cipher_type = priv->pairwise_cipher_suite; - cipher_length = 8; - } else { - cipher_type = CIPHER_SUITE_NONE; - cipher_length = 0; - } - } else { - cipher_type = priv->pairwise_cipher_suite; - if (cipher_type == CIPHER_SUITE_WEP_64 || - cipher_type == CIPHER_SUITE_WEP_128) - cipher_length = 8; - else if (cipher_type == CIPHER_SUITE_TKIP) - cipher_length = 12; - else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 || - priv->group_cipher_suite == CIPHER_SUITE_WEP_128) { - cipher_type = priv->group_cipher_suite; - cipher_length = 8; - } else { - cipher_type = CIPHER_SUITE_NONE; - cipher_length = 0; - } - } - - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail), - cipher_type); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail), - cipher_length); - } - atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L); - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN); - if (priv->tx_desc_previous != priv->tx_desc_tail) - atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0); - priv->tx_desc_previous = priv->tx_desc_tail; - if (priv->tx_desc_tail < (priv->host_info.tx_desc_count - 1)) - priv->tx_desc_tail++; - else - priv->tx_desc_tail = 0; - priv->tx_desc_free--; - priv->tx_free_mem -= len; -} - -static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - struct ieee80211_hdr header; - unsigned long flags; - u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; - - if (priv->card && priv->present_callback && - !(*priv->present_callback)(priv->card)) { - dev->stats.tx_errors++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - if (priv->station_state != STATION_STATE_READY) { - dev->stats.tx_errors++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - /* first ensure the timer func cannot run */ - spin_lock_bh(&priv->timerlock); - /* then stop the hardware ISR */ - spin_lock_irqsave(&priv->irqlock, flags); - /* nb doing the above in the opposite order will deadlock */ - - /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the - 12 first bytes (containing DA/SA) and put them in the appropriate - fields of the Wireless Header. Thus the packet length is then the - initial + 18 (+30-12) */ - - if (!(buff = find_tx_buff(priv, len + 18))) { - dev->stats.tx_dropped++; - spin_unlock_irqrestore(&priv->irqlock, flags); - spin_unlock_bh(&priv->timerlock); - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - } - - frame_ctl = IEEE80211_FTYPE_DATA; - header.duration_id = 0; - header.seq_ctrl = 0; - if (priv->wep_is_on) - frame_ctl |= IEEE80211_FCTL_PROTECTED; - if (priv->operating_mode == IW_MODE_ADHOC) { - skb_copy_from_linear_data(skb, &header.addr1, ETH_ALEN); - memcpy(&header.addr2, dev->dev_addr, ETH_ALEN); - memcpy(&header.addr3, priv->BSSID, ETH_ALEN); - } else { - frame_ctl |= IEEE80211_FCTL_TODS; - memcpy(&header.addr1, priv->CurrentBSSID, ETH_ALEN); - memcpy(&header.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data(skb, &header.addr3, ETH_ALEN); - } - - if (priv->use_wpa) - memcpy(&header.addr4, rfc1042_header, ETH_ALEN); - - header.frame_control = cpu_to_le16(frame_ctl); - /* Copy the wireless header into the card */ - atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); - /* Copy the packet sans its 802.3 header addresses which have been replaced */ - atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); - priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; - - /* low bit of first byte of destination tells us if broadcast */ - tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA); - dev->stats.tx_bytes += len; - - spin_unlock_irqrestore(&priv->irqlock, flags); - spin_unlock_bh(&priv->timerlock); - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u8 *body, int body_len) -{ - u16 buff; - int len = MGMT_FRAME_BODY_OFFSET + body_len; - - if (!(buff = find_tx_buff(priv, len))) - return; - - atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); - atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); - priv->tx_buff_tail += len; - tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); -} - -static void fast_rx_path(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 msdu_size, u16 rx_packet_loc, u32 crc) -{ - /* fast path: unfragmented packet copy directly into skbuf */ - u8 mac4[6]; - struct sk_buff *skb; - unsigned char *skbp; - - /* get the final, mac 4 header field, this tells us encapsulation */ - atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); - msdu_size -= 6; - - if (priv->do_rx_crc) { - crc = crc32_le(crc, mac4, 6); - msdu_size -= 4; - } - - if (!(skb = dev_alloc_skb(msdu_size + 14))) { - priv->dev->stats.rx_dropped++; - return; - } - - skb_reserve(skb, 2); - skbp = skb_put(skb, msdu_size + 12); - atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); - - if (priv->do_rx_crc) { - u32 netcrc; - crc = crc32_le(crc, skbp + 12, msdu_size); - atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); - if ((crc ^ 0xffffffff) != netcrc) { - priv->dev->stats.rx_crc_errors++; - dev_kfree_skb(skb); - return; - } - } - - memcpy(skbp, header->addr1, ETH_ALEN); /* destination address */ - if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) - memcpy(&skbp[ETH_ALEN], header->addr3, ETH_ALEN); - else - memcpy(&skbp[ETH_ALEN], header->addr2, ETH_ALEN); /* source address */ - - skb->protocol = eth_type_trans(skb, priv->dev); - skb->ip_summed = CHECKSUM_NONE; - netif_rx(skb); - priv->dev->stats.rx_bytes += 12 + msdu_size; - priv->dev->stats.rx_packets++; -} - -/* Test to see if the packet in card memory at packet_loc has a valid CRC - It doesn't matter that this is slow: it is only used to proble the first few - packets. */ -static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) -{ - int i = msdu_size - 4; - u32 netcrc, crc = 0xffffffff; - - if (msdu_size < 4) - return 0; - - atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); - - atmel_writeAR(priv->dev, packet_loc); - while (i--) { - u8 octet = atmel_read8(priv->dev, DR); - crc = crc32_le(crc, &octet, 1); - } - - return (crc ^ 0xffffffff) == netcrc; -} - -static void frag_rx_path(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, - u8 frag_no, int more_frags) -{ - u8 mac4[ETH_ALEN]; - u8 source[ETH_ALEN]; - struct sk_buff *skb; - - if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) - memcpy(source, header->addr3, ETH_ALEN); - else - memcpy(source, header->addr2, ETH_ALEN); - - rx_packet_loc += 24; /* skip header */ - - if (priv->do_rx_crc) - msdu_size -= 4; - - if (frag_no == 0) { /* first fragment */ - atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, ETH_ALEN); - msdu_size -= ETH_ALEN; - rx_packet_loc += ETH_ALEN; - - if (priv->do_rx_crc) - crc = crc32_le(crc, mac4, 6); - - priv->frag_seq = seq_no; - priv->frag_no = 1; - priv->frag_len = msdu_size; - memcpy(priv->frag_source, source, ETH_ALEN); - memcpy(&priv->rx_buf[ETH_ALEN], source, ETH_ALEN); - memcpy(priv->rx_buf, header->addr1, ETH_ALEN); - - atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); - - if (priv->do_rx_crc) { - u32 netcrc; - crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); - atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); - if ((crc ^ 0xffffffff) != netcrc) { - priv->dev->stats.rx_crc_errors++; - eth_broadcast_addr(priv->frag_source); - } - } - - } else if (priv->frag_no == frag_no && - priv->frag_seq == seq_no && - memcmp(priv->frag_source, source, ETH_ALEN) == 0) { - - atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], - rx_packet_loc, msdu_size); - if (priv->do_rx_crc) { - u32 netcrc; - crc = crc32_le(crc, - &priv->rx_buf[12 + priv->frag_len], - msdu_size); - atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); - if ((crc ^ 0xffffffff) != netcrc) { - priv->dev->stats.rx_crc_errors++; - eth_broadcast_addr(priv->frag_source); - more_frags = 1; /* don't send broken assembly */ - } - } - - priv->frag_len += msdu_size; - priv->frag_no++; - - if (!more_frags) { /* last one */ - eth_broadcast_addr(priv->frag_source); - if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { - priv->dev->stats.rx_dropped++; - } else { - skb_reserve(skb, 2); - skb_put_data(skb, priv->rx_buf, - priv->frag_len + 12); - skb->protocol = eth_type_trans(skb, priv->dev); - skb->ip_summed = CHECKSUM_NONE; - netif_rx(skb); - priv->dev->stats.rx_bytes += priv->frag_len + 12; - priv->dev->stats.rx_packets++; - } - } - } else - priv->wstats.discard.fragment++; -} - -static void rx_done_irq(struct atmel_private *priv) -{ - int i; - struct ieee80211_hdr header; - - for (i = 0; - atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && - i < priv->host_info.rx_desc_count; - i++) { - - u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; - u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); - u32 crc = 0xffffffff; - - if (status != RX_STATUS_SUCCESS) { - if (status == 0xc1) /* determined by experiment */ - priv->wstats.discard.nwid++; - else - priv->dev->stats.rx_errors++; - goto next; - } - - msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); - rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); - - if (msdu_size < 30) { - priv->dev->stats.rx_errors++; - goto next; - } - - /* Get header as far as end of seq_ctrl */ - atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); - frame_ctl = le16_to_cpu(header.frame_control); - seq_control = le16_to_cpu(header.seq_ctrl); - - /* probe for CRC use here if needed once five packets have - arrived with the same crc status, we assume we know what's - happening and stop probing */ - if (priv->probe_crc) { - if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) { - priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); - } else { - priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); - } - if (priv->do_rx_crc) { - if (priv->crc_ok_cnt++ > 5) - priv->probe_crc = 0; - } else { - if (priv->crc_ko_cnt++ > 5) - priv->probe_crc = 0; - } - } - - /* don't CRC header when WEP in use */ - if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) { - crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); - } - msdu_size -= 24; /* header */ - - if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { - int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS; - u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG; - u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4; - - if (!more_fragments && packet_fragment_no == 0) { - fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); - } else { - frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, - packet_sequence_no, packet_fragment_no, more_fragments); - } - } - - if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - /* copy rest of packet into buffer */ - atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); - - /* we use the same buffer for frag reassembly and control packets */ - eth_broadcast_addr(priv->frag_source); - - if (priv->do_rx_crc) { - /* last 4 octets is crc */ - msdu_size -= 4; - crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); - if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { - priv->dev->stats.rx_crc_errors++; - goto next; - } - } - - atmel_management_frame(priv, &header, msdu_size, - atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); - } - -next: - /* release descriptor */ - atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); - - if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) - priv->rx_desc_head++; - else - priv->rx_desc_head = 0; - } -} - -static irqreturn_t service_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct atmel_private *priv = netdev_priv(dev); - u8 isr; - int i = -1; - static const u8 irq_order[] = { - ISR_OUT_OF_RANGE, - ISR_RxCOMPLETE, - ISR_TxCOMPLETE, - ISR_RxFRAMELOST, - ISR_FATAL_ERROR, - ISR_COMMAND_COMPLETE, - ISR_IBSS_MERGE, - ISR_GENERIC_IRQ - }; - - if (priv->card && priv->present_callback && - !(*priv->present_callback)(priv->card)) - return IRQ_HANDLED; - - /* In this state upper-level code assumes it can mess with - the card unhampered by interrupts which may change register state. - Note that even though the card shouldn't generate interrupts - the inturrupt line may be shared. This allows card setup - to go on without disabling interrupts for a long time. */ - if (priv->station_state == STATION_STATE_DOWN) - return IRQ_NONE; - - atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ - - while (1) { - if (!atmel_lock_mac(priv)) { - /* failed to contact card */ - printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); - return IRQ_HANDLED; - } - - isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); - - if (!isr) { - atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ - return i == -1 ? IRQ_NONE : IRQ_HANDLED; - } - - atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ - - for (i = 0; i < ARRAY_SIZE(irq_order); i++) - if (isr & irq_order[i]) - break; - - if (!atmel_lock_mac(priv)) { - /* failed to contact card */ - printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); - return IRQ_HANDLED; - } - - isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); - isr ^= irq_order[i]; - atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); - - switch (irq_order[i]) { - - case ISR_OUT_OF_RANGE: - if (priv->operating_mode == IW_MODE_INFRA && - priv->station_state == STATION_STATE_READY) { - priv->station_is_associated = 0; - atmel_scan(priv, 1); - } - break; - - case ISR_RxFRAMELOST: - priv->wstats.discard.misc++; - fallthrough; - case ISR_RxCOMPLETE: - rx_done_irq(priv); - break; - - case ISR_TxCOMPLETE: - tx_done_irq(priv); - break; - - case ISR_FATAL_ERROR: - printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - break; - - case ISR_COMMAND_COMPLETE: - atmel_command_irq(priv); - break; - - case ISR_IBSS_MERGE: - atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, - priv->CurrentBSSID, 6); - /* The WPA stuff cares about the current AP address */ - if (priv->use_wpa) - build_wpa_mib(priv); - break; - case ISR_GENERIC_IRQ: - printk(KERN_INFO "%s: Generic_irq received.\n", dev->name); - break; - } - } -} - -static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - - /* update the link quality here in case we are seeing no beacons - at all to drive the process */ - atmel_smooth_qual(priv); - - priv->wstats.status = priv->station_state; - - if (priv->operating_mode == IW_MODE_INFRA) { - if (priv->station_state != STATION_STATE_READY) { - priv->wstats.qual.qual = 0; - priv->wstats.qual.level = 0; - priv->wstats.qual.updated = (IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_INVALID); - } - priv->wstats.qual.noise = 0; - priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID; - } else { - /* Quality levels cannot be determined in ad-hoc mode, - because we can 'hear' more that one remote station. */ - priv->wstats.qual.qual = 0; - priv->wstats.qual.level = 0; - priv->wstats.qual.noise = 0; - priv->wstats.qual.updated = IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_INVALID - | IW_QUAL_NOISE_INVALID; - priv->wstats.miss.beacon = 0; - } - - return &priv->wstats; -} - -static int atmel_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - - eth_hw_addr_set(dev, addr->sa_data); - return atmel_open(dev); -} - -EXPORT_SYMBOL(atmel_open); - -int atmel_open(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - int i, channel, err; - - /* any scheduled timer is no longer needed and might screw things up.. */ - del_timer_sync(&priv->management_timer); - - /* Interrupts will not touch the card once in this state... */ - priv->station_state = STATION_STATE_DOWN; - - if (priv->new_SSID_size) { - memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); - priv->SSID_size = priv->new_SSID_size; - priv->new_SSID_size = 0; - } - priv->BSS_list_entries = 0; - - priv->AuthenticationRequestRetryCnt = 0; - priv->AssociationRequestRetryCnt = 0; - priv->ReAssociationRequestRetryCnt = 0; - priv->CurrentAuthentTransactionSeqNum = 0x0001; - priv->ExpectedAuthentTransactionSeqNum = 0x0002; - - priv->site_survey_state = SITE_SURVEY_IDLE; - priv->station_is_associated = 0; - - err = reset_atmel_card(dev); - if (err) - return err; - - if (priv->config_reg_domain) { - priv->reg_domain = priv->config_reg_domain; - atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain); - } else { - priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); - for (i = 0; i < ARRAY_SIZE(channel_table); i++) - if (priv->reg_domain == channel_table[i].reg_domain) - break; - if (i == ARRAY_SIZE(channel_table)) { - priv->reg_domain = REG_DOMAIN_MKK1; - printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); - } - } - - if ((channel = atmel_validate_channel(priv, priv->channel))) - priv->channel = channel; - - /* this moves station_state on.... */ - atmel_scan(priv, 1); - - atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ - return 0; -} - -static int atmel_close(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - - /* Send event to userspace that we are disassociating */ - if (priv->station_state == STATION_STATE_READY) { - union iwreq_data wrqu; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - eth_zero_addr(wrqu.ap_addr.sa_data); - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - } - - atmel_enter_state(priv, STATION_STATE_DOWN); - - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - return 0; -} - -static int atmel_validate_channel(struct atmel_private *priv, int channel) -{ - /* check that channel is OK, if so return zero, - else return suitable default channel */ - int i; - - for (i = 0; i < ARRAY_SIZE(channel_table); i++) - if (priv->reg_domain == channel_table[i].reg_domain) { - if (channel >= channel_table[i].min && - channel <= channel_table[i].max) - return 0; - else - return channel_table[i].min; - } - return 0; -} - -#ifdef CONFIG_PROC_FS -static int atmel_proc_show(struct seq_file *m, void *v) -{ - struct atmel_private *priv = m->private; - int i; - char *s, *r, *c; - - seq_printf(m, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR); - - if (priv->station_state != STATION_STATE_DOWN) { - seq_printf(m, - "Firmware version:\t%d.%d build %d\n" - "Firmware location:\t", - priv->host_info.major_version, - priv->host_info.minor_version, - priv->host_info.build_version); - - if (priv->card_type != CARD_TYPE_EEPROM) - seq_puts(m, "on card\n"); - else if (priv->firmware) - seq_printf(m, "%s loaded by host\n", priv->firmware_id); - else - seq_printf(m, "%s loaded by hotplug\n", priv->firmware_id); - - switch (priv->card_type) { - case CARD_TYPE_PARALLEL_FLASH: - c = "Parallel flash"; - break; - case CARD_TYPE_SPI_FLASH: - c = "SPI flash\n"; - break; - case CARD_TYPE_EEPROM: - c = "EEPROM"; - break; - default: - c = "<unknown>"; - } - - r = "<unknown>"; - for (i = 0; i < ARRAY_SIZE(channel_table); i++) - if (priv->reg_domain == channel_table[i].reg_domain) - r = channel_table[i].name; - - seq_printf(m, "MAC memory type:\t%s\n", c); - seq_printf(m, "Regulatory domain:\t%s\n", r); - seq_printf(m, "Host CRC checking:\t%s\n", - priv->do_rx_crc ? "On" : "Off"); - seq_printf(m, "WPA-capable firmware:\t%s\n", - priv->use_wpa ? "Yes" : "No"); - } - - switch (priv->station_state) { - case STATION_STATE_SCANNING: - s = "Scanning"; - break; - case STATION_STATE_JOINNING: - s = "Joining"; - break; - case STATION_STATE_AUTHENTICATING: - s = "Authenticating"; - break; - case STATION_STATE_ASSOCIATING: - s = "Associating"; - break; - case STATION_STATE_READY: - s = "Ready"; - break; - case STATION_STATE_REASSOCIATING: - s = "Reassociating"; - break; - case STATION_STATE_MGMT_ERROR: - s = "Management error"; - break; - case STATION_STATE_DOWN: - s = "Down"; - break; - default: - s = "<unknown>"; - } - - seq_printf(m, "Current state:\t\t%s\n", s); - return 0; -} -#endif - -static const struct net_device_ops atmel_netdev_ops = { - .ndo_open = atmel_open, - .ndo_stop = atmel_close, - .ndo_set_mac_address = atmel_set_mac_address, - .ndo_start_xmit = start_tx, - .ndo_validate_addr = eth_validate_addr, -}; - -struct net_device *init_atmel_card(unsigned short irq, unsigned long port, - const AtmelFWType fw_type, - struct device *sys_dev, - int (*card_present)(void *), void *card) -{ - struct net_device *dev; - struct atmel_private *priv; - int rc; - - /* Create the network device object. */ - dev = alloc_etherdev(sizeof(*priv)); - if (!dev) - return NULL; - - if (dev_alloc_name(dev, dev->name) < 0) { - printk(KERN_ERR "atmel: Couldn't get name!\n"); - goto err_out_free; - } - - priv = netdev_priv(dev); - priv->dev = dev; - priv->sys_dev = sys_dev; - priv->present_callback = card_present; - priv->card = card; - priv->firmware = NULL; - priv->firmware_type = fw_type; - if (firmware) /* module parameter */ - strscpy(priv->firmware_id, firmware, sizeof(priv->firmware_id)); - priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; - priv->station_state = STATION_STATE_DOWN; - priv->do_rx_crc = 0; - /* For PCMCIA cards, some chips need CRC, some don't - so we have to probe. */ - if (priv->bus_type == BUS_TYPE_PCCARD) { - priv->probe_crc = 1; - priv->crc_ok_cnt = priv->crc_ko_cnt = 0; - } else - priv->probe_crc = 0; - priv->last_qual = jiffies; - priv->last_beacon_timestamp = 0; - memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); - eth_zero_addr(priv->BSSID); - priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */ - priv->station_was_associated = 0; - - priv->last_survey = jiffies; - priv->preamble = LONG_PREAMBLE; - priv->operating_mode = IW_MODE_INFRA; - priv->connect_to_any_BSS = 0; - priv->config_reg_domain = 0; - priv->reg_domain = 0; - priv->tx_rate = 3; - priv->auto_tx_rate = 1; - priv->channel = 4; - priv->power_mode = 0; - priv->SSID[0] = '\0'; - priv->SSID_size = 0; - priv->new_SSID_size = 0; - priv->frag_threshold = 2346; - priv->rts_threshold = 2347; - priv->short_retry = 7; - priv->long_retry = 4; - - priv->wep_is_on = 0; - priv->default_key = 0; - priv->encryption_level = 0; - priv->exclude_unencrypted = 0; - priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; - priv->use_wpa = 0; - memset(priv->wep_keys, 0, sizeof(priv->wep_keys)); - memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); - - priv->default_beacon_period = priv->beacon_period = 100; - priv->listen_interval = 1; - - timer_setup(&priv->management_timer, atmel_management_timer, 0); - spin_lock_init(&priv->irqlock); - spin_lock_init(&priv->timerlock); - - dev->netdev_ops = &atmel_netdev_ops; - dev->wireless_handlers = &atmel_handler_def; - dev->irq = irq; - dev->base_addr = port; - - /* MTU range: 68 - 2312 */ - dev->min_mtu = 68; - dev->max_mtu = MAX_WIRELESS_BODY - ETH_FCS_LEN; - - SET_NETDEV_DEV(dev, sys_dev); - - if ((rc = request_irq(dev->irq, service_interrupt, IRQF_SHARED, dev->name, dev))) { - printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc); - goto err_out_free; - } - - if (!request_region(dev->base_addr, 32, - priv->bus_type == BUS_TYPE_PCCARD ? "atmel_cs" : "atmel_pci")) { - goto err_out_irq; - } - - if (register_netdev(dev)) - goto err_out_res; - - if (!probe_atmel_card(dev)) { - unregister_netdev(dev); - goto err_out_res; - } - - netif_carrier_off(dev); - - if (!proc_create_single_data("driver/atmel", 0, NULL, atmel_proc_show, - priv)) - printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); - - printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", - dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr); - - return dev; - -err_out_res: - release_region(dev->base_addr, 32); -err_out_irq: - free_irq(dev->irq, dev); -err_out_free: - free_netdev(dev); - return NULL; -} - -EXPORT_SYMBOL(init_atmel_card); - -void stop_atmel_card(struct net_device *dev) -{ - struct atmel_private *priv = netdev_priv(dev); - - /* put a brick on it... */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - - del_timer_sync(&priv->management_timer); - unregister_netdev(dev); - remove_proc_entry("driver/atmel", NULL); - free_irq(dev->irq, dev); - kfree(priv->firmware); - release_region(dev->base_addr, 32); - free_netdev(dev); -} - -EXPORT_SYMBOL(stop_atmel_card); - -static int atmel_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct atmel_private *priv = netdev_priv(dev); - - /* Check if we asked for `any' */ - if (dwrq->flags == 0) { - priv->connect_to_any_BSS = 1; - } else { - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - - priv->connect_to_any_BSS = 0; - - /* Check the size of the string */ - if (dwrq->length > MAX_SSID_LENGTH) - return -E2BIG; - if (index != 0) - return -EINVAL; - - memcpy(priv->new_SSID, extra, dwrq->length); - priv->new_SSID_size = dwrq->length; - } - - return -EINPROGRESS; -} - -static int atmel_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct atmel_private *priv = netdev_priv(dev); - - /* Get the current SSID */ - if (priv->new_SSID_size != 0) { - memcpy(extra, priv->new_SSID, priv->new_SSID_size); - dwrq->length = priv->new_SSID_size; - } else { - memcpy(extra, priv->SSID, priv->SSID_size); - dwrq->length = priv->SSID_size; - } - - dwrq->flags = !priv->connect_to_any_BSS; /* active */ - - return 0; -} - -static int atmel_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct atmel_private *priv = netdev_priv(dev); - memcpy(awrq->sa_data, priv->CurrentBSSID, ETH_ALEN); - awrq->sa_family = ARPHRD_ETHER; - - return 0; -} - -static int atmel_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct atmel_private *priv = netdev_priv(dev); - - /* Basic checking: do we have a key to set ? - * Note : with the new API, it's impossible to get a NULL pointer. - * Therefore, we need to check a key size == 0 instead. - * New version of iwconfig properly set the IW_ENCODE_NOKEY flag - * when no key is present (only change flags), but older versions - * don't do it. - Jean II */ - if (dwrq->length > 0) { - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - int current_index = priv->default_key; - /* Check the size of the key */ - if (dwrq->length > 13) { - return -EINVAL; - } - /* Check the index (none -> use current) */ - if (index < 0 || index >= 4) - index = current_index; - else - priv->default_key = index; - /* Set the length */ - if (dwrq->length > 5) - priv->wep_key_len[index] = 13; - else - if (dwrq->length > 0) - priv->wep_key_len[index] = 5; - else - /* Disable the key */ - priv->wep_key_len[index] = 0; - /* Check if the key is not marked as invalid */ - if (!(dwrq->flags & IW_ENCODE_NOKEY)) { - /* Cleanup */ - memset(priv->wep_keys[index], 0, 13); - /* Copy the key in the driver */ - memcpy(priv->wep_keys[index], extra, dwrq->length); - } - /* WE specify that if a valid key is set, encryption - * should be enabled (user may turn it off later) - * This is also how "iwconfig ethX key on" works */ - if (index == current_index && - priv->wep_key_len[index] > 0) { - priv->wep_is_on = 1; - priv->exclude_unencrypted = 1; - if (priv->wep_key_len[index] > 5) { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; - priv->encryption_level = 2; - } else { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; - priv->encryption_level = 1; - } - } - } else { - /* Do we want to just set the transmit key index ? */ - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - if (index >= 0 && index < 4) { - priv->default_key = index; - } else - /* Don't complain if only change the mode */ - if (!(dwrq->flags & IW_ENCODE_MODE)) - return -EINVAL; - } - /* Read the flags */ - if (dwrq->flags & IW_ENCODE_DISABLED) { - priv->wep_is_on = 0; - priv->encryption_level = 0; - priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; - } else { - priv->wep_is_on = 1; - if (priv->wep_key_len[priv->default_key] > 5) { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; - priv->encryption_level = 2; - } else { - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; - priv->encryption_level = 1; - } - } - if (dwrq->flags & IW_ENCODE_RESTRICTED) - priv->exclude_unencrypted = 1; - if (dwrq->flags & IW_ENCODE_OPEN) - priv->exclude_unencrypted = 0; - - return -EINPROGRESS; /* Call commit handler */ -} - -static int atmel_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct atmel_private *priv = netdev_priv(dev); - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - - if (!priv->wep_is_on) - dwrq->flags = IW_ENCODE_DISABLED; - else { - if (priv->exclude_unencrypted) - dwrq->flags = IW_ENCODE_RESTRICTED; - else - dwrq->flags = IW_ENCODE_OPEN; - } - /* Which key do we want ? -1 -> tx index */ - if (index < 0 || index >= 4) - index = priv->default_key; - dwrq->flags |= index + 1; - /* Copy the key to the user buffer */ - dwrq->length = priv->wep_key_len[index]; - if (dwrq->length > 16) { - dwrq->length = 0; - } else { - memset(extra, 0, 16); - memcpy(extra, priv->wep_keys[index], dwrq->length); - } - - return 0; -} - -static int atmel_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, key_len, alg = ext->alg, set_key = 1; - - /* Determine and validate the key index */ - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (idx < 1 || idx > 4) - return -EINVAL; - idx--; - } else - idx = priv->default_key; - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - priv->default_key = idx; - set_key = ext->key_len > 0 ? 1 : 0; - } - - if (set_key) { - /* Set the requested key first */ - switch (alg) { - case IW_ENCODE_ALG_NONE: - priv->wep_is_on = 0; - priv->encryption_level = 0; - priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; - break; - case IW_ENCODE_ALG_WEP: - if (ext->key_len > 5) { - priv->wep_key_len[idx] = 13; - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; - priv->encryption_level = 2; - } else if (ext->key_len > 0) { - priv->wep_key_len[idx] = 5; - priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; - priv->encryption_level = 1; - } else { - return -EINVAL; - } - priv->wep_is_on = 1; - memset(priv->wep_keys[idx], 0, 13); - key_len = min ((int)ext->key_len, priv->wep_key_len[idx]); - memcpy(priv->wep_keys[idx], ext->key, key_len); - break; - default: - return -EINVAL; - } - } - - return -EINPROGRESS; -} - -static int atmel_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (idx < 1 || idx > 4) - return -EINVAL; - idx--; - } else - idx = priv->default_key; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - if (!priv->wep_is_on) { - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - encoding->flags |= IW_ENCODE_DISABLED; - } else { - if (priv->encryption_level > 0) - ext->alg = IW_ENCODE_ALG_WEP; - else - return -EINVAL; - - ext->key_len = priv->wep_key_len[idx]; - memcpy(ext->key, priv->wep_keys[idx], ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - } - - return 0; -} - -static int atmel_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_param *param = &wrqu->param; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_PRIVACY_INVOKED: - /* - * atmel does not use these parameters - */ - break; - - case IW_AUTH_DROP_UNENCRYPTED: - priv->exclude_unencrypted = param->value ? 1 : 0; - break; - - case IW_AUTH_80211_AUTH_ALG: { - if (param->value & IW_AUTH_ALG_SHARED_KEY) { - priv->exclude_unencrypted = 1; - } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { - priv->exclude_unencrypted = 0; - } else - return -EINVAL; - break; - } - - case IW_AUTH_WPA_ENABLED: - /* Silently accept disable of WPA */ - if (param->value > 0) - return -EOPNOTSUPP; - break; - - default: - return -EOPNOTSUPP; - } - return -EINPROGRESS; -} - -static int atmel_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - struct iw_param *param = &wrqu->param; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_DROP_UNENCRYPTED: - param->value = priv->exclude_unencrypted; - break; - - case IW_AUTH_80211_AUTH_ALG: - if (priv->exclude_unencrypted == 1) - param->value = IW_AUTH_ALG_SHARED_KEY; - else - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = 0; - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - - -static int atmel_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - strcpy(wrqu->name, "IEEE 802.11-DS"); - return 0; -} - -static int atmel_set_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct atmel_private *priv = netdev_priv(dev); - - if (vwrq->fixed == 0) { - priv->tx_rate = 3; - priv->auto_tx_rate = 1; - } else { - priv->auto_tx_rate = 0; - - /* Which type of value ? */ - if ((vwrq->value < 4) && (vwrq->value >= 0)) { - /* Setting by rate index */ - priv->tx_rate = vwrq->value; - } else { - /* Setting by frequency value */ - switch (vwrq->value) { - case 1000000: - priv->tx_rate = 0; - break; - case 2000000: - priv->tx_rate = 1; - break; - case 5500000: - priv->tx_rate = 2; - break; - case 11000000: - priv->tx_rate = 3; - break; - default: - return -EINVAL; - } - } - } - - return -EINPROGRESS; -} - -static int atmel_set_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - __u32 *uwrq = &wrqu->mode; - struct atmel_private *priv = netdev_priv(dev); - - if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) - return -EINVAL; - - priv->operating_mode = *uwrq; - return -EINPROGRESS; -} - -static int atmel_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - __u32 *uwrq = &wrqu->mode; - struct atmel_private *priv = netdev_priv(dev); - - *uwrq = priv->operating_mode; - return 0; -} - -static int atmel_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct atmel_private *priv = netdev_priv(dev); - - if (priv->auto_tx_rate) { - vwrq->fixed = 0; - vwrq->value = 11000000; - } else { - vwrq->fixed = 1; - switch (priv->tx_rate) { - case 0: - vwrq->value = 1000000; - break; - case 1: - vwrq->value = 2000000; - break; - case 2: - vwrq->value = 5500000; - break; - case 3: - vwrq->value = 11000000; - break; - } - } - return 0; -} - -static int atmel_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct atmel_private *priv = netdev_priv(dev); - priv->power_mode = vwrq->disabled ? 0 : 1; - return -EINPROGRESS; -} - -static int atmel_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct atmel_private *priv = netdev_priv(dev); - vwrq->disabled = priv->power_mode ? 0 : 1; - vwrq->flags = IW_POWER_ON; - return 0; -} - -static int atmel_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct atmel_private *priv = netdev_priv(dev); - - if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { - if (vwrq->flags & IW_RETRY_LONG) - priv->long_retry = vwrq->value; - else if (vwrq->flags & IW_RETRY_SHORT) - priv->short_retry = vwrq->value; - else { - /* No modifier : set both */ - priv->long_retry = vwrq->value; - priv->short_retry = vwrq->value; - } - return -EINPROGRESS; - } - - return -EINVAL; -} - -static int atmel_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct atmel_private *priv = netdev_priv(dev); - - vwrq->disabled = 0; /* Can't be disabled */ - - /* Note : by default, display the short retry number */ - if (vwrq->flags & IW_RETRY_LONG) { - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - vwrq->value = priv->long_retry; - } else { - vwrq->flags = IW_RETRY_LIMIT; - vwrq->value = priv->short_retry; - if (priv->long_retry != priv->short_retry) - vwrq->flags |= IW_RETRY_SHORT; - } - - return 0; -} - -static int atmel_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct atmel_private *priv = netdev_priv(dev); - int rthr = vwrq->value; - - if (vwrq->disabled) - rthr = 2347; - if ((rthr < 0) || (rthr > 2347)) { - return -EINVAL; - } - priv->rts_threshold = rthr; - - return -EINPROGRESS; /* Call commit handler */ -} - -static int atmel_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct atmel_private *priv = netdev_priv(dev); - - vwrq->value = priv->rts_threshold; - vwrq->disabled = (vwrq->value >= 2347); - vwrq->fixed = 1; - - return 0; -} - -static int atmel_set_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct atmel_private *priv = netdev_priv(dev); - int fthr = vwrq->value; - - if (vwrq->disabled) - fthr = 2346; - if ((fthr < 256) || (fthr > 2346)) { - return -EINVAL; - } - fthr &= ~0x1; /* Get an even value - is it really needed ??? */ - priv->frag_threshold = fthr; - - return -EINPROGRESS; /* Call commit handler */ -} - -static int atmel_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct atmel_private *priv = netdev_priv(dev); - - vwrq->value = priv->frag_threshold; - vwrq->disabled = (vwrq->value >= 2346); - vwrq->fixed = 1; - - return 0; -} - -static int atmel_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct atmel_private *priv = netdev_priv(dev); - int rc = -EINPROGRESS; /* Call commit handler */ - - /* If setting by frequency, convert to a channel */ - if (fwrq->e == 1) { - int f = fwrq->m / 100000; - - /* Hack to fall through... */ - fwrq->e = 0; - fwrq->m = ieee80211_frequency_to_channel(f); - } - /* Setting by channel number */ - if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0) - rc = -EOPNOTSUPP; - else { - int channel = fwrq->m; - if (atmel_validate_channel(priv, channel) == 0) { - priv->channel = channel; - } else { - rc = -EINVAL; - } - } - return rc; -} - -static int atmel_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct atmel_private *priv = netdev_priv(dev); - - fwrq->m = priv->channel; - fwrq->e = 0; - return 0; -} - -static int atmel_set_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *dwrq, - char *extra) -{ - struct atmel_private *priv = netdev_priv(dev); - unsigned long flags; - - /* Note : you may have realised that, as this is a SET operation, - * this is privileged and therefore a normal user can't - * perform scanning. - * This is not an error, while the device perform scanning, - * traffic doesn't flow, so it's a perfect DoS... - * Jean II */ - - if (priv->station_state == STATION_STATE_DOWN) - return -EAGAIN; - - /* Timeout old surveys. */ - if (time_after(jiffies, priv->last_survey + 20 * HZ)) - priv->site_survey_state = SITE_SURVEY_IDLE; - priv->last_survey = jiffies; - - /* Initiate a scan command */ - if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) - return -EBUSY; - - del_timer_sync(&priv->management_timer); - spin_lock_irqsave(&priv->irqlock, flags); - - priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; - priv->fast_scan = 0; - atmel_scan(priv, 0); - spin_unlock_irqrestore(&priv->irqlock, flags); - - return 0; -} - -static int atmel_get_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct atmel_private *priv = netdev_priv(dev); - int i; - char *current_ev = extra; - struct iw_event iwe; - - if (priv->site_survey_state != SITE_SURVEY_COMPLETED) - return -EAGAIN; - - for (i = 0; i < priv->BSS_list_entries; i++) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_ADDR_LEN); - - iwe.u.data.length = priv->BSSinfo[i].SSIDsize; - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, priv->BSSinfo[i].SSID); - - iwe.cmd = SIOCGIWMODE; - iwe.u.mode = priv->BSSinfo[i].BSStype; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_UINT_LEN); - - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = priv->BSSinfo[i].channel; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_FREQ_LEN); - - /* Add quality statistics */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.level = priv->BSSinfo[i].RSSI; - iwe.u.qual.qual = iwe.u.qual.level; - /* iwe.u.qual.noise = SOMETHING */ - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_QUAL_LEN); - - - iwe.cmd = SIOCGIWENCODE; - if (priv->BSSinfo[i].UsingWEP) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, NULL); - } - - /* Length of data */ - dwrq->length = (current_ev - extra); - dwrq->flags = 0; - - return 0; -} - -static int atmel_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct atmel_private *priv = netdev_priv(dev); - struct iw_range *range = (struct iw_range *) extra; - int k, i, j; - - dwrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - range->min_nwid = 0x0000; - range->max_nwid = 0x0000; - range->num_channels = 0; - for (j = 0; j < ARRAY_SIZE(channel_table); j++) - if (priv->reg_domain == channel_table[j].reg_domain) { - range->num_channels = channel_table[j].max - channel_table[j].min + 1; - break; - } - if (range->num_channels != 0) { - for (k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) { - range->freq[k].i = i; /* List index */ - - /* Values in MHz -> * 10^5 * 10 */ - range->freq[k].m = 100000 * - ieee80211_channel_to_frequency(i, NL80211_BAND_2GHZ); - range->freq[k++].e = 1; - } - range->num_frequency = k; - } - - range->max_qual.qual = 100; - range->max_qual.level = 100; - range->max_qual.noise = 0; - range->max_qual.updated = IW_QUAL_NOISE_INVALID; - - range->avg_qual.qual = 50; - range->avg_qual.level = 50; - range->avg_qual.noise = 0; - range->avg_qual.updated = IW_QUAL_NOISE_INVALID; - - range->sensitivity = 0; - - range->bitrate[0] = 1000000; - range->bitrate[1] = 2000000; - range->bitrate[2] = 5500000; - range->bitrate[3] = 11000000; - range->num_bitrates = 4; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = 4; - - range->pmp_flags = IW_POWER_ON; - range->pmt_flags = IW_POWER_ON; - range->pm_capa = 0; - - range->we_version_source = WIRELESS_EXT; - range->we_version_compiled = WIRELESS_EXT; - range->retry_capa = IW_RETRY_LIMIT ; - range->retry_flags = IW_RETRY_LIMIT; - range->r_time_flags = 0; - range->min_retry = 1; - range->max_retry = 65535; - - return 0; -} - -static int atmel_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct atmel_private *priv = netdev_priv(dev); - int i; - static const u8 any[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - unsigned long flags; - - if (awrq->sa_family != ARPHRD_ETHER) - return -EINVAL; - - if (!memcmp(any, awrq->sa_data, 6) || - !memcmp(off, awrq->sa_data, 6)) { - del_timer_sync(&priv->management_timer); - spin_lock_irqsave(&priv->irqlock, flags); - atmel_scan(priv, 1); - spin_unlock_irqrestore(&priv->irqlock, flags); - return 0; - } - - for (i = 0; i < priv->BSS_list_entries; i++) { - if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) { - if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) { - return -EINVAL; - } else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) { - return -EINVAL; - } else { - del_timer_sync(&priv->management_timer); - spin_lock_irqsave(&priv->irqlock, flags); - atmel_join_bss(priv, i); - spin_unlock_irqrestore(&priv->irqlock, flags); - return 0; - } - } - } - - return -EINVAL; -} - -static int atmel_config_commit(struct net_device *dev, - struct iw_request_info *info, /* NULL */ - union iwreq_data *zwrq, /* NULL */ - char *extra) /* NULL */ -{ - return atmel_open(dev); -} - -static const iw_handler atmel_handler[] = -{ - IW_HANDLER(SIOCSIWCOMMIT, atmel_config_commit), - IW_HANDLER(SIOCGIWNAME, atmel_get_name), - IW_HANDLER(SIOCSIWFREQ, atmel_set_freq), - IW_HANDLER(SIOCGIWFREQ, atmel_get_freq), - IW_HANDLER(SIOCSIWMODE, atmel_set_mode), - IW_HANDLER(SIOCGIWMODE, atmel_get_mode), - IW_HANDLER(SIOCGIWRANGE, atmel_get_range), - IW_HANDLER(SIOCSIWAP, atmel_set_wap), - IW_HANDLER(SIOCGIWAP, atmel_get_wap), - IW_HANDLER(SIOCSIWSCAN, atmel_set_scan), - IW_HANDLER(SIOCGIWSCAN, atmel_get_scan), - IW_HANDLER(SIOCSIWESSID, atmel_set_essid), - IW_HANDLER(SIOCGIWESSID, atmel_get_essid), - IW_HANDLER(SIOCSIWRATE, atmel_set_rate), - IW_HANDLER(SIOCGIWRATE, atmel_get_rate), - IW_HANDLER(SIOCSIWRTS, atmel_set_rts), - IW_HANDLER(SIOCGIWRTS, atmel_get_rts), - IW_HANDLER(SIOCSIWFRAG, atmel_set_frag), - IW_HANDLER(SIOCGIWFRAG, atmel_get_frag), - IW_HANDLER(SIOCSIWRETRY, atmel_set_retry), - IW_HANDLER(SIOCGIWRETRY, atmel_get_retry), - IW_HANDLER(SIOCSIWENCODE, atmel_set_encode), - IW_HANDLER(SIOCGIWENCODE, atmel_get_encode), - IW_HANDLER(SIOCSIWPOWER, atmel_set_power), - IW_HANDLER(SIOCGIWPOWER, atmel_get_power), - IW_HANDLER(SIOCSIWAUTH, atmel_set_auth), - IW_HANDLER(SIOCGIWAUTH, atmel_get_auth), - IW_HANDLER(SIOCSIWENCODEEXT, atmel_set_encodeext), - IW_HANDLER(SIOCGIWENCODEEXT, atmel_get_encodeext), -}; - -static const iw_handler atmel_private_handler[] = -{ - NULL, /* SIOCIWFIRSTPRIV */ -}; - -struct atmel_priv_ioctl { - char id[32]; - unsigned char __user *data; - unsigned short len; -}; - -#define ATMELFWL SIOCIWFIRSTPRIV -#define ATMELIDIFC ATMELFWL + 1 -#define ATMELRD ATMELFWL + 2 -#define ATMELMAGIC 0x51807 -#define REGDOMAINSZ 20 - -static const struct iw_priv_args atmel_private_args[] = { - { - .cmd = ATMELFWL, - .set_args = IW_PRIV_TYPE_BYTE - | IW_PRIV_SIZE_FIXED - | sizeof(struct atmel_priv_ioctl), - .get_args = IW_PRIV_TYPE_NONE, - .name = "atmelfwl" - }, { - .cmd = ATMELIDIFC, - .set_args = IW_PRIV_TYPE_NONE, - .get_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "atmelidifc" - }, { - .cmd = ATMELRD, - .set_args = IW_PRIV_TYPE_CHAR | REGDOMAINSZ, - .get_args = IW_PRIV_TYPE_NONE, - .name = "regdomain" - }, -}; - -static const struct iw_handler_def atmel_handler_def = { - .num_standard = ARRAY_SIZE(atmel_handler), - .num_private = ARRAY_SIZE(atmel_private_handler), - .num_private_args = ARRAY_SIZE(atmel_private_args), - .standard = atmel_handler, - .private = atmel_private_handler, - .private_args = (struct iw_priv_args *) atmel_private_args, - .get_wireless_stats = atmel_get_wireless_stats -}; - -struct auth_body { - __le16 alg; - __le16 trans_seq; - __le16 status; - u8 el_id; - u8 chall_text_len; - u8 chall_text[253]; -}; - -static void atmel_enter_state(struct atmel_private *priv, int new_state) -{ - int old_state = priv->station_state; - - if (new_state == old_state) - return; - - priv->station_state = new_state; - - if (new_state == STATION_STATE_READY) { - netif_start_queue(priv->dev); - netif_carrier_on(priv->dev); - } - - if (old_state == STATION_STATE_READY) { - netif_carrier_off(priv->dev); - if (netif_running(priv->dev)) - netif_stop_queue(priv->dev); - priv->last_beacon_timestamp = 0; - } -} - -static void atmel_scan(struct atmel_private *priv, int specific_ssid) -{ - struct { - u8 BSSID[ETH_ALEN]; - u8 SSID[MAX_SSID_LENGTH]; - u8 scan_type; - u8 channel; - __le16 BSS_type; - __le16 min_channel_time; - __le16 max_channel_time; - u8 options; - u8 SSID_size; - } cmd; - - eth_broadcast_addr(cmd.BSSID); - - if (priv->fast_scan) { - cmd.SSID_size = priv->SSID_size; - memcpy(cmd.SSID, priv->SSID, priv->SSID_size); - cmd.min_channel_time = cpu_to_le16(10); - cmd.max_channel_time = cpu_to_le16(50); - } else { - priv->BSS_list_entries = 0; - cmd.SSID_size = 0; - cmd.min_channel_time = cpu_to_le16(10); - cmd.max_channel_time = cpu_to_le16(120); - } - - cmd.options = 0; - - if (!specific_ssid) - cmd.options |= SCAN_OPTIONS_SITE_SURVEY; - - cmd.channel = (priv->channel & 0x7f); - cmd.scan_type = SCAN_TYPE_ACTIVE; - cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ? - BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); - - atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); - - /* This must come after all hardware access to avoid being messed up - by stuff happening in interrupt context after we leave STATE_DOWN */ - atmel_enter_state(priv, STATION_STATE_SCANNING); -} - -static void join(struct atmel_private *priv, int type) -{ - struct { - u8 BSSID[6]; - u8 SSID[MAX_SSID_LENGTH]; - u8 BSS_type; /* this is a short in a scan command - weird */ - u8 channel; - __le16 timeout; - u8 SSID_size; - u8 reserved; - } cmd; - - cmd.SSID_size = priv->SSID_size; - memcpy(cmd.SSID, priv->SSID, priv->SSID_size); - memcpy(cmd.BSSID, priv->CurrentBSSID, ETH_ALEN); - cmd.channel = (priv->channel & 0x7f); - cmd.BSS_type = type; - cmd.timeout = cpu_to_le16(2000); - - atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd)); -} - -static void start(struct atmel_private *priv, int type) -{ - struct { - u8 BSSID[6]; - u8 SSID[MAX_SSID_LENGTH]; - u8 BSS_type; - u8 channel; - u8 SSID_size; - u8 reserved[3]; - } cmd; - - cmd.SSID_size = priv->SSID_size; - memcpy(cmd.SSID, priv->SSID, priv->SSID_size); - memcpy(cmd.BSSID, priv->BSSID, ETH_ALEN); - cmd.BSS_type = type; - cmd.channel = (priv->channel & 0x7f); - - atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd)); -} - -static void handle_beacon_probe(struct atmel_private *priv, u16 capability, - u8 channel) -{ - int rejoin = 0; - int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? - SHORT_PREAMBLE : LONG_PREAMBLE; - - if (priv->preamble != new) { - priv->preamble = new; - rejoin = 1; - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new); - } - - if (priv->channel != channel) { - priv->channel = channel; - rejoin = 1; - atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel); - } - - if (rejoin) { - priv->station_is_associated = 0; - atmel_enter_state(priv, STATION_STATE_JOINNING); - - if (priv->operating_mode == IW_MODE_INFRA) - join(priv, BSS_TYPE_INFRASTRUCTURE); - else - join(priv, BSS_TYPE_AD_HOC); - } -} - -static void send_authentication_request(struct atmel_private *priv, u16 system, - u8 *challenge, int challenge_len) -{ - struct ieee80211_hdr header; - struct auth_body auth; - - header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); - header.duration_id = cpu_to_le16(0x8000); - header.seq_ctrl = 0; - memcpy(header.addr1, priv->CurrentBSSID, ETH_ALEN); - memcpy(header.addr2, priv->dev->dev_addr, ETH_ALEN); - memcpy(header.addr3, priv->CurrentBSSID, ETH_ALEN); - - if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) - /* no WEP for authentication frames with TrSeqNo 1 */ - header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - - auth.alg = cpu_to_le16(system); - - auth.status = 0; - auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum); - priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1; - priv->CurrentAuthentTransactionSeqNum += 2; - - if (challenge_len != 0) { - auth.el_id = 16; /* challenge_text */ - auth.chall_text_len = challenge_len; - memcpy(auth.chall_text, challenge, challenge_len); - atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len); - } else { - atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6); - } -} - -static void send_association_request(struct atmel_private *priv, int is_reassoc) -{ - u8 *ssid_el_p; - int bodysize; - struct ieee80211_hdr header; - struct ass_req_format { - __le16 capability; - __le16 listen_interval; - u8 ap[ETH_ALEN]; /* nothing after here directly accessible */ - u8 ssid_el_id; - u8 ssid_len; - u8 ssid[MAX_SSID_LENGTH]; - u8 sup_rates_el_id; - u8 sup_rates_len; - u8 rates[4]; - } body; - - header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ)); - header.duration_id = cpu_to_le16(0x8000); - header.seq_ctrl = 0; - - memcpy(header.addr1, priv->CurrentBSSID, ETH_ALEN); - memcpy(header.addr2, priv->dev->dev_addr, ETH_ALEN); - memcpy(header.addr3, priv->CurrentBSSID, ETH_ALEN); - - body.capability = cpu_to_le16(WLAN_CAPABILITY_ESS); - if (priv->wep_is_on) - body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); - if (priv->preamble == SHORT_PREAMBLE) - body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); - - body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); - - /* current AP address - only in reassoc frame */ - if (is_reassoc) { - memcpy(body.ap, priv->CurrentBSSID, ETH_ALEN); - ssid_el_p = &body.ssid_el_id; - bodysize = 18 + priv->SSID_size; - } else { - ssid_el_p = &body.ap[0]; - bodysize = 12 + priv->SSID_size; - } - - ssid_el_p[0] = WLAN_EID_SSID; - ssid_el_p[1] = priv->SSID_size; - memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); - ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES; - ssid_el_p[3 + priv->SSID_size] = 4; /* len of supported rates */ - memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); - - atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); -} - -static int is_frame_from_current_bss(struct atmel_private *priv, - struct ieee80211_hdr *header) -{ - if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) - return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; - else - return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; -} - -static int retrieve_bss(struct atmel_private *priv) -{ - int i; - int max_rssi = -128; - int max_index = -1; - - if (priv->BSS_list_entries == 0) - return -1; - - if (priv->connect_to_any_BSS) { - /* Select a BSS with the max-RSSI but of the same type and of - the same WEP mode and that it is not marked as 'bad' (i.e. - we had previously failed to connect to this BSS with the - settings that we currently use) */ - priv->current_BSS = 0; - for (i = 0; i < priv->BSS_list_entries; i++) { - if (priv->operating_mode == priv->BSSinfo[i].BSStype && - ((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) || - (priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) && - !(priv->BSSinfo[i].channel & 0x80)) { - max_rssi = priv->BSSinfo[i].RSSI; - priv->current_BSS = max_index = i; - } - } - return max_index; - } - - for (i = 0; i < priv->BSS_list_entries; i++) { - if (priv->SSID_size == priv->BSSinfo[i].SSIDsize && - memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 && - priv->operating_mode == priv->BSSinfo[i].BSStype && - atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) { - if (priv->BSSinfo[i].RSSI >= max_rssi) { - max_rssi = priv->BSSinfo[i].RSSI; - max_index = i; - } - } - } - return max_index; -} - -static void store_bss_info(struct atmel_private *priv, - struct ieee80211_hdr *header, u16 capability, - u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, - u8 *ssid, int is_beacon) -{ - u8 *bss = capability & WLAN_CAPABILITY_ESS ? header->addr2 : header->addr3; - int i, index; - - for (index = -1, i = 0; i < priv->BSS_list_entries; i++) - if (memcmp(bss, priv->BSSinfo[i].BSSID, ETH_ALEN) == 0) - index = i; - - /* If we process a probe and an entry from this BSS exists - we will update the BSS entry with the info from this BSS. - If we process a beacon we will only update RSSI */ - - if (index == -1) { - if (priv->BSS_list_entries == MAX_BSS_ENTRIES) - return; - index = priv->BSS_list_entries++; - memcpy(priv->BSSinfo[index].BSSID, bss, ETH_ALEN); - priv->BSSinfo[index].RSSI = rssi; - } else { - if (rssi > priv->BSSinfo[index].RSSI) - priv->BSSinfo[index].RSSI = rssi; - if (is_beacon) - return; - } - - priv->BSSinfo[index].channel = channel; - priv->BSSinfo[index].beacon_period = beacon_period; - priv->BSSinfo[index].UsingWEP = capability & WLAN_CAPABILITY_PRIVACY; - memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); - priv->BSSinfo[index].SSIDsize = ssid_len; - - if (capability & WLAN_CAPABILITY_IBSS) - priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; - else if (capability & WLAN_CAPABILITY_ESS) - priv->BSSinfo[index].BSStype = IW_MODE_INFRA; - - priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? - SHORT_PREAMBLE : LONG_PREAMBLE; -} - -static void authenticate(struct atmel_private *priv, u16 frame_len) -{ - struct auth_body *auth = (struct auth_body *)priv->rx_buf; - u16 status = le16_to_cpu(auth->status); - u16 trans_seq_no = le16_to_cpu(auth->trans_seq); - u16 system = le16_to_cpu(auth->alg); - - if (status == WLAN_STATUS_SUCCESS && !priv->wep_is_on) { - /* no WEP */ - if (priv->station_was_associated) { - atmel_enter_state(priv, STATION_STATE_REASSOCIATING); - send_association_request(priv, 1); - return; - } else { - atmel_enter_state(priv, STATION_STATE_ASSOCIATING); - send_association_request(priv, 0); - return; - } - } - - if (status == WLAN_STATUS_SUCCESS && priv->wep_is_on) { - int should_associate = 0; - /* WEP */ - if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) - return; - - if (system == WLAN_AUTH_OPEN) { - if (trans_seq_no == 0x0002) { - should_associate = 1; - } - } else if (system == WLAN_AUTH_SHARED_KEY) { - if (trans_seq_no == 0x0002 && - auth->el_id == WLAN_EID_CHALLENGE) { - send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len); - return; - } else if (trans_seq_no == 0x0004) { - should_associate = 1; - } - } - - if (should_associate) { - if (priv->station_was_associated) { - atmel_enter_state(priv, STATION_STATE_REASSOCIATING); - send_association_request(priv, 1); - return; - } else { - atmel_enter_state(priv, STATION_STATE_ASSOCIATING); - send_association_request(priv, 0); - return; - } - } - } - - if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { - /* Flip back and forth between WEP auth modes until the max - * authentication tries has been exceeded. - */ - if (system == WLAN_AUTH_OPEN) { - priv->CurrentAuthentTransactionSeqNum = 0x001; - priv->exclude_unencrypted = 1; - send_authentication_request(priv, WLAN_AUTH_SHARED_KEY, NULL, 0); - return; - } else if (system == WLAN_AUTH_SHARED_KEY - && priv->wep_is_on) { - priv->CurrentAuthentTransactionSeqNum = 0x001; - priv->exclude_unencrypted = 0; - send_authentication_request(priv, WLAN_AUTH_OPEN, NULL, 0); - return; - } else if (priv->connect_to_any_BSS) { - int bss_index; - - priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; - - if ((bss_index = retrieve_bss(priv)) != -1) { - atmel_join_bss(priv, bss_index); - return; - } - } - } - - priv->AuthenticationRequestRetryCnt = 0; - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; -} - -static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) -{ - struct ass_resp_format { - __le16 capability; - __le16 status; - __le16 ass_id; - u8 el_id; - u8 length; - u8 rates[4]; - } *ass_resp = (struct ass_resp_format *)priv->rx_buf; - - u16 status = le16_to_cpu(ass_resp->status); - u16 ass_id = le16_to_cpu(ass_resp->ass_id); - u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; - - union iwreq_data wrqu; - - if (frame_len < 8 + rates_len) - return; - - if (status == WLAN_STATUS_SUCCESS) { - if (subtype == IEEE80211_STYPE_ASSOC_RESP) - priv->AssociationRequestRetryCnt = 0; - else - priv->ReAssociationRequestRetryCnt = 0; - - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff); - atmel_set_mib(priv, Phy_Mib_Type, - PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len); - if (priv->power_mode == 0) { - priv->listen_interval = 1; - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); - } else { - priv->listen_interval = 2; - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_PS_MODE_POS, PS_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2); - } - - priv->station_is_associated = 1; - priv->station_was_associated = 1; - atmel_enter_state(priv, STATION_STATE_READY); - - /* Send association event to userspace */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - memcpy(wrqu.ap_addr.sa_data, priv->CurrentBSSID, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - - return; - } - - if (subtype == IEEE80211_STYPE_ASSOC_RESP && - status != WLAN_STATUS_ASSOC_DENIED_RATES && - status != WLAN_STATUS_CAPS_UNSUPPORTED && - priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - priv->AssociationRequestRetryCnt++; - send_association_request(priv, 0); - return; - } - - if (subtype == IEEE80211_STYPE_REASSOC_RESP && - status != WLAN_STATUS_ASSOC_DENIED_RATES && - status != WLAN_STATUS_CAPS_UNSUPPORTED && - priv->ReAssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - priv->ReAssociationRequestRetryCnt++; - send_association_request(priv, 1); - return; - } - - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - - if (priv->connect_to_any_BSS) { - int bss_index; - priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; - - if ((bss_index = retrieve_bss(priv)) != -1) - atmel_join_bss(priv, bss_index); - } -} - -static void atmel_join_bss(struct atmel_private *priv, int bss_index) -{ - struct bss_info *bss = &priv->BSSinfo[bss_index]; - - memcpy(priv->CurrentBSSID, bss->BSSID, ETH_ALEN); - memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize); - - /* The WPA stuff cares about the current AP address */ - if (priv->use_wpa) - build_wpa_mib(priv); - - /* When switching to AdHoc turn OFF Power Save if needed */ - - if (bss->BSStype == IW_MODE_ADHOC && - priv->operating_mode != IW_MODE_ADHOC && - priv->power_mode) { - priv->power_mode = 0; - priv->listen_interval = 1; - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, - MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); - } - - priv->operating_mode = bss->BSStype; - priv->channel = bss->channel & 0x7f; - priv->beacon_period = bss->beacon_period; - - if (priv->preamble != bss->preamble) { - priv->preamble = bss->preamble; - atmel_set_mib8(priv, Local_Mib_Type, - LOCAL_MIB_PREAMBLE_TYPE, bss->preamble); - } - - if (!priv->wep_is_on && bss->UsingWEP) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - return; - } - - if (priv->wep_is_on && !bss->UsingWEP) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - return; - } - - atmel_enter_state(priv, STATION_STATE_JOINNING); - - if (priv->operating_mode == IW_MODE_INFRA) - join(priv, BSS_TYPE_INFRASTRUCTURE); - else - join(priv, BSS_TYPE_AD_HOC); -} - -static void restart_search(struct atmel_private *priv) -{ - int bss_index; - - if (!priv->connect_to_any_BSS) { - atmel_scan(priv, 1); - } else { - priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; - - if ((bss_index = retrieve_bss(priv)) != -1) - atmel_join_bss(priv, bss_index); - else - atmel_scan(priv, 0); - } -} - -static void smooth_rssi(struct atmel_private *priv, u8 rssi) -{ - u8 old = priv->wstats.qual.level; - u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */ - - switch (priv->firmware_type) { - case ATMEL_FW_TYPE_502E: - max_rssi = 63; /* 502-rmfd-reve max by experiment */ - break; - default: - break; - } - - rssi = rssi * 100 / max_rssi; - if ((rssi + old) % 2) - priv->wstats.qual.level = (rssi + old) / 2 + 1; - else - priv->wstats.qual.level = (rssi + old) / 2; - priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; - priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID; -} - -static void atmel_smooth_qual(struct atmel_private *priv) -{ - unsigned long time_diff = (jiffies - priv->last_qual) / HZ; - while (time_diff--) { - priv->last_qual += HZ; - priv->wstats.qual.qual = priv->wstats.qual.qual / 2; - priv->wstats.qual.qual += - priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000; - priv->beacons_this_sec = 0; - } - priv->wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; - priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID; -} - -/* deals with incoming management frames. */ -static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, - u16 frame_len, u8 rssi) -{ - u16 subtype; - - subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE; - switch (subtype) { - case IEEE80211_STYPE_BEACON: - case IEEE80211_STYPE_PROBE_RESP: - - /* beacon frame has multiple variable-length fields - - never let an engineer loose with a data structure design. */ - { - struct beacon_format { - __le64 timestamp; - __le16 interval; - __le16 capability; - u8 ssid_el_id; - u8 ssid_length; - /* ssid here */ - u8 rates_el_id; - u8 rates_length; - /* rates here */ - u8 ds_el_id; - u8 ds_length; - /* ds here */ - } *beacon = (struct beacon_format *)priv->rx_buf; - - u8 channel, rates_length, ssid_length; - u64 timestamp = le64_to_cpu(beacon->timestamp); - u16 beacon_interval = le16_to_cpu(beacon->interval); - u16 capability = le16_to_cpu(beacon->capability); - u8 *beaconp = priv->rx_buf; - ssid_length = beacon->ssid_length; - /* this blows chunks. */ - if (frame_len < 14 || frame_len < ssid_length + 15) - return; - rates_length = beaconp[beacon->ssid_length + 15]; - if (frame_len < ssid_length + rates_length + 18) - return; - if (ssid_length > MAX_SSID_LENGTH) - return; - channel = beaconp[ssid_length + rates_length + 18]; - - if (priv->station_state == STATION_STATE_READY) { - smooth_rssi(priv, rssi); - if (is_frame_from_current_bss(priv, header)) { - priv->beacons_this_sec++; - atmel_smooth_qual(priv); - if (priv->last_beacon_timestamp) { - /* Note truncate this to 32 bits - kernel can't divide a long */ - u32 beacon_delay = timestamp - priv->last_beacon_timestamp; - int beacons = beacon_delay / (beacon_interval * 1000); - if (beacons > 1) - priv->wstats.miss.beacon += beacons - 1; - } - priv->last_beacon_timestamp = timestamp; - handle_beacon_probe(priv, capability, channel); - } - } - - if (priv->station_state == STATION_STATE_SCANNING) - store_bss_info(priv, header, capability, - beacon_interval, channel, rssi, - ssid_length, - &beacon->rates_el_id, - subtype == IEEE80211_STYPE_BEACON); - } - break; - - case IEEE80211_STYPE_AUTH: - - if (priv->station_state == STATION_STATE_AUTHENTICATING) - authenticate(priv, frame_len); - - break; - - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: - - if (priv->station_state == STATION_STATE_ASSOCIATING || - priv->station_state == STATION_STATE_REASSOCIATING) - associate(priv, frame_len, subtype); - - break; - - case IEEE80211_STYPE_DISASSOC: - if (priv->station_is_associated && - priv->operating_mode == IW_MODE_INFRA && - is_frame_from_current_bss(priv, header)) { - priv->station_was_associated = 0; - priv->station_is_associated = 0; - - atmel_enter_state(priv, STATION_STATE_JOINNING); - join(priv, BSS_TYPE_INFRASTRUCTURE); - } - - break; - - case IEEE80211_STYPE_DEAUTH: - if (priv->operating_mode == IW_MODE_INFRA && - is_frame_from_current_bss(priv, header)) { - priv->station_was_associated = 0; - - atmel_enter_state(priv, STATION_STATE_JOINNING); - join(priv, BSS_TYPE_INFRASTRUCTURE); - } - - break; - } -} - -/* run when timer expires */ -static void atmel_management_timer(struct timer_list *t) -{ - struct atmel_private *priv = from_timer(priv, t, management_timer); - unsigned long flags; - - /* Check if the card has been yanked. */ - if (priv->card && priv->present_callback && - !(*priv->present_callback)(priv->card)) - return; - - spin_lock_irqsave(&priv->irqlock, flags); - - switch (priv->station_state) { - - case STATION_STATE_AUTHENTICATING: - if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - priv->AuthenticationRequestRetryCnt = 0; - restart_search(priv); - } else { - int auth = WLAN_AUTH_OPEN; - priv->AuthenticationRequestRetryCnt++; - priv->CurrentAuthentTransactionSeqNum = 0x0001; - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - if (priv->wep_is_on && priv->exclude_unencrypted) - auth = WLAN_AUTH_SHARED_KEY; - send_authentication_request(priv, auth, NULL, 0); - } - break; - - case STATION_STATE_ASSOCIATING: - if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - priv->AssociationRequestRetryCnt = 0; - restart_search(priv); - } else { - priv->AssociationRequestRetryCnt++; - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - send_association_request(priv, 0); - } - break; - - case STATION_STATE_REASSOCIATING: - if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { - atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); - priv->station_is_associated = 0; - priv->ReAssociationRequestRetryCnt = 0; - restart_search(priv); - } else { - priv->ReAssociationRequestRetryCnt++; - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - send_association_request(priv, 1); - } - break; - - default: - break; - } - - spin_unlock_irqrestore(&priv->irqlock, flags); -} - -static void atmel_command_irq(struct atmel_private *priv) -{ - u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); - u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); - int fast_scan; - union iwreq_data wrqu; - - if (status == CMD_STATUS_IDLE || - status == CMD_STATUS_IN_PROGRESS) - return; - - switch (command) { - case CMD_Start: - if (status == CMD_STATUS_COMPLETE) { - priv->station_was_associated = priv->station_is_associated; - atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, - (u8 *)priv->CurrentBSSID, 6); - atmel_enter_state(priv, STATION_STATE_READY); - } - break; - - case CMD_Scan: - fast_scan = priv->fast_scan; - priv->fast_scan = 0; - - if (status != CMD_STATUS_COMPLETE) { - atmel_scan(priv, 1); - } else { - int bss_index = retrieve_bss(priv); - int notify_scan_complete = 1; - if (bss_index != -1) { - atmel_join_bss(priv, bss_index); - } else if (priv->operating_mode == IW_MODE_ADHOC && - priv->SSID_size != 0) { - start(priv, BSS_TYPE_AD_HOC); - } else { - priv->fast_scan = !fast_scan; - atmel_scan(priv, 1); - notify_scan_complete = 0; - } - priv->site_survey_state = SITE_SURVEY_COMPLETED; - if (notify_scan_complete) { - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); - } - } - break; - - case CMD_SiteSurvey: - priv->fast_scan = 0; - - if (status != CMD_STATUS_COMPLETE) - return; - - priv->site_survey_state = SITE_SURVEY_COMPLETED; - if (priv->station_is_associated) { - atmel_enter_state(priv, STATION_STATE_READY); - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); - } else { - atmel_scan(priv, 1); - } - break; - - case CMD_Join: - if (status == CMD_STATUS_COMPLETE) { - if (priv->operating_mode == IW_MODE_ADHOC) { - priv->station_was_associated = priv->station_is_associated; - atmel_enter_state(priv, STATION_STATE_READY); - } else { - int auth = WLAN_AUTH_OPEN; - priv->AuthenticationRequestRetryCnt = 0; - atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); - - mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); - priv->CurrentAuthentTransactionSeqNum = 0x0001; - if (priv->wep_is_on && priv->exclude_unencrypted) - auth = WLAN_AUTH_SHARED_KEY; - send_authentication_request(priv, auth, NULL, 0); - } - return; - } - - atmel_scan(priv, 1); - } -} - -static int atmel_wakeup_firmware(struct atmel_private *priv) -{ - struct host_info_struct *iface = &priv->host_info; - u16 mr1, mr3; - int i; - - if (priv->card_type == CARD_TYPE_SPI_FLASH) - atmel_set_gcr(priv->dev, GCR_REMAP); - - /* wake up on-board processor */ - atmel_clear_gcr(priv->dev, 0x0040); - atmel_write16(priv->dev, BSR, BSS_SRAM); - - if (priv->card_type == CARD_TYPE_SPI_FLASH) - mdelay(100); - - /* and wait for it */ - for (i = LOOP_RETRY_LIMIT; i; i--) { - mr1 = atmel_read16(priv->dev, MR1); - mr3 = atmel_read16(priv->dev, MR3); - - if (mr3 & MAC_BOOT_COMPLETE) - break; - if (mr1 & MAC_BOOT_COMPLETE && - priv->bus_type == BUS_TYPE_PCCARD) - break; - } - - if (i == 0) { - printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name); - return -EIO; - } - - if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { - printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); - return -ENODEV; - } - - /* now check for completion of MAC initialization through - the FunCtrl field of the IFACE, poll MR1 to detect completion of - MAC initialization, check completion status, set interrupt mask, - enables interrupts and calls Tx and Rx initialization functions */ - - atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE); - - for (i = LOOP_RETRY_LIMIT; i; i--) { - mr1 = atmel_read16(priv->dev, MR1); - mr3 = atmel_read16(priv->dev, MR3); - - if (mr3 & MAC_INIT_COMPLETE) - break; - if (mr1 & MAC_INIT_COMPLETE && - priv->bus_type == BUS_TYPE_PCCARD) - break; - } - - if (i == 0) { - printk(KERN_ALERT "%s: MAC failed to initialise.\n", - priv->dev->name); - return -EIO; - } - - /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */ - if ((mr3 & MAC_INIT_COMPLETE) && - !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) { - printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name); - return -EIO; - } - if ((mr1 & MAC_INIT_COMPLETE) && - !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) { - printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); - return -EIO; - } - - atmel_copy_to_host(priv->dev, (unsigned char *)iface, - priv->host_info_base, sizeof(*iface)); - - iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); - iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); - iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); - iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count); - iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos); - iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size); - iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos); - iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count); - iface->build_version = le16_to_cpu(iface->build_version); - iface->command_pos = le16_to_cpu(iface->command_pos); - iface->major_version = le16_to_cpu(iface->major_version); - iface->minor_version = le16_to_cpu(iface->minor_version); - iface->func_ctrl = le16_to_cpu(iface->func_ctrl); - iface->mac_status = le16_to_cpu(iface->mac_status); - - return 0; -} - -/* determine type of memory and MAC address */ -static int probe_atmel_card(struct net_device *dev) -{ - int rc = 0; - struct atmel_private *priv = netdev_priv(dev); - u8 addr[ETH_ALEN] = {}; - - /* reset pccard */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - - atmel_write16(dev, GCR, 0x0040); - msleep(500); - - if (atmel_read16(dev, MR2) == 0) { - /* No stored firmware so load a small stub which just - tells us the MAC address */ - int i; - priv->card_type = CARD_TYPE_EEPROM; - atmel_write16(dev, BSR, BSS_IRAM); - atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader)); - atmel_set_gcr(dev, GCR_REMAP); - atmel_clear_gcr(priv->dev, 0x0040); - atmel_write16(dev, BSR, BSS_SRAM); - for (i = LOOP_RETRY_LIMIT; i; i--) - if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE) - break; - if (i == 0) { - printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); - } else { - - atmel_copy_to_host(dev, addr, atmel_read16(dev, MR2), 6); - eth_hw_addr_set(dev, addr); - /* got address, now squash it again until the network - interface is opened */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - rc = 1; - } - } else if (atmel_read16(dev, MR4) == 0) { - /* Mac address easy in this case. */ - priv->card_type = CARD_TYPE_PARALLEL_FLASH; - atmel_write16(dev, BSR, 1); - atmel_copy_to_host(dev, addr, 0xc000, 6); - eth_hw_addr_set(dev, addr); - atmel_write16(dev, BSR, 0x200); - rc = 1; - } else { - /* Standard firmware in flash, boot it up and ask - for the Mac Address */ - priv->card_type = CARD_TYPE_SPI_FLASH; - if (atmel_wakeup_firmware(priv) == 0) { - atmel_get_mib(priv, Mac_Address_Mib_Type, 0, addr, 6); - eth_hw_addr_set(dev, addr); - - /* got address, now squash it again until the network - interface is opened */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(dev, GCR, 0x0060); - atmel_write16(dev, GCR, 0x0040); - rc = 1; - } - } - - if (rc) { - if (dev->dev_addr[0] == 0xFF) { - static const u8 default_mac[] = { - 0x00, 0x04, 0x25, 0x00, 0x00, 0x00 - }; - printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); - eth_hw_addr_set(dev, default_mac); - } - } - - return rc; -} - -/* Move the encyption information on the MIB structure. - This routine is for the pre-WPA firmware: later firmware has - a different format MIB and a different routine. */ -static void build_wep_mib(struct atmel_private *priv) -{ - struct { /* NB this is matched to the hardware, don't change. */ - u8 wep_is_on; - u8 default_key; /* 0..3 */ - u8 reserved; - u8 exclude_unencrypted; - - u32 WEPICV_error_count; - u32 WEP_excluded_count; - - u8 wep_keys[MAX_ENCRYPTION_KEYS][13]; - u8 encryption_level; /* 0, 1, 2 */ - u8 reserved2[3]; - } mib; - int i; - - mib.wep_is_on = priv->wep_is_on; - if (priv->wep_is_on) { - if (priv->wep_key_len[priv->default_key] > 5) - mib.encryption_level = 2; - else - mib.encryption_level = 1; - } else { - mib.encryption_level = 0; - } - - mib.default_key = priv->default_key; - mib.exclude_unencrypted = priv->exclude_unencrypted; - - for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) - memcpy(mib.wep_keys[i], priv->wep_keys[i], 13); - - atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); -} - -static void build_wpa_mib(struct atmel_private *priv) -{ - /* This is for the later (WPA enabled) firmware. */ - - struct { /* NB this is matched to the hardware, don't change. */ - u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; - u8 receiver_address[ETH_ALEN]; - u8 wep_is_on; - u8 default_key; /* 0..3 */ - u8 group_key; - u8 exclude_unencrypted; - u8 encryption_type; - u8 reserved; - - u32 WEPICV_error_count; - u32 WEP_excluded_count; - - u8 key_RSC[4][8]; - } mib; - - int i; - - mib.wep_is_on = priv->wep_is_on; - mib.exclude_unencrypted = priv->exclude_unencrypted; - memcpy(mib.receiver_address, priv->CurrentBSSID, ETH_ALEN); - - /* zero all the keys before adding in valid ones. */ - memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value)); - - if (priv->wep_is_on) { - /* There's a comment in the Atmel code to the effect that this - is only valid when still using WEP, it may need to be set to - something to use WPA */ - memset(mib.key_RSC, 0, sizeof(mib.key_RSC)); - - mib.default_key = mib.group_key = 255; - for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) { - if (priv->wep_key_len[i] > 0) { - memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE); - if (i == priv->default_key) { - mib.default_key = i; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite; - } else { - mib.group_key = i; - priv->group_cipher_suite = priv->pairwise_cipher_suite; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1; - mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite; - } - } - } - if (mib.default_key == 255) - mib.default_key = mib.group_key != 255 ? mib.group_key : 0; - if (mib.group_key == 255) - mib.group_key = mib.default_key; - - } - - atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); -} - -static int reset_atmel_card(struct net_device *dev) -{ - /* do everything necessary to wake up the hardware, including - waiting for the lightning strike and throwing the knife switch.... - - set all the Mib values which matter in the card to match - their settings in the atmel_private structure. Some of these - can be altered on the fly, but many (WEP, infrastructure or ad-hoc) - can only be changed by tearing down the world and coming back through - here. - - This routine is also responsible for initialising some - hardware-specific fields in the atmel_private structure, - including a copy of the firmware's hostinfo structure - which is the route into the rest of the firmware datastructures. */ - - struct atmel_private *priv = netdev_priv(dev); - u8 configuration; - int old_state = priv->station_state; - int err = 0; - - /* data to add to the firmware names, in priority order - this implemenents firmware versioning */ - - static char *firmware_modifier[] = { - "-wpa", - "", - NULL - }; - - /* reset pccard */ - if (priv->bus_type == BUS_TYPE_PCCARD) - atmel_write16(priv->dev, GCR, 0x0060); - - /* stop card , disable interrupts */ - atmel_write16(priv->dev, GCR, 0x0040); - - if (priv->card_type == CARD_TYPE_EEPROM) { - /* copy in firmware if needed */ - const struct firmware *fw_entry = NULL; - const unsigned char *fw; - int len = priv->firmware_length; - if (!(fw = priv->firmware)) { - if (priv->firmware_type == ATMEL_FW_TYPE_NONE) { - if (strlen(priv->firmware_id) == 0) { - printk(KERN_INFO - "%s: card type is unknown: assuming at76c502 firmware is OK.\n", - dev->name); - printk(KERN_INFO - "%s: if not, use the firmware= module parameter.\n", - dev->name); - strcpy(priv->firmware_id, "atmel_at76c502.bin"); - } - err = request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev); - if (err != 0) { - printk(KERN_ALERT - "%s: firmware %s is missing, cannot continue.\n", - dev->name, priv->firmware_id); - return err; - } - } else { - int fw_index = 0; - int success = 0; - - /* get firmware filename entry based on firmware type ID */ - while (fw_table[fw_index].fw_type != priv->firmware_type - && fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) - fw_index++; - - /* construct the actual firmware file name */ - if (fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) { - int i; - for (i = 0; firmware_modifier[i]; i++) { - snprintf(priv->firmware_id, 32, "%s%s.%s", fw_table[fw_index].fw_file, - firmware_modifier[i], fw_table[fw_index].fw_file_ext); - priv->firmware_id[31] = '\0'; - if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) { - success = 1; - break; - } - } - } - if (!success) { - printk(KERN_ALERT - "%s: firmware %s is missing, cannot start.\n", - dev->name, priv->firmware_id); - priv->firmware_id[0] = '\0'; - return -ENOENT; - } - } - - fw = fw_entry->data; - len = fw_entry->size; - } - - if (len <= 0x6000) { - atmel_write16(priv->dev, BSR, BSS_IRAM); - atmel_copy_to_card(priv->dev, 0, fw, len); - atmel_set_gcr(priv->dev, GCR_REMAP); - } else { - /* Remap */ - atmel_set_gcr(priv->dev, GCR_REMAP); - atmel_write16(priv->dev, BSR, BSS_IRAM); - atmel_copy_to_card(priv->dev, 0, fw, 0x6000); - atmel_write16(priv->dev, BSR, 0x2ff); - atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); - } - - release_firmware(fw_entry); - } - - err = atmel_wakeup_firmware(priv); - if (err != 0) - return err; - - /* Check the version and set the correct flag for wpa stuff, - old and new firmware is incompatible. - The pre-wpa 3com firmware reports major version 5, - the wpa 3com firmware is major version 4 and doesn't need - the 3com broken-ness filter. */ - priv->use_wpa = (priv->host_info.major_version == 4); - priv->radio_on_broken = (priv->host_info.major_version == 5); - - /* unmask all irq sources */ - atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff); - - /* int Tx system and enable Tx */ - atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0); - atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L); - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0); - atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0); - - priv->tx_desc_free = priv->host_info.tx_desc_count; - priv->tx_desc_head = 0; - priv->tx_desc_tail = 0; - priv->tx_desc_previous = 0; - priv->tx_free_mem = priv->host_info.tx_buff_size; - priv->tx_buff_head = 0; - priv->tx_buff_tail = 0; - - configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); - atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), - configuration | FUNC_CTRL_TxENABLE); - - /* init Rx system and enable */ - priv->rx_desc_head = 0; - - configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); - atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), - configuration | FUNC_CTRL_RxENABLE); - - if (!priv->radio_on_broken) { - if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == - CMD_STATUS_REJECTED_RADIO_OFF) { - printk(KERN_INFO "%s: cannot turn the radio on.\n", - dev->name); - return -EIO; - } - } - - /* set up enough MIB values to run. */ - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate); - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF); - atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold); - atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold); - atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry); - atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry); - atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble); - atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS, - priv->dev->dev_addr, 6); - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); - atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period); - atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4); - atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on); - if (priv->use_wpa) - build_wpa_mib(priv); - else - build_wep_mib(priv); - - if (old_state == STATION_STATE_READY) { - union iwreq_data wrqu; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - eth_zero_addr(wrqu.ap_addr.sa_data); - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - } - - return 0; -} - -static void atmel_send_command(struct atmel_private *priv, int command, - void *cmd, int cmd_size) -{ - if (cmd) - atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET), - cmd, cmd_size); - - atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command); - atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0); -} - -static int atmel_send_command_wait(struct atmel_private *priv, int command, - void *cmd, int cmd_size) -{ - int i, status; - - atmel_send_command(priv, command, cmd, cmd_size); - - for (i = 5000; i; i--) { - status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); - if (status != CMD_STATUS_IDLE && - status != CMD_STATUS_IN_PROGRESS) - break; - udelay(20); - } - - if (i == 0) { - printk(KERN_ALERT "%s: failed to contact MAC.\n", priv->dev->name); - status = CMD_STATUS_HOST_ERROR; - } else { - if (command != CMD_EnableRadio) - status = CMD_STATUS_COMPLETE; - } - - return status; -} - -static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index) -{ - struct get_set_mib m; - m.type = type; - m.size = 1; - m.index = index; - - atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1); - return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE)); -} - -static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data) -{ - struct get_set_mib m; - m.type = type; - m.size = 1; - m.index = index; - m.data[0] = data; - - atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1); -} - -static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, - u16 data) -{ - struct get_set_mib m; - m.type = type; - m.size = 2; - m.index = index; - m.data[0] = data; - m.data[1] = data >> 8; - - atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2); -} - -static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, - const u8 *data, int data_len) -{ - struct get_set_mib m; - m.type = type; - m.size = data_len; - m.index = index; - - if (data_len > MIB_MAX_DATA_BYTES) - printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); - - memcpy(m.data, data, data_len); - atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); -} - -static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, - u8 *data, int data_len) -{ - struct get_set_mib m; - m.type = type; - m.size = data_len; - m.index = index; - - if (data_len > MIB_MAX_DATA_BYTES) - printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); - - atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); - atmel_copy_to_host(priv->dev, data, - atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len); -} - -static void atmel_writeAR(struct net_device *dev, u16 data) -{ - int i; - outw(data, dev->base_addr + AR); - /* Address register appears to need some convincing..... */ - for (i = 0; data != inw(dev->base_addr + AR) && i < 10; i++) - outw(data, dev->base_addr + AR); -} - -static void atmel_copy_to_card(struct net_device *dev, u16 dest, - const unsigned char *src, u16 len) -{ - int i; - atmel_writeAR(dev, dest); - if (dest % 2) { - atmel_write8(dev, DR, *src); - src++; len--; - } - for (i = len; i > 1 ; i -= 2) { - u8 lb = *src++; - u8 hb = *src++; - atmel_write16(dev, DR, lb | (hb << 8)); - } - if (i) - atmel_write8(dev, DR, *src); -} - -static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, - u16 src, u16 len) -{ - int i; - atmel_writeAR(dev, src); - if (src % 2) { - *dest = atmel_read8(dev, DR); - dest++; len--; - } - for (i = len; i > 1 ; i -= 2) { - u16 hw = atmel_read16(dev, DR); - *dest++ = hw; - *dest++ = hw >> 8; - } - if (i) - *dest = atmel_read8(dev, DR); -} - -static void atmel_set_gcr(struct net_device *dev, u16 mask) -{ - outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR); -} - -static void atmel_clear_gcr(struct net_device *dev, u16 mask) -{ - outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR); -} - -static int atmel_lock_mac(struct atmel_private *priv) -{ - int i, j = 20; - retry: - for (i = 5000; i; i--) { - if (!atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) - break; - udelay(20); - } - - if (!i) - return 0; /* timed out */ - - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1); - if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) { - atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); - if (!j--) - return 0; /* timed out */ - goto retry; - } - - return 1; -} - -static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) -{ - atmel_writeAR(priv->dev, pos); - atmel_write16(priv->dev, DR, data); /* card is little-endian */ - atmel_write16(priv->dev, DR, data >> 16); -} - -/***************************************************************************/ -/* There follows the source form of the MAC address reading firmware */ -/***************************************************************************/ -#if 0 - -/* Copyright 2003 Matthew T. Russotto */ -/* But derived from the Atmel 76C502 firmware written by Atmel and */ -/* included in "atmel wireless lan drivers" package */ -/* - This file is part of net.russotto.AtmelMACFW, hereto referred to - as AtmelMACFW - - AtmelMACFW is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - AtmelMACFW is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with AtmelMACFW; if not, see <http://www.gnu.org/licenses/>. - -****************************************************************************/ -/* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ -/* It will probably work on the 76C504 and 76C502 RFMD_3COM */ -/* It only works on SPI EEPROM versions of the card. */ - -/* This firmware initializes the SPI controller and clock, reads the MAC */ -/* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */ -/* address in MR2, and sets MR3 to 0x10 to indicate it is done */ -/* It also puts a complete copy of the EEPROM in SRAM with the offset in */ -/* MR4, for investigational purposes (maybe we can determine chip type */ -/* from that?) */ - - .org 0 - .set MRBASE, 0x8000000 - .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */ - .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */ - .set SRAM_BASE, 0x02000000 - .set SP_BASE, 0x0F300000 - .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */ - .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */ - .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */ - .set STACK_BASE, 0x5600 - .set SP_SR, 0x10 - .set SP_TDRE, 2 /* status register bit -- TDR empty */ - .set SP_RDRF, 1 /* status register bit -- RDR full */ - .set SP_SWRST, 0x80 - .set SP_SPIEN, 0x1 - .set SP_CR, 0 /* control register */ - .set SP_MR, 4 /* mode register */ - .set SP_RDR, 0x08 /* Read Data Register */ - .set SP_TDR, 0x0C /* Transmit Data Register */ - .set SP_CSR0, 0x30 /* chip select registers */ - .set SP_CSR1, 0x34 - .set SP_CSR2, 0x38 - .set SP_CSR3, 0x3C - .set NVRAM_CMD_RDSR, 5 /* read status register */ - .set NVRAM_CMD_READ, 3 /* read data */ - .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */ - .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the - serial output, since SO is normally high. But it - does cause 8 clock cycles and thus 8 bits to be - clocked in to the chip. See Atmel's SPI - controller (e.g. AT91M55800) timing and 4K - SPI EEPROM manuals */ - - .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */ - .set NVRAM_IMAGE, 0x02000200 - .set NVRAM_LENGTH, 0x0200 - .set MAC_ADDRESS_MIB, SRAM_BASE - .set MAC_ADDRESS_LENGTH, 6 - .set MAC_BOOT_FLAG, 0x10 - .set MR1, 0 - .set MR2, 4 - .set MR3, 8 - .set MR4, 0xC -RESET_VECTOR: - b RESET_HANDLER -UNDEF_VECTOR: - b HALT1 -SWI_VECTOR: - b HALT1 -IABORT_VECTOR: - b HALT1 -DABORT_VECTOR: -RESERVED_VECTOR: - b HALT1 -IRQ_VECTOR: - b HALT1 -FIQ_VECTOR: - b HALT1 -HALT1: b HALT1 -RESET_HANDLER: - mov r0, #CPSR_INITIAL - msr CPSR_c, r0 /* This is probably unnecessary */ - -/* I'm guessing this is initializing clock generator electronics for SPI */ - ldr r0, =SPI_CGEN_BASE - mov r1, #0 - mov r1, r1, lsl #3 - orr r1, r1, #0 - str r1, [r0] - ldr r1, [r0, #28] - bic r1, r1, #16 - str r1, [r0, #28] - mov r1, #1 - str r1, [r0, #8] - - ldr r0, =MRBASE - mov r1, #0 - strh r1, [r0, #MR1] - strh r1, [r0, #MR2] - strh r1, [r0, #MR3] - strh r1, [r0, #MR4] - - mov sp, #STACK_BASE - bl SP_INIT - mov r0, #10 - bl DELAY9 - bl GET_MAC_ADDR - bl GET_WHOLE_NVRAM - ldr r0, =MRBASE - ldr r1, =MAC_ADDRESS_MIB - strh r1, [r0, #MR2] - ldr r1, =NVRAM_IMAGE - strh r1, [r0, #MR4] - mov r1, #MAC_BOOT_FLAG - strh r1, [r0, #MR3] -HALT2: b HALT2 -.func Get_Whole_NVRAM, GET_WHOLE_NVRAM -GET_WHOLE_NVRAM: - stmdb sp!, {lr} - mov r2, #0 /* 0th bytes of NVRAM */ - mov r3, #NVRAM_LENGTH - mov r1, #0 /* not used in routine */ - ldr r0, =NVRAM_IMAGE - bl NVRAM_XFER - ldmia sp!, {lr} - bx lr -.endfunc - -.func Get_MAC_Addr, GET_MAC_ADDR -GET_MAC_ADDR: - stmdb sp!, {lr} - mov r2, #0x120 /* address of MAC Address within NVRAM */ - mov r3, #MAC_ADDRESS_LENGTH - mov r1, #0 /* not used in routine */ - ldr r0, =MAC_ADDRESS_MIB - bl NVRAM_XFER - ldmia sp!, {lr} - bx lr -.endfunc -.ltorg -.func Delay9, DELAY9 -DELAY9: - adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */ -DELAYLOOP: - beq DELAY9_done - subs r0, r0, #1 - b DELAYLOOP -DELAY9_done: - bx lr -.endfunc - -.func SP_Init, SP_INIT -SP_INIT: - mov r1, #SP_SWRST - ldr r0, =SP_BASE - str r1, [r0, #SP_CR] /* reset the SPI */ - mov r1, #0 - str r1, [r0, #SP_CR] /* release SPI from reset state */ - mov r1, #SP_SPIEN - str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/ - str r1, [r0, #SP_CR] /* enable the SPI */ - -/* My guess would be this turns on the SPI clock */ - ldr r3, =SPI_CGEN_BASE - ldr r1, [r3, #28] - orr r1, r1, #0x2000 - str r1, [r3, #28] - - ldr r1, =0x2000c01 - str r1, [r0, #SP_CSR0] - ldr r1, =0x2000201 - str r1, [r0, #SP_CSR1] - str r1, [r0, #SP_CSR2] - str r1, [r0, #SP_CSR3] - ldr r1, [r0, #SP_SR] - ldr r0, [r0, #SP_RDR] - bx lr -.endfunc -.func NVRAM_Init, NVRAM_INIT -NVRAM_INIT: - ldr r1, =SP_BASE - ldr r0, [r1, #SP_RDR] - mov r0, #NVRAM_CMD_RDSR - str r0, [r1, #SP_TDR] -SP_loop1: - ldr r0, [r1, #SP_SR] - tst r0, #SP_TDRE - beq SP_loop1 - - mov r0, #SPI_8CLOCKS - str r0, [r1, #SP_TDR] -SP_loop2: - ldr r0, [r1, #SP_SR] - tst r0, #SP_TDRE - beq SP_loop2 - - ldr r0, [r1, #SP_RDR] -SP_loop3: - ldr r0, [r1, #SP_SR] - tst r0, #SP_RDRF - beq SP_loop3 - - ldr r0, [r1, #SP_RDR] - and r0, r0, #255 - bx lr -.endfunc - -.func NVRAM_Xfer, NVRAM_XFER - /* r0 = dest address */ - /* r1 = not used */ - /* r2 = src address within NVRAM */ - /* r3 = length */ -NVRAM_XFER: - stmdb sp!, {r4, r5, lr} - mov r5, r0 /* save r0 (dest address) */ - mov r4, r3 /* save r3 (length) */ - mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */ - and r0, r0, #8 - add r0, r0, #NVRAM_CMD_READ - ldr r1, =NVRAM_SCRATCH - strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */ - strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */ -_local1: - bl NVRAM_INIT - tst r0, #NVRAM_SR_RDY - bne _local1 - mov r0, #20 - bl DELAY9 - mov r2, r4 /* length */ - mov r1, r5 /* dest address */ - mov r0, #2 /* bytes to transfer in command */ - bl NVRAM_XFER2 - ldmia sp!, {r4, r5, lr} - bx lr -.endfunc - -.func NVRAM_Xfer2, NVRAM_XFER2 -NVRAM_XFER2: - stmdb sp!, {r4, r5, r6, lr} - ldr r4, =SP_BASE - mov r3, #0 - cmp r0, #0 - bls _local2 - ldr r5, =NVRAM_SCRATCH -_local4: - ldrb r6, [r5, r3] - str r6, [r4, #SP_TDR] -_local3: - ldr r6, [r4, #SP_SR] - tst r6, #SP_TDRE - beq _local3 - add r3, r3, #1 - cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */ - blo _local4 -_local2: - mov r3, #SPI_8CLOCKS - str r3, [r4, #SP_TDR] - ldr r0, [r4, #SP_RDR] -_local5: - ldr r0, [r4, #SP_SR] - tst r0, #SP_RDRF - beq _local5 - ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */ - mov r0, #0 - cmp r2, #0 /* r2 is # of bytes to copy in */ - bls _local6 -_local7: - ldr r5, [r4, #SP_SR] - tst r5, #SP_TDRE - beq _local7 - str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */ -_local8: - ldr r5, [r4, #SP_SR] - tst r5, #SP_RDRF - beq _local8 - ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */ - strb r5, [r1], #1 /* postindexed */ - add r0, r0, #1 - cmp r0, r2 - blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */ -_local6: - mov r0, #200 - bl DELAY9 - ldmia sp!, {r4, r5, r6, lr} - bx lr -#endif diff --git a/drivers/net/wireless/atmel/atmel.h b/drivers/net/wireless/atmel/atmel.h deleted file mode 100644 index d2aa52cf6e..0000000000 --- a/drivers/net/wireless/atmel/atmel.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2005 Dan Williams and Red Hat, Inc. - - -******************************************************************************/ - -#ifndef _ATMEL_H -#define _ATMEL_H - -typedef enum { - ATMEL_FW_TYPE_NONE = 0, - ATMEL_FW_TYPE_502, - ATMEL_FW_TYPE_502D, - ATMEL_FW_TYPE_502E, - ATMEL_FW_TYPE_502_3COM, - ATMEL_FW_TYPE_504, - ATMEL_FW_TYPE_504_2958, - ATMEL_FW_TYPE_504A_2958, - ATMEL_FW_TYPE_506 -} AtmelFWType; - -struct net_device *init_atmel_card(unsigned short, unsigned long, const AtmelFWType, struct device *, - int (*present_func)(void *), void * ); -void stop_atmel_card( struct net_device *); -int atmel_open( struct net_device * ); - -#endif diff --git a/drivers/net/wireless/atmel/atmel_cs.c b/drivers/net/wireless/atmel/atmel_cs.c deleted file mode 100644 index 58bba9875d..0000000000 --- a/drivers/net/wireless/atmel/atmel_cs.c +++ /dev/null @@ -1,292 +0,0 @@ -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2000-2001 ATMEL Corporation. - Copyright 2003 Simon Kelley. - - This code was developed from version 2.1.1 of the Atmel drivers, - released by Atmel corp. under the GPL in December 2002. It also - includes code from the Linux aironet drivers (C) Benjamin Reed, - and the Linux PCMCIA package, (C) David Hinds. - - For all queries about this code, please contact the current author, - Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This software is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Atmel wireless lan drivers; if not, see - <http://www.gnu.org/licenses/>. - -******************************************************************************/ - -#ifdef __IN_PCMCIA_PACKAGE__ -#include <pcmcia/k_compat.h> -#endif -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/netdevice.h> -#include <linux/moduleparam.h> -#include <linux/device.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> -#include <pcmcia/ciscode.h> - -#include <asm/io.h> -#include <linux/wireless.h> - -#include "atmel.h" - - -/*====================================================================*/ - -MODULE_AUTHOR("Simon Kelley"); -MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); -MODULE_LICENSE("GPL"); - -/*====================================================================*/ - -static int atmel_config(struct pcmcia_device *link); -static void atmel_release(struct pcmcia_device *link); - -static void atmel_detach(struct pcmcia_device *p_dev); - -struct local_info { - struct net_device *eth_dev; -}; - -static int atmel_probe(struct pcmcia_device *p_dev) -{ - struct local_info *local; - int ret; - - dev_dbg(&p_dev->dev, "atmel_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(*local), GFP_KERNEL); - if (!local) - return -ENOMEM; - - p_dev->priv = local; - - ret = atmel_config(p_dev); - if (ret) - goto err_free_priv; - - return 0; - -err_free_priv: - kfree(p_dev->priv); - return ret; -} - -static void atmel_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "atmel_detach\n"); - - atmel_release(link); - - kfree(link->priv); -} - -/* Call-back function to interrogate PCMCIA-specific information - about the current existence of the card */ -static int card_present(void *arg) -{ - struct pcmcia_device *link = (struct pcmcia_device *)arg; - - if (pcmcia_dev_present(link)) - return 1; - - return 0; -} - -static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - -static int atmel_config(struct pcmcia_device *link) -{ - int ret; - const struct pcmcia_device_id *did; - - did = dev_get_drvdata(&link->dev); - - dev_dbg(&link->dev, "atmel_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | - CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - - if (pcmcia_loop_config(link, atmel_config_check, NULL)) - goto failed; - - if (!link->irq) { - dev_err(&link->dev, "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); - goto failed; - } - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - ((struct local_info *)link->priv)->eth_dev = - init_atmel_card(link->irq, - link->resource[0]->start, - did ? did->driver_info : ATMEL_FW_TYPE_NONE, - &link->dev, - card_present, - link); - if (!((struct local_info *)link->priv)->eth_dev) - goto failed; - - - return 0; - - failed: - atmel_release(link); - return -ENODEV; -} - -static void atmel_release(struct pcmcia_device *link) -{ - struct net_device *dev = ((struct local_info *)link->priv)->eth_dev; - - dev_dbg(&link->dev, "atmel_release\n"); - - if (dev) - stop_atmel_card(dev); - ((struct local_info *)link->priv)->eth_dev = NULL; - - pcmcia_disable_device(link); -} - -static int atmel_suspend(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - netif_device_detach(local->eth_dev); - - return 0; -} - -static int atmel_resume(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - atmel_open(local->eth_dev); - netif_device_attach(local->eth_dev); - - return 0; -} - -/*====================================================================*/ -/* We use the driver_info field to store the correct firmware type for a card. */ - -#define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \ - .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \ - PCMCIA_DEV_ID_MATCH_CARD_ID, \ - .manf_id = (manf), \ - .card_id = (card), \ - .driver_info = (kernel_ulong_t)(info), } - -#define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \ - .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \ - PCMCIA_DEV_ID_MATCH_PROD_ID2, \ - .prod_id = { (v1), (v2), NULL, NULL }, \ - .prod_id_hash = { (vh1), (vh2), 0, 0 }, \ - .driver_info = (kernel_ulong_t)(info), } - -static const struct pcmcia_device_id atmel_ids[] = { - PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM), - PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM), - PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504), - PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958), - PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958), - PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502), - PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D), - PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E), - PCMCIA_DEVICE_NULL -}; - -MODULE_DEVICE_TABLE(pcmcia, atmel_ids); - -static struct pcmcia_driver atmel_driver = { - .owner = THIS_MODULE, - .name = "atmel_cs", - .probe = atmel_probe, - .remove = atmel_detach, - .id_table = atmel_ids, - .suspend = atmel_suspend, - .resume = atmel_resume, -}; -module_pcmcia_driver(atmel_driver); - -/* - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - In addition: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ diff --git a/drivers/net/wireless/atmel/atmel_pci.c b/drivers/net/wireless/atmel/atmel_pci.c deleted file mode 100644 index f428dc79d9..0000000000 --- a/drivers/net/wireless/atmel/atmel_pci.c +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/*** -*- linux-c -*- ********************************************************** - - Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. - - Copyright 2004 Simon Kelley. - - -******************************************************************************/ -#include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include "atmel.h" - -MODULE_AUTHOR("Simon Kelley"); -MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); -MODULE_LICENSE("GPL"); - -static const struct pci_device_id card_ids[] = { - { 0x1114, 0x0506, PCI_ANY_ID, PCI_ANY_ID }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, card_ids); - -static int atmel_pci_probe(struct pci_dev *, const struct pci_device_id *); -static void atmel_pci_remove(struct pci_dev *); - -static struct pci_driver atmel_driver = { - .name = "atmel", - .id_table = card_ids, - .probe = atmel_pci_probe, - .remove = atmel_pci_remove, -}; - - -static int atmel_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *pent) -{ - struct net_device *dev; - - if (pci_enable_device(pdev)) - return -ENODEV; - - pci_set_master(pdev); - - dev = init_atmel_card(pdev->irq, pdev->resource[1].start, - ATMEL_FW_TYPE_506, - &pdev->dev, NULL, NULL); - if (!dev) { - pci_disable_device(pdev); - return -ENODEV; - } - - pci_set_drvdata(pdev, dev); - return 0; -} - -static void atmel_pci_remove(struct pci_dev *pdev) -{ - stop_atmel_card(pci_get_drvdata(pdev)); -} - -module_pci_driver(atmel_driver); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c index d55f3271d6..4f0c1e1a8e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c @@ -20,6 +20,7 @@ static void __exit brcmf_bca_exit(void) brcmf_fwvid_unregister_vendor(BRCMF_FWVENDOR_BCA, THIS_MODULE); } +MODULE_DESCRIPTION("Broadcom FullMAC WLAN driver plugin for Broadcom AP chipsets"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(BRCMFMAC); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 0ff15d4083..625b7cb37f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -867,7 +867,7 @@ struct wireless_dev *brcmf_apsta_add_vif(struct wiphy *wiphy, const char *name, goto fail; } - strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); + strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name)); err = brcmf_net_attach(ifp, true); if (err) { bphy_err(drvr, "Registering netdevice failed\n"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index a194b0e68e..b6d458e022 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -578,18 +578,16 @@ static int __init brcmf_common_pd_probe(struct platform_device *pdev) return 0; } -static int brcmf_common_pd_remove(struct platform_device *pdev) +static void brcmf_common_pd_remove(struct platform_device *pdev) { brcmf_dbg(INFO, "Enter\n"); if (brcmfmac_pdata->power_off) brcmfmac_pdata->power_off(); - - return 0; } static struct platform_driver brcmf_pd = { - .remove = brcmf_common_pd_remove, + .remove_new = brcmf_common_pd_remove, .driver = { .name = BRCMFMAC_PDATA_NAME, } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c index f82fbbe3ec..90d06cda03 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c @@ -20,6 +20,7 @@ static void __exit brcmf_cyw_exit(void) brcmf_fwvid_unregister_vendor(BRCMF_FWVENDOR_CYW, THIS_MODULE); } +MODULE_DESCRIPTION("Broadcom FullMAC WLAN driver plugin for Cypress/Infineon chipsets"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(BRCMFMAC); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c index 86ff174936..c3a6021976 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c @@ -83,6 +83,15 @@ static const struct dmi_system_id dmi_platform_data[] = { .driver_data = (void *)&acepc_t8_data, }, { + /* ACEPC W5 Pro Cherry Trail Z8350 HDMI stick, same wifi as the T8 */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"), + DMI_MATCH(DMI_CHASSIS_TYPE, "3"), + DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), + }, + .driver_data = (void *)&acepc_t8_data, + }, + { /* Chuwi Hi8 Pro with D2D3_Hi8Pro.233 BIOS */ .matches = { DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Hampoo"), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index d4492d02e4..6e0c90f471 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2334,7 +2334,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, goto fail; } - strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); + strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name)); ifp->ndev->name_assign_type = name_assign_type; err = brcmf_net_attach(ifp, true); if (err) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 80220685f5..d7fb88bb6a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -2707,7 +2707,6 @@ MODULE_DEVICE_TABLE(pci, brcmf_pcie_devid_table); static struct pci_driver brcmf_pciedrvr = { - .node = {}, .name = KBUILD_MODNAME, .id_table = brcmf_pcie_devid_table, .probe = brcmf_pcie_probe, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index 2178675ae1..0ccf735316 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1581,7 +1581,7 @@ static int brcmf_usb_reset_device(struct device *dev, void *notused) void brcmf_usb_exit(void) { - struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver; + struct device_driver *drv = &brcmf_usbdrvr.driver; int ret; brcmf_dbg(USB, "Enter\n"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c index 02918d4345..b66135e3cf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c @@ -20,6 +20,7 @@ static void __exit brcmf_wcc_exit(void) brcmf_fwvid_unregister_vendor(BRCMF_FWVENDOR_WCC, THIS_MODULE); } +MODULE_DESCRIPTION("Broadcom FullMAC WLAN driver plugin for Broadcom mobility chipsets"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(BRCMFMAC); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c index 5a6d9c8655..f6962e558d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c @@ -341,7 +341,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) /* store the country code for passing up as a regulatory hint */ wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len); if (brcms_c_country_valid(ccode)) - strncpy(wlc->pub->srom_ccode, ccode, ccode_len); + memcpy(wlc->pub->srom_ccode, ccode, ccode_len); /* * If no custom world domain is found in the SROM, use the @@ -354,10 +354,10 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) } /* save default country for exiting 11d regulatory mode */ - strncpy(wlc->country_default, ccode, ccode_len); + memcpy(wlc->country_default, ccode, ccode_len); /* initialize autocountry_default to driver default */ - strncpy(wlc->autocountry_default, ccode, ccode_len); + memcpy(wlc->autocountry_default, ccode, ccode_len); brcms_c_set_country(wlc_cm, wlc_cm->world_regd); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c index b7df576bb8..3d5c1ef8f7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c @@ -584,8 +584,7 @@ struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc, rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase); /* make a private copy of our callers name */ - strncpy(di->name, name, MAXNAMEL); - di->name[MAXNAMEL - 1] = '\0'; + strscpy(di->name, name, sizeof(di->name)); di->dmadev = core->dma_dev; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index b3663c5ef3..34460b5815 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -5551,8 +5551,8 @@ int brcms_c_module_register(struct brcms_pub *pub, /* find an empty entry and just add, no duplication check! */ for (i = 0; i < BRCMS_MAXMODULES; i++) { if (wlc->modulecb[i].name[0] == '\0') { - strncpy(wlc->modulecb[i].name, name, - sizeof(wlc->modulecb[i].name) - 1); + strscpy(wlc->modulecb[i].name, name, + sizeof(wlc->modulecb[i].name)); wlc->modulecb[i].hdl = hdl; wlc->modulecb[i].down_fn = d_fn; return 0; diff --git a/drivers/net/wireless/cisco/Kconfig b/drivers/net/wireless/cisco/Kconfig deleted file mode 100644 index b40ee25aca..0000000000 --- a/drivers/net/wireless/cisco/Kconfig +++ /dev/null @@ -1,59 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config WLAN_VENDOR_CISCO - bool "Cisco devices" - default y - help - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all the - questions about these cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_CISCO - -config AIRO - tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" - depends on CFG80211 && (PCI || BROKEN) - select WIRELESS_EXT - select CRYPTO - select CRYPTO_SKCIPHER - select WEXT_SPY - select WEXT_PRIV - help - This is the standard Linux driver to support Cisco/Aironet ISA and - PCI 802.11 wireless cards. - It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - - with or without encryption) as well as card before the Cisco - acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). - - This driver support both the standard Linux Wireless Extensions - and Cisco proprietary API, so both the Linux Wireless Tools and the - Cisco Linux utilities can be used to configure the card. - - The driver can be compiled as a module and will be named "airo". - -config AIRO_CS - tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on CFG80211 && PCMCIA - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select CRYPTO - select CRYPTO_AES - select CRYPTO_CTR - help - This is the standard Linux driver to support Cisco/Aironet PCMCIA - 802.11 wireless cards. This driver is the same as the Aironet - driver part of the Linux Pcmcia package. - It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - - with or without encryption) as well as card before the Cisco - acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also - supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom - 802.11b cards. - - This driver support both the standard Linux Wireless Extensions - and Cisco proprietary API, so both the Linux Wireless Tools and the - Cisco Linux utilities can be used to configure the card. - -endif # WLAN_VENDOR_CISCO diff --git a/drivers/net/wireless/cisco/Makefile b/drivers/net/wireless/cisco/Makefile deleted file mode 100644 index 506a19ce37..0000000000 --- a/drivers/net/wireless/cisco/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_AIRO) += airo.o -obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c deleted file mode 100644 index dbd13f7aa3..0000000000 --- a/drivers/net/wireless/cisco/airo.c +++ /dev/null @@ -1,8288 +0,0 @@ -/*====================================================================== - - Aironet driver for 4500 and 4800 series cards - - This code is released under both the GPL version 2 and BSD licenses. - Either license may be used. The respective licenses are found at - the end of this file. - - This code was developed by Benjamin Reed <breed@users.sourceforge.net> - including portions of which come from the Aironet PC4500 - Developer's Reference Manual and used with permission. Copyright - (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use - code in the Developer's manual was granted for this driver by - Aironet. Major code contributions were received from Javier Achirica - <achirica@users.sourceforge.net> and Jean Tourrilhes <jt@hpl.hp.com>. - Code was also integrated from the Cisco Aironet driver for Linux. - Support for MPI350 cards was added by Fabrice Bellet - <fabrice@bellet.info>. - -======================================================================*/ - -#include <linux/err.h> -#include <linux/init.h> - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/proc_fs.h> - -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/in.h> -#include <linux/bitops.h> -#include <linux/scatterlist.h> -#include <linux/crypto.h> -#include <linux/io.h> -#include <asm/unaligned.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/if_arp.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/uaccess.h> -#include <linux/kthread.h> -#include <linux/freezer.h> - -#include <crypto/aes.h> -#include <crypto/skcipher.h> - -#include <net/cfg80211.h> -#include <net/iw_handler.h> - -#include "airo.h" - -#define DRV_NAME "airo" - -#ifdef CONFIG_PCI -static const struct pci_device_id card_ids[] = { - { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, - { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, card_ids); - -static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *); -static void airo_pci_remove(struct pci_dev *); -static int __maybe_unused airo_pci_suspend(struct device *dev); -static int __maybe_unused airo_pci_resume(struct device *dev); - -static SIMPLE_DEV_PM_OPS(airo_pci_pm_ops, - airo_pci_suspend, - airo_pci_resume); - -static struct pci_driver airo_driver = { - .name = DRV_NAME, - .id_table = card_ids, - .probe = airo_pci_probe, - .remove = airo_pci_remove, - .driver.pm = &airo_pci_pm_ops, -}; -#endif /* CONFIG_PCI */ - -/* Include Wireless Extension definition and check version - Jean II */ -#include <linux/wireless.h> -#define WIRELESS_SPY /* enable iwspy support */ - -#define CISCO_EXT /* enable Cisco extensions */ -#ifdef CISCO_EXT -#include <linux/delay.h> -#endif - -/* Hack to do some power saving */ -#define POWER_ON_DOWN - -/* As you can see this list is HUGH! - I really don't know what a lot of these counts are about, but they - are all here for completeness. If the IGNLABEL macro is put in - infront of the label, that statistic will not be included in the list - of statistics in the /proc filesystem */ - -#define IGNLABEL(comment) NULL -static const char *statsLabels[] = { - "RxOverrun", - IGNLABEL("RxPlcpCrcErr"), - IGNLABEL("RxPlcpFormatErr"), - IGNLABEL("RxPlcpLengthErr"), - "RxMacCrcErr", - "RxMacCrcOk", - "RxWepErr", - "RxWepOk", - "RetryLong", - "RetryShort", - "MaxRetries", - "NoAck", - "NoCts", - "RxAck", - "RxCts", - "TxAck", - "TxRts", - "TxCts", - "TxMc", - "TxBc", - "TxUcFrags", - "TxUcPackets", - "TxBeacon", - "RxBeacon", - "TxSinColl", - "TxMulColl", - "DefersNo", - "DefersProt", - "DefersEngy", - "DupFram", - "RxFragDisc", - "TxAged", - "RxAged", - "LostSync-MaxRetry", - "LostSync-MissedBeacons", - "LostSync-ArlExceeded", - "LostSync-Deauth", - "LostSync-Disassoced", - "LostSync-TsfTiming", - "HostTxMc", - "HostTxBc", - "HostTxUc", - "HostTxFail", - "HostRxMc", - "HostRxBc", - "HostRxUc", - "HostRxDiscard", - IGNLABEL("HmacTxMc"), - IGNLABEL("HmacTxBc"), - IGNLABEL("HmacTxUc"), - IGNLABEL("HmacTxFail"), - IGNLABEL("HmacRxMc"), - IGNLABEL("HmacRxBc"), - IGNLABEL("HmacRxUc"), - IGNLABEL("HmacRxDiscard"), - IGNLABEL("HmacRxAccepted"), - "SsidMismatch", - "ApMismatch", - "RatesMismatch", - "AuthReject", - "AuthTimeout", - "AssocReject", - "AssocTimeout", - IGNLABEL("ReasonOutsideTable"), - IGNLABEL("ReasonStatus1"), - IGNLABEL("ReasonStatus2"), - IGNLABEL("ReasonStatus3"), - IGNLABEL("ReasonStatus4"), - IGNLABEL("ReasonStatus5"), - IGNLABEL("ReasonStatus6"), - IGNLABEL("ReasonStatus7"), - IGNLABEL("ReasonStatus8"), - IGNLABEL("ReasonStatus9"), - IGNLABEL("ReasonStatus10"), - IGNLABEL("ReasonStatus11"), - IGNLABEL("ReasonStatus12"), - IGNLABEL("ReasonStatus13"), - IGNLABEL("ReasonStatus14"), - IGNLABEL("ReasonStatus15"), - IGNLABEL("ReasonStatus16"), - IGNLABEL("ReasonStatus17"), - IGNLABEL("ReasonStatus18"), - IGNLABEL("ReasonStatus19"), - "RxMan", - "TxMan", - "RxRefresh", - "TxRefresh", - "RxPoll", - "TxPoll", - "HostRetries", - "LostSync-HostReq", - "HostTxBytes", - "HostRxBytes", - "ElapsedUsec", - "ElapsedSec", - "LostSyncBetterAP", - "PrivacyMismatch", - "Jammed", - "DiscRxNotWepped", - "PhyEleMismatch", - (char*)-1 }; -#ifndef RUN_AT -#define RUN_AT(x) (jiffies+(x)) -#endif - - -/* These variables are for insmod, since it seems that the rates - can only be set in setup_card. Rates should be a comma separated - (no spaces) list of rates (up to 8). */ - -static int rates[8]; -static char *ssids[3]; - -static int io[4]; -static int irq[4]; - -static -int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at. - 0 means no limit. For old cards this was 4 */ - -static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */ -static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read - the bap, needed on some older cards and buses. */ -static int adhoc; - -static int probe = 1; - -static kuid_t proc_kuid; -static int proc_uid /* = 0 */; - -static kgid_t proc_kgid; -static int proc_gid /* = 0 */; - -static int airo_perm = 0555; - -static int proc_perm = 0644; - -MODULE_AUTHOR("Benjamin Reed"); -MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet cards. " - "Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs."); -MODULE_LICENSE("Dual BSD/GPL"); -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param_array(rates, int, NULL, 0); -module_param_array(ssids, charp, NULL, 0); -module_param(auto_wep, int, 0); -MODULE_PARM_DESC(auto_wep, - "If non-zero, the driver will keep looping through the authentication options until an association is made. " - "The value of auto_wep is number of the wep keys to check. " - "A value of 2 will try using the key at index 0 and index 1."); -module_param(aux_bap, int, 0); -MODULE_PARM_DESC(aux_bap, - "If non-zero, the driver will switch into a mode that seems to work better for older cards with some older buses. " - "Before switching it checks that the switch is needed."); -module_param(maxencrypt, int, 0); -MODULE_PARM_DESC(maxencrypt, - "The maximum speed that the card can do encryption. " - "Units are in 512kbs. " - "Zero (default) means there is no limit. " - "Older cards used to be limited to 2mbs (4)."); -module_param(adhoc, int, 0); -MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode."); -module_param(probe, int, 0); -MODULE_PARM_DESC(probe, "If zero, the driver won't start the card."); - -module_param(proc_uid, int, 0); -MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to."); -module_param(proc_gid, int, 0); -MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to."); -module_param(airo_perm, int, 0); -MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet."); -module_param(proc_perm, int, 0); -MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc"); - -/* This is a kind of sloppy hack to get this information to OUT4500 and - IN4500. I would be extremely interested in the situation where this - doesn't work though!!! */ -static int do8bitIO /* = 0 */; - -/* Return codes */ -#define SUCCESS 0 -#define ERROR -1 -#define NO_PACKET -2 - -/* Commands */ -#define NOP2 0x0000 -#define MAC_ENABLE 0x0001 -#define MAC_DISABLE 0x0002 -#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */ -#define CMD_SOFTRESET 0x0004 -#define HOSTSLEEP 0x0005 -#define CMD_MAGIC_PKT 0x0006 -#define CMD_SETWAKEMASK 0x0007 -#define CMD_READCFG 0x0008 -#define CMD_SETMODE 0x0009 -#define CMD_ALLOCATETX 0x000a -#define CMD_TRANSMIT 0x000b -#define CMD_DEALLOCATETX 0x000c -#define NOP 0x0010 -#define CMD_WORKAROUND 0x0011 -#define CMD_ALLOCATEAUX 0x0020 -#define CMD_ACCESS 0x0021 -#define CMD_PCIBAP 0x0022 -#define CMD_PCIAUX 0x0023 -#define CMD_ALLOCBUF 0x0028 -#define CMD_GETTLV 0x0029 -#define CMD_PUTTLV 0x002a -#define CMD_DELTLV 0x002b -#define CMD_FINDNEXTTLV 0x002c -#define CMD_PSPNODES 0x0030 -#define CMD_SETCW 0x0031 -#define CMD_SETPCF 0x0032 -#define CMD_SETPHYREG 0x003e -#define CMD_TXTEST 0x003f -#define MAC_ENABLETX 0x0101 -#define CMD_LISTBSS 0x0103 -#define CMD_SAVECFG 0x0108 -#define CMD_ENABLEAUX 0x0111 -#define CMD_WRITERID 0x0121 -#define CMD_USEPSPNODES 0x0130 -#define MAC_ENABLERX 0x0201 - -/* Command errors */ -#define ERROR_QUALIF 0x00 -#define ERROR_ILLCMD 0x01 -#define ERROR_ILLFMT 0x02 -#define ERROR_INVFID 0x03 -#define ERROR_INVRID 0x04 -#define ERROR_LARGE 0x05 -#define ERROR_NDISABL 0x06 -#define ERROR_ALLOCBSY 0x07 -#define ERROR_NORD 0x0B -#define ERROR_NOWR 0x0C -#define ERROR_INVFIDTX 0x0D -#define ERROR_TESTACT 0x0E -#define ERROR_TAGNFND 0x12 -#define ERROR_DECODE 0x20 -#define ERROR_DESCUNAV 0x21 -#define ERROR_BADLEN 0x22 -#define ERROR_MODE 0x80 -#define ERROR_HOP 0x81 -#define ERROR_BINTER 0x82 -#define ERROR_RXMODE 0x83 -#define ERROR_MACADDR 0x84 -#define ERROR_RATES 0x85 -#define ERROR_ORDER 0x86 -#define ERROR_SCAN 0x87 -#define ERROR_AUTH 0x88 -#define ERROR_PSMODE 0x89 -#define ERROR_RTYPE 0x8A -#define ERROR_DIVER 0x8B -#define ERROR_SSID 0x8C -#define ERROR_APLIST 0x8D -#define ERROR_AUTOWAKE 0x8E -#define ERROR_LEAP 0x8F - -/* Registers */ -#define COMMAND 0x00 -#define PARAM0 0x02 -#define PARAM1 0x04 -#define PARAM2 0x06 -#define STATUS 0x08 -#define RESP0 0x0a -#define RESP1 0x0c -#define RESP2 0x0e -#define LINKSTAT 0x10 -#define SELECT0 0x18 -#define OFFSET0 0x1c -#define RXFID 0x20 -#define TXALLOCFID 0x22 -#define TXCOMPLFID 0x24 -#define DATA0 0x36 -#define EVSTAT 0x30 -#define EVINTEN 0x32 -#define EVACK 0x34 -#define SWS0 0x28 -#define SWS1 0x2a -#define SWS2 0x2c -#define SWS3 0x2e -#define AUXPAGE 0x3A -#define AUXOFF 0x3C -#define AUXDATA 0x3E - -#define FID_TX 1 -#define FID_RX 2 -/* Offset into aux memory for descriptors */ -#define AUX_OFFSET 0x800 -/* Size of allocated packets */ -#define PKTSIZE 1840 -#define RIDSIZE 2048 -/* Size of the transmit queue */ -#define MAXTXQ 64 - -/* BAP selectors */ -#define BAP0 0 /* Used for receiving packets */ -#define BAP1 2 /* Used for xmiting packets and working with RIDS */ - -/* Flags */ -#define COMMAND_BUSY 0x8000 - -#define BAP_BUSY 0x8000 -#define BAP_ERR 0x4000 -#define BAP_DONE 0x2000 - -#define PROMISC 0xffff -#define NOPROMISC 0x0000 - -#define EV_CMD 0x10 -#define EV_CLEARCOMMANDBUSY 0x4000 -#define EV_RX 0x01 -#define EV_TX 0x02 -#define EV_TXEXC 0x04 -#define EV_ALLOC 0x08 -#define EV_LINK 0x80 -#define EV_AWAKE 0x100 -#define EV_TXCPY 0x400 -#define EV_UNKNOWN 0x800 -#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */ -#define EV_AWAKEN 0x2000 -#define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC) - -#ifdef CHECK_UNKNOWN_INTS -#define IGNORE_INTS (EV_CMD | EV_UNKNOWN) -#else -#define IGNORE_INTS (~STATUS_INTS) -#endif - -/* RID TYPES */ -#define RID_RW 0x20 - -/* The RIDs */ -#define RID_CAPABILITIES 0xFF00 -#define RID_APINFO 0xFF01 -#define RID_RADIOINFO 0xFF02 -#define RID_UNKNOWN3 0xFF03 -#define RID_RSSI 0xFF04 -#define RID_CONFIG 0xFF10 -#define RID_SSID 0xFF11 -#define RID_APLIST 0xFF12 -#define RID_DRVNAME 0xFF13 -#define RID_ETHERENCAP 0xFF14 -#define RID_WEP_TEMP 0xFF15 -#define RID_WEP_PERM 0xFF16 -#define RID_MODULATION 0xFF17 -#define RID_OPTIONS 0xFF18 -#define RID_ACTUALCONFIG 0xFF20 /*readonly*/ -#define RID_FACTORYCONFIG 0xFF21 -#define RID_UNKNOWN22 0xFF22 -#define RID_LEAPUSERNAME 0xFF23 -#define RID_LEAPPASSWORD 0xFF24 -#define RID_STATUS 0xFF50 -#define RID_BEACON_HST 0xFF51 -#define RID_BUSY_HST 0xFF52 -#define RID_RETRIES_HST 0xFF53 -#define RID_UNKNOWN54 0xFF54 -#define RID_UNKNOWN55 0xFF55 -#define RID_UNKNOWN56 0xFF56 -#define RID_MIC 0xFF57 -#define RID_STATS16 0xFF60 -#define RID_STATS16DELTA 0xFF61 -#define RID_STATS16DELTACLEAR 0xFF62 -#define RID_STATS 0xFF68 -#define RID_STATSDELTA 0xFF69 -#define RID_STATSDELTACLEAR 0xFF6A -#define RID_ECHOTEST_RID 0xFF70 -#define RID_ECHOTEST_RESULTS 0xFF71 -#define RID_BSSLISTFIRST 0xFF72 -#define RID_BSSLISTNEXT 0xFF73 -#define RID_WPA_BSSLISTFIRST 0xFF74 -#define RID_WPA_BSSLISTNEXT 0xFF75 - -typedef struct { - u16 cmd; - u16 parm0; - u16 parm1; - u16 parm2; -} Cmd; - -typedef struct { - u16 status; - u16 rsp0; - u16 rsp1; - u16 rsp2; -} Resp; - -/* - * Rids and endian-ness: The Rids will always be in cpu endian, since - * this all the patches from the big-endian guys end up doing that. - * so all rid access should use the read/writeXXXRid routines. - */ - -/* This structure came from an email sent to me from an engineer at - aironet for inclusion into this driver */ -typedef struct WepKeyRid WepKeyRid; -struct WepKeyRid { - __le16 len; - __le16 kindex; - u8 mac[ETH_ALEN]; - __le16 klen; - u8 key[16]; -} __packed; - -/* These structures are from the Aironet's PC4500 Developers Manual */ -typedef struct Ssid Ssid; -struct Ssid { - __le16 len; - u8 ssid[32]; -} __packed; - -typedef struct SsidRid SsidRid; -struct SsidRid { - __le16 len; - Ssid ssids[3]; -} __packed; - -typedef struct ModulationRid ModulationRid; -struct ModulationRid { - __le16 len; - __le16 modulation; -#define MOD_DEFAULT cpu_to_le16(0) -#define MOD_CCK cpu_to_le16(1) -#define MOD_MOK cpu_to_le16(2) -} __packed; - -typedef struct ConfigRid ConfigRid; -struct ConfigRid { - __le16 len; /* sizeof(ConfigRid) */ - __le16 opmode; /* operating mode */ -#define MODE_STA_IBSS cpu_to_le16(0) -#define MODE_STA_ESS cpu_to_le16(1) -#define MODE_AP cpu_to_le16(2) -#define MODE_AP_RPTR cpu_to_le16(3) -#define MODE_CFG_MASK cpu_to_le16(0xff) -#define MODE_ETHERNET_HOST cpu_to_le16(0<<8) /* rx payloads converted */ -#define MODE_LLC_HOST cpu_to_le16(1<<8) /* rx payloads left as is */ -#define MODE_AIRONET_EXTEND cpu_to_le16(1<<9) /* enable Aironet extensions */ -#define MODE_AP_INTERFACE cpu_to_le16(1<<10) /* enable ap interface extensions */ -#define MODE_ANTENNA_ALIGN cpu_to_le16(1<<11) /* enable antenna alignment */ -#define MODE_ETHER_LLC cpu_to_le16(1<<12) /* enable ethernet LLC */ -#define MODE_LEAF_NODE cpu_to_le16(1<<13) /* enable leaf node bridge */ -#define MODE_CF_POLLABLE cpu_to_le16(1<<14) /* enable CF pollable */ -#define MODE_MIC cpu_to_le16(1<<15) /* enable MIC */ - __le16 rmode; /* receive mode */ -#define RXMODE_BC_MC_ADDR cpu_to_le16(0) -#define RXMODE_BC_ADDR cpu_to_le16(1) /* ignore multicasts */ -#define RXMODE_ADDR cpu_to_le16(2) /* ignore multicast and broadcast */ -#define RXMODE_RFMON cpu_to_le16(3) /* wireless monitor mode */ -#define RXMODE_RFMON_ANYBSS cpu_to_le16(4) -#define RXMODE_LANMON cpu_to_le16(5) /* lan style monitor -- data packets only */ -#define RXMODE_MASK cpu_to_le16(255) -#define RXMODE_DISABLE_802_3_HEADER cpu_to_le16(1<<8) /* disables 802.3 header on rx */ -#define RXMODE_FULL_MASK (RXMODE_MASK | RXMODE_DISABLE_802_3_HEADER) -#define RXMODE_NORMALIZED_RSSI cpu_to_le16(1<<9) /* return normalized RSSI */ - __le16 fragThresh; - __le16 rtsThres; - u8 macAddr[ETH_ALEN]; - u8 rates[8]; - __le16 shortRetryLimit; - __le16 longRetryLimit; - __le16 txLifetime; /* in kusec */ - __le16 rxLifetime; /* in kusec */ - __le16 stationary; - __le16 ordering; - __le16 u16deviceType; /* for overriding device type */ - __le16 cfpRate; - __le16 cfpDuration; - __le16 _reserved1[3]; - /*---------- Scanning/Associating ----------*/ - __le16 scanMode; -#define SCANMODE_ACTIVE cpu_to_le16(0) -#define SCANMODE_PASSIVE cpu_to_le16(1) -#define SCANMODE_AIROSCAN cpu_to_le16(2) - __le16 probeDelay; /* in kusec */ - __le16 probeEnergyTimeout; /* in kusec */ - __le16 probeResponseTimeout; - __le16 beaconListenTimeout; - __le16 joinNetTimeout; - __le16 authTimeout; - __le16 authType; -#define AUTH_OPEN cpu_to_le16(0x1) -#define AUTH_ENCRYPT cpu_to_le16(0x101) -#define AUTH_SHAREDKEY cpu_to_le16(0x102) -#define AUTH_ALLOW_UNENCRYPTED cpu_to_le16(0x200) - __le16 associationTimeout; - __le16 specifiedApTimeout; - __le16 offlineScanInterval; - __le16 offlineScanDuration; - __le16 linkLossDelay; - __le16 maxBeaconLostTime; - __le16 refreshInterval; -#define DISABLE_REFRESH cpu_to_le16(0xFFFF) - __le16 _reserved1a[1]; - /*---------- Power save operation ----------*/ - __le16 powerSaveMode; -#define POWERSAVE_CAM cpu_to_le16(0) -#define POWERSAVE_PSP cpu_to_le16(1) -#define POWERSAVE_PSPCAM cpu_to_le16(2) - __le16 sleepForDtims; - __le16 listenInterval; - __le16 fastListenInterval; - __le16 listenDecay; - __le16 fastListenDelay; - __le16 _reserved2[2]; - /*---------- Ap/Ibss config items ----------*/ - __le16 beaconPeriod; - __le16 atimDuration; - __le16 hopPeriod; - __le16 channelSet; - __le16 channel; - __le16 dtimPeriod; - __le16 bridgeDistance; - __le16 radioID; - /*---------- Radio configuration ----------*/ - __le16 radioType; -#define RADIOTYPE_DEFAULT cpu_to_le16(0) -#define RADIOTYPE_802_11 cpu_to_le16(1) -#define RADIOTYPE_LEGACY cpu_to_le16(2) - u8 rxDiversity; - u8 txDiversity; - __le16 txPower; -#define TXPOWER_DEFAULT 0 - __le16 rssiThreshold; -#define RSSI_DEFAULT 0 - __le16 modulation; -#define PREAMBLE_AUTO cpu_to_le16(0) -#define PREAMBLE_LONG cpu_to_le16(1) -#define PREAMBLE_SHORT cpu_to_le16(2) - __le16 preamble; - __le16 homeProduct; - __le16 radioSpecific; - /*---------- Aironet Extensions ----------*/ - u8 nodeName[16]; - __le16 arlThreshold; - __le16 arlDecay; - __le16 arlDelay; - __le16 _reserved4[1]; - /*---------- Aironet Extensions ----------*/ - u8 magicAction; -#define MAGIC_ACTION_STSCHG 1 -#define MAGIC_ACTION_RESUME 2 -#define MAGIC_IGNORE_MCAST (1<<8) -#define MAGIC_IGNORE_BCAST (1<<9) -#define MAGIC_SWITCH_TO_PSP (0<<10) -#define MAGIC_STAY_IN_CAM (1<<10) - u8 magicControl; - __le16 autoWake; -} __packed; - -typedef struct StatusRid StatusRid; -struct StatusRid { - __le16 len; - u8 mac[ETH_ALEN]; - __le16 mode; - __le16 errorCode; - __le16 sigQuality; - __le16 SSIDlen; - char SSID[32]; - char apName[16]; - u8 bssid[4][ETH_ALEN]; - __le16 beaconPeriod; - __le16 dimPeriod; - __le16 atimDuration; - __le16 hopPeriod; - __le16 channelSet; - __le16 channel; - __le16 hopsToBackbone; - __le16 apTotalLoad; - __le16 generatedLoad; - __le16 accumulatedArl; - __le16 signalQuality; - __le16 currentXmitRate; - __le16 apDevExtensions; - __le16 normalizedSignalStrength; - __le16 shortPreamble; - u8 apIP[4]; - u8 noisePercent; /* Noise percent in last second */ - u8 noisedBm; /* Noise dBm in last second */ - u8 noiseAvePercent; /* Noise percent in last minute */ - u8 noiseAvedBm; /* Noise dBm in last minute */ - u8 noiseMaxPercent; /* Highest noise percent in last minute */ - u8 noiseMaxdBm; /* Highest noise dbm in last minute */ - __le16 load; - u8 carrier[4]; - __le16 assocStatus; -#define STAT_NOPACKETS 0 -#define STAT_NOCARRIERSET 10 -#define STAT_GOTCARRIERSET 11 -#define STAT_WRONGSSID 20 -#define STAT_BADCHANNEL 25 -#define STAT_BADBITRATES 30 -#define STAT_BADPRIVACY 35 -#define STAT_APFOUND 40 -#define STAT_APREJECTED 50 -#define STAT_AUTHENTICATING 60 -#define STAT_DEAUTHENTICATED 61 -#define STAT_AUTHTIMEOUT 62 -#define STAT_ASSOCIATING 70 -#define STAT_DEASSOCIATED 71 -#define STAT_ASSOCTIMEOUT 72 -#define STAT_NOTAIROAP 73 -#define STAT_ASSOCIATED 80 -#define STAT_LEAPING 90 -#define STAT_LEAPFAILED 91 -#define STAT_LEAPTIMEDOUT 92 -#define STAT_LEAPCOMPLETE 93 -} __packed; - -typedef struct StatsRid StatsRid; -struct StatsRid { - __le16 len; - __le16 spacer; - __le32 vals[100]; -} __packed; - -typedef struct APListRid APListRid; -struct APListRid { - __le16 len; - u8 ap[4][ETH_ALEN]; -} __packed; - -typedef struct CapabilityRid CapabilityRid; -struct CapabilityRid { - __le16 len; - char oui[3]; - char zero; - __le16 prodNum; - char manName[32]; - char prodName[16]; - char prodVer[8]; - char factoryAddr[ETH_ALEN]; - char aironetAddr[ETH_ALEN]; - __le16 radioType; - __le16 country; - char callid[ETH_ALEN]; - char supportedRates[8]; - char rxDiversity; - char txDiversity; - __le16 txPowerLevels[8]; - __le16 hardVer; - __le16 hardCap; - __le16 tempRange; - __le16 softVer; - __le16 softSubVer; - __le16 interfaceVer; - __le16 softCap; - __le16 bootBlockVer; - __le16 requiredHard; - __le16 extSoftCap; -} __packed; - -/* Only present on firmware >= 5.30.17 */ -typedef struct BSSListRidExtra BSSListRidExtra; -struct BSSListRidExtra { - __le16 unknown[4]; - u8 fixed[12]; /* WLAN management frame */ - u8 iep[624]; -} __packed; - -typedef struct BSSListRid BSSListRid; -struct BSSListRid { - __le16 len; - __le16 index; /* First is 0 and 0xffff means end of list */ -#define RADIO_FH 1 /* Frequency hopping radio type */ -#define RADIO_DS 2 /* Direct sequence radio type */ -#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */ - __le16 radioType; - u8 bssid[ETH_ALEN]; /* Mac address of the BSS */ - u8 zero; - u8 ssidLen; - u8 ssid[32]; - __le16 dBm; -#define CAP_ESS cpu_to_le16(1<<0) -#define CAP_IBSS cpu_to_le16(1<<1) -#define CAP_PRIVACY cpu_to_le16(1<<4) -#define CAP_SHORTHDR cpu_to_le16(1<<5) - __le16 cap; - __le16 beaconInterval; - u8 rates[8]; /* Same as rates for config rid */ - struct { /* For frequency hopping only */ - __le16 dwell; - u8 hopSet; - u8 hopPattern; - u8 hopIndex; - u8 fill; - } fh; - __le16 dsChannel; - __le16 atimWindow; - - /* Only present on firmware >= 5.30.17 */ - BSSListRidExtra extra; -} __packed; - -typedef struct { - BSSListRid bss; - struct list_head list; -} BSSListElement; - -typedef struct tdsRssiEntry tdsRssiEntry; -struct tdsRssiEntry { - u8 rssipct; - u8 rssidBm; -} __packed; - -typedef struct tdsRssiRid tdsRssiRid; -struct tdsRssiRid { - u16 len; - tdsRssiEntry x[256]; -} __packed; - -typedef struct MICRid MICRid; -struct MICRid { - __le16 len; - __le16 state; - __le16 multicastValid; - u8 multicast[16]; - __le16 unicastValid; - u8 unicast[16]; -} __packed; - -typedef struct MICBuffer MICBuffer; -struct MICBuffer { - __be16 typelen; - - union { - u8 snap[8]; - struct { - u8 dsap; - u8 ssap; - u8 control; - u8 orgcode[3]; - u8 fieldtype[2]; - } llc; - } u; - __be32 mic; - __be32 seq; -} __packed; - -typedef struct { - u8 da[ETH_ALEN]; - u8 sa[ETH_ALEN]; -} etherHead; - -#define TXCTL_TXOK (1<<1) /* report if tx is ok */ -#define TXCTL_TXEX (1<<2) /* report if tx fails */ -#define TXCTL_802_3 (0<<3) /* 802.3 packet */ -#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */ -#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */ -#define TXCTL_LLC (1<<4) /* payload is llc */ -#define TXCTL_RELEASE (0<<5) /* release after completion */ -#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */ - -#define BUSY_FID 0x10000 - -#ifdef CISCO_EXT -#define AIROMAGIC 0xa55a -/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */ -#ifdef SIOCIWFIRSTPRIV -#ifdef SIOCDEVPRIVATE -#define AIROOLDIOCTL SIOCDEVPRIVATE -#define AIROOLDIDIFC AIROOLDIOCTL + 1 -#endif /* SIOCDEVPRIVATE */ -#else /* SIOCIWFIRSTPRIV */ -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif /* SIOCIWFIRSTPRIV */ -/* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably - * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root - * only and don't return the modified struct ifreq to the application which - * is usually a problem. - Jean II */ -#define AIROIOCTL SIOCIWFIRSTPRIV -#define AIROIDIFC AIROIOCTL + 1 - -/* Ioctl constants to be used in airo_ioctl.command */ - -#define AIROGCAP 0 // Capability rid -#define AIROGCFG 1 // USED A LOT -#define AIROGSLIST 2 // System ID list -#define AIROGVLIST 3 // List of specified AP's -#define AIROGDRVNAM 4 // NOTUSED -#define AIROGEHTENC 5 // NOTUSED -#define AIROGWEPKTMP 6 -#define AIROGWEPKNV 7 -#define AIROGSTAT 8 -#define AIROGSTATSC32 9 -#define AIROGSTATSD32 10 -#define AIROGMICRID 11 -#define AIROGMICSTATS 12 -#define AIROGFLAGS 13 -#define AIROGID 14 -#define AIRORRID 15 -#define AIRORSWVERSION 17 - -/* Leave gap of 40 commands after AIROGSTATSD32 for future */ - -#define AIROPCAP AIROGSTATSD32 + 40 -#define AIROPVLIST AIROPCAP + 1 -#define AIROPSLIST AIROPVLIST + 1 -#define AIROPCFG AIROPSLIST + 1 -#define AIROPSIDS AIROPCFG + 1 -#define AIROPAPLIST AIROPSIDS + 1 -#define AIROPMACON AIROPAPLIST + 1 /* Enable mac */ -#define AIROPMACOFF AIROPMACON + 1 /* Disable mac */ -#define AIROPSTCLR AIROPMACOFF + 1 -#define AIROPWEPKEY AIROPSTCLR + 1 -#define AIROPWEPKEYNV AIROPWEPKEY + 1 -#define AIROPLEAPPWD AIROPWEPKEYNV + 1 -#define AIROPLEAPUSR AIROPLEAPPWD + 1 - -/* Flash codes */ - -#define AIROFLSHRST AIROPWEPKEYNV + 40 -#define AIROFLSHGCHR AIROFLSHRST + 1 -#define AIROFLSHSTFL AIROFLSHGCHR + 1 -#define AIROFLSHPCHR AIROFLSHSTFL + 1 -#define AIROFLPUTBUF AIROFLSHPCHR + 1 -#define AIRORESTART AIROFLPUTBUF + 1 - -#define FLASHSIZE 32768 -#define AUXMEMSIZE (256 * 1024) - -typedef struct aironet_ioctl { - unsigned short command; // What to do - unsigned short len; // Len of data - unsigned short ridnum; // rid number - unsigned char __user *data; // d-data -} aironet_ioctl; - -static const char swversion[] = "2.1"; -#endif /* CISCO_EXT */ - -#define NUM_MODULES 2 -#define MIC_MSGLEN_MAX 2400 -#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX -#define AIRO_DEF_MTU 2312 - -typedef struct { - u32 size; // size - u8 enabled; // MIC enabled or not - u32 rxSuccess; // successful packets received - u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison - u32 rxNotMICed; // pkts dropped due to not being MIC'd - u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed - u32 rxWrongSequence; // pkts dropped due to sequence number violation - u32 reserve[32]; -} mic_statistics; - -typedef struct { - __be32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2]; - u64 accum; // accumulated mic, reduced to u32 in final() - int position; // current position (byte offset) in message - union { - u8 d8[4]; - __be32 d32; - } part; // saves partial message word across update() calls -} emmh32_context; - -typedef struct { - emmh32_context seed; // Context - the seed - u32 rx; // Received sequence number - u32 tx; // Tx sequence number - u32 window; // Start of window - u8 valid; // Flag to say if context is valid or not - u8 key[16]; -} miccntx; - -typedef struct { - miccntx mCtx; // Multicast context - miccntx uCtx; // Unicast context -} mic_module; - -typedef struct { - unsigned int rid: 16; - unsigned int len: 15; - unsigned int valid: 1; - dma_addr_t host_addr; -} Rid; - -typedef struct { - unsigned int offset: 15; - unsigned int eoc: 1; - unsigned int len: 15; - unsigned int valid: 1; - dma_addr_t host_addr; -} TxFid; - -struct rx_hdr { - __le16 status, len; - u8 rssi[2]; - u8 rate; - u8 freq; - __le16 tmp[4]; -} __packed; - -typedef struct { - unsigned int ctl: 15; - unsigned int rdy: 1; - unsigned int len: 15; - unsigned int valid: 1; - dma_addr_t host_addr; -} RxFid; - -/* - * Host receive descriptor - */ -typedef struct { - unsigned char __iomem *card_ram_off; /* offset into card memory of the - desc */ - RxFid rx_desc; /* card receive descriptor */ - char *virtual_host_addr; /* virtual address of host receive - buffer */ - int pending; -} HostRxDesc; - -/* - * Host transmit descriptor - */ -typedef struct { - unsigned char __iomem *card_ram_off; /* offset into card memory of the - desc */ - TxFid tx_desc; /* card transmit descriptor */ - char *virtual_host_addr; /* virtual address of host receive - buffer */ - int pending; -} HostTxDesc; - -/* - * Host RID descriptor - */ -typedef struct { - unsigned char __iomem *card_ram_off; /* offset into card memory of the - descriptor */ - Rid rid_desc; /* card RID descriptor */ - char *virtual_host_addr; /* virtual address of host receive - buffer */ -} HostRidDesc; - -typedef struct { - u16 sw0; - u16 sw1; - u16 status; - u16 len; -#define HOST_SET (1 << 0) -#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */ -#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */ -#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */ -#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */ -#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */ -#define HOST_CLR_AID (1 << 7) /* clear AID failure */ -#define HOST_RTS (1 << 9) /* Force RTS use */ -#define HOST_SHORT (1 << 10) /* Do short preamble */ - u16 ctl; - u16 aid; - u16 retries; - u16 fill; -} TxCtlHdr; - -typedef struct { - u16 ctl; - u16 duration; - char addr1[6]; - char addr2[6]; - char addr3[6]; - u16 seq; - char addr4[6]; -} WifiHdr; - - -typedef struct { - TxCtlHdr ctlhdr; - u16 fill1; - u16 fill2; - WifiHdr wifihdr; - u16 gaplen; - u16 status; -} WifiCtlHdr; - -static WifiCtlHdr wifictlhdr8023 = { - .ctlhdr = { - .ctl = HOST_DONT_RLSE, - } -}; - -// A few details needed for WEP (Wireless Equivalent Privacy) -#define MAX_KEY_SIZE 13 // 128 (?) bits -#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP -typedef struct wep_key_t { - u16 len; - u8 key[16]; /* 40-bit and 104-bit keys */ -} wep_key_t; - -/* List of Wireless Handlers (new API) */ -static const struct iw_handler_def airo_handler_def; - -static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; - -struct airo_info; - -static int get_dec_u16(char *buffer, int *start, int limit); -static void OUT4500(struct airo_info *, u16 reg, u16 value); -static unsigned short IN4500(struct airo_info *, u16 reg); -static u16 setup_card(struct airo_info*, struct net_device *dev, int lock); -static int enable_MAC(struct airo_info *ai, int lock); -static void disable_MAC(struct airo_info *ai, int lock); -static void enable_interrupts(struct airo_info*); -static void disable_interrupts(struct airo_info*); -static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp, - bool may_sleep); -static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap); -static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen, - int whichbap); -static int fast_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen, - int whichbap); -static int bap_write(struct airo_info*, const __le16 *pu16Src, int bytelen, - int whichbap); -static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd); -static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock); -static int PC4500_writerid(struct airo_info*, u16 rid, const void - *pBuf, int len, int lock); -static int do_writerid(struct airo_info*, u16 rid, const void *rid_data, - int len, int dummy); -static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw); -static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket, - bool may_sleep); -static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket, - bool may_sleep); - -static int mpi_send_packet(struct net_device *dev); -static void mpi_unmap_card(struct pci_dev *pci); -static void mpi_receive_802_3(struct airo_info *ai); -static void mpi_receive_802_11(struct airo_info *ai); -static int waitbusy(struct airo_info *ai); - -static irqreturn_t airo_interrupt(int irq, void* dev_id); -static int airo_thread(void *data); -static void timer_func(struct net_device *dev); -static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *, int cmd); -static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev); -#ifdef CISCO_EXT -static int readrids(struct net_device *dev, aironet_ioctl *comp); -static int writerids(struct net_device *dev, aironet_ioctl *comp); -static int flashcard(struct net_device *dev, aironet_ioctl *comp); -#endif /* CISCO_EXT */ -static void micinit(struct airo_info *ai); -static int micsetup(struct airo_info *ai); -static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len); -static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen); - -static u8 airo_rssi_to_dbm(tdsRssiEntry *rssi_rid, u8 rssi); -static u8 airo_dbm_to_pct(tdsRssiEntry *rssi_rid, u8 dbm); - -static void airo_networks_free(struct airo_info *ai); - -struct airo_info { - struct net_device *dev; - struct list_head dev_list; - /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we - use the high bit to mark whether it is in use. */ -#define MAX_FIDS 6 -#define MPI_MAX_FIDS 1 - u32 fids[MAX_FIDS]; - ConfigRid config; - char keyindex; // Used with auto wep - char defindex; // Used with auto wep - struct proc_dir_entry *proc_entry; - spinlock_t aux_lock; -#define FLAG_RADIO_OFF 0 /* User disabling of MAC */ -#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */ -#define FLAG_RADIO_MASK 0x03 -#define FLAG_ENABLED 2 -#define FLAG_ADHOC 3 /* Needed by MIC */ -#define FLAG_MIC_CAPABLE 4 -#define FLAG_UPDATE_MULTI 5 -#define FLAG_UPDATE_UNI 6 -#define FLAG_802_11 7 -#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */ -#define FLAG_PENDING_XMIT 9 -#define FLAG_PENDING_XMIT11 10 -#define FLAG_MPI 11 -#define FLAG_REGISTERED 12 -#define FLAG_COMMIT 13 -#define FLAG_RESET 14 -#define FLAG_FLASHING 15 -#define FLAG_WPA_CAPABLE 16 - unsigned long flags; -#define JOB_DIE 0 -#define JOB_XMIT 1 -#define JOB_XMIT11 2 -#define JOB_STATS 3 -#define JOB_PROMISC 4 -#define JOB_MIC 5 -#define JOB_EVENT 6 -#define JOB_AUTOWEP 7 -#define JOB_SCAN_RESULTS 9 - unsigned long jobs; - int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen, - int whichbap); - unsigned short *flash; - tdsRssiEntry *rssi; - struct task_struct *list_bss_task; - struct task_struct *airo_thread_task; - struct semaphore sem; - wait_queue_head_t thr_wait; - unsigned long expires; - struct { - struct sk_buff *skb; - int fid; - } xmit, xmit11; - struct net_device *wifidev; - struct iw_statistics wstats; // wireless stats - unsigned long scan_timeout; /* Time scan should be read */ - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; - /* MIC stuff */ - struct crypto_sync_skcipher *tfm; - mic_module mod[2]; - mic_statistics micstats; - HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors - HostTxDesc txfids[MPI_MAX_FIDS]; - HostRidDesc config_desc; - unsigned long ridbus; // phys addr of config_desc - struct sk_buff_head txq;// tx queue used by mpi350 code - struct pci_dev *pci; - unsigned char __iomem *pcimem; - unsigned char __iomem *pciaux; - unsigned char *shared; - dma_addr_t shared_dma; - pm_message_t power; - SsidRid *SSID; - APListRid APList; -#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE - char proc_name[IFNAMSIZ]; - - int wep_capable; - int max_wep_idx; - int last_auth; - - /* WPA-related stuff */ - unsigned int bssListFirst; - unsigned int bssListNext; - unsigned int bssListRidLen; - - struct list_head network_list; - struct list_head network_free_list; - BSSListElement *networks; -}; - -static inline int bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen, - int whichbap) -{ - return ai->bap_read(ai, pu16Dst, bytelen, whichbap); -} - -static int setup_proc_entry(struct net_device *dev, - struct airo_info *apriv); -static int takedown_proc_entry(struct net_device *dev, - struct airo_info *apriv); - -static int cmdreset(struct airo_info *ai); -static int setflashmode(struct airo_info *ai); -static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime); -static int flashputbuf(struct airo_info *ai); -static int flashrestart(struct airo_info *ai, struct net_device *dev); - -#define airo_print(type, name, fmt, args...) \ - printk(type DRV_NAME "(%s): " fmt "\n", name, ##args) - -#define airo_print_info(name, fmt, args...) \ - airo_print(KERN_INFO, name, fmt, ##args) - -#define airo_print_dbg(name, fmt, args...) \ - airo_print(KERN_DEBUG, name, fmt, ##args) - -#define airo_print_warn(name, fmt, args...) \ - airo_print(KERN_WARNING, name, fmt, ##args) - -#define airo_print_err(name, fmt, args...) \ - airo_print(KERN_ERR, name, fmt, ##args) - -#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash) - -/*********************************************************************** - * MIC ROUTINES * - *********************************************************************** - */ - -static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq); -static void MoveWindow(miccntx *context, u32 micSeq); -static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, - struct crypto_sync_skcipher *tfm); -static void emmh32_init(emmh32_context *context); -static void emmh32_update(emmh32_context *context, u8 *pOctets, int len); -static void emmh32_final(emmh32_context *context, u8 digest[4]); -static int flashpchar(struct airo_info *ai, int byte, int dwelltime); - -static void age_mic_context(miccntx *cur, miccntx *old, u8 *key, int key_len, - struct crypto_sync_skcipher *tfm) -{ - /* If the current MIC context is valid and its key is the same as - * the MIC register, there's nothing to do. - */ - if (cur->valid && (memcmp(cur->key, key, key_len) == 0)) - return; - - /* Age current mic Context */ - memcpy(old, cur, sizeof(*cur)); - - /* Initialize new context */ - memcpy(cur->key, key, key_len); - cur->window = 33; /* Window always points to the middle */ - cur->rx = 0; /* Rx Sequence numbers */ - cur->tx = 0; /* Tx sequence numbers */ - cur->valid = 1; /* Key is now valid */ - - /* Give key to mic seed */ - emmh32_setseed(&cur->seed, key, key_len, tfm); -} - -/* micinit - Initialize mic seed */ - -static void micinit(struct airo_info *ai) -{ - MICRid mic_rid; - - clear_bit(JOB_MIC, &ai->jobs); - PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0); - up(&ai->sem); - - ai->micstats.enabled = (le16_to_cpu(mic_rid.state) & 0x00FF) ? 1 : 0; - if (!ai->micstats.enabled) { - /* So next time we have a valid key and mic is enabled, we will - * update the sequence number if the key is the same as before. - */ - ai->mod[0].uCtx.valid = 0; - ai->mod[0].mCtx.valid = 0; - return; - } - - if (mic_rid.multicastValid) { - age_mic_context(&ai->mod[0].mCtx, &ai->mod[1].mCtx, - mic_rid.multicast, sizeof(mic_rid.multicast), - ai->tfm); - } - - if (mic_rid.unicastValid) { - age_mic_context(&ai->mod[0].uCtx, &ai->mod[1].uCtx, - mic_rid.unicast, sizeof(mic_rid.unicast), - ai->tfm); - } -} - -/* micsetup - Get ready for business */ - -static int micsetup(struct airo_info *ai) -{ - int i; - - if (ai->tfm == NULL) - ai->tfm = crypto_alloc_sync_skcipher("ctr(aes)", 0, 0); - - if (IS_ERR(ai->tfm)) { - airo_print_err(ai->dev->name, "failed to load transform for AES"); - ai->tfm = NULL; - return ERROR; - } - - for (i = 0; i < NUM_MODULES; i++) { - memset(&ai->mod[i].mCtx, 0, sizeof(miccntx)); - memset(&ai->mod[i].uCtx, 0, sizeof(miccntx)); - } - return SUCCESS; -} - -static const u8 micsnap[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; - -/*=========================================================================== - * Description: Mic a packet - * - * Inputs: etherHead * pointer to an 802.3 frame - * - * Returns: BOOLEAN if successful, otherwise false. - * PacketTxLen will be updated with the mic'd packets size. - * - * Caveats: It is assumed that the frame buffer will already - * be big enough to hold the largets mic message possible. - * (No memory allocation is done here). - * - * Author: sbraneky (10/15/01) - * Merciless hacks by rwilcher (1/14/02) - */ - -static int encapsulate(struct airo_info *ai, etherHead *frame, MICBuffer *mic, int payLen) -{ - miccntx *context; - - // Determine correct context - // If not adhoc, always use unicast key - - if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1)) - context = &ai->mod[0].mCtx; - else - context = &ai->mod[0].uCtx; - - if (!context->valid) - return ERROR; - - mic->typelen = htons(payLen + 16); //Length of Mic'd packet - - memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap - - // Add Tx sequence - mic->seq = htonl(context->tx); - context->tx += 2; - - emmh32_init(&context->seed); // Mic the packet - emmh32_update(&context->seed, frame->da, ETH_ALEN * 2); // DA, SA - emmh32_update(&context->seed, (u8*)&mic->typelen, 10); // Type/Length and Snap - emmh32_update(&context->seed, (u8*)&mic->seq, sizeof(mic->seq)); //SEQ - emmh32_update(&context->seed, (u8*)(frame + 1), payLen); //payload - emmh32_final(&context->seed, (u8*)&mic->mic); - - /* New Type/length ?????????? */ - mic->typelen = 0; //Let NIC know it could be an oversized packet - return SUCCESS; -} - -typedef enum { - NONE, - NOMIC, - NOMICPLUMMED, - SEQUENCE, - INCORRECTMIC, -} mic_error; - -/*=========================================================================== - * Description: Decapsulates a MIC'd packet and returns the 802.3 packet - * (removes the MIC stuff) if packet is a valid packet. - * - * Inputs: etherHead pointer to the 802.3 packet - * - * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE - * - * Author: sbraneky (10/15/01) - * Merciless hacks by rwilcher (1/14/02) - *--------------------------------------------------------------------------- - */ - -static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen) -{ - int i; - u32 micSEQ; - miccntx *context; - u8 digest[4]; - mic_error micError = NONE; - - // Check if the packet is a Mic'd packet - - if (!ai->micstats.enabled) { - //No Mic set or Mic OFF but we received a MIC'd packet. - if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) { - ai->micstats.rxMICPlummed++; - return ERROR; - } - return SUCCESS; - } - - if (ntohs(mic->typelen) == 0x888E) - return SUCCESS; - - if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) { - // Mic enabled but packet isn't Mic'd - ai->micstats.rxMICPlummed++; - return ERROR; - } - - micSEQ = ntohl(mic->seq); //store SEQ as CPU order - - //At this point we a have a mic'd packet and mic is enabled - //Now do the mic error checking. - - //Receive seq must be odd - if ((micSEQ & 1) == 0) { - ai->micstats.rxWrongSequence++; - return ERROR; - } - - for (i = 0; i < NUM_MODULES; i++) { - int mcast = eth->da[0] & 1; - //Determine proper context - context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx; - - //Make sure context is valid - if (!context->valid) { - if (i == 0) - micError = NOMICPLUMMED; - continue; - } - //DeMic it - - if (!mic->typelen) - mic->typelen = htons(payLen + sizeof(MICBuffer) - 2); - - emmh32_init(&context->seed); - emmh32_update(&context->seed, eth->da, ETH_ALEN*2); - emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap)); - emmh32_update(&context->seed, (u8 *)&mic->seq, sizeof(mic->seq)); - emmh32_update(&context->seed, (u8 *)(eth + 1), payLen); - //Calculate MIC - emmh32_final(&context->seed, digest); - - if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match - //Invalid Mic - if (i == 0) - micError = INCORRECTMIC; - continue; - } - - //Check Sequence number if mics pass - if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) { - ai->micstats.rxSuccess++; - return SUCCESS; - } - if (i == 0) - micError = SEQUENCE; - } - - // Update statistics - switch (micError) { - case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break; - case SEQUENCE: ai->micstats.rxWrongSequence++; break; - case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break; - case NONE: break; - case NOMIC: break; - } - return ERROR; -} - -/*=========================================================================== - * Description: Checks the Rx Seq number to make sure it is valid - * and hasn't already been received - * - * Inputs: miccntx - mic context to check seq against - * micSeq - the Mic seq number - * - * Returns: TRUE if valid otherwise FALSE. - * - * Author: sbraneky (10/15/01) - * Merciless hacks by rwilcher (1/14/02) - *--------------------------------------------------------------------------- - */ - -static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq) -{ - u32 seq, index; - - //Allow for the ap being rebooted - if it is then use the next - //sequence number of the current sequence number - might go backwards - - if (mcast) { - if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) { - clear_bit (FLAG_UPDATE_MULTI, &ai->flags); - context->window = (micSeq > 33) ? micSeq : 33; - context->rx = 0; // Reset rx - } - } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) { - clear_bit (FLAG_UPDATE_UNI, &ai->flags); - context->window = (micSeq > 33) ? micSeq : 33; // Move window - context->rx = 0; // Reset rx - } - - //Make sequence number relative to START of window - seq = micSeq - (context->window - 33); - - //Too old of a SEQ number to check. - if ((s32)seq < 0) - return ERROR; - - if (seq > 64) { - //Window is infinite forward - MoveWindow(context, micSeq); - return SUCCESS; - } - - // We are in the window. Now check the context rx bit to see if it was already sent - seq >>= 1; //divide by 2 because we only have odd numbers - index = 1 << seq; //Get an index number - - if (!(context->rx & index)) { - //micSEQ falls inside the window. - //Add seqence number to the list of received numbers. - context->rx |= index; - - MoveWindow(context, micSeq); - - return SUCCESS; - } - return ERROR; -} - -static void MoveWindow(miccntx *context, u32 micSeq) -{ - u32 shift; - - //Move window if seq greater than the middle of the window - if (micSeq > context->window) { - shift = (micSeq - context->window) >> 1; - - //Shift out old - if (shift < 32) - context->rx >>= shift; - else - context->rx = 0; - - context->window = micSeq; //Move window - } -} - -/*==============================================*/ -/*========== EMMH ROUTINES ====================*/ -/*==============================================*/ - -/* mic accumulate */ -#define MIC_ACCUM(val) \ - context->accum += (u64)(val) * be32_to_cpu(context->coeff[coeff_position++]); - -/* expand the key to fill the MMH coefficient array */ -static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, - struct crypto_sync_skcipher *tfm) -{ - /* take the keying material, expand if necessary, truncate at 16-bytes */ - /* run through AES counter mode to generate context->coeff[] */ - - SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); - struct scatterlist sg; - u8 iv[AES_BLOCK_SIZE] = {}; - int ret; - - crypto_sync_skcipher_setkey(tfm, pkey, 16); - - memset(context->coeff, 0, sizeof(context->coeff)); - sg_init_one(&sg, context->coeff, sizeof(context->coeff)); - - skcipher_request_set_sync_tfm(req, tfm); - skcipher_request_set_callback(req, 0, NULL, NULL); - skcipher_request_set_crypt(req, &sg, &sg, sizeof(context->coeff), iv); - - ret = crypto_skcipher_encrypt(req); - WARN_ON_ONCE(ret); -} - -/* prepare for calculation of a new mic */ -static void emmh32_init(emmh32_context *context) -{ - /* prepare for new mic calculation */ - context->accum = 0; - context->position = 0; -} - -/* add some bytes to the mic calculation */ -static void emmh32_update(emmh32_context *context, u8 *pOctets, int len) -{ - int coeff_position, byte_position; - - if (len == 0) return; - - coeff_position = context->position >> 2; - - /* deal with partial 32-bit word left over from last update */ - byte_position = context->position & 3; - if (byte_position) { - /* have a partial word in part to deal with */ - do { - if (len == 0) return; - context->part.d8[byte_position++] = *pOctets++; - context->position++; - len--; - } while (byte_position < 4); - MIC_ACCUM(ntohl(context->part.d32)); - } - - /* deal with full 32-bit words */ - while (len >= 4) { - MIC_ACCUM(ntohl(*(__be32 *)pOctets)); - context->position += 4; - pOctets += 4; - len -= 4; - } - - /* deal with partial 32-bit word that will be left over from this update */ - byte_position = 0; - while (len > 0) { - context->part.d8[byte_position++] = *pOctets++; - context->position++; - len--; - } -} - -/* mask used to zero empty bytes for final partial word */ -static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; - -/* calculate the mic */ -static void emmh32_final(emmh32_context *context, u8 digest[4]) -{ - int coeff_position, byte_position; - u32 val; - - u64 sum, utmp; - s64 stmp; - - coeff_position = context->position >> 2; - - /* deal with partial 32-bit word left over from last update */ - byte_position = context->position & 3; - if (byte_position) { - /* have a partial word in part to deal with */ - val = ntohl(context->part.d32); - MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */ - } - - /* reduce the accumulated u64 to a 32-bit MIC */ - sum = context->accum; - stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15); - utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15); - sum = utmp & 0xffffffffLL; - if (utmp > 0x10000000fLL) - sum -= 15; - - val = (u32)sum; - digest[0] = (val>>24) & 0xFF; - digest[1] = (val>>16) & 0xFF; - digest[2] = (val>>8) & 0xFF; - digest[3] = val & 0xFF; -} - -static int readBSSListRid(struct airo_info *ai, int first, - BSSListRid *list) -{ - Cmd cmd; - Resp rsp; - - if (first == 1) { - if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LISTBSS; - if (down_interruptible(&ai->sem)) - return -ERESTARTSYS; - ai->list_bss_task = current; - issuecommand(ai, &cmd, &rsp, true); - up(&ai->sem); - /* Let the command take effect */ - schedule_timeout_uninterruptible(3 * HZ); - ai->list_bss_task = NULL; - } - return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext, - list, ai->bssListRidLen, 1); -} - -static int readWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int temp, int lock) -{ - return PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, - wkr, sizeof(*wkr), lock); -} - -static int writeWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int perm, int lock) -{ - int rc; - rc = PC4500_writerid(ai, RID_WEP_TEMP, wkr, sizeof(*wkr), lock); - if (rc!=SUCCESS) - airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc); - if (perm) { - rc = PC4500_writerid(ai, RID_WEP_PERM, wkr, sizeof(*wkr), lock); - if (rc!=SUCCESS) - airo_print_err(ai->dev->name, "WEP_PERM set %x", rc); - } - return rc; -} - -static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) -{ - return PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1); -} - -static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) -{ - return PC4500_writerid(ai, RID_SSID, pssidr, sizeof(*pssidr), lock); -} - -static int readConfigRid(struct airo_info *ai, int lock) -{ - int rc; - ConfigRid cfg; - - if (ai->config.len) - return SUCCESS; - - rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock); - if (rc != SUCCESS) - return rc; - - ai->config = cfg; - return SUCCESS; -} - -static inline void checkThrottle(struct airo_info *ai) -{ - int i; -/* Old hardware had a limit on encryption speed */ - if (ai->config.authType != AUTH_OPEN && maxencrypt) { - for (i = 0; i<8; i++) { - if (ai->config.rates[i] > maxencrypt) { - ai->config.rates[i] = 0; - } - } - } -} - -static int writeConfigRid(struct airo_info *ai, int lock) -{ - ConfigRid cfgr; - - if (!test_bit (FLAG_COMMIT, &ai->flags)) - return SUCCESS; - - clear_bit (FLAG_COMMIT, &ai->flags); - clear_bit (FLAG_RESET, &ai->flags); - checkThrottle(ai); - cfgr = ai->config; - - if ((cfgr.opmode & MODE_CFG_MASK) == MODE_STA_IBSS) - set_bit(FLAG_ADHOC, &ai->flags); - else - clear_bit(FLAG_ADHOC, &ai->flags); - - return PC4500_writerid(ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock); -} - -static int readStatusRid(struct airo_info *ai, StatusRid *statr, int lock) -{ - return PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock); -} - -static int writeAPListRid(struct airo_info *ai, APListRid *aplr, int lock) -{ - return PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock); -} - -static int readCapabilityRid(struct airo_info *ai, CapabilityRid *capr, int lock) -{ - return PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock); -} - -static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) -{ - return PC4500_readrid(ai, rid, sr, sizeof(*sr), lock); -} - -static void try_auto_wep(struct airo_info *ai) -{ - if (auto_wep && !test_bit(FLAG_RADIO_DOWN, &ai->flags)) { - ai->expires = RUN_AT(3*HZ); - wake_up_interruptible(&ai->thr_wait); - } -} - -static int airo_open(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - int rc = 0; - - if (test_bit(FLAG_FLASHING, &ai->flags)) - return -EIO; - - /* Make sure the card is configured. - * Wireless Extensions may postpone config changes until the card - * is open (to pipeline changes and speed-up card setup). If - * those changes are not yet committed, do it now - Jean II */ - if (test_bit(FLAG_COMMIT, &ai->flags)) { - disable_MAC(ai, 1); - writeConfigRid(ai, 1); - } - - if (ai->wifidev != dev) { - clear_bit(JOB_DIE, &ai->jobs); - ai->airo_thread_task = kthread_run(airo_thread, dev, "%s", - dev->name); - if (IS_ERR(ai->airo_thread_task)) - return (int)PTR_ERR(ai->airo_thread_task); - - rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED, - dev->name, dev); - if (rc) { - airo_print_err(dev->name, - "register interrupt %d failed, rc %d", - dev->irq, rc); - set_bit(JOB_DIE, &ai->jobs); - kthread_stop(ai->airo_thread_task); - return rc; - } - - /* Power on the MAC controller (which may have been disabled) */ - clear_bit(FLAG_RADIO_DOWN, &ai->flags); - enable_interrupts(ai); - - try_auto_wep(ai); - } - enable_MAC(ai, 1); - - netif_start_queue(dev); - return 0; -} - -static netdev_tx_t mpi_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - int npacks, pending; - unsigned long flags; - struct airo_info *ai = dev->ml_priv; - - if (!skb) { - airo_print_err(dev->name, "%s: skb == NULL!",__func__); - return NETDEV_TX_OK; - } - if (skb_padto(skb, ETH_ZLEN)) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - npacks = skb_queue_len (&ai->txq); - - if (npacks >= MAXTXQ - 1) { - netif_stop_queue (dev); - if (npacks > MAXTXQ) { - dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; - } - skb_queue_tail (&ai->txq, skb); - return NETDEV_TX_OK; - } - - spin_lock_irqsave(&ai->aux_lock, flags); - skb_queue_tail (&ai->txq, skb); - pending = test_bit(FLAG_PENDING_XMIT, &ai->flags); - spin_unlock_irqrestore(&ai->aux_lock, flags); - netif_wake_queue (dev); - - if (pending == 0) { - set_bit(FLAG_PENDING_XMIT, &ai->flags); - mpi_send_packet (dev); - } - return NETDEV_TX_OK; -} - -/* - * @mpi_send_packet - * - * Attempt to transmit a packet. Can be called from interrupt - * or transmit . return number of packets we tried to send - */ - -static int mpi_send_packet (struct net_device *dev) -{ - struct sk_buff *skb; - unsigned char *buffer; - s16 len; - __le16 *payloadLen; - struct airo_info *ai = dev->ml_priv; - u8 *sendbuf; - - /* get a packet to send */ - - if ((skb = skb_dequeue(&ai->txq)) == NULL) { - airo_print_err(dev->name, - "%s: Dequeue'd zero in send_packet()", - __func__); - return 0; - } - - /* check min length*/ - len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - buffer = skb->data; - - ai->txfids[0].tx_desc.offset = 0; - ai->txfids[0].tx_desc.valid = 1; - ai->txfids[0].tx_desc.eoc = 1; - ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr); - -/* - * Magic, the cards firmware needs a length count (2 bytes) in the host buffer - * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen - * is immediately after it. ------------------------------------------------ - * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA| - * ------------------------------------------------ - */ - - memcpy(ai->txfids[0].virtual_host_addr, - (char *)&wifictlhdr8023, sizeof(wifictlhdr8023)); - - payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr + - sizeof(wifictlhdr8023)); - sendbuf = ai->txfids[0].virtual_host_addr + - sizeof(wifictlhdr8023) + 2 ; - - /* - * Firmware automatically puts 802 header on so - * we don't need to account for it in the length - */ - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && - (ntohs(((__be16 *)buffer)[6]) != 0x888E)) { - MICBuffer pMic; - - if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS) - return ERROR; - - *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic)); - ai->txfids[0].tx_desc.len += sizeof(pMic); - /* copy data into airo dma buffer */ - memcpy (sendbuf, buffer, sizeof(etherHead)); - buffer += sizeof(etherHead); - sendbuf += sizeof(etherHead); - memcpy (sendbuf, &pMic, sizeof(pMic)); - sendbuf += sizeof(pMic); - memcpy (sendbuf, buffer, len - sizeof(etherHead)); - } else { - *payloadLen = cpu_to_le16(len - sizeof(etherHead)); - - netif_trans_update(dev); - - /* copy data into airo dma buffer */ - memcpy(sendbuf, buffer, len); - } - - memcpy_toio(ai->txfids[0].card_ram_off, - &ai->txfids[0].tx_desc, sizeof(TxFid)); - - OUT4500(ai, EVACK, 8); - - dev_kfree_skb_any(skb); - return 1; -} - -static void get_tx_error(struct airo_info *ai, s32 fid) -{ - __le16 status; - - if (fid < 0) - status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status; - else { - if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS) - return; - bap_read(ai, &status, 2, BAP0); - } - if (le16_to_cpu(status) & 2) /* Too many retries */ - ai->dev->stats.tx_aborted_errors++; - if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */ - ai->dev->stats.tx_heartbeat_errors++; - if (le16_to_cpu(status) & 8) /* Aid fail */ - { } - if (le16_to_cpu(status) & 0x10) /* MAC disabled */ - ai->dev->stats.tx_carrier_errors++; - if (le16_to_cpu(status) & 0x20) /* Association lost */ - { } - /* We produce a TXDROP event only for retry or lifetime - * exceeded, because that's the only status that really mean - * that this particular node went away. - * Other errors means that *we* screwed up. - Jean II */ - if ((le16_to_cpu(status) & 2) || - (le16_to_cpu(status) & 4)) { - union iwreq_data wrqu; - char junk[0x18]; - - /* Faster to skip over useless data than to do - * another bap_setup(). We are at offset 0x6 and - * need to go to 0x18 and read 6 bytes - Jean II */ - bap_read(ai, (__le16 *) junk, 0x18, BAP0); - - /* Copy 802.11 dest address. - * We use the 802.11 header because the frame may - * not be 802.3 or may be mangled... - * In Ad-Hoc mode, it will be the node address. - * In managed mode, it will be most likely the AP addr - * User space will figure out how to convert it to - * whatever it needs (IP address or else). - * - Jean II */ - memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL); - } -} - -static void airo_end_xmit(struct net_device *dev, bool may_sleep) -{ - u16 status; - int i; - struct airo_info *priv = dev->ml_priv; - struct sk_buff *skb = priv->xmit.skb; - int fid = priv->xmit.fid; - u32 *fids = priv->fids; - - clear_bit(JOB_XMIT, &priv->jobs); - clear_bit(FLAG_PENDING_XMIT, &priv->flags); - status = transmit_802_3_packet(priv, fids[fid], skb->data, may_sleep); - up(&priv->sem); - - i = 0; - if (status == SUCCESS) { - netif_trans_update(dev); - for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++); - } else { - priv->fids[fid] &= 0xffff; - dev->stats.tx_window_errors++; - } - if (i < MAX_FIDS / 2) - netif_wake_queue(dev); - dev_kfree_skb(skb); -} - -static netdev_tx_t airo_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - s16 len; - int i, j; - struct airo_info *priv = dev->ml_priv; - u32 *fids = priv->fids; - - if (skb == NULL) { - airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return NETDEV_TX_OK; - } - if (skb_padto(skb, ETH_ZLEN)) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - /* Find a vacant FID */ - for (i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++); - for (j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++); - - if (j >= MAX_FIDS / 2) { - netif_stop_queue(dev); - - if (i == MAX_FIDS / 2) { - dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; - } - } - /* check min length*/ - len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - /* Mark fid as used & save length for later */ - fids[i] |= (len << 16); - priv->xmit.skb = skb; - priv->xmit.fid = i; - if (down_trylock(&priv->sem) != 0) { - set_bit(FLAG_PENDING_XMIT, &priv->flags); - netif_stop_queue(dev); - set_bit(JOB_XMIT, &priv->jobs); - wake_up_interruptible(&priv->thr_wait); - } else - airo_end_xmit(dev, false); - return NETDEV_TX_OK; -} - -static void airo_end_xmit11(struct net_device *dev, bool may_sleep) -{ - u16 status; - int i; - struct airo_info *priv = dev->ml_priv; - struct sk_buff *skb = priv->xmit11.skb; - int fid = priv->xmit11.fid; - u32 *fids = priv->fids; - - clear_bit(JOB_XMIT11, &priv->jobs); - clear_bit(FLAG_PENDING_XMIT11, &priv->flags); - status = transmit_802_11_packet(priv, fids[fid], skb->data, may_sleep); - up(&priv->sem); - - i = MAX_FIDS / 2; - if (status == SUCCESS) { - netif_trans_update(dev); - for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++); - } else { - priv->fids[fid] &= 0xffff; - dev->stats.tx_window_errors++; - } - if (i < MAX_FIDS) - netif_wake_queue(dev); - dev_kfree_skb(skb); -} - -static netdev_tx_t airo_start_xmit11(struct sk_buff *skb, - struct net_device *dev) -{ - s16 len; - int i, j; - struct airo_info *priv = dev->ml_priv; - u32 *fids = priv->fids; - - if (test_bit(FLAG_MPI, &priv->flags)) { - /* Not implemented yet for MPI350 */ - netif_stop_queue(dev); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - - if (skb == NULL) { - airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return NETDEV_TX_OK; - } - if (skb_padto(skb, ETH_ZLEN)) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - /* Find a vacant FID */ - for (i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++); - for (j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++); - - if (j >= MAX_FIDS) { - netif_stop_queue(dev); - - if (i == MAX_FIDS) { - dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; - } - } - /* check min length*/ - len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - /* Mark fid as used & save length for later */ - fids[i] |= (len << 16); - priv->xmit11.skb = skb; - priv->xmit11.fid = i; - if (down_trylock(&priv->sem) != 0) { - set_bit(FLAG_PENDING_XMIT11, &priv->flags); - netif_stop_queue(dev); - set_bit(JOB_XMIT11, &priv->jobs); - wake_up_interruptible(&priv->thr_wait); - } else - airo_end_xmit11(dev, false); - return NETDEV_TX_OK; -} - -static void airo_read_stats(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - StatsRid stats_rid; - __le32 *vals = stats_rid.vals; - - clear_bit(JOB_STATS, &ai->jobs); - if (ai->power.event) { - up(&ai->sem); - return; - } - readStatsRid(ai, &stats_rid, RID_STATS, 0); - up(&ai->sem); - - dev->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) + - le32_to_cpu(vals[45]); - dev->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) + - le32_to_cpu(vals[41]); - dev->stats.rx_bytes = le32_to_cpu(vals[92]); - dev->stats.tx_bytes = le32_to_cpu(vals[91]); - dev->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) + - le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]); - dev->stats.tx_errors = le32_to_cpu(vals[42]) + - dev->stats.tx_fifo_errors; - dev->stats.multicast = le32_to_cpu(vals[43]); - dev->stats.collisions = le32_to_cpu(vals[89]); - - /* detailed rx_errors: */ - dev->stats.rx_length_errors = le32_to_cpu(vals[3]); - dev->stats.rx_crc_errors = le32_to_cpu(vals[4]); - dev->stats.rx_frame_errors = le32_to_cpu(vals[2]); - dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]); -} - -static struct net_device_stats *airo_get_stats(struct net_device *dev) -{ - struct airo_info *local = dev->ml_priv; - - if (!test_bit(JOB_STATS, &local->jobs)) { - set_bit(JOB_STATS, &local->jobs); - wake_up_interruptible(&local->thr_wait); - } - - return &dev->stats; -} - -static void airo_set_promisc(struct airo_info *ai, bool may_sleep) -{ - Cmd cmd; - Resp rsp; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_SETMODE; - clear_bit(JOB_PROMISC, &ai->jobs); - cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC; - issuecommand(ai, &cmd, &rsp, may_sleep); - up(&ai->sem); -} - -static void airo_set_multicast_list(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - - if ((dev->flags ^ ai->flags) & IFF_PROMISC) { - change_bit(FLAG_PROMISC, &ai->flags); - if (down_trylock(&ai->sem) != 0) { - set_bit(JOB_PROMISC, &ai->jobs); - wake_up_interruptible(&ai->thr_wait); - } else - airo_set_promisc(ai, false); - } - - if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) { - /* Turn on multicast. (Should be already setup...) */ - } -} - -static int airo_set_mac_address(struct net_device *dev, void *p) -{ - struct airo_info *ai = dev->ml_priv; - struct sockaddr *addr = p; - - readConfigRid(ai, 1); - memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); - set_bit (FLAG_COMMIT, &ai->flags); - disable_MAC(ai, 1); - writeConfigRid (ai, 1); - enable_MAC(ai, 1); - dev_addr_set(ai->dev, addr->sa_data); - if (ai->wifidev) - dev_addr_set(ai->wifidev, addr->sa_data); - return 0; -} - -static LIST_HEAD(airo_devices); - -static void add_airo_dev(struct airo_info *ai) -{ - /* Upper layers already keep track of PCI devices, - * so we only need to remember our non-PCI cards. */ - if (!ai->pci) - list_add_tail(&ai->dev_list, &airo_devices); -} - -static void del_airo_dev(struct airo_info *ai) -{ - if (!ai->pci) - list_del(&ai->dev_list); -} - -static int airo_close(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - - netif_stop_queue(dev); - - if (ai->wifidev != dev) { -#ifdef POWER_ON_DOWN - /* Shut power to the card. The idea is that the user can save - * power when he doesn't need the card with "ifconfig down". - * That's the method that is most friendly towards the network - * stack (i.e. the network stack won't try to broadcast - * anything on the interface and routes are gone. Jean II */ - set_bit(FLAG_RADIO_DOWN, &ai->flags); - disable_MAC(ai, 1); -#endif - disable_interrupts(ai); - - free_irq(dev->irq, dev); - - set_bit(JOB_DIE, &ai->jobs); - kthread_stop(ai->airo_thread_task); - } - return 0; -} - -void stop_airo_card(struct net_device *dev, int freeres) -{ - struct airo_info *ai = dev->ml_priv; - - set_bit(FLAG_RADIO_DOWN, &ai->flags); - disable_MAC(ai, 1); - disable_interrupts(ai); - takedown_proc_entry(dev, ai); - if (test_bit(FLAG_REGISTERED, &ai->flags)) { - unregister_netdev(dev); - if (ai->wifidev) { - unregister_netdev(ai->wifidev); - free_netdev(ai->wifidev); - ai->wifidev = NULL; - } - clear_bit(FLAG_REGISTERED, &ai->flags); - } - /* - * Clean out tx queue - */ - if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) { - struct sk_buff *skb = NULL; - for (;(skb = skb_dequeue(&ai->txq));) - dev_kfree_skb(skb); - } - - airo_networks_free (ai); - - kfree(ai->flash); - kfree(ai->rssi); - kfree(ai->SSID); - if (freeres) { - /* PCMCIA frees this stuff, so only for PCI and ISA */ - release_region(dev->base_addr, 64); - if (test_bit(FLAG_MPI, &ai->flags)) { - if (ai->pci) - mpi_unmap_card(ai->pci); - if (ai->pcimem) - iounmap(ai->pcimem); - if (ai->pciaux) - iounmap(ai->pciaux); - dma_free_coherent(&ai->pci->dev, PCI_SHARED_LEN, - ai->shared, ai->shared_dma); - } - } - crypto_free_sync_skcipher(ai->tfm); - del_airo_dev(ai); - free_netdev(dev); -} - -EXPORT_SYMBOL(stop_airo_card); - -static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); - return ETH_ALEN; -} - -static void mpi_unmap_card(struct pci_dev *pci) -{ - unsigned long mem_start = pci_resource_start(pci, 1); - unsigned long mem_len = pci_resource_len(pci, 1); - unsigned long aux_start = pci_resource_start(pci, 2); - unsigned long aux_len = AUXMEMSIZE; - - release_mem_region(aux_start, aux_len); - release_mem_region(mem_start, mem_len); -} - -/************************************************************* - * This routine assumes that descriptors have been setup . - * Run at insmod time or after reset when the descriptors - * have been initialized . Returns 0 if all is well nz - * otherwise . Does not allocate memory but sets up card - * using previously allocated descriptors. - */ -static int mpi_init_descriptors (struct airo_info *ai) -{ - Cmd cmd; - Resp rsp; - int i; - int rc = SUCCESS; - - /* Alloc card RX descriptors */ - netif_stop_queue(ai->dev); - - memset(&rsp, 0, sizeof(rsp)); - memset(&cmd, 0, sizeof(cmd)); - - cmd.cmd = CMD_ALLOCATEAUX; - cmd.parm0 = FID_RX; - cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux); - cmd.parm2 = MPI_MAX_FIDS; - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc != SUCCESS) { - airo_print_err(ai->dev->name, "Couldn't allocate RX FID"); - return rc; - } - - for (i = 0; i<MPI_MAX_FIDS; i++) { - memcpy_toio(ai->rxfids[i].card_ram_off, - &ai->rxfids[i].rx_desc, sizeof(RxFid)); - } - - /* Alloc card TX descriptors */ - - memset(&rsp, 0, sizeof(rsp)); - memset(&cmd, 0, sizeof(cmd)); - - cmd.cmd = CMD_ALLOCATEAUX; - cmd.parm0 = FID_TX; - cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux); - cmd.parm2 = MPI_MAX_FIDS; - - for (i = 0; i<MPI_MAX_FIDS; i++) { - ai->txfids[i].tx_desc.valid = 1; - memcpy_toio(ai->txfids[i].card_ram_off, - &ai->txfids[i].tx_desc, sizeof(TxFid)); - } - ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ - - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc != SUCCESS) { - airo_print_err(ai->dev->name, "Couldn't allocate TX FID"); - return rc; - } - - /* Alloc card Rid descriptor */ - memset(&rsp, 0, sizeof(rsp)); - memset(&cmd, 0, sizeof(cmd)); - - cmd.cmd = CMD_ALLOCATEAUX; - cmd.parm0 = RID_RW; - cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux); - cmd.parm2 = 1; /* Magic number... */ - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc != SUCCESS) { - airo_print_err(ai->dev->name, "Couldn't allocate RID"); - return rc; - } - - memcpy_toio(ai->config_desc.card_ram_off, - &ai->config_desc.rid_desc, sizeof(Rid)); - - return rc; -} - -/* - * We are setting up three things here: - * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid. - * 2) Map PCI memory for issuing commands. - * 3) Allocate memory (shared) to send and receive ethernet frames. - */ -static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci) -{ - unsigned long mem_start, mem_len, aux_start, aux_len; - int rc = -1; - int i; - dma_addr_t busaddroff; - unsigned char *vpackoff; - unsigned char __iomem *pciaddroff; - - mem_start = pci_resource_start(pci, 1); - mem_len = pci_resource_len(pci, 1); - aux_start = pci_resource_start(pci, 2); - aux_len = AUXMEMSIZE; - - if (!request_mem_region(mem_start, mem_len, DRV_NAME)) { - airo_print_err("", "Couldn't get region %x[%x]", - (int)mem_start, (int)mem_len); - goto out; - } - if (!request_mem_region(aux_start, aux_len, DRV_NAME)) { - airo_print_err("", "Couldn't get region %x[%x]", - (int)aux_start, (int)aux_len); - goto free_region1; - } - - ai->pcimem = ioremap(mem_start, mem_len); - if (!ai->pcimem) { - airo_print_err("", "Couldn't map region %x[%x]", - (int)mem_start, (int)mem_len); - goto free_region2; - } - ai->pciaux = ioremap(aux_start, aux_len); - if (!ai->pciaux) { - airo_print_err("", "Couldn't map region %x[%x]", - (int)aux_start, (int)aux_len); - goto free_memmap; - } - - /* Reserve PKTSIZE for each fid and 2K for the Rids */ - ai->shared = dma_alloc_coherent(&pci->dev, PCI_SHARED_LEN, - &ai->shared_dma, GFP_KERNEL); - if (!ai->shared) { - airo_print_err("", "Couldn't alloc_coherent %d", - PCI_SHARED_LEN); - goto free_auxmap; - } - - /* - * Setup descriptor RX, TX, CONFIG - */ - busaddroff = ai->shared_dma; - pciaddroff = ai->pciaux + AUX_OFFSET; - vpackoff = ai->shared; - - /* RX descriptor setup */ - for (i = 0; i < MPI_MAX_FIDS; i++) { - ai->rxfids[i].pending = 0; - ai->rxfids[i].card_ram_off = pciaddroff; - ai->rxfids[i].virtual_host_addr = vpackoff; - ai->rxfids[i].rx_desc.host_addr = busaddroff; - ai->rxfids[i].rx_desc.valid = 1; - ai->rxfids[i].rx_desc.len = PKTSIZE; - ai->rxfids[i].rx_desc.rdy = 0; - - pciaddroff += sizeof(RxFid); - busaddroff += PKTSIZE; - vpackoff += PKTSIZE; - } - - /* TX descriptor setup */ - for (i = 0; i < MPI_MAX_FIDS; i++) { - ai->txfids[i].card_ram_off = pciaddroff; - ai->txfids[i].virtual_host_addr = vpackoff; - ai->txfids[i].tx_desc.valid = 1; - ai->txfids[i].tx_desc.host_addr = busaddroff; - memcpy(ai->txfids[i].virtual_host_addr, - &wifictlhdr8023, sizeof(wifictlhdr8023)); - - pciaddroff += sizeof(TxFid); - busaddroff += PKTSIZE; - vpackoff += PKTSIZE; - } - ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ - - /* Rid descriptor setup */ - ai->config_desc.card_ram_off = pciaddroff; - ai->config_desc.virtual_host_addr = vpackoff; - ai->config_desc.rid_desc.host_addr = busaddroff; - ai->ridbus = busaddroff; - ai->config_desc.rid_desc.rid = 0; - ai->config_desc.rid_desc.len = RIDSIZE; - ai->config_desc.rid_desc.valid = 1; - pciaddroff += sizeof(Rid); - busaddroff += RIDSIZE; - vpackoff += RIDSIZE; - - /* Tell card about descriptors */ - if (mpi_init_descriptors (ai) != SUCCESS) - goto free_shared; - - return 0; - free_shared: - dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared, - ai->shared_dma); - free_auxmap: - iounmap(ai->pciaux); - free_memmap: - iounmap(ai->pcimem); - free_region2: - release_mem_region(aux_start, aux_len); - free_region1: - release_mem_region(mem_start, mem_len); - out: - return rc; -} - -static const struct header_ops airo_header_ops = { - .parse = wll_header_parse, -}; - -static const struct net_device_ops airo11_netdev_ops = { - .ndo_open = airo_open, - .ndo_stop = airo_close, - .ndo_start_xmit = airo_start_xmit11, - .ndo_get_stats = airo_get_stats, - .ndo_set_mac_address = airo_set_mac_address, - .ndo_siocdevprivate = airo_siocdevprivate, -}; - -static void wifi_setup(struct net_device *dev) -{ - dev->netdev_ops = &airo11_netdev_ops; - dev->header_ops = &airo_header_ops; - dev->wireless_handlers = &airo_handler_def; - - dev->type = ARPHRD_IEEE80211; - dev->hard_header_len = ETH_HLEN; - dev->mtu = AIRO_DEF_MTU; - dev->min_mtu = 68; - dev->max_mtu = MIC_MSGLEN_MAX; - dev->addr_len = ETH_ALEN; - dev->tx_queue_len = 100; - - eth_broadcast_addr(dev->broadcast); - - dev->flags = IFF_BROADCAST|IFF_MULTICAST; -} - -static struct net_device *init_wifidev(struct airo_info *ai, - struct net_device *ethdev) -{ - int err; - struct net_device *dev = alloc_netdev(0, "wifi%d", NET_NAME_UNKNOWN, - wifi_setup); - if (!dev) - return NULL; - dev->ml_priv = ethdev->ml_priv; - dev->irq = ethdev->irq; - dev->base_addr = ethdev->base_addr; - dev->wireless_data = ethdev->wireless_data; - SET_NETDEV_DEV(dev, ethdev->dev.parent); - eth_hw_addr_inherit(dev, ethdev); - err = register_netdev(dev); - if (err<0) { - free_netdev(dev); - return NULL; - } - return dev; -} - -static int reset_card(struct net_device *dev, int lock) -{ - struct airo_info *ai = dev->ml_priv; - - if (lock && down_interruptible(&ai->sem)) - return -1; - waitbusy (ai); - OUT4500(ai, COMMAND, CMD_SOFTRESET); - msleep(200); - waitbusy (ai); - msleep(200); - if (lock) - up(&ai->sem); - return 0; -} - -#define AIRO_MAX_NETWORK_COUNT 64 -static int airo_networks_allocate(struct airo_info *ai) -{ - if (ai->networks) - return 0; - - ai->networks = kcalloc(AIRO_MAX_NETWORK_COUNT, sizeof(BSSListElement), - GFP_KERNEL); - if (!ai->networks) { - airo_print_warn("", "Out of memory allocating beacons"); - return -ENOMEM; - } - - return 0; -} - -static void airo_networks_free(struct airo_info *ai) -{ - kfree(ai->networks); - ai->networks = NULL; -} - -static void airo_networks_initialize(struct airo_info *ai) -{ - int i; - - INIT_LIST_HEAD(&ai->network_free_list); - INIT_LIST_HEAD(&ai->network_list); - for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++) - list_add_tail(&ai->networks[i].list, - &ai->network_free_list); -} - -static const struct net_device_ops airo_netdev_ops = { - .ndo_open = airo_open, - .ndo_stop = airo_close, - .ndo_start_xmit = airo_start_xmit, - .ndo_get_stats = airo_get_stats, - .ndo_set_rx_mode = airo_set_multicast_list, - .ndo_set_mac_address = airo_set_mac_address, - .ndo_siocdevprivate = airo_siocdevprivate, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops mpi_netdev_ops = { - .ndo_open = airo_open, - .ndo_stop = airo_close, - .ndo_start_xmit = mpi_start_xmit, - .ndo_get_stats = airo_get_stats, - .ndo_set_rx_mode = airo_set_multicast_list, - .ndo_set_mac_address = airo_set_mac_address, - .ndo_siocdevprivate = airo_siocdevprivate, - .ndo_validate_addr = eth_validate_addr, -}; - - -static struct net_device *_init_airo_card(unsigned short irq, int port, - int is_pcmcia, struct pci_dev *pci, - struct device *dmdev) -{ - struct net_device *dev; - struct airo_info *ai; - int i, rc; - CapabilityRid cap_rid; - - /* Create the network device object. */ - dev = alloc_netdev(sizeof(*ai), "", NET_NAME_UNKNOWN, ether_setup); - if (!dev) { - airo_print_err("", "Couldn't alloc_etherdev"); - return NULL; - } - - ai = dev->ml_priv = netdev_priv(dev); - ai->wifidev = NULL; - ai->flags = 1 << FLAG_RADIO_DOWN; - ai->jobs = 0; - ai->dev = dev; - if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) { - airo_print_dbg("", "Found an MPI350 card"); - set_bit(FLAG_MPI, &ai->flags); - } - spin_lock_init(&ai->aux_lock); - sema_init(&ai->sem, 1); - ai->config.len = 0; - ai->pci = pci; - init_waitqueue_head (&ai->thr_wait); - ai->tfm = NULL; - add_airo_dev(ai); - ai->APList.len = cpu_to_le16(sizeof(struct APListRid)); - - if (airo_networks_allocate (ai)) - goto err_out_free; - airo_networks_initialize (ai); - - skb_queue_head_init (&ai->txq); - - /* The Airo-specific entries in the device structure. */ - if (test_bit(FLAG_MPI,&ai->flags)) - dev->netdev_ops = &mpi_netdev_ops; - else - dev->netdev_ops = &airo_netdev_ops; - dev->wireless_handlers = &airo_handler_def; - ai->wireless_data.spy_data = &ai->spy_data; - dev->wireless_data = &ai->wireless_data; - dev->irq = irq; - dev->base_addr = port; - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - dev->max_mtu = MIC_MSGLEN_MAX; - - SET_NETDEV_DEV(dev, dmdev); - - reset_card (dev, 1); - msleep(400); - - if (!is_pcmcia) { - if (!request_region(dev->base_addr, 64, DRV_NAME)) { - rc = -EBUSY; - airo_print_err(dev->name, "Couldn't request region"); - goto err_out_nets; - } - } - - if (test_bit(FLAG_MPI,&ai->flags)) { - if (mpi_map_card(ai, pci)) { - airo_print_err("", "Could not map memory"); - goto err_out_res; - } - } - - if (probe) { - if (setup_card(ai, dev, 1) != SUCCESS) { - airo_print_err(dev->name, "MAC could not be enabled"); - rc = -EIO; - goto err_out_map; - } - } else if (!test_bit(FLAG_MPI,&ai->flags)) { - ai->bap_read = fast_bap_read; - set_bit(FLAG_FLASHING, &ai->flags); - } - - strcpy(dev->name, "eth%d"); - rc = register_netdev(dev); - if (rc) { - airo_print_err(dev->name, "Couldn't register_netdev"); - goto err_out_map; - } - ai->wifidev = init_wifidev(ai, dev); - if (!ai->wifidev) - goto err_out_reg; - - rc = readCapabilityRid(ai, &cap_rid, 1); - if (rc != SUCCESS) { - rc = -EIO; - goto err_out_wifi; - } - /* WEP capability discovery */ - ai->wep_capable = (cap_rid.softCap & cpu_to_le16(0x02)) ? 1 : 0; - ai->max_wep_idx = (cap_rid.softCap & cpu_to_le16(0x80)) ? 3 : 0; - - airo_print_info(dev->name, "Firmware version %x.%x.%02d", - ((le16_to_cpu(cap_rid.softVer) >> 8) & 0xF), - (le16_to_cpu(cap_rid.softVer) & 0xFF), - le16_to_cpu(cap_rid.softSubVer)); - - /* Test for WPA support */ - /* Only firmware versions 5.30.17 or better can do WPA */ - if (le16_to_cpu(cap_rid.softVer) > 0x530 - || (le16_to_cpu(cap_rid.softVer) == 0x530 - && le16_to_cpu(cap_rid.softSubVer) >= 17)) { - airo_print_info(ai->dev->name, "WPA supported."); - - set_bit(FLAG_WPA_CAPABLE, &ai->flags); - ai->bssListFirst = RID_WPA_BSSLISTFIRST; - ai->bssListNext = RID_WPA_BSSLISTNEXT; - ai->bssListRidLen = sizeof(BSSListRid); - } else { - airo_print_info(ai->dev->name, "WPA unsupported with firmware " - "versions older than 5.30.17."); - - ai->bssListFirst = RID_BSSLISTFIRST; - ai->bssListNext = RID_BSSLISTNEXT; - ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra); - } - - set_bit(FLAG_REGISTERED,&ai->flags); - airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); - - /* Allocate the transmit buffers */ - if (probe && !test_bit(FLAG_MPI,&ai->flags)) - for (i = 0; i < MAX_FIDS; i++) - ai->fids[i] = transmit_allocate(ai, AIRO_DEF_MTU, i>=MAX_FIDS/2); - - if (setup_proc_entry(dev, dev->ml_priv) < 0) - goto err_out_wifi; - - return dev; - -err_out_wifi: - unregister_netdev(ai->wifidev); - free_netdev(ai->wifidev); -err_out_reg: - unregister_netdev(dev); -err_out_map: - if (test_bit(FLAG_MPI,&ai->flags) && pci) { - dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared, - ai->shared_dma); - iounmap(ai->pciaux); - iounmap(ai->pcimem); - mpi_unmap_card(ai->pci); - } -err_out_res: - if (!is_pcmcia) - release_region(dev->base_addr, 64); -err_out_nets: - airo_networks_free(ai); -err_out_free: - del_airo_dev(ai); - free_netdev(dev); - return NULL; -} - -struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia, - struct device *dmdev) -{ - return _init_airo_card (irq, port, is_pcmcia, NULL, dmdev); -} - -EXPORT_SYMBOL(init_airo_card); - -static int waitbusy (struct airo_info *ai) -{ - int delay = 0; - while ((IN4500(ai, COMMAND) & COMMAND_BUSY) && (delay < 10000)) { - udelay (10); - if ((++delay % 20) == 0) - OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); - } - return delay < 10000; -} - -int reset_airo_card(struct net_device *dev) -{ - int i; - struct airo_info *ai = dev->ml_priv; - - if (reset_card (dev, 1)) - return -1; - - if (setup_card(ai, dev, 1) != SUCCESS) { - airo_print_err(dev->name, "MAC could not be enabled"); - return -1; - } - airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); - /* Allocate the transmit buffers if needed */ - if (!test_bit(FLAG_MPI,&ai->flags)) - for (i = 0; i < MAX_FIDS; i++) - ai->fids[i] = transmit_allocate (ai, AIRO_DEF_MTU, i>=MAX_FIDS/2); - - enable_interrupts(ai); - netif_wake_queue(dev); - return 0; -} - -EXPORT_SYMBOL(reset_airo_card); - -static void airo_send_event(struct net_device *dev) -{ - struct airo_info *ai = dev->ml_priv; - union iwreq_data wrqu; - StatusRid status_rid; - - clear_bit(JOB_EVENT, &ai->jobs); - PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0); - up(&ai->sem); - wrqu.data.length = 0; - wrqu.data.flags = 0; - memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); -} - -static void airo_process_scan_results (struct airo_info *ai) -{ - union iwreq_data wrqu; - BSSListRid bss; - int rc; - BSSListElement * loop_net; - BSSListElement * tmp_net; - - /* Blow away current list of scan results */ - list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) { - list_move_tail (&loop_net->list, &ai->network_free_list); - /* Don't blow away ->list, just BSS data */ - memset (loop_net, 0, sizeof (loop_net->bss)); - } - - /* Try to read the first entry of the scan result */ - rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0); - if ((rc) || (bss.index == cpu_to_le16(0xffff))) { - /* No scan results */ - goto out; - } - - /* Read and parse all entries */ - tmp_net = NULL; - while ((!rc) && (bss.index != cpu_to_le16(0xffff))) { - /* Grab a network off the free list */ - if (!list_empty(&ai->network_free_list)) { - tmp_net = list_entry(ai->network_free_list.next, - BSSListElement, list); - list_del(ai->network_free_list.next); - } - - if (tmp_net != NULL) { - memcpy(tmp_net, &bss, sizeof(tmp_net->bss)); - list_add_tail(&tmp_net->list, &ai->network_list); - tmp_net = NULL; - } - - /* Read next entry */ - rc = PC4500_readrid(ai, ai->bssListNext, - &bss, ai->bssListRidLen, 0); - } - -out: - /* write APList back (we cleared it in airo_set_scan) */ - disable_MAC(ai, 2); - writeAPListRid(ai, &ai->APList, 0); - enable_MAC(ai, 0); - - ai->scan_timeout = 0; - clear_bit(JOB_SCAN_RESULTS, &ai->jobs); - up(&ai->sem); - - /* Send an empty event to user space. - * We don't send the received data on - * the event because it would require - * us to do complex transcoding, and - * we want to minimise the work done in - * the irq handler. Use a request to - * extract the data - Jean II */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL); -} - -static int airo_thread(void *data) -{ - struct net_device *dev = data; - struct airo_info *ai = dev->ml_priv; - int locked; - - set_freezable(); - while (1) { - /* make swsusp happy with our thread */ - try_to_freeze(); - - if (test_bit(JOB_DIE, &ai->jobs)) - break; - - if (ai->jobs) { - locked = down_interruptible(&ai->sem); - } else { - wait_queue_entry_t wait; - - init_waitqueue_entry(&wait, current); - add_wait_queue(&ai->thr_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (ai->jobs) - break; - if (ai->expires || ai->scan_timeout) { - if (ai->scan_timeout && - time_after_eq(jiffies, ai->scan_timeout)) { - set_bit(JOB_SCAN_RESULTS, &ai->jobs); - break; - } else if (ai->expires && - time_after_eq(jiffies, ai->expires)) { - set_bit(JOB_AUTOWEP, &ai->jobs); - break; - } - if (!kthread_should_stop() && - !freezing(current)) { - unsigned long wake_at; - if (!ai->expires || !ai->scan_timeout) { - wake_at = max(ai->expires, - ai->scan_timeout); - } else { - wake_at = min(ai->expires, - ai->scan_timeout); - } - schedule_timeout(wake_at - jiffies); - continue; - } - } else if (!kthread_should_stop() && - !freezing(current)) { - schedule(); - continue; - } - break; - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&ai->thr_wait, &wait); - locked = 1; - } - - if (locked) - continue; - - if (test_bit(JOB_DIE, &ai->jobs)) { - up(&ai->sem); - break; - } - - if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) { - up(&ai->sem); - continue; - } - - if (test_bit(JOB_XMIT, &ai->jobs)) - airo_end_xmit(dev, true); - else if (test_bit(JOB_XMIT11, &ai->jobs)) - airo_end_xmit11(dev, true); - else if (test_bit(JOB_STATS, &ai->jobs)) - airo_read_stats(dev); - else if (test_bit(JOB_PROMISC, &ai->jobs)) - airo_set_promisc(ai, true); - else if (test_bit(JOB_MIC, &ai->jobs)) - micinit(ai); - else if (test_bit(JOB_EVENT, &ai->jobs)) - airo_send_event(dev); - else if (test_bit(JOB_AUTOWEP, &ai->jobs)) - timer_func(dev); - else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs)) - airo_process_scan_results(ai); - else /* Shouldn't get here, but we make sure to unlock */ - up(&ai->sem); - } - - return 0; -} - -static int header_len(__le16 ctl) -{ - u16 fc = le16_to_cpu(ctl); - switch (fc & 0xc) { - case 4: - if ((fc & 0xe0) == 0xc0) - return 10; /* one-address control packet */ - return 16; /* two-address control packet */ - case 8: - if ((fc & 0x300) == 0x300) - return 30; /* WDS packet */ - } - return 24; -} - -static void airo_handle_cisco_mic(struct airo_info *ai) -{ - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) { - set_bit(JOB_MIC, &ai->jobs); - wake_up_interruptible(&ai->thr_wait); - } -} - -/* Airo Status codes */ -#define STAT_NOBEACON 0x8000 /* Loss of sync - missed beacons */ -#define STAT_MAXRETRIES 0x8001 /* Loss of sync - max retries */ -#define STAT_MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/ -#define STAT_FORCELOSS 0x8003 /* Loss of sync - host request */ -#define STAT_TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */ -#define STAT_DEAUTH 0x8100 /* low byte is 802.11 reason code */ -#define STAT_DISASSOC 0x8200 /* low byte is 802.11 reason code */ -#define STAT_ASSOC_FAIL 0x8400 /* low byte is 802.11 reason code */ -#define STAT_AUTH_FAIL 0x0300 /* low byte is 802.11 reason code */ -#define STAT_ASSOC 0x0400 /* Associated */ -#define STAT_REASSOC 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */ - -static void airo_print_status(const char *devname, u16 status) -{ - u8 reason = status & 0xFF; - - switch (status & 0xFF00) { - case STAT_NOBEACON: - switch (status) { - case STAT_NOBEACON: - airo_print_dbg(devname, "link lost (missed beacons)"); - break; - case STAT_MAXRETRIES: - case STAT_MAXARL: - airo_print_dbg(devname, "link lost (max retries)"); - break; - case STAT_FORCELOSS: - airo_print_dbg(devname, "link lost (local choice)"); - break; - case STAT_TSFSYNC: - airo_print_dbg(devname, "link lost (TSF sync lost)"); - break; - default: - airo_print_dbg(devname, "unknown status %x\n", status); - break; - } - break; - case STAT_DEAUTH: - airo_print_dbg(devname, "deauthenticated (reason: %d)", reason); - break; - case STAT_DISASSOC: - airo_print_dbg(devname, "disassociated (reason: %d)", reason); - break; - case STAT_ASSOC_FAIL: - airo_print_dbg(devname, "association failed (reason: %d)", - reason); - break; - case STAT_AUTH_FAIL: - airo_print_dbg(devname, "authentication failed (reason: %d)", - reason); - break; - case STAT_ASSOC: - case STAT_REASSOC: - break; - default: - airo_print_dbg(devname, "unknown status %x\n", status); - break; - } -} - -static void airo_handle_link(struct airo_info *ai) -{ - union iwreq_data wrqu; - int scan_forceloss = 0; - u16 status; - - /* Get new status and acknowledge the link change */ - status = le16_to_cpu(IN4500(ai, LINKSTAT)); - OUT4500(ai, EVACK, EV_LINK); - - if ((status == STAT_FORCELOSS) && (ai->scan_timeout > 0)) - scan_forceloss = 1; - - airo_print_status(ai->dev->name, status); - - if ((status == STAT_ASSOC) || (status == STAT_REASSOC)) { - if (auto_wep) - ai->expires = 0; - if (ai->list_bss_task) - wake_up_process(ai->list_bss_task); - set_bit(FLAG_UPDATE_UNI, &ai->flags); - set_bit(FLAG_UPDATE_MULTI, &ai->flags); - - set_bit(JOB_EVENT, &ai->jobs); - wake_up_interruptible(&ai->thr_wait); - - netif_carrier_on(ai->dev); - } else if (!scan_forceloss) { - if (auto_wep && !ai->expires) { - ai->expires = RUN_AT(3*HZ); - wake_up_interruptible(&ai->thr_wait); - } - - /* Send event to user space */ - eth_zero_addr(wrqu.ap_addr.sa_data); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(ai->dev, SIOCGIWAP, &wrqu, NULL); - netif_carrier_off(ai->dev); - } else { - netif_carrier_off(ai->dev); - } -} - -static void airo_handle_rx(struct airo_info *ai) -{ - struct sk_buff *skb = NULL; - __le16 fc, v, *buffer, tmpbuf[4]; - u16 len, hdrlen = 0, gap, fid; - struct rx_hdr hdr; - int success = 0; - - if (test_bit(FLAG_MPI, &ai->flags)) { - if (test_bit(FLAG_802_11, &ai->flags)) - mpi_receive_802_11(ai); - else - mpi_receive_802_3(ai); - OUT4500(ai, EVACK, EV_RX); - return; - } - - fid = IN4500(ai, RXFID); - - /* Get the packet length */ - if (test_bit(FLAG_802_11, &ai->flags)) { - bap_setup (ai, fid, 4, BAP0); - bap_read (ai, (__le16*)&hdr, sizeof(hdr), BAP0); - /* Bad CRC. Ignore packet */ - if (le16_to_cpu(hdr.status) & 2) - hdr.len = 0; - if (ai->wifidev == NULL) - hdr.len = 0; - } else { - bap_setup(ai, fid, 0x36, BAP0); - bap_read(ai, &hdr.len, 2, BAP0); - } - len = le16_to_cpu(hdr.len); - - if (len > AIRO_DEF_MTU) { - airo_print_err(ai->dev->name, "Bad size %d", len); - goto done; - } - if (len == 0) - goto done; - - if (test_bit(FLAG_802_11, &ai->flags)) { - bap_read(ai, &fc, sizeof (fc), BAP0); - hdrlen = header_len(fc); - } else - hdrlen = ETH_ALEN * 2; - - skb = dev_alloc_skb(len + hdrlen + 2 + 2); - if (!skb) { - ai->dev->stats.rx_dropped++; - goto done; - } - - skb_reserve(skb, 2); /* This way the IP header is aligned */ - buffer = skb_put(skb, len + hdrlen); - if (test_bit(FLAG_802_11, &ai->flags)) { - buffer[0] = fc; - bap_read(ai, buffer + 1, hdrlen - 2, BAP0); - if (hdrlen == 24) - bap_read(ai, tmpbuf, 6, BAP0); - - bap_read(ai, &v, sizeof(v), BAP0); - gap = le16_to_cpu(v); - if (gap) { - if (gap <= 8) { - bap_read(ai, tmpbuf, gap, BAP0); - } else { - airo_print_err(ai->dev->name, "gaplen too " - "big. Problems will follow..."); - } - } - bap_read(ai, buffer + hdrlen/2, len, BAP0); - } else { - MICBuffer micbuf; - - bap_read(ai, buffer, ETH_ALEN * 2, BAP0); - if (ai->micstats.enabled) { - bap_read(ai, (__le16 *) &micbuf, sizeof (micbuf), BAP0); - if (ntohs(micbuf.typelen) > 0x05DC) - bap_setup(ai, fid, 0x44, BAP0); - else { - if (len <= sizeof (micbuf)) { - dev_kfree_skb_irq(skb); - goto done; - } - - len -= sizeof(micbuf); - skb_trim(skb, len + hdrlen); - } - } - - bap_read(ai, buffer + ETH_ALEN, len, BAP0); - if (decapsulate(ai, &micbuf, (etherHead*) buffer, len)) - dev_kfree_skb_irq (skb); - else - success = 1; - } - -#ifdef WIRELESS_SPY - if (success && (ai->spy_data.spy_number > 0)) { - char *sa; - struct iw_quality wstats; - - /* Prepare spy data : addr + qual */ - if (!test_bit(FLAG_802_11, &ai->flags)) { - sa = (char *) buffer + 6; - bap_setup(ai, fid, 8, BAP0); - bap_read(ai, (__le16 *) hdr.rssi, 2, BAP0); - } else - sa = (char *) buffer + 10; - wstats.qual = hdr.rssi[0]; - if (ai->rssi) - wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; - else - wstats.level = (hdr.rssi[1] + 321) / 2; - wstats.noise = ai->wstats.qual.noise; - wstats.updated = IW_QUAL_LEVEL_UPDATED - | IW_QUAL_QUAL_UPDATED - | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(ai->dev, sa, &wstats); - } -#endif /* WIRELESS_SPY */ - -done: - OUT4500(ai, EVACK, EV_RX); - - if (success) { - if (test_bit(FLAG_802_11, &ai->flags)) { - skb_reset_mac_header(skb); - skb->pkt_type = PACKET_OTHERHOST; - skb->dev = ai->wifidev; - skb->protocol = htons(ETH_P_802_2); - } else - skb->protocol = eth_type_trans(skb, ai->dev); - skb->ip_summed = CHECKSUM_NONE; - - netif_rx(skb); - } -} - -static void airo_handle_tx(struct airo_info *ai, u16 status) -{ - int i, index = -1; - u16 fid; - - if (test_bit(FLAG_MPI, &ai->flags)) { - unsigned long flags; - - if (status & EV_TXEXC) - get_tx_error(ai, -1); - - spin_lock_irqsave(&ai->aux_lock, flags); - if (!skb_queue_empty(&ai->txq)) { - spin_unlock_irqrestore(&ai->aux_lock, flags); - mpi_send_packet(ai->dev); - } else { - clear_bit(FLAG_PENDING_XMIT, &ai->flags); - spin_unlock_irqrestore(&ai->aux_lock, flags); - netif_wake_queue(ai->dev); - } - OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); - return; - } - - fid = IN4500(ai, TXCOMPLFID); - - for (i = 0; i < MAX_FIDS; i++) { - if ((ai->fids[i] & 0xffff) == fid) - index = i; - } - - if (index != -1) { - if (status & EV_TXEXC) - get_tx_error(ai, index); - - OUT4500(ai, EVACK, status & (EV_TX | EV_TXEXC)); - - /* Set up to be used again */ - ai->fids[index] &= 0xffff; - if (index < MAX_FIDS / 2) { - if (!test_bit(FLAG_PENDING_XMIT, &ai->flags)) - netif_wake_queue(ai->dev); - } else { - if (!test_bit(FLAG_PENDING_XMIT11, &ai->flags)) - netif_wake_queue(ai->wifidev); - } - } else { - OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); - airo_print_err(ai->dev->name, "Unallocated FID was used to xmit"); - } -} - -static irqreturn_t airo_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - u16 status, savedInterrupts = 0; - struct airo_info *ai = dev->ml_priv; - int handled = 0; - - if (!netif_device_present(dev)) - return IRQ_NONE; - - for (;;) { - status = IN4500(ai, EVSTAT); - if (!(status & STATUS_INTS) || (status == 0xffff)) - break; - - handled = 1; - - if (status & EV_AWAKE) { - OUT4500(ai, EVACK, EV_AWAKE); - OUT4500(ai, EVACK, EV_AWAKE); - } - - if (!savedInterrupts) { - savedInterrupts = IN4500(ai, EVINTEN); - OUT4500(ai, EVINTEN, 0); - } - - if (status & EV_MIC) { - OUT4500(ai, EVACK, EV_MIC); - airo_handle_cisco_mic(ai); - } - - if (status & EV_LINK) { - /* Link status changed */ - airo_handle_link(ai); - } - - /* Check to see if there is something to receive */ - if (status & EV_RX) - airo_handle_rx(ai); - - /* Check to see if a packet has been transmitted */ - if (status & (EV_TX | EV_TXCPY | EV_TXEXC)) - airo_handle_tx(ai, status); - - if (status & ~STATUS_INTS & ~IGNORE_INTS) { - airo_print_warn(ai->dev->name, "Got weird status %x", - status & ~STATUS_INTS & ~IGNORE_INTS); - } - } - - if (savedInterrupts) - OUT4500(ai, EVINTEN, savedInterrupts); - - return IRQ_RETVAL(handled); -} - -/* - * Routines to talk to the card - */ - -/* - * This was originally written for the 4500, hence the name - * NOTE: If use with 8bit mode and SMP bad things will happen! - * Why would some one do 8 bit IO in an SMP machine?!? - */ -static void OUT4500(struct airo_info *ai, u16 reg, u16 val) -{ - if (test_bit(FLAG_MPI,&ai->flags)) - reg <<= 1; - if (!do8bitIO) - outw(val, ai->dev->base_addr + reg); - else { - outb(val & 0xff, ai->dev->base_addr + reg); - outb(val >> 8, ai->dev->base_addr + reg + 1); - } -} - -static u16 IN4500(struct airo_info *ai, u16 reg) -{ - unsigned short rc; - - if (test_bit(FLAG_MPI,&ai->flags)) - reg <<= 1; - if (!do8bitIO) - rc = inw(ai->dev->base_addr + reg); - else { - rc = inb(ai->dev->base_addr + reg); - rc += ((int)inb(ai->dev->base_addr + reg + 1)) << 8; - } - return rc; -} - -static int enable_MAC(struct airo_info *ai, int lock) -{ - int rc; - Cmd cmd; - Resp rsp; - - /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions - * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down" - * Note : we could try to use !netif_running(dev) in enable_MAC() - * instead of this flag, but I don't trust it *within* the - * open/close functions, and testing both flags together is - * "cheaper" - Jean II */ - if (ai->flags & FLAG_RADIO_MASK) return SUCCESS; - - if (lock && down_interruptible(&ai->sem)) - return -ERESTARTSYS; - - if (!test_bit(FLAG_ENABLED, &ai->flags)) { - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = MAC_ENABLE; - rc = issuecommand(ai, &cmd, &rsp, true); - if (rc == SUCCESS) - set_bit(FLAG_ENABLED, &ai->flags); - } else - rc = SUCCESS; - - if (lock) - up(&ai->sem); - - if (rc) - airo_print_err(ai->dev->name, "Cannot enable MAC"); - else if ((rsp.status & 0xFF00) != 0) { - airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, " - "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2); - rc = ERROR; - } - return rc; -} - -static void disable_MAC(struct airo_info *ai, int lock) -{ - Cmd cmd; - Resp rsp; - - if (lock == 1 && down_interruptible(&ai->sem)) - return; - - if (test_bit(FLAG_ENABLED, &ai->flags)) { - if (lock != 2) /* lock == 2 means don't disable carrier */ - netif_carrier_off(ai->dev); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = MAC_DISABLE; // disable in case already enabled - issuecommand(ai, &cmd, &rsp, true); - clear_bit(FLAG_ENABLED, &ai->flags); - } - if (lock == 1) - up(&ai->sem); -} - -static void enable_interrupts(struct airo_info *ai) -{ - /* Enable the interrupts */ - OUT4500(ai, EVINTEN, STATUS_INTS); -} - -static void disable_interrupts(struct airo_info *ai) -{ - OUT4500(ai, EVINTEN, 0); -} - -static void mpi_receive_802_3(struct airo_info *ai) -{ - RxFid rxd; - int len = 0; - struct sk_buff *skb; - char *buffer; - int off = 0; - MICBuffer micbuf; - - memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); - /* Make sure we got something */ - if (rxd.rdy && rxd.valid == 0) { - len = rxd.len + 12; - if (len < 12 || len > 2048) - goto badrx; - - skb = dev_alloc_skb(len); - if (!skb) { - ai->dev->stats.rx_dropped++; - goto badrx; - } - buffer = skb_put(skb, len); - memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2); - if (ai->micstats.enabled) { - memcpy(&micbuf, - ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2, - sizeof(micbuf)); - if (ntohs(micbuf.typelen) <= 0x05DC) { - if (len <= sizeof(micbuf) + ETH_ALEN * 2) - goto badmic; - - off = sizeof(micbuf); - skb_trim (skb, len - off); - } - } - memcpy(buffer + ETH_ALEN * 2, - ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off, - len - ETH_ALEN * 2 - off); - if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) { -badmic: - dev_kfree_skb_irq (skb); - goto badrx; - } -#ifdef WIRELESS_SPY - if (ai->spy_data.spy_number > 0) { - char *sa; - struct iw_quality wstats; - /* Prepare spy data : addr + qual */ - sa = buffer + ETH_ALEN; - wstats.qual = 0; /* XXX Where do I get that info from ??? */ - wstats.level = 0; - wstats.updated = 0; - /* Update spy records */ - wireless_spy_update(ai->dev, sa, &wstats); - } -#endif /* WIRELESS_SPY */ - - skb->ip_summed = CHECKSUM_NONE; - skb->protocol = eth_type_trans(skb, ai->dev); - netif_rx(skb); - } -badrx: - if (rxd.valid == 0) { - rxd.valid = 1; - rxd.rdy = 0; - rxd.len = PKTSIZE; - memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); - } -} - -static void mpi_receive_802_11(struct airo_info *ai) -{ - RxFid rxd; - struct sk_buff *skb = NULL; - u16 len, hdrlen = 0; - __le16 fc; - struct rx_hdr hdr; - u16 gap; - u16 *buffer; - char *ptr = ai->rxfids[0].virtual_host_addr + 4; - - memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); - memcpy ((char *)&hdr, ptr, sizeof(hdr)); - ptr += sizeof(hdr); - /* Bad CRC. Ignore packet */ - if (le16_to_cpu(hdr.status) & 2) - hdr.len = 0; - if (ai->wifidev == NULL) - hdr.len = 0; - len = le16_to_cpu(hdr.len); - if (len > AIRO_DEF_MTU) { - airo_print_err(ai->dev->name, "Bad size %d", len); - goto badrx; - } - if (len == 0) - goto badrx; - - fc = get_unaligned((__le16 *)ptr); - hdrlen = header_len(fc); - - skb = dev_alloc_skb(len + hdrlen + 2); - if (!skb) { - ai->dev->stats.rx_dropped++; - goto badrx; - } - buffer = skb_put(skb, len + hdrlen); - memcpy ((char *)buffer, ptr, hdrlen); - ptr += hdrlen; - if (hdrlen == 24) - ptr += 6; - gap = get_unaligned_le16(ptr); - ptr += sizeof(__le16); - if (gap) { - if (gap <= 8) - ptr += gap; - else - airo_print_err(ai->dev->name, - "gaplen too big. Problems will follow..."); - } - memcpy ((char *)buffer + hdrlen, ptr, len); - ptr += len; -#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ - if (ai->spy_data.spy_number > 0) { - char *sa; - struct iw_quality wstats; - /* Prepare spy data : addr + qual */ - sa = (char*)buffer + 10; - wstats.qual = hdr.rssi[0]; - if (ai->rssi) - wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; - else - wstats.level = (hdr.rssi[1] + 321) / 2; - wstats.noise = ai->wstats.qual.noise; - wstats.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(ai->dev, sa, &wstats); - } -#endif /* IW_WIRELESS_SPY */ - skb_reset_mac_header(skb); - skb->pkt_type = PACKET_OTHERHOST; - skb->dev = ai->wifidev; - skb->protocol = htons(ETH_P_802_2); - skb->ip_summed = CHECKSUM_NONE; - netif_rx(skb); - -badrx: - if (rxd.valid == 0) { - rxd.valid = 1; - rxd.rdy = 0; - rxd.len = PKTSIZE; - memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); - } -} - -static inline void set_auth_type(struct airo_info *local, int auth_type) -{ - local->config.authType = auth_type; - /* Cache the last auth type used (of AUTH_OPEN and AUTH_ENCRYPT). - * Used by airo_set_auth() - */ - if (auth_type == AUTH_OPEN || auth_type == AUTH_ENCRYPT) - local->last_auth = auth_type; -} - -static int noinline_for_stack airo_readconfig(struct airo_info *ai, - struct net_device *dev, int lock) -{ - int i, status; - /* large variables, so don't inline this function, - * maybe change to kmalloc - */ - tdsRssiRid rssi_rid; - CapabilityRid cap_rid; - - kfree(ai->SSID); - ai->SSID = NULL; - // general configuration (read/modify/write) - status = readConfigRid(ai, lock); - if (status != SUCCESS) return ERROR; - - status = readCapabilityRid(ai, &cap_rid, lock); - if (status != SUCCESS) return ERROR; - - status = PC4500_readrid(ai, RID_RSSI, &rssi_rid, sizeof(rssi_rid), lock); - if (status == SUCCESS) { - if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) - memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */ - } - else { - kfree(ai->rssi); - ai->rssi = NULL; - if (cap_rid.softCap & cpu_to_le16(8)) - ai->config.rmode |= RXMODE_NORMALIZED_RSSI; - else - airo_print_warn(ai->dev->name, "unknown received signal " - "level scale"); - } - ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS; - set_auth_type(ai, AUTH_OPEN); - ai->config.modulation = MOD_CCK; - - if (le16_to_cpu(cap_rid.len) >= sizeof(cap_rid) && - (cap_rid.extSoftCap & cpu_to_le16(1)) && - micsetup(ai) == SUCCESS) { - ai->config.opmode |= MODE_MIC; - set_bit(FLAG_MIC_CAPABLE, &ai->flags); - } - - /* Save off the MAC */ - eth_hw_addr_set(dev, ai->config.macAddr); - - /* Check to see if there are any insmod configured - rates to add */ - if (rates[0]) { - memset(ai->config.rates, 0, sizeof(ai->config.rates)); - for (i = 0; i < 8 && rates[i]; i++) { - ai->config.rates[i] = rates[i]; - } - } - set_bit (FLAG_COMMIT, &ai->flags); - - return SUCCESS; -} - - -static u16 setup_card(struct airo_info *ai, struct net_device *dev, int lock) -{ - Cmd cmd; - Resp rsp; - int status; - SsidRid mySsid; - __le16 lastindex; - WepKeyRid wkr; - int rc; - - memset(&mySsid, 0, sizeof(mySsid)); - kfree (ai->flash); - ai->flash = NULL; - - /* The NOP is the first step in getting the card going */ - cmd.cmd = NOP; - cmd.parm0 = cmd.parm1 = cmd.parm2 = 0; - if (lock && down_interruptible(&ai->sem)) - return ERROR; - if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { - if (lock) - up(&ai->sem); - return ERROR; - } - disable_MAC(ai, 0); - - // Let's figure out if we need to use the AUX port - if (!test_bit(FLAG_MPI,&ai->flags)) { - cmd.cmd = CMD_ENABLEAUX; - if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { - if (lock) - up(&ai->sem); - airo_print_err(ai->dev->name, "Error checking for AUX port"); - return ERROR; - } - if (!aux_bap || rsp.status & 0xff00) { - ai->bap_read = fast_bap_read; - airo_print_dbg(ai->dev->name, "Doing fast bap_reads"); - } else { - ai->bap_read = aux_bap_read; - airo_print_dbg(ai->dev->name, "Doing AUX bap_reads"); - } - } - if (lock) - up(&ai->sem); - if (ai->config.len == 0) { - status = airo_readconfig(ai, dev, lock); - if (status != SUCCESS) - return ERROR; - } - - /* Setup the SSIDs if present */ - if (ssids[0]) { - int i; - for (i = 0; i < 3 && ssids[i]; i++) { - size_t len = strlen(ssids[i]); - if (len > 32) - len = 32; - mySsid.ssids[i].len = cpu_to_le16(len); - memcpy(mySsid.ssids[i].ssid, ssids[i], len); - } - mySsid.len = cpu_to_le16(sizeof(mySsid)); - } - - status = writeConfigRid(ai, lock); - if (status != SUCCESS) return ERROR; - - /* Set up the SSID list */ - if (ssids[0]) { - status = writeSsidRid(ai, &mySsid, lock); - if (status != SUCCESS) return ERROR; - } - - status = enable_MAC(ai, lock); - if (status != SUCCESS) - return ERROR; - - /* Grab the initial wep key, we gotta save it for auto_wep */ - rc = readWepKeyRid(ai, &wkr, 1, lock); - if (rc == SUCCESS) do { - lastindex = wkr.kindex; - if (wkr.kindex == cpu_to_le16(0xffff)) { - ai->defindex = wkr.mac[0]; - } - rc = readWepKeyRid(ai, &wkr, 0, lock); - } while (lastindex != wkr.kindex); - - try_auto_wep(ai); - - return SUCCESS; -} - -static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp, - bool may_sleep) -{ - // Im really paranoid about letting it run forever! - int max_tries = 600000; - - if (IN4500(ai, EVSTAT) & EV_CMD) - OUT4500(ai, EVACK, EV_CMD); - - OUT4500(ai, PARAM0, pCmd->parm0); - OUT4500(ai, PARAM1, pCmd->parm1); - OUT4500(ai, PARAM2, pCmd->parm2); - OUT4500(ai, COMMAND, pCmd->cmd); - - while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) { - if ((IN4500(ai, COMMAND)) == pCmd->cmd) - // PC4500 didn't notice command, try again - OUT4500(ai, COMMAND, pCmd->cmd); - if (may_sleep && (max_tries & 255) == 0) - cond_resched(); - } - - if (max_tries == -1) { - airo_print_err(ai->dev->name, - "Max tries exceeded when issuing command"); - if (IN4500(ai, COMMAND) & COMMAND_BUSY) - OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); - return ERROR; - } - - // command completed - pRsp->status = IN4500(ai, STATUS); - pRsp->rsp0 = IN4500(ai, RESP0); - pRsp->rsp1 = IN4500(ai, RESP1); - pRsp->rsp2 = IN4500(ai, RESP2); - if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) - airo_print_err(ai->dev->name, - "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x", - pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1, - pRsp->rsp2); - - // clear stuck command busy if necessary - if (IN4500(ai, COMMAND) & COMMAND_BUSY) { - OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); - } - // acknowledge processing the status/response - OUT4500(ai, EVACK, EV_CMD); - - return SUCCESS; -} - -/* Sets up the bap to start exchange data. whichbap should - * be one of the BAP0 or BAP1 defines. Locks should be held before - * calling! */ -static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap) -{ - int timeout = 50; - int max_tries = 3; - - OUT4500(ai, SELECT0+whichbap, rid); - OUT4500(ai, OFFSET0+whichbap, offset); - while (1) { - int status = IN4500(ai, OFFSET0+whichbap); - if (status & BAP_BUSY) { - /* This isn't really a timeout, but its kinda - close */ - if (timeout--) { - continue; - } - } else if (status & BAP_ERR) { - /* invalid rid or offset */ - airo_print_err(ai->dev->name, "BAP error %x %d", - status, whichbap); - return ERROR; - } else if (status & BAP_DONE) { // success - return SUCCESS; - } - if (!(max_tries--)) { - airo_print_err(ai->dev->name, - "BAP setup error too many retries\n"); - return ERROR; - } - // -- PC4500 missed it, try again - OUT4500(ai, SELECT0+whichbap, rid); - OUT4500(ai, OFFSET0+whichbap, offset); - timeout = 50; - } -} - -/* should only be called by aux_bap_read. This aux function and the - following use concepts not documented in the developers guide. I - got them from a patch given to my by Aironet */ -static u16 aux_setup(struct airo_info *ai, u16 page, - u16 offset, u16 *len) -{ - u16 next; - - OUT4500(ai, AUXPAGE, page); - OUT4500(ai, AUXOFF, 0); - next = IN4500(ai, AUXDATA); - *len = IN4500(ai, AUXDATA)&0xff; - if (offset != 4) OUT4500(ai, AUXOFF, offset); - return next; -} - -/* requires call to bap_setup() first */ -static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst, - int bytelen, int whichbap) -{ - u16 len; - u16 page; - u16 offset; - u16 next; - int words; - int i; - unsigned long flags; - - spin_lock_irqsave(&ai->aux_lock, flags); - page = IN4500(ai, SWS0+whichbap); - offset = IN4500(ai, SWS2+whichbap); - next = aux_setup(ai, page, offset, &len); - words = (bytelen+1)>>1; - - for (i = 0; i<words;) { - int count; - count = (len>>1) < (words-i) ? (len>>1) : (words-i); - if (!do8bitIO) - insw(ai->dev->base_addr+DATA0+whichbap, - pu16Dst+i, count); - else - insb(ai->dev->base_addr+DATA0+whichbap, - pu16Dst+i, count << 1); - i += count; - if (i<words) { - next = aux_setup(ai, next, 4, &len); - } - } - spin_unlock_irqrestore(&ai->aux_lock, flags); - return SUCCESS; -} - - -/* requires call to bap_setup() first */ -static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst, - int bytelen, int whichbap) -{ - bytelen = (bytelen + 1) & (~1); // round up to even value - if (!do8bitIO) - insw(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1); - else - insb(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen); - return SUCCESS; -} - -/* requires call to bap_setup() first */ -static int bap_write(struct airo_info *ai, const __le16 *pu16Src, - int bytelen, int whichbap) -{ - bytelen = (bytelen + 1) & (~1); // round up to even value - if (!do8bitIO) - outsw(ai->dev->base_addr+DATA0+whichbap, - pu16Src, bytelen>>1); - else - outsb(ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen); - return SUCCESS; -} - -static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd) -{ - Cmd cmd; /* for issuing commands */ - Resp rsp; /* response from commands */ - u16 status; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = accmd; - cmd.parm0 = rid; - status = issuecommand(ai, &cmd, &rsp, true); - if (status != 0) return status; - if ((rsp.status & 0x7F00) != 0) { - return (accmd << 8) + (rsp.rsp0 & 0xFF); - } - return 0; -} - -/* Note, that we are using BAP1 which is also used by transmit, so - * we must get a lock. */ -static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock) -{ - u16 status; - int rc = SUCCESS; - - if (lock) { - if (down_interruptible(&ai->sem)) - return ERROR; - } - if (test_bit(FLAG_MPI,&ai->flags)) { - Cmd cmd; - Resp rsp; - - memset(&cmd, 0, sizeof(cmd)); - memset(&rsp, 0, sizeof(rsp)); - ai->config_desc.rid_desc.valid = 1; - ai->config_desc.rid_desc.len = RIDSIZE; - ai->config_desc.rid_desc.rid = 0; - ai->config_desc.rid_desc.host_addr = ai->ridbus; - - cmd.cmd = CMD_ACCESS; - cmd.parm0 = rid; - - memcpy_toio(ai->config_desc.card_ram_off, - &ai->config_desc.rid_desc, sizeof(Rid)); - - rc = issuecommand(ai, &cmd, &rsp, true); - - if (rsp.status & 0x7f00) - rc = rsp.rsp0; - if (!rc) - memcpy(pBuf, ai->config_desc.virtual_host_addr, len); - goto done; - } else { - if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) { - rc = status; - goto done; - } - if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { - rc = ERROR; - goto done; - } - // read the rid length field - bap_read(ai, pBuf, 2, BAP1); - // length for remaining part of rid - len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2; - - if (len <= 2) { - airo_print_err(ai->dev->name, - "Rid %x has a length of %d which is too short", - (int)rid, (int)len); - rc = ERROR; - goto done; - } - // read remainder of the rid - rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1); - } -done: - if (lock) - up(&ai->sem); - return rc; -} - -/* Note, that we are using BAP1 which is also used by transmit, so - * make sure this isn't called when a transmit is happening */ -static int PC4500_writerid(struct airo_info *ai, u16 rid, - const void *pBuf, int len, int lock) -{ - u16 status; - int rc = SUCCESS; - - *(__le16*)pBuf = cpu_to_le16((u16)len); - - if (lock) { - if (down_interruptible(&ai->sem)) - return ERROR; - } - if (test_bit(FLAG_MPI,&ai->flags)) { - Cmd cmd; - Resp rsp; - - if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid)) - airo_print_err(ai->dev->name, - "%s: MAC should be disabled (rid=%04x)", - __func__, rid); - memset(&cmd, 0, sizeof(cmd)); - memset(&rsp, 0, sizeof(rsp)); - - ai->config_desc.rid_desc.valid = 1; - ai->config_desc.rid_desc.len = *((u16 *)pBuf); - ai->config_desc.rid_desc.rid = 0; - - cmd.cmd = CMD_WRITERID; - cmd.parm0 = rid; - - memcpy_toio(ai->config_desc.card_ram_off, - &ai->config_desc.rid_desc, sizeof(Rid)); - - if (len < 4 || len > 2047) { - airo_print_err(ai->dev->name, "%s: len=%d", __func__, len); - rc = -1; - } else { - memcpy(ai->config_desc.virtual_host_addr, - pBuf, len); - - rc = issuecommand(ai, &cmd, &rsp, true); - if ((rc & 0xff00) != 0) { - airo_print_err(ai->dev->name, "%s: Write rid Error %d", - __func__, rc); - airo_print_err(ai->dev->name, "%s: Cmd=%04x", - __func__, cmd.cmd); - } - - if ((rsp.status & 0x7f00)) - rc = rsp.rsp0; - } - } else { - // --- first access so that we can write the rid data - if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) { - rc = status; - goto done; - } - // --- now write the rid data - if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { - rc = ERROR; - goto done; - } - bap_write(ai, pBuf, len, BAP1); - // ---now commit the rid data - rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS); - } -done: - if (lock) - up(&ai->sem); - return rc; -} - -/* Allocates a FID to be used for transmitting packets. We only use - one for now. */ -static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw) -{ - unsigned int loop = 3000; - Cmd cmd; - Resp rsp; - u16 txFid; - __le16 txControl; - - cmd.cmd = CMD_ALLOCATETX; - cmd.parm0 = lenPayload; - if (down_interruptible(&ai->sem)) - return ERROR; - if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { - txFid = ERROR; - goto done; - } - if ((rsp.status & 0xFF00) != 0) { - txFid = ERROR; - goto done; - } - /* wait for the allocate event/indication - * It makes me kind of nervous that this can just sit here and spin, - * but in practice it only loops like four times. */ - while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop); - if (!loop) { - txFid = ERROR; - goto done; - } - - // get the allocated fid and acknowledge - txFid = IN4500(ai, TXALLOCFID); - OUT4500(ai, EVACK, EV_ALLOC); - - /* The CARD is pretty cool since it converts the ethernet packet - * into 802.11. Also note that we don't release the FID since we - * will be using the same one over and over again. */ - /* We only have to setup the control once since we are not - * releasing the fid. */ - if (raw) - txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11 - | TXCTL_ETHERNET | TXCTL_NORELEASE); - else - txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3 - | TXCTL_ETHERNET | TXCTL_NORELEASE); - if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) - txFid = ERROR; - else - bap_write(ai, &txControl, sizeof(txControl), BAP1); - -done: - up(&ai->sem); - - return txFid; -} - -/* In general BAP1 is dedicated to transmiting packets. However, - since we need a BAP when accessing RIDs, we also use BAP1 for that. - Make sure the BAP1 spinlock is held when this is called. */ -static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket, - bool may_sleep) -{ - __le16 payloadLen; - Cmd cmd; - Resp rsp; - int miclen = 0; - u16 txFid = len; - MICBuffer pMic; - - len >>= 16; - - if (len <= ETH_ALEN * 2) { - airo_print_warn(ai->dev->name, "Short packet %d", len); - return ERROR; - } - len -= ETH_ALEN * 2; - - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && - (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) { - if (encapsulate(ai, (etherHead *)pPacket,&pMic, len) != SUCCESS) - return ERROR; - miclen = sizeof(pMic); - } - // packet is destination[6], source[6], payload[len-12] - // write the payload length and dst/src/payload - if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR; - /* The hardware addresses aren't counted as part of the payload, so - * we have to subtract the 12 bytes for the addresses off */ - payloadLen = cpu_to_le16(len + miclen); - bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1); - bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1); - if (miclen) - bap_write(ai, (__le16*)&pMic, miclen, BAP1); - bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1); - // issue the transmit command - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_TRANSMIT; - cmd.parm0 = txFid; - if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS) - return ERROR; - if ((rsp.status & 0xFF00) != 0) return ERROR; - return SUCCESS; -} - -static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket, - bool may_sleep) -{ - __le16 fc, payloadLen; - Cmd cmd; - Resp rsp; - int hdrlen; - static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6}; - /* padding of header to full size + le16 gaplen (6) + gaplen bytes */ - u16 txFid = len; - len >>= 16; - - fc = *(__le16*)pPacket; - hdrlen = header_len(fc); - - if (len < hdrlen) { - airo_print_warn(ai->dev->name, "Short packet %d", len); - return ERROR; - } - - /* packet is 802.11 header + payload - * write the payload length and dst/src/payload */ - if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR; - /* The 802.11 header aren't counted as part of the payload, so - * we have to subtract the header bytes off */ - payloadLen = cpu_to_le16(len-hdrlen); - bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1); - if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR; - bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1); - bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1); - - bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1); - // issue the transmit command - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_TRANSMIT; - cmd.parm0 = txFid; - if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS) - return ERROR; - if ((rsp.status & 0xFF00) != 0) return ERROR; - return SUCCESS; -} - -/* - * This is the proc_fs routines. It is a bit messier than I would - * like! Feel free to clean it up! - */ - -static ssize_t proc_read(struct file *file, - char __user *buffer, - size_t len, - loff_t *offset); - -static ssize_t proc_write(struct file *file, - const char __user *buffer, - size_t len, - loff_t *offset); -static int proc_close(struct inode *inode, struct file *file); - -static int proc_stats_open(struct inode *inode, struct file *file); -static int proc_statsdelta_open(struct inode *inode, struct file *file); -static int proc_status_open(struct inode *inode, struct file *file); -static int proc_SSID_open(struct inode *inode, struct file *file); -static int proc_APList_open(struct inode *inode, struct file *file); -static int proc_BSSList_open(struct inode *inode, struct file *file); -static int proc_config_open(struct inode *inode, struct file *file); -static int proc_wepkey_open(struct inode *inode, struct file *file); - -static const struct proc_ops proc_statsdelta_ops = { - .proc_read = proc_read, - .proc_open = proc_statsdelta_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_stats_ops = { - .proc_read = proc_read, - .proc_open = proc_stats_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_status_ops = { - .proc_read = proc_read, - .proc_open = proc_status_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_SSID_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_SSID_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_BSSList_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_BSSList_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_APList_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_APList_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_config_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_config_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static const struct proc_ops proc_wepkey_ops = { - .proc_read = proc_read, - .proc_write = proc_write, - .proc_open = proc_wepkey_open, - .proc_release = proc_close, - .proc_lseek = default_llseek, -}; - -static struct proc_dir_entry *airo_entry; - -struct proc_data { - int release_buffer; - int readlen; - char *rbuffer; - int writelen; - int maxwritelen; - char *wbuffer; - void (*on_close) (struct inode *, struct file *); -}; - -static int setup_proc_entry(struct net_device *dev, - struct airo_info *apriv) -{ - struct proc_dir_entry *entry; - - /* First setup the device directory */ - strcpy(apriv->proc_name, dev->name); - apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm, - airo_entry); - if (!apriv->proc_entry) - return -ENOMEM; - proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid); - - /* Setup the StatsDelta */ - entry = proc_create_data("StatsDelta", 0444 & proc_perm, - apriv->proc_entry, &proc_statsdelta_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the Stats */ - entry = proc_create_data("Stats", 0444 & proc_perm, - apriv->proc_entry, &proc_stats_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the Status */ - entry = proc_create_data("Status", 0444 & proc_perm, - apriv->proc_entry, &proc_status_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the Config */ - entry = proc_create_data("Config", proc_perm, - apriv->proc_entry, &proc_config_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the SSID */ - entry = proc_create_data("SSID", proc_perm, - apriv->proc_entry, &proc_SSID_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the APList */ - entry = proc_create_data("APList", proc_perm, - apriv->proc_entry, &proc_APList_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the BSSList */ - entry = proc_create_data("BSSList", proc_perm, - apriv->proc_entry, &proc_BSSList_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - - /* Setup the WepKey */ - entry = proc_create_data("WepKey", proc_perm, - apriv->proc_entry, &proc_wepkey_ops, dev); - if (!entry) - goto fail; - proc_set_user(entry, proc_kuid, proc_kgid); - return 0; - -fail: - remove_proc_subtree(apriv->proc_name, airo_entry); - return -ENOMEM; -} - -static int takedown_proc_entry(struct net_device *dev, - struct airo_info *apriv) -{ - remove_proc_subtree(apriv->proc_name, airo_entry); - return 0; -} - -/* - * What we want from the proc_fs is to be able to efficiently read - * and write the configuration. To do this, we want to read the - * configuration when the file is opened and write it when the file is - * closed. So basically we allocate a read buffer at open and fill it - * with data, and allocate a write buffer and read it at close. - */ - -/* - * The read routine is generic, it relies on the preallocated rbuffer - * to supply the data. - */ -static ssize_t proc_read(struct file *file, - char __user *buffer, - size_t len, - loff_t *offset) -{ - struct proc_data *priv = file->private_data; - - if (!priv->rbuffer) - return -EINVAL; - - return simple_read_from_buffer(buffer, len, offset, priv->rbuffer, - priv->readlen); -} - -/* - * The write routine is generic, it fills in a preallocated rbuffer - * to supply the data. - */ -static ssize_t proc_write(struct file *file, - const char __user *buffer, - size_t len, - loff_t *offset) -{ - ssize_t ret; - struct proc_data *priv = file->private_data; - - if (!priv->wbuffer) - return -EINVAL; - - ret = simple_write_to_buffer(priv->wbuffer, priv->maxwritelen, offset, - buffer, len); - if (ret > 0) - priv->writelen = max_t(int, priv->writelen, *offset); - - return ret; -} - -static int proc_status_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *apriv = dev->ml_priv; - CapabilityRid cap_rid; - StatusRid status_rid; - u16 mode; - int i; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - - readStatusRid(apriv, &status_rid, 1); - readCapabilityRid(apriv, &cap_rid, 1); - - mode = le16_to_cpu(status_rid.mode); - - i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n", - mode & 1 ? "CFG ": "", - mode & 2 ? "ACT ": "", - mode & 0x10 ? "SYN ": "", - mode & 0x20 ? "LNK ": "", - mode & 0x40 ? "LEAP ": "", - mode & 0x80 ? "PRIV ": "", - mode & 0x100 ? "KEY ": "", - mode & 0x200 ? "WEP ": "", - mode & 0x8000 ? "ERR ": ""); - sprintf(data->rbuffer+i, "Mode: %x\n" - "Signal Strength: %d\n" - "Signal Quality: %d\n" - "SSID: %-.*s\n" - "AP: %-.16s\n" - "Freq: %d\n" - "BitRate: %dmbs\n" - "Driver Version: %s\n" - "Device: %s\nManufacturer: %s\nFirmware Version: %s\n" - "Radio type: %x\nCountry: %x\nHardware Version: %x\n" - "Software Version: %x\nSoftware Subversion: %x\n" - "Boot block version: %x\n", - le16_to_cpu(status_rid.mode), - le16_to_cpu(status_rid.normalizedSignalStrength), - le16_to_cpu(status_rid.signalQuality), - le16_to_cpu(status_rid.SSIDlen), - status_rid.SSID, - status_rid.apName, - le16_to_cpu(status_rid.channel), - le16_to_cpu(status_rid.currentXmitRate) / 2, - version, - cap_rid.prodName, - cap_rid.manName, - cap_rid.prodVer, - le16_to_cpu(cap_rid.radioType), - le16_to_cpu(cap_rid.country), - le16_to_cpu(cap_rid.hardVer), - le16_to_cpu(cap_rid.softVer), - le16_to_cpu(cap_rid.softSubVer), - le16_to_cpu(cap_rid.bootBlockVer)); - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_stats_rid_open(struct inode*, struct file*, u16); -static int proc_statsdelta_open(struct inode *inode, - struct file *file) -{ - if (file->f_mode&FMODE_WRITE) { - return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR); - } - return proc_stats_rid_open(inode, file, RID_STATSDELTA); -} - -static int proc_stats_open(struct inode *inode, struct file *file) -{ - return proc_stats_rid_open(inode, file, RID_STATS); -} - -static int proc_stats_rid_open(struct inode *inode, - struct file *file, - u16 rid) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *apriv = dev->ml_priv; - StatsRid stats; - int i, j; - __le32 *vals = stats.vals; - int len; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(4096, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - - readStatsRid(apriv, &stats, rid, 1); - len = le16_to_cpu(stats.len); - - j = 0; - for (i = 0; statsLabels[i]!=(char *)-1 && i*4<len; i++) { - if (!statsLabels[i]) continue; - if (j+strlen(statsLabels[i])+16>4096) { - airo_print_warn(apriv->dev->name, - "Potentially disastrous buffer overflow averted!"); - break; - } - j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], - le32_to_cpu(vals[i])); - } - if (i*4 >= len) { - airo_print_warn(apriv->dev->name, "Got a short rid"); - } - data->readlen = j; - return 0; -} - -static int get_dec_u16(char *buffer, int *start, int limit) -{ - u16 value; - int valid = 0; - for (value = 0; *start < limit && buffer[*start] >= '0' && - buffer[*start] <= '9'; (*start)++) { - valid = 1; - value *= 10; - value += buffer[*start] - '0'; - } - if (!valid) return -1; - return value; -} - -static int airo_config_commit(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra); - -static inline int sniffing_mode(struct airo_info *ai) -{ - return (le16_to_cpu(ai->config.rmode) & le16_to_cpu(RXMODE_MASK)) >= - le16_to_cpu(RXMODE_RFMON); -} - -static void proc_config_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - char *line; - - if (!data->writelen) return; - - readConfigRid(ai, 1); - set_bit (FLAG_COMMIT, &ai->flags); - - line = data->wbuffer; - while (line[0]) { -/*** Mode processing */ - if (!strncmp(line, "Mode: ", 6)) { - line += 6; - if (sniffing_mode(ai)) - set_bit (FLAG_RESET, &ai->flags); - ai->config.rmode &= ~RXMODE_FULL_MASK; - clear_bit (FLAG_802_11, &ai->flags); - ai->config.opmode &= ~MODE_CFG_MASK; - ai->config.scanMode = SCANMODE_ACTIVE; - if (line[0] == 'a') { - ai->config.opmode |= MODE_STA_IBSS; - } else { - ai->config.opmode |= MODE_STA_ESS; - if (line[0] == 'r') { - ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; - ai->config.scanMode = SCANMODE_PASSIVE; - set_bit (FLAG_802_11, &ai->flags); - } else if (line[0] == 'y') { - ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER; - ai->config.scanMode = SCANMODE_PASSIVE; - set_bit (FLAG_802_11, &ai->flags); - } else if (line[0] == 'l') - ai->config.rmode |= RXMODE_LANMON; - } - set_bit (FLAG_COMMIT, &ai->flags); - } - -/*** Radio status */ - else if (!strncmp(line,"Radio: ", 7)) { - line += 7; - if (!strncmp(line,"off", 3)) { - set_bit (FLAG_RADIO_OFF, &ai->flags); - } else { - clear_bit (FLAG_RADIO_OFF, &ai->flags); - } - } -/*** NodeName processing */ - else if (!strncmp(line, "NodeName: ", 10)) { - int j; - - line += 10; - memset(ai->config.nodeName, 0, 16); -/* Do the name, assume a space between the mode and node name */ - for (j = 0; j < 16 && line[j] != '\n'; j++) { - ai->config.nodeName[j] = line[j]; - } - set_bit (FLAG_COMMIT, &ai->flags); - } - -/*** PowerMode processing */ - else if (!strncmp(line, "PowerMode: ", 11)) { - line += 11; - if (!strncmp(line, "PSPCAM", 6)) { - ai->config.powerSaveMode = POWERSAVE_PSPCAM; - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "PSP", 3)) { - ai->config.powerSaveMode = POWERSAVE_PSP; - set_bit (FLAG_COMMIT, &ai->flags); - } else { - ai->config.powerSaveMode = POWERSAVE_CAM; - set_bit (FLAG_COMMIT, &ai->flags); - } - } else if (!strncmp(line, "DataRates: ", 11)) { - int v, i = 0, k = 0; /* i is index into line, - k is index to rates */ - - line += 11; - while ((v = get_dec_u16(line, &i, 3))!=-1) { - ai->config.rates[k++] = (u8)v; - line += i + 1; - i = 0; - } - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "Channel: ", 9)) { - int v, i = 0; - line += 9; - v = get_dec_u16(line, &i, i+3); - if (v != -1) { - ai->config.channelSet = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } - } else if (!strncmp(line, "XmitPower: ", 11)) { - int v, i = 0; - line += 11; - v = get_dec_u16(line, &i, i+3); - if (v != -1) { - ai->config.txPower = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } - } else if (!strncmp(line, "WEP: ", 5)) { - line += 5; - switch(line[0]) { - case 's': - set_auth_type(ai, AUTH_SHAREDKEY); - break; - case 'e': - set_auth_type(ai, AUTH_ENCRYPT); - break; - default: - set_auth_type(ai, AUTH_OPEN); - break; - } - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "LongRetryLimit: ", 16)) { - int v, i = 0; - - line += 16; - v = get_dec_u16(line, &i, 3); - v = (v<0) ? 0 : ((v>255) ? 255 : v); - ai->config.longRetryLimit = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "ShortRetryLimit: ", 17)) { - int v, i = 0; - - line += 17; - v = get_dec_u16(line, &i, 3); - v = (v<0) ? 0 : ((v>255) ? 255 : v); - ai->config.shortRetryLimit = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "RTSThreshold: ", 14)) { - int v, i = 0; - - line += 14; - v = get_dec_u16(line, &i, 4); - v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); - ai->config.rtsThres = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "TXMSDULifetime: ", 16)) { - int v, i = 0; - - line += 16; - v = get_dec_u16(line, &i, 5); - v = (v<0) ? 0 : v; - ai->config.txLifetime = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "RXMSDULifetime: ", 16)) { - int v, i = 0; - - line += 16; - v = get_dec_u16(line, &i, 5); - v = (v<0) ? 0 : v; - ai->config.rxLifetime = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "TXDiversity: ", 13)) { - ai->config.txDiversity = - (line[13]=='l') ? 1 : - ((line[13]=='r')? 2: 3); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "RXDiversity: ", 13)) { - ai->config.rxDiversity = - (line[13]=='l') ? 1 : - ((line[13]=='r')? 2: 3); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "FragThreshold: ", 15)) { - int v, i = 0; - - line += 15; - v = get_dec_u16(line, &i, 4); - v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); - v = v & 0xfffe; /* Make sure its even */ - ai->config.fragThresh = cpu_to_le16(v); - set_bit (FLAG_COMMIT, &ai->flags); - } else if (!strncmp(line, "Modulation: ", 12)) { - line += 12; - switch(*line) { - case 'd': ai->config.modulation = MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break; - case 'c': ai->config.modulation = MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break; - case 'm': ai->config.modulation = MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break; - default: airo_print_warn(ai->dev->name, "Unknown modulation"); - } - } else if (!strncmp(line, "Preamble: ", 10)) { - line += 10; - switch(*line) { - case 'a': ai->config.preamble = PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break; - case 'l': ai->config.preamble = PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break; - case 's': ai->config.preamble = PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break; - default: airo_print_warn(ai->dev->name, "Unknown preamble"); - } - } else { - airo_print_warn(ai->dev->name, "Couldn't figure out %s", line); - } - while (line[0] && line[0] != '\n') line++; - if (line[0]) line++; - } - airo_config_commit(dev, NULL, NULL, NULL); -} - -static const char *get_rmode(__le16 mode) -{ - switch(mode & RXMODE_MASK) { - case RXMODE_RFMON: return "rfmon"; - case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon"; - case RXMODE_LANMON: return "lanmon"; - } - return "ESS"; -} - -static int proc_config_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i; - __le16 mode; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - if ((data->wbuffer = kzalloc(2048, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->maxwritelen = 2048; - data->on_close = proc_config_on_close; - - readConfigRid(ai, 1); - - mode = ai->config.opmode & MODE_CFG_MASK; - i = sprintf(data->rbuffer, - "Mode: %s\n" - "Radio: %s\n" - "NodeName: %-16s\n" - "PowerMode: %s\n" - "DataRates: %d %d %d %d %d %d %d %d\n" - "Channel: %d\n" - "XmitPower: %d\n", - mode == MODE_STA_IBSS ? "adhoc" : - mode == MODE_STA_ESS ? get_rmode(ai->config.rmode): - mode == MODE_AP ? "AP" : - mode == MODE_AP_RPTR ? "AP RPTR" : "Error", - test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on", - ai->config.nodeName, - ai->config.powerSaveMode == POWERSAVE_CAM ? "CAM" : - ai->config.powerSaveMode == POWERSAVE_PSP ? "PSP" : - ai->config.powerSaveMode == POWERSAVE_PSPCAM ? "PSPCAM" : - "Error", - (int)ai->config.rates[0], - (int)ai->config.rates[1], - (int)ai->config.rates[2], - (int)ai->config.rates[3], - (int)ai->config.rates[4], - (int)ai->config.rates[5], - (int)ai->config.rates[6], - (int)ai->config.rates[7], - le16_to_cpu(ai->config.channelSet), - le16_to_cpu(ai->config.txPower) - ); - sprintf(data->rbuffer + i, - "LongRetryLimit: %d\n" - "ShortRetryLimit: %d\n" - "RTSThreshold: %d\n" - "TXMSDULifetime: %d\n" - "RXMSDULifetime: %d\n" - "TXDiversity: %s\n" - "RXDiversity: %s\n" - "FragThreshold: %d\n" - "WEP: %s\n" - "Modulation: %s\n" - "Preamble: %s\n", - le16_to_cpu(ai->config.longRetryLimit), - le16_to_cpu(ai->config.shortRetryLimit), - le16_to_cpu(ai->config.rtsThres), - le16_to_cpu(ai->config.txLifetime), - le16_to_cpu(ai->config.rxLifetime), - ai->config.txDiversity == 1 ? "left" : - ai->config.txDiversity == 2 ? "right" : "both", - ai->config.rxDiversity == 1 ? "left" : - ai->config.rxDiversity == 2 ? "right" : "both", - le16_to_cpu(ai->config.fragThresh), - ai->config.authType == AUTH_ENCRYPT ? "encrypt" : - ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open", - ai->config.modulation == MOD_DEFAULT ? "default" : - ai->config.modulation == MOD_CCK ? "cck" : - ai->config.modulation == MOD_MOK ? "mok" : "error", - ai->config.preamble == PREAMBLE_AUTO ? "auto" : - ai->config.preamble == PREAMBLE_LONG ? "long" : - ai->config.preamble == PREAMBLE_SHORT ? "short" : "error" - ); - data->readlen = strlen(data->rbuffer); - return 0; -} - -static void proc_SSID_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - SsidRid SSID_rid; - int i; - char *p = data->wbuffer; - char *end = p + data->writelen; - - if (!data->writelen) - return; - - *end = '\n'; /* sentinel; we have space for it */ - - memset(&SSID_rid, 0, sizeof(SSID_rid)); - - for (i = 0; i < 3 && p < end; i++) { - int j = 0; - /* copy up to 32 characters from this line */ - while (*p != '\n' && j < 32) - SSID_rid.ssids[i].ssid[j++] = *p++; - if (j == 0) - break; - SSID_rid.ssids[i].len = cpu_to_le16(j); - /* skip to the beginning of the next line */ - while (*p++ != '\n') - ; - } - if (i) - SSID_rid.len = cpu_to_le16(sizeof(SSID_rid)); - disable_MAC(ai, 1); - writeSsidRid(ai, &SSID_rid, 1); - enable_MAC(ai, 1); -} - -static void proc_APList_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - APListRid *APList_rid = &ai->APList; - int i; - - if (!data->writelen) return; - - memset(APList_rid, 0, sizeof(*APList_rid)); - APList_rid->len = cpu_to_le16(sizeof(*APList_rid)); - - for (i = 0; i < 4 && data->writelen >= (i + 1) * 6 * 3; i++) - mac_pton(data->wbuffer + i * 6 * 3, APList_rid->ap[i]); - - disable_MAC(ai, 1); - writeAPListRid(ai, APList_rid, 1); - enable_MAC(ai, 1); -} - -/* This function wraps PC4500_writerid with a MAC disable */ -static int do_writerid(struct airo_info *ai, u16 rid, const void *rid_data, - int len, int dummy) -{ - int rc; - - disable_MAC(ai, 1); - rc = PC4500_writerid(ai, rid, rid_data, len, 1); - enable_MAC(ai, 1); - return rc; -} - -/* Returns the WEP key at the specified index, or -1 if that key does - * not exist. The buffer is assumed to be at least 16 bytes in length. - */ -static int get_wep_key(struct airo_info *ai, u16 index, char *buf, u16 buflen) -{ - WepKeyRid wkr; - int rc; - __le16 lastindex; - - rc = readWepKeyRid(ai, &wkr, 1, 1); - if (rc != SUCCESS) - return -1; - do { - lastindex = wkr.kindex; - if (le16_to_cpu(wkr.kindex) == index) { - int klen = min_t(int, buflen, le16_to_cpu(wkr.klen)); - memcpy(buf, wkr.key, klen); - return klen; - } - rc = readWepKeyRid(ai, &wkr, 0, 1); - if (rc != SUCCESS) - return -1; - } while (lastindex != wkr.kindex); - return -1; -} - -static int get_wep_tx_idx(struct airo_info *ai) -{ - WepKeyRid wkr; - int rc; - __le16 lastindex; - - rc = readWepKeyRid(ai, &wkr, 1, 1); - if (rc != SUCCESS) - return -1; - do { - lastindex = wkr.kindex; - if (wkr.kindex == cpu_to_le16(0xffff)) - return wkr.mac[0]; - rc = readWepKeyRid(ai, &wkr, 0, 1); - if (rc != SUCCESS) - return -1; - } while (lastindex != wkr.kindex); - return -1; -} - -static int set_wep_key(struct airo_info *ai, u16 index, const u8 *key, - u16 keylen, int perm, int lock) -{ - static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; - WepKeyRid wkr; - int rc; - - if (WARN_ON(keylen == 0)) - return -1; - - memset(&wkr, 0, sizeof(wkr)); - wkr.len = cpu_to_le16(sizeof(wkr)); - wkr.kindex = cpu_to_le16(index); - wkr.klen = cpu_to_le16(keylen); - memcpy(wkr.key, key, keylen); - memcpy(wkr.mac, macaddr, ETH_ALEN); - - if (perm) disable_MAC(ai, lock); - rc = writeWepKeyRid(ai, &wkr, perm, lock); - if (perm) enable_MAC(ai, lock); - return rc; -} - -static int set_wep_tx_idx(struct airo_info *ai, u16 index, int perm, int lock) -{ - WepKeyRid wkr; - int rc; - - memset(&wkr, 0, sizeof(wkr)); - wkr.len = cpu_to_le16(sizeof(wkr)); - wkr.kindex = cpu_to_le16(0xffff); - wkr.mac[0] = (char)index; - - if (perm) { - ai->defindex = (char)index; - disable_MAC(ai, lock); - } - - rc = writeWepKeyRid(ai, &wkr, perm, lock); - - if (perm) - enable_MAC(ai, lock); - return rc; -} - -static void proc_wepkey_on_close(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i, rc; - u8 key[16]; - u16 index = 0; - int j = 0; - - memset(key, 0, sizeof(key)); - - data = file->private_data; - if (!data->writelen) return; - - if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' && - (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) { - index = data->wbuffer[0] - '0'; - if (data->wbuffer[1] == '\n') { - rc = set_wep_tx_idx(ai, index, 1, 1); - if (rc < 0) { - airo_print_err(ai->dev->name, "failed to set " - "WEP transmit index to %d: %d.", - index, rc); - } - return; - } - j = 2; - } else { - airo_print_err(ai->dev->name, "WepKey passed invalid key index"); - return; - } - - for (i = 0; i < 16*3 && data->wbuffer[i+j]; i++) { - int val; - - if (i % 3 == 2) - continue; - - val = hex_to_bin(data->wbuffer[i+j]); - if (val < 0) { - airo_print_err(ai->dev->name, "WebKey passed invalid key hex"); - return; - } - switch(i%3) { - case 0: - key[i/3] = (u8)val << 4; - break; - case 1: - key[i/3] |= (u8)val; - break; - } - } - - rc = set_wep_key(ai, index, key, i/3, 1, 1); - if (rc < 0) { - airo_print_err(ai->dev->name, "failed to set WEP key at index " - "%d: %d.", index, rc); - } -} - -static int proc_wepkey_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - char *ptr; - WepKeyRid wkr; - __le16 lastindex; - int j = 0; - int rc; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - memset(&wkr, 0, sizeof(wkr)); - data = file->private_data; - if ((data->rbuffer = kzalloc(180, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 80; - if ((data->wbuffer = kzalloc(80, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->on_close = proc_wepkey_on_close; - - ptr = data->rbuffer; - strcpy(ptr, "No wep keys\n"); - rc = readWepKeyRid(ai, &wkr, 1, 1); - if (rc == SUCCESS) do { - lastindex = wkr.kindex; - if (wkr.kindex == cpu_to_le16(0xffff)) { - j += sprintf(ptr+j, "Tx key = %d\n", - (int)wkr.mac[0]); - } else { - j += sprintf(ptr+j, "Key %d set with length = %d\n", - le16_to_cpu(wkr.kindex), - le16_to_cpu(wkr.klen)); - } - readWepKeyRid(ai, &wkr, 0, 1); - } while ((lastindex != wkr.kindex) && (j < 180-30)); - - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_SSID_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i; - char *ptr; - SsidRid SSID_rid; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(104, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 33*3; - /* allocate maxwritelen + 1; we'll want a sentinel */ - if ((data->wbuffer = kzalloc(33*3 + 1, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->on_close = proc_SSID_on_close; - - readSsidRid(ai, &SSID_rid); - ptr = data->rbuffer; - for (i = 0; i < 3; i++) { - int j; - size_t len = le16_to_cpu(SSID_rid.ssids[i].len); - if (!len) - break; - if (len > 32) - len = 32; - for (j = 0; j < len && SSID_rid.ssids[i].ssid[j]; j++) - *ptr++ = SSID_rid.ssids[i].ssid[j]; - *ptr++ = '\n'; - } - *ptr = '\0'; - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_APList_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - int i; - char *ptr; - APListRid *APList_rid = &ai->APList; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(104, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 4*6*3; - if ((data->wbuffer = kzalloc(data->maxwritelen, GFP_KERNEL)) == NULL) { - kfree (data->rbuffer); - kfree (file->private_data); - return -ENOMEM; - } - data->on_close = proc_APList_on_close; - - ptr = data->rbuffer; - for (i = 0; i < 4; i++) { -// We end when we find a zero MAC - if (!*(int*)APList_rid->ap[i] && - !*(int*)&APList_rid->ap[i][2]) break; - ptr += sprintf(ptr, "%pM\n", APList_rid->ap[i]); - } - if (i==0) ptr += sprintf(ptr, "Not using specific APs\n"); - - *ptr = '\0'; - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_BSSList_open(struct inode *inode, struct file *file) -{ - struct proc_data *data; - struct net_device *dev = pde_data(inode); - struct airo_info *ai = dev->ml_priv; - char *ptr; - BSSListRid BSSList_rid; - int rc; - /* If doLoseSync is not 1, we won't do a Lose Sync */ - int doLoseSync = -1; - - if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) - return -ENOMEM; - data = file->private_data; - if ((data->rbuffer = kmalloc(1024, GFP_KERNEL)) == NULL) { - kfree (file->private_data); - return -ENOMEM; - } - data->writelen = 0; - data->maxwritelen = 0; - data->wbuffer = NULL; - data->on_close = NULL; - - if (file->f_mode & FMODE_WRITE) { - if (!(file->f_mode & FMODE_READ)) { - Cmd cmd; - Resp rsp; - - if (ai->flags & FLAG_RADIO_MASK) { - kfree(data->rbuffer); - kfree(file->private_data); - return -ENETDOWN; - } - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LISTBSS; - if (down_interruptible(&ai->sem)) { - kfree(data->rbuffer); - kfree(file->private_data); - return -ERESTARTSYS; - } - issuecommand(ai, &cmd, &rsp, true); - up(&ai->sem); - data->readlen = 0; - return 0; - } - doLoseSync = 1; - } - ptr = data->rbuffer; - /* There is a race condition here if there are concurrent opens. - Since it is a rare condition, we'll just live with it, otherwise - we have to add a spin lock... */ - rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); - while (rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) { - ptr += sprintf(ptr, "%pM %.*s rssi = %d", - BSSList_rid.bssid, - (int)BSSList_rid.ssidLen, - BSSList_rid.ssid, - le16_to_cpu(BSSList_rid.dBm)); - ptr += sprintf(ptr, " channel = %d %s %s %s %s\n", - le16_to_cpu(BSSList_rid.dsChannel), - BSSList_rid.cap & CAP_ESS ? "ESS" : "", - BSSList_rid.cap & CAP_IBSS ? "adhoc" : "", - BSSList_rid.cap & CAP_PRIVACY ? "wep" : "", - BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : ""); - rc = readBSSListRid(ai, 0, &BSSList_rid); - } - *ptr = '\0'; - data->readlen = strlen(data->rbuffer); - return 0; -} - -static int proc_close(struct inode *inode, struct file *file) -{ - struct proc_data *data = file->private_data; - - if (data->on_close != NULL) - data->on_close(inode, file); - kfree(data->rbuffer); - kfree(data->wbuffer); - kfree(data); - return 0; -} - -/* Since the card doesn't automatically switch to the right WEP mode, - we will make it do it. If the card isn't associated, every secs we - will switch WEP modes to see if that will help. If the card is - associated we will check every minute to see if anything has - changed. */ -static void timer_func(struct net_device *dev) -{ - struct airo_info *apriv = dev->ml_priv; - -/* We don't have a link so try changing the authtype */ - readConfigRid(apriv, 0); - disable_MAC(apriv, 0); - switch(apriv->config.authType) { - case AUTH_ENCRYPT: -/* So drop to OPEN */ - apriv->config.authType = AUTH_OPEN; - break; - case AUTH_SHAREDKEY: - if (apriv->keyindex < auto_wep) { - set_wep_tx_idx(apriv, apriv->keyindex, 0, 0); - apriv->config.authType = AUTH_SHAREDKEY; - apriv->keyindex++; - } else { - /* Drop to ENCRYPT */ - apriv->keyindex = 0; - set_wep_tx_idx(apriv, apriv->defindex, 0, 0); - apriv->config.authType = AUTH_ENCRYPT; - } - break; - default: /* We'll escalate to SHAREDKEY */ - apriv->config.authType = AUTH_SHAREDKEY; - } - set_bit (FLAG_COMMIT, &apriv->flags); - writeConfigRid(apriv, 0); - enable_MAC(apriv, 0); - up(&apriv->sem); - -/* Schedule check to see if the change worked */ - clear_bit(JOB_AUTOWEP, &apriv->jobs); - apriv->expires = RUN_AT(HZ*3); -} - -#ifdef CONFIG_PCI -static int airo_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *pent) -{ - struct net_device *dev; - - if (pci_enable_device(pdev)) - return -ENODEV; - pci_set_master(pdev); - - if (pdev->device == 0x5000 || pdev->device == 0xa504) - dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev); - else - dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev); - if (!dev) { - pci_disable_device(pdev); - return -ENODEV; - } - - pci_set_drvdata(pdev, dev); - return 0; -} - -static void airo_pci_remove(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - airo_print_info(dev->name, "Unregistering..."); - stop_airo_card(dev, 1); - pci_disable_device(pdev); -} - -static int __maybe_unused airo_pci_suspend(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - struct airo_info *ai = dev->ml_priv; - Cmd cmd; - Resp rsp; - - if (!ai->SSID) - ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL); - if (!ai->SSID) - return -ENOMEM; - readSsidRid(ai, ai->SSID); - memset(&cmd, 0, sizeof(cmd)); - /* the lock will be released at the end of the resume callback */ - if (down_interruptible(&ai->sem)) - return -EAGAIN; - disable_MAC(ai, 0); - netif_device_detach(dev); - ai->power = PMSG_SUSPEND; - cmd.cmd = HOSTSLEEP; - issuecommand(ai, &cmd, &rsp, true); - - device_wakeup_enable(dev_d); - return 0; -} - -static int __maybe_unused airo_pci_resume(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - struct airo_info *ai = dev->ml_priv; - pci_power_t prev_state = to_pci_dev(dev_d)->current_state; - - device_wakeup_disable(dev_d); - - if (prev_state != PCI_D1) { - reset_card(dev, 0); - mpi_init_descriptors(ai); - setup_card(ai, dev, 0); - clear_bit(FLAG_RADIO_OFF, &ai->flags); - clear_bit(FLAG_PENDING_XMIT, &ai->flags); - } else { - OUT4500(ai, EVACK, EV_AWAKEN); - OUT4500(ai, EVACK, EV_AWAKEN); - msleep(100); - } - - set_bit(FLAG_COMMIT, &ai->flags); - disable_MAC(ai, 0); - msleep(200); - if (ai->SSID) { - writeSsidRid(ai, ai->SSID, 0); - kfree(ai->SSID); - ai->SSID = NULL; - } - writeAPListRid(ai, &ai->APList, 0); - writeConfigRid(ai, 0); - enable_MAC(ai, 0); - ai->power = PMSG_ON; - netif_device_attach(dev); - netif_wake_queue(dev); - enable_interrupts(ai); - up(&ai->sem); - return 0; -} -#endif - -static int __init airo_init_module(void) -{ - int i; - - proc_kuid = make_kuid(&init_user_ns, proc_uid); - proc_kgid = make_kgid(&init_user_ns, proc_gid); - if (!uid_valid(proc_kuid) || !gid_valid(proc_kgid)) - return -EINVAL; - - airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL); - - if (airo_entry) - proc_set_user(airo_entry, proc_kuid, proc_kgid); - - for (i = 0; i < 4 && io[i] && irq[i]; i++) { - airo_print_info("", "Trying to configure ISA adapter at irq=%d " - "io = 0x%x", irq[i], io[i]); - if (init_airo_card(irq[i], io[i], 0, NULL)) { - /* do nothing */ ; - } - } - -#ifdef CONFIG_PCI - airo_print_info("", "Probing for PCI adapters"); - i = pci_register_driver(&airo_driver); - airo_print_info("", "Finished probing for PCI adapters"); - - if (i) { - remove_proc_entry("driver/aironet", NULL); - return i; - } -#endif - - /* Always exit with success, as we are a library module - * as well as a driver module - */ - return 0; -} - -static void __exit airo_cleanup_module(void) -{ - struct airo_info *ai; - while (!list_empty(&airo_devices)) { - ai = list_entry(airo_devices.next, struct airo_info, dev_list); - airo_print_info(ai->dev->name, "Unregistering..."); - stop_airo_card(ai->dev, 1); - } -#ifdef CONFIG_PCI - pci_unregister_driver(&airo_driver); -#endif - remove_proc_entry("driver/aironet", NULL); -} - -/* - * Initial Wireless Extension code for Aironet driver by : - * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00 - * Conversion to new driver API by : - * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 26 March 02 - * Javier also did a good amount of work here, adding some new extensions - * and fixing my code. Let's just say that without him this code just - * would not work at all... - Jean II - */ - -static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi) -{ - if (!rssi_rid) - return 0; - - return (0x100 - rssi_rid[rssi].rssidBm); -} - -static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm) -{ - int i; - - if (!rssi_rid) - return 0; - - for (i = 0; i < 256; i++) - if (rssi_rid[i].rssidBm == dbm) - return rssi_rid[i].rssipct; - - return 0; -} - - -static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid) -{ - int quality = 0; - u16 sq; - - if ((status_rid->mode & cpu_to_le16(0x3f)) != cpu_to_le16(0x3f)) - return 0; - - if (!(cap_rid->hardCap & cpu_to_le16(8))) - return 0; - - sq = le16_to_cpu(status_rid->signalQuality); - if (memcmp(cap_rid->prodName, "350", 3)) - if (sq > 0x20) - quality = 0; - else - quality = 0x20 - sq; - else - if (sq > 0xb0) - quality = 0; - else if (sq < 0x10) - quality = 0xa0; - else - quality = 0xb0 - sq; - return quality; -} - -#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0) -#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50) - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get protocol name - */ -static int airo_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *cwrq, - char *extra) -{ - strcpy(cwrq->name, "IEEE 802.11-DS"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set frequency - */ -static int airo_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct airo_info *local = dev->ml_priv; - int rc = -EINPROGRESS; /* Call commit handler */ - - /* If setting by frequency, convert to a channel */ - if (fwrq->e == 1) { - int f = fwrq->m / 100000; - - /* Hack to fall through... */ - fwrq->e = 0; - fwrq->m = ieee80211_frequency_to_channel(f); - } - /* Setting by channel number */ - if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0) - rc = -EOPNOTSUPP; - else { - int channel = fwrq->m; - /* We should do a better check than that, - * based on the card capability !!! */ - if ((channel < 1) || (channel > 14)) { - airo_print_dbg(dev->name, "New channel value of %d is invalid!", - fwrq->m); - rc = -EINVAL; - } else { - readConfigRid(local, 1); - /* Yes ! We can set it !!! */ - local->config.channelSet = cpu_to_le16(channel); - set_bit (FLAG_COMMIT, &local->flags); - } - } - return rc; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get frequency - */ -static int airo_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *fwrq = &wrqu->freq; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - int ch; - - readConfigRid(local, 1); - if ((local->config.opmode & MODE_CFG_MASK) == MODE_STA_ESS) - status_rid.channel = local->config.channelSet; - else - readStatusRid(local, &status_rid, 1); - - ch = le16_to_cpu(status_rid.channel); - if ((ch > 0) && (ch < 15)) { - fwrq->m = 100000 * - ieee80211_channel_to_frequency(ch, NL80211_BAND_2GHZ); - fwrq->e = 1; - } else { - fwrq->m = ch; - fwrq->e = 0; - } - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set ESSID - */ -static int airo_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct airo_info *local = dev->ml_priv; - SsidRid SSID_rid; /* SSIDs */ - - /* Reload the list of current SSID */ - readSsidRid(local, &SSID_rid); - - /* Check if we asked for `any' */ - if (dwrq->flags == 0) { - /* Just send an empty SSID list */ - memset(&SSID_rid, 0, sizeof(SSID_rid)); - } else { - unsigned index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - - /* Check the size of the string */ - if (dwrq->length > IW_ESSID_MAX_SIZE) - return -E2BIG ; - - /* Check if index is valid */ - if (index >= ARRAY_SIZE(SSID_rid.ssids)) - return -EINVAL; - - /* Set the SSID */ - memset(SSID_rid.ssids[index].ssid, 0, - sizeof(SSID_rid.ssids[index].ssid)); - memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length); - SSID_rid.ssids[index].len = cpu_to_le16(dwrq->length); - } - SSID_rid.len = cpu_to_le16(sizeof(SSID_rid)); - /* Write it to the card */ - disable_MAC(local, 1); - writeSsidRid(local, &SSID_rid, 1); - enable_MAC(local, 1); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get ESSID - */ -static int airo_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->essid; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - - readStatusRid(local, &status_rid, 1); - - /* Note : if dwrq->flags != 0, we should - * get the relevant SSID from the SSID list... */ - - /* Get the current SSID */ - memcpy(extra, status_rid.SSID, le16_to_cpu(status_rid.SSIDlen)); - /* If none, we may want to get the one that was set */ - - /* Push it out ! */ - dwrq->length = le16_to_cpu(status_rid.SSIDlen); - dwrq->flags = 1; /* active */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set AP address - */ -static int airo_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct airo_info *local = dev->ml_priv; - Cmd cmd; - Resp rsp; - APListRid *APList_rid = &local->APList; - - if (awrq->sa_family != ARPHRD_ETHER) - return -EINVAL; - else if (is_broadcast_ether_addr(awrq->sa_data) || - is_zero_ether_addr(awrq->sa_data)) { - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LOSE_SYNC; - if (down_interruptible(&local->sem)) - return -ERESTARTSYS; - issuecommand(local, &cmd, &rsp, true); - up(&local->sem); - } else { - memset(APList_rid, 0, sizeof(*APList_rid)); - APList_rid->len = cpu_to_le16(sizeof(*APList_rid)); - memcpy(APList_rid->ap[0], awrq->sa_data, ETH_ALEN); - disable_MAC(local, 1); - writeAPListRid(local, APList_rid, 1); - enable_MAC(local, 1); - } - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get AP address - */ -static int airo_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *awrq = &wrqu->ap_addr; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - - readStatusRid(local, &status_rid, 1); - - /* Tentative. This seems to work, wow, I'm lucky !!! */ - memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN); - awrq->sa_family = ARPHRD_ETHER; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Nickname - */ -static int airo_set_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - - /* Check the size of the string */ - if (dwrq->length > 16) { - return -E2BIG; - } - readConfigRid(local, 1); - memset(local->config.nodeName, 0, sizeof(local->config.nodeName)); - memcpy(local->config.nodeName, extra, dwrq->length); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Nickname - */ -static int airo_get_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - strncpy(extra, local->config.nodeName, 16); - extra[16] = '\0'; - dwrq->length = strlen(extra); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Bit-Rate - */ -static int airo_set_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct airo_info *local = dev->ml_priv; - CapabilityRid cap_rid; /* Card capability info */ - u8 brate = 0; - int i; - - /* First : get a valid bit rate value */ - readCapabilityRid(local, &cap_rid, 1); - - /* Which type of value ? */ - if ((vwrq->value < 8) && (vwrq->value >= 0)) { - /* Setting by rate index */ - /* Find value in the magic rate table */ - brate = cap_rid.supportedRates[vwrq->value]; - } else { - /* Setting by frequency value */ - u8 normvalue = (u8) (vwrq->value/500000); - - /* Check if rate is valid */ - for (i = 0 ; i < 8 ; i++) { - if (normvalue == cap_rid.supportedRates[i]) { - brate = normvalue; - break; - } - } - } - /* -1 designed the max rate (mostly auto mode) */ - if (vwrq->value == -1) { - /* Get the highest available rate */ - for (i = 0 ; i < 8 ; i++) { - if (cap_rid.supportedRates[i] == 0) - break; - } - if (i != 0) - brate = cap_rid.supportedRates[i - 1]; - } - /* Check that it is valid */ - if (brate == 0) { - return -EINVAL; - } - - readConfigRid(local, 1); - /* Now, check if we want a fixed or auto value */ - if (vwrq->fixed == 0) { - /* Fill all the rates up to this max rate */ - memset(local->config.rates, 0, 8); - for (i = 0 ; i < 8 ; i++) { - local->config.rates[i] = cap_rid.supportedRates[i]; - if (local->config.rates[i] == brate) - break; - } - } else { - /* Fixed mode */ - /* One rate, fixed */ - memset(local->config.rates, 0, 8); - local->config.rates[0] = brate; - } - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Bit-Rate - */ -static int airo_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->bitrate; - struct airo_info *local = dev->ml_priv; - StatusRid status_rid; /* Card status info */ - int ret; - - ret = readStatusRid(local, &status_rid, 1); - if (ret) - return -EBUSY; - - vwrq->value = le16_to_cpu(status_rid.currentXmitRate) * 500000; - /* If more than one rate, set auto */ - readConfigRid(local, 1); - vwrq->fixed = (local->config.rates[1] == 0); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set RTS threshold - */ -static int airo_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct airo_info *local = dev->ml_priv; - int rthr = vwrq->value; - - if (vwrq->disabled) - rthr = AIRO_DEF_MTU; - if ((rthr < 0) || (rthr > AIRO_DEF_MTU)) { - return -EINVAL; - } - readConfigRid(local, 1); - local->config.rtsThres = cpu_to_le16(rthr); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get RTS threshold - */ -static int airo_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->rts; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.rtsThres); - vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); - vwrq->fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Fragmentation threshold - */ -static int airo_set_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct airo_info *local = dev->ml_priv; - int fthr = vwrq->value; - - if (vwrq->disabled) - fthr = AIRO_DEF_MTU; - if ((fthr < 256) || (fthr > AIRO_DEF_MTU)) { - return -EINVAL; - } - fthr &= ~0x1; /* Get an even value - is it really needed ??? */ - readConfigRid(local, 1); - local->config.fragThresh = cpu_to_le16(fthr); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Fragmentation threshold - */ -static int airo_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->frag; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.fragThresh); - vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); - vwrq->fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Mode of Operation - */ -static int airo_set_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *uwrq, - char *extra) -{ - __u32 mode = uwrq->mode; - struct airo_info *local = dev->ml_priv; - int reset = 0; - - readConfigRid(local, 1); - if (sniffing_mode(local)) - reset = 1; - - switch (mode) { - case IW_MODE_ADHOC: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_STA_IBSS; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_INFRA: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_STA_ESS; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_MASTER: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_AP; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_REPEAT: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_AP_RPTR; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.scanMode = SCANMODE_ACTIVE; - clear_bit (FLAG_802_11, &local->flags); - break; - case IW_MODE_MONITOR: - local->config.opmode &= ~MODE_CFG_MASK; - local->config.opmode |= MODE_STA_ESS; - local->config.rmode &= ~RXMODE_FULL_MASK; - local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; - local->config.scanMode = SCANMODE_PASSIVE; - set_bit (FLAG_802_11, &local->flags); - break; - default: - return -EINVAL; - } - if (reset) - set_bit (FLAG_RESET, &local->flags); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Mode of Operation - */ -static int airo_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *uwrq, - char *extra) -{ - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - /* If not managed, assume it's ad-hoc */ - switch (local->config.opmode & MODE_CFG_MASK) { - case MODE_STA_ESS: - uwrq->mode = IW_MODE_INFRA; - break; - case MODE_AP: - uwrq->mode = IW_MODE_MASTER; - break; - case MODE_AP_RPTR: - uwrq->mode = IW_MODE_REPEAT; - break; - default: - uwrq->mode = IW_MODE_ADHOC; - } - - return 0; -} - -static inline int valid_index(struct airo_info *ai, int index) -{ - return (index >= 0) && (index <= ai->max_wep_idx); -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Encryption Key - */ -static int airo_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct airo_info *local = dev->ml_priv; - int perm = (dwrq->flags & IW_ENCODE_TEMP ? 0 : 1); - __le16 currentAuthType = local->config.authType; - int rc = 0; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - /* Basic checking: do we have a key to set ? - * Note : with the new API, it's impossible to get a NULL pointer. - * Therefore, we need to check a key size == 0 instead. - * New version of iwconfig properly set the IW_ENCODE_NOKEY flag - * when no key is present (only change flags), but older versions - * don't do it. - Jean II */ - if (dwrq->length > 0) { - wep_key_t key; - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - int current_index; - - /* Check the size of the key */ - if (dwrq->length > MAX_KEY_SIZE) { - return -EINVAL; - } - - current_index = get_wep_tx_idx(local); - if (current_index < 0) - current_index = 0; - - /* Check the index (none -> use current) */ - if (!valid_index(local, index)) - index = current_index; - - /* Set the length */ - if (dwrq->length > MIN_KEY_SIZE) - key.len = MAX_KEY_SIZE; - else - key.len = MIN_KEY_SIZE; - /* Check if the key is not marked as invalid */ - if (!(dwrq->flags & IW_ENCODE_NOKEY)) { - /* Cleanup */ - memset(key.key, 0, MAX_KEY_SIZE); - /* Copy the key in the driver */ - memcpy(key.key, extra, dwrq->length); - /* Send the key to the card */ - rc = set_wep_key(local, index, key.key, key.len, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, "failed to set" - " WEP key at index %d: %d.", - index, rc); - return rc; - } - } - /* WE specify that if a valid key is set, encryption - * should be enabled (user may turn it off later) - * This is also how "iwconfig ethX key on" works */ - if ((index == current_index) && (key.len > 0) && - (local->config.authType == AUTH_OPEN)) - set_auth_type(local, AUTH_ENCRYPT); - } else { - /* Do we want to just set the transmit key index ? */ - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - if (valid_index(local, index)) { - rc = set_wep_tx_idx(local, index, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, "failed to set" - " WEP transmit index to %d: %d.", - index, rc); - return rc; - } - } else { - /* Don't complain if only change the mode */ - if (!(dwrq->flags & IW_ENCODE_MODE)) - return -EINVAL; - } - } - /* Read the flags */ - if (dwrq->flags & IW_ENCODE_DISABLED) - set_auth_type(local, AUTH_OPEN); /* disable encryption */ - if (dwrq->flags & IW_ENCODE_RESTRICTED) - set_auth_type(local, AUTH_SHAREDKEY); /* Only Both */ - if (dwrq->flags & IW_ENCODE_OPEN) - set_auth_type(local, AUTH_ENCRYPT); /* Only Wep */ - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Encryption Key - */ -static int airo_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->encoding; - struct airo_info *local = dev->ml_priv; - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - int wep_key_len; - u8 buf[16]; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - /* Check encryption mode */ - switch(local->config.authType) { - case AUTH_ENCRYPT: - dwrq->flags = IW_ENCODE_OPEN; - break; - case AUTH_SHAREDKEY: - dwrq->flags = IW_ENCODE_RESTRICTED; - break; - default: - case AUTH_OPEN: - dwrq->flags = IW_ENCODE_DISABLED; - break; - } - /* We can't return the key, so set the proper flag and return zero */ - dwrq->flags |= IW_ENCODE_NOKEY; - memset(extra, 0, 16); - - /* Which key do we want ? -1 -> tx index */ - if (!valid_index(local, index)) { - index = get_wep_tx_idx(local); - if (index < 0) - index = 0; - } - dwrq->flags |= index + 1; - - /* Copy the key to the user buffer */ - wep_key_len = get_wep_key(local, index, &buf[0], sizeof(buf)); - if (wep_key_len < 0) { - dwrq->length = 0; - } else { - dwrq->length = wep_key_len; - memcpy(extra, buf, dwrq->length); - } - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set extended Encryption parameters - */ -static int airo_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int perm = (encoding->flags & IW_ENCODE_TEMP ? 0 : 1); - __le16 currentAuthType = local->config.authType; - int idx, key_len, alg = ext->alg, set_key = 1, rc; - wep_key_t key; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - /* Determine and validate the key index */ - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (!valid_index(local, idx - 1)) - return -EINVAL; - idx--; - } else { - idx = get_wep_tx_idx(local); - if (idx < 0) - idx = 0; - } - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - /* Only set transmit key index here, actual - * key is set below if needed. - */ - rc = set_wep_tx_idx(local, idx, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, "failed to set " - "WEP transmit index to %d: %d.", - idx, rc); - return rc; - } - set_key = ext->key_len > 0 ? 1 : 0; - } - - if (set_key) { - /* Set the requested key first */ - memset(key.key, 0, MAX_KEY_SIZE); - switch (alg) { - case IW_ENCODE_ALG_NONE: - key.len = 0; - break; - case IW_ENCODE_ALG_WEP: - if (ext->key_len > MIN_KEY_SIZE) { - key.len = MAX_KEY_SIZE; - } else if (ext->key_len > 0) { - key.len = MIN_KEY_SIZE; - } else { - return -EINVAL; - } - key_len = min (ext->key_len, key.len); - memcpy(key.key, ext->key, key_len); - break; - default: - return -EINVAL; - } - if (key.len == 0) { - rc = set_wep_tx_idx(local, idx, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, - "failed to set WEP transmit index to %d: %d.", - idx, rc); - return rc; - } - } else { - rc = set_wep_key(local, idx, key.key, key.len, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, - "failed to set WEP key at index %d: %d.", - idx, rc); - return rc; - } - } - } - - /* Read the flags */ - if (encoding->flags & IW_ENCODE_DISABLED) - set_auth_type(local, AUTH_OPEN); /* disable encryption */ - if (encoding->flags & IW_ENCODE_RESTRICTED) - set_auth_type(local, AUTH_SHAREDKEY); /* Only Both */ - if (encoding->flags & IW_ENCODE_OPEN) - set_auth_type(local, AUTH_ENCRYPT); - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get extended Encryption parameters - */ -static int airo_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len, wep_key_len; - u8 buf[16]; - - if (!local->wep_capable) - return -EOPNOTSUPP; - - readConfigRid(local, 1); - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (!valid_index(local, idx - 1)) - return -EINVAL; - idx--; - } else { - idx = get_wep_tx_idx(local); - if (idx < 0) - idx = 0; - } - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - /* Check encryption mode */ - switch(local->config.authType) { - case AUTH_ENCRYPT: - encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED; - break; - case AUTH_SHAREDKEY: - encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED; - break; - default: - case AUTH_OPEN: - encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED; - break; - } - /* We can't return the key, so set the proper flag and return zero */ - encoding->flags |= IW_ENCODE_NOKEY; - memset(extra, 0, 16); - - /* Copy the key to the user buffer */ - wep_key_len = get_wep_key(local, idx, &buf[0], sizeof(buf)); - if (wep_key_len < 0) { - ext->key_len = 0; - } else { - ext->key_len = wep_key_len; - memcpy(extra, buf, ext->key_len); - } - - return 0; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set extended authentication parameters - */ -static int airo_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_param *param = &wrqu->param; - __le16 currentAuthType = local->config.authType; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_PRIVACY_INVOKED: - /* - * airo does not use these parameters - */ - break; - - case IW_AUTH_DROP_UNENCRYPTED: - if (param->value) { - /* Only change auth type if unencrypted */ - if (currentAuthType == AUTH_OPEN) - set_auth_type(local, AUTH_ENCRYPT); - } else { - set_auth_type(local, AUTH_OPEN); - } - - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - break; - - case IW_AUTH_80211_AUTH_ALG: { - if (param->value & IW_AUTH_ALG_SHARED_KEY) { - set_auth_type(local, AUTH_SHAREDKEY); - } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { - /* We don't know here if WEP open system or - * unencrypted mode was requested - so use the - * last mode (of these two) used last time - */ - set_auth_type(local, local->last_auth); - } else - return -EINVAL; - - /* Commit the changes to flags if needed */ - if (local->config.authType != currentAuthType) - set_bit (FLAG_COMMIT, &local->flags); - break; - } - - case IW_AUTH_WPA_ENABLED: - /* Silently accept disable of WPA */ - if (param->value > 0) - return -EOPNOTSUPP; - break; - - default: - return -EOPNOTSUPP; - } - return -EINPROGRESS; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get extended authentication parameters - */ -static int airo_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct airo_info *local = dev->ml_priv; - struct iw_param *param = &wrqu->param; - __le16 currentAuthType = local->config.authType; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_DROP_UNENCRYPTED: - switch (currentAuthType) { - case AUTH_SHAREDKEY: - case AUTH_ENCRYPT: - param->value = 1; - break; - default: - param->value = 0; - break; - } - break; - - case IW_AUTH_80211_AUTH_ALG: - switch (currentAuthType) { - case AUTH_SHAREDKEY: - param->value = IW_AUTH_ALG_SHARED_KEY; - break; - case AUTH_ENCRYPT: - default: - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - } - break; - - case IW_AUTH_WPA_ENABLED: - param->value = 0; - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Tx-Power - */ -static int airo_set_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->txpower; - struct airo_info *local = dev->ml_priv; - CapabilityRid cap_rid; /* Card capability info */ - int i; - int rc = -EINVAL; - __le16 v = cpu_to_le16(vwrq->value); - - readCapabilityRid(local, &cap_rid, 1); - - if (vwrq->disabled) { - set_bit (FLAG_RADIO_OFF, &local->flags); - set_bit (FLAG_COMMIT, &local->flags); - return -EINPROGRESS; /* Call commit handler */ - } - if (vwrq->flags != IW_TXPOW_MWATT) { - return -EINVAL; - } - clear_bit (FLAG_RADIO_OFF, &local->flags); - for (i = 0; i < 8 && cap_rid.txPowerLevels[i]; i++) - if (v == cap_rid.txPowerLevels[i]) { - readConfigRid(local, 1); - local->config.txPower = v; - set_bit (FLAG_COMMIT, &local->flags); - rc = -EINPROGRESS; /* Call commit handler */ - break; - } - return rc; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Tx-Power - */ -static int airo_get_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->txpower; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.txPower); - vwrq->fixed = 1; /* No power control */ - vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags); - vwrq->flags = IW_TXPOW_MWATT; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Retry limits - */ -static int airo_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct airo_info *local = dev->ml_priv; - int rc = -EINVAL; - - if (vwrq->disabled) { - return -EINVAL; - } - readConfigRid(local, 1); - if (vwrq->flags & IW_RETRY_LIMIT) { - __le16 v = cpu_to_le16(vwrq->value); - if (vwrq->flags & IW_RETRY_LONG) - local->config.longRetryLimit = v; - else if (vwrq->flags & IW_RETRY_SHORT) - local->config.shortRetryLimit = v; - else { - /* No modifier : set both */ - local->config.longRetryLimit = v; - local->config.shortRetryLimit = v; - } - set_bit (FLAG_COMMIT, &local->flags); - rc = -EINPROGRESS; /* Call commit handler */ - } - if (vwrq->flags & IW_RETRY_LIFETIME) { - local->config.txLifetime = cpu_to_le16(vwrq->value / 1024); - set_bit (FLAG_COMMIT, &local->flags); - rc = -EINPROGRESS; /* Call commit handler */ - } - return rc; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Retry limits - */ -static int airo_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->retry; - struct airo_info *local = dev->ml_priv; - - vwrq->disabled = 0; /* Can't be disabled */ - - readConfigRid(local, 1); - /* Note : by default, display the min retry number */ - if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - vwrq->flags = IW_RETRY_LIFETIME; - vwrq->value = le16_to_cpu(local->config.txLifetime) * 1024; - } else if ((vwrq->flags & IW_RETRY_LONG)) { - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - vwrq->value = le16_to_cpu(local->config.longRetryLimit); - } else { - vwrq->flags = IW_RETRY_LIMIT; - vwrq->value = le16_to_cpu(local->config.shortRetryLimit); - if (local->config.shortRetryLimit != local->config.longRetryLimit) - vwrq->flags |= IW_RETRY_SHORT; - } - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get range info - */ -static int airo_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - struct iw_range *range = (struct iw_range *) extra; - CapabilityRid cap_rid; /* Card capability info */ - int i; - int k; - - readCapabilityRid(local, &cap_rid, 1); - - dwrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(*range)); - range->min_nwid = 0x0000; - range->max_nwid = 0x0000; - range->num_channels = 14; - /* Should be based on cap_rid.country to give only - * what the current card support */ - k = 0; - for (i = 0; i < 14; i++) { - range->freq[k].i = i + 1; /* List index */ - range->freq[k].m = 100000 * - ieee80211_channel_to_frequency(i + 1, NL80211_BAND_2GHZ); - range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */ - } - range->num_frequency = k; - - range->sensitivity = 65535; - - /* Hum... Should put the right values there */ - if (local->rssi) - range->max_qual.qual = 100; /* % */ - else - range->max_qual.qual = airo_get_max_quality(&cap_rid); - range->max_qual.level = 0x100 - 120; /* -120 dBm */ - range->max_qual.noise = 0x100 - 120; /* -120 dBm */ - - /* Experimental measurements - boundary 11/5.5 Mb/s */ - /* Note : with or without the (local->rssi), results - * are somewhat different. - Jean II */ - if (local->rssi) { - range->avg_qual.qual = 50; /* % */ - range->avg_qual.level = 0x100 - 70; /* -70 dBm */ - } else { - range->avg_qual.qual = airo_get_avg_quality(&cap_rid); - range->avg_qual.level = 0x100 - 80; /* -80 dBm */ - } - range->avg_qual.noise = 0x100 - 85; /* -85 dBm */ - - for (i = 0 ; i < 8 ; i++) { - range->bitrate[i] = cap_rid.supportedRates[i] * 500000; - if (range->bitrate[i] == 0) - break; - } - range->num_bitrates = i; - - /* Set an indication of the max TCP throughput - * in bit/s that we can expect using this interface. - * May be use for QoS stuff... Jean II */ - if (i > 2) - range->throughput = 5000 * 1000; - else - range->throughput = 1500 * 1000; - - range->min_rts = 0; - range->max_rts = AIRO_DEF_MTU; - range->min_frag = 256; - range->max_frag = AIRO_DEF_MTU; - - if (cap_rid.softCap & cpu_to_le16(2)) { - // WEP: RC4 40 bits - range->encoding_size[0] = 5; - // RC4 ~128 bits - if (cap_rid.softCap & cpu_to_le16(0x100)) { - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - } else - range->num_encoding_sizes = 1; - range->max_encoding_tokens = - cap_rid.softCap & cpu_to_le16(0x80) ? 4 : 1; - } else { - range->num_encoding_sizes = 0; - range->max_encoding_tokens = 0; - } - range->min_pmp = 0; - range->max_pmp = 5000000; /* 5 secs */ - range->min_pmt = 0; - range->max_pmt = 65535 * 1024; /* ??? */ - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; - - /* Transmit Power - values are in mW */ - for (i = 0 ; i < 8 ; i++) { - range->txpower[i] = le16_to_cpu(cap_rid.txPowerLevels[i]); - if (range->txpower[i] == 0) - break; - } - range->num_txpower = i; - range->txpower_capa = IW_TXPOW_MWATT; - range->we_version_source = 19; - range->we_version_compiled = WIRELESS_EXT; - range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; - range->retry_flags = IW_RETRY_LIMIT; - range->r_time_flags = IW_RETRY_LIFETIME; - range->min_retry = 1; - range->max_retry = 65535; - range->min_r_time = 1024; - range->max_r_time = 65535 * 1024; - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | - IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | - IW_EVENT_CAPA_MASK(SIOCGIWAP) | - IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Power Management - */ -static int airo_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - if (vwrq->disabled) { - if (sniffing_mode(local)) - return -EINVAL; - local->config.powerSaveMode = POWERSAVE_CAM; - local->config.rmode &= ~RXMODE_MASK; - local->config.rmode |= RXMODE_BC_MC_ADDR; - set_bit (FLAG_COMMIT, &local->flags); - return -EINPROGRESS; /* Call commit handler */ - } - if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - local->config.fastListenDelay = cpu_to_le16((vwrq->value + 500) / 1024); - local->config.powerSaveMode = POWERSAVE_PSPCAM; - set_bit (FLAG_COMMIT, &local->flags); - } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { - local->config.fastListenInterval = - local->config.listenInterval = - cpu_to_le16((vwrq->value + 500) / 1024); - local->config.powerSaveMode = POWERSAVE_PSPCAM; - set_bit (FLAG_COMMIT, &local->flags); - } - switch (vwrq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - if (sniffing_mode(local)) - return -EINVAL; - local->config.rmode &= ~RXMODE_MASK; - local->config.rmode |= RXMODE_ADDR; - set_bit (FLAG_COMMIT, &local->flags); - break; - case IW_POWER_ALL_R: - if (sniffing_mode(local)) - return -EINVAL; - local->config.rmode &= ~RXMODE_MASK; - local->config.rmode |= RXMODE_BC_MC_ADDR; - set_bit (FLAG_COMMIT, &local->flags); - break; - case IW_POWER_ON: - /* This is broken, fixme ;-) */ - break; - default: - return -EINVAL; - } - // Note : we may want to factor local->need_commit here - // Note2 : may also want to factor RXMODE_RFMON test - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Power Management - */ -static int airo_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct airo_info *local = dev->ml_priv; - __le16 mode; - - readConfigRid(local, 1); - mode = local->config.powerSaveMode; - if ((vwrq->disabled = (mode == POWERSAVE_CAM))) - return 0; - if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - vwrq->value = le16_to_cpu(local->config.fastListenDelay) * 1024; - vwrq->flags = IW_POWER_TIMEOUT; - } else { - vwrq->value = le16_to_cpu(local->config.fastListenInterval) * 1024; - vwrq->flags = IW_POWER_PERIOD; - } - if ((local->config.rmode & RXMODE_MASK) == RXMODE_ADDR) - vwrq->flags |= IW_POWER_UNICAST_R; - else - vwrq->flags |= IW_POWER_ALL_R; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Sensitivity - */ -static int airo_set_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->sens; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - local->config.rssiThreshold = - cpu_to_le16(vwrq->disabled ? RSSI_DEFAULT : vwrq->value); - set_bit (FLAG_COMMIT, &local->flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Sensitivity - */ -static int airo_get_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *vwrq = &wrqu->sens; - struct airo_info *local = dev->ml_priv; - - readConfigRid(local, 1); - vwrq->value = le16_to_cpu(local->config.rssiThreshold); - vwrq->disabled = (vwrq->value == 0); - vwrq->fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get AP List - * Note : this is deprecated in favor of IWSCAN - */ -static int airo_get_aplist(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *local = dev->ml_priv; - struct sockaddr *address = (struct sockaddr *) extra; - struct iw_quality *qual; - BSSListRid BSSList; - int i; - int loseSync = capable(CAP_NET_ADMIN) ? 1: -1; - - qual = kmalloc_array(IW_MAX_AP, sizeof(*qual), GFP_KERNEL); - if (!qual) - return -ENOMEM; - - for (i = 0; i < IW_MAX_AP; i++) { - u16 dBm; - if (readBSSListRid(local, loseSync, &BSSList)) - break; - loseSync = 0; - memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN); - address[i].sa_family = ARPHRD_ETHER; - dBm = le16_to_cpu(BSSList.dBm); - if (local->rssi) { - qual[i].level = 0x100 - dBm; - qual[i].qual = airo_dbm_to_pct(local->rssi, dBm); - qual[i].updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } else { - qual[i].level = (dBm + 321) / 2; - qual[i].qual = 0; - qual[i].updated = IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } - qual[i].noise = local->wstats.qual.noise; - if (BSSList.index == cpu_to_le16(0xffff)) - break; - } - if (!i) { - StatusRid status_rid; /* Card status info */ - readStatusRid(local, &status_rid, 1); - for (i = 0; - i < min(IW_MAX_AP, 4) && - (status_rid.bssid[i][0] - & status_rid.bssid[i][1] - & status_rid.bssid[i][2] - & status_rid.bssid[i][3] - & status_rid.bssid[i][4] - & status_rid.bssid[i][5])!=0xff && - (status_rid.bssid[i][0] - | status_rid.bssid[i][1] - | status_rid.bssid[i][2] - | status_rid.bssid[i][3] - | status_rid.bssid[i][4] - | status_rid.bssid[i][5]); - i++) { - memcpy(address[i].sa_data, - status_rid.bssid[i], ETH_ALEN); - address[i].sa_family = ARPHRD_ETHER; - } - } else { - dwrq->flags = 1; /* Should be define'd */ - memcpy(extra + sizeof(struct sockaddr) * i, qual, - sizeof(struct iw_quality) * i); - } - dwrq->length = i; - - kfree(qual); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : Initiate Scan - */ -static int airo_set_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct airo_info *ai = dev->ml_priv; - Cmd cmd; - Resp rsp; - int wake = 0; - APListRid APList_rid_empty; - - /* Note : you may have realised that, as this is a SET operation, - * this is privileged and therefore a normal user can't - * perform scanning. - * This is not an error, while the device perform scanning, - * traffic doesn't flow, so it's a perfect DoS... - * Jean II */ - if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; - - if (down_interruptible(&ai->sem)) - return -ERESTARTSYS; - - /* If there's already a scan in progress, don't - * trigger another one. */ - if (ai->scan_timeout > 0) - goto out; - - /* Clear APList as it affects scan results */ - memset(&APList_rid_empty, 0, sizeof(APList_rid_empty)); - APList_rid_empty.len = cpu_to_le16(sizeof(APList_rid_empty)); - disable_MAC(ai, 2); - writeAPListRid(ai, &APList_rid_empty, 0); - enable_MAC(ai, 0); - - /* Initiate a scan command */ - ai->scan_timeout = RUN_AT(3*HZ); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = CMD_LISTBSS; - issuecommand(ai, &cmd, &rsp, true); - wake = 1; - -out: - up(&ai->sem); - if (wake) - wake_up_interruptible(&ai->thr_wait); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Translate scan data returned from the card to a card independent - * format that the Wireless Tools will understand - Jean II - */ -static inline char *airo_translate_scan(struct net_device *dev, - struct iw_request_info *info, - char *current_ev, - char *end_buf, - BSSListRid *bss) -{ - struct airo_info *ai = dev->ml_priv; - struct iw_event iwe; /* Temporary buffer */ - __le16 capabilities; - char * current_val; /* For rates */ - int i; - char * buf; - u16 dBm; - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - /* Add the ESSID */ - iwe.u.data.length = bss->ssidLen; - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->ssid); - - /* Add mode */ - iwe.cmd = SIOCGIWMODE; - capabilities = bss->cap; - if (capabilities & (CAP_ESS | CAP_IBSS)) { - if (capabilities & CAP_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - /* Add frequency */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = le16_to_cpu(bss->dsChannel); - iwe.u.freq.m = 100000 * - ieee80211_channel_to_frequency(iwe.u.freq.m, NL80211_BAND_2GHZ); - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - dBm = le16_to_cpu(bss->dBm); - - /* Add quality statistics */ - iwe.cmd = IWEVQUAL; - if (ai->rssi) { - iwe.u.qual.level = 0x100 - dBm; - iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm); - iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } else { - iwe.u.qual.level = (dBm + 321) / 2; - iwe.u.qual.qual = 0; - iwe.u.qual.updated = IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_DBM; - } - iwe.u.qual.noise = ai->wstats.qual.noise; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (capabilities & CAP_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->ssid); - - /* Rate : stuffing multiple values in a single event require a bit - * more of magic - Jean II */ - current_val = current_ev + iwe_stream_lcp_len(info); - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - /* Max 8 values */ - for (i = 0 ; i < 8 ; i++) { - /* NULL terminated */ - if (bss->rates[i] == 0) - break; - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000); - /* Add new value to event */ - current_val = iwe_stream_add_value(info, current_ev, - current_val, end_buf, - &iwe, IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - current_ev) > iwe_stream_lcp_len(info)) - current_ev = current_val; - - /* Beacon interval */ - buf = kmalloc(30, GFP_KERNEL); - if (buf) { - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "bcn_int=%d", bss->beaconInterval); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, buf); - kfree(buf); - } - - /* Put WPA/RSN Information Elements into the event stream */ - if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) { - unsigned int num_null_ies = 0; - u16 length = sizeof (bss->extra.iep); - u8 *ie = (void *)&bss->extra.iep; - - while ((length >= 2) && (num_null_ies < 2)) { - if (2 + ie[1] > length) { - /* Invalid element, don't continue parsing IE */ - break; - } - - switch (ie[0]) { - case WLAN_EID_SSID: - /* Two zero-length SSID elements - * mean we're done parsing elements */ - if (!ie[1]) - num_null_ies++; - break; - - case WLAN_EID_VENDOR_SPECIFIC: - if (ie[1] >= 4 && - ie[2] == 0x00 && - ie[3] == 0x50 && - ie[4] == 0xf2 && - ie[5] == 0x01) { - iwe.cmd = IWEVGENIE; - /* 64 is an arbitrary cut-off */ - iwe.u.data.length = min(ie[1] + 2, - 64); - current_ev = iwe_stream_add_point( - info, current_ev, - end_buf, &iwe, ie); - } - break; - - case WLAN_EID_RSN: - iwe.cmd = IWEVGENIE; - /* 64 is an arbitrary cut-off */ - iwe.u.data.length = min(ie[1] + 2, 64); - current_ev = iwe_stream_add_point( - info, current_ev, end_buf, - &iwe, ie); - break; - - default: - break; - } - - length -= 2 + ie[1]; - ie += 2 + ie[1]; - } - } - return current_ev; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : Read Scan Results - */ -static int airo_get_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *dwrq = &wrqu->data; - struct airo_info *ai = dev->ml_priv; - BSSListElement *net; - int err = 0; - char *current_ev = extra; - - /* If a scan is in-progress, return -EAGAIN */ - if (ai->scan_timeout > 0) - return -EAGAIN; - - if (down_interruptible(&ai->sem)) - return -EAGAIN; - - list_for_each_entry (net, &ai->network_list, list) { - /* Translate to WE format this entry */ - current_ev = airo_translate_scan(dev, info, current_ev, - extra + dwrq->length, - &net->bss); - - /* Check if there is space for one more entry */ - if ((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - err = -E2BIG; - goto out; - } - } - - /* Length of data */ - dwrq->length = (current_ev - extra); - dwrq->flags = 0; /* todo */ - -out: - up(&ai->sem); - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Commit handler : called after a bunch of SET operations - */ -static int airo_config_commit(struct net_device *dev, - struct iw_request_info *info, /* NULL */ - union iwreq_data *wrqu, /* NULL */ - char *extra) /* NULL */ -{ - struct airo_info *local = dev->ml_priv; - - if (!test_bit (FLAG_COMMIT, &local->flags)) - return 0; - - /* Some of the "SET" function may have modified some of the - * parameters. It's now time to commit them in the card */ - disable_MAC(local, 1); - if (test_bit (FLAG_RESET, &local->flags)) { - SsidRid SSID_rid; - - readSsidRid(local, &SSID_rid); - if (test_bit(FLAG_MPI,&local->flags)) - setup_card(local, dev, 1); - else - reset_airo_card(dev); - disable_MAC(local, 1); - writeSsidRid(local, &SSID_rid, 1); - writeAPListRid(local, &local->APList, 1); - } - if (down_interruptible(&local->sem)) - return -ERESTARTSYS; - writeConfigRid(local, 0); - enable_MAC(local, 0); - if (test_bit (FLAG_RESET, &local->flags)) - airo_set_promisc(local, true); - else - up(&local->sem); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Structures to export the Wireless Handlers - */ - -static const struct iw_priv_args airo_private_args[] = { -/*{ cmd, set_args, get_args, name } */ - { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), - IW_PRIV_TYPE_BYTE | 2047, "airoioctl" }, - { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" }, -}; - -static const iw_handler airo_handler[] = -{ - IW_HANDLER(SIOCSIWCOMMIT, airo_config_commit), - IW_HANDLER(SIOCGIWNAME, airo_get_name), - IW_HANDLER(SIOCSIWFREQ, airo_set_freq), - IW_HANDLER(SIOCGIWFREQ, airo_get_freq), - IW_HANDLER(SIOCSIWMODE, airo_set_mode), - IW_HANDLER(SIOCGIWMODE, airo_get_mode), - IW_HANDLER(SIOCSIWSENS, airo_set_sens), - IW_HANDLER(SIOCGIWSENS, airo_get_sens), - IW_HANDLER(SIOCGIWRANGE, airo_get_range), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, airo_set_wap), - IW_HANDLER(SIOCGIWAP, airo_get_wap), - IW_HANDLER(SIOCGIWAPLIST, airo_get_aplist), - IW_HANDLER(SIOCSIWSCAN, airo_set_scan), - IW_HANDLER(SIOCGIWSCAN, airo_get_scan), - IW_HANDLER(SIOCSIWESSID, airo_set_essid), - IW_HANDLER(SIOCGIWESSID, airo_get_essid), - IW_HANDLER(SIOCSIWNICKN, airo_set_nick), - IW_HANDLER(SIOCGIWNICKN, airo_get_nick), - IW_HANDLER(SIOCSIWRATE, airo_set_rate), - IW_HANDLER(SIOCGIWRATE, airo_get_rate), - IW_HANDLER(SIOCSIWRTS, airo_set_rts), - IW_HANDLER(SIOCGIWRTS, airo_get_rts), - IW_HANDLER(SIOCSIWFRAG, airo_set_frag), - IW_HANDLER(SIOCGIWFRAG, airo_get_frag), - IW_HANDLER(SIOCSIWTXPOW, airo_set_txpow), - IW_HANDLER(SIOCGIWTXPOW, airo_get_txpow), - IW_HANDLER(SIOCSIWRETRY, airo_set_retry), - IW_HANDLER(SIOCGIWRETRY, airo_get_retry), - IW_HANDLER(SIOCSIWENCODE, airo_set_encode), - IW_HANDLER(SIOCGIWENCODE, airo_get_encode), - IW_HANDLER(SIOCSIWPOWER, airo_set_power), - IW_HANDLER(SIOCGIWPOWER, airo_get_power), - IW_HANDLER(SIOCSIWAUTH, airo_set_auth), - IW_HANDLER(SIOCGIWAUTH, airo_get_auth), - IW_HANDLER(SIOCSIWENCODEEXT, airo_set_encodeext), - IW_HANDLER(SIOCGIWENCODEEXT, airo_get_encodeext), -}; - -/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here. - * We want to force the use of the ioctl code, because those can't be - * won't work the iw_handler code (because they simultaneously read - * and write data and iw_handler can't do that). - * Note that it's perfectly legal to read/write on a single ioctl command, - * you just can't use iwpriv and need to force it via the ioctl handler. - * Jean II */ -static const iw_handler airo_private_handler[] = -{ - NULL, /* SIOCIWFIRSTPRIV */ -}; - -static const struct iw_handler_def airo_handler_def = -{ - .num_standard = ARRAY_SIZE(airo_handler), - .num_private = ARRAY_SIZE(airo_private_handler), - .num_private_args = ARRAY_SIZE(airo_private_args), - .standard = airo_handler, - .private = airo_private_handler, - .private_args = airo_private_args, - .get_wireless_stats = airo_get_wireless_stats, -}; - -/* - * This defines the configuration part of the Wireless Extensions - * Note : irq and spinlock protection will occur in the subroutines - * - * TODO : - * o Check input value more carefully and fill correct values in range - * o Test and shakeout the bugs (if any) - * - * Jean II - * - * Javier Achirica did a great job of merging code from the unnamed CISCO - * developer that added support for flashing the card. - */ -static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, - void __user *data, int cmd) -{ - int rc = 0; - struct airo_info *ai = dev->ml_priv; - - if (ai->power.event) - return 0; - - switch (cmd) { -#ifdef CISCO_EXT - case AIROIDIFC: -#ifdef AIROOLDIDIFC - case AIROOLDIDIFC: -#endif - { - int val = AIROMAGIC; - aironet_ioctl com; - if (copy_from_user(&com, data, sizeof(com))) - rc = -EFAULT; - else if (copy_to_user(com.data, (char *)&val, sizeof(val))) - rc = -EFAULT; - } - break; - - case AIROIOCTL: -#ifdef AIROOLDIOCTL - case AIROOLDIOCTL: -#endif - /* Get the command struct and hand it off for evaluation by - * the proper subfunction - */ - { - aironet_ioctl com; - if (copy_from_user(&com, data, sizeof(com))) { - rc = -EFAULT; - break; - } - - /* Separate R/W functions bracket legality here - */ - if (com.command == AIRORSWVERSION) { - if (copy_to_user(com.data, swversion, sizeof(swversion))) - rc = -EFAULT; - else - rc = 0; - } - else if (com.command <= AIRORRID) - rc = readrids(dev,&com); - else if (com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2)) - rc = writerids(dev,&com); - else if (com.command >= AIROFLSHRST && com.command <= AIRORESTART) - rc = flashcard(dev,&com); - else - rc = -EINVAL; /* Bad command in ioctl */ - } - break; -#endif /* CISCO_EXT */ - - // All other calls are currently unsupported - default: - rc = -EOPNOTSUPP; - } - return rc; -} - -/* - * Get the Wireless stats out of the driver - * Note : irq and spinlock protection will occur in the subroutines - * - * TODO : - * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs) - * - * Jean - */ -static void airo_read_wireless_stats(struct airo_info *local) -{ - StatusRid status_rid; - StatsRid stats_rid; - CapabilityRid cap_rid; - __le32 *vals = stats_rid.vals; - - /* Get stats out of the card */ - if (local->power.event) - return; - - readCapabilityRid(local, &cap_rid, 0); - readStatusRid(local, &status_rid, 0); - readStatsRid(local, &stats_rid, RID_STATS, 0); - - /* The status */ - local->wstats.status = le16_to_cpu(status_rid.mode); - - /* Signal quality and co */ - if (local->rssi) { - local->wstats.qual.level = - airo_rssi_to_dbm(local->rssi, - le16_to_cpu(status_rid.sigQuality)); - /* normalizedSignalStrength appears to be a percentage */ - local->wstats.qual.qual = - le16_to_cpu(status_rid.normalizedSignalStrength); - } else { - local->wstats.qual.level = - (le16_to_cpu(status_rid.normalizedSignalStrength) + 321) / 2; - local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid); - } - if (le16_to_cpu(status_rid.len) >= 124) { - local->wstats.qual.noise = 0x100 - status_rid.noisedBm; - local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - } else { - local->wstats.qual.noise = 0; - local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID | IW_QUAL_DBM; - } - - /* Packets discarded in the wireless adapter due to wireless - * specific problems */ - local->wstats.discard.nwid = le32_to_cpu(vals[56]) + - le32_to_cpu(vals[57]) + - le32_to_cpu(vals[58]); /* SSID Mismatch */ - local->wstats.discard.code = le32_to_cpu(vals[6]);/* RxWepErr */ - local->wstats.discard.fragment = le32_to_cpu(vals[30]); - local->wstats.discard.retries = le32_to_cpu(vals[10]); - local->wstats.discard.misc = le32_to_cpu(vals[1]) + - le32_to_cpu(vals[32]); - local->wstats.miss.beacon = le32_to_cpu(vals[34]); -} - -static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) -{ - struct airo_info *local = dev->ml_priv; - - if (!down_interruptible(&local->sem)) { - airo_read_wireless_stats(local); - up(&local->sem); - } - return &local->wstats; -} - -#ifdef CISCO_EXT -/* - * This just translates from driver IOCTL codes to the command codes to - * feed to the radio's host interface. Things can be added/deleted - * as needed. This represents the READ side of control I/O to - * the card - */ -static int readrids(struct net_device *dev, aironet_ioctl *comp) -{ - unsigned short ridcode; - unsigned char *iobuf; - int len; - struct airo_info *ai = dev->ml_priv; - - if (test_bit(FLAG_FLASHING, &ai->flags)) - return -EIO; - - switch(comp->command) - { - case AIROGCAP: ridcode = RID_CAPABILITIES; break; - case AIROGCFG: ridcode = RID_CONFIG; - if (test_bit(FLAG_COMMIT, &ai->flags)) { - disable_MAC (ai, 1); - writeConfigRid (ai, 1); - enable_MAC(ai, 1); - } - break; - case AIROGSLIST: ridcode = RID_SSID; break; - case AIROGVLIST: ridcode = RID_APLIST; break; - case AIROGDRVNAM: ridcode = RID_DRVNAME; break; - case AIROGEHTENC: ridcode = RID_ETHERENCAP; break; - case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; break; - case AIROGWEPKNV: ridcode = RID_WEP_PERM; break; - case AIROGSTAT: ridcode = RID_STATUS; break; - case AIROGSTATSD32: ridcode = RID_STATSDELTA; break; - case AIROGSTATSC32: ridcode = RID_STATS; break; - case AIROGMICSTATS: - if (copy_to_user(comp->data, &ai->micstats, - min((int)comp->len, (int)sizeof(ai->micstats)))) - return -EFAULT; - return 0; - case AIRORRID: ridcode = comp->ridnum; break; - default: - return -EINVAL; - } - - if (ridcode == RID_WEP_TEMP || ridcode == RID_WEP_PERM) { - /* Only super-user can read WEP keys */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - } - - if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - PC4500_readrid(ai, ridcode, iobuf, RIDSIZE, 1); - /* get the count of bytes in the rid docs say 1st 2 bytes is it. - * then return it to the user - * 9/22/2000 Honor user given length - */ - len = comp->len; - - if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) { - kfree (iobuf); - return -EFAULT; - } - kfree (iobuf); - return 0; -} - -/* - * Danger Will Robinson write the rids here - */ - -static int writerids(struct net_device *dev, aironet_ioctl *comp) -{ - struct airo_info *ai = dev->ml_priv; - int ridcode; - int enabled; - int (*writer)(struct airo_info *, u16 rid, const void *, int, int); - unsigned char *iobuf; - - /* Only super-user can write RIDs */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (test_bit(FLAG_FLASHING, &ai->flags)) - return -EIO; - - ridcode = 0; - writer = do_writerid; - - switch(comp->command) - { - case AIROPSIDS: ridcode = RID_SSID; break; - case AIROPCAP: ridcode = RID_CAPABILITIES; break; - case AIROPAPLIST: ridcode = RID_APLIST; break; - case AIROPCFG: ai->config.len = 0; - clear_bit(FLAG_COMMIT, &ai->flags); - ridcode = RID_CONFIG; break; - case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break; - case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break; - case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break; - case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid; - break; - case AIROPLEAPUSR+1: ridcode = 0xFF2A; break; - case AIROPLEAPUSR+2: ridcode = 0xFF2B; break; - - /* this is not really a rid but a command given to the card - * same with MAC off - */ - case AIROPMACON: - if (enable_MAC(ai, 1) != 0) - return -EIO; - return 0; - - /* - * Evidently this code in the airo driver does not get a symbol - * as disable_MAC. it's probably so short the compiler does not gen one. - */ - case AIROPMACOFF: - disable_MAC(ai, 1); - return 0; - - /* This command merely clears the counts does not actually store any data - * only reads rid. But as it changes the cards state, I put it in the - * writerid routines. - */ - case AIROPSTCLR: - if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - PC4500_readrid(ai, RID_STATSDELTACLEAR, iobuf, RIDSIZE, 1); - - enabled = ai->micstats.enabled; - memset(&ai->micstats, 0, sizeof(ai->micstats)); - ai->micstats.enabled = enabled; - - if (copy_to_user(comp->data, iobuf, - min((int)comp->len, (int)RIDSIZE))) { - kfree (iobuf); - return -EFAULT; - } - kfree (iobuf); - return 0; - - default: - return -EOPNOTSUPP; /* Blarg! */ - } - if (comp->len > RIDSIZE) - return -EINVAL; - - if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - if (copy_from_user(iobuf, comp->data, comp->len)) { - kfree (iobuf); - return -EFAULT; - } - - if (comp->command == AIROPCFG) { - ConfigRid *cfg = (ConfigRid *)iobuf; - - if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) - cfg->opmode |= MODE_MIC; - - if ((cfg->opmode & MODE_CFG_MASK) == MODE_STA_IBSS) - set_bit (FLAG_ADHOC, &ai->flags); - else - clear_bit (FLAG_ADHOC, &ai->flags); - } - - if ((*writer)(ai, ridcode, iobuf, comp->len, 1)) { - kfree (iobuf); - return -EIO; - } - kfree (iobuf); - return 0; -} - -/***************************************************************************** - * Ancillary flash / mod functions much black magic lurkes here * - ***************************************************************************** - */ - -/* - * Flash command switch table - */ - -static int flashcard(struct net_device *dev, aironet_ioctl *comp) -{ - int z; - - /* Only super-user can modify flash */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch(comp->command) - { - case AIROFLSHRST: - return cmdreset((struct airo_info *)dev->ml_priv); - - case AIROFLSHSTFL: - if (!AIRO_FLASH(dev) && - (AIRO_FLASH(dev) = kmalloc(FLASHSIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - return setflashmode((struct airo_info *)dev->ml_priv); - - case AIROFLSHGCHR: /* Get char from aux */ - if (comp->len != sizeof(int)) - return -EINVAL; - if (copy_from_user(&z, comp->data, comp->len)) - return -EFAULT; - return flashgchar((struct airo_info *)dev->ml_priv, z, 8000); - - case AIROFLSHPCHR: /* Send char to card. */ - if (comp->len != sizeof(int)) - return -EINVAL; - if (copy_from_user(&z, comp->data, comp->len)) - return -EFAULT; - return flashpchar((struct airo_info *)dev->ml_priv, z, 8000); - - case AIROFLPUTBUF: /* Send 32k to card */ - if (!AIRO_FLASH(dev)) - return -ENOMEM; - if (comp->len > FLASHSIZE) - return -EINVAL; - if (copy_from_user(AIRO_FLASH(dev), comp->data, comp->len)) - return -EFAULT; - - flashputbuf((struct airo_info *)dev->ml_priv); - return 0; - - case AIRORESTART: - if (flashrestart((struct airo_info *)dev->ml_priv, dev)) - return -EIO; - return 0; - } - return -EINVAL; -} - -#define FLASH_COMMAND 0x7e7e - -/* - * STEP 1) - * Disable MAC and do soft reset on - * card. - */ - -static int cmdreset(struct airo_info *ai) -{ - disable_MAC(ai, 1); - - if (!waitbusy (ai)) { - airo_print_info(ai->dev->name, "Waitbusy hang before RESET"); - return -EBUSY; - } - - OUT4500(ai, COMMAND, CMD_SOFTRESET); - - ssleep(1); /* WAS 600 12/7/00 */ - - if (!waitbusy (ai)) { - airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET"); - return -EBUSY; - } - return 0; -} - -/* STEP 2) - * Put the card in legendary flash - * mode - */ - -static int setflashmode (struct airo_info *ai) -{ - set_bit (FLAG_FLASHING, &ai->flags); - - OUT4500(ai, SWS0, FLASH_COMMAND); - OUT4500(ai, SWS1, FLASH_COMMAND); - if (probe) { - OUT4500(ai, SWS0, FLASH_COMMAND); - OUT4500(ai, COMMAND, 0x10); - } else { - OUT4500(ai, SWS2, FLASH_COMMAND); - OUT4500(ai, SWS3, FLASH_COMMAND); - OUT4500(ai, COMMAND, 0); - } - msleep(500); /* 500ms delay */ - - if (!waitbusy(ai)) { - clear_bit (FLAG_FLASHING, &ai->flags); - airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode"); - return -EIO; - } - return 0; -} - -/* Put character to SWS0 wait for dwelltime - * x 50us for echo . - */ - -static int flashpchar(struct airo_info *ai, int byte, int dwelltime) -{ - int echo; - int waittime; - - byte |= 0x8000; - - if (dwelltime == 0) - dwelltime = 200; - - waittime = dwelltime; - - /* Wait for busy bit d15 to go false indicating buffer empty */ - while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) { - udelay (50); - waittime -= 50; - } - - /* timeout for busy clear wait */ - if (waittime <= 0) { - airo_print_info(ai->dev->name, "flash putchar busywait timeout!"); - return -EBUSY; - } - - /* Port is clear now write byte and wait for it to echo back */ - do { - OUT4500(ai, SWS0, byte); - udelay(50); - dwelltime -= 50; - echo = IN4500(ai, SWS1); - } while (dwelltime >= 0 && echo != byte); - - OUT4500(ai, SWS1, 0); - - return (echo == byte) ? 0 : -EIO; -} - -/* - * Get a character from the card matching matchbyte - * Step 3) - */ -static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime) -{ - int rchar; - unsigned char rbyte = 0; - - do { - rchar = IN4500(ai, SWS1); - - if (dwelltime && !(0x8000 & rchar)) { - dwelltime -= 10; - mdelay(10); - continue; - } - rbyte = 0xff & rchar; - - if ((rbyte == matchbyte) && (0x8000 & rchar)) { - OUT4500(ai, SWS1, 0); - return 0; - } - if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar) - break; - OUT4500(ai, SWS1, 0); - - } while (dwelltime > 0); - return -EIO; -} - -/* - * Transfer 32k of firmware data from user buffer to our buffer and - * send to the card - */ - -static int flashputbuf(struct airo_info *ai) -{ - int nwords; - - /* Write stuff */ - if (test_bit(FLAG_MPI,&ai->flags)) - memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE); - else { - OUT4500(ai, AUXPAGE, 0x100); - OUT4500(ai, AUXOFF, 0); - - for (nwords = 0; nwords != FLASHSIZE / 2; nwords++) { - OUT4500(ai, AUXDATA, ai->flash[nwords] & 0xffff); - } - } - OUT4500(ai, SWS0, 0x8000); - - return 0; -} - -/* - * - */ -static int flashrestart(struct airo_info *ai, struct net_device *dev) -{ - int i, status; - - ssleep(1); /* Added 12/7/00 */ - clear_bit (FLAG_FLASHING, &ai->flags); - if (test_bit(FLAG_MPI, &ai->flags)) { - status = mpi_init_descriptors(ai); - if (status != SUCCESS) - return status; - } - status = setup_card(ai, dev, 1); - - if (!test_bit(FLAG_MPI,&ai->flags)) - for (i = 0; i < MAX_FIDS; i++) { - ai->fids[i] = transmit_allocate - (ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2); - } - - ssleep(1); /* Added 12/7/00 */ - return status; -} -#endif /* CISCO_EXT */ - -/* - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - In addition: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -module_init(airo_init_module); -module_exit(airo_cleanup_module); diff --git a/drivers/net/wireless/cisco/airo.h b/drivers/net/wireless/cisco/airo.h deleted file mode 100644 index 8a02977a2e..0000000000 --- a/drivers/net/wireless/cisco/airo.h +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _AIRO_H_ -#define _AIRO_H_ - -struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia, - struct device *dmdev); -int reset_airo_card(struct net_device *dev); -void stop_airo_card(struct net_device *dev, int freeres); - -#endif /* _AIRO_H_ */ diff --git a/drivers/net/wireless/cisco/airo_cs.c b/drivers/net/wireless/cisco/airo_cs.c deleted file mode 100644 index fcfe4c6d62..0000000000 --- a/drivers/net/wireless/cisco/airo_cs.c +++ /dev/null @@ -1,218 +0,0 @@ -/*====================================================================== - - Aironet driver for 4500 and 4800 series cards - - This code is released under both the GPL version 2 and BSD licenses. - Either license may be used. The respective licenses are found at - the end of this file. - - This code was developed by Benjamin Reed <breed@users.sourceforge.net> - including portions of which come from the Aironet PC4500 - Developer's Reference Manual and used with permission. Copyright - (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use - code in the Developer's manual was granted for this driver by - Aironet. - - In addition this module was derived from dummy_cs. - The initial developer of dummy_cs is David A. Hinds - <dahinds@users.sourceforge.net>. Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - -======================================================================*/ - -#ifdef __IN_PCMCIA_PACKAGE__ -#include <pcmcia/k_compat.h> -#endif -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/netdevice.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> - -#include <linux/io.h> - -#include "airo.h" - - -/*====================================================================*/ - -MODULE_AUTHOR("Benjamin Reed"); -MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet " - "cards. This is the module that links the PCMCIA card " - "with the airo module."); -MODULE_LICENSE("Dual BSD/GPL"); - -/*====================================================================*/ - -static int airo_config(struct pcmcia_device *link); -static void airo_release(struct pcmcia_device *link); - -static void airo_detach(struct pcmcia_device *p_dev); - -struct local_info { - struct net_device *eth_dev; -}; - -static int airo_probe(struct pcmcia_device *p_dev) -{ - struct local_info *local; - - dev_dbg(&p_dev->dev, "airo_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(*local), GFP_KERNEL); - if (!local) - return -ENOMEM; - - p_dev->priv = local; - - return airo_config(p_dev); -} /* airo_attach */ - -static void airo_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "airo_detach\n"); - - airo_release(link); - - if (((struct local_info *)link->priv)->eth_dev) { - stop_airo_card(((struct local_info *)link->priv)->eth_dev, - 0); - } - ((struct local_info *)link->priv)->eth_dev = NULL; - - kfree(link->priv); -} /* airo_detach */ - -static int airo_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - - -static int airo_config(struct pcmcia_device *link) -{ - int ret; - - dev_dbg(&link->dev, "airo_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | - CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, airo_cs_config_check, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - ((struct local_info *)link->priv)->eth_dev = - init_airo_card(link->irq, - link->resource[0]->start, 1, &link->dev); - if (!((struct local_info *)link->priv)->eth_dev) - goto failed; - - return 0; - - failed: - airo_release(link); - return -ENODEV; -} /* airo_config */ - -static void airo_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "airo_release\n"); - pcmcia_disable_device(link); -} - -static int airo_suspend(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - netif_device_detach(local->eth_dev); - - return 0; -} - -static int airo_resume(struct pcmcia_device *link) -{ - struct local_info *local = link->priv; - - if (link->open) { - reset_airo_card(local->eth_dev); - netif_device_attach(local->eth_dev); - } - - return 0; -} - -static const struct pcmcia_device_id airo_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a), - PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005), - PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007), - PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0007), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, airo_ids); - -static struct pcmcia_driver airo_driver = { - .owner = THIS_MODULE, - .name = "airo_cs", - .probe = airo_probe, - .remove = airo_detach, - .id_table = airo_ids, - .suspend = airo_suspend, - .resume = airo_resume, -}; -module_pcmcia_driver(airo_driver); - -/* - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - In addition: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 69276266ce..70e420df16 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -4231,8 +4231,6 @@ il4965_rx_handle(struct il_priv *il) fill_rx = 1; while (i != r) { - int len; - rxb = rxq->queue[i]; /* If an RXB doesn't have a Rx queue slot associated with it, @@ -4246,10 +4244,6 @@ il4965_rx_handle(struct il_priv *il) PAGE_SIZE << il->hw_params.rx_page_order, DMA_FROM_DEVICE); pkt = rxb_addr(rxb); - - len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; - len += sizeof(u32); /* account for status word */ - reclaim = il_need_reclaim(il, pkt); /* Based on type of command response or notification, diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 054fef680a..17570d62c8 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -541,6 +541,9 @@ il_leds_init(struct il_priv *il) il->led.name = kasprintf(GFP_KERNEL, "%s-led", wiphy_name(il->hw->wiphy)); + if (!il->led.name) + return; + il->led.brightness_set = il_led_brightness_set; il->led.blink_set = il_led_blink_set; il->led.max_brightness = 1; diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index 134635c70c..73cbb120a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -299,3 +299,9 @@ MODULE_FIRMWARE(IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_GF4_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); + +MODULE_FIRMWARE("iwlwifi-so-a0-gf-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-so-a0-gf4-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-ty-a0-gf-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-ma-b0-gf-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-ma-b0-gf4-a0.pnvm"); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 82da957adc..1b6249561c 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -179,3 +179,5 @@ MODULE_FIRMWARE(IWL_BZ_A_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_C_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); + +MODULE_FIRMWARE("iwlwifi-gl-c0-fm-c0.pnvm"); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 80eb9b4995..156c428547 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <linux/module.h> #include <linux/stringify.h> @@ -33,6 +33,10 @@ #define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0" #define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0" #define IWL_SC_A_WH_A_FW_PRE "iwlwifi-sc-a0-wh-a0" +#define IWL_SC2_A_FM_C_FW_PRE "iwlwifi-sc2-a0-fm-c0" +#define IWL_SC2_A_WH_A_FW_PRE "iwlwifi-sc2-a0-wh-a0" +#define IWL_SC2F_A_FM_C_FW_PRE "iwlwifi-sc2f-a0-fm-c0" +#define IWL_SC2F_A_WH_A_FW_PRE "iwlwifi-sc2f-a0-wh-a0" #define IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(api) \ IWL_SC_A_FM_B_FW_PRE "-" __stringify(api) ".ucode" @@ -48,6 +52,14 @@ IWL_SC_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(api) \ IWL_SC_A_WH_A_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2_A_FM_C_FW_MODULE_FIRMWARE(api) \ + IWL_SC2_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2_A_WH_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC2_A_WH_A_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2F_A_FM_C_FW_MODULE_FIRMWARE(api) \ + IWL_SC2F_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2F_A_WH_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC2F_A_WH_A_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl_sc_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -124,6 +136,9 @@ static const struct iwl_base_params iwl_sc_base_params = { #define IWL_DEVICE_SC \ IWL_DEVICE_BZ_COMMON, \ + .uhb_supported = true, \ + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ + .num_rbds = IWL_NUM_RBDS_SC_EHT, \ .ht_params = &iwl_22000_ht_params /* @@ -149,10 +164,21 @@ const char iwl_sc_name[] = "Intel(R) TBD Sc device"; const struct iwl_cfg iwl_cfg_sc = { .fw_name_mac = "sc", - .uhb_supported = true, IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_SC_EHT, +}; + +const char iwl_sc2_name[] = "Intel(R) TBD Sc2 device"; + +const struct iwl_cfg iwl_cfg_sc2 = { + .fw_name_mac = "sc2", + IWL_DEVICE_SC, +}; + +const char iwl_sc2f_name[] = "Intel(R) TBD Sc2f device"; + +const struct iwl_cfg iwl_cfg_sc2f = { + .fw_name_mac = "sc2f", + IWL_DEVICE_SC, }; MODULE_FIRMWARE(IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); @@ -162,3 +188,7 @@ MODULE_FIRMWARE(IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SC_A_GF_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SC_A_GF4_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2_A_FM_C_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2_A_WH_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2F_A_FM_C_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2F_A_WH_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h index 8248c3beb1..b740c65a7d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h @@ -60,6 +60,12 @@ enum iwl_debug_cmds { */ FW_DUMP_COMPLETE_CMD = 0xB, /** + * @FW_CLEAR_BUFFER: + * clears the firmware's internal buffer + * no payload + */ + FW_CLEAR_BUFFER = 0xD, + /** * @MFU_ASSERT_DUMP_NTF: * &struct iwl_mfu_assert_dump_notif */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index dfe0bebabc..7ec959244f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -269,6 +269,9 @@ struct iwl_nvm_access_complete_cmd { __le32 reserved; } __packed; /* NVM_ACCESS_COMPLETE_CMD_API_S_VER_1 */ +#define IWL_MCC_US 0x5553 +#define IWL_MCC_CANADA 0x4341 + /** * struct iwl_mcc_update_cmd - Request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 57ddd8aefa..59f7a75c72 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -19,7 +19,6 @@ * @fwrt_ptr: pointer to the buffer coming from fwrt * @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the * transport's data. - * @trans_len: length of the valid data in trans_ptr * @fwrt_len: length of the valid data in fwrt_ptr */ struct iwl_fw_dump_ptrs { @@ -880,10 +879,10 @@ iwl_fw_error_dump_file(struct iwl_fw_runtime *fwrt, cpu_to_le32(fwrt->trans->hw_rev_step); memcpy(dump_info->fw_human_readable, fwrt->fw->human_readable, sizeof(dump_info->fw_human_readable)); - strncpy(dump_info->dev_human_readable, fwrt->trans->name, - sizeof(dump_info->dev_human_readable) - 1); - strncpy(dump_info->bus_human_readable, fwrt->dev->bus->name, - sizeof(dump_info->bus_human_readable) - 1); + strscpy_pad(dump_info->dev_human_readable, fwrt->trans->name, + sizeof(dump_info->dev_human_readable)); + strscpy_pad(dump_info->bus_human_readable, fwrt->dev->bus->name, + sizeof(dump_info->bus_human_readable)); dump_info->num_of_lmacs = fwrt->smem_cfg.num_lmacs; dump_info->lmac_err_id[0] = cpu_to_le32(fwrt->dump.lmac_err_id[0]); @@ -3396,3 +3395,22 @@ void iwl_fw_disable_dbg_asserts(struct iwl_fw_runtime *fwrt) iwl_trans_send_cmd(fwrt->trans, &hcmd); } IWL_EXPORT_SYMBOL(iwl_fw_disable_dbg_asserts); + +void iwl_fw_dbg_clear_monitor_buf(struct iwl_fw_runtime *fwrt) +{ + struct iwl_fw_dbg_params params = {0}; + + iwl_fw_dbg_stop_sync(fwrt); + + if (fw_has_api(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR)) { + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(DEBUG_GROUP, FW_CLEAR_BUFFER), + }; + iwl_trans_send_cmd(fwrt->trans, &hcmd); + } + + iwl_dbg_tlv_init_cfg(fwrt); + iwl_fw_dbg_stop_restart_recording(fwrt, ¶ms, false); +} +IWL_EXPORT_SYMBOL(iwl_fw_dbg_clear_monitor_buf); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 66b233250c..eb38c686b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -330,6 +330,7 @@ void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt, u32 timepoint, u32 timepoint_data); void iwl_fw_disable_dbg_asserts(struct iwl_fw_runtime *fwrt); +void iwl_fw_dbg_clear_monitor_buf(struct iwl_fw_runtime *fwrt); #define IWL_FW_CHECK_FAILED(_obj, _fmt, ...) \ IWL_ERR_LIMIT(_obj, _fmt, __VA_ARGS__) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 03f6e52014..bfc39bd5bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -20,7 +20,7 @@ struct iwl_ucode_header { __le32 init_size; /* bytes of init code */ __le32 init_data_size; /* bytes of init data */ __le32 boot_size; /* bytes of bootstrap code */ - u8 data[0]; /* in same order as sizes */ + u8 data[]; /* in same order as sizes */ } v1; struct { __le32 build; /* build number */ @@ -29,7 +29,7 @@ struct iwl_ucode_header { __le32 init_size; /* bytes of init code */ __le32 init_data_size; /* bytes of init data */ __le32 boot_size; /* bytes of bootstrap code */ - u8 data[0]; /* in same order as sizes */ + u8 data[]; /* in same order as sizes */ } v2; } u; }; @@ -243,6 +243,10 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * version tables. * @IWL_UCODE_TLV_API_REDUCED_SCAN_CONFIG: This ucode supports v3 of * SCAN_CONFIG_DB_CMD_API_S. + * @IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX: Firmware offloaded the station disable tx + * logic. + * @IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR: Firmware supports clearing the debug + * internal buffer * * @NUM_IWL_UCODE_TLV_API: number of bits used */ @@ -280,6 +284,9 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP = (__force iwl_ucode_tlv_api_t)57, IWL_UCODE_TLV_API_SCAN_EXT_CHAN_VER = (__force iwl_ucode_tlv_api_t)58, IWL_UCODE_TLV_API_BAND_IN_RX_DATA = (__force iwl_ucode_tlv_api_t)59, + /* API Set 2 */ + IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX = (__force iwl_ucode_tlv_api_t)66, + IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR = (__force iwl_ucode_tlv_api_t)67, NUM_IWL_UCODE_TLV_API /* diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 02ded22295..e99d691362 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -2,7 +2,7 @@ /* * Copyright (C) 2005-2014, 2018-2021 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #ifndef __IWL_CONFIG_H__ #define __IWL_CONFIG_H__ @@ -377,7 +377,6 @@ struct iwl_cfg { u16 nvm_calib_ver; u32 rx_with_siso_diversity:1, tx_with_siso_diversity:1, - bt_shared_single_ant:1, internal_wimax_coex:1, host_interrupt_operation_mode:1, high_temp:1, @@ -419,6 +418,8 @@ struct iwl_cfg { #define IWL_CFG_MAC_TYPE_BZ 0x46 #define IWL_CFG_MAC_TYPE_GL 0x47 #define IWL_CFG_MAC_TYPE_SC 0x48 +#define IWL_CFG_MAC_TYPE_SC2 0x49 +#define IWL_CFG_MAC_TYPE_SC2F 0x4A #define IWL_CFG_RF_TYPE_TH 0x105 #define IWL_CFG_RF_TYPE_TH1 0x108 @@ -528,6 +529,8 @@ extern const char iwl_ax231_name[]; extern const char iwl_ax411_name[]; extern const char iwl_bz_name[]; extern const char iwl_sc_name[]; +extern const char iwl_sc2_name[]; +extern const char iwl_sc2f_name[]; #if IS_ENABLED(CONFIG_IWLDVM) extern const struct iwl_cfg iwl5300_agn_cfg; extern const struct iwl_cfg iwl5100_agn_cfg; @@ -633,6 +636,8 @@ extern const struct iwl_cfg iwl_cfg_bz; extern const struct iwl_cfg iwl_cfg_gl; extern const struct iwl_cfg iwl_cfg_sc; +extern const struct iwl_cfg iwl_cfg_sc2; +extern const struct iwl_cfg iwl_cfg_sc2f; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index a4df67ff21..4511d7fb22 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -354,6 +354,8 @@ enum { #define CSR_HW_RF_ID_TYPE_GF (0x0010D000) #define CSR_HW_RF_ID_TYPE_GF4 (0x0010E000) #define CSR_HW_RF_ID_TYPE_MS (0x00111000) +#define CSR_HW_RF_ID_TYPE_FM (0x00112000) +#define CSR_HW_RF_ID_TYPE_WP (0x00113000) /* HW_RF CHIP STEP */ #define CSR_HW_RF_STEP(_val) (((_val) >> 8) & 0xF) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 55d2ed13a9..3442dfab50 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -1280,7 +1280,7 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync, return 0; } -static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) +void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) { enum iwl_fw_ini_buffer_location *ini_dest = &fwrt->trans->dbg.ini_dest; int ret, i; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h index 06fb7d6653..7ed6329fd8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h @@ -57,6 +57,7 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data, bool sync); +void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt); static inline void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h index 347fd95c4e..2c280a2fe3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h @@ -3,7 +3,7 @@ * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2018 - 2019, 2023 Intel Corporation *****************************************************************************/ #if !defined(__IWLWIFI_DEVICE_TRACE_DATA) || defined(TRACE_HEADER_MULTI_READ) @@ -36,20 +36,17 @@ TRACE_EVENT(iwlwifi_dev_tx_tb, TRACE_EVENT(iwlwifi_dev_rx_data, TP_PROTO(const struct device *dev, - const struct iwl_trans *trans, - void *rxbuf, size_t len), - TP_ARGS(dev, trans, rxbuf, len), + void *rxbuf, size_t len, size_t start), + TP_ARGS(dev, rxbuf, len, start), TP_STRUCT__entry( DEV_ENTRY - __dynamic_array(u8, data, - len - iwl_rx_trace_len(trans, rxbuf, len, NULL)) + __dynamic_array(u8, data, len - start) ), TP_fast_assign( - size_t offs = iwl_rx_trace_len(trans, rxbuf, len, NULL); DEV_ASSIGN; - if (offs < len) + if (start < len) memcpy(__get_dynamic_array(data), - ((u8 *)rxbuf) + offs, len - offs); + ((u8 *)rxbuf) + start, len - start); ), TP_printk("[%s] RX frame data", __get_str(dev)) ); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h index 46ed723f13..e656bf6bc0 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h @@ -4,7 +4,7 @@ * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018, 2023 Intel Corporation *****************************************************************************/ #if !defined(__IWLWIFI_DEVICE_TRACE_IWLWIFI) || defined(TRACE_HEADER_MULTI_READ) @@ -50,23 +50,20 @@ TRACE_EVENT(iwlwifi_dev_hcmd, ); TRACE_EVENT(iwlwifi_dev_rx, - TP_PROTO(const struct device *dev, const struct iwl_trans *trans, - struct iwl_rx_packet *pkt, size_t len), - TP_ARGS(dev, trans, pkt, len), + TP_PROTO(const struct device *dev, + struct iwl_rx_packet *pkt, size_t len, size_t trace_len, + size_t hdr_offset), + TP_ARGS(dev, pkt, len, trace_len, hdr_offset), TP_STRUCT__entry( DEV_ENTRY __field(u16, cmd) __field(u8, hdr_offset) - __dynamic_array(u8, rxbuf, - iwl_rx_trace_len(trans, pkt, len, NULL)) + __dynamic_array(u8, rxbuf, trace_len) ), TP_fast_assign( - size_t hdr_offset = 0; - DEV_ASSIGN; __entry->cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd); - memcpy(__get_dynamic_array(rxbuf), pkt, - iwl_rx_trace_len(trans, pkt, len, &hdr_offset)); + memcpy(__get_dynamic_array(rxbuf), pkt, trace_len); __entry->hdr_offset = hdr_offset; ), TP_printk("[%s] RX cmd %#.2x", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c index e46639b097..7e68629796 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018, 2023 Intel Corporation *****************************************************************************/ #include <linux/module.h> @@ -20,4 +20,17 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event); -#endif +#else +#include "iwl-devtrace.h" +#endif /* __CHECKER__ */ + +void __trace_iwlwifi_dev_rx(struct iwl_trans *trans, void *pkt, size_t len) +{ + size_t hdr_offset = 0, trace_len; + + trace_len = iwl_rx_trace_len(trans, pkt, len, &hdr_offset); + trace_iwlwifi_dev_rx(trans->dev, pkt, len, trace_len, hdr_offset); + + if (trace_len < len) + trace_iwlwifi_dev_rx_data(trans->dev, pkt, len, trace_len); +} diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h index 01fb7b900a..c3e09f4fef 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h @@ -7,12 +7,12 @@ *****************************************************************************/ #ifndef __IWLWIFI_DEVICE_TRACE +#define __IWLWIFI_DEVICE_TRACE #include <linux/skbuff.h> #include <linux/ieee80211.h> #include <net/cfg80211.h> #include <net/mac80211.h> #include "iwl-trans.h" -#if !defined(__IWLWIFI_DEVICE_TRACE) static inline bool iwl_trace_data(struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -70,9 +70,6 @@ static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans, return sizeof(__le32) + sizeof(*cmd) + trans->rx_mpdu_cmd_hdr_size + ieee80211_hdrlen(hdr->frame_control); } -#endif - -#define __IWLWIFI_DEVICE_TRACE #include <linux/tracepoint.h> #include <linux/device.h> @@ -98,4 +95,20 @@ static inline void trace_ ## name(proto) {} #include "iwl-devtrace-data.h" #include "iwl-devtrace-iwlwifi.h" +#ifdef CONFIG_IWLWIFI_DEVICE_TRACING +DECLARE_TRACEPOINT(iwlwifi_dev_rx); +DECLARE_TRACEPOINT(iwlwifi_dev_rx_data); +#endif + +void __trace_iwlwifi_dev_rx(struct iwl_trans *trans, void *pkt, size_t len); + +static inline void maybe_trace_iwlwifi_dev_rx(struct iwl_trans *trans, + void *pkt, size_t len) +{ +#ifdef CONFIG_IWLWIFI_DEVICE_TRACING + if (tracepoint_enabled(iwlwifi_dev_rx) || + tracepoint_enabled(iwlwifi_dev_rx_data)) + __trace_iwlwifi_dev_rx(trans, pkt, len); +#endif +} #endif /* __IWLWIFI_DEVICE_TRACE */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index d85cadd8e1..501a8cc213 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1606,10 +1606,17 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, /* Set the GO concurrent flag only in case that NO_IR is set. * Otherwise it is meaningless */ - if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) && - (flags & NL80211_RRF_NO_IR)) - flags |= NL80211_RRF_GO_CONCURRENT; - + if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT)) { + if (flags & NL80211_RRF_NO_IR) + flags |= NL80211_RRF_GO_CONCURRENT; + if (flags & NL80211_RRF_DFS) { + flags |= NL80211_RRF_DFS_CONCURRENT; + /* Our device doesn't set active bit for DFS channels + * however, once marked as DFS no-ir is not needed. + */ + flags &= ~NL80211_RRF_NO_IR; + } + } /* * reg_capa is per regulatory domain so apply it for every channel */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index af5f9b210f..3dc618a7c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -64,8 +64,6 @@ struct iwl_cfg; * received on the RSS queue(s). The queue parameter indicates which of the * RSS queues received this frame; it will always be non-zero. * This method must not sleep. - * @async_cb: called when an ASYNC command with CMD_WANT_ASYNC_CALLBACK set - * completes. Must be atomic. * @queue_full: notifies that a HW queue is full. * Must be atomic and called with BH disabled. * @queue_not_full: notifies that a HW queue is not full any more. @@ -96,8 +94,6 @@ struct iwl_op_mode_ops { struct iwl_rx_cmd_buffer *rxb); void (*rx_rss)(struct iwl_op_mode *op_mode, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, unsigned int queue); - void (*async_cb)(struct iwl_op_mode *op_mode, - const struct iwl_device_cmd *cmd); void (*queue_full)(struct iwl_op_mode *op_mode, int queue); void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue); bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); @@ -147,13 +143,6 @@ static inline void iwl_op_mode_rx_rss(struct iwl_op_mode *op_mode, op_mode->ops->rx_rss(op_mode, napi, rxb, queue); } -static inline void iwl_op_mode_async_cb(struct iwl_op_mode *op_mode, - const struct iwl_device_cmd *cmd) -{ - if (op_mode->ops->async_cb) - op_mode->ops->async_cb(op_mode, cmd); -} - static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, int queue) { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 4bd759432d..f95098c21c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -172,10 +172,6 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) return -EIO; } - if (WARN_ON((cmd->flags & CMD_WANT_ASYNC_CALLBACK) && - !(cmd->flags & CMD_ASYNC))) - return -EINVAL; - if (!(cmd->flags & CMD_ASYNC)) lock_map_acquire_read(&trans->sync_cmd_lockdep_map); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 05e72a2125..5789a87359 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -110,8 +110,7 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt) * @CMD_WANT_SKB: Not valid with CMD_ASYNC. The caller needs the buffer of * the response. The caller needs to call iwl_free_resp when done. * @CMD_SEND_IN_RFKILL: Send the command even if the NIC is in RF-kill. - * @CMD_WANT_ASYNC_CALLBACK: the op_mode's async callback function must be - * called after this command completes. Valid only with CMD_ASYNC. + * @CMD_BLOCK_TXQS: Block TXQs while the comment is executing. * @CMD_SEND_IN_D3: Allow the command to be sent in D3 mode, relevant to * SUSPEND and RESUME commands. We are in D3 mode when we set * trans->system_pm_mode to IWL_PLAT_PM_MODE_D3. @@ -120,7 +119,7 @@ enum CMD_MODE { CMD_ASYNC = BIT(0), CMD_WANT_SKB = BIT(1), CMD_SEND_IN_RFKILL = BIT(2), - CMD_WANT_ASYNC_CALLBACK = BIT(3), + CMD_BLOCK_TXQS = BIT(3), CMD_SEND_IN_D3 = BIT(4), }; @@ -534,11 +533,6 @@ struct iwl_pnvm_image { * @wait_txq_empty: wait until specific tx queue is empty. May sleep. * @freeze_txq_timer: prevents the timer of the queue from firing until the * queue is set to awake. Must be atomic. - * @block_txq_ptrs: stop updating the write pointers of the Tx queues. Note - * that the transport needs to refcount the calls since this function - * will be called several times with block = true, and then the queues - * need to be unblocked only after the same number of calls with - * block = false. * @write8: write a u8 to a register at offset ofs from the BAR * @write32: write a u32 to a register at offset ofs from the BAR * @read32: read a u32 register at offset ofs from the BAR @@ -613,7 +607,6 @@ struct iwl_trans_ops { int (*wait_txq_empty)(struct iwl_trans *trans, int queue); void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs, bool freeze); - void (*block_txq_ptrs)(struct iwl_trans *trans, bool block); void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val); void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val); @@ -1323,7 +1316,7 @@ iwl_trans_get_rxq_dma_data(struct iwl_trans *trans, int queue, struct iwl_trans_rxq_dma_data *data) { if (WARN_ON_ONCE(!trans->ops->rxq_dma_data)) - return -ENOTSUPP; + return -EOPNOTSUPP; return trans->ops->rxq_dma_data(trans, queue, data); } @@ -1345,7 +1338,7 @@ iwl_trans_txq_alloc(struct iwl_trans *trans, might_sleep(); if (WARN_ON_ONCE(!trans->ops->txq_alloc)) - return -ENOTSUPP; + return -EOPNOTSUPP; if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); @@ -1407,23 +1400,11 @@ static inline void iwl_trans_freeze_txq_timer(struct iwl_trans *trans, trans->ops->freeze_txq_timer(trans, txqs, freeze); } -static inline void iwl_trans_block_txq_ptrs(struct iwl_trans *trans, - bool block) -{ - if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return; - } - - if (trans->ops->block_txq_ptrs) - trans->ops->block_txq_ptrs(trans, block); -} - static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, u32 txqs) { if (WARN_ON_ONCE(!trans->ops->wait_tx_queues_empty)) - return -ENOTSUPP; + return -EOPNOTSUPP; /* No need to wait if the firmware is not alive */ if (trans->state != IWL_TRANS_FW_ALIVE) { @@ -1437,7 +1418,7 @@ static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, static inline int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue) { if (WARN_ON_ONCE(!trans->ops->wait_txq_empty)) - return -ENOTSUPP; + return -EOPNOTSUPP; if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 5a5b1128e7..9fe1761691 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2013-2014, 2018-2020, 2022 Intel Corporation + * Copyright (C) 2013-2014, 2018-2020, 2022-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH */ #include <linux/ieee80211.h> @@ -116,11 +116,6 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) ret = BT_COEX_TX_DIS_LUT; - if (mvm->cfg->bt_shared_single_ant) { - rcu_read_unlock(); - return ret; - } - phy_ctx_id = *((u16 *)chanctx_conf->drv_priv); primary_ch_phy_id = le32_to_cpu(mvm->last_bt_ci_cmd.primary_ch_phy_id); secondary_ch_phy_id = @@ -383,13 +378,12 @@ static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, /* * don't reduce the Tx power if one of these is true: * we are in LOOSE - * single share antenna product * BT is inactive * we are not associated */ if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || - mvm->cfg->bt_shared_single_ant || !vif->cfg.assoc || - le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) { + le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF || + !vif->cfg.assoc) { iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id, false); /* FIXME: should this be per link? */ iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); @@ -570,7 +564,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * Check if rssi is good enough for reduced Tx power, but not in loose * scheme. */ - if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant || + if (rssi_event == RSSI_EVENT_LOW || iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT) ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->deflink.ap_sta_id, @@ -639,10 +633,6 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant) { - /* there is no other antenna, shared antenna is always available */ - if (mvm->cfg->bt_shared_single_ant) - return true; - if (ant & mvm->cfg->non_shared_ant) return true; @@ -652,10 +642,6 @@ bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant) bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) { - /* there is no other antenna, shared antenna is always available */ - if (mvm->cfg->bt_shared_single_ant) - return true; - return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index d99a712e7f..2a08369238 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1128,14 +1128,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, return ret; } - /* - * This needs to be unlocked due to lock ordering - * constraints. Since we're in the suspend path - * that isn't really a problem though. - */ - mutex_unlock(&mvm->mutex); ret = iwl_mvm_wowlan_config_key_params(mvm, vif); - mutex_lock(&mvm->mutex); if (ret) return ret; @@ -2508,7 +2501,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, struct iwl_wowlan_status_data *status) { int i; - bool keep; + bool keep = false; struct iwl_mvm_sta *mvm_ap_sta; if (!status) @@ -2536,18 +2529,12 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, mvm_ap_sta->tid_data[i].seq_number >> 4); } - /* now we have all the data we need, unlock to avoid mac80211 issues */ - mutex_unlock(&mvm->mutex); - iwl_mvm_report_wakeup_reasons(mvm, vif, status); keep = iwl_mvm_setup_connection_keep(mvm, vif, status); - - return keep; - out_unlock: mutex_unlock(&mvm->mutex); - return false; + return keep; } #define ND_QUERY_BUF_LEN (sizeof(struct iwl_scan_offload_profile_match) * \ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 7737650e56..edc8204f7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1521,7 +1521,7 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm, /* supporting only MQ RX */ if (!mvm->trans->trans_cfg->mq_rx_supported) - return -ENOTSUPP; + return -EOPNOTSUPP; rxb._page = alloc_pages(GFP_ATOMIC, 0); if (!rxb._page) @@ -1714,6 +1714,20 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, return count; } +static ssize_t iwl_dbgfs_fw_dbg_clear_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000) + return -EOPNOTSUPP; + + mutex_lock(&mvm->mutex); + iwl_fw_dbg_clear_monitor_buf(&mvm->fwrt); + mutex_unlock(&mvm->mutex); + + return count; +} + static ssize_t iwl_dbgfs_dbg_time_point_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) @@ -2166,6 +2180,7 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64); +MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_clear, 64); MVM_DEBUGFS_WRITE_FILE_OPS(dbg_time_point, 64); MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, (IWL_RSS_INDIRECTION_TABLE_SIZE * 2)); @@ -2372,6 +2387,7 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm) MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, 0600); MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, 0600); MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(fw_dbg_clear, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(dbg_time_point, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 233ae81884..ae0eb585b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -53,6 +53,8 @@ int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (!pasn) return -ENOBUFS; + iwl_mvm_ftm_remove_pasn_sta(mvm, addr); + pasn->cipher = iwl_mvm_cipher_to_location_cipher(cipher); switch (pasn->cipher) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index 10b9219b3b..8f10590f9c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -39,7 +39,7 @@ static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef, *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); break; default: - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; @@ -77,7 +77,7 @@ static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef, } fallthrough; default: - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; @@ -291,7 +291,7 @@ iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm, default: IWL_ERR(mvm, "Unsupported DYN_CONFIG_CMD version %u\n", cmd_ver); - ret = -ENOTSUPP; + ret = -EOPNOTSUPP; } return ret; @@ -333,7 +333,7 @@ int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm, if (cmd_ver < 3) { IWL_ERR(mvm, "Adding PASN station not supported by FW\n"); - return -ENOTSUPP; + return -EOPNOTSUPP; } if ((!hltk || !hltk_len) && (!tk || !tk_len)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 403bd17b8b..1252084662 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -27,9 +27,6 @@ #define MVM_UCODE_ALIVE_TIMEOUT (2 * HZ) #define MVM_UCODE_CALIB_TIMEOUT (2 * HZ) -#define IWL_TAS_US_MCC 0x5553 -#define IWL_TAS_CANADA_MCC 0x4341 - #define IWL_UATS_VLP_AP_SUPPORTED BIT(29) #define IWL_UATS_AFC_AP_SUPPORTED BIT(30) @@ -1234,10 +1231,10 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) dmi_get_system_info(DMI_SYS_VENDOR)); if ((!iwl_mvm_add_to_tas_block_list(cmd.v4.block_list_array, &cmd.v4.block_list_size, - IWL_TAS_US_MCC)) || + IWL_MCC_US)) || (!iwl_mvm_add_to_tas_block_list(cmd.v4.block_list_array, &cmd.v4.block_list_size, - IWL_TAS_CANADA_MCC))) { + IWL_MCC_CANADA))) { IWL_DEBUG_RADIO(mvm, "Unable to add US/Canada to TAS block list, disabling TAS\n"); return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 168e4a2ffe..e321d41d1a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -152,6 +152,16 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, mvm->lar_regdom_set = true; mvm->mcc_src = src_id; + /* Some kind of regulatory mess means we need to currently disallow + * puncturing in the US and Canada. Do that here, at least until we + * figure out the new chanctx APIs for puncturing. + */ + if (resp->mcc == cpu_to_le16(IWL_MCC_US) || + resp->mcc == cpu_to_le16(IWL_MCC_CANADA)) + ieee80211_hw_set(mvm->hw, DISALLOW_PUNCTURING); + else + __clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING, mvm->hw->flags); + iwl_mei_set_country_code(__le16_to_cpu(resp->mcc)); out: @@ -288,7 +298,7 @@ int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) /* This has been tested on those devices only */ if (mvm->trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_9000 && mvm->trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_22000) - return -ENOTSUPP; + return -EOPNOTSUPP; if (!mvm->nvm_data) return -EBUSY; @@ -517,6 +527,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | REGULATORY_DISABLE_BEACON_HINTS; + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_DFS_CONCURRENT); + hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; hw->wiphy->flags |= WIPHY_FLAG_SPLIT_SCAN_6GHZ; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index 6af606e5da..1628bf5545 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -874,6 +874,9 @@ void iwl_mvm_mld_sta_modify_disable_tx(struct iwl_mvm *mvm, cmd.sta_id = cpu_to_le32(mvmsta->deflink.sta_id); cmd.disable = cpu_to_le32(disable); + if (WARN_ON(iwl_mvm_has_no_host_disable_tx(mvm))) + return; + ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, STA_DISABLE_TX_CMD), CMD_ASYNC, sizeof(cmd), &cmd); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 1e33de05d2..fe0fa9ff53 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -947,6 +947,7 @@ struct iwl_mvm { /* the vif that requested the current scan */ struct iwl_mvm_vif *scan_vif; + u8 scan_link_id; /* rx chain antennas set through debugfs for the scan command */ u8 scan_rx_ant; @@ -1513,6 +1514,12 @@ static inline bool iwl_mvm_has_quota_low_latency(struct iwl_mvm *mvm) IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY); } +static inline bool iwl_mvm_has_no_host_disable_tx(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX); +} + static inline bool iwl_mvm_has_tlc_offload(const struct iwl_mvm *mvm) { return fw_has_capa(&mvm->fw->ucode_capa, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 1627b2f819..adbbe19aea 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1703,18 +1703,6 @@ void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode, iwl_mvm_rx_common(mvm, rxb, pkt); } -static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode, - const struct iwl_device_cmd *cmd) -{ - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - - /* - * For now, we only set the CMD_WANT_ASYNC_CALLBACK for ADD_STA - * commands that need to block the Tx queues. - */ - iwl_trans_block_txq_ptrs(mvm->trans, false); -} - static int iwl_mvm_is_static_queue(struct iwl_mvm *mvm, int queue) { return queue == mvm->aux_queue || queue == mvm->probe_queue || @@ -2024,7 +2012,6 @@ static void iwl_op_mode_mvm_time_point(struct iwl_op_mode *op_mode, #define IWL_MVM_COMMON_OPS \ /* these could be differentiated */ \ - .async_cb = iwl_mvm_async_cb, \ .queue_full = iwl_mvm_stop_sw_queue, \ .queue_not_full = iwl_mvm_wake_sw_queue, \ .hw_rf_kill = iwl_mvm_set_hw_rfkill_state, \ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c index 2ecd32bed7..045c862a8f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c @@ -132,14 +132,18 @@ struct iwl_rfi_freq_table_resp_cmd *iwl_rfi_get_freq_table(struct iwl_mvm *mvm) if (ret) return ERR_PTR(ret); - if (WARN_ON_ONCE(iwl_rx_packet_payload_len(cmd.resp_pkt) != resp_size)) + if (WARN_ON_ONCE(iwl_rx_packet_payload_len(cmd.resp_pkt) != + resp_size)) { + iwl_free_resp(&cmd); return ERR_PTR(-EIO); + } resp = kmemdup(cmd.resp_pkt->data, resp_size, GFP_KERNEL); + iwl_free_resp(&cmd); + if (!resp) return ERR_PTR(-ENOMEM); - iwl_free_resp(&cmd); return resp; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 7bf2a5947e..481dfbbe46 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -236,21 +236,13 @@ static void iwl_mvm_add_rtap_sniffer_config(struct iwl_mvm *mvm, static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, struct napi_struct *napi, struct sk_buff *skb, int queue, - struct ieee80211_sta *sta, - struct ieee80211_link_sta *link_sta) + struct ieee80211_sta *sta) { if (unlikely(iwl_mvm_check_pn(mvm, skb, queue, sta))) { kfree_skb(skb); return; } - if (sta && sta->valid_links && link_sta) { - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - - rx_status->link_valid = 1; - rx_status->link_id = link_sta->link_id; - } - ieee80211_rx_napi(mvm->hw, sta, skb, napi); } @@ -587,7 +579,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm, while ((skb = __skb_dequeue(skb_list))) { iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, reorder_buf->queue, - sta, NULL /* FIXME */); + sta); reorder_buf->num_stored--; } } @@ -2214,6 +2206,11 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (IS_ERR(sta)) sta = NULL; link_sta = rcu_dereference(mvm->fw_id_to_link_sta[id]); + + if (sta && sta->valid_links && link_sta) { + rx_status->link_valid = 1; + rx_status->link_id = link_sta->link_id; + } } } else if (!is_multicast_ether_addr(hdr->addr2)) { /* @@ -2357,8 +2354,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, !(desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME)) rx_status->flag |= RX_FLAG_AMSDU_MORE; - iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta, - link_sta); + iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta); } out: rcu_read_unlock(); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 75c5c58e14..97d44354db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -101,6 +101,7 @@ struct iwl_mvm_scan_params { bool scan_6ghz; bool enable_6ghz_passive; bool respect_p2p_go, respect_p2p_go_hb; + s8 tsf_report_link_id; u8 bssid[ETH_ALEN] __aligned(2); }; @@ -2342,20 +2343,15 @@ iwl_mvm_scan_umac_fill_general_p_v12(struct iwl_mvm *mvm, if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2) gp->num_of_fragments[SCAN_HB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; + mvm->scan_link_id = 0; + if (version < 16) { gp->scan_start_mac_or_link_id = scan_vif->id; } else { - struct iwl_mvm_vif_link_info *link_info; - u8 link_id = 0; + struct iwl_mvm_vif_link_info *link_info = + scan_vif->link[params->tsf_report_link_id]; - /* Use one of the active link (if any). In the future it would - * be possible that the link ID would be part of the scan - * request coming from upper layers so we would need to use it. - */ - if (vif->active_links) - link_id = ffs(vif->active_links) - 1; - - link_info = scan_vif->link[link_id]; + mvm->scan_link_id = params->tsf_report_link_id; if (!WARN_ON(!link_info)) gp->scan_start_mac_or_link_id = link_info->fw_link_id; } @@ -2819,7 +2815,8 @@ static int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm, if (ver_handler->version != scan_ver) continue; - return ver_handler->handler(mvm, vif, params, type, uid); + err = ver_handler->handler(mvm, vif, params, type, uid); + return err ? : uid; } err = iwl_mvm_scan_umac(mvm, vif, params, type, uid); @@ -2977,6 +2974,14 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (req->duration) params.iter_notif = true; + params.tsf_report_link_id = req->tsf_report_link_id; + if (params.tsf_report_link_id < 0) { + if (vif->active_links) + params.tsf_report_link_id = __ffs(vif->active_links); + else + params.tsf_report_link_id = 0; + } + iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); iwl_mvm_scan_6ghz_passive_scan(mvm, ¶ms, vif); @@ -3164,8 +3169,13 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, .aborted = aborted, .scan_start_tsf = mvm->scan_start, }; + struct iwl_mvm_vif *scan_vif = mvm->scan_vif; + struct iwl_mvm_vif_link_info *link_info = + scan_vif->link[mvm->scan_link_id]; + + if (!WARN_ON(!link_info)) + memcpy(info.tsf_bssid, link_info->bssid, ETH_ALEN); - memcpy(info.tsf_bssid, mvm->scan_vif->deflink.bssid, ETH_ALEN); ieee80211_scan_completed(mvm->hw, &info); mvm->scan_vif = NULL; cancel_delayed_work(&mvm->scan_timeout_dwork); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 9905925142..c2e0cff740 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2578,7 +2578,7 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (WARN_ON(vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_ADHOC)) - return -ENOTSUPP; + return -EOPNOTSUPP; /* * In IBSS, ieee80211_check_queues() sets the cab_queue to be @@ -3262,7 +3262,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * should be updated as well. */ if (buf_size < IWL_FRAME_LIMIT) - return -ENOTSUPP; + return -EOPNOTSUPP; ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); if (ret) @@ -4139,10 +4139,8 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, } /* block the Tx queues until the FW updated the sleep Tx count */ - iwl_trans_block_txq_ptrs(mvm->trans, true); - ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, - CMD_ASYNC | CMD_WANT_ASYNC_CALLBACK, + CMD_ASYNC | CMD_BLOCK_TXQS, iwl_mvm_add_sta_cmd_size(mvm), &cmd); if (ret) IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); @@ -4180,7 +4178,8 @@ void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, int ret; if (mvm->mld_api_is_used) { - iwl_mvm_mld_sta_modify_disable_tx(mvm, mvmsta, disable); + if (!iwl_mvm_has_no_host_disable_tx(mvm)) + iwl_mvm_mld_sta_modify_disable_tx(mvm, mvmsta, disable); return; } @@ -4197,7 +4196,8 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); if (mvm->mld_api_is_used) { - iwl_mvm_mld_sta_modify_disable_tx_ap(mvm, sta, disable); + if (!iwl_mvm_has_no_host_disable_tx(mvm)) + iwl_mvm_mld_sta_modify_disable_tx_ap(mvm, sta, disable); return; } @@ -4252,7 +4252,9 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, int i; if (mvm->mld_api_is_used) { - iwl_mvm_mld_modify_all_sta_disable_tx(mvm, mvmvif, disable); + if (!iwl_mvm_has_no_host_disable_tx(mvm)) + iwl_mvm_mld_modify_all_sta_disable_tx(mvm, mvmvif, + disable); return; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index da00ef6e4f..3d96a824db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -898,9 +898,8 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm_session_prot_notif *notif = (void *)pkt->data; unsigned int ver = - iwl_fw_lookup_cmd_ver(mvm->fw, - WIDE_ID(MAC_CONF_GROUP, - SESSION_PROTECTION_CMD), 2); + iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, + SESSION_PROTECTION_NOTIF, 2); int id = le32_to_cpu(notif->mac_link_id); struct ieee80211_vif *vif; struct iwl_mvm_vif *mvmvif; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 26a0953603..ba3db601ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -502,12 +502,16 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* Bz devices */ {IWL_PCI_DEVICE(0x2727, PCI_ANY_ID, iwl_bz_trans_cfg)}, + {IWL_PCI_DEVICE(0x272D, PCI_ANY_ID, iwl_bz_trans_cfg)}, {IWL_PCI_DEVICE(0x272b, PCI_ANY_ID, iwl_bz_trans_cfg)}, {IWL_PCI_DEVICE(0xA840, PCI_ANY_ID, iwl_bz_trans_cfg)}, {IWL_PCI_DEVICE(0x7740, PCI_ANY_ID, iwl_bz_trans_cfg)}, /* Sc devices */ {IWL_PCI_DEVICE(0xE440, PCI_ANY_ID, iwl_sc_trans_cfg)}, + {IWL_PCI_DEVICE(0xE340, PCI_ANY_ID, iwl_sc_trans_cfg)}, + {IWL_PCI_DEVICE(0xD340, PCI_ANY_ID, iwl_sc_trans_cfg)}, + {IWL_PCI_DEVICE(0x6E70, PCI_ANY_ID, iwl_sc_trans_cfg)}, #endif /* CONFIG_IWLMVM */ {0} @@ -1115,15 +1119,24 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, iwl_cfg_sc, iwl_sc_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC2, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + iwl_cfg_sc2, iwl_sc2_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC2F, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + iwl_cfg_sc2f, iwl_sc2f_name), #endif /* CONFIG_IWLMVM */ }; /* * Read rf id and cdb info from prph register and store it */ -static int get_crf_id(struct iwl_trans *iwl_trans) +static void get_crf_id(struct iwl_trans *iwl_trans) { - int ret = 0; u32 sd_reg_ver_addr; u32 val = 0; @@ -1150,8 +1163,6 @@ static int get_crf_id(struct iwl_trans *iwl_trans) IWL_INFO(iwl_trans, "Detected crf-id 0x%x, cnv-id 0x%x wfpm id 0x%x\n", iwl_trans->hw_crf_id, iwl_trans->hw_cnv_id, iwl_trans->hw_wfpm_id); - - return ret; } /* diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 07931c2db4..9c2461ba13 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1351,8 +1351,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, if (len < sizeof(*pkt) || offset > max_len) break; - trace_iwlwifi_dev_rx(trans->dev, trans, pkt, len); - trace_iwlwifi_dev_rx_data(trans->dev, trans, pkt, len); + maybe_trace_iwlwifi_dev_rx(trans, pkt, len); /* Reclaim a command buffer only if this packet is a response * to a (driver-originated) command. diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index c9e5bda8f0..a4a4772330 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -290,6 +290,16 @@ static void iwl_pcie_get_rf_name(struct iwl_trans *trans) case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_MS): pos = scnprintf(buf, buflen, "MS"); break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_FM): + pos = scnprintf(buf, buflen, "FM"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_WP): + if (SILICON_Z_STEP == + CSR_HW_RFID_STEP(trans->hw_rf_id)) + pos = scnprintf(buf, buflen, "WHTC"); + else + pos = scnprintf(buf, buflen, "WH"); + break; default: return; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index d10208075a..63e13577af 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2108,18 +2108,29 @@ static void iwl_trans_pcie_removal_wk(struct work_struct *wk) container_of(wk, struct iwl_trans_pcie_removal, work); struct pci_dev *pdev = removal->pdev; static char *prop[] = {"EVENT=INACCESSIBLE", NULL}; - struct pci_bus *bus = pdev->bus; + struct pci_bus *bus; + + pci_lock_rescan_remove(); + + bus = pdev->bus; + /* in this case, something else already removed the device */ + if (!bus) + goto out; dev_err(&pdev->dev, "Device gone - attempting removal\n"); + kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, prop); - pci_lock_rescan_remove(); - pci_dev_put(pdev); + pci_stop_and_remove_bus_device(pdev); - if (removal->rescan && bus) { + pci_dev_put(pdev); + + if (removal->rescan) { if (bus->parent) bus = bus->parent; pci_rescan_bus(bus); } + +out: pci_unlock_rescan_remove(); kfree(removal); @@ -2134,6 +2145,7 @@ void iwl_trans_pcie_remove(struct iwl_trans *trans, bool rescan) return; IWL_ERR(trans, "Device gone - scheduling removal!\n"); + iwl_pcie_dump_csr(trans); /* * get a module reference to avoid doing this @@ -2366,32 +2378,6 @@ static int iwl_trans_pcie_read_config32(struct iwl_trans *trans, u32 ofs, ofs, val); } -static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block) -{ - int i; - - for (i = 0; i < trans->trans_cfg->base_params->num_of_queues; i++) { - struct iwl_txq *txq = trans->txqs.txq[i]; - - if (i == trans->txqs.cmd.q_id) - continue; - - spin_lock_bh(&txq->lock); - - if (!block && !(WARN_ON_ONCE(!txq->block))) { - txq->block--; - if (!txq->block) { - iwl_write32(trans, HBUS_TARG_WRPTR, - txq->write_ptr | (i << 8)); - } - } else if (block) { - txq->block++; - } - - spin_unlock_bh(&txq->lock); - } -} - #define IWL_FLUSH_WAIT_MS 2000 static int iwl_trans_pcie_rxq_dma_data(struct iwl_trans *trans, int queue, @@ -3573,7 +3559,6 @@ static const struct iwl_trans_ops trans_ops_pcie = { .wait_tx_queues_empty = iwl_trans_pcie_wait_txqs_empty, .freeze_txq_timer = iwl_trans_txq_freeze_timer, - .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, #ifdef CONFIG_IWLWIFI_DEBUGFS .debugfs_cleanup = iwl_trans_pcie_debugfs_cleanup, #endif diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index c72a84d8bb..aabbef114b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2020, 2023 Intel Corporation */ #include <net/tso.h> #include <linux/tcp.h> @@ -42,6 +42,9 @@ int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, struct iwl_tfh_tfd *tfd; unsigned long flags; + if (WARN_ON(cmd->flags & CMD_BLOCK_TXQS)) + return -EINVAL; + copy_size = sizeof(struct iwl_cmd_header_wide); cmd_size = sizeof(struct iwl_cmd_header_wide); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 2f39b639c4..6c2b37e56c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -873,6 +873,33 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, /*************** HOST COMMAND QUEUE FUNCTIONS *****/ +static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block) +{ + int i; + + for (i = 0; i < trans->trans_cfg->base_params->num_of_queues; i++) { + struct iwl_txq *txq = trans->txqs.txq[i]; + + if (i == trans->txqs.cmd.q_id) + continue; + + /* we skip the command queue (obviously) so it's OK to nest */ + spin_lock_nested(&txq->lock, 1); + + if (!block && !(WARN_ON_ONCE(!txq->block))) { + txq->block--; + if (!txq->block) { + iwl_write32(trans, HBUS_TARG_WRPTR, + txq->write_ptr | (i << 8)); + } + } else if (block) { + txq->block++; + } + + spin_unlock(&txq->lock); + } +} + /* * iwl_pcie_enqueue_hcmd - enqueue a uCode command * @priv: device private data point @@ -1137,6 +1164,9 @@ int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, goto out; } + if (cmd->flags & CMD_BLOCK_TXQS) + iwl_trans_pcie_block_txq_ptrs(trans, true); + /* Increment and update queue's write index */ txq->write_ptr = iwl_txq_inc_wrap(trans, txq->write_ptr); iwl_pcie_txq_inc_wr_ptr(trans, txq); @@ -1202,8 +1232,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, meta->source->_rx_page_order = trans_pcie->rx_page_order; } - if (meta->flags & CMD_WANT_ASYNC_CALLBACK) - iwl_op_mode_async_cb(trans->op_mode, cmd); + if (meta->flags & CMD_BLOCK_TXQS) + iwl_trans_pcie_block_txq_ptrs(trans, false); iwl_pcie_cmdq_reclaim(trans, txq_id, index); diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig index bd6bf70ece..201b1534a9 100644 --- a/drivers/net/wireless/intersil/Kconfig +++ b/drivers/net/wireless/intersil/Kconfig @@ -12,8 +12,6 @@ config WLAN_VENDOR_INTERSIL if WLAN_VENDOR_INTERSIL -source "drivers/net/wireless/intersil/hostap/Kconfig" -source "drivers/net/wireless/intersil/orinoco/Kconfig" source "drivers/net/wireless/intersil/p54/Kconfig" endif # WLAN_VENDOR_INTERSIL diff --git a/drivers/net/wireless/intersil/Makefile b/drivers/net/wireless/intersil/Makefile index 65281d1b3d..27e9b2869d 100644 --- a/drivers/net/wireless/intersil/Makefile +++ b/drivers/net/wireless/intersil/Makefile @@ -1,4 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_HOSTAP) += hostap/ -obj-$(CONFIG_HERMES) += orinoco/ obj-$(CONFIG_P54_COMMON) += p54/ diff --git a/drivers/net/wireless/intersil/hostap/Kconfig b/drivers/net/wireless/intersil/hostap/Kconfig deleted file mode 100644 index 2edff8efbc..0000000000 --- a/drivers/net/wireless/intersil/hostap/Kconfig +++ /dev/null @@ -1,95 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config HOSTAP - tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select CRYPTO - select CRYPTO_MICHAEL_MIC - select CRC32 - select LIB80211 - select LIB80211_CRYPT_WEP - select LIB80211_CRYPT_TKIP - select LIB80211_CRYPT_CCMP - help - Shared driver code for IEEE 802.11b wireless cards based on - Intersil Prism2/2.5/3 chipset. This driver supports so called - Host AP mode that allows the card to act as an IEEE 802.11 - access point. - - See <http://hostap.epitest.fi/> for more information about the - Host AP driver configuration and tools. This site includes - information and tools (hostapd and wpa_supplicant) for WPA/WPA2 - support. - - This option includes the base Host AP driver code that is shared by - different hardware models. You will also need to enable support for - PLX/PCI/CS version of the driver to actually use the driver. - - The driver can be compiled as a module and it will be called - hostap. - -config HOSTAP_FIRMWARE - bool "Support downloading firmware images with Host AP driver" - depends on HOSTAP - help - Configure Host AP driver to include support for firmware image - download. This option by itself only enables downloading to the - volatile memory, i.e. the card RAM. This option is required to - support cards that don't have firmware in flash, such as D-Link - DWL-520 rev E and D-Link DWL-650 rev P. - - Firmware image downloading needs a user space tool, prism2_srec. - It is available from http://hostap.epitest.fi/. - -config HOSTAP_FIRMWARE_NVRAM - bool "Support for non-volatile firmware download" - depends on HOSTAP_FIRMWARE - help - Allow Host AP driver to write firmware images to the non-volatile - card memory, i.e. flash memory that survives power cycling. - Enable this option if you want to be able to change card firmware - permanently. - - Firmware image downloading needs a user space tool, prism2_srec. - It is available from http://hostap.epitest.fi/. - -config HOSTAP_PLX - tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors" - depends on PCI && HOSTAP && HAS_IOPORT - help - Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based - PCI adaptors. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_plx. - -config HOSTAP_PCI - tristate "Host AP driver for Prism2.5 PCI adaptors" - depends on PCI && HOSTAP - help - Host AP driver's version for Prism2.5 PCI adaptors. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_pci. - -config HOSTAP_CS - tristate "Host AP driver for Prism2/2.5/3 PC Cards" - depends on PCMCIA && HOSTAP - help - Host AP driver's version for Prism2/2.5/3 PC Cards. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_cs. diff --git a/drivers/net/wireless/intersil/hostap/Makefile b/drivers/net/wireless/intersil/hostap/Makefile deleted file mode 100644 index ae3bb73b2d..0000000000 --- a/drivers/net/wireless/intersil/hostap/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -hostap-y := hostap_80211_rx.o hostap_80211_tx.o hostap_ap.o hostap_info.o \ - hostap_ioctl.o hostap_main.o hostap_proc.o -obj-$(CONFIG_HOSTAP) += hostap.o - -obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o -obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o -obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o diff --git a/drivers/net/wireless/intersil/hostap/hostap.h b/drivers/net/wireless/intersil/hostap/hostap.h deleted file mode 100644 index 552ae33d78..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap.h +++ /dev/null @@ -1,98 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_H -#define HOSTAP_H - -#include <linux/ethtool.h> -#include <linux/kernel.h> - -#include "hostap_wlan.h" -#include "hostap_ap.h" - -static const long __maybe_unused freq_list[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 -}; -#define FREQ_COUNT ARRAY_SIZE(freq_list) - -/* hostap.c */ - -extern struct proc_dir_entry *hostap_proc; - -u16 hostap_tx_callback_register(local_info_t *local, - void (*func)(struct sk_buff *, int ok, void *), - void *data); -int hostap_tx_callback_unregister(local_info_t *local, u16 idx); -int hostap_set_word(struct net_device *dev, int rid, u16 val); -int hostap_set_string(struct net_device *dev, int rid, const char *val); -u16 hostap_get_porttype(local_info_t *local); -int hostap_set_encryption(local_info_t *local); -int hostap_set_antsel(local_info_t *local); -int hostap_set_roaming(local_info_t *local); -int hostap_set_auth_algs(local_info_t *local); -void hostap_dump_rx_header(const char *name, - const struct hfa384x_rx_frame *rx); -void hostap_dump_tx_header(const char *name, - const struct hfa384x_tx_frame *tx); -extern const struct header_ops hostap_80211_ops; -int hostap_80211_get_hdrlen(__le16 fc); -struct net_device_stats *hostap_get_stats(struct net_device *dev); -void hostap_setup_dev(struct net_device *dev, local_info_t *local, - int type); -void hostap_set_multicast_list_queue(struct work_struct *work); -int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); -int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked); -void hostap_cleanup(local_info_t *local); -void hostap_cleanup_handler(void *data); -struct net_device * hostap_add_interface(struct local_info *local, - int type, int rtnl_locked, - const char *prefix, const char *name); -void hostap_remove_interface(struct net_device *dev, int rtnl_locked, - int remove_from_list); -int prism2_update_comms_qual(struct net_device *dev); -int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, - u8 *body, size_t bodylen); -int prism2_sta_deauth(local_info_t *local, u16 reason); -int prism2_wds_add(local_info_t *local, u8 *remote_addr, - int rtnl_locked); -int prism2_wds_del(local_info_t *local, u8 *remote_addr, - int rtnl_locked, int do_not_remove); - - -/* hostap_ap.c */ - -int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac); -int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac); -void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); -int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac); -void ap_control_kickall(struct ap_data *ap); -void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct lib80211_crypt_data ***crypt); -int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], - struct iw_quality qual[], int buf_size, - int aplist); -int prism2_ap_translate_scan(struct net_device *dev, - struct iw_request_info *info, char *buffer); -int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param); - - -/* hostap_proc.c */ - -void hostap_init_proc(local_info_t *local); -void hostap_remove_proc(local_info_t *local); - - -/* hostap_info.c */ - -void hostap_info_init(local_info_t *local); -void hostap_info_process(local_info_t *local, struct sk_buff *skb); - - -/* hostap_ioctl.c */ - -extern const struct iw_handler_def hostap_iw_handler_def; -extern const struct ethtool_ops prism2_ethtool_ops; - -int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd); - -#endif /* HOSTAP_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211.h b/drivers/net/wireless/intersil/hostap/hostap_80211.h deleted file mode 100644 index 1452cf6ecb..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_80211.h +++ /dev/null @@ -1,97 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_80211_H -#define HOSTAP_80211_H - -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> - -struct hostap_ieee80211_mgmt { - __le16 frame_control; - __le16 duration; - u8 da[6]; - u8 sa[6]; - u8 bssid[6]; - __le16 seq_ctrl; - union { - struct { - __le16 auth_alg; - __le16 auth_transaction; - __le16 status_code; - /* possibly followed by Challenge text */ - u8 variable[0]; - } __packed auth; - struct { - __le16 reason_code; - } __packed deauth; - struct { - __le16 capab_info; - __le16 listen_interval; - /* followed by SSID and Supported rates */ - u8 variable[0]; - } __packed assoc_req; - struct { - __le16 capab_info; - __le16 status_code; - __le16 aid; - /* followed by Supported rates */ - u8 variable[0]; - } __packed assoc_resp, reassoc_resp; - struct { - __le16 capab_info; - __le16 listen_interval; - u8 current_ap[6]; - /* followed by SSID and Supported rates */ - u8 variable[0]; - } __packed reassoc_req; - struct { - __le16 reason_code; - } __packed disassoc; - struct { - } __packed probe_req; - struct { - u8 timestamp[8]; - __le16 beacon_int; - __le16 capab_info; - /* followed by some of SSID, Supported rates, - * FH Params, DS Params, CF Params, IBSS Params, TIM */ - u8 variable[0]; - } __packed beacon, probe_resp; - } u; -} __packed; - - -#define IEEE80211_MGMT_HDR_LEN 24 -#define IEEE80211_DATA_HDR3_LEN 24 -#define IEEE80211_DATA_HDR4_LEN 30 - - -struct hostap_80211_rx_status { - u32 mac_time; - u8 signal; - u8 noise; - u16 rate; /* in 100 kbps */ -}; - -/* prism2_rx_80211 'type' argument */ -enum { - PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC, - PRISM2_RX_NULLFUNC_ACK -}; - -int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, int type); -void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats); -void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats); - -void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); -netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, - struct net_device *dev); -netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, - struct net_device *dev); -netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, - struct net_device *dev); - -#endif /* HOSTAP_80211_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c deleted file mode 100644 index 61be822f90..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c +++ /dev/null @@ -1,1116 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/etherdevice.h> -#include <linux/slab.h> -#include <linux/export.h> -#include <net/lib80211.h> -#include <linux/if_arp.h> - -#include "hostap_80211.h" -#include "hostap.h" -#include "hostap_ap.h" - -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char rfc1042_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char bridge_tunnel_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -/* No encapsulation header if EtherType < 0x600 (=length) */ - -void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct ieee80211_hdr *hdr; - u16 fc; - - hdr = (struct ieee80211_hdr *) skb->data; - - printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " - "jiffies=%ld\n", - name, rx_stats->signal, rx_stats->noise, rx_stats->rate, - skb->len, jiffies); - - if (skb->len < 2) - return; - - fc = le16_to_cpu(hdr->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - if (skb->len < IEEE80211_DATA_HDR3_LEN) { - printk("\n"); - return; - } - - printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), - le16_to_cpu(hdr->seq_ctrl)); - - printk(KERN_DEBUG " A1=%pM", hdr->addr1); - printk(" A2=%pM", hdr->addr2); - printk(" A3=%pM", hdr->addr3); - if (skb->len >= 30) - printk(" A4=%pM", hdr->addr4); - printk("\n"); -} - - -/* Send RX frame to netif with 802.11 (and possible prism) header. - * Called from hardware or software IRQ context. */ -int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, int type) -{ - struct hostap_interface *iface; - local_info_t *local; - int hdrlen, phdrlen, head_need, tail_need; - u16 fc; - int prism_header, ret; - struct ieee80211_hdr *fhdr; - - iface = netdev_priv(dev); - local = iface->local; - - if (dev->type == ARPHRD_IEEE80211_PRISM) { - if (local->monitor_type == PRISM2_MONITOR_PRISM) { - prism_header = 1; - phdrlen = sizeof(struct linux_wlan_ng_prism_hdr); - } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */ - prism_header = 2; - phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); - } - } else if (dev->type == ARPHRD_IEEE80211_RADIOTAP) { - prism_header = 3; - phdrlen = sizeof(struct hostap_radiotap_rx); - } else { - prism_header = 0; - phdrlen = 0; - } - - fhdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(fhdr->frame_control); - - if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { - printk(KERN_DEBUG "%s: dropped management frame with header " - "version %d\n", dev->name, fc & IEEE80211_FCTL_VERS); - dev_kfree_skb_any(skb); - return 0; - } - - hdrlen = hostap_80211_get_hdrlen(fhdr->frame_control); - - /* check if there is enough room for extra data; if not, expand skb - * buffer to be large enough for the changes */ - head_need = phdrlen; - tail_need = 0; -#ifdef PRISM2_ADD_BOGUS_CRC - tail_need += 4; -#endif /* PRISM2_ADD_BOGUS_CRC */ - - head_need -= skb_headroom(skb); - tail_need -= skb_tailroom(skb); - - if (head_need > 0 || tail_need > 0) { - if (pskb_expand_head(skb, head_need > 0 ? head_need : 0, - tail_need > 0 ? tail_need : 0, - GFP_ATOMIC)) { - printk(KERN_DEBUG "%s: prism2_rx_80211 failed to " - "reallocate skb buffer\n", dev->name); - dev_kfree_skb_any(skb); - return 0; - } - } - - /* We now have an skb with enough head and tail room, so just insert - * the extra data */ - -#ifdef PRISM2_ADD_BOGUS_CRC - memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */ -#endif /* PRISM2_ADD_BOGUS_CRC */ - - if (prism_header == 1) { - struct linux_wlan_ng_prism_hdr *hdr; - hdr = skb_push(skb, phdrlen); - memset(hdr, 0, phdrlen); - hdr->msgcode = LWNG_CAP_DID_BASE; - hdr->msglen = sizeof(*hdr); - memcpy(hdr->devname, dev->name, sizeof(hdr->devname)); -#define LWNG_SETVAL(f,i,s,l,d) \ -hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \ -hdr->f.status = s; hdr->f.len = l; hdr->f.data = d - LWNG_SETVAL(hosttime, 1, 0, 4, jiffies); - LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time); - LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0); - LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0); - LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0); - LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal); - LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise); - LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5); - LWNG_SETVAL(istx, 9, 0, 4, 0); - LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen); -#undef LWNG_SETVAL - } else if (prism_header == 2) { - struct linux_wlan_ng_cap_hdr *hdr; - hdr = skb_push(skb, phdrlen); - memset(hdr, 0, phdrlen); - hdr->version = htonl(LWNG_CAPHDR_VERSION); - hdr->length = htonl(phdrlen); - hdr->mactime = __cpu_to_be64(rx_stats->mac_time); - hdr->hosttime = __cpu_to_be64(jiffies); - hdr->phytype = htonl(4); /* dss_dot11_b */ - hdr->channel = htonl(local->channel); - hdr->datarate = htonl(rx_stats->rate); - hdr->antenna = htonl(0); /* unknown */ - hdr->priority = htonl(0); /* unknown */ - hdr->ssi_type = htonl(3); /* raw */ - hdr->ssi_signal = htonl(rx_stats->signal); - hdr->ssi_noise = htonl(rx_stats->noise); - hdr->preamble = htonl(0); /* unknown */ - hdr->encoding = htonl(1); /* cck */ - } else if (prism_header == 3) { - struct hostap_radiotap_rx *hdr; - hdr = skb_push(skb, phdrlen); - memset(hdr, 0, phdrlen); - hdr->hdr.it_len = cpu_to_le16(phdrlen); - hdr->hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)); - hdr->tsft = cpu_to_le64(rx_stats->mac_time); - hdr->chan_freq = cpu_to_le16(freq_list[local->channel - 1]); - hdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ); - hdr->rate = rx_stats->rate / 5; - hdr->dbm_antsignal = rx_stats->signal; - hdr->dbm_antnoise = rx_stats->noise; - } - - ret = skb->len - phdrlen; - skb->dev = dev; - skb_reset_mac_header(skb); - skb_pull(skb, hdrlen); - if (prism_header) - skb_pull(skb, phdrlen); - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = cpu_to_be16(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -static void monitor_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - int len; - - len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR); - dev->stats.rx_packets++; - dev->stats.rx_bytes += len; -} - - -/* Called only as a tasklet (software IRQ) */ -static struct prism2_frag_entry * -prism2_frag_cache_find(local_info_t *local, unsigned int seq, - unsigned int frag, u8 *src, u8 *dst) -{ - struct prism2_frag_entry *entry; - int i; - - for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { - entry = &local->frag_cache[i]; - if (entry->skb != NULL && - time_after(jiffies, entry->first_frag_time + 2 * HZ)) { - printk(KERN_DEBUG "%s: expiring fragment cache entry " - "seq=%u last_frag=%u\n", - local->dev->name, entry->seq, entry->last_frag); - dev_kfree_skb(entry->skb); - entry->skb = NULL; - } - - if (entry->skb != NULL && entry->seq == seq && - (entry->last_frag + 1 == frag || frag == -1) && - memcmp(entry->src_addr, src, ETH_ALEN) == 0 && - memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) - return entry; - } - - return NULL; -} - - -/* Called only as a tasklet (software IRQ) */ -static struct sk_buff * -prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) -{ - struct sk_buff *skb = NULL; - u16 sc; - unsigned int frag, seq; - struct prism2_frag_entry *entry; - - sc = le16_to_cpu(hdr->seq_ctrl); - frag = sc & IEEE80211_SCTL_FRAG; - seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - - if (frag == 0) { - /* Reserve enough space to fit maximum frame length */ - skb = dev_alloc_skb(local->dev->mtu + - sizeof(struct ieee80211_hdr) + - 8 /* LLC */ + - 2 /* alignment */ + - 8 /* WEP */ + ETH_ALEN /* WDS */); - if (skb == NULL) - return NULL; - - entry = &local->frag_cache[local->frag_next_idx]; - local->frag_next_idx++; - if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN) - local->frag_next_idx = 0; - - if (entry->skb != NULL) - dev_kfree_skb(entry->skb); - - entry->first_frag_time = jiffies; - entry->seq = seq; - entry->last_frag = frag; - entry->skb = skb; - memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); - memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); - } else { - /* received a fragment of a frame for which the head fragment - * should have already been received */ - entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2, - hdr->addr1); - if (entry != NULL) { - entry->last_frag = frag; - skb = entry->skb; - } - } - - return skb; -} - - -/* Called only as a tasklet (software IRQ) */ -static int prism2_frag_cache_invalidate(local_info_t *local, - struct ieee80211_hdr *hdr) -{ - u16 sc; - unsigned int seq; - struct prism2_frag_entry *entry; - - sc = le16_to_cpu(hdr->seq_ctrl); - seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - - entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1); - - if (entry == NULL) { - printk(KERN_DEBUG "%s: could not invalidate fragment cache " - "entry (seq=%u)\n", - local->dev->name, seq); - return -1; - } - - entry->skb = NULL; - return 0; -} - - -static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid, - u8 *ssid, size_t ssid_len) -{ - struct list_head *ptr; - struct hostap_bss_info *bss; - - list_for_each(ptr, &local->bss_list) { - bss = list_entry(ptr, struct hostap_bss_info, list); - if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && - (ssid == NULL || - (ssid_len == bss->ssid_len && - memcmp(ssid, bss->ssid, ssid_len) == 0))) { - list_move(&bss->list, &local->bss_list); - return bss; - } - } - - return NULL; -} - - -static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid, - u8 *ssid, size_t ssid_len) -{ - struct hostap_bss_info *bss; - - if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) { - bss = list_entry(local->bss_list.prev, - struct hostap_bss_info, list); - list_del(&bss->list); - local->num_bss_info--; - } else { - bss = kmalloc(sizeof(*bss), GFP_ATOMIC); - if (bss == NULL) - return NULL; - } - - memset(bss, 0, sizeof(*bss)); - memcpy(bss->bssid, bssid, ETH_ALEN); - memcpy(bss->ssid, ssid, ssid_len); - bss->ssid_len = ssid_len; - local->num_bss_info++; - list_add(&bss->list, &local->bss_list); - return bss; -} - - -static void __hostap_expire_bss(local_info_t *local) -{ - struct hostap_bss_info *bss; - - while (local->num_bss_info > 0) { - bss = list_entry(local->bss_list.prev, - struct hostap_bss_info, list); - if (!time_after(jiffies, bss->last_update + 60 * HZ)) - break; - - list_del(&bss->list); - local->num_bss_info--; - kfree(bss); - } -} - - -/* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so - * the same routine can be used to parse both of them. */ -static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb, - int stype) -{ - struct hostap_ieee80211_mgmt *mgmt; - int left, chan = 0; - u8 *pos; - u8 *ssid = NULL, *wpa = NULL, *rsn = NULL; - size_t ssid_len = 0, wpa_len = 0, rsn_len = 0; - struct hostap_bss_info *bss; - - if (skb->len < IEEE80211_MGMT_HDR_LEN + sizeof(mgmt->u.beacon)) - return; - - mgmt = (struct hostap_ieee80211_mgmt *) skb->data; - pos = mgmt->u.beacon.variable; - left = skb->len - (pos - skb->data); - - while (left >= 2) { - if (2 + pos[1] > left) - return; /* parse failed */ - switch (*pos) { - case WLAN_EID_SSID: - ssid = pos + 2; - ssid_len = pos[1]; - break; - case WLAN_EID_VENDOR_SPECIFIC: - if (pos[1] >= 4 && - pos[2] == 0x00 && pos[3] == 0x50 && - pos[4] == 0xf2 && pos[5] == 1) { - wpa = pos; - wpa_len = pos[1] + 2; - } - break; - case WLAN_EID_RSN: - rsn = pos; - rsn_len = pos[1] + 2; - break; - case WLAN_EID_DS_PARAMS: - if (pos[1] >= 1) - chan = pos[2]; - break; - } - left -= 2 + pos[1]; - pos += 2 + pos[1]; - } - - if (wpa_len > MAX_WPA_IE_LEN) - wpa_len = MAX_WPA_IE_LEN; - if (rsn_len > MAX_WPA_IE_LEN) - rsn_len = MAX_WPA_IE_LEN; - if (ssid_len > sizeof(bss->ssid)) - ssid_len = sizeof(bss->ssid); - - spin_lock(&local->lock); - bss = __hostap_get_bss(local, mgmt->bssid, ssid, ssid_len); - if (bss == NULL) - bss = __hostap_add_bss(local, mgmt->bssid, ssid, ssid_len); - if (bss) { - bss->last_update = jiffies; - bss->count++; - bss->capab_info = le16_to_cpu(mgmt->u.beacon.capab_info); - if (wpa) { - memcpy(bss->wpa_ie, wpa, wpa_len); - bss->wpa_ie_len = wpa_len; - } else - bss->wpa_ie_len = 0; - if (rsn) { - memcpy(bss->rsn_ie, rsn, rsn_len); - bss->rsn_ie_len = rsn_len; - } else - bss->rsn_ie_len = 0; - bss->chan = chan; - } - __hostap_expire_bss(local); - spin_unlock(&local->lock); -} - - -static int -hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, u16 type, - u16 stype) -{ - if (local->iw_mode == IW_MODE_MASTER) - hostap_update_sta_ps(local, (struct ieee80211_hdr *) skb->data); - - if (local->hostapd && type == IEEE80211_FTYPE_MGMT) { - if (stype == IEEE80211_STYPE_BEACON && - local->iw_mode == IW_MODE_MASTER) { - struct sk_buff *skb2; - /* Process beacon frames also in kernel driver to - * update STA(AP) table statistics */ - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) - hostap_rx(skb2->dev, skb2, rx_stats); - } - - /* send management frames to the user space daemon for - * processing */ - local->apdevstats.rx_packets++; - local->apdevstats.rx_bytes += skb->len; - if (local->apdev == NULL) - return -1; - prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT); - return 0; - } - - if (local->iw_mode == IW_MODE_MASTER) { - if (type != IEEE80211_FTYPE_MGMT && - type != IEEE80211_FTYPE_CTL) { - printk(KERN_DEBUG "%s: unknown management frame " - "(type=0x%02x, stype=0x%02x) dropped\n", - skb->dev->name, type >> 2, stype >> 4); - return -1; - } - - hostap_rx(skb->dev, skb, rx_stats); - return 0; - } else if (type == IEEE80211_FTYPE_MGMT && - (stype == IEEE80211_STYPE_BEACON || - stype == IEEE80211_STYPE_PROBE_RESP)) { - hostap_rx_sta_beacon(local, skb, stype); - return -1; - } else if (type == IEEE80211_FTYPE_MGMT && - (stype == IEEE80211_STYPE_ASSOC_RESP || - stype == IEEE80211_STYPE_REASSOC_RESP)) { - /* Ignore (Re)AssocResp silently since these are not currently - * needed but are still received when WPA/RSN mode is enabled. - */ - return -1; - } else { - printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled" - " management frame in non-Host AP mode (type=%d:%d)\n", - skb->dev->name, type >> 2, stype >> 4); - return -1; - } -} - - -/* Called only as a tasklet (software IRQ) */ -static struct net_device *prism2_rx_get_wds(local_info_t *local, - u8 *addr) -{ - struct hostap_interface *iface = NULL; - struct list_head *ptr; - - read_lock_bh(&local->iface_lock); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_WDS && - memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0) - break; - iface = NULL; - } - read_unlock_bh(&local->iface_lock); - - return iface ? iface->dev : NULL; -} - - -static int -hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, u16 fc, - struct net_device **wds) -{ - /* FIX: is this really supposed to accept WDS frames only in Master - * mode? What about Repeater or Managed with WDS frames? */ - if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != - (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS) && - (local->iw_mode != IW_MODE_MASTER || !(fc & IEEE80211_FCTL_TODS))) - return 0; /* not a WDS frame */ - - /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS) - * or own non-standard frame with 4th address after payload */ - if (!ether_addr_equal(hdr->addr1, local->dev->dev_addr) && - (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff || - hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff || - hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { - /* RA (or BSSID) is not ours - drop */ - PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with " - "not own or broadcast %s=%pM\n", - local->dev->name, - fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", - hdr->addr1); - return -1; - } - - /* check if the frame came from a registered WDS connection */ - *wds = prism2_rx_get_wds(local, hdr->addr2); - if (*wds == NULL && fc & IEEE80211_FCTL_FROMDS && - (local->iw_mode != IW_MODE_INFRA || - !(local->wds_type & HOSTAP_WDS_AP_CLIENT) || - memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) { - /* require that WDS link has been registered with TA or the - * frame is from current AP when using 'AP client mode' */ - PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " - "from unknown TA=%pM\n", - local->dev->name, hdr->addr2); - if (local->ap && local->ap->autom_ap_wds) - hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); - return -1; - } - - if (*wds && !(fc & IEEE80211_FCTL_FROMDS) && local->ap && - hostap_is_sta_assoc(local->ap, hdr->addr2)) { - /* STA is actually associated with us even though it has a - * registered WDS link. Assume it is in 'AP client' mode. - * Since this is a 3-addr frame, assume it is not (bogus) WDS - * frame and process it like any normal ToDS frame from - * associated STA. */ - *wds = NULL; - } - - return 0; -} - - -static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) -{ - struct net_device *dev = local->dev; - u16 fc, ethertype; - struct ieee80211_hdr *hdr; - u8 *pos; - - if (skb->len < 24) - return 0; - - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - /* check that the frame is unicast frame to us */ - if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_TODS && - ether_addr_equal(hdr->addr1, dev->dev_addr) && - ether_addr_equal(hdr->addr3, dev->dev_addr)) { - /* ToDS frame with own addr BSSID and DA */ - } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_FROMDS && - ether_addr_equal(hdr->addr1, dev->dev_addr)) { - /* FromDS frame with own addr as DA */ - } else - return 0; - - if (skb->len < 24 + 8) - return 0; - - /* check for port access entity Ethernet type */ - pos = skb->data + 24; - ethertype = (pos[6] << 8) | pos[7]; - if (ethertype == ETH_P_PAE) - return 1; - - return 0; -} - - -/* Called only as a tasklet (software IRQ) */ -static int -hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, - struct lib80211_crypt_data *crypt) -{ - struct ieee80211_hdr *hdr; - int res, hdrlen; - - if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) - return 0; - - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - if (local->tkip_countermeasures && - strcmp(crypt->ops->name, "TKIP") == 0) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "received packet from %pM\n", - local->dev->name, hdr->addr2); - } - return -1; - } - - atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n", - local->dev->name, hdr->addr2, res); - local->comm_tallies.rx_discards_wep_undecryptable++; - return -1; - } - - return res; -} - - -/* Called only as a tasklet (software IRQ) */ -static int -hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, - int keyidx, struct lib80211_crypt_data *crypt) -{ - struct ieee80211_hdr *hdr; - int res, hdrlen; - - if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) - return 0; - - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=%pM keyidx=%d)\n", - local->dev->name, hdr->addr2, keyidx); - return -1; - } - - return 0; -} - - -/* All received frames are sent to this function. @skb contains the frame in - * IEEE 802.11 format, i.e., in the format it was sent over air. - * This function is called only as a tasklet (software IRQ). */ -void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - size_t hdrlen; - u16 fc, type, stype, sc; - struct net_device *wds = NULL; - unsigned int frag; - u8 *payload; - struct sk_buff *skb2 = NULL; - u16 ethertype; - int frame_authorized = 0; - int from_assoc_ap = 0; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - struct lib80211_crypt_data *crypt = NULL; - void *sta = NULL; - int keyidx = 0; - - iface = netdev_priv(dev); - local = iface->local; - iface->stats.rx_packets++; - iface->stats.rx_bytes += skb->len; - - /* dev is the master radio device; change this to be the default - * virtual interface (this may be changed to WDS device below) */ - dev = local->ddev; - iface = netdev_priv(dev); - - hdr = (struct ieee80211_hdr *) skb->data; - - if (skb->len < 10) - goto rx_dropped; - - fc = le16_to_cpu(hdr->frame_control); - type = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - sc = le16_to_cpu(hdr->seq_ctrl); - frag = sc & IEEE80211_SCTL_FRAG; - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - /* Put this code here so that we avoid duplicating it in all - * Rx paths. - Jean II */ -#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ - /* If spy monitoring on */ - if (iface->spy_data.spy_number > 0) { - struct iw_quality wstats; - wstats.level = rx_stats->signal; - wstats.noise = rx_stats->noise; - wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED - | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(dev, hdr->addr2, &wstats); - } -#endif /* IW_WIRELESS_SPY */ - hostap_update_rx_stats(local->ap, hdr, rx_stats); - - if (local->iw_mode == IW_MODE_MONITOR) { - monitor_rx(dev, skb, rx_stats); - return; - } - - if (local->host_decrypt) { - int idx = 0; - if (skb->len >= hdrlen + 3) - idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt_info.crypt[idx]; - sta = NULL; - - /* Use station specific key to override default keys if the - * receiver address is a unicast address ("individual RA"). If - * bcrx_sta_key parameter is set, station specific key is used - * even with broad/multicast targets (this is against IEEE - * 802.11, but makes it easier to use different keys with - * stations that do not support WEP key mapping). */ - - if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) - (void) hostap_handle_sta_crypto(local, hdr, &crypt, - &sta); - - /* allow NULL decrypt to indicate an station specific override - * for default encryption */ - if (crypt && (crypt->ops == NULL || - crypt->ops->decrypt_mpdu == NULL)) - crypt = NULL; - - if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) { -#if 0 - /* This seems to be triggered by some (multicast?) - * frames from other than current BSS, so just drop the - * frames silently instead of filling system log with - * these reports. */ - printk(KERN_DEBUG "%s: WEP decryption failed (not set)" - " (SA=%pM)\n", - local->dev->name, hdr->addr2); -#endif - local->comm_tallies.rx_discards_wep_undecryptable++; - goto rx_dropped; - } - } - - if (type != IEEE80211_FTYPE_DATA) { - if (type == IEEE80211_FTYPE_MGMT && - stype == IEEE80211_STYPE_AUTH && - fc & IEEE80211_FCTL_PROTECTED && local->host_decrypt && - (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) - { - printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from %pM\n", dev->name, hdr->addr2); - /* TODO: could inform hostapd about this so that it - * could send auth failure report */ - goto rx_dropped; - } - - if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype)) - goto rx_dropped; - else - goto rx_exit; - } - - /* Data frame - extract src/dst addresses */ - if (skb->len < IEEE80211_DATA_HDR3_LEN) - goto rx_dropped; - - switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { - case IEEE80211_FCTL_FROMDS: - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr3, ETH_ALEN); - break; - case IEEE80211_FCTL_TODS: - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - break; - case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - if (skb->len < IEEE80211_DATA_HDR4_LEN) - goto rx_dropped; - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr4, ETH_ALEN); - break; - default: - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - break; - } - - if (hostap_rx_frame_wds(local, hdr, fc, &wds)) - goto rx_dropped; - if (wds) - skb->dev = dev = wds; - - if (local->iw_mode == IW_MODE_MASTER && !wds && - (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_FROMDS && - local->stadev && - memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) { - /* Frame from BSSID of the AP for which we are a client */ - skb->dev = dev = local->stadev; - from_assoc_ap = 1; - } - - if ((local->iw_mode == IW_MODE_MASTER || - local->iw_mode == IW_MODE_REPEAT) && - !from_assoc_ap) { - switch (hostap_handle_sta_rx(local, dev, skb, rx_stats, - wds != NULL)) { - case AP_RX_CONTINUE_NOT_AUTHORIZED: - frame_authorized = 0; - break; - case AP_RX_CONTINUE: - frame_authorized = 1; - break; - case AP_RX_DROP: - goto rx_dropped; - case AP_RX_EXIT: - goto rx_exit; - } - } - - /* Nullfunc frames may have PS-bit set, so they must be passed to - * hostap_handle_sta_rx() before being dropped here. */ - if (stype != IEEE80211_STYPE_DATA && - stype != IEEE80211_STYPE_DATA_CFACK && - stype != IEEE80211_STYPE_DATA_CFPOLL && - stype != IEEE80211_STYPE_DATA_CFACKPOLL) { - if (stype != IEEE80211_STYPE_NULLFUNC) - printk(KERN_DEBUG "%s: RX: dropped data frame " - "with no data (type=0x%02x, subtype=0x%02x)\n", - dev->name, type >> 2, stype >> 4); - goto rx_dropped; - } - - /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ - - if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && - (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) - goto rx_dropped; - hdr = (struct ieee80211_hdr *) skb->data; - - /* skb: hdr + (possibly fragmented) plaintext payload */ - - if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && - (frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { - int flen; - struct sk_buff *frag_skb = - prism2_frag_cache_get(local, hdr); - if (!frag_skb) { - printk(KERN_DEBUG "%s: Rx cannot get skb from " - "fragment cache (morefrag=%d seq=%u frag=%u)\n", - dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0, - (sc & IEEE80211_SCTL_SEQ) >> 4, frag); - goto rx_dropped; - } - - flen = skb->len; - if (frag != 0) - flen -= hdrlen; - - if (frag_skb->tail + flen > frag_skb->end) { - printk(KERN_WARNING "%s: host decrypted and " - "reassembled frame did not fit skb\n", - dev->name); - prism2_frag_cache_invalidate(local, hdr); - goto rx_dropped; - } - - if (frag == 0) { - /* copy first fragment (including full headers) into - * beginning of the fragment cache skb */ - skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), - flen); - } else { - /* append frame payload to the end of the fragment - * cache skb */ - skb_copy_from_linear_data_offset(skb, hdrlen, - skb_put(frag_skb, - flen), flen); - } - dev_kfree_skb(skb); - skb = NULL; - - if (fc & IEEE80211_FCTL_MOREFRAGS) { - /* more fragments expected - leave the skb in fragment - * cache for now; it will be delivered to upper layers - * after all fragments have been received */ - goto rx_exit; - } - - /* this was the last fragment and the frame will be - * delivered, so remove skb from fragment cache */ - skb = frag_skb; - hdr = (struct ieee80211_hdr *) skb->data; - prism2_frag_cache_invalidate(local, hdr); - } - - /* skb: hdr + (possible reassembled) full MSDU payload; possibly still - * encrypted/authenticated */ - - if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && - hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) - goto rx_dropped; - - hdr = (struct ieee80211_hdr *) skb->data; - if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { - if (local->ieee_802_1x && - hostap_is_eapol_frame(local, skb)) { - /* pass unencrypted EAPOL frames even if encryption is - * configured */ - PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing " - "unencrypted EAPOL frame\n", local->dev->name); - } else { - printk(KERN_DEBUG "%s: encryption configured, but RX " - "frame not encrypted (SA=%pM)\n", - local->dev->name, hdr->addr2); - goto rx_dropped; - } - } - - if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) && - !hostap_is_eapol_frame(local, skb)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped unencrypted RX data " - "frame from %pM (drop_unencrypted=1)\n", - dev->name, hdr->addr2); - } - goto rx_dropped; - } - - /* skb: hdr + (possible reassembled) full plaintext payload */ - - payload = skb->data + hdrlen; - ethertype = (payload[6] << 8) | payload[7]; - - /* If IEEE 802.1X is used, check whether the port is authorized to send - * the received frame. */ - if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) { - if (ethertype == ETH_P_PAE) { - PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n", - dev->name); - if (local->hostapd && local->apdev) { - /* Send IEEE 802.1X frames to the user - * space daemon for processing */ - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_MGMT); - local->apdevstats.rx_packets++; - local->apdevstats.rx_bytes += skb->len; - goto rx_exit; - } - } else if (!frame_authorized) { - printk(KERN_DEBUG "%s: dropped frame from " - "unauthorized port (IEEE 802.1X): " - "ethertype=0x%04x\n", - dev->name, ethertype); - goto rx_dropped; - } - } - - /* convert hdr + possible LLC headers into Ethernet header */ - if (skb->len - hdrlen >= 8 && - ((memcmp(payload, rfc1042_header, 6) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - memcmp(payload, bridge_tunnel_header, 6) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType */ - skb_pull(skb, hdrlen + 6); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - __be16 len; - /* Leave Ethernet header part of hdr and full payload */ - skb_pull(skb, hdrlen); - len = htons(skb->len); - memcpy(skb_push(skb, 2), &len, 2); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } - - if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_TODS) && - skb->len >= ETH_HLEN + ETH_ALEN) { - /* Non-standard frame: get addr4 from its bogus location after - * the payload */ - skb_copy_from_linear_data_offset(skb, skb->len - ETH_ALEN, - skb->data + ETH_ALEN, - ETH_ALEN); - skb_trim(skb, skb->len - ETH_ALEN); - } - - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - if (local->iw_mode == IW_MODE_MASTER && !wds && - local->ap->bridge_packets) { - if (dst[0] & 0x01) { - /* copy multicast frame both to the higher layers and - * to the wireless media */ - local->ap->bridged_multicast++; - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2 == NULL) - printk(KERN_DEBUG "%s: skb_clone failed for " - "multicast frame\n", dev->name); - } else if (hostap_is_sta_authorized(local->ap, dst)) { - /* send frame directly to the associated STA using - * wireless media and not passing to higher layers */ - local->ap->bridged_unicast++; - skb2 = skb; - skb = NULL; - } - } - - if (skb2 != NULL) { - /* send to wireless media */ - skb2->dev = dev; - skb2->protocol = cpu_to_be16(ETH_P_802_3); - skb_reset_mac_header(skb2); - skb_reset_network_header(skb2); - /* skb2->network_header += ETH_HLEN; */ - dev_queue_xmit(skb2); - } - - if (skb) { - skb->protocol = eth_type_trans(skb, dev); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - } - - rx_exit: - if (sta) - hostap_handle_sta_release(sta); - return; - - rx_dropped: - dev_kfree_skb(skb); - - dev->stats.rx_dropped++; - goto rx_exit; -} - - -EXPORT_SYMBOL(hostap_80211_rx); diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c deleted file mode 100644 index c47da06945..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c +++ /dev/null @@ -1,554 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/slab.h> -#include <linux/export.h> -#include <linux/etherdevice.h> - -#include "hostap_80211.h" -#include "hostap_common.h" -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char rfc1042_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char bridge_tunnel_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -/* No encapsulation header if EtherType < 0x600 (=length) */ - -void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - u16 fc; - - hdr = (struct ieee80211_hdr *) skb->data; - - printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", - name, skb->len, jiffies); - - if (skb->len < 2) - return; - - fc = le16_to_cpu(hdr->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - if (skb->len < IEEE80211_DATA_HDR3_LEN) { - printk("\n"); - return; - } - - printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), - le16_to_cpu(hdr->seq_ctrl)); - - printk(KERN_DEBUG " A1=%pM", hdr->addr1); - printk(" A2=%pM", hdr->addr2); - printk(" A3=%pM", hdr->addr3); - if (skb->len >= 30) - printk(" A4=%pM", hdr->addr4); - printk("\n"); -} - - -/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta) - * Convert Ethernet header into a suitable IEEE 802.11 header depending on - * device configuration. */ -netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int need_headroom, need_tailroom = 0; - struct ieee80211_hdr hdr; - u16 fc, ethertype = 0; - enum { - WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME - } use_wds = WDS_NO; - u8 *encaps_data; - int hdr_len, encaps_len, skip_header_bytes; - int to_assoc_ap = 0; - struct hostap_skb_tx_data *meta; - - iface = netdev_priv(dev); - local = iface->local; - - if (skb->len < ETH_HLEN) { - printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb " - "(len=%d)\n", dev->name, skb->len); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - if (local->ddev != dev) { - use_wds = (local->iw_mode == IW_MODE_MASTER && - !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ? - WDS_OWN_FRAME : WDS_COMPLIANT_FRAME; - if (dev == local->stadev) { - to_assoc_ap = 1; - use_wds = WDS_NO; - } else if (dev == local->apdev) { - printk(KERN_DEBUG "%s: prism2_tx: trying to use " - "AP device with Ethernet net dev\n", dev->name); - kfree_skb(skb); - return NETDEV_TX_OK; - } - } else { - if (local->iw_mode == IW_MODE_REPEAT) { - printk(KERN_DEBUG "%s: prism2_tx: trying to use " - "non-WDS link in Repeater mode\n", dev->name); - kfree_skb(skb); - return NETDEV_TX_OK; - } else if (local->iw_mode == IW_MODE_INFRA && - (local->wds_type & HOSTAP_WDS_AP_CLIENT) && - !ether_addr_equal(skb->data + ETH_ALEN, dev->dev_addr)) { - /* AP client mode: send frames with foreign src addr - * using 4-addr WDS frames */ - use_wds = WDS_COMPLIANT_FRAME; - } - } - - /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload - * ==> - * Prism2 TX frame with 802.11 header: - * txdesc (address order depending on used mode; includes dst_addr and - * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel; - * proto[2], payload {, possible addr4[6]} */ - - ethertype = (skb->data[12] << 8) | skb->data[13]; - - memset(&hdr, 0, sizeof(hdr)); - - /* Length of data after IEEE 802.11 header */ - encaps_data = NULL; - encaps_len = 0; - skip_header_bytes = ETH_HLEN; - if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { - encaps_data = bridge_tunnel_header; - encaps_len = sizeof(bridge_tunnel_header); - skip_header_bytes -= 2; - } else if (ethertype >= 0x600) { - encaps_data = rfc1042_header; - encaps_len = sizeof(rfc1042_header); - skip_header_bytes -= 2; - } - - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; - hdr_len = IEEE80211_DATA_HDR3_LEN; - - if (use_wds != WDS_NO) { - /* Note! Prism2 station firmware has problems with sending real - * 802.11 frames with four addresses; until these problems can - * be fixed or worked around, 4-addr frames needed for WDS are - * using incompatible format: FromDS flag is not set and the - * fourth address is added after the frame payload; it is - * assumed, that the receiving station knows how to handle this - * frame format */ - - if (use_wds == WDS_COMPLIANT_FRAME) { - fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; - /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA, - * Addr4 = SA */ - skb_copy_from_linear_data_offset(skb, ETH_ALEN, - &hdr.addr4, ETH_ALEN); - hdr_len += ETH_ALEN; - } else { - /* bogus 4-addr format to workaround Prism2 station - * f/w bug */ - fc |= IEEE80211_FCTL_TODS; - /* From DS: Addr1 = DA (used as RA), - * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA), - */ - - /* SA from skb->data + ETH_ALEN will be added after - * frame payload; use hdr.addr4 as a temporary buffer - */ - skb_copy_from_linear_data_offset(skb, ETH_ALEN, - &hdr.addr4, ETH_ALEN); - need_tailroom += ETH_ALEN; - } - - /* send broadcast and multicast frames to broadcast RA, if - * configured; otherwise, use unicast RA of the WDS link */ - if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) && - is_multicast_ether_addr(skb->data)) - eth_broadcast_addr(hdr.addr1); - else if (iface->type == HOSTAP_INTERFACE_WDS) - memcpy(&hdr.addr1, iface->u.wds.remote_addr, - ETH_ALEN); - else - memcpy(&hdr.addr1, local->bssid, ETH_ALEN); - memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN); - } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) { - fc |= IEEE80211_FCTL_FROMDS; - /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */ - skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN); - memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3, - ETH_ALEN); - } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) { - fc |= IEEE80211_FCTL_TODS; - /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ - memcpy(&hdr.addr1, to_assoc_ap ? - local->assoc_ap_addr : local->bssid, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2, - ETH_ALEN); - skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN); - } else if (local->iw_mode == IW_MODE_ADHOC) { - /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ - skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2, - ETH_ALEN); - memcpy(&hdr.addr3, local->bssid, ETH_ALEN); - } - - hdr.frame_control = cpu_to_le16(fc); - - skb_pull(skb, skip_header_bytes); - need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len; - if (skb_tailroom(skb) < need_tailroom) { - skb = skb_unshare(skb, GFP_ATOMIC); - if (skb == NULL) { - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - if (pskb_expand_head(skb, need_headroom, need_tailroom, - GFP_ATOMIC)) { - kfree_skb(skb); - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - } else if (skb_headroom(skb) < need_headroom) { - struct sk_buff *tmp = skb; - skb = skb_realloc_headroom(skb, need_headroom); - kfree_skb(tmp); - if (skb == NULL) { - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - } else { - skb = skb_unshare(skb, GFP_ATOMIC); - if (skb == NULL) { - iface->stats.tx_dropped++; - return NETDEV_TX_OK; - } - } - - if (encaps_data) - memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); - memcpy(skb_push(skb, hdr_len), &hdr, hdr_len); - if (use_wds == WDS_OWN_FRAME) { - skb_put_data(skb, &hdr.addr4, ETH_ALEN); - } - - iface->stats.tx_packets++; - iface->stats.tx_bytes += skb->len; - - skb_reset_mac_header(skb); - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - if (use_wds) - meta->flags |= HOSTAP_TX_FLAGS_WDS; - meta->ethertype = ethertype; - meta->iface = iface; - - /* Send IEEE 802.11 encapsulated frame using the master radio device */ - skb->dev = local->dev; - dev_queue_xmit(skb); - return NETDEV_TX_OK; -} - - -/* hard_start_xmit function for hostapd wlan#ap interfaces */ -netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hostap_skb_tx_data *meta; - struct ieee80211_hdr *hdr; - u16 fc; - - iface = netdev_priv(dev); - local = iface->local; - - if (skb->len < 10) { - printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb " - "(len=%d)\n", dev->name, skb->len); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - iface->stats.tx_packets++; - iface->stats.tx_bytes += skb->len; - - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - meta->iface = iface; - - if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - if (ieee80211_is_data(hdr->frame_control) && - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DATA) { - u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN + - sizeof(rfc1042_header)]; - meta->ethertype = (pos[0] << 8) | pos[1]; - } - } - - /* Send IEEE 802.11 encapsulated frame using the master radio device */ - skb->dev = local->dev; - dev_queue_xmit(skb); - return NETDEV_TX_OK; -} - - -/* Called only from software IRQ */ -static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct lib80211_crypt_data *crypt) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - int prefix_len, postfix_len, hdr_len, res; - - iface = netdev_priv(skb->dev); - local = iface->local; - - if (skb->len < IEEE80211_DATA_HDR3_LEN) { - kfree_skb(skb); - return NULL; - } - - if (local->tkip_countermeasures && - strcmp(crypt->ops->name, "TKIP") == 0) { - hdr = (struct ieee80211_hdr *) skb->data; - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "TX packet to %pM\n", - local->dev->name, hdr->addr1); - } - kfree_skb(skb); - return NULL; - } - - skb = skb_unshare(skb, GFP_ATOMIC); - if (skb == NULL) - return NULL; - - prefix_len = crypt->ops->extra_mpdu_prefix_len + - crypt->ops->extra_msdu_prefix_len; - postfix_len = crypt->ops->extra_mpdu_postfix_len + - crypt->ops->extra_msdu_postfix_len; - if ((skb_headroom(skb) < prefix_len || - skb_tailroom(skb) < postfix_len) && - pskb_expand_head(skb, prefix_len, postfix_len, GFP_ATOMIC)) { - kfree_skb(skb); - return NULL; - } - - hdr = (struct ieee80211_hdr *) skb->data; - hdr_len = hostap_80211_get_hdrlen(hdr->frame_control); - - /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so - * call both MSDU and MPDU encryption functions from here. */ - atomic_inc(&crypt->refcnt); - res = 0; - if (crypt->ops->encrypt_msdu) - res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv); - if (res == 0 && crypt->ops->encrypt_mpdu) - res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - kfree_skb(skb); - return NULL; - } - - return skb; -} - - -/* hard_start_xmit function for master radio interface wifi#. - * AP processing (TX rate control, power save buffering, etc.). - * Use hardware TX function to send the frame. */ -netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - netdev_tx_t ret = NETDEV_TX_BUSY; - u16 fc; - struct hostap_tx_data tx; - ap_tx_ret tx_ret; - struct hostap_skb_tx_data *meta; - int no_encrypt = 0; - struct ieee80211_hdr *hdr; - - iface = netdev_priv(dev); - local = iface->local; - - tx.skb = skb; - tx.sta_ptr = NULL; - - meta = (struct hostap_skb_tx_data *) skb->cb; - if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { - printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " - "expected 0x%08x)\n", - dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - goto fail; - } - - if (local->host_encrypt) { - /* Set crypt to default algorithm and key; will be replaced in - * AP code if STA has own alg/key */ - tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx]; - tx.host_encrypt = 1; - } else { - tx.crypt = NULL; - tx.host_encrypt = 0; - } - - if (skb->len < 24) { - printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb " - "(len=%d)\n", dev->name, skb->len); - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - goto fail; - } - - /* FIX (?): - * Wi-Fi 802.11b test plan suggests that AP should ignore power save - * bit in authentication and (re)association frames and assume tha - * STA remains awake for the response. */ - tx_ret = hostap_handle_sta_tx(local, &tx); - skb = tx.skb; - meta = (struct hostap_skb_tx_data *) skb->cb; - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - switch (tx_ret) { - case AP_TX_CONTINUE: - break; - case AP_TX_CONTINUE_NOT_AUTHORIZED: - if (local->ieee_802_1x && - ieee80211_is_data(hdr->frame_control) && - meta->ethertype != ETH_P_PAE && - !(meta->flags & HOSTAP_TX_FLAGS_WDS)) { - printk(KERN_DEBUG "%s: dropped frame to unauthorized " - "port (IEEE 802.1X): ethertype=0x%04x\n", - dev->name, meta->ethertype); - hostap_dump_tx_80211(dev->name, skb); - - ret = NETDEV_TX_OK; /* drop packet */ - iface->stats.tx_dropped++; - goto fail; - } - break; - case AP_TX_DROP: - ret = NETDEV_TX_OK; /* drop packet */ - iface->stats.tx_dropped++; - goto fail; - case AP_TX_RETRY: - goto fail; - case AP_TX_BUFFERED: - /* do not free skb here, it will be freed when the - * buffered frame is sent/timed out */ - ret = NETDEV_TX_OK; - goto tx_exit; - } - - /* Request TX callback if protocol version is 2 in 802.11 header; - * this version 2 is a special case used between hostapd and kernel - * driver */ - if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) && - local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) { - meta->tx_cb_idx = local->ap->tx_callback_idx; - - /* remove special version from the frame header */ - fc &= ~IEEE80211_FCTL_VERS; - hdr->frame_control = cpu_to_le16(fc); - } - - if (!ieee80211_is_data(hdr->frame_control)) { - no_encrypt = 1; - tx.crypt = NULL; - } - - if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && - !(fc & IEEE80211_FCTL_PROTECTED)) { - no_encrypt = 1; - PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " - "unencrypted EAPOL frame\n", dev->name); - tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */ - } - - if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu)) - tx.crypt = NULL; - else if ((tx.crypt || - local->crypt_info.crypt[local->crypt_info.tx_keyidx]) && - !no_encrypt) { - /* Add ISWEP flag both for firmware and host based encryption - */ - fc |= IEEE80211_FCTL_PROTECTED; - hdr->frame_control = cpu_to_le16(fc); - } else if (local->drop_unencrypted && - ieee80211_is_data(hdr->frame_control) && - meta->ethertype != ETH_P_PAE) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped unencrypted TX data " - "frame (drop_unencrypted=1)\n", dev->name); - } - iface->stats.tx_dropped++; - ret = NETDEV_TX_OK; - goto fail; - } - - if (tx.crypt) { - skb = hostap_tx_encrypt(skb, tx.crypt); - if (skb == NULL) { - printk(KERN_DEBUG "%s: TX - encryption failed\n", - dev->name); - ret = NETDEV_TX_OK; - goto fail; - } - meta = (struct hostap_skb_tx_data *) skb->cb; - if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { - printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " - "expected 0x%08x) after hostap_tx_encrypt\n", - dev->name, meta->magic, - HOSTAP_SKB_TX_DATA_MAGIC); - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - goto fail; - } - } - - if (local->func->tx == NULL || local->func->tx(skb, dev)) { - ret = NETDEV_TX_OK; - iface->stats.tx_dropped++; - } else { - ret = NETDEV_TX_OK; - iface->stats.tx_packets++; - iface->stats.tx_bytes += skb->len; - } - - fail: - if (ret == NETDEV_TX_OK && skb) - dev_kfree_skb(skb); - tx_exit: - if (tx.sta_ptr) - hostap_handle_sta_release(tx.sta_ptr); - return ret; -} - - -EXPORT_SYMBOL(hostap_master_start_xmit); diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c deleted file mode 100644 index 9b546a71e7..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.c +++ /dev/null @@ -1,3277 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intersil Prism2 driver with Host AP (software access point) support - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * <j@w1.fi> - * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> - * - * This file is to be included into hostap.c when S/W AP functionality is - * compiled. - * - * AP: FIX: - * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from - * unauthenticated STA, send deauth. frame (8802.11: 5.5) - * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received - * from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5) - * - if unicast Class 3 received from unauthenticated STA, send deauth. frame - * (8802.11: 5.5) - */ - -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/delay.h> -#include <linux/random.h> -#include <linux/if_arp.h> -#include <linux/slab.h> -#include <linux/export.h> -#include <linux/moduleparam.h> -#include <linux/etherdevice.h> - -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL, - DEF_INTS }; -module_param_array(other_ap_policy, int, NULL, 0444); -MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)"); - -static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC, - DEF_INTS }; -module_param_array(ap_max_inactivity, int, NULL, 0444); -MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station " - "inactivity"); - -static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS }; -module_param_array(ap_bridge_packets, int, NULL, 0444); -MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between " - "stations"); - -static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS }; -module_param_array(autom_ap_wds, int, NULL, 0444); -MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs " - "automatically"); - - -static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta); -static void hostap_event_expired_sta(struct net_device *dev, - struct sta_info *sta); -static void handle_add_proc_queue(struct work_struct *work); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -static void handle_wds_oper_queue(struct work_struct *work); -static void prism2_send_mgmt(struct net_device *dev, - u16 type_subtype, char *body, - int body_len, u8 *addr, u16 tx_cb_idx); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS) -static int ap_debug_proc_show(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - - seq_printf(m, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); - seq_printf(m, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); - seq_printf(m, "max_inactivity=%u\n", ap->max_inactivity / HZ); - seq_printf(m, "bridge_packets=%u\n", ap->bridge_packets); - seq_printf(m, "nullfunc_ack=%u\n", ap->nullfunc_ack); - seq_printf(m, "autom_ap_wds=%u\n", ap->autom_ap_wds); - seq_printf(m, "auth_algs=%u\n", ap->local->auth_algs); - seq_printf(m, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc); - return 0; -} -#endif - -static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) -{ - sta->hnext = ap->sta_hash[STA_HASH(sta->addr)]; - ap->sta_hash[STA_HASH(sta->addr)] = sta; -} - -static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) -{ - struct sta_info *s; - - s = ap->sta_hash[STA_HASH(sta->addr)]; - if (s == NULL) return; - if (ether_addr_equal(s->addr, sta->addr)) { - ap->sta_hash[STA_HASH(sta->addr)] = s->hnext; - return; - } - - while (s->hnext != NULL && !ether_addr_equal(s->hnext->addr, sta->addr)) - s = s->hnext; - if (s->hnext != NULL) - s->hnext = s->hnext->hnext; - else - printk("AP: could not remove STA %pM from hash table\n", - sta->addr); -} - -static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) -{ - if (sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - - if (ap->proc != NULL) { - char name[20]; - sprintf(name, "%pM", sta->addr); - remove_proc_entry(name, ap->proc); - } - - if (sta->crypt) { - sta->crypt->ops->deinit(sta->crypt->priv); - kfree(sta->crypt); - sta->crypt = NULL; - } - - skb_queue_purge(&sta->tx_buf); - - ap->num_sta--; -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (sta->aid > 0) - ap->sta_aid[sta->aid - 1] = NULL; - - if (!sta->ap) - kfree(sta->u.sta.challenge); - timer_shutdown_sync(&sta->timer); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - kfree(sta); -} - - -static void hostap_set_tim(local_info_t *local, int aid, int set) -{ - if (local->func->set_tim) - local->func->set_tim(local->dev, aid, set); -} - - -static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta) -{ - union iwreq_data wrqu; - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL); -} - - -static void hostap_event_expired_sta(struct net_device *dev, - struct sta_info *sta) -{ - union iwreq_data wrqu; - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static void ap_handle_timer(struct timer_list *t) -{ - struct sta_info *sta = from_timer(sta, t, timer); - local_info_t *local; - struct ap_data *ap; - unsigned long next_time = 0; - int was_assoc; - - if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { - PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); - return; - } - - local = sta->local; - ap = local->ap; - was_assoc = sta->flags & WLAN_STA_ASSOC; - - if (atomic_read(&sta->users) != 0) - next_time = jiffies + HZ; - else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH)) - next_time = jiffies + ap->max_inactivity; - - if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) { - /* station activity detected; reset timeout state */ - sta->timeout_next = STA_NULLFUNC; - next_time = sta->last_rx + ap->max_inactivity; - } else if (sta->timeout_next == STA_DISASSOC && - !(sta->flags & WLAN_STA_PENDING_POLL)) { - /* STA ACKed data nullfunc frame poll */ - sta->timeout_next = STA_NULLFUNC; - next_time = jiffies + ap->max_inactivity; - } - - if (next_time) { - sta->timer.expires = next_time; - add_timer(&sta->timer); - return; - } - - if (sta->ap) - sta->timeout_next = STA_DEAUTH; - - if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) { - spin_lock(&ap->sta_table_lock); - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - spin_unlock(&ap->sta_table_lock); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - } else if (sta->timeout_next == STA_DISASSOC) - sta->flags &= ~WLAN_STA_ASSOC; - - if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(local->dev, sta); - - if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 && - !skb_queue_empty(&sta->tx_buf)) { - hostap_set_tim(local, sta->aid, 0); - sta->flags &= ~WLAN_STA_TIM; - } - - if (sta->ap) { - if (ap->autom_ap_wds) { - PDEBUG(DEBUG_AP, "%s: removing automatic WDS " - "connection to AP %pM\n", - local->dev->name, sta->addr); - hostap_wds_link_oper(local, sta->addr, WDS_DEL); - } - } else if (sta->timeout_next == STA_NULLFUNC) { - /* send data frame to poll STA and check whether this frame - * is ACKed */ - /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but - * it is apparently not retried so TX Exc events are not - * received for it */ - sta->flags |= WLAN_STA_PENDING_POLL; - prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_DATA, NULL, 0, - sta->addr, ap->tx_callback_poll); - } else { - int deauth = sta->timeout_next == STA_DEAUTH; - __le16 resp; - PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM" - "(last=%lu, jiffies=%lu)\n", - local->dev->name, - deauth ? "deauthentication" : "disassociation", - sta->addr, sta->last_rx, jiffies); - - resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); - prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT | - (deauth ? IEEE80211_STYPE_DEAUTH : - IEEE80211_STYPE_DISASSOC), - (char *) &resp, 2, sta->addr, 0); - } - - if (sta->timeout_next == STA_DEAUTH) { - if (sta->flags & WLAN_STA_PERM) { - PDEBUG(DEBUG_AP, "%s: STA %pM" - " would have been removed, " - "but it has 'perm' flag\n", - local->dev->name, sta->addr); - } else - ap_free_sta(ap, sta); - return; - } - - if (sta->timeout_next == STA_NULLFUNC) { - sta->timeout_next = STA_DISASSOC; - sta->timer.expires = jiffies + AP_DISASSOC_DELAY; - } else { - sta->timeout_next = STA_DEAUTH; - sta->timer.expires = jiffies + AP_DEAUTH_DELAY; - } - - add_timer(&sta->timer); -} - - -void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, - int resend) -{ - u8 addr[ETH_ALEN]; - __le16 resp; - int i; - - PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name); - eth_broadcast_addr(addr); - - resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); - - /* deauth message sent; try to resend it few times; the message is - * broadcast, so it may be delayed until next DTIM; there is not much - * else we can do at this point since the driver is going to be shut - * down */ - for (i = 0; i < 5; i++) { - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_DEAUTH, - (char *) &resp, 2, addr, 0); - - if (!resend || ap->num_sta <= 0) - return; - - mdelay(50); - } -} - - -static int ap_control_proc_show(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - char *policy_txt; - struct mac_entry *entry; - - if (v == SEQ_START_TOKEN) { - switch (ap->mac_restrictions.policy) { - case MAC_POLICY_OPEN: - policy_txt = "open"; - break; - case MAC_POLICY_ALLOW: - policy_txt = "allow"; - break; - case MAC_POLICY_DENY: - policy_txt = "deny"; - break; - default: - policy_txt = "unknown"; - break; - } - seq_printf(m, "MAC policy: %s\n", policy_txt); - seq_printf(m, "MAC entries: %u\n", ap->mac_restrictions.entries); - seq_puts(m, "MAC list:\n"); - return 0; - } - - entry = v; - seq_printf(m, "%pM\n", entry->addr); - return 0; -} - -static void *ap_control_proc_start(struct seq_file *m, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_lock_bh(&ap->mac_restrictions.lock); - return seq_list_start_head(&ap->mac_restrictions.mac_list, *_pos); -} - -static void *ap_control_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - return seq_list_next(v, &ap->mac_restrictions.mac_list, _pos); -} - -static void ap_control_proc_stop(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_unlock_bh(&ap->mac_restrictions.lock); -} - -static const struct seq_operations ap_control_proc_seqops = { - .start = ap_control_proc_start, - .next = ap_control_proc_next, - .stop = ap_control_proc_stop, - .show = ap_control_proc_show, -}; - -int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac) -{ - struct mac_entry *entry; - - entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL); - if (entry == NULL) - return -ENOMEM; - - memcpy(entry->addr, mac, ETH_ALEN); - - spin_lock_bh(&mac_restrictions->lock); - list_add_tail(&entry->list, &mac_restrictions->mac_list); - mac_restrictions->entries++; - spin_unlock_bh(&mac_restrictions->lock); - - return 0; -} - - -int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac) -{ - struct list_head *ptr; - struct mac_entry *entry; - - spin_lock_bh(&mac_restrictions->lock); - for (ptr = mac_restrictions->mac_list.next; - ptr != &mac_restrictions->mac_list; ptr = ptr->next) { - entry = list_entry(ptr, struct mac_entry, list); - - if (ether_addr_equal(entry->addr, mac)) { - list_del(ptr); - kfree(entry); - mac_restrictions->entries--; - spin_unlock_bh(&mac_restrictions->lock); - return 0; - } - } - spin_unlock_bh(&mac_restrictions->lock); - return -1; -} - - -static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, - u8 *mac) -{ - struct mac_entry *entry; - int found = 0; - - if (mac_restrictions->policy == MAC_POLICY_OPEN) - return 0; - - spin_lock_bh(&mac_restrictions->lock); - list_for_each_entry(entry, &mac_restrictions->mac_list, list) { - if (ether_addr_equal(entry->addr, mac)) { - found = 1; - break; - } - } - spin_unlock_bh(&mac_restrictions->lock); - - if (mac_restrictions->policy == MAC_POLICY_ALLOW) - return !found; - else - return found; -} - - -void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) -{ - struct list_head *ptr, *n; - struct mac_entry *entry; - - if (mac_restrictions->entries == 0) - return; - - spin_lock_bh(&mac_restrictions->lock); - for (ptr = mac_restrictions->mac_list.next, n = ptr->next; - ptr != &mac_restrictions->mac_list; - ptr = n, n = ptr->next) { - entry = list_entry(ptr, struct mac_entry, list); - list_del(ptr); - kfree(entry); - } - mac_restrictions->entries = 0; - spin_unlock_bh(&mac_restrictions->lock); -} - - -int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac) -{ - struct sta_info *sta; - __le16 resp; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, mac); - if (sta) { - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -EINVAL; - - resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH, - (char *) &resp, 2, sta->addr, 0); - - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(dev, sta); - - ap_free_sta(ap, sta); - - return 0; -} - -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -void ap_control_kickall(struct ap_data *ap) -{ - struct list_head *ptr, *n; - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list; - ptr = n, n = ptr->next) { - sta = list_entry(ptr, struct sta_info, list); - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - ap_free_sta(ap, sta); - } - spin_unlock_bh(&ap->sta_table_lock); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static int prism2_ap_proc_show(struct seq_file *m, void *v) -{ - struct sta_info *sta = v; - int i; - - if (v == SEQ_START_TOKEN) { - seq_printf(m, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); - return 0; - } - - if (!sta->ap) - return 0; - - seq_printf(m, "%pM %d %d %d %d '", - sta->addr, - sta->u.ap.channel, sta->last_rx_signal, - sta->last_rx_silence, sta->last_rx_rate); - - for (i = 0; i < sta->u.ap.ssid_len; i++) { - if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) - seq_putc(m, sta->u.ap.ssid[i]); - else - seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); - } - - seq_putc(m, '\''); - if (sta->capability & WLAN_CAPABILITY_ESS) - seq_puts(m, " [ESS]"); - if (sta->capability & WLAN_CAPABILITY_IBSS) - seq_puts(m, " [IBSS]"); - if (sta->capability & WLAN_CAPABILITY_PRIVACY) - seq_puts(m, " [WEP]"); - seq_putc(m, '\n'); - return 0; -} - -static void *prism2_ap_proc_start(struct seq_file *m, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_lock_bh(&ap->sta_table_lock); - return seq_list_start_head(&ap->sta_list, *_pos); -} - -static void *prism2_ap_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - return seq_list_next(v, &ap->sta_list, _pos); -} - -static void prism2_ap_proc_stop(struct seq_file *m, void *v) -{ - struct ap_data *ap = pde_data(file_inode(m->file)); - spin_unlock_bh(&ap->sta_table_lock); -} - -static const struct seq_operations prism2_ap_proc_seqops = { - .start = prism2_ap_proc_start, - .next = prism2_ap_proc_next, - .stop = prism2_ap_proc_stop, - .show = prism2_ap_proc_show, -}; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver) -{ - if (!ap) - return; - - if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) { - PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - " - "firmware upgrade recommended\n"); - ap->nullfunc_ack = 1; - } else - ap->nullfunc_ack = 0; - - if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) { - printk(KERN_WARNING "%s: Warning: secondary station firmware " - "version 1.4.2 does not seem to work in Host AP mode\n", - ap->local->dev->name); - } -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct ieee80211_hdr *hdr; - - if (!ap->local->hostapd || !ap->local->apdev) { - dev_kfree_skb(skb); - return; - } - - /* Pass the TX callback frame to the hostapd; use 802.11 header version - * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ - - hdr = (struct ieee80211_hdr *) skb->data; - hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_VERS); - hdr->frame_control |= cpu_to_le16(ok ? BIT(1) : BIT(0)); - - skb->dev = ap->local->apdev; - skb_pull(skb, hostap_80211_get_hdrlen(hdr->frame_control)); - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = cpu_to_be16(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -/* Called only as a tasklet (software IRQ) */ -static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; - u16 auth_alg, auth_transaction, status; - __le16 *pos; - struct sta_info *sta = NULL; - char *txt = NULL; - - if (ap->local->hostapd) { - dev_kfree_skb(skb); - return; - } - - hdr = (struct ieee80211_hdr *) skb->data; - if (!ieee80211_is_auth(hdr->frame_control) || - skb->len < IEEE80211_MGMT_HDR_LEN + 6) { - printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " - "frame\n", dev->name); - dev_kfree_skb(skb); - return; - } - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - auth_alg = le16_to_cpu(*pos++); - auth_transaction = le16_to_cpu(*pos++); - status = le16_to_cpu(*pos++); - - if (!ok) { - txt = "frame was not ACKed"; - goto done; - } - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr1); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&ap->sta_table_lock); - - if (!sta) { - txt = "STA not found"; - goto done; - } - - if (status == WLAN_STATUS_SUCCESS && - ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || - (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { - txt = "STA authenticated"; - sta->flags |= WLAN_STA_AUTH; - sta->last_auth = jiffies; - } else if (status != WLAN_STATUS_SUCCESS) - txt = "authentication failed"; - - done: - if (sta) - atomic_dec(&sta->users); - if (txt) { - PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d " - "trans#=%d status=%d - %s\n", - dev->name, hdr->addr1, - auth_alg, auth_transaction, status, txt); - } - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; - u16 status; - __le16 *pos; - struct sta_info *sta = NULL; - char *txt = NULL; - - if (ap->local->hostapd) { - dev_kfree_skb(skb); - return; - } - - hdr = (struct ieee80211_hdr *) skb->data; - if ((!ieee80211_is_assoc_resp(hdr->frame_control) && - !ieee80211_is_reassoc_resp(hdr->frame_control)) || - skb->len < IEEE80211_MGMT_HDR_LEN + 4) { - printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " - "frame\n", dev->name); - dev_kfree_skb(skb); - return; - } - - if (!ok) { - txt = "frame was not ACKed"; - goto done; - } - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr1); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&ap->sta_table_lock); - - if (!sta) { - txt = "STA not found"; - goto done; - } - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - pos++; - status = le16_to_cpu(*pos++); - if (status == WLAN_STATUS_SUCCESS) { - if (!(sta->flags & WLAN_STA_ASSOC)) - hostap_event_new_sta(dev, sta); - txt = "STA associated"; - sta->flags |= WLAN_STA_ASSOC; - sta->last_assoc = jiffies; - } else - txt = "association failed"; - - done: - if (sta) - atomic_dec(&sta->users); - if (txt) { - PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n", - dev->name, hdr->addr1, txt); - } - dev_kfree_skb(skb); -} - -/* Called only as a tasklet (software IRQ); TX callback for poll frames used - * in verifying whether the STA is still present. */ -static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) -{ - struct ap_data *ap = data; - struct ieee80211_hdr *hdr; - struct sta_info *sta; - - if (skb->len < 24) - goto fail; - hdr = (struct ieee80211_hdr *) skb->data; - if (ok) { - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr1); - if (sta) - sta->flags &= ~WLAN_STA_PENDING_POLL; - spin_unlock(&ap->sta_table_lock); - } else { - PDEBUG(DEBUG_AP, - "%s: STA %pM did not ACK activity poll frame\n", - ap->local->dev->name, hdr->addr1); - } - - fail: - dev_kfree_skb(skb); -} -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -void hostap_init_data(local_info_t *local) -{ - struct ap_data *ap = local->ap; - - if (ap == NULL) { - printk(KERN_WARNING "hostap_init_data: ap == NULL\n"); - return; - } - memset(ap, 0, sizeof(struct ap_data)); - ap->local = local; - - ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx); - ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx); - ap->max_inactivity = - GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ; - ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx); - - spin_lock_init(&ap->sta_table_lock); - INIT_LIST_HEAD(&ap->sta_list); - - /* Initialize task queue structure for AP management */ - INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue); - - ap->tx_callback_idx = - hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); - if (ap->tx_callback_idx == 0) - printk(KERN_WARNING "%s: failed to register TX callback for " - "AP\n", local->dev->name); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue); - - ap->tx_callback_auth = - hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); - ap->tx_callback_assoc = - hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap); - ap->tx_callback_poll = - hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap); - if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 || - ap->tx_callback_poll == 0) - printk(KERN_WARNING "%s: failed to register TX callback for " - "AP\n", local->dev->name); - - spin_lock_init(&ap->mac_restrictions.lock); - INIT_LIST_HEAD(&ap->mac_restrictions.mac_list); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - ap->initialized = 1; -} - - -void hostap_init_ap_proc(local_info_t *local) -{ - struct ap_data *ap = local->ap; - - ap->proc = local->proc; - if (ap->proc == NULL) - return; - -#ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_single_data("ap_debug", 0, ap->proc, ap_debug_proc_show, ap); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - proc_create_seq_data("ap_control", 0, ap->proc, &ap_control_proc_seqops, - ap); - proc_create_seq_data("ap", 0, ap->proc, &prism2_ap_proc_seqops, ap); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -} - - -void hostap_free_data(struct ap_data *ap) -{ - struct sta_info *n, *sta; - - if (ap == NULL || !ap->initialized) { - printk(KERN_DEBUG "hostap_free_data: ap has not yet been " - "initialized - skip resource freeing\n"); - return; - } - - flush_work(&ap->add_sta_proc_queue); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - flush_work(&ap->wds_oper_queue); - if (ap->crypt) - ap->crypt->deinit(ap->crypt_priv); - ap->crypt = ap->crypt_priv = NULL; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - list_for_each_entry_safe(sta, n, &ap->sta_list, list) { - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - ap_free_sta(ap, sta); - } - -#ifndef PRISM2_NO_PROCFS_DEBUG - if (ap->proc != NULL) { - remove_proc_entry("ap_debug", ap->proc); - } -#endif /* PRISM2_NO_PROCFS_DEBUG */ - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (ap->proc != NULL) { - remove_proc_entry("ap", ap->proc); - remove_proc_entry("ap_control", ap->proc); - } - ap_control_flush_macs(&ap->mac_restrictions); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - ap->initialized = 0; -} - - -/* caller should have mutex for AP STA list handling */ -static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta) -{ - struct sta_info *s; - - s = ap->sta_hash[STA_HASH(sta)]; - while (s != NULL && !ether_addr_equal(s->addr, sta)) - s = s->hnext; - return s; -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -/* Called from timer handler and from scheduled AP queue handlers */ -static void prism2_send_mgmt(struct net_device *dev, - u16 type_subtype, char *body, - int body_len, u8 *addr, u16 tx_cb_idx) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - u16 fc; - struct sk_buff *skb; - struct hostap_skb_tx_data *meta; - int hdrlen; - - iface = netdev_priv(dev); - local = iface->local; - dev = local->dev; /* always use master radio device */ - iface = netdev_priv(dev); - - if (!(dev->flags & IFF_UP)) { - PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - " - "cannot send frame\n", dev->name); - return; - } - - skb = dev_alloc_skb(sizeof(*hdr) + body_len); - if (skb == NULL) { - PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate " - "skb\n", dev->name); - return; - } - - fc = type_subtype; - hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype)); - hdr = skb_put_zero(skb, hdrlen); - if (body) - skb_put_data(skb, body, body_len); - - /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 - * tx_control instead of using local->tx_control */ - - - memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ - if (ieee80211_is_data(hdr->frame_control)) { - fc |= IEEE80211_FCTL_FROMDS; - memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ - memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ - } else if (ieee80211_is_ctl(hdr->frame_control)) { - /* control:ACK does not have addr2 or addr3 */ - eth_zero_addr(hdr->addr2); - eth_zero_addr(hdr->addr3); - } else { - memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */ - memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ - } - - hdr->frame_control = cpu_to_le16(fc); - - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - meta->iface = iface; - meta->tx_cb_idx = tx_cb_idx; - - skb->dev = dev; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - dev_queue_xmit(skb); -} -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -#ifdef CONFIG_PROC_FS -static int prism2_sta_proc_show(struct seq_file *m, void *v) -{ - struct sta_info *sta = m->private; - int i; - - /* FIX: possible race condition.. the STA data could have just expired, - * but proc entry was still here so that the read could have started; - * some locking should be done here.. */ - - seq_printf(m, - "%s=%pM\nusers=%d\naid=%d\n" - "flags=0x%04x%s%s%s%s%s%s%s\n" - "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", - sta->ap ? "AP" : "STA", - sta->addr, atomic_read(&sta->users), sta->aid, - sta->flags, - sta->flags & WLAN_STA_AUTH ? " AUTH" : "", - sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", - sta->flags & WLAN_STA_PS ? " PS" : "", - sta->flags & WLAN_STA_TIM ? " TIM" : "", - sta->flags & WLAN_STA_PERM ? " PERM" : "", - sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", - sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", - sta->capability, sta->listen_interval); - /* supported_rates: 500 kbit/s units with msb ignored */ - for (i = 0; i < sizeof(sta->supported_rates); i++) - if (sta->supported_rates[i] != 0) - seq_printf(m, "%d%sMbps ", - (sta->supported_rates[i] & 0x7f) / 2, - sta->supported_rates[i] & 1 ? ".5" : ""); - seq_printf(m, - "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" - "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" - "tx_packets=%lu\n" - "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" - "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" - "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" - "tx[11M]=%d\n" - "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", - jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, - sta->last_tx, - sta->rx_packets, sta->tx_packets, sta->rx_bytes, - sta->tx_bytes, skb_queue_len(&sta->tx_buf), - sta->last_rx_silence, - sta->last_rx_signal, sta->last_rx_rate / 10, - sta->last_rx_rate % 10 ? ".5" : "", - sta->tx_rate, sta->tx_count[0], sta->tx_count[1], - sta->tx_count[2], sta->tx_count[3], sta->rx_count[0], - sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); - if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats) - sta->crypt->ops->print_stats(m, sta->crypt->priv); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (sta->ap) { - if (sta->u.ap.channel >= 0) - seq_printf(m, "channel=%d\n", sta->u.ap.channel); - seq_puts(m, "ssid="); - for (i = 0; i < sta->u.ap.ssid_len; i++) { - if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) - seq_putc(m, sta->u.ap.ssid[i]); - else - seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); - } - seq_putc(m, '\n'); - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - return 0; -} -#endif - -static void handle_add_proc_queue(struct work_struct *work) -{ - struct ap_data *ap = container_of(work, struct ap_data, - add_sta_proc_queue); - struct sta_info *sta; - char name[20]; - struct add_sta_proc_data *entry, *prev; - - entry = ap->add_sta_proc_entries; - ap->add_sta_proc_entries = NULL; - - while (entry) { - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, entry->addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (sta) { - sprintf(name, "%pM", sta->addr); - sta->proc = proc_create_single_data( - name, 0, ap->proc, - prism2_sta_proc_show, sta); - - atomic_dec(&sta->users); - } - - prev = entry; - entry = entry->next; - kfree(prev); - } -} - - -static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr) -{ - struct sta_info *sta; - - sta = kzalloc(sizeof(struct sta_info), GFP_ATOMIC); - if (sta == NULL) { - PDEBUG(DEBUG_AP, "AP: kmalloc failed\n"); - return NULL; - } - - /* initialize STA info data */ - sta->local = ap->local; - skb_queue_head_init(&sta->tx_buf); - memcpy(sta->addr, addr, ETH_ALEN); - - atomic_inc(&sta->users); - spin_lock_bh(&ap->sta_table_lock); - list_add(&sta->list, &ap->sta_list); - ap->num_sta++; - ap_sta_hash_add(ap, sta); - spin_unlock_bh(&ap->sta_table_lock); - - if (ap->proc) { - struct add_sta_proc_data *entry; - /* schedule a non-interrupt context process to add a procfs - * entry for the STA since procfs code use GFP_KERNEL */ - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (entry) { - memcpy(entry->addr, sta->addr, ETH_ALEN); - entry->next = ap->add_sta_proc_entries; - ap->add_sta_proc_entries = entry; - schedule_work(&ap->add_sta_proc_queue); - } else - printk(KERN_DEBUG "Failed to add STA proc data\n"); - } - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - timer_setup(&sta->timer, ap_handle_timer, 0); - sta->timer.expires = jiffies + ap->max_inactivity; - if (!ap->local->hostapd) - add_timer(&sta->timer); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - return sta; -} - - -static int ap_tx_rate_ok(int rateidx, struct sta_info *sta, - local_info_t *local) -{ - if (rateidx > sta->tx_max_rate || - !(sta->tx_supp_rates & (1 << rateidx))) - return 0; - - if (local->tx_rate_control != 0 && - !(local->tx_rate_control & (1 << rateidx))) - return 0; - - return 1; -} - - -static void prism2_check_tx_rates(struct sta_info *sta) -{ - int i; - - sta->tx_supp_rates = 0; - for (i = 0; i < sizeof(sta->supported_rates); i++) { - if ((sta->supported_rates[i] & 0x7f) == 2) - sta->tx_supp_rates |= WLAN_RATE_1M; - if ((sta->supported_rates[i] & 0x7f) == 4) - sta->tx_supp_rates |= WLAN_RATE_2M; - if ((sta->supported_rates[i] & 0x7f) == 11) - sta->tx_supp_rates |= WLAN_RATE_5M5; - if ((sta->supported_rates[i] & 0x7f) == 22) - sta->tx_supp_rates |= WLAN_RATE_11M; - } - sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0; - if (sta->tx_supp_rates & WLAN_RATE_1M) { - sta->tx_max_rate = 0; - if (ap_tx_rate_ok(0, sta, sta->local)) { - sta->tx_rate = 10; - sta->tx_rate_idx = 0; - } - } - if (sta->tx_supp_rates & WLAN_RATE_2M) { - sta->tx_max_rate = 1; - if (ap_tx_rate_ok(1, sta, sta->local)) { - sta->tx_rate = 20; - sta->tx_rate_idx = 1; - } - } - if (sta->tx_supp_rates & WLAN_RATE_5M5) { - sta->tx_max_rate = 2; - if (ap_tx_rate_ok(2, sta, sta->local)) { - sta->tx_rate = 55; - sta->tx_rate_idx = 2; - } - } - if (sta->tx_supp_rates & WLAN_RATE_11M) { - sta->tx_max_rate = 3; - if (ap_tx_rate_ok(3, sta, sta->local)) { - sta->tx_rate = 110; - sta->tx_rate_idx = 3; - } - } -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static void ap_crypt_init(struct ap_data *ap) -{ - ap->crypt = lib80211_get_crypto_ops("WEP"); - - if (ap->crypt) { - if (ap->crypt->init) { - ap->crypt_priv = ap->crypt->init(0); - if (ap->crypt_priv == NULL) - ap->crypt = NULL; - else { - u8 key[WEP_KEY_LEN]; - get_random_bytes(key, WEP_KEY_LEN); - ap->crypt->set_key(key, WEP_KEY_LEN, NULL, - ap->crypt_priv); - } - } - } - - if (ap->crypt == NULL) { - printk(KERN_WARNING "AP could not initialize WEP: load module " - "lib80211_crypt_wep.ko\n"); - } -} - - -/* Generate challenge data for shared key authentication. IEEE 802.11 specifies - * that WEP algorithm is used for generating challenge. This should be unique, - * but otherwise there is not really need for randomness etc. Initialize WEP - * with pseudo random key and then use increasing IV to get unique challenge - * streams. - * - * Called only as a scheduled task for pending AP frames. - */ -static char * ap_auth_make_challenge(struct ap_data *ap) -{ - char *tmpbuf; - struct sk_buff *skb; - - if (ap->crypt == NULL) { - ap_crypt_init(ap); - if (ap->crypt == NULL) - return NULL; - } - - tmpbuf = kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC); - if (tmpbuf == NULL) { - PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n"); - return NULL; - } - - skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + - ap->crypt->extra_mpdu_prefix_len + - ap->crypt->extra_mpdu_postfix_len); - if (skb == NULL) { - kfree(tmpbuf); - return NULL; - } - - skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); - skb_put_zero(skb, WLAN_AUTH_CHALLENGE_LEN); - if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { - dev_kfree_skb(skb); - kfree(tmpbuf); - return NULL; - } - - skb_copy_from_linear_data_offset(skb, ap->crypt->extra_mpdu_prefix_len, - tmpbuf, WLAN_AUTH_CHALLENGE_LEN); - dev_kfree_skb(skb); - - return tmpbuf; -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_authen(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - size_t hdrlen; - struct ap_data *ap = local->ap; - char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; - int len, olen; - u16 auth_alg, auth_transaction, status_code; - __le16 *pos; - u16 resp = WLAN_STATUS_SUCCESS; - struct sta_info *sta = NULL; - struct lib80211_crypt_data *crypt; - char *txt = ""; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); - - if (len < 6) { - PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " - "(len=%d) from %pM\n", dev->name, len, hdr->addr2); - return; - } - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta && sta->crypt) - crypt = sta->crypt; - else { - int idx = 0; - if (skb->len >= hdrlen + 3) - idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt_info.crypt[idx]; - } - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - auth_alg = __le16_to_cpu(*pos); - pos++; - auth_transaction = __le16_to_cpu(*pos); - pos++; - status_code = __le16_to_cpu(*pos); - pos++; - - if (ether_addr_equal(dev->dev_addr, hdr->addr2) || - ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) { - txt = "authentication denied"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - if (((local->auth_algs & PRISM2_AUTH_OPEN) && - auth_alg == WLAN_AUTH_OPEN) || - ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) && - crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) { - } else { - txt = "unsupported algorithm"; - resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; - goto fail; - } - - if (len >= 8) { - u8 *u = (u8 *) pos; - if (*u == WLAN_EID_CHALLENGE) { - if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) { - txt = "invalid challenge len"; - resp = WLAN_STATUS_CHALLENGE_FAIL; - goto fail; - } - if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) { - txt = "challenge underflow"; - resp = WLAN_STATUS_CHALLENGE_FAIL; - goto fail; - } - challenge = (char *) (u + 2); - } - } - - if (sta && sta->ap) { - if (time_after(jiffies, sta->u.ap.last_beacon + - (10 * sta->listen_interval * HZ) / 1024)) { - PDEBUG(DEBUG_AP, "%s: no beacons received for a while," - " assuming AP %pM is now STA\n", - dev->name, sta->addr); - sta->ap = 0; - sta->flags = 0; - sta->u.sta.challenge = NULL; - } else { - txt = "AP trying to authenticate?"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - } - - if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) || - (auth_alg == WLAN_AUTH_SHARED_KEY && - (auth_transaction == 1 || - (auth_transaction == 3 && sta != NULL && - sta->u.sta.challenge != NULL)))) { - } else { - txt = "unknown authentication transaction number"; - resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; - goto fail; - } - - if (sta == NULL) { - txt = "new STA"; - - if (local->ap->num_sta >= MAX_STA_COUNT) { - /* FIX: might try to remove some old STAs first? */ - txt = "no more room for new STAs"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - sta = ap_add_sta(local->ap, hdr->addr2); - if (sta == NULL) { - txt = "ap_add_sta failed"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - } - - switch (auth_alg) { - case WLAN_AUTH_OPEN: - txt = "authOK"; - /* IEEE 802.11 standard is not completely clear about - * whether STA is considered authenticated after - * authentication OK frame has been send or after it - * has been ACKed. In order to reduce interoperability - * issues, mark the STA authenticated before ACK. */ - sta->flags |= WLAN_STA_AUTH; - break; - - case WLAN_AUTH_SHARED_KEY: - if (auth_transaction == 1) { - if (sta->u.sta.challenge == NULL) { - sta->u.sta.challenge = - ap_auth_make_challenge(local->ap); - if (sta->u.sta.challenge == NULL) { - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - } - } else { - if (sta->u.sta.challenge == NULL || - challenge == NULL || - memcmp(sta->u.sta.challenge, challenge, - WLAN_AUTH_CHALLENGE_LEN) != 0 || - !ieee80211_has_protected(hdr->frame_control)) { - txt = "challenge response incorrect"; - resp = WLAN_STATUS_CHALLENGE_FAIL; - goto fail; - } - - txt = "challenge OK - authOK"; - /* IEEE 802.11 standard is not completely clear about - * whether STA is considered authenticated after - * authentication OK frame has been send or after it - * has been ACKed. In order to reduce interoperability - * issues, mark the STA authenticated before ACK. */ - sta->flags |= WLAN_STA_AUTH; - kfree(sta->u.sta.challenge); - sta->u.sta.challenge = NULL; - } - break; - } - - fail: - pos = (__le16 *) body; - *pos = cpu_to_le16(auth_alg); - pos++; - *pos = cpu_to_le16(auth_transaction + 1); - pos++; - *pos = cpu_to_le16(resp); /* status_code */ - pos++; - olen = 6; - - if (resp == WLAN_STATUS_SUCCESS && sta != NULL && - sta->u.sta.challenge != NULL && - auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) { - u8 *tmp = (u8 *) pos; - *tmp++ = WLAN_EID_CHALLENGE; - *tmp++ = WLAN_AUTH_CHALLENGE_LEN; - pos++; - memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN); - olen += 2 + WLAN_AUTH_CHALLENGE_LEN; - } - - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH, - body, olen, hdr->addr2, ap->tx_callback_auth); - - if (sta) { - sta->last_rx = jiffies; - atomic_dec(&sta->users); - } - - if (resp) { - PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d " - "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", - dev->name, hdr->addr2, - auth_alg, auth_transaction, status_code, len, - le16_to_cpu(hdr->frame_control), resp, txt); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_assoc(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, int reassoc) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char body[12], *p, *lpos; - int len, left; - __le16 *pos; - u16 resp = WLAN_STATUS_SUCCESS; - struct sta_info *sta = NULL; - int send_deauth = 0; - char __always_unused *txt = ""; - u8 prev_ap[ETH_ALEN]; - - left = len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < (reassoc ? 10 : 4)) { - PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " - "(len=%d, reassoc=%d) from %pM\n", - dev->name, len, reassoc, hdr->addr2); - return; - } - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { - spin_unlock_bh(&local->ap->sta_table_lock); - txt = "trying to associate before authentication"; - send_deauth = 1; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - sta = NULL; /* do not decrement sta->users */ - goto fail; - } - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); - sta->capability = __le16_to_cpu(*pos); - pos++; left -= 2; - sta->listen_interval = __le16_to_cpu(*pos); - pos++; left -= 2; - - if (reassoc) { - memcpy(prev_ap, pos, ETH_ALEN); - pos++; pos++; pos++; left -= 6; - } else - eth_zero_addr(prev_ap); - - if (left >= 2) { - unsigned int ileft; - unsigned char *u = (unsigned char *) pos; - - if (*u == WLAN_EID_SSID) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft > MAX_SSID_LEN) { - txt = "SSID overflow"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - if (ileft != strlen(local->essid) || - memcmp(local->essid, u, ileft) != 0) { - txt = "not our SSID"; - resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC; - goto fail; - } - - u += ileft; - left -= ileft; - } - - if (left >= 2 && *u == WLAN_EID_SUPP_RATES) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft == 0 || - ileft > WLAN_SUPP_RATES_MAX) { - txt = "SUPP_RATES len error"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - memset(sta->supported_rates, 0, - sizeof(sta->supported_rates)); - memcpy(sta->supported_rates, u, ileft); - prism2_check_tx_rates(sta); - - u += ileft; - left -= ileft; - } - - if (left > 0) { - PDEBUG(DEBUG_AP, "%s: assoc from %pM" - " with extra data (%d bytes) [", - dev->name, hdr->addr2, left); - while (left > 0) { - PDEBUG2(DEBUG_AP, "<%02x>", *u); - u++; left--; - } - PDEBUG2(DEBUG_AP, "]\n"); - } - } else { - txt = "frame underflow"; - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - /* get a unique AID */ - if (sta->aid > 0) - txt = "OK, old AID"; - else { - spin_lock_bh(&local->ap->sta_table_lock); - for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) - if (local->ap->sta_aid[sta->aid - 1] == NULL) - break; - if (sta->aid > MAX_AID_TABLE_SIZE) { - sta->aid = 0; - spin_unlock_bh(&local->ap->sta_table_lock); - resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - txt = "no room for more AIDs"; - } else { - local->ap->sta_aid[sta->aid - 1] = sta; - spin_unlock_bh(&local->ap->sta_table_lock); - txt = "OK, new AID"; - } - } - - fail: - pos = (__le16 *) body; - - if (send_deauth) { - *pos = cpu_to_le16(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); - pos++; - } else { - /* FIX: CF-Pollable and CF-PollReq should be set to match the - * values in beacons/probe responses */ - /* FIX: how about privacy and WEP? */ - /* capability */ - *pos = cpu_to_le16(WLAN_CAPABILITY_ESS); - pos++; - - /* status_code */ - *pos = cpu_to_le16(resp); - pos++; - - *pos = cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | - BIT(14) | BIT(15)); /* AID */ - pos++; - - /* Supported rates (Information element) */ - p = (char *) pos; - *p++ = WLAN_EID_SUPP_RATES; - lpos = p; - *p++ = 0; /* len */ - if (local->tx_rate_control & WLAN_RATE_1M) { - *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02; - (*lpos)++; - } - if (local->tx_rate_control & WLAN_RATE_2M) { - *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04; - (*lpos)++; - } - if (local->tx_rate_control & WLAN_RATE_5M5) { - *p++ = local->basic_rates & WLAN_RATE_5M5 ? - 0x8b : 0x0b; - (*lpos)++; - } - if (local->tx_rate_control & WLAN_RATE_11M) { - *p++ = local->basic_rates & WLAN_RATE_11M ? - 0x96 : 0x16; - (*lpos)++; - } - pos = (__le16 *) p; - } - - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | - (send_deauth ? IEEE80211_STYPE_DEAUTH : - (reassoc ? IEEE80211_STYPE_REASSOC_RESP : - IEEE80211_STYPE_ASSOC_RESP)), - body, (u8 *) pos - (u8 *) body, - hdr->addr2, - send_deauth ? 0 : local->ap->tx_callback_assoc); - - if (sta) { - if (resp == WLAN_STATUS_SUCCESS) { - sta->last_rx = jiffies; - /* STA will be marked associated from TX callback, if - * AssocResp is ACKed */ - } - atomic_dec(&sta->users); - } - -#if 0 - PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d " - "prev_ap=%pM) => %d(%d) (%s)\n", - dev->name, - hdr->addr2, - reassoc ? "re" : "", len, - prev_ap, - resp, send_deauth, txt); -#endif -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_deauth(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); - int len; - u16 reason_code; - __le16 *pos; - struct sta_info *sta = NULL; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < 2) { - printk("handle_deauth - too short payload (len=%d)\n", len); - return; - } - - pos = (__le16 *) body; - reason_code = le16_to_cpu(*pos); - - PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, " - "reason_code=%d\n", dev->name, hdr->addr2, - len, reason_code); - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta != NULL) { - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(local->dev, sta); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - } - spin_unlock_bh(&local->ap->sta_table_lock); - if (sta == NULL) { - printk("%s: deauthentication from %pM, " - "reason_code=%d, but STA not authenticated\n", dev->name, - hdr->addr2, reason_code); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_disassoc(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char *body = skb->data + IEEE80211_MGMT_HDR_LEN; - int len; - u16 reason_code; - __le16 *pos; - struct sta_info *sta = NULL; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < 2) { - printk("handle_disassoc - too short payload (len=%d)\n", len); - return; - } - - pos = (__le16 *) body; - reason_code = le16_to_cpu(*pos); - - PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, " - "reason_code=%d\n", dev->name, hdr->addr2, - len, reason_code); - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta != NULL) { - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) - hostap_event_expired_sta(local->dev, sta); - sta->flags &= ~WLAN_STA_ASSOC; - } - spin_unlock_bh(&local->ap->sta_table_lock); - if (sta == NULL) { - printk("%s: disassociation from %pM, " - "reason_code=%d, but STA not authenticated\n", - dev->name, hdr->addr2, reason_code); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void ap_handle_data_nullfunc(local_info_t *local, - struct ieee80211_hdr *hdr) -{ - struct net_device *dev = local->dev; - - /* some STA f/w's seem to require control::ACK frame for - * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does - * not send this.. - * send control::ACK for the data::nullfunc */ - - printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n"); - prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK, - NULL, 0, hdr->addr2, 0); -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void ap_handle_dropped_data(local_info_t *local, - struct ieee80211_hdr *hdr) -{ - struct net_device *dev = local->dev; - struct sta_info *sta; - __le16 reason; - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) { - PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n"); - atomic_dec(&sta->users); - return; - } - - reason = cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | - ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? - IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC), - (char *) &reason, sizeof(reason), hdr->addr2, 0); - - if (sta) - atomic_dec(&sta->users); -} - -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -/* Called only as a scheduled task for pending AP frames. */ -static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, - struct sk_buff *skb) -{ - struct hostap_skb_tx_data *meta; - - if (!(sta->flags & WLAN_STA_PS)) { - /* Station has moved to non-PS mode, so send all buffered - * frames using normal device queue. */ - dev_queue_xmit(skb); - return; - } - - /* add a flag for hostap_handle_sta_tx() to know that this skb should - * be passed through even though STA is using PS */ - meta = (struct hostap_skb_tx_data *) skb->cb; - meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME; - if (!skb_queue_empty(&sta->tx_buf)) { - /* indicate to STA that more frames follow */ - meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA; - } - dev_queue_xmit(skb); -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_pspoll(local_info_t *local, - struct ieee80211_hdr *hdr, - struct hostap_80211_rx_status *rx_stats) -{ - struct net_device *dev = local->dev; - struct sta_info *sta; - u16 aid; - struct sk_buff *skb; - - PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n", - hdr->addr1, hdr->addr2, !!ieee80211_has_pm(hdr->frame_control)); - - if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { - PDEBUG(DEBUG_AP, - "handle_pspoll - addr1(BSSID)=%pM not own MAC\n", - hdr->addr1); - return; - } - - aid = le16_to_cpu(hdr->duration_id); - if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { - PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); - return; - } - aid &= ~(BIT(15) | BIT(14)); - if (aid == 0 || aid > MAX_AID_TABLE_SIZE) { - PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid); - return; - } - PDEBUG(DEBUG_PS2, " aid=%d\n", aid); - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta == NULL) { - PDEBUG(DEBUG_PS, " STA not found\n"); - return; - } - if (sta->aid != aid) { - PDEBUG(DEBUG_PS, " received aid=%i does not match with " - "assoc.aid=%d\n", aid, sta->aid); - return; - } - - /* FIX: todo: - * - add timeout for buffering (clear aid in TIM vector if buffer timed - * out (expiry time must be longer than ListenInterval for - * the corresponding STA; "8802-11: 11.2.1.9 AP aging function" - * - what to do, if buffered, pspolled, and sent frame is not ACKed by - * sta; store buffer for later use and leave TIM aid bit set? use - * TX event to check whether frame was ACKed? - */ - - while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) { - /* send buffered frame .. */ - PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL" - " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf)); - - pspoll_send_buffered(local, sta, skb); - - if (sta->flags & WLAN_STA_PS) { - /* send only one buffered packet per PS Poll */ - /* FIX: should ignore further PS Polls until the - * buffered packet that was just sent is acknowledged - * (Tx or TxExc event) */ - break; - } - } - - if (skb_queue_empty(&sta->tx_buf)) { - /* try to clear aid from TIM */ - if (!(sta->flags & WLAN_STA_TIM)) - PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n", - aid); - hostap_set_tim(local, aid, 0); - sta->flags &= ~WLAN_STA_TIM; - } - - atomic_dec(&sta->users); -} - - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - -static void handle_wds_oper_queue(struct work_struct *work) -{ - struct ap_data *ap = container_of(work, struct ap_data, - wds_oper_queue); - local_info_t *local = ap->local; - struct wds_oper_data *entry, *prev; - - spin_lock_bh(&local->lock); - entry = local->ap->wds_oper_entries; - local->ap->wds_oper_entries = NULL; - spin_unlock_bh(&local->lock); - - while (entry) { - PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " - "to AP %pM\n", - local->dev->name, - entry->type == WDS_ADD ? "adding" : "removing", - entry->addr); - if (entry->type == WDS_ADD) - prism2_wds_add(local, entry->addr, 0); - else if (entry->type == WDS_DEL) - prism2_wds_del(local, entry->addr, 0, 1); - - prev = entry; - entry = entry->next; - kfree(prev); - } -} - - -/* Called only as a scheduled task for pending AP frames. */ -static void handle_beacon(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - char *body = skb->data + IEEE80211_MGMT_HDR_LEN; - int len, left; - u16 beacon_int, capability; - __le16 *pos; - char *ssid = NULL; - unsigned char *supp_rates = NULL; - int ssid_len = 0, supp_rates_len = 0; - struct sta_info *sta = NULL; - int new_sta = 0, channel = -1; - - len = skb->len - IEEE80211_MGMT_HDR_LEN; - - if (len < 8 + 2 + 2) { - printk(KERN_DEBUG "handle_beacon - too short payload " - "(len=%d)\n", len); - return; - } - - pos = (__le16 *) body; - left = len; - - /* Timestamp (8 octets) */ - pos += 4; left -= 8; - /* Beacon interval (2 octets) */ - beacon_int = le16_to_cpu(*pos); - pos++; left -= 2; - /* Capability information (2 octets) */ - capability = le16_to_cpu(*pos); - pos++; left -= 2; - - if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && - capability & WLAN_CAPABILITY_IBSS) - return; - - if (left >= 2) { - unsigned int ileft; - unsigned char *u = (unsigned char *) pos; - - if (*u == WLAN_EID_SSID) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft > MAX_SSID_LEN) { - PDEBUG(DEBUG_AP, "SSID: overflow\n"); - return; - } - - if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID && - (ileft != strlen(local->essid) || - memcmp(local->essid, u, ileft) != 0)) { - /* not our SSID */ - return; - } - - ssid = u; - ssid_len = ileft; - - u += ileft; - left -= ileft; - } - - if (*u == WLAN_EID_SUPP_RATES) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft == 0 || ileft > 8) { - PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n"); - return; - } - - supp_rates = u; - supp_rates_len = ileft; - - u += ileft; - left -= ileft; - } - - if (*u == WLAN_EID_DS_PARAMS) { - u++; left--; - ileft = *u; - u++; left--; - - if (ileft > left || ileft != 1) { - PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n"); - return; - } - - channel = *u; - - u += ileft; - left -= ileft; - } - } - - spin_lock_bh(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta != NULL) - atomic_inc(&sta->users); - spin_unlock_bh(&local->ap->sta_table_lock); - - if (sta == NULL) { - /* add new AP */ - new_sta = 1; - sta = ap_add_sta(local->ap, hdr->addr2); - if (sta == NULL) { - printk(KERN_INFO "prism2: kmalloc failed for AP " - "data structure\n"); - return; - } - hostap_event_new_sta(local->dev, sta); - - /* mark APs authentication and associated for pseudo ad-hoc - * style communication */ - sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; - - if (local->ap->autom_ap_wds) { - hostap_wds_link_oper(local, sta->addr, WDS_ADD); - } - } - - sta->ap = 1; - if (ssid) { - sta->u.ap.ssid_len = ssid_len; - memcpy(sta->u.ap.ssid, ssid, ssid_len); - sta->u.ap.ssid[ssid_len] = '\0'; - } else { - sta->u.ap.ssid_len = 0; - sta->u.ap.ssid[0] = '\0'; - } - sta->u.ap.channel = channel; - sta->rx_packets++; - sta->rx_bytes += len; - sta->u.ap.last_beacon = sta->last_rx = jiffies; - sta->capability = capability; - sta->listen_interval = beacon_int; - - atomic_dec(&sta->users); - - if (new_sta) { - memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); - memcpy(sta->supported_rates, supp_rates, supp_rates_len); - prism2_check_tx_rates(sta); - } -} - -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -/* Called only as a tasklet. */ -static void handle_ap_item(local_info_t *local, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - struct net_device *dev = local->dev; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - u16 fc, type, stype; - struct ieee80211_hdr *hdr; - - /* FIX: should give skb->len to handler functions and check that the - * buffer is long enough */ - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - type = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (!local->hostapd && type == IEEE80211_FTYPE_DATA) { - PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); - - if (!(fc & IEEE80211_FCTL_TODS) || - (fc & IEEE80211_FCTL_FROMDS)) { - if (stype == IEEE80211_STYPE_NULLFUNC) { - /* no ToDS nullfunc seems to be used to check - * AP association; so send reject message to - * speed up re-association */ - ap_handle_dropped_data(local, hdr); - goto done; - } - PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n", - fc); - goto done; - } - - if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM" - " not own MAC\n", hdr->addr1); - goto done; - } - - if (local->ap->nullfunc_ack && - stype == IEEE80211_STYPE_NULLFUNC) - ap_handle_data_nullfunc(local, hdr); - else - ap_handle_dropped_data(local, hdr); - goto done; - } - - if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) { - handle_beacon(local, skb, rx_stats); - goto done; - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) { - handle_pspoll(local, hdr, rx_stats); - goto done; - } - - if (local->hostapd) { - PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " - "subtype=0x%02x\n", type, stype); - goto done; - } - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (type != IEEE80211_FTYPE_MGMT) { - PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n"); - goto done; - } - - if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM" - " not own MAC\n", hdr->addr1); - goto done; - } - - if (!ether_addr_equal(hdr->addr3, dev->dev_addr)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM" - " not own MAC\n", hdr->addr3); - goto done; - } - - switch (stype) { - case IEEE80211_STYPE_ASSOC_REQ: - handle_assoc(local, skb, rx_stats, 0); - break; - case IEEE80211_STYPE_ASSOC_RESP: - PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n"); - break; - case IEEE80211_STYPE_REASSOC_REQ: - handle_assoc(local, skb, rx_stats, 1); - break; - case IEEE80211_STYPE_REASSOC_RESP: - PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n"); - break; - case IEEE80211_STYPE_ATIM: - PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n"); - break; - case IEEE80211_STYPE_DISASSOC: - handle_disassoc(local, skb, rx_stats); - break; - case IEEE80211_STYPE_AUTH: - handle_authen(local, skb, rx_stats); - break; - case IEEE80211_STYPE_DEAUTH: - handle_deauth(local, skb, rx_stats); - break; - default: - PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", - stype >> 4); - break; - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - done: - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -void hostap_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ieee80211_hdr *hdr; - - iface = netdev_priv(dev); - local = iface->local; - - if (skb->len < 16) - goto drop; - - dev->stats.rx_packets++; - - hdr = (struct ieee80211_hdr *) skb->data; - - if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && - ieee80211_is_beacon(hdr->frame_control)) - goto drop; - - skb->protocol = cpu_to_be16(ETH_P_HOSTAP); - handle_ap_item(local, skb, rx_stats); - return; - - drop: - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -static void schedule_packet_send(local_info_t *local, struct sta_info *sta) -{ - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - struct hostap_80211_rx_status rx_stats; - - if (skb_queue_empty(&sta->tx_buf)) - return; - - skb = dev_alloc_skb(16); - if (skb == NULL) { - printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc " - "failed\n", local->dev->name); - return; - } - - hdr = skb_put(skb, 16); - - /* Generate a fake pspoll frame to start packet delivery */ - hdr->frame_control = cpu_to_le16( - IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); - memcpy(hdr->addr2, sta->addr, ETH_ALEN); - hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); - - PDEBUG(DEBUG_PS2, - "%s: Scheduling buffered packet delivery for STA %pM\n", - local->dev->name, sta->addr); - - skb->dev = local->dev; - - memset(&rx_stats, 0, sizeof(rx_stats)); - hostap_rx(local->dev, skb, &rx_stats); -} - - -int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], - struct iw_quality qual[], int buf_size, - int aplist) -{ - struct ap_data *ap = local->ap; - struct list_head *ptr; - int count = 0; - - spin_lock_bh(&ap->sta_table_lock); - - for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; - ptr = ptr->next) { - struct sta_info *sta = (struct sta_info *) ptr; - - if (aplist && !sta->ap) - continue; - addr[count].sa_family = ARPHRD_ETHER; - memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); - if (sta->last_rx_silence == 0) - qual[count].qual = sta->last_rx_signal < 27 ? - 0 : (sta->last_rx_signal - 27) * 92 / 127; - else - qual[count].qual = sta->last_rx_signal - - sta->last_rx_silence - 35; - qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); - qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); - qual[count].updated = sta->last_rx_updated; - - sta->last_rx_updated = IW_QUAL_DBM; - - count++; - if (count >= buf_size) - break; - } - spin_unlock_bh(&ap->sta_table_lock); - - return count; -} - - -/* Translate our list of Access Points & Stations to a card independent - * format that the Wireless Tools will understand - Jean II */ -int prism2_ap_translate_scan(struct net_device *dev, - struct iw_request_info *info, char *buffer) -{ - struct hostap_interface *iface; - local_info_t *local; - struct ap_data *ap; - struct list_head *ptr; - struct iw_event iwe; - char *current_ev = buffer; - char *end_buf = buffer + IW_SCAN_MAX_DATA; -#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) - char buf[64]; -#endif - - iface = netdev_priv(dev); - local = iface->local; - ap = local->ap; - - spin_lock_bh(&ap->sta_table_lock); - - for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; - ptr = ptr->next) { - struct sta_info *sta = (struct sta_info *) ptr; - - /* First entry *MUST* be the AP MAC address */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); - iwe.len = IW_EV_ADDR_LEN; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Use the mode to indicate if it's a station or - * an Access Point */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (sta->ap) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_INFRA; - iwe.len = IW_EV_UINT_LEN; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - - /* Some quality */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - if (sta->last_rx_silence == 0) - iwe.u.qual.qual = sta->last_rx_signal < 27 ? - 0 : (sta->last_rx_signal - 27) * 92 / 127; - else - iwe.u.qual.qual = sta->last_rx_signal - - sta->last_rx_silence - 35; - iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); - iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); - iwe.u.qual.updated = sta->last_rx_updated; - iwe.len = IW_EV_QUAL_LEN; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (sta->ap) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = sta->u.ap.ssid_len; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, - sta->u.ap.ssid); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (sta->capability & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = - IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, - sta->u.ap.ssid); - - if (sta->u.ap.channel > 0 && - sta->u.ap.channel <= FREQ_COUNT) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = freq_list[sta->u.ap.channel - 1] - * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event( - info, current_ev, end_buf, &iwe, - IW_EV_FREQ_LEN); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "beacon_interval=%d", - sta->listen_interval); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, buf); - } -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - sta->last_rx_updated = IW_QUAL_DBM; - - /* To be continued, we should make good use of IWEVCUSTOM */ - } - - spin_unlock_bh(&ap->sta_table_lock); - - return current_ev - buffer; -} - - -static int prism2_hostapd_add_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (sta == NULL) { - sta = ap_add_sta(ap, param->sta_addr); - if (sta == NULL) - return -1; - } - - if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_new_sta(sta->local->dev, sta); - - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - sta->last_rx = jiffies; - sta->aid = param->u.add_sta.aid; - sta->capability = param->u.add_sta.capability; - sta->tx_supp_rates = param->u.add_sta.tx_supp_rates; - if (sta->tx_supp_rates & WLAN_RATE_1M) - sta->supported_rates[0] = 2; - if (sta->tx_supp_rates & WLAN_RATE_2M) - sta->supported_rates[1] = 4; - if (sta->tx_supp_rates & WLAN_RATE_5M5) - sta->supported_rates[2] = 11; - if (sta->tx_supp_rates & WLAN_RATE_11M) - sta->supported_rates[3] = 22; - prism2_check_tx_rates(sta); - atomic_dec(&sta->users); - return 0; -} - - -static int prism2_hostapd_remove_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) { - ap_sta_hash_del(ap, sta); - list_del(&sta->list); - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) - hostap_event_expired_sta(sta->local->dev, sta); - ap_free_sta(ap, sta); - - return 0; -} - - -static int prism2_hostapd_get_info_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ; - - atomic_dec(&sta->users); - - return 1; -} - - -static int prism2_hostapd_set_flags_sta(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) { - sta->flags |= param->u.set_flags_sta.flags_or; - sta->flags &= param->u.set_flags_sta.flags_and; - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - return 0; -} - - -static int prism2_hostapd_sta_clear_stats(struct ap_data *ap, - struct prism2_hostapd_param *param) -{ - struct sta_info *sta; - int rate; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, param->sta_addr); - if (sta) { - sta->rx_packets = sta->tx_packets = 0; - sta->rx_bytes = sta->tx_bytes = 0; - for (rate = 0; rate < WLAN_RATE_COUNT; rate++) { - sta->tx_count[rate] = 0; - sta->rx_count[rate] = 0; - } - } - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta) - return -ENOENT; - - return 0; -} - - -int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param) -{ - switch (param->cmd) { - case PRISM2_HOSTAPD_FLUSH: - ap_control_kickall(ap); - return 0; - case PRISM2_HOSTAPD_ADD_STA: - return prism2_hostapd_add_sta(ap, param); - case PRISM2_HOSTAPD_REMOVE_STA: - return prism2_hostapd_remove_sta(ap, param); - case PRISM2_HOSTAPD_GET_INFO_STA: - return prism2_hostapd_get_info_sta(ap, param); - case PRISM2_HOSTAPD_SET_FLAGS_STA: - return prism2_hostapd_set_flags_sta(ap, param); - case PRISM2_HOSTAPD_STA_CLEAR_STATS: - return prism2_hostapd_sta_clear_stats(ap, param); - default: - printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n", - param->cmd); - return -EOPNOTSUPP; - } -} - - -/* Update station info for host-based TX rate control and return current - * TX rate */ -static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) -{ - int ret = sta->tx_rate; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - sta->tx_count[sta->tx_rate_idx]++; - sta->tx_since_last_failure++; - sta->tx_consecutive_exc = 0; - if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT && - sta->tx_rate_idx < sta->tx_max_rate) { - /* use next higher rate */ - int old_rate, new_rate; - old_rate = new_rate = sta->tx_rate_idx; - while (new_rate < sta->tx_max_rate) { - new_rate++; - if (ap_tx_rate_ok(new_rate, sta, local)) { - sta->tx_rate_idx = new_rate; - break; - } - } - if (old_rate != sta->tx_rate_idx) { - switch (sta->tx_rate_idx) { - case 0: sta->tx_rate = 10; break; - case 1: sta->tx_rate = 20; break; - case 2: sta->tx_rate = 55; break; - case 3: sta->tx_rate = 110; break; - default: sta->tx_rate = 0; break; - } - PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n", - dev->name, sta->addr, sta->tx_rate); - } - sta->tx_since_last_failure = 0; - } - - return ret; -} - - -/* Called only from software IRQ. Called for each TX frame prior possible - * encryption and transmit. */ -ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) -{ - struct sta_info *sta = NULL; - struct sk_buff *skb = tx->skb; - int set_tim, ret; - struct ieee80211_hdr *hdr; - struct hostap_skb_tx_data *meta; - - meta = (struct hostap_skb_tx_data *) skb->cb; - ret = AP_TX_CONTINUE; - if (local->ap == NULL || skb->len < 10 || - meta->iface->type == HOSTAP_INTERFACE_STA) - goto out; - - hdr = (struct ieee80211_hdr *) skb->data; - - if (hdr->addr1[0] & 0x01) { - /* broadcast/multicast frame - no AP related processing */ - if (local->ap->num_sta <= 0) - ret = AP_TX_DROP; - goto out; - } - - /* unicast packet - check whether destination STA is associated */ - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr1); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (local->iw_mode == IW_MODE_MASTER && sta == NULL && - !(meta->flags & HOSTAP_TX_FLAGS_WDS) && - meta->iface->type != HOSTAP_INTERFACE_MASTER && - meta->iface->type != HOSTAP_INTERFACE_AP) { -#if 0 - /* This can happen, e.g., when wlan0 is added to a bridge and - * bridging code does not know which port is the correct target - * for a unicast frame. In this case, the packet is send to all - * ports of the bridge. Since this is a valid scenario, do not - * print out any errors here. */ - if (net_ratelimit()) { - printk(KERN_DEBUG "AP: drop packet to non-associated " - "STA %pM\n", hdr->addr1); - } -#endif - local->ap->tx_drop_nonassoc++; - ret = AP_TX_DROP; - goto out; - } - - if (sta == NULL) - goto out; - - if (!(sta->flags & WLAN_STA_AUTHORIZED)) - ret = AP_TX_CONTINUE_NOT_AUTHORIZED; - - /* Set tx_rate if using host-based TX rate control */ - if (!local->fw_tx_rate_control) - local->ap->last_tx_rate = meta->rate = - ap_update_sta_tx_rate(sta, local->dev); - - if (local->iw_mode != IW_MODE_MASTER) - goto out; - - if (!(sta->flags & WLAN_STA_PS)) - goto out; - - if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) { - /* indicate to STA that more frames follow */ - hdr->frame_control |= - cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } - - if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) { - /* packet was already buffered and now send due to - * PS poll, so do not rebuffer it */ - goto out; - } - - if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { - PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s" - "PS mode buffer\n", - local->dev->name, sta->addr); - /* Make sure that TIM is set for the station (it might not be - * after AP wlan hw reset). */ - /* FIX: should fix hw reset to restore bits based on STA - * buffer state.. */ - hostap_set_tim(local, sta->aid, 1); - sta->flags |= WLAN_STA_TIM; - ret = AP_TX_DROP; - goto out; - } - - /* STA in PS mode, buffer frame for later delivery */ - set_tim = skb_queue_empty(&sta->tx_buf); - skb_queue_tail(&sta->tx_buf, skb); - /* FIX: could save RX time to skb and expire buffered frames after - * some time if STA does not poll for them */ - - if (set_tim) { - if (sta->flags & WLAN_STA_TIM) - PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n", - sta->aid); - hostap_set_tim(local, sta->aid, 1); - sta->flags |= WLAN_STA_TIM; - } - - ret = AP_TX_BUFFERED; - - out: - if (sta != NULL) { - if (ret == AP_TX_CONTINUE || - ret == AP_TX_CONTINUE_NOT_AUTHORIZED) { - sta->tx_packets++; - sta->tx_bytes += skb->len; - sta->last_tx = jiffies; - } - - if ((ret == AP_TX_CONTINUE || - ret == AP_TX_CONTINUE_NOT_AUTHORIZED) && - sta->crypt && tx->host_encrypt) { - tx->crypt = sta->crypt; - tx->sta_ptr = sta; /* hostap_handle_sta_release() will - * be called to release sta info - * later */ - } else - atomic_dec(&sta->users); - } - - return ret; -} - - -void hostap_handle_sta_release(void *ptr) -{ - struct sta_info *sta = ptr; - atomic_dec(&sta->users); -} - - -/* Called only as a tasklet (software IRQ) */ -void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) -{ - struct sta_info *sta; - struct ieee80211_hdr *hdr; - struct hostap_skb_tx_data *meta; - - hdr = (struct ieee80211_hdr *) skb->data; - meta = (struct hostap_skb_tx_data *) skb->cb; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr1); - if (!sta) { - spin_unlock(&local->ap->sta_table_lock); - PDEBUG(DEBUG_AP, "%s: Could not find STA %pM" - " for this TX error (@%lu)\n", - local->dev->name, hdr->addr1, jiffies); - return; - } - - sta->tx_since_last_failure = 0; - sta->tx_consecutive_exc++; - - if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD && - sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) { - /* use next lower rate */ - int old, rate; - old = rate = sta->tx_rate_idx; - while (rate > 0) { - rate--; - if (ap_tx_rate_ok(rate, sta, local)) { - sta->tx_rate_idx = rate; - break; - } - } - if (old != sta->tx_rate_idx) { - switch (sta->tx_rate_idx) { - case 0: sta->tx_rate = 10; break; - case 1: sta->tx_rate = 20; break; - case 2: sta->tx_rate = 55; break; - case 3: sta->tx_rate = 110; break; - default: sta->tx_rate = 0; break; - } - PDEBUG(DEBUG_AP, - "%s: STA %pM TX rate lowered to %d\n", - local->dev->name, sta->addr, sta->tx_rate); - } - sta->tx_consecutive_exc = 0; - } - spin_unlock(&local->ap->sta_table_lock); -} - - -static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, - int pwrmgt, int type, int stype) -{ - if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { - sta->flags |= WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %pM changed to use PS " - "mode (type=0x%02X, stype=0x%02X)\n", - sta->addr, type >> 2, stype >> 4); - } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { - sta->flags &= ~WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %pM changed to not use " - "PS mode (type=0x%02X, stype=0x%02X)\n", - sta->addr, type >> 2, stype >> 4); - if (type != IEEE80211_FTYPE_CTL || - stype != IEEE80211_STYPE_PSPOLL) - schedule_packet_send(local, sta); - } -} - - -/* Called only as a tasklet (software IRQ). Called for each RX frame to update - * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */ -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) -{ - struct sta_info *sta; - u16 fc; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (!sta) - return -1; - - fc = le16_to_cpu(hdr->frame_control); - hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, - fc & IEEE80211_FCTL_FTYPE, - fc & IEEE80211_FCTL_STYPE); - - atomic_dec(&sta->users); - return 0; -} - - -/* Called only as a tasklet (software IRQ). Called for each RX frame after - * getting RX header and payload from hardware. */ -ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, - struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, - int wds) -{ - int ret; - struct sta_info *sta; - u16 fc, type, stype; - struct ieee80211_hdr *hdr; - - if (local->ap == NULL) - return AP_RX_CONTINUE; - - hdr = (struct ieee80211_hdr *) skb->data; - - fc = le16_to_cpu(hdr->frame_control); - type = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (sta && !(sta->flags & WLAN_STA_AUTHORIZED)) - ret = AP_RX_CONTINUE_NOT_AUTHORIZED; - else - ret = AP_RX_CONTINUE; - - - if (fc & IEEE80211_FCTL_TODS) { - if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { - if (local->hostapd) { - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_NON_ASSOC); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - } else { - printk(KERN_DEBUG "%s: dropped received packet" - " from non-associated STA %pM" - " (type=0x%02x, subtype=0x%02x)\n", - dev->name, hdr->addr2, - type >> 2, stype >> 4); - hostap_rx(dev, skb, rx_stats); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - } - ret = AP_RX_EXIT; - goto out; - } - } else if (fc & IEEE80211_FCTL_FROMDS) { - if (!wds) { - /* FromDS frame - not for us; probably - * broadcast/multicast in another BSS - drop */ - if (ether_addr_equal(hdr->addr1, dev->dev_addr)) { - printk(KERN_DEBUG "Odd.. FromDS packet " - "received with own BSSID\n"); - hostap_dump_rx_80211(dev->name, skb, rx_stats); - } - ret = AP_RX_DROP; - goto out; - } - } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL && - ether_addr_equal(hdr->addr1, dev->dev_addr)) { - - if (local->hostapd) { - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_NON_ASSOC); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - } else { - /* At least Lucent f/w seems to send data::nullfunc - * frames with no ToDS flag when the current AP returns - * after being unavailable for some time. Speed up - * re-association by informing the station about it not - * being associated. */ - printk(KERN_DEBUG "%s: rejected received nullfunc frame" - " without ToDS from not associated STA %pM\n", - dev->name, hdr->addr2); - hostap_rx(dev, skb, rx_stats); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - } - ret = AP_RX_EXIT; - goto out; - } else if (stype == IEEE80211_STYPE_NULLFUNC) { - /* At least Lucent cards seem to send periodic nullfunc - * frames with ToDS. Let these through to update SQ - * stats and PS state. Nullfunc frames do not contain - * any data and they will be dropped below. */ - } else { - /* If BSSID (Addr3) is foreign, this frame is a normal - * broadcast frame from an IBSS network. Drop it silently. - * If BSSID is own, report the dropping of this frame. */ - if (ether_addr_equal(hdr->addr3, dev->dev_addr)) { - printk(KERN_DEBUG "%s: dropped received packet from %pM" - " with no ToDS flag " - "(type=0x%02x, subtype=0x%02x)\n", dev->name, - hdr->addr2, type >> 2, stype >> 4); - hostap_dump_rx_80211(dev->name, skb, rx_stats); - } - ret = AP_RX_DROP; - goto out; - } - - if (sta) { - hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, - type, stype); - - sta->rx_packets++; - sta->rx_bytes += skb->len; - sta->last_rx = jiffies; - } - - if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC && - fc & IEEE80211_FCTL_TODS) { - if (local->hostapd) { - prism2_rx_80211(local->apdev, skb, rx_stats, - PRISM2_RX_NULLFUNC_ACK); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - } else { - /* some STA f/w's seem to require control::ACK frame - * for data::nullfunc, but Prism2 f/w 0.8.0 (at least - * from Compaq) does not send this.. Try to generate - * ACK for these frames from the host driver to make - * power saving work with, e.g., Lucent WaveLAN f/w */ - hostap_rx(dev, skb, rx_stats); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - } - ret = AP_RX_EXIT; - goto out; - } - - out: - if (sta) - atomic_dec(&sta->users); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_handle_sta_crypto(local_info_t *local, - struct ieee80211_hdr *hdr, - struct lib80211_crypt_data **crypt, - void **sta_ptr) -{ - struct sta_info *sta; - - spin_lock(&local->ap->sta_table_lock); - sta = ap_get_sta(local->ap, hdr->addr2); - if (sta) - atomic_inc(&sta->users); - spin_unlock(&local->ap->sta_table_lock); - - if (!sta) - return -1; - - if (sta->crypt) { - *crypt = sta->crypt; - *sta_ptr = sta; - /* hostap_handle_sta_release() will be called to release STA - * info */ - } else - atomic_dec(&sta->users); - - return 0; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr) -{ - struct sta_info *sta; - int ret = 0; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, sta_addr); - if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap) - ret = 1; - spin_unlock(&ap->sta_table_lock); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr) -{ - struct sta_info *sta; - int ret = 0; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, sta_addr); - if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap && - ((sta->flags & WLAN_STA_AUTHORIZED) || - ap->local->ieee_802_1x == 0)) - ret = 1; - spin_unlock(&ap->sta_table_lock); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) -{ - struct sta_info *sta; - int ret = 1; - - if (!ap) - return -1; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, sta_addr); - if (sta) - ret = 0; - spin_unlock(&ap->sta_table_lock); - - if (ret == 1) { - sta = ap_add_sta(ap, sta_addr); - if (!sta) - return -1; - sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; - sta->ap = 1; - memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); - /* No way of knowing which rates are supported since we did not - * get supported rates element from beacon/assoc req. Assume - * that remote end supports all 802.11b rates. */ - sta->supported_rates[0] = 0x82; - sta->supported_rates[1] = 0x84; - sta->supported_rates[2] = 0x0b; - sta->supported_rates[3] = 0x16; - sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M | - WLAN_RATE_5M5 | WLAN_RATE_11M; - sta->tx_rate = 110; - sta->tx_max_rate = sta->tx_rate_idx = 3; - } - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -int hostap_update_rx_stats(struct ap_data *ap, - struct ieee80211_hdr *hdr, - struct hostap_80211_rx_status *rx_stats) -{ - struct sta_info *sta; - - if (!ap) - return -1; - - spin_lock(&ap->sta_table_lock); - sta = ap_get_sta(ap, hdr->addr2); - if (sta) { - sta->last_rx_silence = rx_stats->noise; - sta->last_rx_signal = rx_stats->signal; - sta->last_rx_rate = rx_stats->rate; - sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - if (rx_stats->rate == 10) - sta->rx_count[0]++; - else if (rx_stats->rate == 20) - sta->rx_count[1]++; - else if (rx_stats->rate == 55) - sta->rx_count[2]++; - else if (rx_stats->rate == 110) - sta->rx_count[3]++; - } - spin_unlock(&ap->sta_table_lock); - - return sta ? 0 : -1; -} - - -void hostap_update_rates(local_info_t *local) -{ - struct sta_info *sta; - struct ap_data *ap = local->ap; - - if (!ap) - return; - - spin_lock_bh(&ap->sta_table_lock); - list_for_each_entry(sta, &ap->sta_list, list) { - prism2_check_tx_rates(sta); - } - spin_unlock_bh(&ap->sta_table_lock); -} - - -void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct lib80211_crypt_data ***crypt) -{ - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - sta = ap_get_sta(ap, addr); - if (sta) - atomic_inc(&sta->users); - spin_unlock_bh(&ap->sta_table_lock); - - if (!sta && permanent) - sta = ap_add_sta(ap, addr); - - if (!sta) - return NULL; - - if (permanent) - sta->flags |= WLAN_STA_PERM; - - *crypt = &sta->crypt; - - return sta; -} - - -void hostap_add_wds_links(local_info_t *local) -{ - struct ap_data *ap = local->ap; - struct sta_info *sta; - - spin_lock_bh(&ap->sta_table_lock); - list_for_each_entry(sta, &ap->sta_list, list) { - if (sta->ap) - hostap_wds_link_oper(local, sta->addr, WDS_ADD); - } - spin_unlock_bh(&ap->sta_table_lock); - - schedule_work(&local->ap->wds_oper_queue); -} - - -void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type) -{ - struct wds_oper_data *entry; - - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) - return; - memcpy(entry->addr, addr, ETH_ALEN); - entry->type = type; - spin_lock_bh(&local->lock); - entry->next = local->ap->wds_oper_entries; - local->ap->wds_oper_entries = entry; - spin_unlock_bh(&local->lock); - - schedule_work(&local->ap->wds_oper_queue); -} - - -EXPORT_SYMBOL(hostap_init_data); -EXPORT_SYMBOL(hostap_init_ap_proc); -EXPORT_SYMBOL(hostap_free_data); -EXPORT_SYMBOL(hostap_check_sta_fw_version); -EXPORT_SYMBOL(hostap_handle_sta_tx_exc); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.h b/drivers/net/wireless/intersil/hostap/hostap_ap.h deleted file mode 100644 index b7ac9e2f1a..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.h +++ /dev/null @@ -1,264 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_AP_H -#define HOSTAP_AP_H - -#include "hostap_80211.h" - -/* AP data structures for STAs */ - -/* maximum number of frames to buffer per STA */ -#define STA_MAX_TX_BUFFER 32 - -/* STA flags */ -#define WLAN_STA_AUTH BIT(0) -#define WLAN_STA_ASSOC BIT(1) -#define WLAN_STA_PS BIT(2) -#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ -#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ -#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is - * controlling whether STA is authorized to - * send and receive non-IEEE 802.1X frames - */ -#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ - -#define WLAN_RATE_1M BIT(0) -#define WLAN_RATE_2M BIT(1) -#define WLAN_RATE_5M5 BIT(2) -#define WLAN_RATE_11M BIT(3) -#define WLAN_RATE_COUNT 4 - -/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8, - * but some pre-standard IEEE 802.11g products use longer elements. */ -#define WLAN_SUPP_RATES_MAX 32 - -/* Try to increase TX rate after # successfully sent consecutive packets */ -#define WLAN_RATE_UPDATE_COUNT 50 - -/* Decrease TX rate after # consecutive dropped packets */ -#define WLAN_RATE_DECREASE_THRESHOLD 2 - -struct sta_info { - struct list_head list; - struct sta_info *hnext; /* next entry in hash table list */ - atomic_t users; /* number of users (do not remove if > 0) */ - struct proc_dir_entry *proc; - - u8 addr[6]; - u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ - u32 flags; - u16 capability; - u16 listen_interval; /* or beacon_int for APs */ - u8 supported_rates[WLAN_SUPP_RATES_MAX]; - - unsigned long last_auth; - unsigned long last_assoc; - unsigned long last_rx; - unsigned long last_tx; - unsigned long rx_packets, tx_packets; - unsigned long rx_bytes, tx_bytes; - struct sk_buff_head tx_buf; - /* FIX: timeout buffers with an expiry time somehow derived from - * listen_interval */ - - s8 last_rx_silence; /* Noise in dBm */ - s8 last_rx_signal; /* Signal strength in dBm */ - u8 last_rx_rate; /* TX rate in 0.1 Mbps */ - u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */ - - u8 tx_supp_rates; /* bit field of supported TX rates */ - u8 tx_rate; /* current TX rate (in 0.1 Mbps) */ - u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */ - u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */ - u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */ - u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate) - */ - u32 tx_since_last_failure; - u32 tx_consecutive_exc; - - struct lib80211_crypt_data *crypt; - - int ap; /* whether this station is an AP */ - - local_info_t *local; - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - union { - struct { - char *challenge; /* shared key authentication - * challenge */ - } sta; - struct { - int ssid_len; - unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */ - int channel; - unsigned long last_beacon; /* last RX beacon time */ - } ap; - } u; - - struct timer_list timer; - enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ -}; - - -#define MAX_STA_COUNT 1024 - -/* Maximum number of AIDs to use for STAs; must be 2007 or lower - * (8802.11 limitation) */ -#define MAX_AID_TABLE_SIZE 128 - -#define STA_HASH_SIZE 256 -#define STA_HASH(sta) (sta[5]) - - -/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC - * has passed since last received frame from the station, a nullfunc data - * frame is sent to the station. If this frame is not acknowledged and no other - * frames have been received, the station will be disassociated after - * AP_DISASSOC_DELAY. Similarly, a the station will be deauthenticated after - * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with - * max inactivity timer. */ -#define AP_MAX_INACTIVITY_SEC (5 * 60) -#define AP_DISASSOC_DELAY (HZ) -#define AP_DEAUTH_DELAY (HZ) - -/* ap_policy: whether to accept frames to/from other APs/IBSS */ -typedef enum { - AP_OTHER_AP_SKIP_ALL = 0, - AP_OTHER_AP_SAME_SSID = 1, - AP_OTHER_AP_ALL = 2, - AP_OTHER_AP_EVEN_IBSS = 3 -} ap_policy_enum; - -#define PRISM2_AUTH_OPEN BIT(0) -#define PRISM2_AUTH_SHARED_KEY BIT(1) - - -/* MAC address-based restrictions */ -struct mac_entry { - struct list_head list; - u8 addr[6]; -}; - -struct mac_restrictions { - enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy; - unsigned int entries; - struct list_head mac_list; - spinlock_t lock; -}; - - -struct add_sta_proc_data { - u8 addr[ETH_ALEN]; - struct add_sta_proc_data *next; -}; - - -typedef enum { WDS_ADD, WDS_DEL } wds_oper_type; -struct wds_oper_data { - wds_oper_type type; - u8 addr[ETH_ALEN]; - struct wds_oper_data *next; -}; - - -struct ap_data { - int initialized; /* whether ap_data has been initialized */ - local_info_t *local; - int bridge_packets; /* send packet to associated STAs directly to the - * wireless media instead of higher layers in the - * kernel */ - unsigned int bridged_unicast; /* number of unicast frames bridged on - * wireless media */ - unsigned int bridged_multicast; /* number of non-unicast frames - * bridged on wireless media */ - unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped - * because they were to an address that - * was not associated */ - int nullfunc_ack; /* use workaround for nullfunc frame ACKs */ - - spinlock_t sta_table_lock; - int num_sta; /* number of entries in sta_list */ - struct list_head sta_list; /* STA info list head */ - struct sta_info *sta_hash[STA_HASH_SIZE]; - - struct proc_dir_entry *proc; - - ap_policy_enum ap_policy; - unsigned int max_inactivity; - int autom_ap_wds; - - struct mac_restrictions mac_restrictions; /* MAC-based auth */ - int last_tx_rate; - - struct work_struct add_sta_proc_queue; - struct add_sta_proc_data *add_sta_proc_entries; - - struct work_struct wds_oper_queue; - struct wds_oper_data *wds_oper_entries; - - u16 tx_callback_idx; - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - /* pointers to STA info; based on allocated AID or NULL if AID free - * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 - * and so on - */ - struct sta_info *sta_aid[MAX_AID_TABLE_SIZE]; - - u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll; - - /* WEP operations for generating challenges to be used with shared key - * authentication */ - struct lib80211_crypto_ops *crypt; - void *crypt_priv; -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ -}; - - -void hostap_rx(struct net_device *dev, struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats); -void hostap_init_data(local_info_t *local); -void hostap_init_ap_proc(local_info_t *local); -void hostap_free_data(struct ap_data *ap); -void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver); - -typedef enum { - AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED, - AP_TX_CONTINUE_NOT_AUTHORIZED -} ap_tx_ret; -struct hostap_tx_data { - struct sk_buff *skb; - int host_encrypt; - struct lib80211_crypt_data *crypt; - void *sta_ptr; -}; -ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); -void hostap_handle_sta_release(void *ptr); -void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr); -typedef enum { - AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED -} ap_rx_ret; -ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, - struct sk_buff *skb, - struct hostap_80211_rx_status *rx_stats, - int wds); -int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr, - struct lib80211_crypt_data **crypt, - void **sta_ptr); -int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); -int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); -int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); -int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr, - struct hostap_80211_rx_status *rx_stats); -void hostap_update_rates(local_info_t *local); -void hostap_add_wds_links(local_info_t *local); -void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type); - -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, - int resend); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -#endif /* HOSTAP_AP_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_common.h b/drivers/net/wireless/intersil/hostap/hostap_common.h deleted file mode 100644 index dd29a8e8d3..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_common.h +++ /dev/null @@ -1,420 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_COMMON_H -#define HOSTAP_COMMON_H - -#include <linux/types.h> -#include <linux/if_ether.h> - -/* IEEE 802.11 defines */ - -/* HFA384X Configuration RIDs */ -#define HFA384X_RID_CNFPORTTYPE 0xFC00 -#define HFA384X_RID_CNFOWNMACADDR 0xFC01 -#define HFA384X_RID_CNFDESIREDSSID 0xFC02 -#define HFA384X_RID_CNFOWNCHANNEL 0xFC03 -#define HFA384X_RID_CNFOWNSSID 0xFC04 -#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05 -#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06 -#define HFA384X_RID_CNFMAXDATALEN 0xFC07 -#define HFA384X_RID_CNFWDSADDRESS 0xFC08 -#define HFA384X_RID_CNFPMENABLED 0xFC09 -#define HFA384X_RID_CNFPMEPS 0xFC0A -#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B -#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C -#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D -#define HFA384X_RID_CNFOWNNAME 0xFC0E -#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10 -#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */ -#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */ -#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */ -#define HFA384X_RID_UNKNOWN1 0xFC20 -#define HFA384X_RID_UNKNOWN2 0xFC21 -#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23 -#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24 -#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25 -#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26 -#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27 -#define HFA384X_RID_CNFWEPFLAGS 0xFC28 -#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 -#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A -#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */ -#define HFA384X_RID_CNFTXCONTROL 0xFC2C -#define HFA384X_RID_CNFROAMINGMODE 0xFC2D -#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */ -#define HFA384X_RID_CNFRCVCRCERROR 0xFC30 -#define HFA384X_RID_CNFMMLIFE 0xFC31 -#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32 -#define HFA384X_RID_CNFBEACONINT 0xFC33 -#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */ -#define HFA384X_RID_CNFSTAPCFINFO 0xFC35 -#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37 -#define HFA384X_RID_CNFTIMCTRL 0xFC40 -#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */ -#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */ -#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */ -#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0; - * write only */ -#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */ -#define HFA384X_RID_GROUPADDRESSES 0xFC80 -#define HFA384X_RID_CREATEIBSS 0xFC81 -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82 -#define HFA384X_RID_RTSTHRESHOLD 0xFC83 -#define HFA384X_RID_TXRATECONTROL 0xFC84 -#define HFA384X_RID_PROMISCUOUSMODE 0xFC85 -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */ -#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */ -#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */ -#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */ -#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0 -#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 -#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 -#define HFA384X_RID_CNFBASICRATES 0xFCB3 -#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4 -#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */ -#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */ -#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */ -#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */ -#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */ -#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */ -#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */ -#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */ -#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */ -#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */ -#define HFA384X_RID_TICKTIME 0xFCE0 -#define HFA384X_RID_SCANREQUEST 0xFCE1 -#define HFA384X_RID_JOINREQUEST 0xFCE2 -#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */ -#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */ -#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */ - -/* HFA384X Information RIDs */ -#define HFA384X_RID_MAXLOADTIME 0xFD00 -#define HFA384X_RID_DOWNLOADBUFFER 0xFD01 -#define HFA384X_RID_PRIID 0xFD02 -#define HFA384X_RID_PRISUPRANGE 0xFD03 -#define HFA384X_RID_CFIACTRANGES 0xFD04 -#define HFA384X_RID_NICSERNUM 0xFD0A -#define HFA384X_RID_NICID 0xFD0B -#define HFA384X_RID_MFISUPRANGE 0xFD0C -#define HFA384X_RID_CFISUPRANGE 0xFD0D -#define HFA384X_RID_CHANNELLIST 0xFD10 -#define HFA384X_RID_REGULATORYDOMAINS 0xFD11 -#define HFA384X_RID_TEMPTYPE 0xFD12 -#define HFA384X_RID_CIS 0xFD13 -#define HFA384X_RID_STAID 0xFD20 -#define HFA384X_RID_STASUPRANGE 0xFD21 -#define HFA384X_RID_MFIACTRANGES 0xFD22 -#define HFA384X_RID_CFIACTRANGES2 0xFD23 -#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1; - * only Prism2.5(?) */ -#define HFA384X_RID_PORTSTATUS 0xFD40 -#define HFA384X_RID_CURRENTSSID 0xFD41 -#define HFA384X_RID_CURRENTBSSID 0xFD42 -#define HFA384X_RID_COMMSQUALITY 0xFD43 -#define HFA384X_RID_CURRENTTXRATE 0xFD44 -#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45 -#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46 -#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47 -#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48 -#define HFA384X_RID_LONGRETRYLIMIT 0xFD49 -#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A -#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B -#define HFA384X_RID_CFPOLLABLE 0xFD4C -#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D -#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F -#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */ -#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */ -#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */ -#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */ -#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */ -#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */ -#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */ -#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */ -#define HFA384X_RID_PHYTYPE 0xFDC0 -#define HFA384X_RID_CURRENTCHANNEL 0xFDC1 -#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2 -#define HFA384X_RID_CCAMODE 0xFDC3 -#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6 -#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */ -#define HFA384X_RID_BUILDSEQ 0xFFFE -#define HFA384X_RID_FWID 0xFFFF - - -struct hfa384x_comp_ident -{ - __le16 id; - __le16 variant; - __le16 major; - __le16 minor; -} __packed; - -#define HFA384X_COMP_ID_PRI 0x15 -#define HFA384X_COMP_ID_STA 0x1f -#define HFA384X_COMP_ID_FW_AP 0x14b - -struct hfa384x_sup_range -{ - __le16 role; - __le16 id; - __le16 variant; - __le16 bottom; - __le16 top; -} __packed; - - -struct hfa384x_build_id -{ - __le16 pri_seq; - __le16 sec_seq; -} __packed; - -/* FD01 - Download Buffer */ -struct hfa384x_rid_download_buffer -{ - __le16 page; - __le16 offset; - __le16 length; -} __packed; - -/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */ -struct hfa384x_comms_quality { - __le16 comm_qual; /* 0 .. 92 */ - __le16 signal_level; /* 27 .. 154 */ - __le16 noise_level; /* 27 .. 154 */ -} __packed; - - -/* netdevice private ioctls (used, e.g., with iwpriv from user space) */ - -/* New wireless extensions API - SET/GET convention (even ioctl numbers are - * root only) - */ -#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) -#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) -#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2) -#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3) -#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4) -#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6) -#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8) -#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10) -#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12) -#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14) -#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16) -#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18) -#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20) -#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22) - -/* following are not in SIOCGIWPRIV list; check permission in the driver code - */ -#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) -#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) - - -/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */ -enum { - /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */ - PRISM2_PARAM_TXRATECTRL = 2, - PRISM2_PARAM_BEACON_INT = 3, - PRISM2_PARAM_PSEUDO_IBSS = 4, - PRISM2_PARAM_ALC = 5, - /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */ - PRISM2_PARAM_DUMP = 7, - PRISM2_PARAM_OTHER_AP_POLICY = 8, - PRISM2_PARAM_AP_MAX_INACTIVITY = 9, - PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, - PRISM2_PARAM_DTIM_PERIOD = 11, - PRISM2_PARAM_AP_NULLFUNC_ACK = 12, - PRISM2_PARAM_MAX_WDS = 13, - PRISM2_PARAM_AP_AUTOM_AP_WDS = 14, - PRISM2_PARAM_AP_AUTH_ALGS = 15, - PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16, - PRISM2_PARAM_HOST_ENCRYPT = 17, - PRISM2_PARAM_HOST_DECRYPT = 18, - /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */ - /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */ - PRISM2_PARAM_HOST_ROAMING = 21, - PRISM2_PARAM_BCRX_STA_KEY = 22, - PRISM2_PARAM_IEEE_802_1X = 23, - PRISM2_PARAM_ANTSEL_TX = 24, - PRISM2_PARAM_ANTSEL_RX = 25, - PRISM2_PARAM_MONITOR_TYPE = 26, - PRISM2_PARAM_WDS_TYPE = 27, - PRISM2_PARAM_HOSTSCAN = 28, - PRISM2_PARAM_AP_SCAN = 29, - PRISM2_PARAM_ENH_SEC = 30, - PRISM2_PARAM_IO_DEBUG = 31, - PRISM2_PARAM_BASIC_RATES = 32, - PRISM2_PARAM_OPER_RATES = 33, - PRISM2_PARAM_HOSTAPD = 34, - PRISM2_PARAM_HOSTAPD_STA = 35, - PRISM2_PARAM_WPA = 36, - PRISM2_PARAM_PRIVACY_INVOKED = 37, - PRISM2_PARAM_TKIP_COUNTERMEASURES = 38, - PRISM2_PARAM_DROP_UNENCRYPTED = 39, - PRISM2_PARAM_SCAN_CHANNEL_MASK = 40, -}; - -enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, - HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 }; - - -/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */ -enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1, - AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3, - AP_MAC_CMD_KICKALL = 4 }; - - -/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */ -enum { - PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */, - /* Note! Old versions of prism2_srec have a fatal error in CRC-16 - * calculation, which will corrupt all non-volatile downloads. - * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to - * prevent use of old versions of prism2_srec for non-volatile - * download. */ - PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */, - PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */, - /* Persistent versions of volatile download commands (keep firmware - * data in memory and automatically re-download after hw_reset */ - PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5, - PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6, -}; - -struct prism2_download_param { - u32 dl_cmd; - u32 start_addr; - u32 num_areas; - struct prism2_download_area { - u32 addr; /* wlan card address */ - u32 len; - void __user *ptr; /* pointer to data in user space */ - } data[]; -}; - -#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072 -#define PRISM2_MAX_DOWNLOAD_LEN 262144 - - -/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */ -enum { - PRISM2_HOSTAPD_FLUSH = 1, - PRISM2_HOSTAPD_ADD_STA = 2, - PRISM2_HOSTAPD_REMOVE_STA = 3, - PRISM2_HOSTAPD_GET_INFO_STA = 4, - /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ - PRISM2_SET_ENCRYPTION = 6, - PRISM2_GET_ENCRYPTION = 7, - PRISM2_HOSTAPD_SET_FLAGS_STA = 8, - PRISM2_HOSTAPD_GET_RID = 9, - PRISM2_HOSTAPD_SET_RID = 10, - PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11, - PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, - PRISM2_HOSTAPD_MLME = 13, - PRISM2_HOSTAPD_SCAN_REQ = 14, - PRISM2_HOSTAPD_STA_CLEAR_STATS = 15, -}; - -#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 -#define PRISM2_HOSTAPD_RID_HDR_LEN \ -offsetof(struct prism2_hostapd_param, u.rid.data) -#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ -offsetof(struct prism2_hostapd_param, u.generic_elem.data) - -/* Maximum length for algorithm names (-1 for nul termination) used in ioctl() - */ -#define HOSTAP_CRYPT_ALG_NAME_LEN 16 - - -struct prism2_hostapd_param { - u32 cmd; - u8 sta_addr[ETH_ALEN]; - union { - struct { - u16 aid; - u16 capability; - u8 tx_supp_rates; - } add_sta; - struct { - u32 inactive_sec; - } get_info_sta; - struct { - u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; - u32 flags; - u32 err; - u8 idx; - u8 seq[8]; /* sequence counter (set: RX, get: TX) */ - u16 key_len; - u8 key[0]; - } crypt; - struct { - u32 flags_and; - u32 flags_or; - } set_flags_sta; - struct { - u16 rid; - u16 len; - u8 data[0]; - } rid; - struct { - u8 len; - u8 data[0]; - } generic_elem; - struct { -#define MLME_STA_DEAUTH 0 -#define MLME_STA_DISASSOC 1 - u16 cmd; - u16 reason_code; - } mlme; - struct { - u8 ssid_len; - u8 ssid[32]; - } scan_req; - } u; -}; - -#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0) -#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1) - -#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 -#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 -#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 -#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 -#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 -#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 - - -#endif /* HOSTAP_COMMON_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_config.h b/drivers/net/wireless/intersil/hostap/hostap_config.h deleted file mode 100644 index 3ebd55847f..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_config.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_CONFIG_H -#define HOSTAP_CONFIG_H - -/* In the previous versions of Host AP driver, support for user space version - * of IEEE 802.11 management (hostapd) used to be disabled in the default - * configuration. From now on, support for hostapd is always included and it is - * possible to disable kernel driver version of IEEE 802.11 management with a - * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */ -/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */ - -/* Maximum number of events handler per one interrupt */ -#define PRISM2_MAX_INTERRUPT_EVENTS 20 - -/* Include code for downloading firmware images into volatile RAM. */ -#define PRISM2_DOWNLOAD_SUPPORT - -/* Allow kernel configuration to enable download support. */ -#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE) -#define PRISM2_DOWNLOAD_SUPPORT -#endif - -/* Allow kernel configuration to enable non-volatile download support. */ -#ifdef CONFIG_HOSTAP_FIRMWARE_NVRAM -#define PRISM2_NON_VOLATILE_DOWNLOAD -#endif - -/* Save low-level I/O for debugging. This should not be enabled in normal use. - */ -/* #define PRISM2_IO_DEBUG */ - -/* Following defines can be used to remove unneeded parts of the driver, e.g., - * to limit the size of the kernel module. Definitions can be added here in - * hostap_config.h or they can be added to make command with ccflags-y, - * e.g., - * 'make pccard ccflags-y="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' - */ - -/* Do not include debug messages into the driver */ -/* #define PRISM2_NO_DEBUG */ - -/* Do not include /proc/net/prism2/wlan#/{registers,debug} */ -/* #define PRISM2_NO_PROCFS_DEBUG */ - -/* Do not include station functionality (i.e., allow only Master (Host AP) mode - */ -/* #define PRISM2_NO_STATION_MODES */ - -#endif /* HOSTAP_CONFIG_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_cs.c b/drivers/net/wireless/intersil/hostap/hostap_cs.c deleted file mode 100644 index ec7db2badc..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_cs.c +++ /dev/null @@ -1,710 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#define PRISM2_PCCARD - -#include <linux/module.h> -#include <linux/if.h> -#include <linux/slab.h> -#include <linux/wait.h> -#include <linux/timer.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/workqueue.h> -#include <linux/wireless.h> -#include <net/iw_handler.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> - -#include <asm/io.h> - -#include "hostap_wlan.h" - - -static char *dev_info = "hostap_cs"; - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " - "cards (PC Card)."); -MODULE_LICENSE("GPL"); - - -static int ignore_cis_vcc; -module_param(ignore_cis_vcc, int, 0444); -MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); - - -/* struct local_info::hw_priv */ -struct hostap_cs_priv { - struct pcmcia_device *link; - int sandisk_connectplus; -}; - - -#ifdef PRISM2_IO_DEBUG - -static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); - outb(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u8 v; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - v = inb(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); - outw(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u16 v; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - v = inw(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outsw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); - outsw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline void hfa384x_insw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); - insw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) -#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) -#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) - -#else /* PRISM2_IO_DEBUG */ - -#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) -#define HFA384X_INB(a) inb(dev->base_addr + (a)) -#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) -#define HFA384X_INW(a) inw(dev->base_addr + (a)) -#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) -#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) - -#endif /* PRISM2_IO_DEBUG */ - - -static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, - int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_INSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - *((char *) pos) = HFA384X_INB(d_off); - - return 0; -} - - -static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_OUTSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - HFA384X_OUTB(*((char *) pos), d_off); - - return 0; -} - - -/* FIX: This might change at some point.. */ -#include "hostap_hw.c" - - - -static void prism2_detach(struct pcmcia_device *p_dev); -static void prism2_release(u_long arg); -static int prism2_config(struct pcmcia_device *link); - - -static int prism2_pccard_card_present(local_info_t *local) -{ - struct hostap_cs_priv *hw_priv = local->hw_priv; - if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link)) - return 1; - return 0; -} - - -/* - * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0 - * Document No. 20-10-00058, January 2004 - * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf - */ -#define SANDISK_WLAN_ACTIVATION_OFF 0x40 -#define SANDISK_HCR_OFF 0x42 - - -static void sandisk_set_iobase(local_info_t *local) -{ - int res; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - res = pcmcia_write_config_byte(hw_priv->link, 0x10, - hw_priv->link->resource[0]->start & 0x00ff); - if (res != 0) { - printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" - " res=%d\n", res); - } - udelay(10); - - res = pcmcia_write_config_byte(hw_priv->link, 0x12, - (hw_priv->link->resource[0]->start >> 8) & 0x00ff); - if (res != 0) { - printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" - " res=%d\n", res); - } -} - - -static void sandisk_write_hcr(local_info_t *local, int hcr) -{ - struct net_device *dev = local->dev; - int i; - - HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF); - udelay(50); - for (i = 0; i < 10; i++) { - HFA384X_OUTB(hcr, SANDISK_HCR_OFF); - } - udelay(55); - HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF); -} - - -static int sandisk_enable_wireless(struct net_device *dev) -{ - int res, ret = 0; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - if (resource_size(hw_priv->link->resource[0]) < 0x42) { - /* Not enough ports to be SanDisk multi-function card */ - ret = -ENODEV; - goto done; - } - - if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) { - /* No SanDisk manfid found */ - ret = -ENODEV; - goto done; - } - - if (hw_priv->link->socket->functions < 2) { - /* No multi-function links found */ - ret = -ENODEV; - goto done; - } - - printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected" - " - using vendor-specific initialization\n", dev->name); - hw_priv->sandisk_connectplus = 1; - - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - COR_SOFT_RESET); - if (res != 0) { - printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", - dev->name, res); - goto done; - } - mdelay(5); - - /* - * Do not enable interrupts here to avoid some bogus events. Interrupts - * will be enabled during the first cor_sreset call. - */ - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - (COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | - COR_FUNC_ENA)); - if (res != 0) { - printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", - dev->name, res); - goto done; - } - mdelay(5); - - sandisk_set_iobase(local); - - HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF); - udelay(10); - HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF); - udelay(10); - -done: - return ret; -} - - -static void prism2_pccard_cor_sreset(local_info_t *local) -{ - int res; - u8 val; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - if (!prism2_pccard_card_present(local)) - return; - - res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &val); - if (res != 0) { - printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", - res); - return; - } - printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n", - val); - - val |= COR_SOFT_RESET; - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val); - if (res != 0) { - printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", - res); - return; - } - - mdelay(hw_priv->sandisk_connectplus ? 5 : 2); - - val &= ~COR_SOFT_RESET; - if (hw_priv->sandisk_connectplus) - val |= COR_IREQ_ENA; - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val); - if (res != 0) { - printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", - res); - return; - } - - mdelay(hw_priv->sandisk_connectplus ? 5 : 2); - - if (hw_priv->sandisk_connectplus) - sandisk_set_iobase(local); -} - - -static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) -{ - int res; - u8 old_cor; - struct hostap_cs_priv *hw_priv = local->hw_priv; - - if (!prism2_pccard_card_present(local)) - return; - - if (hw_priv->sandisk_connectplus) { - sandisk_write_hcr(local, hcr); - return; - } - - res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &old_cor); - if (res != 0) { - printk(KERN_DEBUG "%s failed 1 (%d)\n", __func__, res); - return; - } - printk(KERN_DEBUG "%s: original COR %02x\n", __func__, old_cor); - - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - old_cor | COR_SOFT_RESET); - if (res != 0) { - printk(KERN_DEBUG "%s failed 2 (%d)\n", __func__, res); - return; - } - - mdelay(10); - - /* Setup Genesis mode */ - res = pcmcia_write_config_byte(hw_priv->link, CISREG_CCSR, hcr); - if (res != 0) { - printk(KERN_DEBUG "%s failed 3 (%d)\n", __func__, res); - return; - } - mdelay(10); - - res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, - old_cor & ~COR_SOFT_RESET); - if (res != 0) { - printk(KERN_DEBUG "%s failed 4 (%d)\n", __func__, res); - return; - } - - mdelay(10); -} - - -static struct prism2_helper_functions prism2_pccard_funcs = -{ - .card_present = prism2_pccard_card_present, - .cor_sreset = prism2_pccard_cor_sreset, - .genesis_reset = prism2_pccard_genesis_reset, - .hw_type = HOSTAP_HW_PCCARD, -}; - - -/* allocate local data and register with CardServices - * initialize dev_link structure, but do not configure the card yet */ -static int hostap_cs_probe(struct pcmcia_device *p_dev) -{ - int ret; - - PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); - - ret = prism2_config(p_dev); - if (ret) { - PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); - } - - return ret; -} - - -static void prism2_detach(struct pcmcia_device *link) -{ - PDEBUG(DEBUG_FLOW, "prism2_detach\n"); - - prism2_release((u_long)link); - - /* release net devices */ - if (link->priv) { - struct hostap_cs_priv *hw_priv; - struct net_device *dev; - struct hostap_interface *iface; - dev = link->priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - prism2_free_local_data(dev); - kfree(hw_priv); - } -} - - -static int prism2_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - -static int prism2_config(struct pcmcia_device *link) -{ - struct net_device *dev; - struct hostap_interface *iface; - local_info_t *local; - int ret; - struct hostap_cs_priv *hw_priv; - unsigned long flags; - - PDEBUG(DEBUG_FLOW, "prism2_config()\n"); - - hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (hw_priv == NULL) { - ret = -ENOMEM; - goto failed; - } - - /* Look for an appropriate configuration table entry in the CIS */ - link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | - CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; - if (ignore_cis_vcc) - link->config_flags &= ~CONF_AUTO_CHECK_VCC; - ret = pcmcia_loop_config(link, prism2_config_check, NULL); - if (ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - goto failed; - } - - /* Need to allocate net_device before requesting IRQ handler */ - dev = prism2_init_local_data(&prism2_pccard_funcs, 0, - &link->dev); - if (!dev) { - ret = -ENOMEM; - goto failed; - } - link->priv = dev; - - iface = netdev_priv(dev); - local = iface->local; - local->hw_priv = hw_priv; - hw_priv->link = link; - - /* - * We enable IRQ here, but IRQ handler will not proceed - * until dev->base_addr is set below. This protect us from - * receive interrupts when driver is not initialized. - */ - ret = pcmcia_request_irq(link, prism2_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - spin_lock_irqsave(&local->irq_init_lock, flags); - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - spin_unlock_irqrestore(&local->irq_init_lock, flags); - - local->shutdown = 0; - - sandisk_enable_wireless(dev); - - ret = prism2_hw_config(dev, 1); - if (!ret) - ret = hostap_hw_ready(dev); - - return ret; - - failed: - kfree(hw_priv); - prism2_release((u_long)link); - return ret; -} - - -static void prism2_release(u_long arg) -{ - struct pcmcia_device *link = (struct pcmcia_device *)arg; - - PDEBUG(DEBUG_FLOW, "prism2_release\n"); - - if (link->priv) { - struct net_device *dev = link->priv; - struct hostap_interface *iface; - - iface = netdev_priv(dev); - prism2_hw_shutdown(dev, 0); - iface->local->shutdown = 1; - } - - pcmcia_disable_device(link); - PDEBUG(DEBUG_FLOW, "release - done\n"); -} - -static int hostap_cs_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = (struct net_device *) link->priv; - int dev_open = 0; - struct hostap_interface *iface = NULL; - - if (!dev) - return -ENODEV; - - iface = netdev_priv(dev); - - PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); - if (iface && iface->local) - dev_open = iface->local->num_dev_open > 0; - if (dev_open) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - prism2_suspend(dev); - - return 0; -} - -static int hostap_cs_resume(struct pcmcia_device *link) -{ - struct net_device *dev = (struct net_device *) link->priv; - int dev_open = 0; - struct hostap_interface *iface = NULL; - - if (!dev) - return -ENODEV; - - iface = netdev_priv(dev); - - PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); - - if (iface && iface->local) - dev_open = iface->local->num_dev_open > 0; - - prism2_hw_shutdown(dev, 1); - prism2_hw_config(dev, dev_open ? 0 : 1); - if (dev_open) { - netif_device_attach(dev); - netif_start_queue(dev); - } - - return 0; -} - -static const struct pcmcia_device_id hostap_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), - PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), - PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301), - PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), -/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */ - PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), - PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002), - PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF", - 0x2d858104), - PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL", - 0x74c5e40d), - PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil", - 0x4b801a17), - PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.02", - 0x4b74baa0), - PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus", - 0x7a954bd9, 0x74be00c6), - PCMCIA_DEVICE_PROD_ID123( - "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", - 0xe6ec52ce, 0x08649af2, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "Canon", "Wireless LAN CF Card K30225", "Version 01.00", - 0x96ef6fe2, 0x263fcbab, 0xa57adb8c), - PCMCIA_DEVICE_PROD_ID123( - "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02", - 0x71b18589, 0xb6f1b0ab, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "Instant Wireless ", " Network PC CARD", "Version 01.02", - 0x11d901af, 0x6e9bd926, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "SMC", "SMC2632W", "Version 01.02", - 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", - 0x2decece3, 0x82067c18), - PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", - 0x54f7c49c, 0x15a75e5b), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", - 0x74c5e40d, 0xdb472a18), - PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", - 0x0733cc81, 0x0c52f395), - PCMCIA_DEVICE_PROD_ID12( - "ZoomAir 11Mbps High", "Rate wireless Networking", - 0x273fe3db, 0x32a1eaee), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", - 0xa37434e9, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID123( - "Pretec", "CompactWLAN Card 802.11b", "2.5", - 0x1cadd3e5, 0xe697636c, 0x7a5bfcf1), - PCMCIA_DEVICE_PROD_ID123( - "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02", - 0xc7b8df9d, 0x1700d087, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID123( - "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", - "Ver. 1.00", - 0x5cd01705, 0x4271660f, 0x9d08ee12), - PCMCIA_DEVICE_PROD_ID123( - "Wireless LAN" , "11Mbps PC Card", "Version 01.02", - 0x4b8870ff, 0x70e946d1, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092), - PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2), - PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b), - PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); - - -static struct pcmcia_driver hostap_driver = { - .name = "hostap_cs", - .probe = hostap_cs_probe, - .remove = prism2_detach, - .owner = THIS_MODULE, - .id_table = hostap_cs_ids, - .suspend = hostap_cs_suspend, - .resume = hostap_cs_resume, -}; -module_pcmcia_driver(hostap_driver); diff --git a/drivers/net/wireless/intersil/hostap/hostap_download.c b/drivers/net/wireless/intersil/hostap/hostap_download.c deleted file mode 100644 index 5e5bada28b..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_download.c +++ /dev/null @@ -1,810 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -static int prism2_enable_aux_port(struct net_device *dev, int enable) -{ - u16 val, reg; - int i, tries; - unsigned long flags; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - if (enable) { - PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux " - "port is already enabled\n", dev->name); - } - return 0; - } - - spin_lock_irqsave(&local->cmdlock, flags); - - /* wait until busy bit is clear */ - tries = HFA384X_CMD_BUSY_TIMEOUT; - while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { - tries--; - udelay(1); - } - if (tries == 0) { - reg = HFA384X_INW(HFA384X_CMD_OFF); - spin_unlock_irqrestore(&local->cmdlock, flags); - printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n", - dev->name, reg); - return -ETIMEDOUT; - } - - val = HFA384X_INW(HFA384X_CONTROL_OFF); - - if (enable) { - HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF); - HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF); - - if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED) - printk("prism2_enable_aux_port: was not disabled!?\n"); - val &= ~HFA384X_AUX_PORT_MASK; - val |= HFA384X_AUX_PORT_ENABLE; - } else { - HFA384X_OUTW(0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(0, HFA384X_PARAM1_OFF); - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - - if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED) - printk("prism2_enable_aux_port: was not enabled!?\n"); - val &= ~HFA384X_AUX_PORT_MASK; - val |= HFA384X_AUX_PORT_DISABLE; - } - HFA384X_OUTW(val, HFA384X_CONTROL_OFF); - - udelay(5); - - i = 10000; - while (i > 0) { - val = HFA384X_INW(HFA384X_CONTROL_OFF); - val &= HFA384X_AUX_PORT_MASK; - - if ((enable && val == HFA384X_AUX_PORT_ENABLED) || - (!enable && val == HFA384X_AUX_PORT_DISABLED)) - break; - - udelay(10); - i--; - } - - spin_unlock_irqrestore(&local->cmdlock, flags); - - if (i == 0) { - printk("prism2_enable_aux_port(%d) timed out\n", - enable); - return -ETIMEDOUT; - } - - return 0; -} - - -static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len, - void *buf) -{ - u16 page, offset; - if (addr & 1 || len & 1) - return -1; - - page = addr >> 7; - offset = addr & 0x7f; - - HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); - HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); - - udelay(5); - -#ifdef PRISM2_PCI - { - __le16 *pos = (__le16 *) buf; - while (len > 0) { - *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF); - len -= 2; - } - } -#else /* PRISM2_PCI */ - HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2); -#endif /* PRISM2_PCI */ - - return 0; -} - - -static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len, - void *buf) -{ - u16 page, offset; - if (addr & 1 || len & 1) - return -1; - - page = addr >> 7; - offset = addr & 0x7f; - - HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); - HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); - - udelay(5); - -#ifdef PRISM2_PCI - { - __le16 *pos = (__le16 *) buf; - while (len > 0) { - HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF); - len -= 2; - } - } -#else /* PRISM2_PCI */ - HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2); -#endif /* PRISM2_PCI */ - - return 0; -} - - -static int prism2_pda_ok(u8 *buf) -{ - __le16 *pda = (__le16 *) buf; - int pos; - u16 len, pdr; - - if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff && - buf[3] == 0x00) - return 0; - - pos = 0; - while (pos + 1 < PRISM2_PDA_SIZE / 2) { - len = le16_to_cpu(pda[pos]); - pdr = le16_to_cpu(pda[pos + 1]); - if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2) - return 0; - - if (pdr == 0x0000 && len == 2) { - /* PDA end found */ - return 1; - } - - pos += len + 1; - } - - return 0; -} - - -#define prism2_download_aux_dump_npages 65536 - -struct prism2_download_aux_dump { - local_info_t *local; - u16 page[0x80]; -}; - -static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v) -{ - struct prism2_download_aux_dump *ctx = m->private; - - hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page); - seq_write(m, ctx->page, 0x80); - return 0; -} - -static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos) -{ - struct prism2_download_aux_dump *ctx = m->private; - prism2_enable_aux_port(ctx->local->dev, 1); - if (*_pos >= prism2_download_aux_dump_npages) - return NULL; - return (void *)((unsigned long)*_pos + 1); -} - -static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - ++*_pos; - if (*_pos >= prism2_download_aux_dump_npages) - return NULL; - return (void *)((unsigned long)*_pos + 1); -} - -static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v) -{ - struct prism2_download_aux_dump *ctx = m->private; - prism2_enable_aux_port(ctx->local->dev, 0); -} - -static const struct seq_operations prism2_download_aux_dump_proc_seqops = { - .start = prism2_download_aux_dump_proc_start, - .next = prism2_download_aux_dump_proc_next, - .stop = prism2_download_aux_dump_proc_stop, - .show = prism2_download_aux_dump_proc_show, -}; - -static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops, - sizeof(struct prism2_download_aux_dump)); - if (ret == 0) { - struct seq_file *m = file->private_data; - m->private = pde_data(inode); - } - return ret; -} - -static const struct proc_ops prism2_download_aux_dump_proc_ops = { - .proc_open = prism2_download_aux_dump_proc_open, - .proc_read = seq_read, - .proc_lseek = seq_lseek, - .proc_release = seq_release_private, -}; - - -static u8 * prism2_read_pda(struct net_device *dev) -{ - u8 *buf; - int res, i, found = 0; -#define NUM_PDA_ADDRS 4 - unsigned int pda_addr[NUM_PDA_ADDRS] = { - 0x7f0000 /* others than HFA3841 */, - 0x3f0000 /* HFA3841 */, - 0x390000 /* apparently used in older cards */, - 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */, - }; - - buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL); - if (buf == NULL) - return NULL; - - /* Note: wlan card should be in initial state (just after init cmd) - * and no other operations should be performed concurrently. */ - - prism2_enable_aux_port(dev, 1); - - for (i = 0; i < NUM_PDA_ADDRS; i++) { - PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x", - dev->name, pda_addr[i]); - res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf); - if (res) - continue; - if (res == 0 && prism2_pda_ok(buf)) { - PDEBUG2(DEBUG_EXTRA2, ": OK\n"); - found = 1; - break; - } else { - PDEBUG2(DEBUG_EXTRA2, ": failed\n"); - } - } - - prism2_enable_aux_port(dev, 0); - - if (!found) { - printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name); - kfree(buf); - buf = NULL; - } - - return buf; -} - - -static int prism2_download_volatile(local_info_t *local, - struct prism2_download_data *param) -{ - struct net_device *dev = local->dev; - int ret = 0, i; - u16 param0, param1; - - if (local->hw_downloading) { - printk(KERN_WARNING "%s: Already downloading - aborting new " - "request\n", dev->name); - return -1; - } - - local->hw_downloading = 1; - if (local->pri_only) { - hfa384x_disable_interrupts(dev); - } else { - prism2_hw_shutdown(dev, 0); - - if (prism2_hw_init(dev, 0)) { - printk(KERN_WARNING "%s: Could not initialize card for" - " download\n", dev->name); - ret = -1; - goto out; - } - } - - if (prism2_enable_aux_port(dev, 1)) { - printk(KERN_WARNING "%s: Could not enable AUX port\n", - dev->name); - ret = -1; - goto out; - } - - param0 = param->start_addr & 0xffff; - param1 = param->start_addr >> 16; - - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_ENABLE_VOLATILE << 8), - param0)) { - printk(KERN_WARNING "%s: Download command execution failed\n", - dev->name); - ret = -1; - goto out; - } - - for (i = 0; i < param->num_areas; i++) { - PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", - dev->name, param->data[i].len, param->data[i].addr); - if (hfa384x_to_aux(dev, param->data[i].addr, - param->data[i].len, param->data[i].data)) { - printk(KERN_WARNING "%s: RAM download at 0x%08x " - "(len=%d) failed\n", dev->name, - param->data[i].addr, param->data[i].len); - ret = -1; - goto out; - } - } - - HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_DISABLE << 8), param0)) { - printk(KERN_WARNING "%s: Download command execution failed\n", - dev->name); - ret = -1; - goto out; - } - /* ProgMode disable causes the hardware to restart itself from the - * given starting address. Give hw some time and ACK command just in - * case restart did not happen. */ - mdelay(5); - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - - if (prism2_enable_aux_port(dev, 0)) { - printk(KERN_DEBUG "%s: Disabling AUX port failed\n", - dev->name); - /* continue anyway.. restart should have taken care of this */ - } - - mdelay(5); - local->hw_downloading = 0; - if (prism2_hw_config(dev, 2)) { - printk(KERN_WARNING "%s: Card configuration after RAM " - "download failed\n", dev->name); - ret = -1; - goto out; - } - - out: - local->hw_downloading = 0; - return ret; -} - - -static int prism2_enable_genesis(local_info_t *local, int hcr) -{ - struct net_device *dev = local->dev; - u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff }; - u8 readbuf[4]; - - printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n", - dev->name, hcr); - local->func->cor_sreset(local); - hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); - local->func->genesis_reset(local, hcr); - - /* Readback test */ - hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); - hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); - hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); - - if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) { - printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n", - hcr); - return 0; - } else { - printk(KERN_DEBUG "Readback test failed, HCR 0x%02x write %4ph read %4ph\n", - hcr, initseq, readbuf); - return 1; - } -} - - -static int prism2_get_ram_size(local_info_t *local) -{ - int ret; - - /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */ - if (prism2_enable_genesis(local, 0x1f) == 0) - ret = 8; - else if (prism2_enable_genesis(local, 0x0f) == 0) - ret = 16; - else - ret = -1; - - /* Disable genesis mode */ - local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17); - - return ret; -} - - -static int prism2_download_genesis(local_info_t *local, - struct prism2_download_data *param) -{ - struct net_device *dev = local->dev; - int ram16 = 0, i; - int ret = 0; - - if (local->hw_downloading) { - printk(KERN_WARNING "%s: Already downloading - aborting new " - "request\n", dev->name); - return -EBUSY; - } - - if (!local->func->genesis_reset || !local->func->cor_sreset) { - printk(KERN_INFO "%s: Genesis mode downloading not supported " - "with this hwmodel\n", dev->name); - return -EOPNOTSUPP; - } - - local->hw_downloading = 1; - - if (prism2_enable_aux_port(dev, 1)) { - printk(KERN_DEBUG "%s: failed to enable AUX port\n", - dev->name); - ret = -EIO; - goto out; - } - - if (local->sram_type == -1) { - /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */ - if (prism2_enable_genesis(local, 0x1f) == 0) { - ram16 = 0; - PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 " - "SRAM\n", dev->name); - } else if (prism2_enable_genesis(local, 0x0f) == 0) { - ram16 = 1; - PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 " - "SRAM\n", dev->name); - } else { - printk(KERN_DEBUG "%s: Could not initiate genesis " - "mode\n", dev->name); - ret = -EIO; - goto out; - } - } else { - if (prism2_enable_genesis(local, local->sram_type == 8 ? - 0x1f : 0x0f)) { - printk(KERN_DEBUG "%s: Failed to set Genesis " - "mode (sram_type=%d)\n", dev->name, - local->sram_type); - ret = -EIO; - goto out; - } - ram16 = local->sram_type != 8; - } - - for (i = 0; i < param->num_areas; i++) { - PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", - dev->name, param->data[i].len, param->data[i].addr); - if (hfa384x_to_aux(dev, param->data[i].addr, - param->data[i].len, param->data[i].data)) { - printk(KERN_WARNING "%s: RAM download at 0x%08x " - "(len=%d) failed\n", dev->name, - param->data[i].addr, param->data[i].len); - ret = -EIO; - goto out; - } - } - - PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n"); - local->func->genesis_reset(local, ram16 ? 0x07 : 0x17); - if (prism2_enable_aux_port(dev, 0)) { - printk(KERN_DEBUG "%s: Failed to disable AUX port\n", - dev->name); - } - - mdelay(5); - local->hw_downloading = 0; - - PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n"); - /* - * Make sure the INIT command does not generate a command completion - * event by disabling interrupts. - */ - hfa384x_disable_interrupts(dev); - if (prism2_hw_init(dev, 1)) { - printk(KERN_DEBUG "%s: Initialization after genesis mode " - "download failed\n", dev->name); - ret = -EIO; - goto out; - } - - PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n"); - if (prism2_hw_init2(dev, 1)) { - printk(KERN_DEBUG "%s: Initialization(2) after genesis mode " - "download failed\n", dev->name); - ret = -EIO; - goto out; - } - - out: - local->hw_downloading = 0; - return ret; -} - - -#ifdef PRISM2_NON_VOLATILE_DOWNLOAD -/* Note! Non-volatile downloading functionality has not yet been tested - * thoroughly and it may corrupt flash image and effectively kill the card that - * is being updated. You have been warned. */ - -static inline int prism2_download_block(struct net_device *dev, - u32 addr, u8 *data, - u32 bufaddr, int rest_len) -{ - u16 param0, param1; - int block_len; - - block_len = rest_len < 4096 ? rest_len : 4096; - - param0 = addr & 0xffff; - param1 = addr >> 16; - - HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF); - HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); - - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8), - param0)) { - printk(KERN_WARNING "%s: Flash download command execution " - "failed\n", dev->name); - return -1; - } - - if (hfa384x_to_aux(dev, bufaddr, block_len, data)) { - printk(KERN_WARNING "%s: flash download at 0x%08x " - "(len=%d) failed\n", dev->name, addr, block_len); - return -1; - } - - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - HFA384X_OUTW(0, HFA384X_PARAM1_OFF); - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8), - 0)) { - printk(KERN_WARNING "%s: Flash write command execution " - "failed\n", dev->name); - return -1; - } - - return block_len; -} - - -static int prism2_download_nonvolatile(local_info_t *local, - struct prism2_download_data *dl) -{ - struct net_device *dev = local->dev; - int ret = 0, i; - struct { - __le16 page; - __le16 offset; - __le16 len; - } dlbuffer; - u32 bufaddr; - - if (local->hw_downloading) { - printk(KERN_WARNING "%s: Already downloading - aborting new " - "request\n", dev->name); - return -1; - } - - ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER, - &dlbuffer, 6, 0); - - if (ret < 0) { - printk(KERN_WARNING "%s: Could not read download buffer " - "parameters\n", dev->name); - goto out; - } - - printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n", - le16_to_cpu(dlbuffer.len), - le16_to_cpu(dlbuffer.page), - le16_to_cpu(dlbuffer.offset)); - - bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset); - - local->hw_downloading = 1; - - if (!local->pri_only) { - prism2_hw_shutdown(dev, 0); - - if (prism2_hw_init(dev, 0)) { - printk(KERN_WARNING "%s: Could not initialize card for" - " download\n", dev->name); - ret = -1; - goto out; - } - } - - hfa384x_disable_interrupts(dev); - - if (prism2_enable_aux_port(dev, 1)) { - printk(KERN_WARNING "%s: Could not enable AUX port\n", - dev->name); - ret = -1; - goto out; - } - - printk(KERN_DEBUG "%s: starting flash download\n", dev->name); - for (i = 0; i < dl->num_areas; i++) { - int rest_len = dl->data[i].len; - int data_off = 0; - - while (rest_len > 0) { - int block_len; - - block_len = prism2_download_block( - dev, dl->data[i].addr + data_off, - dl->data[i].data + data_off, bufaddr, - rest_len); - - if (block_len < 0) { - ret = -1; - goto out; - } - - rest_len -= block_len; - data_off += block_len; - } - } - - HFA384X_OUTW(0, HFA384X_PARAM1_OFF); - HFA384X_OUTW(0, HFA384X_PARAM2_OFF); - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | - (HFA384X_PROGMODE_DISABLE << 8), 0)) { - printk(KERN_WARNING "%s: Download command execution failed\n", - dev->name); - ret = -1; - goto out; - } - - if (prism2_enable_aux_port(dev, 0)) { - printk(KERN_DEBUG "%s: Disabling AUX port failed\n", - dev->name); - /* continue anyway.. restart should have taken care of this */ - } - - mdelay(5); - - local->func->hw_reset(dev); - local->hw_downloading = 0; - if (prism2_hw_config(dev, 2)) { - printk(KERN_WARNING "%s: Card configuration after flash " - "download failed\n", dev->name); - ret = -1; - } else { - printk(KERN_INFO "%s: Card initialized successfully after " - "flash download\n", dev->name); - } - - out: - local->hw_downloading = 0; - return ret; -} -#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ - - -static void prism2_download_free_data(struct prism2_download_data *dl) -{ - int i; - - if (dl == NULL) - return; - - for (i = 0; i < dl->num_areas; i++) - kfree(dl->data[i].data); - kfree(dl); -} - - -static int prism2_download(local_info_t *local, - struct prism2_download_param *param) -{ - int ret = 0; - int i; - u32 total_len = 0; - struct prism2_download_data *dl = NULL; - - printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x " - "num_areas=%d\n", - param->dl_cmd, param->start_addr, param->num_areas); - - if (param->num_areas > 100) { - ret = -EINVAL; - goto out; - } - - dl = kzalloc(struct_size(dl, data, param->num_areas), GFP_KERNEL); - if (dl == NULL) { - ret = -ENOMEM; - goto out; - } - dl->dl_cmd = param->dl_cmd; - dl->start_addr = param->start_addr; - dl->num_areas = param->num_areas; - for (i = 0; i < param->num_areas; i++) { - PDEBUG(DEBUG_EXTRA2, - " area %d: addr=0x%08x len=%d ptr=0x%p\n", - i, param->data[i].addr, param->data[i].len, - param->data[i].ptr); - - dl->data[i].addr = param->data[i].addr; - dl->data[i].len = param->data[i].len; - - total_len += param->data[i].len; - if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN || - total_len > PRISM2_MAX_DOWNLOAD_LEN) { - ret = -E2BIG; - goto out; - } - - dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL); - if (dl->data[i].data == NULL) { - ret = -ENOMEM; - goto out; - } - - if (copy_from_user(dl->data[i].data, param->data[i].ptr, - param->data[i].len)) { - ret = -EFAULT; - goto out; - } - } - - switch (param->dl_cmd) { - case PRISM2_DOWNLOAD_VOLATILE: - case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT: - ret = prism2_download_volatile(local, dl); - break; - case PRISM2_DOWNLOAD_VOLATILE_GENESIS: - case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT: - ret = prism2_download_genesis(local, dl); - break; - case PRISM2_DOWNLOAD_NON_VOLATILE: -#ifdef PRISM2_NON_VOLATILE_DOWNLOAD - ret = prism2_download_nonvolatile(local, dl); -#else /* PRISM2_NON_VOLATILE_DOWNLOAD */ - printk(KERN_INFO "%s: non-volatile downloading not enabled\n", - local->dev->name); - ret = -EOPNOTSUPP; -#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ - break; - default: - printk(KERN_DEBUG "%s: unsupported download command %d\n", - local->dev->name, param->dl_cmd); - ret = -EINVAL; - break; - } - - out: - if (ret == 0 && dl && - param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) { - prism2_download_free_data(local->dl_pri); - local->dl_pri = dl; - } else if (ret == 0 && dl && - param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) { - prism2_download_free_data(local->dl_sec); - local->dl_sec = dl; - } else - prism2_download_free_data(dl); - - return ret; -} diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c deleted file mode 100644 index b74f4cb5d6..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ /dev/null @@ -1,3387 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Host AP (software wireless LAN access point) driver for - * Intersil Prism2/2.5/3. - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * <j@w1.fi> - * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> - * - * FIX: - * - there is currently no way of associating TX packets to correct wds device - * when TX Exc/OK event occurs, so all tx_packets and some - * tx_errors/tx_dropped are added to the main netdevice; using sw_support - * field in txdesc might be used to fix this (using Alloc event to increment - * tx_packets would need some further info in txfid table) - * - * Buffer Access Path (BAP) usage: - * Prism2 cards have two separate BAPs for accessing the card memory. These - * should allow concurrent access to two different frames and the driver - * previously used BAP0 for sending data and BAP1 for receiving data. - * However, there seems to be number of issues with concurrent access and at - * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI - * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between - * host and card memories. BAP0 accesses are protected with local->baplock - * (spin_lock_bh) to prevent concurrent use. - */ - - - -#include <asm/delay.h> -#include <linux/uaccess.h> - -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/if_arp.h> -#include <linux/delay.h> -#include <linux/random.h> -#include <linux/wait.h> -#include <linux/sched/signal.h> -#include <linux/rtnetlink.h> -#include <linux/wireless.h> -#include <net/iw_handler.h> -#include <net/lib80211.h> -#include <asm/irq.h> - -#include "hostap_80211.h" -#include "hostap.h" -#include "hostap_ap.h" - - -/* #define final_version */ - -static int mtu = 1500; -module_param(mtu, int, 0444); -MODULE_PARM_DESC(mtu, "Maximum transfer unit"); - -static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS }; -module_param_array(channel, int, NULL, 0444); -MODULE_PARM_DESC(channel, "Initial channel"); - -static char essid[33] = "test"; -module_param_string(essid, essid, sizeof(essid), 0444); -MODULE_PARM_DESC(essid, "Host AP's ESSID"); - -static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS }; -module_param_array(iw_mode, int, NULL, 0444); -MODULE_PARM_DESC(iw_mode, "Initial operation mode"); - -static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS }; -module_param_array(beacon_int, int, NULL, 0444); -MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)"); - -static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS }; -module_param_array(dtim_period, int, NULL, 0444); -MODULE_PARM_DESC(dtim_period, "DTIM period"); - -static char dev_template[16] = "wlan%d"; -module_param_string(dev_template, dev_template, sizeof(dev_template), 0444); -MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: " - "wlan%d)"); - -#ifdef final_version -#define EXTRA_EVENTS_WTERR 0 -#else -/* check WTERR events (Wait Time-out) in development versions */ -#define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR -#endif - -/* Events that will be using BAP0 */ -#define HFA384X_BAP0_EVENTS \ - (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX) - -/* event mask, i.e., events that will result in an interrupt */ -#define HFA384X_EVENT_MASK \ - (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \ - HFA384X_EV_CMD | HFA384X_EV_TICK | \ - EXTRA_EVENTS_WTERR) - -/* Default TX control flags: use 802.11 headers and request interrupt for - * failed transmits. Frames that request ACK callback, will add - * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy. - */ -#define HFA384X_TX_CTRL_FLAGS \ - (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX) - - -/* ca. 1 usec */ -#define HFA384X_CMD_BUSY_TIMEOUT 5000 -#define HFA384X_BAP_BUSY_TIMEOUT 50000 - -/* ca. 10 usec */ -#define HFA384X_CMD_COMPL_TIMEOUT 20000 -#define HFA384X_DL_COMPL_TIMEOUT 1000000 - -/* Wait times for initialization; yield to other processes to avoid busy - * waiting for long time. */ -#define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */ -#define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */ - - -static void prism2_hw_reset(struct net_device *dev); -static void prism2_check_sta_fw_version(local_info_t *local); - -#ifdef PRISM2_DOWNLOAD_SUPPORT -/* hostap_download.c */ -static const struct proc_ops prism2_download_aux_dump_proc_ops; -static u8 * prism2_read_pda(struct net_device *dev); -static int prism2_download(local_info_t *local, - struct prism2_download_param *param); -static void prism2_download_free_data(struct prism2_download_data *dl); -static int prism2_download_volatile(local_info_t *local, - struct prism2_download_data *param); -static int prism2_download_genesis(local_info_t *local, - struct prism2_download_data *param); -static int prism2_get_ram_size(local_info_t *local); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - - - -#ifndef final_version -/* magic value written to SWSUPPORT0 reg. for detecting whether card is still - * present */ -#define HFA384X_MAGIC 0x8A32 -#endif - -static void hfa384x_read_regs(struct net_device *dev, - struct hfa384x_regs *regs) -{ - regs->cmd = HFA384X_INW(HFA384X_CMD_OFF); - regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); - regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF); - regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF); - regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF); -} - - -/** - * __hostap_cmd_queue_free - Free Prism2 command queue entry (private) - * @local: pointer to private Host AP driver data - * @entry: Prism2 command queue entry to be freed - * @del_req: request the entry to be removed - * - * Internal helper function for freeing Prism2 command queue entries. - * Caller must have acquired local->cmdlock before calling this function. - */ -static inline void __hostap_cmd_queue_free(local_info_t *local, - struct hostap_cmd_queue *entry, - int del_req) -{ - if (del_req) { - entry->del_req = 1; - if (!list_empty(&entry->list)) { - list_del_init(&entry->list); - local->cmd_queue_len--; - } - } - - if (refcount_dec_and_test(&entry->usecnt) && entry->del_req) - kfree(entry); -} - - -/** - * hostap_cmd_queue_free - Free Prism2 command queue entry - * @local: pointer to private Host AP driver data - * @entry: Prism2 command queue entry to be freed - * @del_req: request the entry to be removed - * - * Free a Prism2 command queue entry. - */ -static inline void hostap_cmd_queue_free(local_info_t *local, - struct hostap_cmd_queue *entry, - int del_req) -{ - unsigned long flags; - - spin_lock_irqsave(&local->cmdlock, flags); - __hostap_cmd_queue_free(local, entry, del_req); - spin_unlock_irqrestore(&local->cmdlock, flags); -} - - -/** - * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries - * @local: pointer to private Host AP driver data - */ -static void prism2_clear_cmd_queue(local_info_t *local) -{ - struct list_head *ptr, *n; - unsigned long flags; - struct hostap_cmd_queue *entry; - - spin_lock_irqsave(&local->cmdlock, flags); - list_for_each_safe(ptr, n, &local->cmd_queue) { - entry = list_entry(ptr, struct hostap_cmd_queue, list); - refcount_inc(&entry->usecnt); - printk(KERN_DEBUG "%s: removed pending cmd_queue entry " - "(type=%d, cmd=0x%04x, param0=0x%04x)\n", - local->dev->name, entry->type, entry->cmd, - entry->param0); - __hostap_cmd_queue_free(local, entry, 1); - } - if (local->cmd_queue_len) { - /* This should not happen; print debug message and clear - * queue length. */ - printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after " - "flush\n", local->dev->name, local->cmd_queue_len); - local->cmd_queue_len = 0; - } - spin_unlock_irqrestore(&local->cmdlock, flags); -} - - -/** - * hfa384x_cmd_issue - Issue a Prism2 command to the hardware - * @dev: pointer to net_device - * @entry: Prism2 command queue entry to be issued - */ -static int hfa384x_cmd_issue(struct net_device *dev, - struct hostap_cmd_queue *entry) -{ - struct hostap_interface *iface; - local_info_t *local; - int tries; - u16 reg; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->card_present && !local->func->card_present(local)) - return -ENODEV; - - if (entry->issued) { - printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n", - dev->name, entry); - } - - /* wait until busy bit is clear; this should always be clear since the - * commands are serialized */ - tries = HFA384X_CMD_BUSY_TIMEOUT; - while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { - tries--; - udelay(1); - } -#ifndef final_version - if (tries != HFA384X_CMD_BUSY_TIMEOUT) { - prism2_io_debug_error(dev, 1); - printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy " - "for %d usec\n", dev->name, - HFA384X_CMD_BUSY_TIMEOUT - tries); - } -#endif - if (tries == 0) { - reg = HFA384X_INW(HFA384X_CMD_OFF); - prism2_io_debug_error(dev, 2); - printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - " - "reg=0x%04x\n", dev->name, reg); - return -ETIMEDOUT; - } - - /* write command */ - spin_lock_irqsave(&local->cmdlock, flags); - HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF); - HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF); - entry->issued = 1; - spin_unlock_irqrestore(&local->cmdlock, flags); - - return 0; -} - - -/** - * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - * @param1: value for Param1 register (pointer; %NULL if not used) - * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed - * - * Issue given command (possibly after waiting in command queue) and sleep - * until the command is completed (or timed out or interrupted). This can be - * called only from user process context. - */ -static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0, - u16 *param1, u16 *resp0) -{ - struct hostap_interface *iface; - local_info_t *local; - int err, res, issue, issued = 0; - unsigned long flags; - struct hostap_cmd_queue *entry; - DECLARE_WAITQUEUE(wait, current); - - iface = netdev_priv(dev); - local = iface->local; - - if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) { - printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", - dev->name); - return -1; - } - - if (signal_pending(current)) - return -EINTR; - - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (entry == NULL) - return -ENOMEM; - - refcount_set(&entry->usecnt, 1); - entry->type = CMD_SLEEP; - entry->cmd = cmd; - entry->param0 = param0; - if (param1) - entry->param1 = *param1; - init_waitqueue_head(&entry->compl); - - /* prepare to wait for command completion event, but do not sleep yet - */ - add_wait_queue(&entry->compl, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&local->cmdlock, flags); - issue = list_empty(&local->cmd_queue); - if (issue) - entry->issuing = 1; - list_add_tail(&entry->list, &local->cmd_queue); - local->cmd_queue_len++; - spin_unlock_irqrestore(&local->cmdlock, flags); - - err = 0; - if (!issue) - goto wait_completion; - - if (signal_pending(current)) - err = -EINTR; - - if (!err) { - if (hfa384x_cmd_issue(dev, entry)) - err = -ETIMEDOUT; - else - issued = 1; - } - - wait_completion: - if (!err && entry->type != CMD_COMPLETED) { - /* sleep until command is completed or timed out */ - res = schedule_timeout(2 * HZ); - } else - res = -1; - - if (!err && signal_pending(current)) - err = -EINTR; - - if (err && issued) { - /* the command was issued, so a CmdCompl event should occur - * soon; however, there's a pending signal and - * schedule_timeout() would be interrupted; wait a short period - * of time to avoid removing entry from the list before - * CmdCompl event */ - udelay(300); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&entry->compl, &wait); - - /* If entry->list is still in the list, it must be removed - * first and in this case prism2_cmd_ev() does not yet have - * local reference to it, and the data can be kfree()'d - * here. If the command completion event is still generated, - * it will be assigned to next (possibly) pending command, but - * the driver will reset the card anyway due to timeout - * - * If the entry is not in the list prism2_cmd_ev() has a local - * reference to it, but keeps cmdlock as long as the data is - * needed, so the data can be kfree()'d here. */ - - /* FIX: if the entry->list is in the list, it has not been completed - * yet, so removing it here is somewhat wrong.. this could cause - * references to freed memory and next list_del() causing NULL pointer - * dereference.. it would probably be better to leave the entry in the - * list and the list should be emptied during hw reset */ - - spin_lock_irqsave(&local->cmdlock, flags); - if (!list_empty(&entry->list)) { - printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? " - "(entry=%p, type=%d, res=%d)\n", dev->name, entry, - entry->type, res); - list_del_init(&entry->list); - local->cmd_queue_len--; - } - spin_unlock_irqrestore(&local->cmdlock, flags); - - if (err) { - printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n", - dev->name, err); - res = err; - goto done; - } - - if (entry->type != CMD_COMPLETED) { - u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF); - printk(KERN_DEBUG "%s: hfa384x_cmd: command was not " - "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, " - "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name, - res, entry, entry->type, entry->cmd, entry->param0, reg, - HFA384X_INW(HFA384X_INTEN_OFF)); - if (reg & HFA384X_EV_CMD) { - /* Command completion event is pending, but the - * interrupt was not delivered - probably an issue - * with pcmcia-cs configuration. */ - printk(KERN_WARNING "%s: interrupt delivery does not " - "seem to work\n", dev->name); - } - prism2_io_debug_error(dev, 3); - res = -ETIMEDOUT; - goto done; - } - - if (resp0 != NULL) - *resp0 = entry->resp0; -#ifndef final_version - if (entry->res) { - printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, " - "resp0=0x%04x\n", - dev->name, cmd, entry->res, entry->resp0); - } -#endif /* final_version */ - - res = entry->res; - done: - hostap_cmd_queue_free(local, entry, 1); - return res; -} - - -/** - * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - * @callback: command completion callback function (%NULL = no callback) - * @context: context data to be given to the callback function - * - * Issue given command (possibly after waiting in command queue) and use - * callback function to indicate command completion. This can be called both - * from user and interrupt context. The callback function will be called in - * hardware IRQ context. It can be %NULL, when no function is called when - * command is completed. - */ -static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, - void (*callback)(struct net_device *dev, - long context, u16 resp0, - u16 status), - long context) -{ - struct hostap_interface *iface; - local_info_t *local; - int issue, ret; - unsigned long flags; - struct hostap_cmd_queue *entry; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) { - printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", - dev->name); - return -1; - } - - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (entry == NULL) - return -ENOMEM; - - refcount_set(&entry->usecnt, 1); - entry->type = CMD_CALLBACK; - entry->cmd = cmd; - entry->param0 = param0; - entry->callback = callback; - entry->context = context; - - spin_lock_irqsave(&local->cmdlock, flags); - issue = list_empty(&local->cmd_queue); - if (issue) - entry->issuing = 1; - list_add_tail(&entry->list, &local->cmd_queue); - local->cmd_queue_len++; - spin_unlock_irqrestore(&local->cmdlock, flags); - - if (issue && hfa384x_cmd_issue(dev, entry)) - ret = -ETIMEDOUT; - else - ret = 0; - - hostap_cmd_queue_free(local, entry, ret); - - return ret; -} - - -/** - * __hfa384x_cmd_no_wait - Issue a Prism2 command (private) - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - * @io_debug_num: I/O debug error number - * - * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait(). - */ -static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0, - int io_debug_num) -{ - int tries; - u16 reg; - - /* wait until busy bit is clear; this should always be clear since the - * commands are serialized */ - tries = HFA384X_CMD_BUSY_TIMEOUT; - while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { - tries--; - udelay(1); - } - if (tries == 0) { - reg = HFA384X_INW(HFA384X_CMD_OFF); - prism2_io_debug_error(dev, io_debug_num); - printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - " - "reg=0x%04x\n", dev->name, io_debug_num, reg); - return -ETIMEDOUT; - } - - /* write command */ - HFA384X_OUTW(param0, HFA384X_PARAM0_OFF); - HFA384X_OUTW(cmd, HFA384X_CMD_OFF); - - return 0; -} - - -/** - * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - */ -static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0) -{ - int res, tries; - u16 reg; - - res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4); - if (res) - return res; - - /* wait for command completion */ - if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD) - tries = HFA384X_DL_COMPL_TIMEOUT; - else - tries = HFA384X_CMD_COMPL_TIMEOUT; - - while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && - tries > 0) { - tries--; - udelay(10); - } - if (tries == 0) { - reg = HFA384X_INW(HFA384X_EVSTAT_OFF); - prism2_io_debug_error(dev, 5); - printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - " - "reg=0x%04x\n", dev->name, reg); - return -ETIMEDOUT; - } - - res = (HFA384X_INW(HFA384X_STATUS_OFF) & - (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | - BIT(8))) >> 8; -#ifndef final_version - if (res) { - printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n", - dev->name, cmd, res); - } -#endif - - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - - return res; -} - - -/** - * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion - * @dev: pointer to net_device - * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) - * @param0: value for Param0 register - */ -static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, - u16 param0) -{ - return __hfa384x_cmd_no_wait(dev, cmd, param0, 6); -} - - -/** - * prism2_cmd_ev - Prism2 command completion event handler - * @dev: pointer to net_device - * - * Interrupt handler for command completion events. Called by the main - * interrupt handler in hardware IRQ context. Read Resp0 and status registers - * from the hardware and ACK the event. Depending on the issued command type - * either wake up the sleeping process that is waiting for command completion - * or call the callback function. Issue the next command, if one is pending. - */ -static void prism2_cmd_ev(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hostap_cmd_queue *entry = NULL; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock(&local->cmdlock); - if (!list_empty(&local->cmd_queue)) { - entry = list_entry(local->cmd_queue.next, - struct hostap_cmd_queue, list); - refcount_inc(&entry->usecnt); - list_del_init(&entry->list); - local->cmd_queue_len--; - - if (!entry->issued) { - printk(KERN_DEBUG "%s: Command completion event, but " - "cmd not issued\n", dev->name); - __hostap_cmd_queue_free(local, entry, 1); - entry = NULL; - } - } - spin_unlock(&local->cmdlock); - - if (!entry) { - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - printk(KERN_DEBUG "%s: Command completion event, but no " - "pending commands\n", dev->name); - return; - } - - entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF); - entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) & - (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | - BIT(9) | BIT(8))) >> 8; - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - - /* TODO: rest of the CmdEv handling could be moved to tasklet */ - if (entry->type == CMD_SLEEP) { - entry->type = CMD_COMPLETED; - wake_up_interruptible(&entry->compl); - } else if (entry->type == CMD_CALLBACK) { - if (entry->callback) - entry->callback(dev, entry->context, entry->resp0, - entry->res); - } else { - printk(KERN_DEBUG "%s: Invalid command completion type %d\n", - dev->name, entry->type); - } - hostap_cmd_queue_free(local, entry, 1); - - /* issue next command, if pending */ - entry = NULL; - spin_lock(&local->cmdlock); - if (!list_empty(&local->cmd_queue)) { - entry = list_entry(local->cmd_queue.next, - struct hostap_cmd_queue, list); - if (entry->issuing) { - /* hfa384x_cmd() has already started issuing this - * command, so do not start here */ - entry = NULL; - } - if (entry) - refcount_inc(&entry->usecnt); - } - spin_unlock(&local->cmdlock); - - if (entry) { - /* issue next command; if command issuing fails, remove the - * entry from cmd_queue */ - int res = hfa384x_cmd_issue(dev, entry); - spin_lock(&local->cmdlock); - __hostap_cmd_queue_free(local, entry, res); - spin_unlock(&local->cmdlock); - } -} - - -static int hfa384x_wait_offset(struct net_device *dev, u16 o_off) -{ - int tries = HFA384X_BAP_BUSY_TIMEOUT; - int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; - - while (res && tries > 0) { - tries--; - udelay(1); - res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; - } - return res; -} - - -/* Offset must be even */ -static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id, - int offset) -{ - u16 o_off, s_off; - int ret = 0; - - if (offset % 2 || bap > 1) - return -EINVAL; - - if (bap == BAP1) { - o_off = HFA384X_OFFSET1_OFF; - s_off = HFA384X_SELECT1_OFF; - } else { - o_off = HFA384X_OFFSET0_OFF; - s_off = HFA384X_SELECT0_OFF; - } - - if (hfa384x_wait_offset(dev, o_off)) { - prism2_io_debug_error(dev, 7); - printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n", - dev->name); - ret = -ETIMEDOUT; - goto out; - } - - HFA384X_OUTW(id, s_off); - HFA384X_OUTW(offset, o_off); - - if (hfa384x_wait_offset(dev, o_off)) { - prism2_io_debug_error(dev, 8); - printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n", - dev->name); - ret = -ETIMEDOUT; - goto out; - } -#ifndef final_version - if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) { - prism2_io_debug_error(dev, 9); - printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error " - "(%d,0x04%x,%d); reg=0x%04x\n", - dev->name, bap, id, offset, HFA384X_INW(o_off)); - ret = -EINVAL; - } -#endif - - out: - return ret; -} - - -static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, - int exact_len) -{ - struct hostap_interface *iface; - local_info_t *local; - int res, rlen = 0; - struct hfa384x_rid_hdr rec; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI " - "f/w\n", dev->name, rid, len); - return -ENOTTY; /* Well.. not really correct, but return - * something unique enough.. */ - } - - if ((local->func->card_present && !local->func->card_present(local)) || - local->hw_downloading) - return -ENODEV; - - res = mutex_lock_interruptible(&local->rid_bap_mtx); - if (res) - return res; - - res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL); - if (res) { - printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " - "(res=%d, rid=%04x, len=%d)\n", - dev->name, res, rid, len); - mutex_unlock(&local->rid_bap_mtx); - return res; - } - - spin_lock_bh(&local->baplock); - - res = hfa384x_setup_bap(dev, BAP0, rid, 0); - if (res) - goto unlock; - - res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); - if (res) - goto unlock; - - if (le16_to_cpu(rec.len) == 0) { - /* RID not available */ - res = -ENODATA; - goto unlock; - } - - rlen = (le16_to_cpu(rec.len) - 1) * 2; - if (exact_len && rlen != len) { - printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " - "rid=0x%04x, len=%d (expected %d)\n", - dev->name, rid, rlen, len); - res = -ENODATA; - } - - res = hfa384x_from_bap(dev, BAP0, buf, len); - -unlock: - spin_unlock_bh(&local->baplock); - mutex_unlock(&local->rid_bap_mtx); - - if (res) { - if (res != -ENODATA) - printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, " - "len=%d) - failed - res=%d\n", dev->name, rid, - len, res); - if (res == -ETIMEDOUT) - prism2_hw_reset(dev); - return res; - } - - return rlen; -} - - -static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_rid_hdr rec; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI " - "f/w\n", dev->name, rid, len); - return -ENOTTY; /* Well.. not really correct, but return - * something unique enough.. */ - } - - if ((local->func->card_present && !local->func->card_present(local)) || - local->hw_downloading) - return -ENODEV; - - rec.rid = cpu_to_le16(rid); - /* RID len in words and +1 for rec.rid */ - rec.len = cpu_to_le16(len / 2 + len % 2 + 1); - - res = mutex_lock_interruptible(&local->rid_bap_mtx); - if (res) - return res; - - spin_lock_bh(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, rid, 0); - if (!res) - res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec)); - if (!res) - res = hfa384x_to_bap(dev, BAP0, buf, len); - spin_unlock_bh(&local->baplock); - - if (res) { - printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " - "failed - res=%d\n", dev->name, rid, len, res); - mutex_unlock(&local->rid_bap_mtx); - return res; - } - - res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); - mutex_unlock(&local->rid_bap_mtx); - - if (res) { - printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " - "failed (res=%d, rid=%04x, len=%d)\n", - dev->name, res, rid, len); - - if (res == -ETIMEDOUT) - prism2_hw_reset(dev); - } - - return res; -} - - -static void hfa384x_disable_interrupts(struct net_device *dev) -{ - /* disable interrupts and clear event status */ - HFA384X_OUTW(0, HFA384X_INTEN_OFF); - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); -} - - -static void hfa384x_enable_interrupts(struct net_device *dev) -{ - /* ack pending events and enable interrupts from selected events */ - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); - HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); -} - - -static void hfa384x_events_no_bap0(struct net_device *dev) -{ - HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS, - HFA384X_INTEN_OFF); -} - - -static void hfa384x_events_all(struct net_device *dev) -{ - HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); -} - - -static void hfa384x_events_only_cmd(struct net_device *dev) -{ - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF); -} - - -static u16 hfa384x_allocate_fid(struct net_device *dev, int len) -{ - u16 fid; - unsigned long delay; - - /* FIX: this could be replace with hfa384x_cmd() if the Alloc event - * below would be handled like CmdCompl event (sleep here, wake up from - * interrupt handler */ - if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) { - printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n", - dev->name, len); - return 0xffff; - } - - delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT; - while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) && - time_before(jiffies, delay)) - yield(); - if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) { - printk("%s: fid allocate, len=%d - timeout\n", dev->name, len); - return 0xffff; - } - - fid = HFA384X_INW(HFA384X_ALLOCFID_OFF); - HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); - - return fid; -} - - -static int prism2_reset_port(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - if (!local->dev_enabled) - return 0; - - res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, - NULL, NULL); - if (res) - printk(KERN_DEBUG "%s: reset port failed to disable port\n", - dev->name); - else { - res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, - NULL, NULL); - if (res) - printk(KERN_DEBUG "%s: reset port failed to enable " - "port\n", dev->name); - } - - /* It looks like at least some STA firmware versions reset - * fragmentation threshold back to 2346 after enable command. Restore - * the configured value, if it differs from this default. */ - if (local->fragm_threshold != 2346 && - hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, - local->fragm_threshold)) { - printk(KERN_DEBUG "%s: failed to restore fragmentation " - "threshold (%d) after Port0 enable\n", - dev->name, local->fragm_threshold); - } - - /* Some firmwares lose antenna selection settings on reset */ - (void) hostap_set_antsel(local); - - return res; -} - - -static int prism2_get_version_info(struct net_device *dev, u16 rid, - const char *txt) -{ - struct hfa384x_comp_ident comp; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - /* PRI f/w not yet available - cannot read RIDs */ - return -1; - } - if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) { - printk(KERN_DEBUG "Could not get RID for component %s\n", txt); - return -1; - } - - printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt, - __le16_to_cpu(comp.id), __le16_to_cpu(comp.major), - __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant)); - return 0; -} - - -static int prism2_setup_rids(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - __le16 tmp; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000); - - if (!local->fw_ap) { - u16 tmp1 = hostap_get_porttype(local); - ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp1); - if (ret) { - printk("%s: Port type setting to %d failed\n", - dev->name, tmp1); - goto fail; - } - } - - /* Setting SSID to empty string seems to kill the card in Host AP mode - */ - if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') { - ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, - local->essid); - if (ret) { - printk("%s: AP own SSID setting failed\n", dev->name); - goto fail; - } - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN, - PRISM2_DATA_MAXLEN); - if (ret) { - printk("%s: MAC data length setting to %d failed\n", - dev->name, PRISM2_DATA_MAXLEN); - goto fail; - } - - if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) { - printk("%s: Channel list read failed\n", dev->name); - ret = -EINVAL; - goto fail; - } - local->channel_mask = le16_to_cpu(tmp); - - if (local->channel < 1 || local->channel > 14 || - !(local->channel_mask & (1 << (local->channel - 1)))) { - printk(KERN_WARNING "%s: Channel setting out of range " - "(%d)!\n", dev->name, local->channel); - ret = -EBUSY; - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel); - if (ret) { - printk("%s: Channel setting to %d failed\n", - dev->name, local->channel); - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, - local->beacon_int); - if (ret) { - printk("%s: Beacon interval setting to %d failed\n", - dev->name, local->beacon_int); - /* this may fail with Symbol/Lucent firmware */ - if (ret == -ETIMEDOUT) - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, - local->dtim_period); - if (ret) { - printk("%s: DTIM period setting to %d failed\n", - dev->name, local->dtim_period); - /* this may fail with Symbol/Lucent firmware */ - if (ret == -ETIMEDOUT) - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, - local->is_promisc); - if (ret) - printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n", - dev->name, local->is_promisc); - - if (!local->fw_ap) { - ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, - local->essid); - if (ret) { - printk("%s: Desired SSID setting failed\n", dev->name); - goto fail; - } - } - - /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and - * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic - * rates */ - if (local->tx_rate_control == 0) { - local->tx_rate_control = - HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | - HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - } - if (local->basic_rates == 0) - local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS; - - if (!local->fw_ap) { - ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, - local->tx_rate_control); - if (ret) { - printk("%s: TXRateControl setting to %d failed\n", - dev->name, local->tx_rate_control); - goto fail; - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, - local->tx_rate_control); - if (ret) { - printk("%s: cnfSupportedRates setting to %d failed\n", - dev->name, local->tx_rate_control); - } - - ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, - local->basic_rates); - if (ret) { - printk("%s: cnfBasicRates setting to %d failed\n", - dev->name, local->basic_rates); - } - - ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1); - if (ret) { - printk("%s: Create IBSS setting to 1 failed\n", - dev->name); - } - } - - if (local->name_set) - (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, - local->name); - - if (hostap_set_encryption(local)) { - printk(KERN_INFO "%s: could not configure encryption\n", - dev->name); - } - - (void) hostap_set_antsel(local); - - if (hostap_set_roaming(local)) { - printk(KERN_INFO "%s: could not set host roaming\n", - dev->name); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) && - hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec)) - printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n", - dev->name, local->enh_sec); - - /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently - * not working correctly (last seven counters report bogus values). - * This has been fixed in 0.8.2, so enable 32-bit tallies only - * beginning with that firmware version. Another bug fix for 32-bit - * tallies in 1.4.0; should 16-bit tallies be used for some other - * versions, too? */ - if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) { - if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) { - printk(KERN_INFO "%s: cnfThirty2Tally setting " - "failed\n", dev->name); - local->tallies32 = 0; - } else - local->tallies32 = 1; - } else - local->tallies32 = 0; - - hostap_set_auth_algs(local); - - if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, - local->fragm_threshold)) { - printk(KERN_INFO "%s: setting FragmentationThreshold to %d " - "failed\n", dev->name, local->fragm_threshold); - } - - if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD, - local->rts_threshold)) { - printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n", - dev->name, local->rts_threshold); - } - - if (local->manual_retry_count >= 0 && - hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, - local->manual_retry_count)) { - printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n", - dev->name, local->manual_retry_count); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) && - hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) { - local->rssi_to_dBm = le16_to_cpu(tmp); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa && - hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) { - printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n", - dev->name); - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem && - hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT, - local->generic_elem, local->generic_elem_len)) { - printk(KERN_INFO "%s: setting genericElement failed\n", - dev->name); - } - - fail: - return ret; -} - - -static int prism2_hw_init(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - int ret, first = 1; - unsigned long start, delay; - - PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n"); - - iface = netdev_priv(dev); - local = iface->local; - - clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits); - - init: - /* initialize HFA 384x */ - ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0); - if (ret) { - printk(KERN_INFO "%s: first command failed - assuming card " - "does not have primary firmware\n", dev_info); - } - - if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { - /* EvStat has Cmd bit set in some cases, so retry once if no - * wait was needed */ - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - printk(KERN_DEBUG "%s: init command completed too quickly - " - "retrying\n", dev->name); - first = 0; - goto init; - } - - start = jiffies; - delay = jiffies + HFA384X_INIT_TIMEOUT; - while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && - time_before(jiffies, delay)) - yield(); - if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { - printk(KERN_DEBUG "%s: assuming no Primary image in " - "flash - card initialization not completed\n", - dev_info); - local->no_pri = 1; -#ifdef PRISM2_DOWNLOAD_SUPPORT - if (local->sram_type == -1) - local->sram_type = prism2_get_ram_size(local); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - return 1; - } - local->no_pri = 0; - printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n", - (jiffies - start) * 1000 / HZ); - HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); - return 0; -} - - -static int prism2_hw_init2(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - int i; - - iface = netdev_priv(dev); - local = iface->local; - -#ifdef PRISM2_DOWNLOAD_SUPPORT - kfree(local->pda); - if (local->no_pri) - local->pda = NULL; - else - local->pda = prism2_read_pda(dev); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - hfa384x_disable_interrupts(dev); - -#ifndef final_version - HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF); - if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { - printk("SWSUPPORT0 write/read failed: %04X != %04X\n", - HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC); - goto failed; - } -#endif - - if (initial || local->pri_only) { - hfa384x_events_only_cmd(dev); - /* get card version information */ - if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") || - prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) { - hfa384x_disable_interrupts(dev); - goto failed; - } - - if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) { - printk(KERN_DEBUG "%s: Failed to read STA f/w version " - "- only Primary f/w present\n", dev->name); - local->pri_only = 1; - return 0; - } - local->pri_only = 0; - hfa384x_disable_interrupts(dev); - } - - /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and - * enable interrupts before this. This would also require some sort of - * sleeping AllocEv waiting */ - - /* allocate TX FIDs */ - local->txfid_len = PRISM2_TXFID_LEN; - for (i = 0; i < PRISM2_TXFID_COUNT; i++) { - local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len); - if (local->txfid[i] == 0xffff && local->txfid_len > 1600) { - local->txfid[i] = hfa384x_allocate_fid(dev, 1600); - if (local->txfid[i] != 0xffff) { - printk(KERN_DEBUG "%s: Using shorter TX FID " - "(1600 bytes)\n", dev->name); - local->txfid_len = 1600; - } - } - if (local->txfid[i] == 0xffff) - goto failed; - local->intransmitfid[i] = PRISM2_TXFID_EMPTY; - } - - hfa384x_events_only_cmd(dev); - - if (initial) { - u8 addr[ETH_ALEN] = {}; - struct list_head *ptr; - - prism2_check_sta_fw_version(local); - - if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, - addr, ETH_ALEN, 1) < 0) { - printk("%s: could not get own MAC address\n", - dev->name); - } - eth_hw_addr_set(dev, addr); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - eth_hw_addr_inherit(iface->dev, dev); - } - } else if (local->fw_ap) - prism2_check_sta_fw_version(local); - - prism2_setup_rids(dev); - - /* MAC is now configured, but port 0 is not yet enabled */ - return 0; - - failed: - if (!local->no_pri) - printk(KERN_WARNING "%s: Initialization failed\n", dev_info); - return 1; -} - - -static int prism2_hw_enable(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - int was_resetting; - - iface = netdev_priv(dev); - local = iface->local; - was_resetting = local->hw_resetting; - - if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) { - printk("%s: MAC port 0 enabling failed\n", dev->name); - return 1; - } - - local->hw_ready = 1; - local->hw_reset_tries = 0; - local->hw_resetting = 0; - hfa384x_enable_interrupts(dev); - - /* at least D-Link DWL-650 seems to require additional port reset - * before it starts acting as an AP, so reset port automatically - * here just in case */ - if (initial && prism2_reset_port(dev)) { - printk("%s: MAC port 0 resetting failed\n", dev->name); - return 1; - } - - if (was_resetting && netif_queue_stopped(dev)) { - /* If hw_reset() was called during pending transmit, netif - * queue was stopped. Wake it up now since the wlan card has - * been resetted. */ - netif_wake_queue(dev); - } - - return 0; -} - - -static int prism2_hw_config(struct net_device *dev, int initial) -{ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->hw_downloading) - return 1; - - if (prism2_hw_init(dev, initial)) { - return local->no_pri ? 0 : 1; - } - - if (prism2_hw_init2(dev, initial)) - return 1; - - /* Enable firmware if secondary image is loaded and at least one of the - * netdevices is up. */ - if (!local->pri_only && - (initial == 0 || (initial == 2 && local->num_dev_open > 0))) { - if (!local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_ENABLE); - local->dev_enabled = 1; - return prism2_hw_enable(dev, initial); - } - - return 0; -} - - -static void prism2_hw_shutdown(struct net_device *dev, int no_disable) -{ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - /* Allow only command completion events during disable */ - hfa384x_events_only_cmd(dev); - - local->hw_ready = 0; - if (local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_DISABLE); - local->dev_enabled = 0; - - if (local->func->card_present && !local->func->card_present(local)) { - printk(KERN_DEBUG "%s: card already removed or not configured " - "during shutdown\n", dev->name); - return; - } - - if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 && - hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL)) - printk(KERN_WARNING "%s: Shutdown failed\n", dev_info); - - hfa384x_disable_interrupts(dev); - - if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL) - hfa384x_events_only_cmd(dev); - else - prism2_clear_cmd_queue(local); -} - - -static void prism2_hw_reset(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - -#if 0 - static long last_reset = 0; - - /* do not reset card more than once per second to avoid ending up in a - * busy loop resetting the card */ - if (time_before_eq(jiffies, last_reset + HZ)) - return; - last_reset = jiffies; -#endif - - iface = netdev_priv(dev); - local = iface->local; - - if (local->hw_downloading) - return; - - if (local->hw_resetting) { - printk(KERN_WARNING "%s: %s: already resetting card - " - "ignoring reset request\n", dev_info, dev->name); - return; - } - - local->hw_reset_tries++; - if (local->hw_reset_tries > 10) { - printk(KERN_WARNING "%s: too many reset tries, skipping\n", - dev->name); - return; - } - - printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name); - hfa384x_disable_interrupts(dev); - local->hw_resetting = 1; - if (local->func->cor_sreset) { - /* Host system seems to hang in some cases with high traffic - * load or shared interrupts during COR sreset. Disable shared - * interrupts during reset to avoid these crashes. COS sreset - * takes quite a long time, so it is unfortunate that this - * seems to be needed. Anyway, I do not know of any better way - * of avoiding the crash. */ - disable_irq(dev->irq); - local->func->cor_sreset(local); - enable_irq(dev->irq); - } - prism2_hw_shutdown(dev, 1); - prism2_hw_config(dev, 0); - local->hw_resetting = 0; - -#ifdef PRISM2_DOWNLOAD_SUPPORT - if (local->dl_pri) { - printk(KERN_DEBUG "%s: persistent download of primary " - "firmware\n", dev->name); - if (prism2_download_genesis(local, local->dl_pri) < 0) - printk(KERN_WARNING "%s: download (PRI) failed\n", - dev->name); - } - - if (local->dl_sec) { - printk(KERN_DEBUG "%s: persistent download of secondary " - "firmware\n", dev->name); - if (prism2_download_volatile(local, local->dl_sec) < 0) - printk(KERN_WARNING "%s: download (SEC) failed\n", - dev->name); - } -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - /* TODO: restore beacon TIM bits for STAs that have buffered frames */ -} - - -static void prism2_schedule_reset(local_info_t *local) -{ - schedule_work(&local->reset_queue); -} - - -/* Called only as scheduled task after noticing card timeout in interrupt - * context */ -static void handle_reset_queue(struct work_struct *work) -{ - local_info_t *local = container_of(work, local_info_t, reset_queue); - - printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); - prism2_hw_reset(local->dev); - - if (netif_queue_stopped(local->dev)) { - int i; - - for (i = 0; i < PRISM2_TXFID_COUNT; i++) - if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) { - PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: " - "wake up queue\n"); - netif_wake_queue(local->dev); - break; - } - } -} - - -static int prism2_get_txfid_idx(local_info_t *local) -{ - int idx, end; - unsigned long flags; - - spin_lock_irqsave(&local->txfidlock, flags); - end = idx = local->next_txfid; - do { - if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { - local->intransmitfid[idx] = PRISM2_TXFID_RESERVED; - spin_unlock_irqrestore(&local->txfidlock, flags); - return idx; - } - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - } while (idx != end); - spin_unlock_irqrestore(&local->txfidlock, flags); - - PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: " - "packet dropped\n"); - local->dev->stats.tx_dropped++; - - return -1; -} - - -/* Called only from hardware IRQ */ -static void prism2_transmit_cb(struct net_device *dev, long context, - u16 resp0, u16 res) -{ - struct hostap_interface *iface; - local_info_t *local; - int idx = (int) context; - - iface = netdev_priv(dev); - local = iface->local; - - if (res) { - printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n", - dev->name, res); - return; - } - - if (idx < 0 || idx >= PRISM2_TXFID_COUNT) { - printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid " - "idx=%d\n", dev->name, idx); - return; - } - - if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { - printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called " - "with no pending transmit\n", dev->name); - } - - if (netif_queue_stopped(dev)) { - /* ready for next TX, so wake up queue that was stopped in - * prism2_transmit() */ - netif_wake_queue(dev); - } - - spin_lock(&local->txfidlock); - - /* With reclaim, Resp0 contains new txfid for transmit; the old txfid - * will be automatically allocated for the next TX frame */ - local->intransmitfid[idx] = resp0; - - PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, " - "resp0=0x%04x, transmit_txfid=0x%04x\n", - dev->name, idx, local->txfid[idx], - resp0, local->intransmitfid[local->next_txfid]); - - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - local->next_txfid = idx; - - /* check if all TX buffers are occupied */ - do { - if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { - spin_unlock(&local->txfidlock); - return; - } - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - } while (idx != local->next_txfid); - spin_unlock(&local->txfidlock); - - /* no empty TX buffers, stop queue */ - netif_stop_queue(dev); -} - - -/* Called only from software IRQ if PCI bus master is not used (with bus master - * this can be called both from software and hardware IRQ) */ -static int prism2_transmit(struct net_device *dev, int idx) -{ - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - /* The driver tries to stop netif queue so that there would not be - * more than one attempt to transmit frames going on; check that this - * is really the case */ - - if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { - printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called " - "when previous TX was pending\n", dev->name); - return -1; - } - - /* stop the queue for the time that transmit is pending */ - netif_stop_queue(dev); - - /* transmit packet */ - res = hfa384x_cmd_callback( - dev, - HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM, - local->txfid[idx], - prism2_transmit_cb, (long) idx); - - if (res) { - printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT " - "failed (res=%d)\n", dev->name, res); - dev->stats.tx_dropped++; - netif_wake_queue(dev); - return -1; - } - netif_trans_update(dev); - - /* Since we did not wait for command completion, the card continues - * to process on the background and we will finish handling when - * command completion event is handled (prism2_cmd_ev() function) */ - - return 0; -} - - -/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and - * send the payload with this descriptor) */ -/* Called only from software IRQ */ -static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_tx_frame txdesc; - struct hostap_skb_tx_data *meta; - int hdr_len, data_len, idx, res, ret = -1; - u16 tx_control; - - iface = netdev_priv(dev); - local = iface->local; - - meta = (struct hostap_skb_tx_data *) skb->cb; - - prism2_callback(local, PRISM2_CALLBACK_TX_START); - - if ((local->func->card_present && !local->func->card_present(local)) || - !local->hw_ready || local->hw_downloading || local->pri_only) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -" - " skipping\n", dev->name); - } - goto fail; - } - - memset(&txdesc, 0, sizeof(txdesc)); - - /* skb->data starts with txdesc->frame_control */ - hdr_len = sizeof(txdesc.header); - BUILD_BUG_ON(hdr_len != 24); - skb_copy_from_linear_data(skb, &txdesc.header, hdr_len); - if (ieee80211_is_data(txdesc.frame_control) && - ieee80211_has_a4(txdesc.frame_control) && - skb->len >= 30) { - /* Addr4 */ - skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4, - ETH_ALEN); - hdr_len += ETH_ALEN; - } - - tx_control = local->tx_control; - if (meta->tx_cb_idx) { - tx_control |= HFA384X_TX_CTRL_TX_OK; - txdesc.sw_support = cpu_to_le32(meta->tx_cb_idx); - } - txdesc.tx_control = cpu_to_le16(tx_control); - txdesc.tx_rate = meta->rate; - - data_len = skb->len - hdr_len; - txdesc.data_len = cpu_to_le16(data_len); - txdesc.len = cpu_to_be16(data_len); - - idx = prism2_get_txfid_idx(local); - if (idx < 0) - goto fail; - - if (local->frame_dump & PRISM2_DUMP_TX_HDR) - hostap_dump_tx_header(dev->name, &txdesc); - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0); - - if (!res) - res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc)); - if (!res) - res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len, - skb->len - hdr_len); - spin_unlock(&local->baplock); - - if (!res) - res = prism2_transmit(dev, idx); - if (res) { - printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n", - dev->name); - local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; - schedule_work(&local->reset_queue); - goto fail; - } - - ret = 0; - -fail: - prism2_callback(local, PRISM2_CALLBACK_TX_END); - return ret; -} - - -/* Some SMP systems have reported number of odd errors with hostap_pci. fid - * register has changed values between consecutive reads for an unknown reason. - * This should really not happen, so more debugging is needed. This test - * version is a bit slower, but it will detect most of such register changes - * and will try to get the correct fid eventually. */ -#define EXTRA_FID_READ_TESTS - -static u16 prism2_read_fid_reg(struct net_device *dev, u16 reg) -{ -#ifdef EXTRA_FID_READ_TESTS - u16 val, val2, val3; - int i; - - for (i = 0; i < 10; i++) { - val = HFA384X_INW(reg); - val2 = HFA384X_INW(reg); - val3 = HFA384X_INW(reg); - - if (val == val2 && val == val3) - return val; - - printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):" - " %04x %04x %04x\n", - dev->name, i, reg, val, val2, val3); - if ((val == val2 || val == val3) && val != 0) - return val; - if (val2 == val3 && val2 != 0) - return val2; - } - printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg " - "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3); - return val; -#else /* EXTRA_FID_READ_TESTS */ - return HFA384X_INW(reg); -#endif /* EXTRA_FID_READ_TESTS */ -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_rx(local_info_t *local) -{ - struct net_device *dev = local->dev; - int res, rx_pending = 0; - u16 len, hdr_len, rxfid, status, macport; - struct hfa384x_rx_frame rxdesc; - struct sk_buff *skb = NULL; - - prism2_callback(local, PRISM2_CALLBACK_RX_START); - - rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF); -#ifndef final_version - if (rxfid == 0) { - rxfid = HFA384X_INW(HFA384X_RXFID_OFF); - printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n", - rxfid); - if (rxfid == 0) { - schedule_work(&local->reset_queue); - goto rx_dropped; - } - /* try to continue with the new rxfid value */ - } -#endif - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, rxfid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc)); - - if (res) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name, - res); - if (res == -ETIMEDOUT) { - schedule_work(&local->reset_queue); - } - goto rx_dropped; - } - - len = le16_to_cpu(rxdesc.data_len); - hdr_len = sizeof(rxdesc); - status = le16_to_cpu(rxdesc.status); - macport = (status >> 8) & 0x07; - - /* Drop frames with too large reported payload length. Monitor mode - * seems to sometimes pass frames (e.g., ctrl::ack) with signed and - * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for - * macport 7 */ - if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) { - if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) { - if (len >= (u16) -14) { - hdr_len -= 65535 - len; - hdr_len--; - } - len = 0; - } else { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: Received frame with invalid " - "length 0x%04x\n", dev->name, len); - hostap_dump_rx_header(dev->name, &rxdesc); - goto rx_dropped; - } - } - - skb = dev_alloc_skb(len + hdr_len); - if (!skb) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: RX failed to allocate skb\n", - dev->name); - goto rx_dropped; - } - skb->dev = dev; - skb_put_data(skb, &rxdesc, hdr_len); - - if (len > 0) - res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len); - spin_unlock(&local->baplock); - if (res) { - printk(KERN_DEBUG "%s: RX failed to read " - "frame data\n", dev->name); - goto rx_dropped; - } - - skb_queue_tail(&local->rx_list, skb); - tasklet_schedule(&local->rx_tasklet); - - rx_exit: - prism2_callback(local, PRISM2_CALLBACK_RX_END); - if (!rx_pending) { - HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); - } - - return; - - rx_dropped: - dev->stats.rx_dropped++; - if (skb) - dev_kfree_skb(skb); - goto rx_exit; -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb) -{ - struct hfa384x_rx_frame *rxdesc; - struct net_device *dev = skb->dev; - struct hostap_80211_rx_status stats; - int hdrlen, rx_hdrlen; - - rx_hdrlen = sizeof(*rxdesc); - if (skb->len < sizeof(*rxdesc)) { - /* Allow monitor mode to receive shorter frames */ - if (local->iw_mode == IW_MODE_MONITOR && - skb->len >= sizeof(*rxdesc) - 30) { - rx_hdrlen = skb->len; - } else { - dev_kfree_skb(skb); - return; - } - } - - rxdesc = (struct hfa384x_rx_frame *) skb->data; - - if (local->frame_dump & PRISM2_DUMP_RX_HDR && - skb->len >= sizeof(*rxdesc)) - hostap_dump_rx_header(dev->name, rxdesc); - - if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR && - (!local->monitor_allow_fcserr || - local->iw_mode != IW_MODE_MONITOR)) - goto drop; - - if (skb->len > PRISM2_DATA_MAXLEN) { - printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n", - dev->name, skb->len, PRISM2_DATA_MAXLEN); - goto drop; - } - - stats.mac_time = le32_to_cpu(rxdesc->time); - stats.signal = rxdesc->signal - local->rssi_to_dBm; - stats.noise = rxdesc->silence - local->rssi_to_dBm; - stats.rate = rxdesc->rate; - - /* Convert Prism2 RX structure into IEEE 802.11 header */ - hdrlen = hostap_80211_get_hdrlen(rxdesc->frame_control); - if (hdrlen > rx_hdrlen) - hdrlen = rx_hdrlen; - - memmove(skb_pull(skb, rx_hdrlen - hdrlen), - &rxdesc->frame_control, hdrlen); - - hostap_80211_rx(dev, skb, &stats); - return; - - drop: - dev_kfree_skb(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_rx_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, rx_tasklet); - struct sk_buff *skb; - - while ((skb = skb_dequeue(&local->rx_list)) != NULL) - hostap_rx_skb(local, skb); -} - - -/* Called only from hardware IRQ */ -static void prism2_alloc_ev(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int idx; - u16 fid; - - iface = netdev_priv(dev); - local = iface->local; - - fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF); - - PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid); - - spin_lock(&local->txfidlock); - idx = local->next_alloc; - - do { - if (local->txfid[idx] == fid) { - PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n", - idx); - -#ifndef final_version - if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) - printk("Already released txfid found at idx " - "%d\n", idx); - if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED) - printk("Already reserved txfid found at idx " - "%d\n", idx); -#endif - local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; - idx++; - local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 : - idx; - - if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) && - netif_queue_stopped(dev)) - netif_wake_queue(dev); - - spin_unlock(&local->txfidlock); - return; - } - - idx++; - if (idx >= PRISM2_TXFID_COUNT) - idx = 0; - } while (idx != local->next_alloc); - - printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new " - "read 0x%04x) for alloc event\n", dev->name, fid, - HFA384X_INW(HFA384X_ALLOCFID_OFF)); - printk(KERN_DEBUG "TXFIDs:"); - for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++) - printk(" %04x[%04x]", local->txfid[idx], - local->intransmitfid[idx]); - printk("\n"); - spin_unlock(&local->txfidlock); - - /* FIX: should probably schedule reset; reference to one txfid was lost - * completely.. Bad things will happen if we run out of txfids - * Actually, this will cause netdev watchdog to notice TX timeout and - * then card reset after all txfids have been leaked. */ -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_tx_callback(local_info_t *local, - struct hfa384x_tx_frame *txdesc, int ok, - char *payload) -{ - u16 sw_support, hdrlen, len; - struct sk_buff *skb; - struct hostap_tx_callback_info *cb; - - /* Make sure that frame was from us. */ - if (!ether_addr_equal(txdesc->addr2, local->dev->dev_addr)) { - printk(KERN_DEBUG "%s: TX callback - foreign frame\n", - local->dev->name); - return; - } - - sw_support = le32_to_cpu(txdesc->sw_support); - - spin_lock(&local->lock); - cb = local->tx_callback; - while (cb != NULL && cb->idx != sw_support) - cb = cb->next; - spin_unlock(&local->lock); - - if (cb == NULL) { - printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n", - local->dev->name, sw_support); - return; - } - - hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control); - len = le16_to_cpu(txdesc->data_len); - skb = dev_alloc_skb(hdrlen + len); - if (skb == NULL) { - printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate " - "skb\n", local->dev->name); - return; - } - - skb_put_data(skb, (void *)&txdesc->frame_control, hdrlen); - if (payload) - skb_put_data(skb, payload, len); - - skb->dev = local->dev; - skb_reset_mac_header(skb); - - cb->func(skb, ok, cb->data); -} - - -/* Called only as a tasklet (software IRQ) */ -static int hostap_tx_compl_read(local_info_t *local, int error, - struct hfa384x_tx_frame *txdesc, - char **payload) -{ - u16 fid, len; - int res, ret = 0; - struct net_device *dev = local->dev; - - fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF); - - PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error); - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, fid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc)); - if (res) { - PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not " - "read txdesc\n", dev->name, error, fid); - if (res == -ETIMEDOUT) { - schedule_work(&local->reset_queue); - } - ret = -1; - goto fail; - } - if (txdesc->sw_support) { - len = le16_to_cpu(txdesc->data_len); - if (len < PRISM2_DATA_MAXLEN) { - *payload = kmalloc(len, GFP_ATOMIC); - if (*payload == NULL || - hfa384x_from_bap(dev, BAP0, *payload, len)) { - PDEBUG(DEBUG_EXTRA, "%s: could not read TX " - "frame payload\n", dev->name); - kfree(*payload); - *payload = NULL; - ret = -1; - goto fail; - } - } - } - - fail: - spin_unlock(&local->baplock); - - return ret; -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_tx_ev(local_info_t *local) -{ - struct net_device *dev = local->dev; - char *payload = NULL; - struct hfa384x_tx_frame txdesc; - - if (hostap_tx_compl_read(local, 0, &txdesc, &payload)) - goto fail; - - if (local->frame_dump & PRISM2_DUMP_TX_HDR) { - PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x " - "retry_count=%d tx_rate=%d seq_ctrl=%d " - "duration_id=%d\n", - dev->name, le16_to_cpu(txdesc.status), - txdesc.retry_count, txdesc.tx_rate, - le16_to_cpu(txdesc.seq_ctrl), - le16_to_cpu(txdesc.duration_id)); - } - - if (txdesc.sw_support) - hostap_tx_callback(local, &txdesc, 1, payload); - kfree(payload); - - fail: - HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_sta_tx_exc_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, sta_tx_exc_tasklet); - struct sk_buff *skb; - - while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) { - struct hfa384x_tx_frame *txdesc = - (struct hfa384x_tx_frame *) skb->data; - - if (skb->len >= sizeof(*txdesc)) { - /* Convert Prism2 RX structure into IEEE 802.11 header - */ - int hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control); - memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen), - &txdesc->frame_control, hdrlen); - - hostap_handle_sta_tx_exc(local, skb); - } - dev_kfree_skb(skb); - } -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_txexc(local_info_t *local) -{ - struct net_device *dev = local->dev; - u16 status, fc; - int show_dump, res; - char *payload = NULL; - struct hfa384x_tx_frame txdesc; - - show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; - dev->stats.tx_errors++; - - res = hostap_tx_compl_read(local, 1, &txdesc, &payload); - HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF); - if (res) - return; - - status = le16_to_cpu(txdesc.status); - - /* We produce a TXDROP event only for retry or lifetime - * exceeded, because that's the only status that really mean - * that this particular node went away. - * Other errors means that *we* screwed up. - Jean II */ - if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR)) - { - union iwreq_data wrqu; - - /* Copy 802.11 dest address. */ - memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); - } else - show_dump = 1; - - if (local->iw_mode == IW_MODE_MASTER || - local->iw_mode == IW_MODE_REPEAT || - local->wds_type & HOSTAP_WDS_AP_CLIENT) { - struct sk_buff *skb; - skb = dev_alloc_skb(sizeof(txdesc)); - if (skb) { - skb_put_data(skb, &txdesc, sizeof(txdesc)); - skb_queue_tail(&local->sta_tx_exc_list, skb); - tasklet_schedule(&local->sta_tx_exc_tasklet); - } - } - - if (txdesc.sw_support) - hostap_tx_callback(local, &txdesc, 0, payload); - kfree(payload); - - if (!show_dump) - return; - - PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)" - " tx_control=%04x\n", - dev->name, status, - status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "", - status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "", - status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "", - status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "", - le16_to_cpu(txdesc.tx_control)); - - fc = le16_to_cpu(txdesc.frame_control); - PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x " - "(%s%s%s::%d%s%s)\n", - txdesc.retry_count, txdesc.tx_rate, fc, - ieee80211_is_mgmt(txdesc.frame_control) ? "Mgmt" : "", - ieee80211_is_ctl(txdesc.frame_control) ? "Ctrl" : "", - ieee80211_is_data(txdesc.frame_control) ? "Data" : "", - (fc & IEEE80211_FCTL_STYPE) >> 4, - ieee80211_has_tods(txdesc.frame_control) ? " ToDS" : "", - ieee80211_has_fromds(txdesc.frame_control) ? " FromDS" : ""); - PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n", - txdesc.addr1, txdesc.addr2, - txdesc.addr3, txdesc.addr4); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_info_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, info_tasklet); - struct sk_buff *skb; - - while ((skb = skb_dequeue(&local->info_list)) != NULL) { - hostap_info_process(local, skb); - dev_kfree_skb(skb); - } -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info(local_info_t *local) -{ - struct net_device *dev = local->dev; - u16 fid; - int res, left; - struct hfa384x_info_frame info; - struct sk_buff *skb; - - fid = HFA384X_INW(HFA384X_INFOFID_OFF); - - spin_lock(&local->baplock); - res = hfa384x_setup_bap(dev, BAP0, fid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info)); - if (res) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n", - fid); - if (res == -ETIMEDOUT) { - schedule_work(&local->reset_queue); - } - goto out; - } - - left = (le16_to_cpu(info.len) - 1) * 2; - - if (info.len & cpu_to_le16(0x8000) || info.len == 0 || left > 2060) { - /* data register seems to give 0x8000 in some error cases even - * though busy bit is not set in offset register; - * in addition, length must be at least 1 due to type field */ - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: Received info frame with invalid " - "length 0x%04x (type 0x%04x)\n", dev->name, - le16_to_cpu(info.len), le16_to_cpu(info.type)); - goto out; - } - - skb = dev_alloc_skb(sizeof(info) + left); - if (skb == NULL) { - spin_unlock(&local->baplock); - printk(KERN_DEBUG "%s: Could not allocate skb for info " - "frame\n", dev->name); - goto out; - } - - skb_put_data(skb, &info, sizeof(info)); - if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left)) - { - spin_unlock(&local->baplock); - printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, " - "len=0x%04x, type=0x%04x\n", dev->name, fid, - le16_to_cpu(info.len), le16_to_cpu(info.type)); - dev_kfree_skb(skb); - goto out; - } - spin_unlock(&local->baplock); - - skb_queue_tail(&local->info_list, skb); - tasklet_schedule(&local->info_tasklet); - - out: - HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF); -} - - -/* Called only as a tasklet (software IRQ) */ -static void hostap_bap_tasklet(struct tasklet_struct *t) -{ - local_info_t *local = from_tasklet(local, t, bap_tasklet); - struct net_device *dev = local->dev; - u16 ev; - int frames = 30; - - if (local->func->card_present && !local->func->card_present(local)) - return; - - set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); - - /* Process all pending BAP events without generating new interrupts - * for them */ - while (frames-- > 0) { - ev = HFA384X_INW(HFA384X_EVSTAT_OFF); - if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS)) - break; - if (ev & HFA384X_EV_RX) - prism2_rx(local); - if (ev & HFA384X_EV_INFO) - prism2_info(local); - if (ev & HFA384X_EV_TX) - prism2_tx_ev(local); - if (ev & HFA384X_EV_TXEXC) - prism2_txexc(local); - } - - set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); - clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); - - /* Enable interrupts for new BAP events */ - hfa384x_events_all(dev); - clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); -} - - -/* Called only from hardware IRQ */ -static void prism2_infdrop(struct net_device *dev) -{ - static unsigned long last_inquire = 0; - - PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name); - - /* some firmware versions seem to get stuck with - * full CommTallies in high traffic load cases; every - * packet will then cause INFDROP event and CommTallies - * info frame will not be sent automatically. Try to - * get out of this state by inquiring CommTallies. */ - if (!last_inquire || time_after(jiffies, last_inquire + HZ)) { - hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE, - HFA384X_INFO_COMMTALLIES, NULL, 0); - last_inquire = jiffies; - } -} - - -/* Called only from hardware IRQ */ -static void prism2_ev_tick(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - u16 evstat, inten; - static int prev_stuck = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (time_after(jiffies, local->last_tick_timer + 5 * HZ) && - local->last_tick_timer) { - evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); - inten = HFA384X_INW(HFA384X_INTEN_OFF); - if (!prev_stuck) { - printk(KERN_INFO "%s: SW TICK stuck? " - "bits=0x%lx EvStat=%04x IntEn=%04x\n", - dev->name, local->bits, evstat, inten); - } - local->sw_tick_stuck++; - if ((evstat & HFA384X_BAP0_EVENTS) && - (inten & HFA384X_BAP0_EVENTS)) { - printk(KERN_INFO "%s: trying to recover from IRQ " - "hang\n", dev->name); - hfa384x_events_no_bap0(dev); - } - prev_stuck = 1; - } else - prev_stuck = 0; -} - - -/* Called only from hardware IRQ */ -static void prism2_check_magic(local_info_t *local) -{ - /* at least PCI Prism2.5 with bus mastering seems to sometimes - * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the - * register once or twice seems to get the correct value.. PCI cards - * cannot anyway be removed during normal operation, so there is not - * really any need for this verification with them. */ - -#ifndef PRISM2_PCI -#ifndef final_version - static unsigned long last_magic_err = 0; - struct net_device *dev = local->dev; - - if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { - if (!local->hw_ready) - return; - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); - if (time_after(jiffies, last_magic_err + 10 * HZ)) { - printk("%s: Interrupt, but SWSUPPORT0 does not match: " - "%04X != %04X - card removed?\n", dev->name, - HFA384X_INW(HFA384X_SWSUPPORT0_OFF), - HFA384X_MAGIC); - last_magic_err = jiffies; - } else if (net_ratelimit()) { - printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x " - "MAGIC=%04x\n", dev->name, - HFA384X_INW(HFA384X_SWSUPPORT0_OFF), - HFA384X_MAGIC); - } - if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff) - schedule_work(&local->reset_queue); - return; - } -#endif /* final_version */ -#endif /* !PRISM2_PCI */ -} - - -/* Called only from hardware IRQ */ -static irqreturn_t prism2_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct hostap_interface *iface; - local_info_t *local; - int events = 0; - u16 ev; - - iface = netdev_priv(dev); - local = iface->local; - - /* Detect early interrupt before driver is fully configured */ - spin_lock(&local->irq_init_lock); - if (!dev->base_addr) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n", - dev->name); - } - spin_unlock(&local->irq_init_lock); - return IRQ_HANDLED; - } - spin_unlock(&local->irq_init_lock); - - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); - - if (local->func->card_present && !local->func->card_present(local)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n", - dev->name); - } - return IRQ_HANDLED; - } - - prism2_check_magic(local); - - for (;;) { - ev = HFA384X_INW(HFA384X_EVSTAT_OFF); - if (ev == 0xffff) { - if (local->shutdown) - return IRQ_HANDLED; - HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); - printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n", - dev->name); - return IRQ_HANDLED; - } - - ev &= HFA384X_INW(HFA384X_INTEN_OFF); - if (ev == 0) - break; - - if (ev & HFA384X_EV_CMD) { - prism2_cmd_ev(dev); - } - - /* Above events are needed even before hw is ready, but other - * events should be skipped during initialization. This may - * change for AllocEv if allocate_fid is implemented without - * busy waiting. */ - if (!local->hw_ready || local->hw_resetting || - !local->dev_enabled) { - ev = HFA384X_INW(HFA384X_EVSTAT_OFF); - if (ev & HFA384X_EV_CMD) - goto next_event; - if ((ev & HFA384X_EVENT_MASK) == 0) - return IRQ_HANDLED; - if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) && - net_ratelimit()) { - printk(KERN_DEBUG "%s: prism2_interrupt: hw " - "not ready; skipping events 0x%04x " - "(IntEn=0x%04x)%s%s%s\n", - dev->name, ev, - HFA384X_INW(HFA384X_INTEN_OFF), - !local->hw_ready ? " (!hw_ready)" : "", - local->hw_resetting ? - " (hw_resetting)" : "", - !local->dev_enabled ? - " (!dev_enabled)" : ""); - } - HFA384X_OUTW(ev, HFA384X_EVACK_OFF); - return IRQ_HANDLED; - } - - if (ev & HFA384X_EV_TICK) { - prism2_ev_tick(dev); - HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF); - } - - if (ev & HFA384X_EV_ALLOC) { - prism2_alloc_ev(dev); - HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); - } - - /* Reading data from the card is quite time consuming, so do it - * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed - * and unmasked after needed data has been read completely. */ - if (ev & HFA384X_BAP0_EVENTS) { - hfa384x_events_no_bap0(dev); - tasklet_schedule(&local->bap_tasklet); - } - -#ifndef final_version - if (ev & HFA384X_EV_WTERR) { - PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name); - HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF); - } -#endif /* final_version */ - - if (ev & HFA384X_EV_INFDROP) { - prism2_infdrop(dev); - HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF); - } - - next_event: - events++; - if (events >= PRISM2_MAX_INTERRUPT_EVENTS) { - PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events " - "(EvStat=0x%04x)\n", - PRISM2_MAX_INTERRUPT_EVENTS, - HFA384X_INW(HFA384X_EVSTAT_OFF)); - break; - } - } - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1); - return IRQ_RETVAL(events); -} - - -static void prism2_check_sta_fw_version(local_info_t *local) -{ - struct hfa384x_comp_ident comp; - int id, variant, major, minor; - - if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID, - &comp, sizeof(comp), 1) < 0) - return; - - local->fw_ap = 0; - id = le16_to_cpu(comp.id); - if (id != HFA384X_COMP_ID_STA) { - if (id == HFA384X_COMP_ID_FW_AP) - local->fw_ap = 1; - return; - } - - major = __le16_to_cpu(comp.major); - minor = __le16_to_cpu(comp.minor); - variant = __le16_to_cpu(comp.variant); - local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant); - - /* Station firmware versions before 1.4.x seem to have a bug in - * firmware-based WEP encryption when using Host AP mode, so use - * host_encrypt as a default for them. Firmware version 1.4.9 is the - * first one that has been seen to produce correct encryption, but the - * bug might be fixed before that (although, at least 1.4.2 is broken). - */ - local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9); - - if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && - !local->fw_encrypt_ok) { - printk(KERN_DEBUG "%s: defaulting to host-based encryption as " - "a workaround for firmware bug in Host AP mode WEP\n", - local->dev->name); - local->host_encrypt = 1; - } - - /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken - * in station firmware versions before 1.5.x. With these versions, the - * driver uses a workaround with bogus frame format (4th address after - * the payload). This is not compatible with other AP devices. Since - * the firmware bug is fixed in the latest station firmware versions, - * automatically enable standard compliant mode for cards using station - * firmware version 1.5.0 or newer. */ - if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0)) - local->wds_type |= HOSTAP_WDS_STANDARD_FRAME; - else { - printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a " - "workaround for firmware bug in Host AP mode WDS\n", - local->dev->name); - } - - hostap_check_sta_fw_version(local->ap, local->sta_fw_ver); -} - - -static void hostap_passive_scan(struct timer_list *t) -{ - local_info_t *local = from_timer(local, t, passive_scan_timer); - struct net_device *dev = local->dev; - u16 chan; - - if (local->passive_scan_interval <= 0) - return; - - if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) { - int max_tries = 16; - - /* Even though host system does not really know when the WLAN - * MAC is sending frames, try to avoid changing channels for - * passive scanning when a host-generated frame is being - * transmitted */ - if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { - printk(KERN_DEBUG "%s: passive scan detected pending " - "TX - delaying\n", dev->name); - local->passive_scan_timer.expires = jiffies + HZ / 10; - add_timer(&local->passive_scan_timer); - return; - } - - do { - local->passive_scan_channel++; - if (local->passive_scan_channel > 14) - local->passive_scan_channel = 1; - max_tries--; - } while (!(local->channel_mask & - (1 << (local->passive_scan_channel - 1))) && - max_tries > 0); - - if (max_tries == 0) { - printk(KERN_INFO "%s: no allowed passive scan channels" - " found\n", dev->name); - return; - } - - printk(KERN_DEBUG "%s: passive scan channel %d\n", - dev->name, local->passive_scan_channel); - chan = local->passive_scan_channel; - local->passive_scan_state = PASSIVE_SCAN_WAIT; - local->passive_scan_timer.expires = jiffies + HZ / 10; - } else { - chan = local->channel; - local->passive_scan_state = PASSIVE_SCAN_LISTEN; - local->passive_scan_timer.expires = jiffies + - local->passive_scan_interval * HZ; - } - - if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CHANGE_CHANNEL << 8), - chan, NULL, 0)) - printk(KERN_ERR "%s: passive scan channel set %d " - "failed\n", dev->name, chan); - - add_timer(&local->passive_scan_timer); -} - - -/* Called only as a scheduled task when communications quality values should - * be updated. */ -static void handle_comms_qual_update(struct work_struct *work) -{ - local_info_t *local = - container_of(work, local_info_t, comms_qual_update); - prism2_update_comms_qual(local->dev); -} - - -/* Software watchdog - called as a timer. Hardware interrupt (Tick event) is - * used to monitor that local->last_tick_timer is being updated. If not, - * interrupt busy-loop is assumed and driver tries to recover by masking out - * some events. */ -static void hostap_tick_timer(struct timer_list *t) -{ - static unsigned long last_inquire = 0; - local_info_t *local = from_timer(local, t, tick_timer); - local->last_tick_timer = jiffies; - - /* Inquire CommTallies every 10 seconds to keep the statistics updated - * more often during low load and when using 32-bit tallies. */ - if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) && - !local->hw_downloading && local->hw_ready && - !local->hw_resetting && local->dev_enabled) { - hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE, - HFA384X_INFO_COMMTALLIES, NULL, 0); - last_inquire = jiffies; - } - - if ((local->last_comms_qual_update == 0 || - time_after(jiffies, local->last_comms_qual_update + 10 * HZ)) && - (local->iw_mode == IW_MODE_INFRA || - local->iw_mode == IW_MODE_ADHOC)) { - schedule_work(&local->comms_qual_update); - } - - local->tick_timer.expires = jiffies + 2 * HZ; - add_timer(&local->tick_timer); -} - - -#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS) -static u16 hfa384x_read_reg(struct net_device *dev, u16 reg) -{ - return HFA384X_INW(reg); -} - -static int prism2_registers_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - -#define SHOW_REG(n) \ - seq_printf(m, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF)) - - SHOW_REG(CMD); - SHOW_REG(PARAM0); - SHOW_REG(PARAM1); - SHOW_REG(PARAM2); - SHOW_REG(STATUS); - SHOW_REG(RESP0); - SHOW_REG(RESP1); - SHOW_REG(RESP2); - SHOW_REG(INFOFID); - SHOW_REG(CONTROL); - SHOW_REG(SELECT0); - SHOW_REG(SELECT1); - SHOW_REG(OFFSET0); - SHOW_REG(OFFSET1); - SHOW_REG(RXFID); - SHOW_REG(ALLOCFID); - SHOW_REG(TXCOMPLFID); - SHOW_REG(SWSUPPORT0); - SHOW_REG(SWSUPPORT1); - SHOW_REG(SWSUPPORT2); - SHOW_REG(EVSTAT); - SHOW_REG(INTEN); - SHOW_REG(EVACK); - /* Do not read data registers, because they change the state of the - * MAC (offset += 2) */ - /* SHOW_REG(DATA0); */ - /* SHOW_REG(DATA1); */ - SHOW_REG(AUXPAGE); - SHOW_REG(AUXOFFSET); - /* SHOW_REG(AUXDATA); */ -#ifdef PRISM2_PCI - SHOW_REG(PCICOR); - SHOW_REG(PCIHCR); - SHOW_REG(PCI_M0_ADDRH); - SHOW_REG(PCI_M0_ADDRL); - SHOW_REG(PCI_M0_LEN); - SHOW_REG(PCI_M0_CTL); - SHOW_REG(PCI_STATUS); - SHOW_REG(PCI_M1_ADDRH); - SHOW_REG(PCI_M1_ADDRL); - SHOW_REG(PCI_M1_LEN); - SHOW_REG(PCI_M1_CTL); -#endif /* PRISM2_PCI */ - - return 0; -} -#endif - -struct set_tim_data { - struct list_head list; - int aid; - int set; -}; - -static int prism2_set_tim(struct net_device *dev, int aid, int set) -{ - struct list_head *ptr; - struct set_tim_data *new_entry; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC); - if (new_entry == NULL) - return -ENOMEM; - - new_entry->aid = aid; - new_entry->set = set; - - spin_lock_bh(&local->set_tim_lock); - list_for_each(ptr, &local->set_tim_list) { - struct set_tim_data *entry = - list_entry(ptr, struct set_tim_data, list); - if (entry->aid == aid) { - PDEBUG(DEBUG_PS2, "%s: prism2_set_tim: aid=%d " - "set=%d ==> %d\n", - local->dev->name, aid, entry->set, set); - entry->set = set; - kfree(new_entry); - new_entry = NULL; - break; - } - } - if (new_entry) - list_add_tail(&new_entry->list, &local->set_tim_list); - spin_unlock_bh(&local->set_tim_lock); - - schedule_work(&local->set_tim_queue); - - return 0; -} - - -static void handle_set_tim_queue(struct work_struct *work) -{ - local_info_t *local = container_of(work, local_info_t, set_tim_queue); - struct set_tim_data *entry; - u16 val; - - for (;;) { - entry = NULL; - spin_lock_bh(&local->set_tim_lock); - if (!list_empty(&local->set_tim_list)) { - entry = list_entry(local->set_tim_list.next, - struct set_tim_data, list); - list_del(&entry->list); - } - spin_unlock_bh(&local->set_tim_lock); - if (!entry) - break; - - PDEBUG(DEBUG_PS2, "%s: handle_set_tim_queue: aid=%d set=%d\n", - local->dev->name, entry->aid, entry->set); - - val = entry->aid; - if (entry->set) - val |= 0x8000; - if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) { - printk(KERN_DEBUG "%s: set_tim failed (aid=%d " - "set=%d)\n", - local->dev->name, entry->aid, entry->set); - } - - kfree(entry); - } -} - - -static void prism2_clear_set_tim_queue(local_info_t *local) -{ - struct list_head *ptr, *n; - - list_for_each_safe(ptr, n, &local->set_tim_list) { - struct set_tim_data *entry; - entry = list_entry(ptr, struct set_tim_data, list); - list_del(&entry->list); - kfree(entry); - } -} - - -/* - * HostAP uses two layers of net devices, where the inner - * layer gets called all the time from the outer layer. - * This is a natural nesting, which needs a split lock type. - */ -static struct lock_class_key hostap_netdev_xmit_lock_key; -static struct lock_class_key hostap_netdev_addr_lock_key; - -static void prism2_set_lockdep_class_one(struct net_device *dev, - struct netdev_queue *txq, - void *_unused) -{ - lockdep_set_class(&txq->_xmit_lock, - &hostap_netdev_xmit_lock_key); -} - -static void prism2_set_lockdep_class(struct net_device *dev) -{ - lockdep_set_class(&dev->addr_list_lock, - &hostap_netdev_addr_lock_key); - netdev_for_each_tx_queue(dev, prism2_set_lockdep_class_one, NULL); -} - -static struct net_device * -prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, - struct device *sdev) -{ - struct net_device *dev; - struct hostap_interface *iface; - struct local_info *local; - int len, i, ret; - - if (funcs == NULL) - return NULL; - - len = strlen(dev_template); - if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) { - printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n", - dev_template); - return NULL; - } - - len = sizeof(struct hostap_interface) + - 3 + sizeof(struct local_info) + - 3 + sizeof(struct ap_data); - - dev = alloc_etherdev(len); - if (dev == NULL) - return NULL; - - iface = netdev_priv(dev); - local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3); - local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3); - local->dev = iface->dev = dev; - iface->local = local; - iface->type = HOSTAP_INTERFACE_MASTER; - INIT_LIST_HEAD(&local->hostap_interfaces); - - local->hw_module = THIS_MODULE; - -#ifdef PRISM2_IO_DEBUG - local->io_debug_enabled = 1; -#endif /* PRISM2_IO_DEBUG */ - - local->func = funcs; - local->func->cmd = hfa384x_cmd; - local->func->read_regs = hfa384x_read_regs; - local->func->get_rid = hfa384x_get_rid; - local->func->set_rid = hfa384x_set_rid; - local->func->hw_enable = prism2_hw_enable; - local->func->hw_config = prism2_hw_config; - local->func->hw_reset = prism2_hw_reset; - local->func->hw_shutdown = prism2_hw_shutdown; - local->func->reset_port = prism2_reset_port; - local->func->schedule_reset = prism2_schedule_reset; -#ifdef PRISM2_DOWNLOAD_SUPPORT - local->func->read_aux_proc_ops = &prism2_download_aux_dump_proc_ops; - local->func->download = prism2_download; -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - local->func->tx = prism2_tx_80211; - local->func->set_tim = prism2_set_tim; - local->func->need_tx_headroom = 0; /* no need to add txdesc in - * skb->data (FIX: maybe for DMA bus - * mastering? */ - - local->mtu = mtu; - - rwlock_init(&local->iface_lock); - spin_lock_init(&local->txfidlock); - spin_lock_init(&local->cmdlock); - spin_lock_init(&local->baplock); - spin_lock_init(&local->lock); - spin_lock_init(&local->irq_init_lock); - mutex_init(&local->rid_bap_mtx); - - if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) - card_idx = 0; - local->card_idx = card_idx; - - len = strlen(essid); - memcpy(local->essid, essid, - len > MAX_SSID_LEN ? MAX_SSID_LEN : len); - local->essid[MAX_SSID_LEN] = '\0'; - i = GET_INT_PARM(iw_mode, card_idx); - if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) || - i == IW_MODE_MONITOR) { - local->iw_mode = i; - } else { - printk(KERN_WARNING "prism2: Unknown iw_mode %d; using " - "IW_MODE_MASTER\n", i); - local->iw_mode = IW_MODE_MASTER; - } - local->channel = GET_INT_PARM(channel, card_idx); - local->beacon_int = GET_INT_PARM(beacon_int, card_idx); - local->dtim_period = GET_INT_PARM(dtim_period, card_idx); - local->wds_max_connections = 16; - local->tx_control = HFA384X_TX_CTRL_FLAGS; - local->manual_retry_count = -1; - local->rts_threshold = 2347; - local->fragm_threshold = 2346; - local->rssi_to_dBm = 100; /* default; to be overriden by - * cnfDbmAdjust, if available */ - local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY; - local->sram_type = -1; - local->scan_channel_mask = 0xffff; - local->monitor_type = PRISM2_MONITOR_RADIOTAP; - - /* Initialize task queue structures */ - INIT_WORK(&local->reset_queue, handle_reset_queue); - INIT_WORK(&local->set_multicast_list_queue, - hostap_set_multicast_list_queue); - - INIT_WORK(&local->set_tim_queue, handle_set_tim_queue); - INIT_LIST_HEAD(&local->set_tim_list); - spin_lock_init(&local->set_tim_lock); - - INIT_WORK(&local->comms_qual_update, handle_comms_qual_update); - - /* Initialize tasklets for handling hardware IRQ related operations - * outside hw IRQ handler */ - tasklet_setup(&local->bap_tasklet, hostap_bap_tasklet); - tasklet_setup(&local->info_tasklet, hostap_info_tasklet); - hostap_info_init(local); - - tasklet_setup(&local->rx_tasklet, hostap_rx_tasklet); - skb_queue_head_init(&local->rx_list); - - tasklet_setup(&local->sta_tx_exc_tasklet, - hostap_sta_tx_exc_tasklet); - skb_queue_head_init(&local->sta_tx_exc_list); - - INIT_LIST_HEAD(&local->cmd_queue); - init_waitqueue_head(&local->hostscan_wq); - - lib80211_crypt_info_init(&local->crypt_info, dev->name, &local->lock); - - timer_setup(&local->passive_scan_timer, hostap_passive_scan, 0); - timer_setup(&local->tick_timer, hostap_tick_timer, 0); - local->tick_timer.expires = jiffies + 2 * HZ; - add_timer(&local->tick_timer); - - INIT_LIST_HEAD(&local->bss_list); - - hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER); - - dev->type = ARPHRD_IEEE80211; - dev->header_ops = &hostap_80211_ops; - - rtnl_lock(); - ret = dev_alloc_name(dev, "wifi%d"); - SET_NETDEV_DEV(dev, sdev); - if (ret >= 0) - ret = register_netdevice(dev); - - prism2_set_lockdep_class(dev); - rtnl_unlock(); - if (ret < 0) { - printk(KERN_WARNING "%s: register netdevice failed!\n", - dev_info); - goto fail; - } - printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name); - - hostap_init_data(local); - return dev; - - fail: - free_netdev(dev); - return NULL; -} - - -static int hostap_hw_ready(struct net_device *dev) -{ - struct hostap_interface *iface; - struct local_info *local; - - iface = netdev_priv(dev); - local = iface->local; - local->ddev = hostap_add_interface(local, HOSTAP_INTERFACE_MAIN, 0, - "", dev_template); - - if (local->ddev) { - if (local->iw_mode == IW_MODE_INFRA || - local->iw_mode == IW_MODE_ADHOC) { - netif_carrier_off(local->dev); - netif_carrier_off(local->ddev); - } - hostap_init_proc(local); -#ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_single_data("registers", 0, local->proc, - prism2_registers_proc_show, local); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - hostap_init_ap_proc(local); - return 0; - } - - return -1; -} - - -static void prism2_free_local_data(struct net_device *dev) -{ - struct hostap_tx_callback_info *tx_cb, *tx_cb_prev; - int i; - struct hostap_interface *iface; - struct local_info *local; - struct list_head *ptr, *n; - - if (dev == NULL) - return; - - iface = netdev_priv(dev); - local = iface->local; - - /* Unregister all netdevs before freeing local data. */ - list_for_each_safe(ptr, n, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_MASTER) { - /* special handling for this interface below */ - continue; - } - hostap_remove_interface(iface->dev, 0, 1); - } - - unregister_netdev(local->dev); - - flush_work(&local->reset_queue); - flush_work(&local->set_multicast_list_queue); - flush_work(&local->set_tim_queue); -#ifndef PRISM2_NO_STATION_MODES - flush_work(&local->info_queue); -#endif - flush_work(&local->comms_qual_update); - - lib80211_crypt_info_free(&local->crypt_info); - - if (timer_pending(&local->passive_scan_timer)) - del_timer(&local->passive_scan_timer); - - if (timer_pending(&local->tick_timer)) - del_timer(&local->tick_timer); - - prism2_clear_cmd_queue(local); - - skb_queue_purge(&local->info_list); - skb_queue_purge(&local->rx_list); - skb_queue_purge(&local->sta_tx_exc_list); - - if (local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_DISABLE); - - if (local->ap != NULL) - hostap_free_data(local->ap); - -#ifndef PRISM2_NO_PROCFS_DEBUG - if (local->proc != NULL) - remove_proc_entry("registers", local->proc); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - hostap_remove_proc(local); - - tx_cb = local->tx_callback; - while (tx_cb != NULL) { - tx_cb_prev = tx_cb; - tx_cb = tx_cb->next; - kfree(tx_cb_prev); - } - - hostap_set_hostapd(local, 0, 0); - hostap_set_hostapd_sta(local, 0, 0); - - for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { - if (local->frag_cache[i].skb != NULL) - dev_kfree_skb(local->frag_cache[i].skb); - } - -#ifdef PRISM2_DOWNLOAD_SUPPORT - prism2_download_free_data(local->dl_pri); - prism2_download_free_data(local->dl_sec); -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - prism2_clear_set_tim_queue(local); - - list_for_each_safe(ptr, n, &local->bss_list) { - struct hostap_bss_info *bss = - list_entry(ptr, struct hostap_bss_info, list); - kfree(bss); - } - - kfree(local->pda); - kfree(local->last_scan_results); - kfree(local->generic_elem); - - free_netdev(local->dev); -} - - -#if defined(PRISM2_PCI) || defined(PRISM2_PCCARD) -static void __maybe_unused prism2_suspend(struct net_device *dev) -{ - struct hostap_interface *iface; - struct local_info *local; - union iwreq_data wrqu; - - iface = netdev_priv(dev); - local = iface->local; - - /* Send disconnect event, e.g., to trigger reassociation after resume - * if wpa_supplicant is used. */ - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); - - /* Disable hardware and firmware */ - prism2_hw_shutdown(dev, 0); -} -#endif /* PRISM2_PCI || PRISM2_PCCARD */ - - -/* These might at some point be compiled separately and used as separate - * kernel modules or linked into one */ -#ifdef PRISM2_DOWNLOAD_SUPPORT -#include "hostap_download.c" -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - -#ifdef PRISM2_CALLBACK -/* External hostap_callback.c file can be used to, e.g., blink activity led. - * This can use platform specific code and must define prism2_callback() - * function (if PRISM2_CALLBACK is not defined, these function calls are not - * used. */ -#include "hostap_callback.c" -#endif /* PRISM2_CALLBACK */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_info.c b/drivers/net/wireless/intersil/hostap/hostap_info.c deleted file mode 100644 index da8c30f10d..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_info.c +++ /dev/null @@ -1,509 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Host AP driver Info Frame processing (part of hostap.o module) */ - -#include <linux/if_arp.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/export.h> -#include <linux/etherdevice.h> -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf, - int left) -{ - struct hfa384x_comm_tallies *tallies; - - if (left < sizeof(struct hfa384x_comm_tallies)) { - printk(KERN_DEBUG "%s: too short (len=%d) commtallies " - "info frame\n", local->dev->name, left); - return; - } - - tallies = (struct hfa384x_comm_tallies *) buf; -#define ADD_COMM_TALLIES(name) \ -local->comm_tallies.name += le16_to_cpu(tallies->name) - ADD_COMM_TALLIES(tx_unicast_frames); - ADD_COMM_TALLIES(tx_multicast_frames); - ADD_COMM_TALLIES(tx_fragments); - ADD_COMM_TALLIES(tx_unicast_octets); - ADD_COMM_TALLIES(tx_multicast_octets); - ADD_COMM_TALLIES(tx_deferred_transmissions); - ADD_COMM_TALLIES(tx_single_retry_frames); - ADD_COMM_TALLIES(tx_multiple_retry_frames); - ADD_COMM_TALLIES(tx_retry_limit_exceeded); - ADD_COMM_TALLIES(tx_discards); - ADD_COMM_TALLIES(rx_unicast_frames); - ADD_COMM_TALLIES(rx_multicast_frames); - ADD_COMM_TALLIES(rx_fragments); - ADD_COMM_TALLIES(rx_unicast_octets); - ADD_COMM_TALLIES(rx_multicast_octets); - ADD_COMM_TALLIES(rx_fcs_errors); - ADD_COMM_TALLIES(rx_discards_no_buffer); - ADD_COMM_TALLIES(tx_discards_wrong_sa); - ADD_COMM_TALLIES(rx_discards_wep_undecryptable); - ADD_COMM_TALLIES(rx_message_in_msg_fragments); - ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); -#undef ADD_COMM_TALLIES -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf, - int left) -{ - struct hfa384x_comm_tallies32 *tallies; - - if (left < sizeof(struct hfa384x_comm_tallies32)) { - printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 " - "info frame\n", local->dev->name, left); - return; - } - - tallies = (struct hfa384x_comm_tallies32 *) buf; -#define ADD_COMM_TALLIES(name) \ -local->comm_tallies.name += le32_to_cpu(tallies->name) - ADD_COMM_TALLIES(tx_unicast_frames); - ADD_COMM_TALLIES(tx_multicast_frames); - ADD_COMM_TALLIES(tx_fragments); - ADD_COMM_TALLIES(tx_unicast_octets); - ADD_COMM_TALLIES(tx_multicast_octets); - ADD_COMM_TALLIES(tx_deferred_transmissions); - ADD_COMM_TALLIES(tx_single_retry_frames); - ADD_COMM_TALLIES(tx_multiple_retry_frames); - ADD_COMM_TALLIES(tx_retry_limit_exceeded); - ADD_COMM_TALLIES(tx_discards); - ADD_COMM_TALLIES(rx_unicast_frames); - ADD_COMM_TALLIES(rx_multicast_frames); - ADD_COMM_TALLIES(rx_fragments); - ADD_COMM_TALLIES(rx_unicast_octets); - ADD_COMM_TALLIES(rx_multicast_octets); - ADD_COMM_TALLIES(rx_fcs_errors); - ADD_COMM_TALLIES(rx_discards_no_buffer); - ADD_COMM_TALLIES(tx_discards_wrong_sa); - ADD_COMM_TALLIES(rx_discards_wep_undecryptable); - ADD_COMM_TALLIES(rx_message_in_msg_fragments); - ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); -#undef ADD_COMM_TALLIES -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_commtallies(local_info_t *local, unsigned char *buf, - int left) -{ - if (local->tallies32) - prism2_info_commtallies32(local, buf, left); - else - prism2_info_commtallies16(local, buf, left); -} - - -#ifndef PRISM2_NO_STATION_MODES -#ifndef PRISM2_NO_DEBUG -static const char* hfa384x_linkstatus_str(u16 linkstatus) -{ - switch (linkstatus) { - case HFA384X_LINKSTATUS_CONNECTED: - return "Connected"; - case HFA384X_LINKSTATUS_DISCONNECTED: - return "Disconnected"; - case HFA384X_LINKSTATUS_AP_CHANGE: - return "Access point change"; - case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE: - return "Access point out of range"; - case HFA384X_LINKSTATUS_AP_IN_RANGE: - return "Access point in range"; - case HFA384X_LINKSTATUS_ASSOC_FAILED: - return "Association failed"; - default: - return "Unknown"; - } -} -#endif /* PRISM2_NO_DEBUG */ - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf, - int left) -{ - u16 val; - int non_sta_mode; - - /* Alloc new JoinRequests to occur since LinkStatus for the previous - * has been received */ - local->last_join_time = 0; - - if (left != 2) { - printk(KERN_DEBUG "%s: invalid linkstatus info frame " - "length %d\n", local->dev->name, left); - return; - } - - non_sta_mode = local->iw_mode == IW_MODE_MASTER || - local->iw_mode == IW_MODE_REPEAT || - local->iw_mode == IW_MODE_MONITOR; - - val = buf[0] | (buf[1] << 8); - if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n", - local->dev->name, val, hfa384x_linkstatus_str(val)); - } - - if (non_sta_mode) { - netif_carrier_on(local->dev); - netif_carrier_on(local->ddev); - return; - } - - /* Get current BSSID later in scheduled task */ - set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info); - local->prev_link_status = val; - schedule_work(&local->info_queue); -} - - -static void prism2_host_roaming(local_info_t *local) -{ - struct hfa384x_join_request req; - struct net_device *dev = local->dev; - struct hfa384x_hostscan_result *selected, *entry; - int i; - unsigned long flags; - - if (local->last_join_time && - time_before(jiffies, local->last_join_time + 10 * HZ)) { - PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been " - "completed - waiting for it before issuing new one\n", - dev->name); - return; - } - - /* ScanResults are sorted: first ESS results in decreasing signal - * quality then IBSS results in similar order. - * Trivial roaming policy: just select the first entry. - * This could probably be improved by adding hysteresis to limit - * number of handoffs, etc. - * - * Could do periodic RID_SCANREQUEST or Inquire F101 to get new - * ScanResults */ - spin_lock_irqsave(&local->lock, flags); - if (local->last_scan_results == NULL || - local->last_scan_results_count == 0) { - spin_unlock_irqrestore(&local->lock, flags); - PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n", - dev->name); - return; - } - - selected = &local->last_scan_results[0]; - - if (local->preferred_ap[0] || local->preferred_ap[1] || - local->preferred_ap[2] || local->preferred_ap[3] || - local->preferred_ap[4] || local->preferred_ap[5]) { - /* Try to find preferred AP */ - PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n", - dev->name, local->preferred_ap); - for (i = 0; i < local->last_scan_results_count; i++) { - entry = &local->last_scan_results[i]; - if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) - { - PDEBUG(DEBUG_EXTRA, "%s: using preferred AP " - "selection\n", dev->name); - selected = entry; - break; - } - } - } - - memcpy(req.bssid, selected->bssid, ETH_ALEN); - req.channel = selected->chid; - spin_unlock_irqrestore(&local->lock, flags); - - PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM" - " channel=%d\n", - dev->name, req.bssid, le16_to_cpu(req.channel)); - if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, - sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); - } - local->last_join_time = jiffies; -} - - -static void hostap_report_scan_complete(local_info_t *local) -{ - union iwreq_data wrqu; - - /* Inform user space about new scan results (just empty event, - * SIOCGIWSCAN can be used to fetch data */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL); - - /* Allow SIOCGIWSCAN handling to occur since we have received - * scanning result */ - local->scan_timestamp = 0; -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_scanresults(local_info_t *local, unsigned char *buf, - int left) -{ - u16 *pos; - int new_count, i; - unsigned long flags; - struct hfa384x_scan_result *res; - struct hfa384x_hostscan_result *results, *prev; - - if (left < 4) { - printk(KERN_DEBUG "%s: invalid scanresult info frame " - "length %d\n", local->dev->name, left); - return; - } - - pos = (u16 *) buf; - pos++; - pos++; - left -= 4; - - new_count = left / sizeof(struct hfa384x_scan_result); - results = kmalloc_array(new_count, - sizeof(struct hfa384x_hostscan_result), - GFP_ATOMIC); - if (results == NULL) - return; - - /* Convert to hostscan result format. */ - res = (struct hfa384x_scan_result *) pos; - for (i = 0; i < new_count; i++) { - memcpy(&results[i], &res[i], - sizeof(struct hfa384x_scan_result)); - results[i].atim = 0; - } - - spin_lock_irqsave(&local->lock, flags); - local->last_scan_type = PRISM2_SCAN; - prev = local->last_scan_results; - local->last_scan_results = results; - local->last_scan_results_count = new_count; - spin_unlock_irqrestore(&local->lock, flags); - kfree(prev); - - hostap_report_scan_complete(local); - - /* Perform rest of ScanResults handling later in scheduled task */ - set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info); - schedule_work(&local->info_queue); -} - - -/* Called only as a tasklet (software IRQ) */ -static void prism2_info_hostscanresults(local_info_t *local, - unsigned char *buf, int left) -{ - int i, result_size, copy_len, new_count; - struct hfa384x_hostscan_result *results, *prev; - unsigned long flags; - __le16 *pos; - u8 *ptr; - - wake_up_interruptible(&local->hostscan_wq); - - if (left < 4) { - printk(KERN_DEBUG "%s: invalid hostscanresult info frame " - "length %d\n", local->dev->name, left); - return; - } - - pos = (__le16 *) buf; - copy_len = result_size = le16_to_cpu(*pos); - if (result_size == 0) { - printk(KERN_DEBUG "%s: invalid result_size (0) in " - "hostscanresults\n", local->dev->name); - return; - } - if (copy_len > sizeof(struct hfa384x_hostscan_result)) - copy_len = sizeof(struct hfa384x_hostscan_result); - - pos++; - pos++; - left -= 4; - ptr = (u8 *) pos; - - new_count = left / result_size; - results = kcalloc(new_count, sizeof(struct hfa384x_hostscan_result), - GFP_ATOMIC); - if (results == NULL) - return; - - for (i = 0; i < new_count; i++) { - memcpy(&results[i], ptr, copy_len); - ptr += result_size; - left -= result_size; - } - - if (left) { - printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n", - local->dev->name, left, result_size); - } - - spin_lock_irqsave(&local->lock, flags); - local->last_scan_type = PRISM2_HOSTSCAN; - prev = local->last_scan_results; - local->last_scan_results = results; - local->last_scan_results_count = new_count; - spin_unlock_irqrestore(&local->lock, flags); - kfree(prev); - - hostap_report_scan_complete(local); -} -#endif /* PRISM2_NO_STATION_MODES */ - - -/* Called only as a tasklet (software IRQ) */ -void hostap_info_process(local_info_t *local, struct sk_buff *skb) -{ - struct hfa384x_info_frame *info; - unsigned char *buf; - int left; -#ifndef PRISM2_NO_DEBUG - int i; -#endif /* PRISM2_NO_DEBUG */ - - info = (struct hfa384x_info_frame *) skb->data; - buf = skb->data + sizeof(*info); - left = skb->len - sizeof(*info); - - switch (le16_to_cpu(info->type)) { - case HFA384X_INFO_COMMTALLIES: - prism2_info_commtallies(local, buf, left); - break; - -#ifndef PRISM2_NO_STATION_MODES - case HFA384X_INFO_LINKSTATUS: - prism2_info_linkstatus(local, buf, left); - break; - - case HFA384X_INFO_SCANRESULTS: - prism2_info_scanresults(local, buf, left); - break; - - case HFA384X_INFO_HOSTSCANRESULTS: - prism2_info_hostscanresults(local, buf, left); - break; -#endif /* PRISM2_NO_STATION_MODES */ - -#ifndef PRISM2_NO_DEBUG - default: - PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n", - local->dev->name, le16_to_cpu(info->len), - le16_to_cpu(info->type)); - PDEBUG(DEBUG_EXTRA, "Unknown info frame:"); - for (i = 0; i < (left < 100 ? left : 100); i++) - PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]); - PDEBUG2(DEBUG_EXTRA, "\n"); - break; -#endif /* PRISM2_NO_DEBUG */ - } -} - - -#ifndef PRISM2_NO_STATION_MODES -static void handle_info_queue_linkstatus(local_info_t *local) -{ - int val = local->prev_link_status; - int connected; - union iwreq_data wrqu; - - connected = - val == HFA384X_LINKSTATUS_CONNECTED || - val == HFA384X_LINKSTATUS_AP_CHANGE || - val == HFA384X_LINKSTATUS_AP_IN_RANGE; - - if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID, - local->bssid, ETH_ALEN, 1) < 0) { - printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " - "LinkStatus event\n", local->dev->name); - } else { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n", - local->dev->name, - (unsigned char *) local->bssid); - if (local->wds_type & HOSTAP_WDS_AP_CLIENT) - hostap_add_sta(local->ap, local->bssid); - } - - /* Get BSSID if we have a valid AP address */ - if (connected) { - netif_carrier_on(local->dev); - netif_carrier_on(local->ddev); - memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN); - } else { - netif_carrier_off(local->dev); - netif_carrier_off(local->ddev); - eth_zero_addr(wrqu.ap_addr.sa_data); - } - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* - * Filter out sequential disconnect events in order not to cause a - * flood of SIOCGIWAP events that have a race condition with EAPOL - * frames and can confuse wpa_supplicant about the current association - * status. - */ - if (connected || local->prev_linkstatus_connected) - wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); - local->prev_linkstatus_connected = connected; -} - - -static void handle_info_queue_scanresults(local_info_t *local) -{ - if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) - prism2_host_roaming(local); - - if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA && - !is_zero_ether_addr(local->preferred_ap)) { - /* - * Firmware seems to be getting into odd state in host_roaming - * mode 2 when hostscan is used without join command, so try - * to fix this by re-joining the current AP. This does not - * actually trigger a new association if the current AP is - * still in the scan results. - */ - prism2_host_roaming(local); - } -} - - -/* Called only as scheduled task after receiving info frames (used to avoid - * pending too much time in HW IRQ handler). */ -static void handle_info_queue(struct work_struct *work) -{ - local_info_t *local = container_of(work, local_info_t, info_queue); - - if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS, - &local->pending_info)) - handle_info_queue_linkstatus(local); - - if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS, - &local->pending_info)) - handle_info_queue_scanresults(local); -} -#endif /* PRISM2_NO_STATION_MODES */ - - -void hostap_info_init(local_info_t *local) -{ - skb_queue_head_init(&local->info_list); -#ifndef PRISM2_NO_STATION_MODES - INIT_WORK(&local->info_queue, handle_info_queue); -#endif /* PRISM2_NO_STATION_MODES */ -} - - -EXPORT_SYMBOL(hostap_info_init); -EXPORT_SYMBOL(hostap_info_process); diff --git a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c deleted file mode 100644 index 26162f92e3..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c +++ /dev/null @@ -1,3847 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */ - -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/sched/signal.h> -#include <linux/ethtool.h> -#include <linux/if_arp.h> -#include <linux/module.h> -#include <linux/etherdevice.h> -#include <net/lib80211.h> - -#include "hostap_wlan.h" -#include "hostap.h" -#include "hostap_ap.h" - -static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct iw_statistics *wstats; - - iface = netdev_priv(dev); - local = iface->local; - - /* Why are we doing that ? Jean II */ - if (iface->type != HOSTAP_INTERFACE_MAIN) - return NULL; - - wstats = &local->wstats; - - wstats->status = 0; - wstats->discard.code = - local->comm_tallies.rx_discards_wep_undecryptable; - wstats->discard.misc = - local->comm_tallies.rx_fcs_errors + - local->comm_tallies.rx_discards_no_buffer + - local->comm_tallies.tx_discards_wrong_sa; - - wstats->discard.retries = - local->comm_tallies.tx_retry_limit_exceeded; - wstats->discard.fragment = - local->comm_tallies.rx_message_in_bad_msg_fragments; - - if (local->iw_mode != IW_MODE_MASTER && - local->iw_mode != IW_MODE_REPEAT) { - - if (prism2_update_comms_qual(dev) == 0) - wstats->qual.updated = IW_QUAL_ALL_UPDATED | - IW_QUAL_DBM; - - wstats->qual.qual = local->comms_qual; - wstats->qual.level = local->avg_signal; - wstats->qual.noise = local->avg_noise; - } else { - wstats->qual.qual = 0; - wstats->qual.level = 0; - wstats->qual.noise = 0; - wstats->qual.updated = IW_QUAL_ALL_INVALID; - } - - return wstats; -} - - -static int prism2_get_datarates(struct net_device *dev, u8 *rates) -{ - struct hostap_interface *iface; - local_info_t *local; - u8 buf[12]; - int len; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf, - sizeof(buf), 0); - if (len < 2) - return 0; - - val = le16_to_cpu(*(__le16 *) buf); /* string length */ - - if (len - 2 < val || val > 10) - return 0; - - memcpy(rates, buf + 2, val); - return val; -} - - -static int prism2_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 rates[10]; - int len, i, over2 = 0; - - len = prism2_get_datarates(dev, rates); - - for (i = 0; i < len; i++) { - if (rates[i] == 0x0b || rates[i] == 0x16) { - over2 = 1; - break; - } - } - - strcpy(wrqu->name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS"); - - return 0; -} - - -static int prism2_ioctl_siwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface; - local_info_t *local; - int i; - struct lib80211_crypt_data **crypt; - - iface = netdev_priv(dev); - local = iface->local; - - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > 4) - i = local->crypt_info.tx_keyidx; - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - - crypt = &local->crypt_info.crypt[i]; - - if (erq->flags & IW_ENCODE_DISABLED) { - if (*crypt) - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - goto done; - } - - if (*crypt != NULL && (*crypt)->ops != NULL && - strcmp((*crypt)->ops->name, "WEP") != 0) { - /* changing to use WEP; deinit previously used algorithm */ - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - } - - if (*crypt == NULL) { - struct lib80211_crypt_data *new_crypt; - - /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), - GFP_KERNEL); - if (new_crypt == NULL) - return -ENOMEM; - new_crypt->ops = lib80211_get_crypto_ops("WEP"); - if (!new_crypt->ops) { - request_module("lib80211_crypt_wep"); - new_crypt->ops = lib80211_get_crypto_ops("WEP"); - } - if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(i); - if (!new_crypt->ops || !new_crypt->priv) { - kfree(new_crypt); - new_crypt = NULL; - - printk(KERN_WARNING "%s: could not initialize WEP: " - "load module hostap_crypt_wep.o\n", - dev->name); - return -EOPNOTSUPP; - } - *crypt = new_crypt; - } - - if (erq->length > 0) { - int len = erq->length <= 5 ? 5 : 13; - int first = 1, j; - if (len > erq->length) - memset(keybuf + erq->length, 0, len - erq->length); - (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); - for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt_info.crypt[j]) { - first = 0; - break; - } - } - if (first) - local->crypt_info.tx_keyidx = i; - } else { - /* No key data - just set the default TX key index */ - local->crypt_info.tx_keyidx = i; - } - - done: - local->open_wep = erq->flags & IW_ENCODE_OPEN; - - if (hostap_set_encryption(local)) { - printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name); - return -EINVAL; - } - - /* Do not reset port0 if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. Prism2 documentation seem to require port reset - * after WEP configuration. However, keys are apparently changed at - * least in Managed mode. */ - if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) { - printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); - return -EINVAL; - } - - return 0; -} - - -static int prism2_ioctl_giwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface; - local_info_t *local; - int i, len; - u16 val; - struct lib80211_crypt_data *crypt; - - iface = netdev_priv(dev); - local = iface->local; - - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > 4) - i = local->crypt_info.tx_keyidx; - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - - crypt = local->crypt_info.crypt[i]; - erq->flags = i + 1; - - if (crypt == NULL || crypt->ops == NULL) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - - if (strcmp(crypt->ops->name, "WEP") != 0) { - /* only WEP is supported with wireless extensions, so just - * report that encryption is used */ - erq->length = 0; - erq->flags |= IW_ENCODE_ENABLED; - return 0; - } - - /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show - * the keys from driver buffer */ - len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv); - erq->length = (len >= 0 ? len : 0); - - if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0) - { - printk("CNFWEPFLAGS reading failed\n"); - return -EOPNOTSUPP; - } - le16_to_cpus(&val); - if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED) - erq->flags |= IW_ENCODE_ENABLED; - else - erq->flags |= IW_ENCODE_DISABLED; - if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - return 0; -} - - -static int hostap_set_rate(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int ret, basic_rates; - - iface = netdev_priv(dev); - local = iface->local; - - basic_rates = local->basic_rates & local->tx_rate_control; - if (!basic_rates || basic_rates != local->basic_rates) { - printk(KERN_INFO "%s: updating basic rate set automatically " - "to match with the new supported rate set\n", - dev->name); - if (!basic_rates) - basic_rates = local->tx_rate_control; - - local->basic_rates = basic_rates; - if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, - basic_rates)) - printk(KERN_WARNING "%s: failed to set " - "cnfBasicRates\n", dev->name); - } - - ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, - local->tx_rate_control) || - hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, - local->tx_rate_control) || - local->func->reset_port(dev)); - - if (ret) { - printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates " - "setting to 0x%x failed\n", - dev->name, local->tx_rate_control); - } - - /* Update TX rate configuration for all STAs based on new operational - * rate set. */ - hostap_update_rates(local); - - return ret; -} - - -static int prism2_ioctl_siwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (rrq->fixed) { - switch (rrq->value) { - case 11000000: - local->tx_rate_control = HFA384X_RATES_11MBPS; - break; - case 5500000: - local->tx_rate_control = HFA384X_RATES_5MBPS; - break; - case 2000000: - local->tx_rate_control = HFA384X_RATES_2MBPS; - break; - case 1000000: - local->tx_rate_control = HFA384X_RATES_1MBPS; - break; - default: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - break; - } - } else { - switch (rrq->value) { - case 11000000: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - break; - case 5500000: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS; - break; - case 2000000: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS; - break; - case 1000000: - local->tx_rate_control = HFA384X_RATES_1MBPS; - break; - default: - local->tx_rate_control = HFA384X_RATES_1MBPS | - HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | - HFA384X_RATES_11MBPS; - break; - } - } - - return hostap_set_rate(dev); -} - - -static int prism2_ioctl_giwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - u16 val; - struct hostap_interface *iface; - local_info_t *local; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) < - 0) - return -EINVAL; - - if ((val & 0x1) && (val > 1)) - rrq->fixed = 0; - else - rrq->fixed = 1; - - if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL && - !local->fw_tx_rate_control) { - /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in - * Host AP mode, so use the recorded TX rate of the last sent - * frame */ - rrq->value = local->ap->last_tx_rate > 0 ? - local->ap->last_tx_rate * 100000 : 11000000; - return 0; - } - - if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) < - 0) - return -EINVAL; - - switch (val) { - case HFA384X_RATES_1MBPS: - rrq->value = 1000000; - break; - case HFA384X_RATES_2MBPS: - rrq->value = 2000000; - break; - case HFA384X_RATES_5MBPS: - rrq->value = 5500000; - break; - case HFA384X_RATES_11MBPS: - rrq->value = 11000000; - break; - default: - /* should not happen */ - rrq->value = 11000000; - ret = -EINVAL; - break; - } - - return ret; -} - - -static int prism2_ioctl_siwsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *sens = &wrqu->sens; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - /* Set the desired AP density */ - if (sens->value < 1 || sens->value > 3) - return -EINVAL; - - if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *sens = &wrqu->sens; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - /* Get the current AP density */ - if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) < - 0) - return -EINVAL; - - sens->value = le16_to_cpu(val); - sens->fixed = 1; - - return 0; -} - - -/* Deprecated in new wireless extension API */ -static int prism2_ioctl_giwaplist(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - struct sockaddr *addr; - struct iw_quality *qual; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->iw_mode != IW_MODE_MASTER) { - printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported " - "in Host AP mode\n"); - data->length = 0; - return -EOPNOTSUPP; - } - - addr = kmalloc_array(IW_MAX_AP, sizeof(struct sockaddr), GFP_KERNEL); - qual = kmalloc_array(IW_MAX_AP, sizeof(struct iw_quality), GFP_KERNEL); - if (addr == NULL || qual == NULL) { - kfree(addr); - kfree(qual); - data->length = 0; - return -ENOMEM; - } - - data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1); - - memcpy(extra, addr, sizeof(struct sockaddr) * data->length); - data->flags = 1; /* has quality information */ - memcpy(extra + sizeof(struct sockaddr) * data->length, qual, - sizeof(struct iw_quality) * data->length); - - kfree(addr); - kfree(qual); - return 0; -} - - -static int prism2_ioctl_siwrts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (rts->disabled) - val = cpu_to_le16(2347); - else if (rts->value < 0 || rts->value > 2347) - return -EINVAL; - else - val = cpu_to_le16(rts->value); - - if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) || - local->func->reset_port(dev)) - return -EINVAL; - - local->rts_threshold = rts->value; - - return 0; -} - -static int prism2_ioctl_giwrts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) < - 0) - return -EINVAL; - - rts->value = le16_to_cpu(val); - rts->disabled = (rts->value == 2347); - rts->fixed = 1; - - return 0; -} - - -static int prism2_ioctl_siwfrag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (rts->disabled) - val = cpu_to_le16(2346); - else if (rts->value < 256 || rts->value > 2346) - return -EINVAL; - else - val = cpu_to_le16(rts->value & ~0x1); /* even numbers only */ - - local->fragm_threshold = rts->value & ~0x1; - if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val, - 2) - || local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwfrag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct hostap_interface *iface; - local_info_t *local; - __le16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, - &val, 2, 1) < 0) - return -EINVAL; - - rts->value = le16_to_cpu(val); - rts->disabled = (rts->value == 2346); - rts->fixed = 1; - - return 0; -} - - -#ifndef PRISM2_NO_STATION_MODES -static int hostap_join_ap(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_join_request req; - unsigned long flags; - int i; - struct hfa384x_hostscan_result *entry; - - iface = netdev_priv(dev); - local = iface->local; - - memcpy(req.bssid, local->preferred_ap, ETH_ALEN); - req.channel = 0; - - spin_lock_irqsave(&local->lock, flags); - for (i = 0; i < local->last_scan_results_count; i++) { - if (!local->last_scan_results) - break; - entry = &local->last_scan_results[i]; - if (ether_addr_equal(local->preferred_ap, entry->bssid)) { - req.channel = entry->chid; - break; - } - } - spin_unlock_irqrestore(&local->lock, flags); - - if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, - sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest %pM failed\n", - dev->name, local->preferred_ap); - return -1; - } - - printk(KERN_DEBUG "%s: Trying to join BSSID %pM\n", - dev->name, local->preferred_ap); - - return 0; -} -#endif /* PRISM2_NO_STATION_MODES */ - - -static int prism2_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN); - - if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) { - struct hfa384x_scan_request scan_req; - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(0x3fff); - scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS); - if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, - &scan_req, sizeof(scan_req))) { - printk(KERN_DEBUG "%s: ScanResults request failed - " - "preferred AP delayed to next unsolicited " - "scan\n", dev->name); - } - } else if (local->host_roaming == 2 && - local->iw_mode == IW_MODE_INFRA) { - if (hostap_join_ap(dev)) - return -EINVAL; - } else { - printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only " - "in Managed mode when host_roaming is enabled\n", - dev->name); - } - - return 0; -#endif /* PRISM2_NO_STATION_MODES */ -} - -static int prism2_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - ap_addr->sa_family = ARPHRD_ETHER; - switch (iface->type) { - case HOSTAP_INTERFACE_AP: - memcpy(&ap_addr->sa_data, dev->dev_addr, ETH_ALEN); - break; - case HOSTAP_INTERFACE_STA: - memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN); - break; - case HOSTAP_INTERFACE_WDS: - memcpy(&ap_addr->sa_data, iface->u.wds.remote_addr, ETH_ALEN); - break; - default: - if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID, - &ap_addr->sa_data, ETH_ALEN, 1) < 0) - return -EOPNOTSUPP; - - /* local->bssid is also updated in LinkStatus handler when in - * station mode */ - memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN); - break; - } - - return 0; -} - - -static int prism2_ioctl_siwnickn(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *nickname) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - memset(local->name, 0, sizeof(local->name)); - memcpy(local->name, nickname, data->length); - local->name_set = 1; - - if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwnickn(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *nickname) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - int len; - char name[MAX_NAME_LEN + 3]; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME, - &name, MAX_NAME_LEN + 2, 0); - val = le16_to_cpu(*(__le16 *) name); - if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN) - return -EOPNOTSUPP; - - name[val + 2] = '\0'; - data->length = val + 1; - memcpy(nickname, name + 2, val + 1); - - return 0; -} - - -static int prism2_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - /* freq => chan. */ - if (freq->e == 1 && - freq->m / 100000 >= freq_list[0] && - freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) { - int ch; - int fr = freq->m / 100000; - for (ch = 0; ch < FREQ_COUNT; ch++) { - if (fr == freq_list[ch]) { - freq->e = 0; - freq->m = ch + 1; - break; - } - } - } - - if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT || - !(local->channel_mask & (1 << (freq->m - 1)))) - return -EINVAL; - - local->channel = freq->m; /* channel is used in prism2_setup_rids() */ - if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct hostap_interface *iface; - local_info_t *local; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) < - 0) - return -EINVAL; - - le16_to_cpus(&val); - if (val < 1 || val > FREQ_COUNT) - return -EINVAL; - - freq->m = freq_list[val - 1] * 100000; - freq->e = 1; - - return 0; -} - - -static void hostap_monitor_set_type(local_info_t *local) -{ - struct net_device *dev = local->ddev; - - if (dev == NULL) - return; - - if (local->monitor_type == PRISM2_MONITOR_PRISM || - local->monitor_type == PRISM2_MONITOR_CAPHDR) { - dev->type = ARPHRD_IEEE80211_PRISM; - } else if (local->monitor_type == PRISM2_MONITOR_RADIOTAP) { - dev->type = ARPHRD_IEEE80211_RADIOTAP; - } else { - dev->type = ARPHRD_IEEE80211; - } -} - - -static int prism2_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *ssid) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (iface->type == HOSTAP_INTERFACE_WDS) - return -EOPNOTSUPP; - - if (data->flags == 0) - ssid[0] = '\0'; /* ANY */ - - if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') { - /* Setting SSID to empty string seems to kill the card in - * Host AP mode */ - printk(KERN_DEBUG "%s: Host AP mode does not support " - "'Any' essid\n", dev->name); - return -EINVAL; - } - - memcpy(local->essid, ssid, data->length); - local->essid[data->length] = '\0'; - - if ((!local->fw_ap && - hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid)) - || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) || - local->func->reset_port(dev)) - return -EINVAL; - - return 0; -} - -static int prism2_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - if (iface->type == HOSTAP_INTERFACE_WDS) - return -EOPNOTSUPP; - - data->flags = 1; /* active */ - if (local->iw_mode == IW_MODE_MASTER) { - data->length = strlen(local->essid); - memcpy(essid, local->essid, IW_ESSID_MAX_SIZE); - } else { - int len; - char ssid[MAX_SSID_LEN + 2]; - memset(ssid, 0, sizeof(ssid)); - len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID, - &ssid, MAX_SSID_LEN + 2, 0); - val = le16_to_cpu(*(__le16 *) ssid); - if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) { - return -EOPNOTSUPP; - } - data->length = val; - memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE); - } - - return 0; -} - - -static int prism2_ioctl_giwrange(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - struct iw_range *range = (struct iw_range *) extra; - u8 rates[10]; - u16 val; - int i, len, over2; - - iface = netdev_priv(dev); - local = iface->local; - - data->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - /* TODO: could fill num_txpower and txpower array with - * something; however, there are 128 different values.. */ - - range->txpower_capa = IW_TXPOW_DBM; - - if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC) - { - range->min_pmp = 1 * 1024; - range->max_pmp = 65535 * 1024; - range->min_pmt = 1 * 1024; - range->max_pmt = 1000 * 1024; - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | - IW_POWER_UNICAST_R | IW_POWER_ALL_R; - } - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 18; - - range->retry_capa = IW_RETRY_LIMIT; - range->retry_flags = IW_RETRY_LIMIT; - range->min_retry = 0; - range->max_retry = 255; - - range->num_channels = FREQ_COUNT; - - val = 0; - for (i = 0; i < FREQ_COUNT; i++) { - if (local->channel_mask & (1 << i)) { - range->freq[val].i = i + 1; - range->freq[val].m = freq_list[i] * 100000; - range->freq[val].e = 1; - val++; - } - if (val == IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = val; - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { - range->max_qual.qual = 70; /* what is correct max? This was not - * documented exactly. At least - * 69 has been observed. */ - range->max_qual.level = 0; /* dB */ - range->max_qual.noise = 0; /* dB */ - - /* What would be suitable values for "average/typical" qual? */ - range->avg_qual.qual = 20; - range->avg_qual.level = -60; - range->avg_qual.noise = -95; - } else { - range->max_qual.qual = 92; /* 0 .. 92 */ - range->max_qual.level = 154; /* 27 .. 154 */ - range->max_qual.noise = 154; /* 27 .. 154 */ - } - range->sensitivity = 3; - - range->max_encoding_tokens = WEP_KEYS; - range->num_encoding_sizes = 2; - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - - over2 = 0; - len = prism2_get_datarates(dev, rates); - range->num_bitrates = 0; - for (i = 0; i < len; i++) { - if (range->num_bitrates < IW_MAX_BITRATES) { - range->bitrate[range->num_bitrates] = - rates[i] * 500000; - range->num_bitrates++; - } - if (rates[i] == 0x0b || rates[i] == 0x16) - over2 = 1; - } - /* estimated maximum TCP throughput values (bps) */ - range->throughput = over2 ? 5500000 : 1500000; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | - IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | - IW_EVENT_CAPA_MASK(SIOCGIWAP) | - IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | - IW_EVENT_CAPA_MASK(IWEVCUSTOM) | - IW_EVENT_CAPA_MASK(IWEVREGISTERED) | - IW_EVENT_CAPA_MASK(IWEVEXPIRED)); - - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) - range->scan_capa = IW_SCAN_CAPA_ESSID; - - return 0; -} - - -static int hostap_monitor_mode_enable(local_info_t *local) -{ - struct net_device *dev = local->dev; - - printk(KERN_DEBUG "Enabling monitor mode\n"); - hostap_monitor_set_type(local); - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - HFA384X_PORTTYPE_PSEUDO_IBSS)) { - printk(KERN_DEBUG "Port type setting for monitor mode " - "failed\n"); - return -EOPNOTSUPP; - } - - /* Host decrypt is needed to get the IV and ICV fields; - * however, monitor mode seems to remove WEP flag from frame - * control field */ - if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS, - HFA384X_WEPFLAGS_HOSTENCRYPT | - HFA384X_WEPFLAGS_HOSTDECRYPT)) { - printk(KERN_DEBUG "WEP flags setting failed\n"); - return -EOPNOTSUPP; - } - - if (local->func->reset_port(dev) || - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_MONITOR << 8), - 0, NULL, NULL)) { - printk(KERN_DEBUG "Setting monitor mode failed\n"); - return -EOPNOTSUPP; - } - - return 0; -} - - -static int hostap_monitor_mode_disable(local_info_t *local) -{ - struct net_device *dev = local->ddev; - - if (dev == NULL) - return -1; - - printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name); - dev->type = ARPHRD_ETHER; - - if (local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_STOP << 8), - 0, NULL, NULL)) - return -1; - return hostap_set_encryption(local); -} - - -static int prism2_ioctl_siwmode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct hostap_interface *iface; - local_info_t *local; - int double_reset = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && - *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT && - *mode != IW_MODE_MONITOR) - return -EOPNOTSUPP; - -#ifdef PRISM2_NO_STATION_MODES - if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA) - return -EOPNOTSUPP; -#endif /* PRISM2_NO_STATION_MODES */ - - if (*mode == local->iw_mode) - return 0; - - if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') { - printk(KERN_WARNING "%s: empty SSID not allowed in Master " - "mode\n", dev->name); - return -EINVAL; - } - - if (local->iw_mode == IW_MODE_MONITOR) - hostap_monitor_mode_disable(local); - - if ((local->iw_mode == IW_MODE_ADHOC || - local->iw_mode == IW_MODE_MONITOR) && *mode == IW_MODE_MASTER) { - /* There seems to be a firmware bug in at least STA f/w v1.5.6 - * that leaves beacon frames to use IBSS type when moving from - * IBSS to Host AP mode. Doing double Port0 reset seems to be - * enough to workaround this. */ - double_reset = 1; - } - - printk(KERN_DEBUG "prism2: %s: operating mode changed " - "%d -> %d\n", dev->name, local->iw_mode, *mode); - local->iw_mode = *mode; - - if (local->iw_mode == IW_MODE_MONITOR) - hostap_monitor_mode_enable(local); - else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && - !local->fw_encrypt_ok) { - printk(KERN_DEBUG "%s: defaulting to host-based encryption as " - "a workaround for firmware bug in Host AP mode WEP\n", - dev->name); - local->host_encrypt = 1; - } - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - hostap_get_porttype(local))) - return -EOPNOTSUPP; - - if (local->func->reset_port(dev)) - return -EINVAL; - if (double_reset && local->func->reset_port(dev)) - return -EINVAL; - - if (local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC) - { - /* netif_carrier is used only in client modes for now, so make - * sure carrier is on when moving to non-client modes. */ - netif_carrier_on(local->dev); - netif_carrier_on(local->ddev); - } - return 0; -} - - -static int prism2_ioctl_giwmode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - switch (iface->type) { - case HOSTAP_INTERFACE_STA: - *mode = IW_MODE_INFRA; - break; - case HOSTAP_INTERFACE_WDS: - *mode = IW_MODE_REPEAT; - break; - default: - *mode = local->iw_mode; - break; - } - return 0; -} - - -static int prism2_ioctl_siwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *wrq = &wrqu->power; -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - int ret = 0; - - if (wrq->disabled) - return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0); - - switch (wrq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - break; - case IW_POWER_ALL_R: - ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - break; - case IW_POWER_ON: - break; - default: - return -EINVAL; - } - - if (wrq->flags & IW_POWER_TIMEOUT) { - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION, - wrq->value / 1024); - if (ret) - return ret; - } - if (wrq->flags & IW_POWER_PERIOD) { - ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); - if (ret) - return ret; - ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION, - wrq->value / 1024); - if (ret) - return ret; - } - - return ret; -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_giwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->power; -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - struct hostap_interface *iface; - local_info_t *local; - __le16 enable, mcast; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1) - < 0) - return -EINVAL; - - if (!le16_to_cpu(enable)) { - rrq->disabled = 1; - return 0; - } - - rrq->disabled = 0; - - if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - __le16 timeout; - if (local->func->get_rid(dev, - HFA384X_RID_CNFPMHOLDOVERDURATION, - &timeout, 2, 1) < 0) - return -EINVAL; - - rrq->flags = IW_POWER_TIMEOUT; - rrq->value = le16_to_cpu(timeout) * 1024; - } else { - __le16 period; - if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION, - &period, 2, 1) < 0) - return -EINVAL; - - rrq->flags = IW_POWER_PERIOD; - rrq->value = le16_to_cpu(period) * 1024; - } - - if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast, - 2, 1) < 0) - return -EINVAL; - - if (le16_to_cpu(mcast)) - rrq->flags |= IW_POWER_ALL_R; - else - rrq->flags |= IW_POWER_UNICAST_R; - - return 0; -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_siwretry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->retry; - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - if (rrq->disabled) - return -EINVAL; - - /* setting retry limits is not supported with the current station - * firmware code; simulate this with alternative retry count for now */ - if (rrq->flags == IW_RETRY_LIMIT) { - if (rrq->value < 0) { - /* disable manual retry count setting and use firmware - * defaults */ - local->manual_retry_count = -1; - local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY; - } else { - if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, - rrq->value)) { - printk(KERN_DEBUG "%s: Alternate retry count " - "setting to %d failed\n", - dev->name, rrq->value); - return -EOPNOTSUPP; - } - - local->manual_retry_count = rrq->value; - local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY; - } - return 0; - } - - return -EOPNOTSUPP; - -#if 0 - /* what could be done, if firmware would support this.. */ - - if (rrq->flags & IW_RETRY_LIMIT) { - if (rrq->flags & IW_RETRY_LONG) - HFA384X_RID_LONGRETRYLIMIT = rrq->value; - else if (rrq->flags & IW_RETRY_SHORT) - HFA384X_RID_SHORTRETRYLIMIT = rrq->value; - else { - HFA384X_RID_LONGRETRYLIMIT = rrq->value; - HFA384X_RID_SHORTRETRYLIMIT = rrq->value; - } - - } - - if (rrq->flags & IW_RETRY_LIFETIME) { - HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024; - } - - return 0; -#endif /* 0 */ -} - -static int prism2_ioctl_giwretry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->retry; - struct hostap_interface *iface; - local_info_t *local; - __le16 shortretry, longretry, lifetime, altretry; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry, - 2, 1) < 0 || - local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry, - 2, 1) < 0 || - local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME, - &lifetime, 2, 1) < 0) - return -EINVAL; - - rrq->disabled = 0; - - if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - rrq->flags = IW_RETRY_LIFETIME; - rrq->value = le16_to_cpu(lifetime) * 1024; - } else { - if (local->manual_retry_count >= 0) { - rrq->flags = IW_RETRY_LIMIT; - if (local->func->get_rid(dev, - HFA384X_RID_CNFALTRETRYCOUNT, - &altretry, 2, 1) >= 0) - rrq->value = le16_to_cpu(altretry); - else - rrq->value = local->manual_retry_count; - } else if ((rrq->flags & IW_RETRY_LONG)) { - rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - rrq->value = le16_to_cpu(longretry); - } else { - rrq->flags = IW_RETRY_LIMIT; - rrq->value = le16_to_cpu(shortretry); - if (shortretry != longretry) - rrq->flags |= IW_RETRY_SHORT; - } - } - return 0; -} - - -/* Note! This TX power controlling is experimental and should not be used in - * production use. It just sets raw power register and does not use any kind of - * feedback information from the measured TX power (CR58). This is now - * commented out to make sure that it is not used by accident. TX power - * configuration will be enabled again after proper algorithm using feedback - * has been implemented. */ - -#ifdef RAW_TXPOWER_SETTING -/* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping.. - * This version assumes following mapping: - * CR31 is 7-bit value with -64 to +63 range. - * -64 is mapped into +20dBm and +63 into -43dBm. - * This is certainly not an exact mapping for every card, but at least - * increasing dBm value should correspond to increasing TX power. - */ - -static int prism2_txpower_hfa386x_to_dBm(u16 val) -{ - signed char tmp; - - if (val > 255) - val = 255; - - tmp = val; - tmp >>= 2; - - return -12 - tmp; -} - -static u16 prism2_txpower_dBm_to_hfa386x(int val) -{ - signed char tmp; - - if (val > 20) - return 128; - else if (val < -43) - return 127; - - tmp = val; - tmp = -12 - tmp; - tmp <<= 2; - - return (unsigned char) tmp; -} -#endif /* RAW_TXPOWER_SETTING */ - - -static int prism2_ioctl_siwtxpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->txpower; - struct hostap_interface *iface; - local_info_t *local; -#ifdef RAW_TXPOWER_SETTING - char *tmp; -#endif - u16 val; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (rrq->disabled) { - if (local->txpower_type != PRISM2_TXPOWER_OFF) { - val = 0xff; /* use all standby and sleep modes */ - ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_A_D_TEST_MODES2, - &val, NULL); - printk(KERN_DEBUG "%s: Turning radio off: %s\n", - dev->name, ret ? "failed" : "OK"); - local->txpower_type = PRISM2_TXPOWER_OFF; - } - return (ret ? -EOPNOTSUPP : 0); - } - - if (local->txpower_type == PRISM2_TXPOWER_OFF) { - val = 0; /* disable all standby and sleep modes */ - ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_A_D_TEST_MODES2, &val, NULL); - printk(KERN_DEBUG "%s: Turning radio on: %s\n", - dev->name, ret ? "failed" : "OK"); - local->txpower_type = PRISM2_TXPOWER_UNKNOWN; - } - -#ifdef RAW_TXPOWER_SETTING - if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) { - printk(KERN_DEBUG "Setting ALC on\n"); - val = HFA384X_TEST_CFG_BIT_ALC; - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL); - local->txpower_type = PRISM2_TXPOWER_AUTO; - return 0; - } - - if (local->txpower_type != PRISM2_TXPOWER_FIXED) { - printk(KERN_DEBUG "Setting ALC off\n"); - val = HFA384X_TEST_CFG_BIT_ALC; - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); - local->txpower_type = PRISM2_TXPOWER_FIXED; - } - - if (rrq->flags == IW_TXPOW_DBM) - tmp = "dBm"; - else if (rrq->flags == IW_TXPOW_MWATT) - tmp = "mW"; - else - tmp = "UNKNOWN"; - printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp); - - if (rrq->flags != IW_TXPOW_DBM) { - printk("SIOCSIWTXPOW with mW is not supported; use dBm\n"); - return -EOPNOTSUPP; - } - - local->txpower = rrq->value; - val = prism2_txpower_dBm_to_hfa386x(local->txpower); - if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) - ret = -EOPNOTSUPP; -#else /* RAW_TXPOWER_SETTING */ - if (rrq->fixed) - ret = -EOPNOTSUPP; -#endif /* RAW_TXPOWER_SETTING */ - - return ret; -} - -static int prism2_ioctl_giwtxpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ -#ifdef RAW_TXPOWER_SETTING - struct iw_param *rrq = &wrqu->txpower; - struct hostap_interface *iface; - local_info_t *local; - u16 resp0; - - iface = netdev_priv(dev); - local = iface->local; - - rrq->flags = IW_TXPOW_DBM; - rrq->disabled = 0; - rrq->fixed = 0; - - if (local->txpower_type == PRISM2_TXPOWER_AUTO) { - if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, - HFA386X_CR_MANUAL_TX_POWER, - NULL, &resp0) == 0) { - rrq->value = prism2_txpower_hfa386x_to_dBm(resp0); - } else { - /* Could not get real txpower; guess 15 dBm */ - rrq->value = 15; - } - } else if (local->txpower_type == PRISM2_TXPOWER_OFF) { - rrq->value = 0; - rrq->disabled = 1; - } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) { - rrq->value = local->txpower; - rrq->fixed = 1; - } else { - printk("SIOCGIWTXPOW - unknown txpower_type=%d\n", - local->txpower_type); - } - return 0; -#else /* RAW_TXPOWER_SETTING */ - return -EOPNOTSUPP; -#endif /* RAW_TXPOWER_SETTING */ -} - - -#ifndef PRISM2_NO_STATION_MODES - -/* HostScan request works with and without host_roaming mode. In addition, it - * does not break current association. However, it requires newer station - * firmware version (>= 1.3.1) than scan request. */ -static int prism2_request_hostscan(struct net_device *dev, - u8 *ssid, u8 ssid_len) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_hostscan_request scan_req; - - iface = netdev_priv(dev); - local = iface->local; - - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(local->channel_mask & - local->scan_channel_mask); - scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS); - if (ssid) { - if (ssid_len > 32) - return -EINVAL; - scan_req.target_ssid_len = cpu_to_le16(ssid_len); - memcpy(scan_req.target_ssid, ssid, ssid_len); - } - - if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, - sizeof(scan_req))) { - printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name); - return -EINVAL; - } - return 0; -} - - -static int prism2_request_scan(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_scan_request scan_req; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(local->channel_mask & - local->scan_channel_mask); - scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS); - - /* FIX: - * It seems to be enough to set roaming mode for a short moment to - * host-based and then setup scanrequest data and return the mode to - * firmware-based. - * - * Master mode would need to drop to Managed mode for a short while - * to make scanning work.. Or sweep through the different channels and - * use passive scan based on beacons. */ - - if (!local->host_roaming) - hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, - HFA384X_ROAMING_HOST); - - if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req, - sizeof(scan_req))) { - printk(KERN_DEBUG "SCANREQUEST failed\n"); - ret = -EINVAL; - } - - if (!local->host_roaming) - hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, - HFA384X_ROAMING_FIRMWARE); - - return ret; -} - -#else /* !PRISM2_NO_STATION_MODES */ - -static inline int prism2_request_hostscan(struct net_device *dev, - u8 *ssid, u8 ssid_len) -{ - return -EOPNOTSUPP; -} - - -static inline int prism2_request_scan(struct net_device *dev) -{ - return -EOPNOTSUPP; -} - -#endif /* !PRISM2_NO_STATION_MODES */ - - -static int prism2_ioctl_siwscan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - int ret; - u8 *ssid = NULL, ssid_len = 0; - struct iw_scan_req *req = (struct iw_scan_req *) extra; - - iface = netdev_priv(dev); - local = iface->local; - - if (data->length < sizeof(struct iw_scan_req)) - req = NULL; - - if (local->iw_mode == IW_MODE_MASTER) { - /* In master mode, we just return the results of our local - * tables, so we don't need to start anything... - * Jean II */ - data->length = 0; - return 0; - } - - if (!local->dev_enabled) - return -ENETDOWN; - - if (req && data->flags & IW_SCAN_THIS_ESSID) { - ssid = req->essid; - ssid_len = req->essid_len; - - if (ssid_len && - ((local->iw_mode != IW_MODE_INFRA && - local->iw_mode != IW_MODE_ADHOC) || - (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))) - return -EOPNOTSUPP; - } - - if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) - ret = prism2_request_hostscan(dev, ssid, ssid_len); - else - ret = prism2_request_scan(dev); - - if (ret == 0) - local->scan_timestamp = jiffies; - - /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */ - - return ret; -} - - -#ifndef PRISM2_NO_STATION_MODES -static char * __prism2_translate_scan(local_info_t *local, - struct iw_request_info *info, - struct hfa384x_hostscan_result *scan, - struct hostap_bss_info *bss, - char *current_ev, char *end_buf) -{ - int i, chan; - struct iw_event iwe; - char *current_val; - u16 capabilities; - u8 *pos; - u8 *ssid, *bssid; - size_t ssid_len; - char *buf; - - if (bss) { - ssid = bss->ssid; - ssid_len = bss->ssid_len; - bssid = bss->bssid; - } else { - ssid = scan->ssid; - ssid_len = le16_to_cpu(scan->ssid_len); - bssid = scan->bssid; - } - if (ssid_len > 32) - ssid_len = 32; - - /* First entry *MUST* be the AP MAC address */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, - IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = ssid_len; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ssid); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (bss) { - capabilities = bss->capab_info; - } else { - capabilities = le16_to_cpu(scan->capability); - } - if (capabilities & (WLAN_CAPABILITY_ESS | - WLAN_CAPABILITY_IBSS)) { - if (capabilities & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - if (scan) { - chan = le16_to_cpu(scan->chid); - } else if (bss) { - chan = bss->chan; - } else { - chan = 0; - } - - if (chan > 0) { - iwe.u.freq.m = freq_list[chan - 1] * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - } - - if (scan) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - if (local->last_scan_type == PRISM2_HOSTSCAN) { - iwe.u.qual.level = le16_to_cpu(scan->sl); - iwe.u.qual.noise = le16_to_cpu(scan->anl); - } else { - iwe.u.qual.level = - HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl)); - iwe.u.qual.noise = - HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl)); - } - iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_UPDATED - | IW_QUAL_QUAL_INVALID - | IW_QUAL_DBM; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (capabilities & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, ""); - - /* TODO: add SuppRates into BSS table */ - if (scan) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWRATE; - current_val = current_ev + iwe_stream_lcp_len(info); - pos = scan->sup_rates; - for (i = 0; i < sizeof(scan->sup_rates); i++) { - if (pos[i] == 0) - break; - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000); - current_val = iwe_stream_add_value( - info, current_ev, current_val, end_buf, &iwe, - IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - current_ev) > iwe_stream_lcp_len(info)) - current_ev = current_val; - } - - /* TODO: add BeaconInt,resp_rate,atim into BSS table */ - buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_ATOMIC); - if (buf && scan) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, buf); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, buf); - - if (local->last_scan_type == PRISM2_HOSTSCAN && - (capabilities & WLAN_CAPABILITY_IBSS)) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "atim=%d", le16_to_cpu(scan->atim)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, buf); - } - } - kfree(buf); - - if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->wpa_ie_len; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->wpa_ie); - } - - if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->rsn_ie_len; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->rsn_ie); - } - - return current_ev; -} - - -/* Translate scan data returned from the card to a card independent - * format that the Wireless Tools will understand - Jean II */ -static inline int prism2_translate_scan(local_info_t *local, - struct iw_request_info *info, - char *buffer, int buflen) -{ - struct hfa384x_hostscan_result *scan; - int entry; - char *current_ev = buffer; - char *end_buf = buffer + buflen; - struct list_head *ptr; - - spin_lock_bh(&local->lock); - - list_for_each(ptr, &local->bss_list) { - struct hostap_bss_info *bss; - bss = list_entry(ptr, struct hostap_bss_info, list); - bss->included = 0; - } - - for (entry = 0; entry < local->last_scan_results_count; entry++) { - int found = 0; - scan = &local->last_scan_results[entry]; - - /* Report every SSID if the AP is using multiple SSIDs. If no - * BSS record is found (e.g., when WPA mode is disabled), - * report the AP once. */ - list_for_each(ptr, &local->bss_list) { - struct hostap_bss_info *bss; - bss = list_entry(ptr, struct hostap_bss_info, list); - if (ether_addr_equal(bss->bssid, scan->bssid)) { - bss->included = 1; - current_ev = __prism2_translate_scan( - local, info, scan, bss, current_ev, - end_buf); - found++; - } - } - if (!found) { - current_ev = __prism2_translate_scan( - local, info, scan, NULL, current_ev, end_buf); - } - /* Check if there is space for one more entry */ - if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - spin_unlock_bh(&local->lock); - return -E2BIG; - } - } - - /* Prism2 firmware has limits (32 at least in some versions) for number - * of BSSes in scan results. Extend this limit by using local BSS list. - */ - list_for_each(ptr, &local->bss_list) { - struct hostap_bss_info *bss; - bss = list_entry(ptr, struct hostap_bss_info, list); - if (bss->included) - continue; - current_ev = __prism2_translate_scan(local, info, NULL, bss, - current_ev, end_buf); - /* Check if there is space for one more entry */ - if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - spin_unlock_bh(&local->lock); - return -E2BIG; - } - } - - spin_unlock_bh(&local->lock); - - return current_ev - buffer; -} -#endif /* PRISM2_NO_STATION_MODES */ - - -static inline int prism2_ioctl_giwscan_sta(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ -#ifdef PRISM2_NO_STATION_MODES - return -EOPNOTSUPP; -#else /* PRISM2_NO_STATION_MODES */ - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - /* Wait until the scan is finished. We can probably do better - * than that - Jean II */ - if (local->scan_timestamp && - time_before(jiffies, local->scan_timestamp + 3 * HZ)) { - /* Important note : we don't want to block the caller - * until results are ready for various reasons. - * First, managing wait queues is complex and racy - * (there may be multiple simultaneous callers). - * Second, we grab some rtnetlink lock before coming - * here (in dev_ioctl()). - * Third, the caller can wait on the Wireless Event - * - Jean II */ - return -EAGAIN; - } - local->scan_timestamp = 0; - - res = prism2_translate_scan(local, info, extra, data->length); - - if (res >= 0) { - data->length = res; - return 0; - } else { - data->length = 0; - return res; - } -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_giwscan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface; - local_info_t *local; - int res; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->iw_mode == IW_MODE_MASTER) { - /* In MASTER mode, it doesn't make sense to go around - * scanning the frequencies and make the stations we serve - * wait when what the user is really interested about is the - * list of stations and access points we are talking to. - * So, just extract results from our cache... - * Jean II */ - - /* Translate to WE format */ - res = prism2_ap_translate_scan(dev, info, extra); - if (res >= 0) { - printk(KERN_DEBUG "Scan result translation succeeded " - "(length=%d)\n", res); - data->length = res; - return 0; - } else { - printk(KERN_DEBUG - "Scan result translation failed (res=%d)\n", - res); - data->length = 0; - return res; - } - } else { - /* Station mode */ - return prism2_ioctl_giwscan_sta(dev, info, data, extra); - } -} - - -static const struct iw_priv_args prism2_priv[] = { - { PRISM2_IOCTL_MONITOR, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" }, - { PRISM2_IOCTL_READMIF, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" }, - { PRISM2_IOCTL_WRITEMIF, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" }, - { PRISM2_IOCTL_RESET, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" }, - { PRISM2_IOCTL_INQUIRE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" }, - { PRISM2_IOCTL_SET_RID_WORD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" }, - { PRISM2_IOCTL_MACCMD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" }, - { PRISM2_IOCTL_WDS_ADD, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" }, - { PRISM2_IOCTL_WDS_DEL, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" }, - { PRISM2_IOCTL_ADDMAC, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" }, - { PRISM2_IOCTL_DELMAC, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" }, - { PRISM2_IOCTL_KICKMAC, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" }, - /* --- raw access to sub-ioctls --- */ - { PRISM2_IOCTL_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" }, - { PRISM2_IOCTL_GET_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" }, - /* --- sub-ioctls handlers --- */ - { PRISM2_IOCTL_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" }, - { PRISM2_IOCTL_GET_PRISM2_PARAM, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, - /* --- sub-ioctls definitions --- */ - { PRISM2_PARAM_TXRATECTRL, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" }, - { PRISM2_PARAM_TXRATECTRL, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" }, - { PRISM2_PARAM_BEACON_INT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" }, - { PRISM2_PARAM_BEACON_INT, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" }, -#ifndef PRISM2_NO_STATION_MODES - { PRISM2_PARAM_PSEUDO_IBSS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" }, - { PRISM2_PARAM_PSEUDO_IBSS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" }, -#endif /* PRISM2_NO_STATION_MODES */ - { PRISM2_PARAM_ALC, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" }, - { PRISM2_PARAM_ALC, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" }, - { PRISM2_PARAM_DUMP, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" }, - { PRISM2_PARAM_DUMP, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" }, - { PRISM2_PARAM_OTHER_AP_POLICY, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" }, - { PRISM2_PARAM_OTHER_AP_POLICY, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" }, - { PRISM2_PARAM_AP_MAX_INACTIVITY, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" }, - { PRISM2_PARAM_AP_MAX_INACTIVITY, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" }, - { PRISM2_PARAM_AP_BRIDGE_PACKETS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" }, - { PRISM2_PARAM_AP_BRIDGE_PACKETS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" }, - { PRISM2_PARAM_DTIM_PERIOD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" }, - { PRISM2_PARAM_DTIM_PERIOD, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" }, - { PRISM2_PARAM_AP_NULLFUNC_ACK, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" }, - { PRISM2_PARAM_AP_NULLFUNC_ACK, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" }, - { PRISM2_PARAM_MAX_WDS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" }, - { PRISM2_PARAM_MAX_WDS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" }, - { PRISM2_PARAM_AP_AUTOM_AP_WDS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" }, - { PRISM2_PARAM_AP_AUTOM_AP_WDS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" }, - { PRISM2_PARAM_AP_AUTH_ALGS, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" }, - { PRISM2_PARAM_AP_AUTH_ALGS, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" }, - { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" }, - { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" }, - { PRISM2_PARAM_HOST_ENCRYPT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" }, - { PRISM2_PARAM_HOST_ENCRYPT, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" }, - { PRISM2_PARAM_HOST_DECRYPT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" }, - { PRISM2_PARAM_HOST_DECRYPT, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" }, -#ifndef PRISM2_NO_STATION_MODES - { PRISM2_PARAM_HOST_ROAMING, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" }, - { PRISM2_PARAM_HOST_ROAMING, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" }, -#endif /* PRISM2_NO_STATION_MODES */ - { PRISM2_PARAM_BCRX_STA_KEY, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" }, - { PRISM2_PARAM_BCRX_STA_KEY, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" }, - { PRISM2_PARAM_IEEE_802_1X, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" }, - { PRISM2_PARAM_IEEE_802_1X, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" }, - { PRISM2_PARAM_ANTSEL_TX, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" }, - { PRISM2_PARAM_ANTSEL_TX, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" }, - { PRISM2_PARAM_ANTSEL_RX, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" }, - { PRISM2_PARAM_ANTSEL_RX, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" }, - { PRISM2_PARAM_MONITOR_TYPE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" }, - { PRISM2_PARAM_MONITOR_TYPE, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" }, - { PRISM2_PARAM_WDS_TYPE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" }, - { PRISM2_PARAM_WDS_TYPE, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" }, - { PRISM2_PARAM_HOSTSCAN, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" }, - { PRISM2_PARAM_HOSTSCAN, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" }, - { PRISM2_PARAM_AP_SCAN, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" }, - { PRISM2_PARAM_AP_SCAN, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" }, - { PRISM2_PARAM_ENH_SEC, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" }, - { PRISM2_PARAM_ENH_SEC, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" }, -#ifdef PRISM2_IO_DEBUG - { PRISM2_PARAM_IO_DEBUG, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" }, - { PRISM2_PARAM_IO_DEBUG, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" }, -#endif /* PRISM2_IO_DEBUG */ - { PRISM2_PARAM_BASIC_RATES, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" }, - { PRISM2_PARAM_BASIC_RATES, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" }, - { PRISM2_PARAM_OPER_RATES, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" }, - { PRISM2_PARAM_OPER_RATES, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" }, - { PRISM2_PARAM_HOSTAPD, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" }, - { PRISM2_PARAM_HOSTAPD, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" }, - { PRISM2_PARAM_HOSTAPD_STA, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd_sta" }, - { PRISM2_PARAM_HOSTAPD_STA, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd_sta" }, - { PRISM2_PARAM_WPA, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wpa" }, - { PRISM2_PARAM_WPA, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwpa" }, - { PRISM2_PARAM_PRIVACY_INVOKED, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "privacy_invoked" }, - { PRISM2_PARAM_PRIVACY_INVOKED, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprivacy_invo" }, - { PRISM2_PARAM_TKIP_COUNTERMEASURES, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tkip_countermea" }, - { PRISM2_PARAM_TKIP_COUNTERMEASURES, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettkip_counter" }, - { PRISM2_PARAM_DROP_UNENCRYPTED, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "drop_unencrypte" }, - { PRISM2_PARAM_DROP_UNENCRYPTED, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdrop_unencry" }, - { PRISM2_PARAM_SCAN_CHANNEL_MASK, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "scan_channels" }, - { PRISM2_PARAM_SCAN_CHANNEL_MASK, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getscan_channel" }, -}; - - -static int prism2_ioctl_priv_prism2_param(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *uwrq, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - int *i = (int *) extra; - int param = *i; - int value = *(i + 1); - int ret = 0; - u16 val; - - iface = netdev_priv(dev); - local = iface->local; - - switch (param) { - case PRISM2_PARAM_TXRATECTRL: - local->fw_tx_rate_control = value; - break; - - case PRISM2_PARAM_BEACON_INT: - if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) || - local->func->reset_port(dev)) - ret = -EINVAL; - else - local->beacon_int = value; - break; - -#ifndef PRISM2_NO_STATION_MODES - case PRISM2_PARAM_PSEUDO_IBSS: - if (value == local->pseudo_adhoc) - break; - - if (value != 0 && value != 1) { - ret = -EINVAL; - break; - } - - printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n", - dev->name, local->pseudo_adhoc, value); - local->pseudo_adhoc = value; - if (local->iw_mode != IW_MODE_ADHOC) - break; - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - hostap_get_porttype(local))) { - ret = -EOPNOTSUPP; - break; - } - - if (local->func->reset_port(dev)) - ret = -EINVAL; - break; -#endif /* PRISM2_NO_STATION_MODES */ - - case PRISM2_PARAM_ALC: - printk(KERN_DEBUG "%s: %s ALC\n", dev->name, - value == 0 ? "Disabling" : "Enabling"); - val = HFA384X_TEST_CFG_BIT_ALC; - local->func->cmd(dev, HFA384X_CMDCODE_TEST | - (HFA384X_TEST_CFG_BITS << 8), - value == 0 ? 0 : 1, &val, NULL); - break; - - case PRISM2_PARAM_DUMP: - local->frame_dump = value; - break; - - case PRISM2_PARAM_OTHER_AP_POLICY: - if (value < 0 || value > 3) { - ret = -EINVAL; - break; - } - if (local->ap != NULL) - local->ap->ap_policy = value; - break; - - case PRISM2_PARAM_AP_MAX_INACTIVITY: - if (value < 0 || value > 7 * 24 * 60 * 60) { - ret = -EINVAL; - break; - } - if (local->ap != NULL) - local->ap->max_inactivity = value * HZ; - break; - - case PRISM2_PARAM_AP_BRIDGE_PACKETS: - if (local->ap != NULL) - local->ap->bridge_packets = value; - break; - - case PRISM2_PARAM_DTIM_PERIOD: - if (value < 0 || value > 65535) { - ret = -EINVAL; - break; - } - if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value) - || local->func->reset_port(dev)) - ret = -EINVAL; - else - local->dtim_period = value; - break; - - case PRISM2_PARAM_AP_NULLFUNC_ACK: - if (local->ap != NULL) - local->ap->nullfunc_ack = value; - break; - - case PRISM2_PARAM_MAX_WDS: - local->wds_max_connections = value; - break; - - case PRISM2_PARAM_AP_AUTOM_AP_WDS: - if (local->ap != NULL) { - if (!local->ap->autom_ap_wds && value) { - /* add WDS link to all APs in STA table */ - hostap_add_wds_links(local); - } - local->ap->autom_ap_wds = value; - } - break; - - case PRISM2_PARAM_AP_AUTH_ALGS: - local->auth_algs = value; - if (hostap_set_auth_algs(local)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: - local->monitor_allow_fcserr = value; - break; - - case PRISM2_PARAM_HOST_ENCRYPT: - local->host_encrypt = value; - if (hostap_set_encryption(local) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_HOST_DECRYPT: - local->host_decrypt = value; - if (hostap_set_encryption(local) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - -#ifndef PRISM2_NO_STATION_MODES - case PRISM2_PARAM_HOST_ROAMING: - if (value < 0 || value > 2) { - ret = -EINVAL; - break; - } - local->host_roaming = value; - if (hostap_set_roaming(local) || local->func->reset_port(dev)) - ret = -EINVAL; - break; -#endif /* PRISM2_NO_STATION_MODES */ - - case PRISM2_PARAM_BCRX_STA_KEY: - local->bcrx_sta_key = value; - break; - - case PRISM2_PARAM_IEEE_802_1X: - local->ieee_802_1x = value; - break; - - case PRISM2_PARAM_ANTSEL_TX: - if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { - ret = -EINVAL; - break; - } - local->antsel_tx = value; - hostap_set_antsel(local); - break; - - case PRISM2_PARAM_ANTSEL_RX: - if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { - ret = -EINVAL; - break; - } - local->antsel_rx = value; - hostap_set_antsel(local); - break; - - case PRISM2_PARAM_MONITOR_TYPE: - if (value != PRISM2_MONITOR_80211 && - value != PRISM2_MONITOR_CAPHDR && - value != PRISM2_MONITOR_PRISM && - value != PRISM2_MONITOR_RADIOTAP) { - ret = -EINVAL; - break; - } - local->monitor_type = value; - if (local->iw_mode == IW_MODE_MONITOR) - hostap_monitor_set_type(local); - break; - - case PRISM2_PARAM_WDS_TYPE: - local->wds_type = value; - break; - - case PRISM2_PARAM_HOSTSCAN: - { - struct hfa384x_hostscan_request scan_req; - u16 rate; - - memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = cpu_to_le16(0x3fff); - switch (value) { - case 1: rate = HFA384X_RATES_1MBPS; break; - case 2: rate = HFA384X_RATES_2MBPS; break; - case 3: rate = HFA384X_RATES_5MBPS; break; - case 4: rate = HFA384X_RATES_11MBPS; break; - default: rate = HFA384X_RATES_1MBPS; break; - } - scan_req.txrate = cpu_to_le16(rate); - /* leave SSID empty to accept all SSIDs */ - - if (local->iw_mode == IW_MODE_MASTER) { - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - HFA384X_PORTTYPE_BSS) || - local->func->reset_port(dev)) - printk(KERN_DEBUG "Leaving Host AP mode " - "for HostScan failed\n"); - } - - if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, - sizeof(scan_req))) { - printk(KERN_DEBUG "HOSTSCAN failed\n"); - ret = -EINVAL; - } - if (local->iw_mode == IW_MODE_MASTER) { - wait_queue_entry_t __wait; - init_waitqueue_entry(&__wait, current); - add_wait_queue(&local->hostscan_wq, &__wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - if (signal_pending(current)) - ret = -EINTR; - set_current_state(TASK_RUNNING); - remove_wait_queue(&local->hostscan_wq, &__wait); - - if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, - HFA384X_PORTTYPE_HOSTAP) || - local->func->reset_port(dev)) - printk(KERN_DEBUG "Returning to Host AP mode " - "after HostScan failed\n"); - } - break; - } - - case PRISM2_PARAM_AP_SCAN: - local->passive_scan_interval = value; - if (timer_pending(&local->passive_scan_timer)) - del_timer(&local->passive_scan_timer); - if (value > 0 && value < INT_MAX / HZ) { - local->passive_scan_timer.expires = jiffies + - local->passive_scan_interval * HZ; - add_timer(&local->passive_scan_timer); - } - break; - - case PRISM2_PARAM_ENH_SEC: - if (value < 0 || value > 3) { - ret = -EINVAL; - break; - } - local->enh_sec = value; - if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, - local->enh_sec) || - local->func->reset_port(dev)) { - printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w " - "1.6.3 or newer\n", dev->name); - ret = -EOPNOTSUPP; - } - break; - -#ifdef PRISM2_IO_DEBUG - case PRISM2_PARAM_IO_DEBUG: - local->io_debug_enabled = value; - break; -#endif /* PRISM2_IO_DEBUG */ - - case PRISM2_PARAM_BASIC_RATES: - if ((value & local->tx_rate_control) != value || value == 0) { - printk(KERN_INFO "%s: invalid basic rate set - basic " - "rates must be in supported rate set\n", - dev->name); - ret = -EINVAL; - break; - } - local->basic_rates = value; - if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, - local->basic_rates) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_OPER_RATES: - local->tx_rate_control = value; - if (hostap_set_rate(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_HOSTAPD: - ret = hostap_set_hostapd(local, value, 1); - break; - - case PRISM2_PARAM_HOSTAPD_STA: - ret = hostap_set_hostapd_sta(local, value, 1); - break; - - case PRISM2_PARAM_WPA: - local->wpa = value; - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - ret = -EOPNOTSUPP; - else if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, - value ? 1 : 0)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_PRIVACY_INVOKED: - local->privacy_invoked = value; - if (hostap_set_encryption(local) || - local->func->reset_port(dev)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_TKIP_COUNTERMEASURES: - local->tkip_countermeasures = value; - break; - - case PRISM2_PARAM_DROP_UNENCRYPTED: - local->drop_unencrypted = value; - break; - - case PRISM2_PARAM_SCAN_CHANNEL_MASK: - local->scan_channel_mask = value; - break; - - default: - printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n", - dev->name, param); - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - - -static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - int *param = (int *) extra; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - switch (*param) { - case PRISM2_PARAM_TXRATECTRL: - *param = local->fw_tx_rate_control; - break; - - case PRISM2_PARAM_BEACON_INT: - *param = local->beacon_int; - break; - - case PRISM2_PARAM_PSEUDO_IBSS: - *param = local->pseudo_adhoc; - break; - - case PRISM2_PARAM_ALC: - ret = -EOPNOTSUPP; /* FIX */ - break; - - case PRISM2_PARAM_DUMP: - *param = local->frame_dump; - break; - - case PRISM2_PARAM_OTHER_AP_POLICY: - if (local->ap != NULL) - *param = local->ap->ap_policy; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_MAX_INACTIVITY: - if (local->ap != NULL) - *param = local->ap->max_inactivity / HZ; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_BRIDGE_PACKETS: - if (local->ap != NULL) - *param = local->ap->bridge_packets; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_DTIM_PERIOD: - *param = local->dtim_period; - break; - - case PRISM2_PARAM_AP_NULLFUNC_ACK: - if (local->ap != NULL) - *param = local->ap->nullfunc_ack; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_MAX_WDS: - *param = local->wds_max_connections; - break; - - case PRISM2_PARAM_AP_AUTOM_AP_WDS: - if (local->ap != NULL) - *param = local->ap->autom_ap_wds; - else - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_AUTH_ALGS: - *param = local->auth_algs; - break; - - case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: - *param = local->monitor_allow_fcserr; - break; - - case PRISM2_PARAM_HOST_ENCRYPT: - *param = local->host_encrypt; - break; - - case PRISM2_PARAM_HOST_DECRYPT: - *param = local->host_decrypt; - break; - - case PRISM2_PARAM_HOST_ROAMING: - *param = local->host_roaming; - break; - - case PRISM2_PARAM_BCRX_STA_KEY: - *param = local->bcrx_sta_key; - break; - - case PRISM2_PARAM_IEEE_802_1X: - *param = local->ieee_802_1x; - break; - - case PRISM2_PARAM_ANTSEL_TX: - *param = local->antsel_tx; - break; - - case PRISM2_PARAM_ANTSEL_RX: - *param = local->antsel_rx; - break; - - case PRISM2_PARAM_MONITOR_TYPE: - *param = local->monitor_type; - break; - - case PRISM2_PARAM_WDS_TYPE: - *param = local->wds_type; - break; - - case PRISM2_PARAM_HOSTSCAN: - ret = -EOPNOTSUPP; - break; - - case PRISM2_PARAM_AP_SCAN: - *param = local->passive_scan_interval; - break; - - case PRISM2_PARAM_ENH_SEC: - *param = local->enh_sec; - break; - -#ifdef PRISM2_IO_DEBUG - case PRISM2_PARAM_IO_DEBUG: - *param = local->io_debug_enabled; - break; -#endif /* PRISM2_IO_DEBUG */ - - case PRISM2_PARAM_BASIC_RATES: - *param = local->basic_rates; - break; - - case PRISM2_PARAM_OPER_RATES: - *param = local->tx_rate_control; - break; - - case PRISM2_PARAM_HOSTAPD: - *param = local->hostapd; - break; - - case PRISM2_PARAM_HOSTAPD_STA: - *param = local->hostapd_sta; - break; - - case PRISM2_PARAM_WPA: - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - ret = -EOPNOTSUPP; - *param = local->wpa; - break; - - case PRISM2_PARAM_PRIVACY_INVOKED: - *param = local->privacy_invoked; - break; - - case PRISM2_PARAM_TKIP_COUNTERMEASURES: - *param = local->tkip_countermeasures; - break; - - case PRISM2_PARAM_DROP_UNENCRYPTED: - *param = local->drop_unencrypted; - break; - - case PRISM2_PARAM_SCAN_CHANNEL_MASK: - *param = local->scan_channel_mask; - break; - - default: - printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n", - dev->name, *param); - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - - -static int prism2_ioctl_priv_readmif(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - u16 resp0; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL, - &resp0)) - return -EOPNOTSUPP; - else - *extra = resp0; - - return 0; -} - - -static int prism2_ioctl_priv_writemif(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface; - local_info_t *local; - u16 cr, val; - - iface = netdev_priv(dev); - local = iface->local; - - cr = *extra; - val = *(extra + 1); - if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL)) - return -EOPNOTSUPP; - - return 0; -} - - -#ifdef PRISM2_DOWNLOAD_SUPPORT -static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) -{ - struct prism2_download_param *param; - int ret = 0; - - if (p->length < sizeof(struct prism2_download_param) || - p->length > 1024 || !p->pointer) - return -EINVAL; - - param = memdup_user(p->pointer, p->length); - if (IS_ERR(param)) { - return PTR_ERR(param); - } - - if (p->length < sizeof(struct prism2_download_param) + - param->num_areas * sizeof(struct prism2_download_area)) { - ret = -EINVAL; - goto out; - } - - ret = local->func->download(local, param); - - out: - kfree(param); - return ret; -} -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - -static int prism2_set_genericelement(struct net_device *dev, u8 *elem, - size_t len) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - u8 *buf; - - /* - * Add 16-bit length in the beginning of the buffer because Prism2 RID - * includes it. - */ - buf = kmalloc(len + 2, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - *((__le16 *) buf) = cpu_to_le16(len); - memcpy(buf + 2, elem, len); - - kfree(local->generic_elem); - local->generic_elem = buf; - local->generic_elem_len = len + 2; - - return local->func->set_rid(local->dev, HFA384X_RID_GENERICELEMENT, - buf, len + 2); -} - - -static int prism2_ioctl_siwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *data = &wrqu->param; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - break; - case IW_AUTH_TKIP_COUNTERMEASURES: - local->tkip_countermeasures = data->value; - break; - case IW_AUTH_DROP_UNENCRYPTED: - local->drop_unencrypted = data->value; - break; - case IW_AUTH_80211_AUTH_ALG: - local->auth_algs = data->value; - break; - case IW_AUTH_WPA_ENABLED: - if (data->value == 0) { - local->wpa = 0; - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - break; - prism2_set_genericelement(dev, "", 0); - local->host_roaming = 0; - local->privacy_invoked = 0; - if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, - 0) || - hostap_set_roaming(local) || - hostap_set_encryption(local) || - local->func->reset_port(dev)) - return -EINVAL; - break; - } - if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) - return -EOPNOTSUPP; - local->host_roaming = 2; - local->privacy_invoked = 1; - local->wpa = 1; - if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1) || - hostap_set_roaming(local) || - hostap_set_encryption(local) || - local->func->reset_port(dev)) - return -EINVAL; - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - local->ieee_802_1x = data->value; - break; - case IW_AUTH_PRIVACY_INVOKED: - local->privacy_invoked = data->value; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - - -static int prism2_ioctl_giwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *data = &wrqu->param; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - return -EOPNOTSUPP; - case IW_AUTH_TKIP_COUNTERMEASURES: - data->value = local->tkip_countermeasures; - break; - case IW_AUTH_DROP_UNENCRYPTED: - data->value = local->drop_unencrypted; - break; - case IW_AUTH_80211_AUTH_ALG: - data->value = local->auth_algs; - break; - case IW_AUTH_WPA_ENABLED: - data->value = local->wpa; - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - data->value = local->ieee_802_1x; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - - -static int prism2_ioctl_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int i, ret = 0; - struct lib80211_crypto_ops *ops; - struct lib80211_crypt_data **crypt; - void *sta_ptr; - u8 *addr; - const char *alg, *module; - - i = erq->flags & IW_ENCODE_INDEX; - if (i > WEP_KEYS) - return -EINVAL; - if (i < 1 || i > WEP_KEYS) - i = local->crypt_info.tx_keyidx; - else - i--; - if (i < 0 || i >= WEP_KEYS) - return -EINVAL; - - addr = ext->addr.sa_data; - if (is_broadcast_ether_addr(addr)) { - sta_ptr = NULL; - crypt = &local->crypt_info.crypt[i]; - } else { - if (i != 0) - return -EINVAL; - sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); - if (sta_ptr == NULL) { - if (local->iw_mode == IW_MODE_INFRA) { - /* - * TODO: add STA entry for the current AP so - * that unicast key can be used. For now, this - * is emulated by using default key idx 0. - */ - i = 0; - crypt = &local->crypt_info.crypt[i]; - } else - return -EINVAL; - } - } - - if ((erq->flags & IW_ENCODE_DISABLED) || - ext->alg == IW_ENCODE_ALG_NONE) { - if (*crypt) - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - goto done; - } - - switch (ext->alg) { - case IW_ENCODE_ALG_WEP: - alg = "WEP"; - module = "lib80211_crypt_wep"; - break; - case IW_ENCODE_ALG_TKIP: - alg = "TKIP"; - module = "lib80211_crypt_tkip"; - break; - case IW_ENCODE_ALG_CCMP: - alg = "CCMP"; - module = "lib80211_crypt_ccmp"; - break; - default: - printk(KERN_DEBUG "%s: unsupported algorithm %d\n", - local->dev->name, ext->alg); - ret = -EOPNOTSUPP; - goto done; - } - - ops = lib80211_get_crypto_ops(alg); - if (ops == NULL) { - request_module(module); - ops = lib80211_get_crypto_ops(alg); - } - if (ops == NULL) { - printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", - local->dev->name, alg); - ret = -EOPNOTSUPP; - goto done; - } - - if (sta_ptr || ext->alg != IW_ENCODE_ALG_WEP) { - /* - * Per station encryption and other than WEP algorithms - * require host-based encryption, so force them on - * automatically. - */ - local->host_decrypt = local->host_encrypt = 1; - } - - if (*crypt == NULL || (*crypt)->ops != ops) { - struct lib80211_crypt_data *new_crypt; - - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), - GFP_KERNEL); - if (new_crypt == NULL) { - ret = -ENOMEM; - goto done; - } - new_crypt->ops = ops; - if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(i); - if (new_crypt->priv == NULL) { - kfree(new_crypt); - ret = -EINVAL; - goto done; - } - - *crypt = new_crypt; - } - - /* - * TODO: if ext_flags does not have IW_ENCODE_EXT_RX_SEQ_VALID, the - * existing seq# should not be changed. - * TODO: if ext_flags has IW_ENCODE_EXT_TX_SEQ_VALID, next TX seq# - * should be changed to something else than zero. - */ - if ((!(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) || ext->key_len > 0) - && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, - (*crypt)->priv) < 0) { - printk(KERN_DEBUG "%s: key setting failed\n", - local->dev->name); - ret = -EINVAL; - goto done; - } - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - if (!sta_ptr) - local->crypt_info.tx_keyidx = i; - } - - - if (sta_ptr == NULL && ext->key_len > 0) { - int first = 1, j; - for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt_info.crypt[j]) { - first = 0; - break; - } - } - if (first) - local->crypt_info.tx_keyidx = i; - } - - done: - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - local->open_wep = erq->flags & IW_ENCODE_OPEN; - - /* - * Do not reset port0 if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. Prism2 documentation seem to require port reset - * after WEP configuration. However, keys are apparently changed at - * least in Managed mode. - */ - if (ret == 0 && - (hostap_set_encryption(local) || - (local->iw_mode != IW_MODE_INFRA && - local->func->reset_port(local->dev)))) - ret = -EINVAL; - - return ret; -} - - -static int prism2_ioctl_giwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *erq = &wrqu->encoding; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct lib80211_crypt_data **crypt; - void *sta_ptr; - int max_key_len, i; - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - u8 *addr; - - max_key_len = erq->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - i = erq->flags & IW_ENCODE_INDEX; - if (i < 1 || i > WEP_KEYS) - i = local->crypt_info.tx_keyidx; - else - i--; - - addr = ext->addr.sa_data; - if (is_broadcast_ether_addr(addr)) { - sta_ptr = NULL; - crypt = &local->crypt_info.crypt[i]; - } else { - i = 0; - sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); - if (sta_ptr == NULL) - return -EINVAL; - } - erq->flags = i + 1; - memset(ext, 0, sizeof(*ext)); - - if (*crypt == NULL || (*crypt)->ops == NULL) { - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - erq->flags |= IW_ENCODE_DISABLED; - } else { - if (strcmp((*crypt)->ops->name, "WEP") == 0) - ext->alg = IW_ENCODE_ALG_WEP; - else if (strcmp((*crypt)->ops->name, "TKIP") == 0) - ext->alg = IW_ENCODE_ALG_TKIP; - else if (strcmp((*crypt)->ops->name, "CCMP") == 0) - ext->alg = IW_ENCODE_ALG_CCMP; - else - return -EINVAL; - - if ((*crypt)->ops->get_key) { - ext->key_len = - (*crypt)->ops->get_key(ext->key, - max_key_len, - ext->tx_seq, - (*crypt)->priv); - if (ext->key_len && - (ext->alg == IW_ENCODE_ALG_TKIP || - ext->alg == IW_ENCODE_ALG_CCMP)) - ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; - } - } - - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - return 0; -} - - -static int prism2_ioctl_set_encryption(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int ret = 0; - struct lib80211_crypto_ops *ops; - struct lib80211_crypt_data **crypt; - void *sta_ptr; - - param->u.crypt.err = 0; - param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0'; - - if (param_len != - (int) ((char *) param->u.crypt.key - (char *) param) + - param->u.crypt.key_len) - return -EINVAL; - - if (is_broadcast_ether_addr(param->sta_addr)) { - if (param->u.crypt.idx >= WEP_KEYS) - return -EINVAL; - sta_ptr = NULL; - crypt = &local->crypt_info.crypt[param->u.crypt.idx]; - } else { - if (param->u.crypt.idx) - return -EINVAL; - sta_ptr = ap_crypt_get_ptrs( - local->ap, param->sta_addr, - (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT), - &crypt); - - if (sta_ptr == NULL) { - param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; - return -EINVAL; - } - } - - if (strcmp(param->u.crypt.alg, "none") == 0) { - if (crypt) - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - goto done; - } - - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { - request_module("lib80211_crypt_wep"); - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { - request_module("lib80211_crypt_tkip"); - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { - request_module("lib80211_crypt_ccmp"); - ops = lib80211_get_crypto_ops(param->u.crypt.alg); - } - if (ops == NULL) { - printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", - local->dev->name, param->u.crypt.alg); - param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG; - ret = -EINVAL; - goto done; - } - - /* station based encryption and other than WEP algorithms require - * host-based encryption, so force them on automatically */ - local->host_decrypt = local->host_encrypt = 1; - - if (*crypt == NULL || (*crypt)->ops != ops) { - struct lib80211_crypt_data *new_crypt; - - lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), - GFP_KERNEL); - if (new_crypt == NULL) { - ret = -ENOMEM; - goto done; - } - new_crypt->ops = ops; - new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx); - if (new_crypt->priv == NULL) { - kfree(new_crypt); - param->u.crypt.err = - HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED; - ret = -EINVAL; - goto done; - } - - *crypt = new_crypt; - } - - if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) || - param->u.crypt.key_len > 0) && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(param->u.crypt.key, - param->u.crypt.key_len, param->u.crypt.seq, - (*crypt)->priv) < 0) { - printk(KERN_DEBUG "%s: key setting failed\n", - local->dev->name); - param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED; - ret = -EINVAL; - goto done; - } - - if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) { - if (!sta_ptr) - local->crypt_info.tx_keyidx = param->u.crypt.idx; - else if (param->u.crypt.idx) { - printk(KERN_DEBUG "%s: TX key idx setting failed\n", - local->dev->name); - param->u.crypt.err = - HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED; - ret = -EINVAL; - goto done; - } - } - - done: - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - /* Do not reset port0 if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. Prism2 documentation seem to require port reset - * after WEP configuration. However, keys are apparently changed at - * least in Managed mode. */ - if (ret == 0 && - (hostap_set_encryption(local) || - (local->iw_mode != IW_MODE_INFRA && - local->func->reset_port(local->dev)))) { - param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED; - return -EINVAL; - } - - return ret; -} - - -static int prism2_ioctl_get_encryption(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - struct lib80211_crypt_data **crypt; - void *sta_ptr; - int max_key_len; - - param->u.crypt.err = 0; - - max_key_len = param_len - - (int) ((char *) param->u.crypt.key - (char *) param); - if (max_key_len < 0) - return -EINVAL; - - if (is_broadcast_ether_addr(param->sta_addr)) { - sta_ptr = NULL; - if (param->u.crypt.idx >= WEP_KEYS) - param->u.crypt.idx = local->crypt_info.tx_keyidx; - crypt = &local->crypt_info.crypt[param->u.crypt.idx]; - } else { - param->u.crypt.idx = 0; - sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0, - &crypt); - - if (sta_ptr == NULL) { - param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; - return -EINVAL; - } - } - - if (*crypt == NULL || (*crypt)->ops == NULL) { - memcpy(param->u.crypt.alg, "none", 5); - param->u.crypt.key_len = 0; - param->u.crypt.idx = 0xff; - } else { - strscpy(param->u.crypt.alg, (*crypt)->ops->name, - HOSTAP_CRYPT_ALG_NAME_LEN); - param->u.crypt.key_len = 0; - - memset(param->u.crypt.seq, 0, 8); - if ((*crypt)->ops->get_key) { - param->u.crypt.key_len = - (*crypt)->ops->get_key(param->u.crypt.key, - max_key_len, - param->u.crypt.seq, - (*crypt)->priv); - } - } - - if (sta_ptr) - hostap_handle_sta_release(sta_ptr); - - return 0; -} - - -static int prism2_ioctl_get_rid(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int max_len, res; - - max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; - if (max_len < 0) - return -EINVAL; - - res = local->func->get_rid(local->dev, param->u.rid.rid, - param->u.rid.data, param->u.rid.len, 0); - if (res >= 0) { - param->u.rid.len = res; - return 0; - } - - return res; -} - - -static int prism2_ioctl_set_rid(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int max_len; - - max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; - if (max_len < 0 || max_len < param->u.rid.len) - return -EINVAL; - - return local->func->set_rid(local->dev, param->u.rid.rid, - param->u.rid.data, param->u.rid.len); -} - - -static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - printk(KERN_DEBUG "%ssta: associated as client with AP %pM\n", - local->dev->name, param->sta_addr); - memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); - return 0; -} - - -static int prism2_ioctl_siwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - return prism2_set_genericelement(dev, extra, data->length); -} - - -static int prism2_ioctl_giwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *data = &wrqu->data; - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - int len = local->generic_elem_len - 2; - - if (len <= 0 || local->generic_elem == NULL) { - data->length = 0; - return 0; - } - - if (data->length < len) - return -E2BIG; - - data->length = len; - memcpy(extra, local->generic_elem + 2, len); - - return 0; -} - - -static int prism2_ioctl_set_generic_element(local_info_t *local, - struct prism2_hostapd_param *param, - int param_len) -{ - int max_len, len; - - len = param->u.generic_elem.len; - max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; - if (max_len < 0 || max_len < len) - return -EINVAL; - - return prism2_set_genericelement(local->dev, - param->u.generic_elem.data, len); -} - - -static int prism2_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - struct iw_mlme *mlme = (struct iw_mlme *) extra; - __le16 reason; - - reason = cpu_to_le16(mlme->reason_code); - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - return prism2_sta_send_mgmt(local, mlme->addr.sa_data, - IEEE80211_STYPE_DEAUTH, - (u8 *) &reason, 2); - case IW_MLME_DISASSOC: - return prism2_sta_send_mgmt(local, mlme->addr.sa_data, - IEEE80211_STYPE_DISASSOC, - (u8 *) &reason, 2); - default: - return -EOPNOTSUPP; - } -} - - -static int prism2_ioctl_mlme(local_info_t *local, - struct prism2_hostapd_param *param) -{ - __le16 reason; - - reason = cpu_to_le16(param->u.mlme.reason_code); - switch (param->u.mlme.cmd) { - case MLME_STA_DEAUTH: - return prism2_sta_send_mgmt(local, param->sta_addr, - IEEE80211_STYPE_DEAUTH, - (u8 *) &reason, 2); - case MLME_STA_DISASSOC: - return prism2_sta_send_mgmt(local, param->sta_addr, - IEEE80211_STYPE_DISASSOC, - (u8 *) &reason, 2); - default: - return -EOPNOTSUPP; - } -} - - -static int prism2_ioctl_scan_req(local_info_t *local, - struct prism2_hostapd_param *param) -{ -#ifndef PRISM2_NO_STATION_MODES - if ((local->iw_mode != IW_MODE_INFRA && - local->iw_mode != IW_MODE_ADHOC) || - (local->sta_fw_ver < PRISM2_FW_VER(1,3,1))) - return -EOPNOTSUPP; - - if (!local->dev_enabled) - return -ENETDOWN; - - return prism2_request_hostscan(local->dev, param->u.scan_req.ssid, - param->u.scan_req.ssid_len); -#else /* PRISM2_NO_STATION_MODES */ - return -EOPNOTSUPP; -#endif /* PRISM2_NO_STATION_MODES */ -} - - -static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) -{ - struct prism2_hostapd_param *param; - int ret = 0; - int ap_ioctl = 0; - - if (p->length < sizeof(struct prism2_hostapd_param) || - p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) - return -EINVAL; - - param = memdup_user(p->pointer, p->length); - if (IS_ERR(param)) { - return PTR_ERR(param); - } - - switch (param->cmd) { - case PRISM2_SET_ENCRYPTION: - ret = prism2_ioctl_set_encryption(local, param, p->length); - break; - case PRISM2_GET_ENCRYPTION: - ret = prism2_ioctl_get_encryption(local, param, p->length); - break; - case PRISM2_HOSTAPD_GET_RID: - ret = prism2_ioctl_get_rid(local, param, p->length); - break; - case PRISM2_HOSTAPD_SET_RID: - ret = prism2_ioctl_set_rid(local, param, p->length); - break; - case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR: - ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length); - break; - case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: - ret = prism2_ioctl_set_generic_element(local, param, - p->length); - break; - case PRISM2_HOSTAPD_MLME: - ret = prism2_ioctl_mlme(local, param); - break; - case PRISM2_HOSTAPD_SCAN_REQ: - ret = prism2_ioctl_scan_req(local, param); - break; - default: - ret = prism2_hostapd(local->ap, param); - ap_ioctl = 1; - break; - } - - if (ret == 1 || !ap_ioctl) { - if (copy_to_user(p->pointer, param, p->length)) { - ret = -EFAULT; - goto out; - } else if (ap_ioctl) - ret = 0; - } - - out: - kfree(param); - return ret; -} - - -static void prism2_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - - strscpy(info->driver, "hostap", sizeof(info->driver)); - snprintf(info->fw_version, sizeof(info->fw_version), - "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff, - (local->sta_fw_ver >> 8) & 0xff, - local->sta_fw_ver & 0xff); -} - -const struct ethtool_ops prism2_ethtool_ops = { - .get_drvinfo = prism2_get_drvinfo -}; - - -/* Structures to export the Wireless Handlers */ - -static const iw_handler prism2_handler[] = -{ - IW_HANDLER(SIOCGIWNAME, prism2_get_name), - IW_HANDLER(SIOCSIWFREQ, prism2_ioctl_siwfreq), - IW_HANDLER(SIOCGIWFREQ, prism2_ioctl_giwfreq), - IW_HANDLER(SIOCSIWMODE, prism2_ioctl_siwmode), - IW_HANDLER(SIOCGIWMODE, prism2_ioctl_giwmode), - IW_HANDLER(SIOCSIWSENS, prism2_ioctl_siwsens), - IW_HANDLER(SIOCGIWSENS, prism2_ioctl_giwsens), - IW_HANDLER(SIOCGIWRANGE, prism2_ioctl_giwrange), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, prism2_ioctl_siwap), - IW_HANDLER(SIOCGIWAP, prism2_ioctl_giwap), - IW_HANDLER(SIOCSIWMLME, prism2_ioctl_siwmlme), - IW_HANDLER(SIOCGIWAPLIST, prism2_ioctl_giwaplist), - IW_HANDLER(SIOCSIWSCAN, prism2_ioctl_siwscan), - IW_HANDLER(SIOCGIWSCAN, prism2_ioctl_giwscan), - IW_HANDLER(SIOCSIWESSID, prism2_ioctl_siwessid), - IW_HANDLER(SIOCGIWESSID, prism2_ioctl_giwessid), - IW_HANDLER(SIOCSIWNICKN, prism2_ioctl_siwnickn), - IW_HANDLER(SIOCGIWNICKN, prism2_ioctl_giwnickn), - IW_HANDLER(SIOCSIWRATE, prism2_ioctl_siwrate), - IW_HANDLER(SIOCGIWRATE, prism2_ioctl_giwrate), - IW_HANDLER(SIOCSIWRTS, prism2_ioctl_siwrts), - IW_HANDLER(SIOCGIWRTS, prism2_ioctl_giwrts), - IW_HANDLER(SIOCSIWFRAG, prism2_ioctl_siwfrag), - IW_HANDLER(SIOCGIWFRAG, prism2_ioctl_giwfrag), - IW_HANDLER(SIOCSIWTXPOW, prism2_ioctl_siwtxpow), - IW_HANDLER(SIOCGIWTXPOW, prism2_ioctl_giwtxpow), - IW_HANDLER(SIOCSIWRETRY, prism2_ioctl_siwretry), - IW_HANDLER(SIOCGIWRETRY, prism2_ioctl_giwretry), - IW_HANDLER(SIOCSIWENCODE, prism2_ioctl_siwencode), - IW_HANDLER(SIOCGIWENCODE, prism2_ioctl_giwencode), - IW_HANDLER(SIOCSIWPOWER, prism2_ioctl_siwpower), - IW_HANDLER(SIOCGIWPOWER, prism2_ioctl_giwpower), - IW_HANDLER(SIOCSIWGENIE, prism2_ioctl_siwgenie), - IW_HANDLER(SIOCGIWGENIE, prism2_ioctl_giwgenie), - IW_HANDLER(SIOCSIWAUTH, prism2_ioctl_siwauth), - IW_HANDLER(SIOCGIWAUTH, prism2_ioctl_giwauth), - IW_HANDLER(SIOCSIWENCODEEXT, prism2_ioctl_siwencodeext), - IW_HANDLER(SIOCGIWENCODEEXT, prism2_ioctl_giwencodeext), -}; - -static const iw_handler prism2_private_handler[] = -{ /* SIOCIWFIRSTPRIV + */ - prism2_ioctl_priv_prism2_param, /* 0 */ - prism2_ioctl_priv_get_prism2_param, /* 1 */ - prism2_ioctl_priv_writemif, /* 2 */ - prism2_ioctl_priv_readmif, /* 3 */ -}; - -const struct iw_handler_def hostap_iw_handler_def = -{ - .num_standard = ARRAY_SIZE(prism2_handler), - .num_private = ARRAY_SIZE(prism2_private_handler), - .num_private_args = ARRAY_SIZE(prism2_priv), - .standard = prism2_handler, - .private = prism2_private_handler, - .private_args = (struct iw_priv_args *) prism2_priv, - .get_wireless_stats = hostap_get_wireless_stats, -}; - - -/* Private ioctls that are not used with iwpriv; - * in SIOCDEVPRIVATE range */ -int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd) -{ - struct iwreq *wrq = (struct iwreq *)ifr; - struct hostap_interface *iface; - local_info_t *local; - int ret = 0; - - iface = netdev_priv(dev); - local = iface->local; - - if (in_compat_syscall()) /* not implemented yet */ - return -EOPNOTSUPP; - - switch (cmd) { -#ifdef PRISM2_DOWNLOAD_SUPPORT - case PRISM2_IOCTL_DOWNLOAD: - if (!capable(CAP_NET_ADMIN)) ret = -EPERM; - else ret = prism2_ioctl_priv_download(local, &wrq->u.data); - break; -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - - case PRISM2_IOCTL_HOSTAPD: - if (!capable(CAP_NET_ADMIN)) ret = -EPERM; - else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data); - break; - - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c deleted file mode 100644 index bf86ac26c2..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_main.c +++ /dev/null @@ -1,1123 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Host AP (software wireless LAN access point) driver for - * Intersil Prism2/2.5/3 - hostap.o module, common routines - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * <j@w1.fi> - * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/proc_fs.h> -#include <linux/if_arp.h> -#include <linux/delay.h> -#include <linux/random.h> -#include <linux/workqueue.h> -#include <linux/kmod.h> -#include <linux/rtnetlink.h> -#include <linux/wireless.h> -#include <linux/etherdevice.h> -#include <net/net_namespace.h> -#include <net/iw_handler.h> -#include <net/lib80211.h> -#include <linux/uaccess.h> - -#include "hostap_wlan.h" -#include "hostap_80211.h" -#include "hostap_ap.h" -#include "hostap.h" - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Host AP common routines"); -MODULE_LICENSE("GPL"); - -#define TX_TIMEOUT (2 * HZ) - -#define PRISM2_MAX_FRAME_SIZE 2304 -#define PRISM2_MIN_MTU 256 -/* FIX: */ -#define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */)) - - -struct net_device * hostap_add_interface(struct local_info *local, - int type, int rtnl_locked, - const char *prefix, - const char *name) -{ - struct net_device *dev, *mdev; - struct hostap_interface *iface; - int ret; - - dev = alloc_etherdev(sizeof(struct hostap_interface)); - if (dev == NULL) - return NULL; - - iface = netdev_priv(dev); - iface->dev = dev; - iface->local = local; - iface->type = type; - list_add(&iface->list, &local->hostap_interfaces); - - mdev = local->dev; - eth_hw_addr_inherit(dev, mdev); - dev->base_addr = mdev->base_addr; - dev->irq = mdev->irq; - dev->mem_start = mdev->mem_start; - dev->mem_end = mdev->mem_end; - - hostap_setup_dev(dev, local, type); - dev->needs_free_netdev = true; - - sprintf(dev->name, "%s%s", prefix, name); - if (!rtnl_locked) - rtnl_lock(); - - SET_NETDEV_DEV(dev, mdev->dev.parent); - ret = register_netdevice(dev); - - if (!rtnl_locked) - rtnl_unlock(); - - if (ret < 0) { - printk(KERN_WARNING "%s: failed to add new netdevice!\n", - dev->name); - free_netdev(dev); - return NULL; - } - - printk(KERN_DEBUG "%s: registered netdevice %s\n", - mdev->name, dev->name); - - return dev; -} - - -void hostap_remove_interface(struct net_device *dev, int rtnl_locked, - int remove_from_list) -{ - struct hostap_interface *iface; - - if (!dev) - return; - - iface = netdev_priv(dev); - - if (remove_from_list) { - list_del(&iface->list); - } - - if (dev == iface->local->ddev) - iface->local->ddev = NULL; - else if (dev == iface->local->apdev) - iface->local->apdev = NULL; - else if (dev == iface->local->stadev) - iface->local->stadev = NULL; - - if (rtnl_locked) - unregister_netdevice(dev); - else - unregister_netdev(dev); - - /* 'dev->needs_free_netdev = true' implies device data, including - * private data, will be freed when the device is removed */ -} - - -static inline int prism2_wds_special_addr(u8 *addr) -{ - if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5]) - return 0; - - return 1; -} - - -int prism2_wds_add(local_info_t *local, u8 *remote_addr, - int rtnl_locked) -{ - struct net_device *dev; - struct list_head *ptr; - struct hostap_interface *iface, *empty, *match; - - empty = match = NULL; - read_lock_bh(&local->iface_lock); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type != HOSTAP_INTERFACE_WDS) - continue; - - if (prism2_wds_special_addr(iface->u.wds.remote_addr)) - empty = iface; - else if (ether_addr_equal(iface->u.wds.remote_addr, remote_addr)) { - match = iface; - break; - } - } - if (!match && empty && !prism2_wds_special_addr(remote_addr)) { - /* take pre-allocated entry into use */ - memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN); - read_unlock_bh(&local->iface_lock); - printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n", - local->dev->name, empty->dev->name); - return 0; - } - read_unlock_bh(&local->iface_lock); - - if (!prism2_wds_special_addr(remote_addr)) { - if (match) - return -EEXIST; - hostap_add_sta(local->ap, remote_addr); - } - - if (local->wds_connections >= local->wds_max_connections) - return -ENOBUFS; - - /* verify that there is room for wds# postfix in the interface name */ - if (strlen(local->dev->name) >= IFNAMSIZ - 5) { - printk(KERN_DEBUG "'%s' too long base device name\n", - local->dev->name); - return -EINVAL; - } - - dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked, - local->ddev->name, "wds%d"); - if (dev == NULL) - return -ENOMEM; - - iface = netdev_priv(dev); - memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN); - - local->wds_connections++; - - return 0; -} - - -int prism2_wds_del(local_info_t *local, u8 *remote_addr, - int rtnl_locked, int do_not_remove) -{ - unsigned long flags; - struct list_head *ptr; - struct hostap_interface *iface, *selected = NULL; - - write_lock_irqsave(&local->iface_lock, flags); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type != HOSTAP_INTERFACE_WDS) - continue; - - if (ether_addr_equal(iface->u.wds.remote_addr, remote_addr)) { - selected = iface; - break; - } - } - if (selected && !do_not_remove) - list_del(&selected->list); - write_unlock_irqrestore(&local->iface_lock, flags); - - if (selected) { - if (do_not_remove) - eth_zero_addr(selected->u.wds.remote_addr); - else { - hostap_remove_interface(selected->dev, rtnl_locked, 0); - local->wds_connections--; - } - } - - return selected ? 0 : -ENODEV; -} - - -u16 hostap_tx_callback_register(local_info_t *local, - void (*func)(struct sk_buff *, int ok, void *), - void *data) -{ - unsigned long flags; - struct hostap_tx_callback_info *entry; - - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (entry == NULL) - return 0; - - entry->func = func; - entry->data = data; - - spin_lock_irqsave(&local->lock, flags); - entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1; - entry->next = local->tx_callback; - local->tx_callback = entry; - spin_unlock_irqrestore(&local->lock, flags); - - return entry->idx; -} - - -int hostap_tx_callback_unregister(local_info_t *local, u16 idx) -{ - unsigned long flags; - struct hostap_tx_callback_info *cb, *prev = NULL; - - spin_lock_irqsave(&local->lock, flags); - cb = local->tx_callback; - while (cb != NULL && cb->idx != idx) { - prev = cb; - cb = cb->next; - } - if (cb) { - if (prev == NULL) - local->tx_callback = cb->next; - else - prev->next = cb->next; - kfree(cb); - } - spin_unlock_irqrestore(&local->lock, flags); - - return cb ? 0 : -1; -} - - -/* val is in host byte order */ -int hostap_set_word(struct net_device *dev, int rid, u16 val) -{ - struct hostap_interface *iface; - __le16 tmp = cpu_to_le16(val); - iface = netdev_priv(dev); - return iface->local->func->set_rid(dev, rid, &tmp, 2); -} - - -int hostap_set_string(struct net_device *dev, int rid, const char *val) -{ - struct hostap_interface *iface; - char buf[MAX_SSID_LEN + 2]; - int len; - - iface = netdev_priv(dev); - len = strlen(val); - if (len > MAX_SSID_LEN) - return -1; - memset(buf, 0, sizeof(buf)); - buf[0] = len; /* little endian 16 bit word */ - memcpy(buf + 2, val, len); - - return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2); -} - - -u16 hostap_get_porttype(local_info_t *local) -{ - if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc) - return HFA384X_PORTTYPE_PSEUDO_IBSS; - if (local->iw_mode == IW_MODE_ADHOC) - return HFA384X_PORTTYPE_IBSS; - if (local->iw_mode == IW_MODE_INFRA) - return HFA384X_PORTTYPE_BSS; - if (local->iw_mode == IW_MODE_REPEAT) - return HFA384X_PORTTYPE_WDS; - if (local->iw_mode == IW_MODE_MONITOR) - return HFA384X_PORTTYPE_PSEUDO_IBSS; - return HFA384X_PORTTYPE_HOSTAP; -} - - -int hostap_set_encryption(local_info_t *local) -{ - u16 val, old_val; - int i, keylen, len, idx; - char keybuf[WEP_KEY_LEN + 1]; - enum { NONE, WEP, OTHER } encrypt_type; - - idx = local->crypt_info.tx_keyidx; - if (local->crypt_info.crypt[idx] == NULL || - local->crypt_info.crypt[idx]->ops == NULL) - encrypt_type = NONE; - else if (strcmp(local->crypt_info.crypt[idx]->ops->name, "WEP") == 0) - encrypt_type = WEP; - else - encrypt_type = OTHER; - - if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, - 1) < 0) { - printk(KERN_DEBUG "Could not read current WEP flags.\n"); - goto fail; - } - le16_to_cpus(&val); - old_val = val; - - if (encrypt_type != NONE || local->privacy_invoked) - val |= HFA384X_WEPFLAGS_PRIVACYINVOKED; - else - val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED; - - if (local->open_wep || encrypt_type == NONE || - ((local->ieee_802_1x || local->wpa) && local->host_decrypt)) - val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; - else - val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; - - if ((encrypt_type != NONE || local->privacy_invoked) && - (encrypt_type == OTHER || local->host_encrypt)) - val |= HFA384X_WEPFLAGS_HOSTENCRYPT; - else - val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT; - if ((encrypt_type != NONE || local->privacy_invoked) && - (encrypt_type == OTHER || local->host_decrypt)) - val |= HFA384X_WEPFLAGS_HOSTDECRYPT; - else - val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT; - - if (val != old_val && - hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) { - printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n", - val); - goto fail; - } - - if (encrypt_type != WEP) - return 0; - - /* 104-bit support seems to require that all the keys are set to the - * same keylen */ - keylen = 6; /* first 5 octets */ - len = local->crypt_info.crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), NULL, - local->crypt_info.crypt[idx]->priv); - if (idx >= 0 && idx < WEP_KEYS && len > 5) - keylen = WEP_KEY_LEN + 1; /* first 13 octets */ - - for (i = 0; i < WEP_KEYS; i++) { - memset(keybuf, 0, sizeof(keybuf)); - if (local->crypt_info.crypt[i]) { - (void) local->crypt_info.crypt[i]->ops->get_key( - keybuf, sizeof(keybuf), - NULL, local->crypt_info.crypt[i]->priv); - } - if (local->func->set_rid(local->dev, - HFA384X_RID_CNFDEFAULTKEY0 + i, - keybuf, keylen)) { - printk(KERN_DEBUG "Could not set key %d (len=%d)\n", - i, keylen); - goto fail; - } - } - if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) { - printk(KERN_DEBUG "Could not set default keyid %d\n", idx); - goto fail; - } - - return 0; - - fail: - printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name); - return -1; -} - - -int hostap_set_antsel(local_info_t *local) -{ - u16 val; - int ret = 0; - - if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH && - local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, - HFA386X_CR_TX_CONFIGURE, - NULL, &val) == 0) { - val &= ~(BIT(2) | BIT(1)); - switch (local->antsel_tx) { - case HOSTAP_ANTSEL_DIVERSITY: - val |= BIT(1); - break; - case HOSTAP_ANTSEL_LOW: - break; - case HOSTAP_ANTSEL_HIGH: - val |= BIT(2); - break; - } - - if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_TX_CONFIGURE, &val, NULL)) { - printk(KERN_INFO "%s: setting TX AntSel failed\n", - local->dev->name); - ret = -1; - } - } - - if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH && - local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, - HFA386X_CR_RX_CONFIGURE, - NULL, &val) == 0) { - val &= ~(BIT(1) | BIT(0)); - switch (local->antsel_rx) { - case HOSTAP_ANTSEL_DIVERSITY: - break; - case HOSTAP_ANTSEL_LOW: - val |= BIT(0); - break; - case HOSTAP_ANTSEL_HIGH: - val |= BIT(0) | BIT(1); - break; - } - - if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, - HFA386X_CR_RX_CONFIGURE, &val, NULL)) { - printk(KERN_INFO "%s: setting RX AntSel failed\n", - local->dev->name); - ret = -1; - } - } - - return ret; -} - - -int hostap_set_roaming(local_info_t *local) -{ - u16 val; - - switch (local->host_roaming) { - case 1: - val = HFA384X_ROAMING_HOST; - break; - case 2: - val = HFA384X_ROAMING_DISABLED; - break; - case 0: - default: - val = HFA384X_ROAMING_FIRMWARE; - break; - } - - return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val); -} - - -int hostap_set_auth_algs(local_info_t *local) -{ - int val = local->auth_algs; - /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication - * set to include both Open and Shared Key flags. It tries to use - * Shared Key authentication in that case even if WEP keys are not - * configured.. STA f/w v0.7.6 is able to handle such configuration, - * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */ - if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) && - val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY) - val = PRISM2_AUTH_OPEN; - - if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) { - printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x " - "failed\n", local->dev->name, local->auth_algs); - return -EINVAL; - } - - return 0; -} - - -void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) -{ - u16 status, fc; - - status = __le16_to_cpu(rx->status); - - printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, " - "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; " - "jiffies=%ld\n", - name, status, (status >> 8) & 0x07, status >> 13, status & 1, - rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies); - - fc = __le16_to_cpu(rx->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " - "data_len=%d%s%s\n", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl), - __le16_to_cpu(rx->data_len), - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", - rx->addr1, rx->addr2, rx->addr3, rx->addr4); - - printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", - rx->dst_addr, rx->src_addr, - __be16_to_cpu(rx->len)); -} - - -void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) -{ - u16 fc; - - printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " - "tx_control=0x%04x; jiffies=%ld\n", - name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate, - __le16_to_cpu(tx->tx_control), jiffies); - - fc = __le16_to_cpu(tx->frame_control); - printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " - "data_len=%d%s%s\n", - fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, - (fc & IEEE80211_FCTL_STYPE) >> 4, - __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl), - __le16_to_cpu(tx->data_len), - fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", - fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - - printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", - tx->addr1, tx->addr2, tx->addr3, tx->addr4); - - printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", - tx->dst_addr, tx->src_addr, - __be16_to_cpu(tx->len)); -} - - -static int hostap_80211_header_parse(const struct sk_buff *skb, - unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} - - -int hostap_80211_get_hdrlen(__le16 fc) -{ - if (ieee80211_is_data(fc) && ieee80211_has_a4 (fc)) - return 30; /* Addr4 */ - else if (ieee80211_is_cts(fc) || ieee80211_is_ack(fc)) - return 10; - else if (ieee80211_is_ctl(fc)) - return 16; - - return 24; -} - - -static int prism2_close(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - - PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name); - - iface = netdev_priv(dev); - local = iface->local; - - if (dev == local->ddev) { - prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING); - } -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - if (!local->hostapd && dev == local->dev && - (!local->func->card_present || local->func->card_present(local)) && - local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER) - hostap_deauth_all_stas(dev, local->ap, 1); -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - if (dev == local->dev) { - local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL); - } - - if (netif_running(dev)) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - - cancel_work_sync(&local->reset_queue); - cancel_work_sync(&local->set_multicast_list_queue); - cancel_work_sync(&local->set_tim_queue); -#ifndef PRISM2_NO_STATION_MODES - cancel_work_sync(&local->info_queue); -#endif - cancel_work_sync(&local->comms_qual_update); - - module_put(local->hw_module); - - local->num_dev_open--; - - if (dev != local->dev && local->dev->flags & IFF_UP && - local->master_dev_auto_open && local->num_dev_open == 1) { - /* Close master radio interface automatically if it was also - * opened automatically and we are now closing the last - * remaining non-master device. */ - dev_close(local->dev); - } - - return 0; -} - - -static int prism2_open(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - - PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name); - - iface = netdev_priv(dev); - local = iface->local; - - if (local->no_pri) { - printk(KERN_DEBUG "%s: could not set interface UP - no PRI " - "f/w\n", dev->name); - return -ENODEV; - } - - if ((local->func->card_present && !local->func->card_present(local)) || - local->hw_downloading) - return -ENODEV; - - if (!try_module_get(local->hw_module)) - return -ENODEV; - local->num_dev_open++; - - if (!local->dev_enabled && local->func->hw_enable(dev, 1)) { - printk(KERN_WARNING "%s: could not enable MAC port\n", - dev->name); - prism2_close(dev); - return -ENODEV; - } - if (!local->dev_enabled) - prism2_callback(local, PRISM2_CALLBACK_ENABLE); - local->dev_enabled = 1; - - if (dev != local->dev && !(local->dev->flags & IFF_UP)) { - /* Master radio interface is needed for all operation, so open - * it automatically when any virtual net_device is opened. */ - local->master_dev_auto_open = 1; - dev_open(local->dev, NULL); - } - - netif_device_attach(dev); - netif_start_queue(dev); - - return 0; -} - - -static int prism2_set_mac_address(struct net_device *dev, void *p) -{ - struct hostap_interface *iface; - local_info_t *local; - struct list_head *ptr; - struct sockaddr *addr = p; - - iface = netdev_priv(dev); - local = iface->local; - - if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data, - ETH_ALEN) < 0 || local->func->reset_port(dev)) - return -EINVAL; - - read_lock_bh(&local->iface_lock); - list_for_each(ptr, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - eth_hw_addr_set(iface->dev, addr->sa_data); - } - eth_hw_addr_set(local->dev, addr->sa_data); - read_unlock_bh(&local->iface_lock); - - return 0; -} - - -/* TODO: to be further implemented as soon as Prism2 fully supports - * GroupAddresses and correct documentation is available */ -void hostap_set_multicast_list_queue(struct work_struct *work) -{ - local_info_t *local = - container_of(work, local_info_t, set_multicast_list_queue); - struct net_device *dev = local->dev; - - if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, - local->is_promisc)) { - printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", - dev->name, local->is_promisc ? "en" : "dis"); - } -} - - -static void hostap_set_multicast_list(struct net_device *dev) -{ -#if 0 - /* FIX: promiscuous mode seems to be causing a lot of problems with - * some station firmware versions (FCSErr frames, invalid MACPort, etc. - * corrupted incoming frames). This code is now commented out while the - * problems are investigated. */ - struct hostap_interface *iface; - local_info_t *local; - - iface = netdev_priv(dev); - local = iface->local; - if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) { - local->is_promisc = 1; - } else { - local->is_promisc = 0; - } - - schedule_work(&local->set_multicast_list_queue); -#endif -} - - -static void prism2_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct hostap_interface *iface; - local_info_t *local; - struct hfa384x_regs regs; - - iface = netdev_priv(dev); - local = iface->local; - - printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name); - netif_stop_queue(local->dev); - - local->func->read_regs(dev, ®s); - printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x " - "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n", - dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1, - regs.swsupport0); - - local->func->schedule_reset(local); -} - -const struct header_ops hostap_80211_ops = { - .create = eth_header, - .cache = eth_header_cache, - .cache_update = eth_header_cache_update, - .parse = hostap_80211_header_parse, -}; -EXPORT_SYMBOL(hostap_80211_ops); - - -static const struct net_device_ops hostap_netdev_ops = { - .ndo_start_xmit = hostap_data_start_xmit, - - .ndo_open = prism2_open, - .ndo_stop = prism2_close, - .ndo_siocdevprivate = hostap_siocdevprivate, - .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_rx_mode = hostap_set_multicast_list, - .ndo_tx_timeout = prism2_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops hostap_mgmt_netdev_ops = { - .ndo_start_xmit = hostap_mgmt_start_xmit, - - .ndo_open = prism2_open, - .ndo_stop = prism2_close, - .ndo_siocdevprivate = hostap_siocdevprivate, - .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_rx_mode = hostap_set_multicast_list, - .ndo_tx_timeout = prism2_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops hostap_master_ops = { - .ndo_start_xmit = hostap_master_start_xmit, - - .ndo_open = prism2_open, - .ndo_stop = prism2_close, - .ndo_siocdevprivate = hostap_siocdevprivate, - .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_rx_mode = hostap_set_multicast_list, - .ndo_tx_timeout = prism2_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -void hostap_setup_dev(struct net_device *dev, local_info_t *local, - int type) -{ - struct hostap_interface *iface; - - iface = netdev_priv(dev); - ether_setup(dev); - dev->min_mtu = PRISM2_MIN_MTU; - dev->max_mtu = PRISM2_MAX_MTU; - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - - /* kernel callbacks */ - if (iface) { - /* Currently, we point to the proper spy_data only on - * the main_dev. This could be fixed. Jean II */ - iface->wireless_data.spy_data = &iface->spy_data; - dev->wireless_data = &iface->wireless_data; - } - dev->wireless_handlers = &hostap_iw_handler_def; - dev->watchdog_timeo = TX_TIMEOUT; - - switch(type) { - case HOSTAP_INTERFACE_AP: - dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */ - dev->netdev_ops = &hostap_mgmt_netdev_ops; - dev->type = ARPHRD_IEEE80211; - dev->header_ops = &hostap_80211_ops; - break; - case HOSTAP_INTERFACE_MASTER: - dev->netdev_ops = &hostap_master_ops; - break; - default: - dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */ - dev->netdev_ops = &hostap_netdev_ops; - } - - dev->mtu = local->mtu; - - - dev->ethtool_ops = &prism2_ethtool_ops; - -} - -static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - if (local->apdev) - return -EEXIST; - - printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name); - - local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP, - rtnl_locked, local->ddev->name, - "ap"); - if (local->apdev == NULL) - return -ENOMEM; - - return 0; -} - - -static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); - - hostap_remove_interface(local->apdev, rtnl_locked, 1); - local->apdev = NULL; - - return 0; -} - - -static int hostap_enable_hostapd_sta(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - if (local->stadev) - return -EEXIST; - - printk(KERN_DEBUG "%s: enabling hostapd STA mode\n", dev->name); - - local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA, - rtnl_locked, local->ddev->name, - "sta"); - if (local->stadev == NULL) - return -ENOMEM; - - return 0; -} - - -static int hostap_disable_hostapd_sta(local_info_t *local, int rtnl_locked) -{ - struct net_device *dev = local->dev; - - printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); - - hostap_remove_interface(local->stadev, rtnl_locked, 1); - local->stadev = NULL; - - return 0; -} - - -int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked) -{ - int ret; - - if (val < 0 || val > 1) - return -EINVAL; - - if (local->hostapd == val) - return 0; - - if (val) { - ret = hostap_enable_hostapd(local, rtnl_locked); - if (ret == 0) - local->hostapd = 1; - } else { - local->hostapd = 0; - ret = hostap_disable_hostapd(local, rtnl_locked); - if (ret != 0) - local->hostapd = 1; - } - - return ret; -} - - -int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked) -{ - int ret; - - if (val < 0 || val > 1) - return -EINVAL; - - if (local->hostapd_sta == val) - return 0; - - if (val) { - ret = hostap_enable_hostapd_sta(local, rtnl_locked); - if (ret == 0) - local->hostapd_sta = 1; - } else { - local->hostapd_sta = 0; - ret = hostap_disable_hostapd_sta(local, rtnl_locked); - if (ret != 0) - local->hostapd_sta = 1; - } - - - return ret; -} - - -int prism2_update_comms_qual(struct net_device *dev) -{ - struct hostap_interface *iface; - local_info_t *local; - int ret = 0; - struct hfa384x_comms_quality sq; - - iface = netdev_priv(dev); - local = iface->local; - if (!local->sta_fw_ver) - ret = -1; - else if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { - if (local->func->get_rid(local->dev, - HFA384X_RID_DBMCOMMSQUALITY, - &sq, sizeof(sq), 1) >= 0) { - local->comms_qual = (s16) le16_to_cpu(sq.comm_qual); - local->avg_signal = (s16) le16_to_cpu(sq.signal_level); - local->avg_noise = (s16) le16_to_cpu(sq.noise_level); - local->last_comms_qual_update = jiffies; - } else - ret = -1; - } else { - if (local->func->get_rid(local->dev, HFA384X_RID_COMMSQUALITY, - &sq, sizeof(sq), 1) >= 0) { - local->comms_qual = le16_to_cpu(sq.comm_qual); - local->avg_signal = HFA384X_LEVEL_TO_dBm( - le16_to_cpu(sq.signal_level)); - local->avg_noise = HFA384X_LEVEL_TO_dBm( - le16_to_cpu(sq.noise_level)); - local->last_comms_qual_update = jiffies; - } else - ret = -1; - } - - return ret; -} - - -int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, - u8 *body, size_t bodylen) -{ - struct sk_buff *skb; - struct hostap_ieee80211_mgmt *mgmt; - struct hostap_skb_tx_data *meta; - struct net_device *dev = local->dev; - - skb = dev_alloc_skb(IEEE80211_MGMT_HDR_LEN + bodylen); - if (skb == NULL) - return -ENOMEM; - - mgmt = skb_put_zero(skb, IEEE80211_MGMT_HDR_LEN); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); - memcpy(mgmt->da, dst, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, dst, ETH_ALEN); - if (body) - skb_put_data(skb, body, bodylen); - - meta = (struct hostap_skb_tx_data *) skb->cb; - memset(meta, 0, sizeof(*meta)); - meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; - meta->iface = netdev_priv(dev); - - skb->dev = dev; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - dev_queue_xmit(skb); - - return 0; -} - - -int prism2_sta_deauth(local_info_t *local, u16 reason) -{ - union iwreq_data wrqu; - int ret; - __le16 val = cpu_to_le16(reason); - - if (local->iw_mode != IW_MODE_INFRA || - is_zero_ether_addr(local->bssid) || - ether_addr_equal(local->bssid, "\x44\x44\x44\x44\x44\x44")) - return 0; - - ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH, - (u8 *) &val, 2); - eth_zero_addr(wrqu.ap_addr.sa_data); - wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); - return ret; -} - - -struct proc_dir_entry *hostap_proc; - -static int __init hostap_init(void) -{ - if (init_net.proc_net != NULL) { - hostap_proc = proc_mkdir("hostap", init_net.proc_net); - if (!hostap_proc) - printk(KERN_WARNING "Failed to mkdir " - "/proc/net/hostap\n"); - } else - hostap_proc = NULL; - - return 0; -} - - -static void __exit hostap_exit(void) -{ - if (hostap_proc != NULL) { - hostap_proc = NULL; - remove_proc_entry("hostap", init_net.proc_net); - } -} - - -EXPORT_SYMBOL(hostap_set_word); -EXPORT_SYMBOL(hostap_set_string); -EXPORT_SYMBOL(hostap_get_porttype); -EXPORT_SYMBOL(hostap_set_encryption); -EXPORT_SYMBOL(hostap_set_antsel); -EXPORT_SYMBOL(hostap_set_roaming); -EXPORT_SYMBOL(hostap_set_auth_algs); -EXPORT_SYMBOL(hostap_dump_rx_header); -EXPORT_SYMBOL(hostap_dump_tx_header); -EXPORT_SYMBOL(hostap_80211_get_hdrlen); -EXPORT_SYMBOL(hostap_setup_dev); -EXPORT_SYMBOL(hostap_set_multicast_list_queue); -EXPORT_SYMBOL(hostap_set_hostapd); -EXPORT_SYMBOL(hostap_set_hostapd_sta); -EXPORT_SYMBOL(hostap_add_interface); -EXPORT_SYMBOL(hostap_remove_interface); -EXPORT_SYMBOL(prism2_update_comms_qual); - -module_init(hostap_init); -module_exit(hostap_exit); diff --git a/drivers/net/wireless/intersil/hostap/hostap_pci.c b/drivers/net/wireless/intersil/hostap/hostap_pci.c deleted file mode 100644 index 52d77506ef..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_pci.c +++ /dev/null @@ -1,445 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#define PRISM2_PCI - -/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on - * driver patches from Reyk Floeter <reyk@vantronix.net> and - * Andy Warner <andyw@pobox.com> */ - -#include <linux/module.h> -#include <linux/if.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/wireless.h> -#include <net/iw_handler.h> - -#include <linux/ioport.h> -#include <linux/pci.h> -#include <asm/io.h> - -#include "hostap_wlan.h" - - -static char *dev_info = "hostap_pci"; - - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN " - "PCI cards."); -MODULE_LICENSE("GPL"); - - -/* struct local_info::hw_priv */ -struct hostap_pci_priv { - void __iomem *mem_start; -}; - - -/* FIX: do we need mb/wmb/rmb with memory operations? */ - - -static const struct pci_device_id prism2_pci_id_table[] = { - /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */ - { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID }, - /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */ - { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID }, - /* Samsung MagicLAN SWL-2210P */ - { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID }, - { 0 } -}; - - -#ifdef PRISM2_IO_DEBUG - -static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); - writeb(v, hw_priv->mem_start + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - u8 v; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - v = readb(hw_priv->mem_start + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); - writew(v, hw_priv->mem_start + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - local_info_t *local; - unsigned long flags; - u16 v; - - iface = netdev_priv(dev); - local = iface->local; - hw_priv = local->hw_priv; - - spin_lock_irqsave(&local->lock, flags); - v = readw(hw_priv->mem_start + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) -#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v))) -#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a))) - -#else /* PRISM2_IO_DEBUG */ - -static inline void hfa384x_outb(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - writeb(v, hw_priv->mem_start + a); -} - -static inline u8 hfa384x_inb(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - return readb(hw_priv->mem_start + a); -} - -static inline void hfa384x_outw(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - writew(v, hw_priv->mem_start + a); -} - -static inline u16 hfa384x_inw(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - return readw(hw_priv->mem_start + a); -} - -#define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw(dev, (a)) -#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v))) -#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a))) - -#endif /* PRISM2_IO_DEBUG */ - - -static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, - int len) -{ - u16 d_off; - __le16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (__le16 *) buf; - - for ( ; len > 1; len -= 2) - *pos++ = HFA384X_INW_DATA(d_off); - - if (len & 1) - *((char *) pos) = HFA384X_INB(d_off); - - return 0; -} - - -static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) -{ - u16 d_off; - __le16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (__le16 *) buf; - - for ( ; len > 1; len -= 2) - HFA384X_OUTW_DATA(*pos++, d_off); - - if (len & 1) - HFA384X_OUTB(*((char *) pos), d_off); - - return 0; -} - - -/* FIX: This might change at some point.. */ -#include "hostap_hw.c" - -static void prism2_pci_cor_sreset(local_info_t *local) -{ - struct net_device *dev = local->dev; - u16 reg; - - reg = HFA384X_INB(HFA384X_PCICOR_OFF); - printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg); - - /* linux-wlan-ng uses extremely long hold and settle times for - * COR sreset. A comment in the driver code mentions that the long - * delays appear to be necessary. However, at least IBM 22P6901 seems - * to work fine with shorter delays. - * - * Longer delays can be configured by uncommenting following line: */ -/* #define PRISM2_PCI_USE_LONG_DELAYS */ - -#ifdef PRISM2_PCI_USE_LONG_DELAYS - int i; - - HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); - mdelay(250); - - HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); - mdelay(500); - - /* Wait for f/w to complete initialization (CMD:BUSY == 0) */ - i = 2000000 / 10; - while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i) - udelay(10); - -#else /* PRISM2_PCI_USE_LONG_DELAYS */ - - HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); - mdelay(2); - HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); - mdelay(2); - -#endif /* PRISM2_PCI_USE_LONG_DELAYS */ - - if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) { - printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name); - } -} - - -static void prism2_pci_genesis_reset(local_info_t *local, int hcr) -{ - struct net_device *dev = local->dev; - - HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF); - mdelay(10); - HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF); - mdelay(10); - HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF); - mdelay(10); -} - - -static struct prism2_helper_functions prism2_pci_funcs = -{ - .card_present = NULL, - .cor_sreset = prism2_pci_cor_sreset, - .genesis_reset = prism2_pci_genesis_reset, - .hw_type = HOSTAP_HW_PCI, -}; - - -static int prism2_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned long phymem; - void __iomem *mem = NULL; - local_info_t *local = NULL; - struct net_device *dev = NULL; - static int cards_found /* = 0 */; - int irq_registered = 0; - struct hostap_interface *iface; - struct hostap_pci_priv *hw_priv; - - hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (hw_priv == NULL) - return -ENOMEM; - - if (pci_enable_device(pdev)) - goto err_out_free; - - phymem = pci_resource_start(pdev, 0); - - if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) { - printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n"); - goto err_out_disable; - } - - mem = pci_ioremap_bar(pdev, 0); - if (mem == NULL) { - printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; - goto fail; - } - - dev = prism2_init_local_data(&prism2_pci_funcs, cards_found, - &pdev->dev); - if (dev == NULL) - goto fail; - iface = netdev_priv(dev); - local = iface->local; - local->hw_priv = hw_priv; - cards_found++; - - dev->irq = pdev->irq; - hw_priv->mem_start = mem; - dev->base_addr = (unsigned long) mem; - - prism2_pci_cor_sreset(local); - - pci_set_drvdata(pdev, dev); - - if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name, - dev)) { - printk(KERN_WARNING "%s: request_irq failed\n", dev->name); - goto fail; - } else - irq_registered = 1; - - if (!local->pri_only && prism2_hw_config(dev, 1)) { - printk(KERN_DEBUG "%s: hardware initialization failed\n", - dev_info); - goto fail; - } - - printk(KERN_INFO "%s: Intersil Prism2.5 PCI: " - "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq); - - return hostap_hw_ready(dev); - - fail: - if (irq_registered && dev) - free_irq(dev->irq, dev); - - if (mem) - iounmap(mem); - - release_mem_region(phymem, pci_resource_len(pdev, 0)); - - err_out_disable: - pci_disable_device(pdev); - prism2_free_local_data(dev); - - err_out_free: - kfree(hw_priv); - - return -ENODEV; -} - - -static void prism2_pci_remove(struct pci_dev *pdev) -{ - struct net_device *dev; - struct hostap_interface *iface; - void __iomem *mem_start; - struct hostap_pci_priv *hw_priv; - - dev = pci_get_drvdata(pdev); - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - - /* Reset the hardware, and ensure interrupts are disabled. */ - prism2_pci_cor_sreset(iface->local); - hfa384x_disable_interrupts(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - - mem_start = hw_priv->mem_start; - prism2_free_local_data(dev); - kfree(hw_priv); - - iounmap(mem_start); - - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - pci_disable_device(pdev); -} - -static int __maybe_unused prism2_pci_suspend(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - - if (netif_running(dev)) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - prism2_suspend(dev); - - return 0; -} - -static int __maybe_unused prism2_pci_resume(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - - prism2_hw_config(dev, 0); - if (netif_running(dev)) { - netif_device_attach(dev); - netif_start_queue(dev); - } - - return 0; -} - -MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); - -static SIMPLE_DEV_PM_OPS(prism2_pci_pm_ops, - prism2_pci_suspend, - prism2_pci_resume); - -static struct pci_driver prism2_pci_driver = { - .name = "hostap_pci", - .id_table = prism2_pci_id_table, - .probe = prism2_pci_probe, - .remove = prism2_pci_remove, - .driver.pm = &prism2_pci_pm_ops, -}; - -module_pci_driver(prism2_pci_driver); diff --git a/drivers/net/wireless/intersil/hostap/hostap_plx.c b/drivers/net/wireless/intersil/hostap/hostap_plx.c deleted file mode 100644 index 58247290fc..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_plx.c +++ /dev/null @@ -1,617 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#define PRISM2_PLX - -/* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is - * based on: - * - Host AP driver patch from james@madingley.org - * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc. - */ - - -#include <linux/module.h> -#include <linux/if.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/wireless.h> -#include <net/iw_handler.h> - -#include <linux/ioport.h> -#include <linux/pci.h> -#include <asm/io.h> - -#include "hostap_wlan.h" - - -static char *dev_info = "hostap_plx"; - - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " - "cards (PLX)."); -MODULE_LICENSE("GPL"); - - -static int ignore_cis; -module_param(ignore_cis, int, 0444); -MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS"); - - -/* struct local_info::hw_priv */ -struct hostap_plx_priv { - void __iomem *attr_mem; - unsigned int cor_offset; -}; - - -#define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */ -#define COR_SRESET 0x80 -#define COR_LEVLREQ 0x40 -#define COR_ENABLE_FUNC 0x01 -/* PCI Configuration Registers */ -#define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */ -/* Local Configuration Registers */ -#define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */ -#define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */ -#define PLX_CNTRL 0x50 -#define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28) - - -#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID } - -static const struct pci_device_id prism2_plx_id_table[] = { - PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"), - PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"), - PLXDEV(0x126c, 0x8030, "Nortel emobility"), - PLXDEV(0x1562, 0x0001, "Symbol LA-4123"), - PLXDEV(0x1385, 0x4100, "Netgear MA301"), - PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"), - PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"), - PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"), - PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"), - PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"), - PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"), - PLXDEV(0x16ab, 0x1103, "Longshine 8031"), - PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"), - PLXDEV(0xec80, 0xec00, "Belkin F5D6000"), - { 0 } -}; - - -/* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid - * is not listed here, you will need to add it here to get the driver - * initialized. */ -static struct prism2_plx_manfid { - u16 manfid1, manfid2; -} prism2_plx_known_manfids[] = { - { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */, - { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */, - { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */, - { 0x0126, 0x8000 } /* Proxim RangeLAN */, - { 0x0138, 0x0002 } /* Compaq WL100 */, - { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */, - { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */, - { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */, - { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */, - { 0x028a, 0x0002 } /* D-Link DRC-650 */, - { 0x0250, 0x0002 } /* Samsung SWL2000-N */, - { 0xc250, 0x0002 } /* EMTAC A2424i */, - { 0xd601, 0x0002 } /* Z-Com XI300 */, - { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */, - { 0, 0} -}; - - -#ifdef PRISM2_IO_DEBUG - -static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); - outb(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u8 v; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - v = inb(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); - outw(v, dev->base_addr + a); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - u16 v; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - v = inw(dev->base_addr + a); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); - spin_unlock_irqrestore(&local->lock, flags); - return v; -} - -static inline void hfa384x_outsw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); - outsw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -static inline void hfa384x_insw_debug(struct net_device *dev, int a, - u8 *buf, int wc) -{ - struct hostap_interface *iface; - local_info_t *local; - unsigned long flags; - - iface = netdev_priv(dev); - local = iface->local; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); - insw(dev->base_addr + a, buf, wc); - spin_unlock_irqrestore(&local->lock, flags); -} - -#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) -#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) -#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) -#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) -#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) -#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) - -#else /* PRISM2_IO_DEBUG */ - -#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) -#define HFA384X_INB(a) inb(dev->base_addr + (a)) -#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) -#define HFA384X_INW(a) inw(dev->base_addr + (a)) -#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) -#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) - -#endif /* PRISM2_IO_DEBUG */ - - -static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, - int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_INSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - *((char *) pos) = HFA384X_INB(d_off); - - return 0; -} - - -static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) -{ - u16 d_off; - u16 *pos; - - d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; - - if (len / 2) - HFA384X_OUTSW(d_off, buf, len / 2); - pos += len / 2; - - if (len & 1) - HFA384X_OUTB(*((char *) pos), d_off); - - return 0; -} - - -/* FIX: This might change at some point.. */ -#include "hostap_hw.c" - - -static void prism2_plx_cor_sreset(local_info_t *local) -{ - unsigned char corsave; - struct hostap_plx_priv *hw_priv = local->hw_priv; - - printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n", - dev_info); - - /* Set sreset bit of COR and clear it after hold time */ - - if (hw_priv->attr_mem == NULL) { - /* TMD7160 - COR at card's first I/O addr */ - corsave = inb(hw_priv->cor_offset); - outb(corsave | COR_SRESET, hw_priv->cor_offset); - mdelay(2); - outb(corsave & ~COR_SRESET, hw_priv->cor_offset); - mdelay(2); - } else { - /* PLX9052 */ - corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset); - writeb(corsave | COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(2); - writeb(corsave & ~COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(2); - } -} - - -static void prism2_plx_genesis_reset(local_info_t *local, int hcr) -{ - unsigned char corsave; - struct hostap_plx_priv *hw_priv = local->hw_priv; - - if (hw_priv->attr_mem == NULL) { - /* TMD7160 - COR at card's first I/O addr */ - corsave = inb(hw_priv->cor_offset); - outb(corsave | COR_SRESET, hw_priv->cor_offset); - mdelay(10); - outb(hcr, hw_priv->cor_offset + 2); - mdelay(10); - outb(corsave & ~COR_SRESET, hw_priv->cor_offset); - mdelay(10); - } else { - /* PLX9052 */ - corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset); - writeb(corsave | COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(10); - writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2); - mdelay(10); - writeb(corsave & ~COR_SRESET, - hw_priv->attr_mem + hw_priv->cor_offset); - mdelay(10); - } -} - - -static struct prism2_helper_functions prism2_plx_funcs = -{ - .card_present = NULL, - .cor_sreset = prism2_plx_cor_sreset, - .genesis_reset = prism2_plx_genesis_reset, - .hw_type = HOSTAP_HW_PLX, -}; - - -static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len, - unsigned int *cor_offset, - unsigned int *cor_index) -{ -#define CISTPL_CONFIG 0x1A -#define CISTPL_MANFID 0x20 -#define CISTPL_END 0xFF -#define CIS_MAX_LEN 256 - u8 *cis; - int i, pos; - unsigned int rmsz, rasz, manfid1, manfid2; - struct prism2_plx_manfid *manfid; - - cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL); - if (cis == NULL) - return -ENOMEM; - - /* read CIS; it is in even offsets in the beginning of attr_mem */ - for (i = 0; i < CIS_MAX_LEN; i++) - cis[i] = readb(attr_mem + 2 * i); - printk(KERN_DEBUG "%s: CIS: %6ph ...\n", dev_info, cis); - - /* set reasonable defaults for Prism2 cards just in case CIS parsing - * fails */ - *cor_offset = 0x3e0; - *cor_index = 0x01; - manfid1 = manfid2 = 0; - - pos = 0; - while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) { - if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN) - goto cis_error; - - switch (cis[pos]) { - case CISTPL_CONFIG: - if (cis[pos + 1] < 2) - goto cis_error; - rmsz = (cis[pos + 2] & 0x3c) >> 2; - rasz = cis[pos + 2] & 0x03; - if (4 + rasz + rmsz > cis[pos + 1]) - goto cis_error; - *cor_index = cis[pos + 3] & 0x3F; - *cor_offset = 0; - for (i = 0; i <= rasz; i++) - *cor_offset += cis[pos + 4 + i] << (8 * i); - printk(KERN_DEBUG "%s: cor_index=0x%x " - "cor_offset=0x%x\n", dev_info, - *cor_index, *cor_offset); - if (*cor_offset > attr_len) { - printk(KERN_ERR "%s: COR offset not within " - "attr_mem\n", dev_info); - kfree(cis); - return -1; - } - break; - - case CISTPL_MANFID: - if (cis[pos + 1] < 4) - goto cis_error; - manfid1 = cis[pos + 2] + (cis[pos + 3] << 8); - manfid2 = cis[pos + 4] + (cis[pos + 5] << 8); - printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n", - dev_info, manfid1, manfid2); - break; - } - - pos += cis[pos + 1] + 2; - } - - if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END) - goto cis_error; - - for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++) - if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) { - kfree(cis); - return 0; - } - - printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is" - " not supported card\n", dev_info, manfid1, manfid2); - goto fail; - - cis_error: - printk(KERN_WARNING "%s: invalid CIS data\n", dev_info); - - fail: - kfree(cis); - if (ignore_cis) { - printk(KERN_INFO "%s: ignore_cis parameter set - ignoring " - "errors during CIS verification\n", dev_info); - return 0; - } - return -1; -} - - -static int prism2_plx_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned int pccard_ioaddr, plx_ioaddr; - unsigned long pccard_attr_mem; - unsigned int pccard_attr_len; - void __iomem *attr_mem = NULL; - unsigned int cor_offset = 0, cor_index = 0; - u32 reg; - local_info_t *local = NULL; - struct net_device *dev = NULL; - struct hostap_interface *iface; - static int cards_found /* = 0 */; - int irq_registered = 0; - int tmd7160; - struct hostap_plx_priv *hw_priv; - - hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (hw_priv == NULL) - return -ENOMEM; - - if (pci_enable_device(pdev)) - goto err_out_free; - - /* National Datacomm NCP130 based on TMD7160, not PLX9052. */ - tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131); - - plx_ioaddr = pci_resource_start(pdev, 1); - pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3); - - if (tmd7160) { - /* TMD7160 */ - attr_mem = NULL; /* no access to PC Card attribute memory */ - - printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, " - "irq=%d, pccard_io=0x%x\n", - plx_ioaddr, pdev->irq, pccard_ioaddr); - - cor_offset = plx_ioaddr; - cor_index = 0x04; - - outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr); - mdelay(1); - reg = inb(plx_ioaddr); - if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) { - printk(KERN_ERR "%s: Error setting COR (expected=" - "0x%02x, was=0x%02x)\n", dev_info, - cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg); - goto fail; - } - } else { - /* PLX9052 */ - pccard_attr_mem = pci_resource_start(pdev, 2); - pccard_attr_len = pci_resource_len(pdev, 2); - if (pccard_attr_len < PLX_MIN_ATTR_LEN) - goto fail; - - - attr_mem = ioremap(pccard_attr_mem, pccard_attr_len); - if (attr_mem == NULL) { - printk(KERN_ERR "%s: cannot remap attr_mem\n", - dev_info); - goto fail; - } - - printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: " - "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n", - pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr); - - if (prism2_plx_check_cis(attr_mem, pccard_attr_len, - &cor_offset, &cor_index)) { - printk(KERN_INFO "Unknown PC Card CIS - not a " - "Prism2/2.5 card?\n"); - goto fail; - } - - printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 " - "adapter\n"); - - /* Write COR to enable PC Card */ - writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, - attr_mem + cor_offset); - - /* Enable PCI interrupts if they are not already enabled */ - reg = inl(plx_ioaddr + PLX_INTCSR); - printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg); - if (!(reg & PLX_INTCSR_PCI_INTEN)) { - outl(reg | PLX_INTCSR_PCI_INTEN, - plx_ioaddr + PLX_INTCSR); - if (!(inl(plx_ioaddr + PLX_INTCSR) & - PLX_INTCSR_PCI_INTEN)) { - printk(KERN_WARNING "%s: Could not enable " - "Local Interrupts\n", dev_info); - goto fail; - } - } - - reg = inl(plx_ioaddr + PLX_CNTRL); - printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM " - "present=%d)\n", - reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0); - /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is - * not present; but are there really such cards in use(?) */ - } - - dev = prism2_init_local_data(&prism2_plx_funcs, cards_found, - &pdev->dev); - if (dev == NULL) - goto fail; - iface = netdev_priv(dev); - local = iface->local; - local->hw_priv = hw_priv; - cards_found++; - - dev->irq = pdev->irq; - dev->base_addr = pccard_ioaddr; - hw_priv->attr_mem = attr_mem; - hw_priv->cor_offset = cor_offset; - - pci_set_drvdata(pdev, dev); - - if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name, - dev)) { - printk(KERN_WARNING "%s: request_irq failed\n", dev->name); - goto fail; - } else - irq_registered = 1; - - if (prism2_hw_config(dev, 1)) { - printk(KERN_DEBUG "%s: hardware initialization failed\n", - dev_info); - goto fail; - } - - return hostap_hw_ready(dev); - - fail: - if (irq_registered && dev) - free_irq(dev->irq, dev); - - if (attr_mem) - iounmap(attr_mem); - - pci_disable_device(pdev); - prism2_free_local_data(dev); - - err_out_free: - kfree(hw_priv); - - return -ENODEV; -} - - -static void prism2_plx_remove(struct pci_dev *pdev) -{ - struct net_device *dev; - struct hostap_interface *iface; - struct hostap_plx_priv *hw_priv; - - dev = pci_get_drvdata(pdev); - iface = netdev_priv(dev); - hw_priv = iface->local->hw_priv; - - /* Reset the hardware, and ensure interrupts are disabled. */ - prism2_plx_cor_sreset(iface->local); - hfa384x_disable_interrupts(dev); - - if (hw_priv->attr_mem) - iounmap(hw_priv->attr_mem); - if (dev->irq) - free_irq(dev->irq, dev); - - prism2_free_local_data(dev); - kfree(hw_priv); - pci_disable_device(pdev); -} - - -MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); - -static struct pci_driver prism2_plx_driver = { - .name = "hostap_plx", - .id_table = prism2_plx_id_table, - .probe = prism2_plx_probe, - .remove = prism2_plx_remove, -}; - -module_pci_driver(prism2_plx_driver); diff --git a/drivers/net/wireless/intersil/hostap/hostap_proc.c b/drivers/net/wireless/intersil/hostap/hostap_proc.c deleted file mode 100644 index 61f6878605..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_proc.c +++ /dev/null @@ -1,411 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* /proc routines for Host AP driver */ - -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/export.h> -#include <net/lib80211.h> - -#include "hostap_wlan.h" -#include "hostap.h" - -#define PROC_LIMIT (PAGE_SIZE - 80) - -#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS) -static int prism2_debug_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - int i; - - seq_printf(m, "next_txfid=%d next_alloc=%d\n", - local->next_txfid, local->next_alloc); - for (i = 0; i < PRISM2_TXFID_COUNT; i++) - seq_printf(m, "FID: tx=%04X intransmit=%04X\n", - local->txfid[i], local->intransmitfid[i]); - seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control); - seq_printf(m, "beacon_int=%d\n", local->beacon_int); - seq_printf(m, "dtim_period=%d\n", local->dtim_period); - seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections); - seq_printf(m, "dev_enabled=%d\n", local->dev_enabled); - seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck); - for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt_info.crypt[i] && - local->crypt_info.crypt[i]->ops) { - seq_printf(m, "crypt[%d]=%s\n", i, - local->crypt_info.crypt[i]->ops->name); - } - } - seq_printf(m, "pri_only=%d\n", local->pri_only); - seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI); - seq_printf(m, "sram_type=%d\n", local->sram_type); - seq_printf(m, "no_pri=%d\n", local->no_pri); - - return 0; -} -#endif - -#ifdef CONFIG_PROC_FS -static int prism2_stats_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - struct comm_tallies_sums *sums = &local->comm_tallies; - - seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames); - seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames); - seq_printf(m, "TxFragments=%u\n", sums->tx_fragments); - seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets); - seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets); - seq_printf(m, "TxDeferredTransmissions=%u\n", - sums->tx_deferred_transmissions); - seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames); - seq_printf(m, "TxMultipleRetryFrames=%u\n", - sums->tx_multiple_retry_frames); - seq_printf(m, "TxRetryLimitExceeded=%u\n", - sums->tx_retry_limit_exceeded); - seq_printf(m, "TxDiscards=%u\n", sums->tx_discards); - seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames); - seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames); - seq_printf(m, "RxFragments=%u\n", sums->rx_fragments); - seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets); - seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets); - seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors); - seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer); - seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa); - seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n", - sums->rx_discards_wep_undecryptable); - seq_printf(m, "RxMessageInMsgFragments=%u\n", - sums->rx_message_in_msg_fragments); - seq_printf(m, "RxMessageInBadMsgFragments=%u\n", - sums->rx_message_in_bad_msg_fragments); - /* FIX: this may grow too long for one page(?) */ - - return 0; -} -#endif - -static int prism2_wds_proc_show(struct seq_file *m, void *v) -{ - struct list_head *ptr = v; - struct hostap_interface *iface; - - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_WDS) - seq_printf(m, "%s\t%pM\n", - iface->dev->name, iface->u.wds.remote_addr); - return 0; -} - -static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - read_lock_bh(&local->iface_lock); - return seq_list_start(&local->hostap_interfaces, *_pos); -} - -static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - return seq_list_next(v, &local->hostap_interfaces, _pos); -} - -static void prism2_wds_proc_stop(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - read_unlock_bh(&local->iface_lock); -} - -static const struct seq_operations prism2_wds_proc_seqops = { - .start = prism2_wds_proc_start, - .next = prism2_wds_proc_next, - .stop = prism2_wds_proc_stop, - .show = prism2_wds_proc_show, -}; - -static int prism2_bss_list_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - struct list_head *ptr = v; - struct hostap_bss_info *bss; - - if (ptr == &local->bss_list) { - seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t" - "SSID(hex)\tWPA IE\n"); - return 0; - } - - bss = list_entry(ptr, struct hostap_bss_info, list); - seq_printf(m, "%pM\t%lu\t%u\t0x%x\t", - bss->bssid, bss->last_update, - bss->count, bss->capab_info); - - seq_printf(m, "%*pE", (int)bss->ssid_len, bss->ssid); - - seq_putc(m, '\t'); - seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid); - seq_putc(m, '\t'); - seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie); - seq_putc(m, '\n'); - return 0; -} - -static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos) - __acquires(&local->lock) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_lock_bh(&local->lock); - return seq_list_start_head(&local->bss_list, *_pos); -} - -static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - return seq_list_next(v, &local->bss_list, _pos); -} - -static void prism2_bss_list_proc_stop(struct seq_file *m, void *v) - __releases(&local->lock) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_unlock_bh(&local->lock); -} - -static const struct seq_operations prism2_bss_list_proc_seqops = { - .start = prism2_bss_list_proc_start, - .next = prism2_bss_list_proc_next, - .stop = prism2_bss_list_proc_stop, - .show = prism2_bss_list_proc_show, -}; - -#ifdef CONFIG_PROC_FS -static int prism2_crypt_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = m->private; - int i; - - seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx); - for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt_info.crypt[i] && - local->crypt_info.crypt[i]->ops && - local->crypt_info.crypt[i]->ops->print_stats) { - local->crypt_info.crypt[i]->ops->print_stats( - m, local->crypt_info.crypt[i]->priv); - } - } - return 0; -} -#endif - -static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf, - size_t count, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(file)); - size_t off; - - if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE) - return 0; - - off = *_pos; - if (count > PRISM2_PDA_SIZE - off) - count = PRISM2_PDA_SIZE - off; - if (copy_to_user(buf, local->pda + off, count) != 0) - return -EFAULT; - *_pos += count; - return count; -} - -static const struct proc_ops prism2_pda_proc_ops = { - .proc_read = prism2_pda_proc_read, - .proc_lseek = generic_file_llseek, -}; - - -static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf, - size_t bufsize, loff_t *_pos) -{ - return 0; -} - -static const struct proc_ops prism2_aux_dump_proc_ops = { - .proc_read = prism2_aux_dump_proc_no_read, - .proc_lseek = default_llseek, -}; - - -#ifdef PRISM2_IO_DEBUG -static int prism2_io_debug_proc_read(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - local_info_t *local = (local_info_t *) data; - int head = local->io_debug_head; - int start_bytes, left, copy; - - if (off + count > PRISM2_IO_DEBUG_SIZE * 4) { - *eof = 1; - if (off >= PRISM2_IO_DEBUG_SIZE * 4) - return 0; - count = PRISM2_IO_DEBUG_SIZE * 4 - off; - } - - start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4; - left = count; - - if (off < start_bytes) { - copy = start_bytes - off; - if (copy > count) - copy = count; - memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy); - left -= copy; - if (left > 0) - memcpy(&page[copy], local->io_debug, left); - } else { - memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes), - left); - } - - *start = page; - - return count; -} -#endif /* PRISM2_IO_DEBUG */ - - -#ifndef PRISM2_NO_STATION_MODES -static int prism2_scan_results_proc_show(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - unsigned long entry; - int i, len; - struct hfa384x_hostscan_result *scanres; - u8 *p; - - if (v == SEQ_START_TOKEN) { - seq_printf(m, - "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n"); - return 0; - } - - entry = (unsigned long)v - 2; - scanres = &local->last_scan_results[entry]; - - seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ", - le16_to_cpu(scanres->chid), - (s16) le16_to_cpu(scanres->anl), - (s16) le16_to_cpu(scanres->sl), - le16_to_cpu(scanres->beacon_interval), - le16_to_cpu(scanres->capability), - le16_to_cpu(scanres->rate), - scanres->bssid, - le16_to_cpu(scanres->atim)); - - p = scanres->sup_rates; - for (i = 0; i < sizeof(scanres->sup_rates); i++) { - if (p[i] == 0) - break; - seq_printf(m, "<%02x>", p[i]); - } - seq_putc(m, ' '); - - p = scanres->ssid; - len = le16_to_cpu(scanres->ssid_len); - if (len > 32) - len = 32; - for (i = 0; i < len; i++) { - unsigned char c = p[i]; - if (c >= 32 && c < 127) - seq_putc(m, c); - else - seq_printf(m, "<%02x>", c); - } - seq_putc(m, '\n'); - return 0; -} - -static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_lock_bh(&local->lock); - - /* We have a header (pos 0) + N results to show (pos 1...N) */ - if (*_pos > local->last_scan_results_count) - return NULL; - return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */ -} - -static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos) -{ - local_info_t *local = pde_data(file_inode(m->file)); - - ++*_pos; - if (*_pos > local->last_scan_results_count) - return NULL; - return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */ -} - -static void prism2_scan_results_proc_stop(struct seq_file *m, void *v) -{ - local_info_t *local = pde_data(file_inode(m->file)); - spin_unlock_bh(&local->lock); -} - -static const struct seq_operations prism2_scan_results_proc_seqops = { - .start = prism2_scan_results_proc_start, - .next = prism2_scan_results_proc_next, - .stop = prism2_scan_results_proc_stop, - .show = prism2_scan_results_proc_show, -}; -#endif /* PRISM2_NO_STATION_MODES */ - - -void hostap_init_proc(local_info_t *local) -{ - local->proc = NULL; - - if (hostap_proc == NULL) { - printk(KERN_WARNING "%s: hostap proc directory not created\n", - local->dev->name); - return; - } - - local->proc = proc_mkdir(local->ddev->name, hostap_proc); - if (local->proc == NULL) { - printk(KERN_INFO "/proc/net/hostap/%s creation failed\n", - local->ddev->name); - return; - } - -#ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_single_data("debug", 0, local->proc, - prism2_debug_proc_show, local); -#endif /* PRISM2_NO_PROCFS_DEBUG */ - proc_create_single_data("stats", 0, local->proc, prism2_stats_proc_show, - local); - proc_create_seq_data("wds", 0, local->proc, - &prism2_wds_proc_seqops, local); - proc_create_data("pda", 0, local->proc, - &prism2_pda_proc_ops, local); - proc_create_data("aux_dump", 0, local->proc, - local->func->read_aux_proc_ops ?: &prism2_aux_dump_proc_ops, - local); - proc_create_seq_data("bss_list", 0, local->proc, - &prism2_bss_list_proc_seqops, local); - proc_create_single_data("crypt", 0, local->proc, prism2_crypt_proc_show, - local); -#ifdef PRISM2_IO_DEBUG - proc_create_single_data("io_debug", 0, local->proc, - prism2_debug_proc_show, local); -#endif /* PRISM2_IO_DEBUG */ -#ifndef PRISM2_NO_STATION_MODES - proc_create_seq_data("scan_results", 0, local->proc, - &prism2_scan_results_proc_seqops, local); -#endif /* PRISM2_NO_STATION_MODES */ -} - - -void hostap_remove_proc(local_info_t *local) -{ - proc_remove(local->proc); -} - - -EXPORT_SYMBOL(hostap_init_proc); -EXPORT_SYMBOL(hostap_remove_proc); diff --git a/drivers/net/wireless/intersil/hostap/hostap_wlan.h b/drivers/net/wireless/intersil/hostap/hostap_wlan.h deleted file mode 100644 index f71c0545c0..0000000000 --- a/drivers/net/wireless/intersil/hostap/hostap_wlan.h +++ /dev/null @@ -1,1051 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef HOSTAP_WLAN_H -#define HOSTAP_WLAN_H - -#include <linux/interrupt.h> -#include <linux/wireless.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/mutex.h> -#include <linux/refcount.h> -#include <net/iw_handler.h> -#include <net/ieee80211_radiotap.h> -#include <net/lib80211.h> - -#include "hostap_config.h" -#include "hostap_common.h" - -#define MAX_PARM_DEVICES 8 -#define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES) -#define DEF_INTS -1, -1, -1, -1, -1, -1, -1 -#define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx] - - -/* Specific skb->protocol value that indicates that the packet already contains - * txdesc header. - * FIX: This might need own value that would be allocated especially for Prism2 - * txdesc; ETH_P_CONTROL is commented as "Card specific control frames". - * However, these skb's should have only minimal path in the kernel side since - * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */ -#define ETH_P_HOSTAP ETH_P_CONTROL - -/* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header - * (from linux-wlan-ng) */ -struct linux_wlan_ng_val { - u32 did; - u16 status, len; - u32 data; -} __packed; - -struct linux_wlan_ng_prism_hdr { - u32 msgcode, msglen; - char devname[16]; - struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal, - noise, rate, istx, frmlen; -} __packed; - -struct linux_wlan_ng_cap_hdr { - __be32 version; - __be32 length; - __be64 mactime; - __be64 hosttime; - __be32 phytype; - __be32 channel; - __be32 datarate; - __be32 antenna; - __be32 priority; - __be32 ssi_type; - __be32 ssi_signal; - __be32 ssi_noise; - __be32 preamble; - __be32 encoding; -} __packed; - -struct hostap_radiotap_rx { - struct ieee80211_radiotap_header hdr; - __le64 tsft; - u8 rate; - u8 padding; - __le16 chan_freq; - __le16 chan_flags; - s8 dbm_antsignal; - s8 dbm_antnoise; -} __packed; - -#define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ -#define LWNG_CAPHDR_VERSION 0x80211001 - -struct hfa384x_rx_frame { - /* HFA384X RX frame descriptor */ - __le16 status; /* HFA384X_RX_STATUS_ flags */ - __le32 time; /* timestamp, 1 microsecond resolution */ - u8 silence; /* 27 .. 154; seems to be 0 */ - u8 signal; /* 27 .. 154 */ - u8 rate; /* 10, 20, 55, or 110 */ - u8 rxflow; - __le32 reserved; - - /* 802.11 */ - __le16 frame_control; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctrl; - u8 addr4[ETH_ALEN]; - __le16 data_len; - - /* 802.3 */ - u8 dst_addr[ETH_ALEN]; - u8 src_addr[ETH_ALEN]; - __be16 len; - - /* followed by frame data; max 2304 bytes */ -} __packed; - - -struct hfa384x_tx_frame { - /* HFA384X TX frame descriptor */ - __le16 status; /* HFA384X_TX_STATUS_ flags */ - __le16 reserved1; - __le16 reserved2; - __le32 sw_support; - u8 retry_count; /* not yet implemented */ - u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */ - __le16 tx_control; /* HFA384X_TX_CTRL_ flags */ - - /* 802.11 */ - struct_group(header, - __le16 frame_control; /* parts not used */ - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; /* filled by firmware */ - u8 addr3[ETH_ALEN]; - __le16 seq_ctrl; /* filled by firmware */ - ); - u8 addr4[ETH_ALEN]; - __le16 data_len; - - /* 802.3 */ - u8 dst_addr[ETH_ALEN]; - u8 src_addr[ETH_ALEN]; - __be16 len; - - /* followed by frame data; max 2304 bytes */ -} __packed; - - -struct hfa384x_rid_hdr -{ - __le16 len; - __le16 rid; -} __packed; - - -/* Macro for converting signal levels (range 27 .. 154) to wireless ext - * dBm value with some accuracy */ -#define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100 - -#define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100 - -struct hfa384x_scan_request { - __le16 channel_list; - __le16 txrate; /* HFA384X_RATES_* */ -} __packed; - -struct hfa384x_hostscan_request { - __le16 channel_list; - __le16 txrate; - __le16 target_ssid_len; - u8 target_ssid[32]; -} __packed; - -struct hfa384x_join_request { - u8 bssid[ETH_ALEN]; - __le16 channel; -} __packed; - -struct hfa384x_info_frame { - __le16 len; - __le16 type; -} __packed; - -struct hfa384x_comm_tallies { - __le16 tx_unicast_frames; - __le16 tx_multicast_frames; - __le16 tx_fragments; - __le16 tx_unicast_octets; - __le16 tx_multicast_octets; - __le16 tx_deferred_transmissions; - __le16 tx_single_retry_frames; - __le16 tx_multiple_retry_frames; - __le16 tx_retry_limit_exceeded; - __le16 tx_discards; - __le16 rx_unicast_frames; - __le16 rx_multicast_frames; - __le16 rx_fragments; - __le16 rx_unicast_octets; - __le16 rx_multicast_octets; - __le16 rx_fcs_errors; - __le16 rx_discards_no_buffer; - __le16 tx_discards_wrong_sa; - __le16 rx_discards_wep_undecryptable; - __le16 rx_message_in_msg_fragments; - __le16 rx_message_in_bad_msg_fragments; -} __packed; - -struct hfa384x_comm_tallies32 { - __le32 tx_unicast_frames; - __le32 tx_multicast_frames; - __le32 tx_fragments; - __le32 tx_unicast_octets; - __le32 tx_multicast_octets; - __le32 tx_deferred_transmissions; - __le32 tx_single_retry_frames; - __le32 tx_multiple_retry_frames; - __le32 tx_retry_limit_exceeded; - __le32 tx_discards; - __le32 rx_unicast_frames; - __le32 rx_multicast_frames; - __le32 rx_fragments; - __le32 rx_unicast_octets; - __le32 rx_multicast_octets; - __le32 rx_fcs_errors; - __le32 rx_discards_no_buffer; - __le32 tx_discards_wrong_sa; - __le32 rx_discards_wep_undecryptable; - __le32 rx_message_in_msg_fragments; - __le32 rx_message_in_bad_msg_fragments; -} __packed; - -struct hfa384x_scan_result_hdr { - __le16 reserved; - __le16 scan_reason; -#define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */ -#define HFA384X_SCAN_HOST_INITIATED 1 -#define HFA384X_SCAN_FIRMWARE_INITIATED 2 -#define HFA384X_SCAN_INQUIRY_FROM_HOST 3 -} __packed; - -#define HFA384X_SCAN_MAX_RESULTS 32 - -struct hfa384x_scan_result { - __le16 chid; - __le16 anl; - __le16 sl; - u8 bssid[ETH_ALEN]; - __le16 beacon_interval; - __le16 capability; - __le16 ssid_len; - u8 ssid[32]; - u8 sup_rates[10]; - __le16 rate; -} __packed; - -struct hfa384x_hostscan_result { - __le16 chid; - __le16 anl; - __le16 sl; - u8 bssid[ETH_ALEN]; - __le16 beacon_interval; - __le16 capability; - __le16 ssid_len; - u8 ssid[32]; - u8 sup_rates[10]; - __le16 rate; - __le16 atim; -} __packed; - -struct comm_tallies_sums { - unsigned int tx_unicast_frames; - unsigned int tx_multicast_frames; - unsigned int tx_fragments; - unsigned int tx_unicast_octets; - unsigned int tx_multicast_octets; - unsigned int tx_deferred_transmissions; - unsigned int tx_single_retry_frames; - unsigned int tx_multiple_retry_frames; - unsigned int tx_retry_limit_exceeded; - unsigned int tx_discards; - unsigned int rx_unicast_frames; - unsigned int rx_multicast_frames; - unsigned int rx_fragments; - unsigned int rx_unicast_octets; - unsigned int rx_multicast_octets; - unsigned int rx_fcs_errors; - unsigned int rx_discards_no_buffer; - unsigned int tx_discards_wrong_sa; - unsigned int rx_discards_wep_undecryptable; - unsigned int rx_message_in_msg_fragments; - unsigned int rx_message_in_bad_msg_fragments; -}; - - -struct hfa384x_regs { - u16 cmd; - u16 evstat; - u16 offset0; - u16 offset1; - u16 swsupport0; -}; - - -#if defined(PRISM2_PCCARD) || defined(PRISM2_PLX) -/* I/O ports for HFA384X Controller access */ -#define HFA384X_CMD_OFF 0x00 -#define HFA384X_PARAM0_OFF 0x02 -#define HFA384X_PARAM1_OFF 0x04 -#define HFA384X_PARAM2_OFF 0x06 -#define HFA384X_STATUS_OFF 0x08 -#define HFA384X_RESP0_OFF 0x0A -#define HFA384X_RESP1_OFF 0x0C -#define HFA384X_RESP2_OFF 0x0E -#define HFA384X_INFOFID_OFF 0x10 -#define HFA384X_CONTROL_OFF 0x14 -#define HFA384X_SELECT0_OFF 0x18 -#define HFA384X_SELECT1_OFF 0x1A -#define HFA384X_OFFSET0_OFF 0x1C -#define HFA384X_OFFSET1_OFF 0x1E -#define HFA384X_RXFID_OFF 0x20 -#define HFA384X_ALLOCFID_OFF 0x22 -#define HFA384X_TXCOMPLFID_OFF 0x24 -#define HFA384X_SWSUPPORT0_OFF 0x28 -#define HFA384X_SWSUPPORT1_OFF 0x2A -#define HFA384X_SWSUPPORT2_OFF 0x2C -#define HFA384X_EVSTAT_OFF 0x30 -#define HFA384X_INTEN_OFF 0x32 -#define HFA384X_EVACK_OFF 0x34 -#define HFA384X_DATA0_OFF 0x36 -#define HFA384X_DATA1_OFF 0x38 -#define HFA384X_AUXPAGE_OFF 0x3A -#define HFA384X_AUXOFFSET_OFF 0x3C -#define HFA384X_AUXDATA_OFF 0x3E -#endif /* PRISM2_PCCARD || PRISM2_PLX */ - -#ifdef PRISM2_PCI -/* Memory addresses for ISL3874 controller access */ -#define HFA384X_CMD_OFF 0x00 -#define HFA384X_PARAM0_OFF 0x04 -#define HFA384X_PARAM1_OFF 0x08 -#define HFA384X_PARAM2_OFF 0x0C -#define HFA384X_STATUS_OFF 0x10 -#define HFA384X_RESP0_OFF 0x14 -#define HFA384X_RESP1_OFF 0x18 -#define HFA384X_RESP2_OFF 0x1C -#define HFA384X_INFOFID_OFF 0x20 -#define HFA384X_CONTROL_OFF 0x28 -#define HFA384X_SELECT0_OFF 0x30 -#define HFA384X_SELECT1_OFF 0x34 -#define HFA384X_OFFSET0_OFF 0x38 -#define HFA384X_OFFSET1_OFF 0x3C -#define HFA384X_RXFID_OFF 0x40 -#define HFA384X_ALLOCFID_OFF 0x44 -#define HFA384X_TXCOMPLFID_OFF 0x48 -#define HFA384X_PCICOR_OFF 0x4C -#define HFA384X_SWSUPPORT0_OFF 0x50 -#define HFA384X_SWSUPPORT1_OFF 0x54 -#define HFA384X_SWSUPPORT2_OFF 0x58 -#define HFA384X_PCIHCR_OFF 0x5C -#define HFA384X_EVSTAT_OFF 0x60 -#define HFA384X_INTEN_OFF 0x64 -#define HFA384X_EVACK_OFF 0x68 -#define HFA384X_DATA0_OFF 0x6C -#define HFA384X_DATA1_OFF 0x70 -#define HFA384X_AUXPAGE_OFF 0x74 -#define HFA384X_AUXOFFSET_OFF 0x78 -#define HFA384X_AUXDATA_OFF 0x7C -#define HFA384X_PCI_M0_ADDRH_OFF 0x80 -#define HFA384X_PCI_M0_ADDRL_OFF 0x84 -#define HFA384X_PCI_M0_LEN_OFF 0x88 -#define HFA384X_PCI_M0_CTL_OFF 0x8C -#define HFA384X_PCI_STATUS_OFF 0x98 -#define HFA384X_PCI_M1_ADDRH_OFF 0xA0 -#define HFA384X_PCI_M1_ADDRL_OFF 0xA4 -#define HFA384X_PCI_M1_LEN_OFF 0xA8 -#define HFA384X_PCI_M1_CTL_OFF 0xAC - -/* PCI bus master control bits (these are undocumented; based on guessing and - * experimenting..) */ -#define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0)) -#define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0)) - -#endif /* PRISM2_PCI */ - - -/* Command codes for CMD reg. */ -#define HFA384X_CMDCODE_INIT 0x00 -#define HFA384X_CMDCODE_ENABLE 0x01 -#define HFA384X_CMDCODE_DISABLE 0x02 -#define HFA384X_CMDCODE_ALLOC 0x0A -#define HFA384X_CMDCODE_TRANSMIT 0x0B -#define HFA384X_CMDCODE_INQUIRE 0x11 -#define HFA384X_CMDCODE_ACCESS 0x21 -#define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8)) -#define HFA384X_CMDCODE_DOWNLOAD 0x22 -#define HFA384X_CMDCODE_READMIF 0x30 -#define HFA384X_CMDCODE_WRITEMIF 0x31 -#define HFA384X_CMDCODE_TEST 0x38 - -#define HFA384X_CMDCODE_MASK 0x3F - -/* Test mode operations */ -#define HFA384X_TEST_CHANGE_CHANNEL 0x08 -#define HFA384X_TEST_MONITOR 0x0B -#define HFA384X_TEST_STOP 0x0F -#define HFA384X_TEST_CFG_BITS 0x15 -#define HFA384X_TEST_CFG_BIT_ALC BIT(3) - -#define HFA384X_CMD_BUSY BIT(15) - -#define HFA384X_CMD_TX_RECLAIM BIT(8) - -#define HFA384X_OFFSET_ERR BIT(14) -#define HFA384X_OFFSET_BUSY BIT(15) - - -/* ProgMode for download command */ -#define HFA384X_PROGMODE_DISABLE 0 -#define HFA384X_PROGMODE_ENABLE_VOLATILE 1 -#define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2 -#define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3 - -#define HFA384X_AUX_MAGIC0 0xfe01 -#define HFA384X_AUX_MAGIC1 0xdc23 -#define HFA384X_AUX_MAGIC2 0xba45 - -#define HFA384X_AUX_PORT_DISABLED 0 -#define HFA384X_AUX_PORT_DISABLE BIT(14) -#define HFA384X_AUX_PORT_ENABLE BIT(15) -#define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15)) -#define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15)) - -#define PRISM2_PDA_SIZE 1024 - - -/* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */ -#define HFA384X_EV_TICK BIT(15) -#define HFA384X_EV_WTERR BIT(14) -#define HFA384X_EV_INFDROP BIT(13) -#ifdef PRISM2_PCI -#define HFA384X_EV_PCI_M1 BIT(9) -#define HFA384X_EV_PCI_M0 BIT(8) -#endif /* PRISM2_PCI */ -#define HFA384X_EV_INFO BIT(7) -#define HFA384X_EV_DTIM BIT(5) -#define HFA384X_EV_CMD BIT(4) -#define HFA384X_EV_ALLOC BIT(3) -#define HFA384X_EV_TXEXC BIT(2) -#define HFA384X_EV_TX BIT(1) -#define HFA384X_EV_RX BIT(0) - - -/* HFA384X Information frames */ -#define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */ -#define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */ -#define HFA384X_INFO_COMMTALLIES 0xF100 -#define HFA384X_INFO_SCANRESULTS 0xF101 -#define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */ -#define HFA384X_INFO_HOSTSCANRESULTS 0xF103 -#define HFA384X_INFO_LINKSTATUS 0xF200 -#define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */ -#define HFA384X_INFO_AUTHREQ 0xF202 /* ? */ -#define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */ -#define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */ - -enum { HFA384X_LINKSTATUS_CONNECTED = 1, - HFA384X_LINKSTATUS_DISCONNECTED = 2, - HFA384X_LINKSTATUS_AP_CHANGE = 3, - HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4, - HFA384X_LINKSTATUS_AP_IN_RANGE = 5, - HFA384X_LINKSTATUS_ASSOC_FAILED = 6 }; - -enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2, - HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0, - HFA384X_PORTTYPE_HOSTAP = 6 }; - -#define HFA384X_RATES_1MBPS BIT(0) -#define HFA384X_RATES_2MBPS BIT(1) -#define HFA384X_RATES_5MBPS BIT(2) -#define HFA384X_RATES_11MBPS BIT(3) - -#define HFA384X_ROAMING_FIRMWARE 1 -#define HFA384X_ROAMING_HOST 2 -#define HFA384X_ROAMING_DISABLED 3 - -#define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0) -#define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1) -#define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4) -#define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7) - -#define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13)) -#define HFA384X_RX_STATUS_PCF BIT(12) -#define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8)) -#define HFA384X_RX_STATUS_UNDECR BIT(1) -#define HFA384X_RX_STATUS_FCSERR BIT(0) - -#define HFA384X_RX_STATUS_GET_MSGTYPE(s) \ -(((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13) -#define HFA384X_RX_STATUS_GET_MACPORT(s) \ -(((s) & HFA384X_RX_STATUS_MACPORT) >> 8) - -enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1, - HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 }; - - -#define HFA384X_TX_CTRL_ALT_RTRY BIT(5) -#define HFA384X_TX_CTRL_802_11 BIT(3) -#define HFA384X_TX_CTRL_802_3 0 -#define HFA384X_TX_CTRL_TX_EX BIT(2) -#define HFA384X_TX_CTRL_TX_OK BIT(1) - -#define HFA384X_TX_STATUS_RETRYERR BIT(0) -#define HFA384X_TX_STATUS_AGEDERR BIT(1) -#define HFA384X_TX_STATUS_DISCON BIT(2) -#define HFA384X_TX_STATUS_FORMERR BIT(3) - -/* HFA3861/3863 (BBP) Control Registers */ -#define HFA386X_CR_TX_CONFIGURE 0x12 /* CR9 */ -#define HFA386X_CR_RX_CONFIGURE 0x14 /* CR10 */ -#define HFA386X_CR_A_D_TEST_MODES2 0x1A /* CR13 */ -#define HFA386X_CR_MANUAL_TX_POWER 0x3E /* CR31 */ -#define HFA386X_CR_MEASURED_TX_POWER 0x74 /* CR58 */ - - -#ifdef __KERNEL__ - -#define PRISM2_TXFID_COUNT 8 -#define PRISM2_DATA_MAXLEN 2304 -#define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame)) -#define PRISM2_TXFID_EMPTY 0xffff -#define PRISM2_TXFID_RESERVED 0xfffe -#define PRISM2_DUMMY_FID 0xffff -#define MAX_SSID_LEN 32 -#define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */ - -#define PRISM2_DUMP_RX_HDR BIT(0) -#define PRISM2_DUMP_TX_HDR BIT(1) -#define PRISM2_DUMP_TXEXC_HDR BIT(2) - -struct hostap_tx_callback_info { - u16 idx; - void (*func)(struct sk_buff *, int ok, void *); - void *data; - struct hostap_tx_callback_info *next; -}; - - -/* IEEE 802.11 requires that STA supports concurrent reception of at least - * three fragmented frames. This define can be increased to support more - * concurrent frames, but it should be noted that each entry can consume about - * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ -#define PRISM2_FRAG_CACHE_LEN 4 - -struct prism2_frag_entry { - unsigned long first_frag_time; - unsigned int seq; - unsigned int last_frag; - struct sk_buff *skb; - u8 src_addr[ETH_ALEN]; - u8 dst_addr[ETH_ALEN]; -}; - - -struct hostap_cmd_queue { - struct list_head list; - wait_queue_head_t compl; - volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type; - void (*callback)(struct net_device *dev, long context, u16 resp0, - u16 res); - long context; - u16 cmd, param0, param1; - u16 resp0, res; - volatile int issued, issuing; - - refcount_t usecnt; - int del_req; -}; - -/* options for hw_shutdown */ -#define HOSTAP_HW_NO_DISABLE BIT(0) -#define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1) - -typedef struct local_info local_info_t; - -struct prism2_helper_functions { - /* these functions are defined in hardware model specific files - * (hostap_{cs,plx,pci}.c */ - int (*card_present)(local_info_t *local); - void (*cor_sreset)(local_info_t *local); - void (*genesis_reset)(local_info_t *local, int hcr); - - /* the following functions are from hostap_hw.c, but they may have some - * hardware model specific code */ - - /* FIX: low-level commands like cmd might disappear at some point to - * make it easier to change them if needed (e.g., cmd would be replaced - * with write_mif/read_mif/testcmd/inquire); at least get_rid and - * set_rid might move to hostap_{cs,plx,pci}.c */ - int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1, - u16 *resp0); - void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs); - int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len, - int exact_len); - int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len); - int (*hw_enable)(struct net_device *dev, int initial); - int (*hw_config)(struct net_device *dev, int initial); - void (*hw_reset)(struct net_device *dev); - void (*hw_shutdown)(struct net_device *dev, int no_disable); - int (*reset_port)(struct net_device *dev); - void (*schedule_reset)(local_info_t *local); - int (*download)(local_info_t *local, - struct prism2_download_param *param); - int (*tx)(struct sk_buff *skb, struct net_device *dev); - int (*set_tim)(struct net_device *dev, int aid, int set); - const struct proc_ops *read_aux_proc_ops; - - int need_tx_headroom; /* number of bytes of headroom needed before - * IEEE 802.11 header */ - enum { HOSTAP_HW_PCCARD, HOSTAP_HW_PLX, HOSTAP_HW_PCI } hw_type; -}; - - -struct prism2_download_data { - u32 dl_cmd; - u32 start_addr; - u32 num_areas; - struct prism2_download_data_area { - u32 addr; /* wlan card address */ - u32 len; - u8 *data; /* allocated data */ - } data[] __counted_by(num_areas); -}; - - -#define HOSTAP_MAX_BSS_COUNT 64 -#define MAX_WPA_IE_LEN 64 - -struct hostap_bss_info { - struct list_head list; - unsigned long last_update; - unsigned int count; - u8 bssid[ETH_ALEN]; - u16 capab_info; - u8 ssid[32]; - size_t ssid_len; - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - u8 rsn_ie[MAX_WPA_IE_LEN]; - size_t rsn_ie_len; - int chan; - int included; -}; - - -/* Per radio private Host AP data - shared by all net devices interfaces used - * by each radio (wlan#, wlan#ap, wlan#sta, WDS). - * ((struct hostap_interface *) netdev_priv(dev))->local points to this - * structure. */ -struct local_info { - struct module *hw_module; - int card_idx; - int dev_enabled; - int master_dev_auto_open; /* was master device opened automatically */ - int num_dev_open; /* number of open devices */ - struct net_device *dev; /* master radio device */ - struct net_device *ddev; /* main data device */ - struct list_head hostap_interfaces; /* Host AP interface list (contains - * struct hostap_interface entries) - */ - rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock - * when removing entries from the list. - * TX and RX paths can use read lock. */ - spinlock_t cmdlock, baplock, lock, irq_init_lock; - struct mutex rid_bap_mtx; - u16 infofid; /* MAC buffer id for info frame */ - /* txfid, intransmitfid, next_txtid, and next_alloc are protected by - * txfidlock */ - spinlock_t txfidlock; - int txfid_len; /* length of allocated TX buffers */ - u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */ - /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if - * corresponding txfid is free for next TX frame */ - u16 intransmitfid[PRISM2_TXFID_COUNT]; - int next_txfid; /* index to the next txfid to be checked for - * availability */ - int next_alloc; /* index to the next intransmitfid to be checked for - * allocation events */ - - /* bitfield for atomic bitops */ -#define HOSTAP_BITS_TRANSMIT 0 -#define HOSTAP_BITS_BAP_TASKLET 1 -#define HOSTAP_BITS_BAP_TASKLET2 2 - unsigned long bits; - - struct ap_data *ap; - - char essid[MAX_SSID_LEN + 1]; - char name[MAX_NAME_LEN + 1]; - int name_set; - u16 channel_mask; /* mask of allowed channels */ - u16 scan_channel_mask; /* mask of channels to be scanned */ - struct comm_tallies_sums comm_tallies; - struct proc_dir_entry *proc; - int iw_mode; /* operating mode (IW_MODE_*) */ - int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS - * 1: IW_MODE_ADHOC is "pseudo IBSS" */ - char bssid[ETH_ALEN]; - int channel; - int beacon_int; - int dtim_period; - int mtu; - int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */ - int fw_tx_rate_control; - u16 tx_rate_control; - u16 basic_rates; - int hw_resetting; - int hw_ready; - int hw_reset_tries; /* how many times reset has been tried */ - int hw_downloading; - int shutdown; - int pri_only; - int no_pri; /* no PRI f/w present */ - int sram_type; /* 8 = x8 SRAM, 16 = x16 SRAM, -1 = unknown */ - - enum { - PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF, - PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN - } txpower_type; - int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */ - - /* command queue for hfa384x_cmd(); protected with cmdlock */ - struct list_head cmd_queue; - /* max_len for cmd_queue; in addition, cmd_callback can use two - * additional entries to prevent sleeping commands from stopping - * transmits */ -#define HOSTAP_CMD_QUEUE_MAX_LEN 16 - int cmd_queue_len; /* number of entries in cmd_queue */ - - /* if card timeout is detected in interrupt context, reset_queue is - * used to schedule card reseting to be done in user context */ - struct work_struct reset_queue; - - /* For scheduling a change of the promiscuous mode RID */ - int is_promisc; - struct work_struct set_multicast_list_queue; - - struct work_struct set_tim_queue; - struct list_head set_tim_list; - spinlock_t set_tim_lock; - - int wds_max_connections; - int wds_connections; -#define HOSTAP_WDS_BROADCAST_RA BIT(0) -#define HOSTAP_WDS_AP_CLIENT BIT(1) -#define HOSTAP_WDS_STANDARD_FRAME BIT(2) - u32 wds_type; - u16 tx_control; /* flags to be used in TX description */ - int manual_retry_count; /* -1 = use f/w default; otherwise retry count - * to be used with all frames */ - - struct iw_statistics wstats; - unsigned long scan_timestamp; /* Time started to scan */ - enum { - PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, - PRISM2_MONITOR_CAPHDR = 2, PRISM2_MONITOR_RADIOTAP = 3 - } monitor_type; - int monitor_allow_fcserr; - - int hostapd; /* whether user space daemon, hostapd, is used for AP - * management */ - int hostapd_sta; /* whether hostapd is used with an extra STA interface - */ - struct net_device *apdev; - struct net_device_stats apdevstats; - - char assoc_ap_addr[ETH_ALEN]; - struct net_device *stadev; - struct net_device_stats stadevstats; - -#define WEP_KEYS 4 -#define WEP_KEY_LEN 13 - struct lib80211_crypt_info crypt_info; - - int open_wep; /* allow unencrypted frames */ - int host_encrypt; - int host_decrypt; - int privacy_invoked; /* force privacy invoked flag even if no keys are - * configured */ - int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working - * in Host AP mode (STA f/w 1.4.9 or newer) */ - int bcrx_sta_key; /* use individual keys to override default keys even - * with RX of broad/multicast frames */ - - struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN]; - unsigned int frag_next_idx; - - int ieee_802_1x; /* is IEEE 802.1X used */ - - int antsel_tx, antsel_rx; - int rts_threshold; /* dot11RTSThreshold */ - int fragm_threshold; /* dot11FragmentationThreshold */ - int auth_algs; /* PRISM2_AUTH_ flags */ - - int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */ - int tallies32; /* 32-bit tallies in use */ - - struct prism2_helper_functions *func; - - u8 *pda; - int fw_ap; -#define PRISM2_FW_VER(major, minor, variant) \ -(((major) << 16) | ((minor) << 8) | variant) - u32 sta_fw_ver; - - /* Tasklets for handling hardware IRQ related operations outside hw IRQ - * handler */ - struct tasklet_struct bap_tasklet; - - struct tasklet_struct info_tasklet; - struct sk_buff_head info_list; /* info frames as skb's for - * info_tasklet */ - - struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks - */ - - struct tasklet_struct rx_tasklet; - struct sk_buff_head rx_list; - - struct tasklet_struct sta_tx_exc_tasklet; - struct sk_buff_head sta_tx_exc_list; - - int host_roaming; - unsigned long last_join_time; /* time of last JoinRequest */ - struct hfa384x_hostscan_result *last_scan_results; - int last_scan_results_count; - enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; - struct work_struct info_queue; - unsigned long pending_info; /* bit field of pending info_queue items */ -#define PRISM2_INFO_PENDING_LINKSTATUS 0 -#define PRISM2_INFO_PENDING_SCANRESULTS 1 - int prev_link_status; /* previous received LinkStatus info */ - int prev_linkstatus_connected; - u8 preferred_ap[ETH_ALEN]; /* use this AP if possible */ - -#ifdef PRISM2_CALLBACK - void *callback_data; /* Can be used in callbacks; e.g., allocate - * on enable event and free on disable event. - * Host AP driver code does not touch this. */ -#endif /* PRISM2_CALLBACK */ - - wait_queue_head_t hostscan_wq; - - /* Passive scan in Host AP mode */ - struct timer_list passive_scan_timer; - int passive_scan_interval; /* in seconds, 0 = disabled */ - int passive_scan_channel; - enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state; - - struct timer_list tick_timer; - unsigned long last_tick_timer; - unsigned int sw_tick_stuck; - - /* commsQuality / dBmCommsQuality data from periodic polling; only - * valid for Managed and Ad-hoc modes */ - unsigned long last_comms_qual_update; - int comms_qual; /* in some odd unit.. */ - int avg_signal; /* in dB (note: negative) */ - int avg_noise; /* in dB (note: negative) */ - struct work_struct comms_qual_update; - - /* RSSI to dBm adjustment (for RX descriptor fields) */ - int rssi_to_dBm; /* subtract from RSSI to get approximate dBm value */ - - /* BSS list / protected by local->lock */ - struct list_head bss_list; - int num_bss_info; - int wpa; /* WPA support enabled */ - int tkip_countermeasures; - int drop_unencrypted; - /* Generic IEEE 802.11 info element to be added to - * ProbeResp/Beacon/(Re)AssocReq */ - u8 *generic_elem; - size_t generic_elem_len; - -#ifdef PRISM2_DOWNLOAD_SUPPORT - /* Persistent volatile download data */ - struct prism2_download_data *dl_pri; - struct prism2_download_data *dl_sec; -#endif /* PRISM2_DOWNLOAD_SUPPORT */ - -#ifdef PRISM2_IO_DEBUG -#define PRISM2_IO_DEBUG_SIZE 10000 - u32 io_debug[PRISM2_IO_DEBUG_SIZE]; - int io_debug_head; - int io_debug_enabled; -#endif /* PRISM2_IO_DEBUG */ - - /* Pointer to hardware model specific (cs,pci,plx) private data. */ - void *hw_priv; -}; - - -/* Per interface private Host AP data - * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta, - * WDS) and netdev_priv(dev) points to this structure. */ -struct hostap_interface { - struct list_head list; /* list entry in Host AP interface list */ - struct net_device *dev; /* pointer to this device */ - struct local_info *local; /* pointer to shared private data */ - struct net_device_stats stats; - struct iw_spy_data spy_data; /* iwspy support */ - struct iw_public_data wireless_data; - - enum { - HOSTAP_INTERFACE_MASTER, - HOSTAP_INTERFACE_MAIN, - HOSTAP_INTERFACE_AP, - HOSTAP_INTERFACE_STA, - HOSTAP_INTERFACE_WDS, - } type; - - union { - struct hostap_interface_wds { - u8 remote_addr[ETH_ALEN]; - } wds; - } u; -}; - - -#define HOSTAP_SKB_TX_DATA_MAGIC 0xf08a36a2 - -/* - * TX meta data - stored in skb->cb buffer, so this must not be increased over - * the 48-byte limit. - * THE PADDING THIS STARTS WITH IS A HORRIBLE HACK THAT SHOULD NOT LIVE - * TO SEE THE DAY. - */ -struct hostap_skb_tx_data { - unsigned int __padding_for_default_qdiscs; - u32 magic; /* HOSTAP_SKB_TX_DATA_MAGIC */ - u8 rate; /* transmit rate */ -#define HOSTAP_TX_FLAGS_WDS BIT(0) -#define HOSTAP_TX_FLAGS_BUFFERED_FRAME BIT(1) -#define HOSTAP_TX_FLAGS_ADD_MOREDATA BIT(2) - u8 flags; /* HOSTAP_TX_FLAGS_* */ - u16 tx_cb_idx; - struct hostap_interface *iface; - unsigned long jiffies; /* queueing timestamp */ - unsigned short ethertype; -}; - - -#ifndef PRISM2_NO_DEBUG - -#define DEBUG_FID BIT(0) -#define DEBUG_PS BIT(1) -#define DEBUG_FLOW BIT(2) -#define DEBUG_AP BIT(3) -#define DEBUG_HW BIT(4) -#define DEBUG_EXTRA BIT(5) -#define DEBUG_EXTRA2 BIT(6) -#define DEBUG_PS2 BIT(7) -#define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA) -#define PDEBUG(n, args...) \ -do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0) -#define PDEBUG2(n, args...) \ -do { if ((n) & DEBUG_MASK) printk(args); } while (0) - -#else /* PRISM2_NO_DEBUG */ - -#define PDEBUG(n, args...) -#define PDEBUG2(n, args...) - -#endif /* PRISM2_NO_DEBUG */ - -enum { BAP0 = 0, BAP1 = 1 }; - -#define PRISM2_IO_DEBUG_CMD_INB 0 -#define PRISM2_IO_DEBUG_CMD_INW 1 -#define PRISM2_IO_DEBUG_CMD_INSW 2 -#define PRISM2_IO_DEBUG_CMD_OUTB 3 -#define PRISM2_IO_DEBUG_CMD_OUTW 4 -#define PRISM2_IO_DEBUG_CMD_OUTSW 5 -#define PRISM2_IO_DEBUG_CMD_ERROR 6 -#define PRISM2_IO_DEBUG_CMD_INTERRUPT 7 - -#ifdef PRISM2_IO_DEBUG - -#define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \ -(((cmd) << 24) | ((reg) << 16) | value) - -static inline void prism2_io_debug_add(struct net_device *dev, int cmd, - int reg, int value) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - - if (!local->io_debug_enabled) - return; - - local->io_debug[local->io_debug_head] = jiffies & 0xffffffff; - if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) - local->io_debug_head = 0; - local->io_debug[local->io_debug_head] = - PRISM2_IO_DEBUG_ENTRY(cmd, reg, value); - if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) - local->io_debug_head = 0; -} - - -static inline void prism2_io_debug_error(struct net_device *dev, int err) -{ - struct hostap_interface *iface = netdev_priv(dev); - local_info_t *local = iface->local; - unsigned long flags; - - if (!local->io_debug_enabled) - return; - - spin_lock_irqsave(&local->lock, flags); - prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err); - if (local->io_debug_enabled == 1) { - local->io_debug_enabled = 0; - printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name); - } - spin_unlock_irqrestore(&local->lock, flags); -} - -#else /* PRISM2_IO_DEBUG */ - -static inline void prism2_io_debug_add(struct net_device *dev, int cmd, - int reg, int value) -{ -} - -static inline void prism2_io_debug_error(struct net_device *dev, int err) -{ -} - -#endif /* PRISM2_IO_DEBUG */ - - -#ifdef PRISM2_CALLBACK -enum { - /* Called when card is enabled */ - PRISM2_CALLBACK_ENABLE, - - /* Called when card is disabled */ - PRISM2_CALLBACK_DISABLE, - - /* Called when RX/TX starts/ends */ - PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END, - PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END -}; -void prism2_callback(local_info_t *local, int event); -#else /* PRISM2_CALLBACK */ -#define prism2_callback(d, e) do { } while (0) -#endif /* PRISM2_CALLBACK */ - -#endif /* __KERNEL__ */ - -#endif /* HOSTAP_WLAN_H */ diff --git a/drivers/net/wireless/intersil/orinoco/Kconfig b/drivers/net/wireless/intersil/orinoco/Kconfig deleted file mode 100644 index f62730aa7b..0000000000 --- a/drivers/net/wireless/intersil/orinoco/Kconfig +++ /dev/null @@ -1,143 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config HERMES - tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" - depends on (PPC_PMAC || PCI || PCMCIA) - depends on CFG80211 - select CFG80211_WEXT_EXPORT - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select FW_LOADER - select CRYPTO - select CRYPTO_MICHAEL_MIC - help - A driver for 802.11b wireless cards based on the "Hermes" or - Intersil HFA384x (Prism 2) MAC controller. This includes the vast - majority of the PCMCIA 802.11b cards (which are nearly all rebadges) - - except for the Cisco/Aironet cards. Cards supported include the - Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco, - Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya, - IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear - MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel - IPW2011, and Symbol Spectrum24 High Rate amongst others. - - This option includes the guts of the driver, but in order to - actually use a card you will also need to enable support for PCMCIA - Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below. - - You will also very likely also need the Wireless Tools in order to - configure your card and that /etc/pcmcia/wireless.opts works : - <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html> - -config HERMES_PRISM - bool "Support Prism 2/2.5 chipset" - depends on HERMES - help - - Say Y to enable support for Prism 2 and 2.5 chipsets. These - chipsets are better handled by the hostap driver. This driver - would not support WPA or firmware download for Prism chipset. - - If you are not sure, say N. - -config HERMES_CACHE_FW_ON_INIT - bool "Cache Hermes firmware on driver initialisation" - depends on HERMES - default y - help - Say Y to cache any firmware required by the Hermes drivers - on startup. The firmware will remain cached until the - driver is unloaded. The cache uses 64K of RAM. - - Otherwise load the firmware from userspace as required. In - this case the driver should be unloaded and restarted - whenever the firmware is changed. - - If you are not sure, say Y. - -config APPLE_AIRPORT - tristate "Apple Airport support (built-in)" - depends on PPC_PMAC && HERMES - help - Say Y here to support the Airport 802.11b wireless Ethernet hardware - built into the Macintosh iBook and other recent PowerPC-based - Macintosh machines. This is essentially a Lucent Orinoco card with - a non-standard interface. - - This driver does not support the Airport Extreme (802.11b/g). Use - the BCM43xx driver for Airport Extreme cards. - -config PLX_HERMES - tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in PLX9052 based PCI adaptors. These - adaptors are not a full PCMCIA controller but act as a more limited - PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that - 802.11b PCMCIA cards can be used in desktop machines. The Netgear - MA301 is such an adaptor. - -config TMD_HERMES - tristate "Hermes in TMD7160 based PCI adaptor support" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in TMD7160 based PCI adaptors. These - adaptors are not a full PCMCIA controller but act as a more limited - PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that - 802.11b PCMCIA cards can be used in desktop machines. - -config NORTEL_HERMES - tristate "Nortel emobility PCI adaptor support" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in Nortel emobility PCI adaptors. These - adaptors are not full PCMCIA controllers, but act as a more limited - PCI <-> PCMCIA bridge. - -config PCI_HERMES - tristate "Prism 2.5 PCI 802.11b adaptor support" - depends on PCI && HERMES && HERMES_PRISM - help - Enable support for PCI and mini-PCI 802.11b wireless NICs based on - the Prism 2.5 chipset. These are true PCI cards, not the 802.11b - PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also - common. Some of the built-in wireless adaptors in laptops are of - this variety. - -config PCMCIA_HERMES - tristate "Hermes PCMCIA card support" - depends on PCMCIA && HERMES && HAS_IOPORT_MAP - help - A driver for "Hermes" chipset based PCMCIA wireless adaptors, such - as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and - others). It should also be usable on various Prism II based cards - such as the Linksys, D-Link and Farallon Skyline. It should also - work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN. - - You will very likely need the Wireless Tools in order to - configure your card and that /etc/pcmcia/wireless.opts works: - <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. - -config PCMCIA_SPECTRUM - tristate "Symbol Spectrum24 Trilogy PCMCIA card support" - depends on PCMCIA && HERMES && HAS_IOPORT_MAP - help - - This is a driver for 802.11b cards using RAM-loadable Symbol - firmware, such as Symbol Wireless Networker LA4100, CompactFlash - cards by Socket Communications and Intel PRO/Wireless 2011B. - - This driver requires firmware download on startup. Utilities - for downloading Symbol firmware are available at - <http://sourceforge.net/projects/orinoco/> - -config ORINOCO_USB - tristate "Agere Orinoco USB support" - depends on USB && HERMES - select FW_LOADER - help - This driver is for USB versions of the Agere Orinoco card. diff --git a/drivers/net/wireless/intersil/orinoco/Makefile b/drivers/net/wireless/intersil/orinoco/Makefile deleted file mode 100644 index 0c29c56c88..0000000000 --- a/drivers/net/wireless/intersil/orinoco/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the orinoco wireless device drivers. -# -orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o - -obj-$(CONFIG_HERMES) += orinoco.o -obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o -obj-$(CONFIG_APPLE_AIRPORT) += airport.o -obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o -obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o -obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o -obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o -obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o -obj-$(CONFIG_ORINOCO_USB) += orinoco_usb.o diff --git a/drivers/net/wireless/intersil/orinoco/airport.c b/drivers/net/wireless/intersil/orinoco/airport.c deleted file mode 100644 index 45ac00fdaf..0000000000 --- a/drivers/net/wireless/intersil/orinoco/airport.c +++ /dev/null @@ -1,268 +0,0 @@ -/* airport.c - * - * A driver for "Hermes" chipset based Apple Airport wireless - * card. - * - * Copyright notice & release notes in file main.c - * - * Note specific to airport stub: - * - * 0.05 : first version of the new split driver - * 0.06 : fix possible hang on powerup, add sleep support - */ - -#define DRIVER_NAME "airport" -#define PFX DRIVER_NAME ": " - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/mod_devicetable.h> -#include <asm/pmac_feature.h> - -#include "orinoco.h" - -#define AIRPORT_IO_LEN (0x1000) /* one page */ - -struct airport { - struct macio_dev *mdev; - void __iomem *vaddr; - unsigned int irq; - int irq_requested; - int ndev_registered; -}; - -static int -airport_suspend(struct macio_dev *mdev, pm_message_t state) -{ - struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct net_device *dev = priv->ndev; - struct airport *card = priv->card; - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name); - - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n", - dev->name); - return 0; - } - - orinoco_down(priv); - orinoco_unlock(priv, &flags); - - disable_irq(card->irq); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 0); - - return 0; -} - -static int -airport_resume(struct macio_dev *mdev) -{ - struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct net_device *dev = priv->ndev; - struct airport *card = priv->card; - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 1); - msleep(200); - - enable_irq(card->irq); - - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - err = orinoco_up(priv); - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - return err; -} - -static int -airport_detach(struct macio_dev *mdev) -{ - struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct airport *card = priv->card; - - if (card->ndev_registered) - orinoco_if_del(priv); - card->ndev_registered = 0; - - if (card->irq_requested) - free_irq(card->irq, priv); - card->irq_requested = 0; - - if (card->vaddr) - iounmap(card->vaddr); - card->vaddr = NULL; - - macio_release_resource(mdev, 0); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 0); - ssleep(1); - - macio_set_drvdata(mdev, NULL); - free_orinocodev(priv); - - return 0; -} - -static int airport_hard_reset(struct orinoco_private *priv) -{ - /* It would be nice to power cycle the Airport for a real hard - * reset, but for some reason although it appears to - * re-initialize properly, it falls in a screaming heap - * shortly afterwards. */ -#if 0 - struct airport *card = priv->card; - - /* Vitally important. If we don't do this it seems we get an - * interrupt somewhere during the power cycle, since - * hw_unavailable is already set it doesn't get ACKed, we get - * into an interrupt loop and the PMU decides to turn us - * off. */ - disable_irq(card->irq); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(card->mdev), 0, 0); - ssleep(1); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(card->mdev), 0, 1); - ssleep(1); - - enable_irq(card->irq); - ssleep(1); -#endif - - return 0; -} - -static int -airport_attach(struct macio_dev *mdev, const struct of_device_id *match) -{ - struct orinoco_private *priv; - struct airport *card; - unsigned long phys_addr; - struct hermes *hw; - - if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { - printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n"); - return -ENODEV; - } - - /* Allocate space for private device-specific data */ - priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, - airport_hard_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - return -ENODEV; - } - card = priv->card; - - hw = &priv->hw; - card->mdev = mdev; - - if (macio_request_resource(mdev, 0, DRIVER_NAME)) { - printk(KERN_ERR PFX "can't request IO resource !\n"); - free_orinocodev(priv); - return -EBUSY; - } - - macio_set_drvdata(mdev, priv); - - /* Setup interrupts & base address */ - card->irq = macio_irq(mdev, 0); - phys_addr = macio_resource_start(mdev, 0); /* Physical address */ - printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); - card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); - if (!card->vaddr) { - printk(KERN_ERR PFX "ioremap() failed\n"); - goto failed; - } - - hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING); - - /* Power up card */ - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, - macio_get_of_node(mdev), 0, 1); - ssleep(1); - - /* Reset it before we get the interrupt */ - hw->ops->init(hw); - - if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) { - printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq); - goto failed; - } - card->irq_requested = 1; - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto failed; - } - - /* Register an interface with the stack */ - if (orinoco_if_add(priv, phys_addr, card->irq, NULL) != 0) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto failed; - } - card->ndev_registered = 1; - return 0; - failed: - airport_detach(mdev); - return -ENODEV; -} /* airport_attach */ - - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; -MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); -MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); -MODULE_LICENSE("Dual MPL/GPL"); - -static const struct of_device_id airport_match[] = { - { - .name = "radio", - }, - {}, -}; - -MODULE_DEVICE_TABLE(of, airport_match); - -static struct macio_driver airport_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = airport_match, - }, - .probe = airport_attach, - .remove = airport_detach, - .suspend = airport_suspend, - .resume = airport_resume, -}; - -static int __init -init_airport(void) -{ - printk(KERN_DEBUG "%s\n", version); - - return macio_register_driver(&airport_driver); -} - -static void __exit -exit_airport(void) -{ - macio_unregister_driver(&airport_driver); -} - -module_init(init_airport); -module_exit(exit_airport); diff --git a/drivers/net/wireless/intersil/orinoco/cfg.c b/drivers/net/wireless/intersil/orinoco/cfg.c deleted file mode 100644 index b2d5ec8634..0000000000 --- a/drivers/net/wireless/intersil/orinoco/cfg.c +++ /dev/null @@ -1,291 +0,0 @@ -/* cfg80211 support - * - * See copyright notice in main.c - */ -#include <linux/ieee80211.h> -#include <net/cfg80211.h> -#include "hw.h" -#include "main.h" -#include "orinoco.h" - -#include "cfg.h" - -/* Supported bitrates. Must agree with hw.c */ -static struct ieee80211_rate orinoco_rates[] = { - { .bitrate = 10 }, - { .bitrate = 20 }, - { .bitrate = 55 }, - { .bitrate = 110 }, -}; - -static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid; - -/* Called after orinoco_private is allocated. */ -void orinoco_wiphy_init(struct wiphy *wiphy) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - - wiphy->privid = orinoco_wiphy_privid; - - set_wiphy_dev(wiphy, priv->dev); -} - -/* Called after firmware is initialised */ -int orinoco_wiphy_register(struct wiphy *wiphy) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int i, channels = 0; - - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) - wiphy->max_scan_ssids = 1; - else - wiphy->max_scan_ssids = 0; - - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - - /* TODO: should we set if we only have demo ad-hoc? - * (priv->has_port3) - */ - if (priv->has_ibss) - wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); - - if (!priv->broken_monitor || force_monitor) - wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); - - priv->band.bitrates = orinoco_rates; - priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates); - - /* Only support channels allowed by the card EEPROM */ - for (i = 0; i < NUM_CHANNELS; i++) { - if (priv->channel_mask & (1 << i)) { - priv->channels[i].center_freq = - ieee80211_channel_to_frequency(i + 1, - NL80211_BAND_2GHZ); - channels++; - } - } - priv->band.channels = priv->channels; - priv->band.n_channels = channels; - - wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - - i = 0; - if (priv->has_wep) { - priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40; - i++; - - if (priv->has_big_wep) { - priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104; - i++; - } - } - if (priv->has_wpa) { - priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP; - i++; - } - wiphy->cipher_suites = priv->cipher_suites; - wiphy->n_cipher_suites = i; - - wiphy->rts_threshold = priv->rts_thresh; - if (!priv->has_mwo) - wiphy->frag_threshold = priv->frag_thresh + 1; - wiphy->retry_short = priv->short_retry_limit; - wiphy->retry_long = priv->long_retry_limit; - - return wiphy_register(wiphy); -} - -static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, - enum nl80211_iftype type, - struct vif_params *params) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int err = 0; - unsigned long lock; - - if (orinoco_lock(priv, &lock) != 0) - return -EBUSY; - - switch (type) { - case NL80211_IFTYPE_ADHOC: - if (!priv->has_ibss && !priv->has_port3) - err = -EINVAL; - break; - - case NL80211_IFTYPE_STATION: - break; - - case NL80211_IFTYPE_MONITOR: - if (priv->broken_monitor && !force_monitor) { - wiphy_warn(wiphy, - "Monitor mode support is buggy in this firmware, not enabling\n"); - err = -EINVAL; - } - break; - - default: - err = -EINVAL; - } - - if (!err) { - priv->iw_mode = type; - set_port_type(priv); - err = orinoco_commit(priv); - } - - orinoco_unlock(priv, &lock); - - return err; -} - -static int orinoco_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int err; - - if (!request) - return -EINVAL; - - if (priv->scan_request && priv->scan_request != request) - return -EBUSY; - - priv->scan_request = request; - - err = orinoco_hw_trigger_scan(priv, request->ssids); - /* On error the we aren't processing the request */ - if (err) - priv->scan_request = NULL; - - return err; -} - -static int orinoco_set_monitor_channel(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int err = 0; - unsigned long flags; - int channel; - - if (!chandef->chan) - return -EINVAL; - - if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) - return -EINVAL; - - if (chandef->chan->band != NL80211_BAND_2GHZ) - return -EINVAL; - - channel = ieee80211_frequency_to_channel(chandef->chan->center_freq); - - if ((channel < 1) || (channel > NUM_CHANNELS) || - !(priv->channel_mask & (1 << (channel - 1)))) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->channel = channel; - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - /* Fast channel change - no commit if successful */ - struct hermes *hw = &priv->hw; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_SET_CHANNEL, - channel, NULL); - } - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct orinoco_private *priv = wiphy_priv(wiphy); - int frag_value = -1; - int rts_value = -1; - int err = 0; - - if (changed & WIPHY_PARAM_RETRY_SHORT) { - /* Setting short retry not supported */ - err = -EINVAL; - } - - if (changed & WIPHY_PARAM_RETRY_LONG) { - /* Setting long retry not supported */ - err = -EINVAL; - } - - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { - /* Set fragmentation */ - if (priv->has_mwo) { - if (wiphy->frag_threshold == -1) - frag_value = 0; - else { - printk(KERN_WARNING "%s: Fixed fragmentation " - "is not supported on this firmware. " - "Using MWO robust instead.\n", - priv->ndev->name); - frag_value = 1; - } - } else { - if (wiphy->frag_threshold == -1) - frag_value = 2346; - else if ((wiphy->frag_threshold < 257) || - (wiphy->frag_threshold > 2347)) - err = -EINVAL; - else - /* cfg80211 value is 257-2347 (odd only) - * orinoco rid has range 256-2346 (even only) */ - frag_value = wiphy->frag_threshold & ~0x1; - } - } - - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - /* Set RTS. - * - * Prism documentation suggests default of 2432, - * and a range of 0-3000. - * - * Current implementation uses 2347 as the default and - * the upper limit. - */ - - if (wiphy->rts_threshold == -1) - rts_value = 2347; - else if (wiphy->rts_threshold > 2347) - err = -EINVAL; - else - rts_value = wiphy->rts_threshold; - } - - if (!err) { - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (frag_value >= 0) { - if (priv->has_mwo) - priv->mwo_robust = frag_value; - else - priv->frag_thresh = frag_value; - } - if (rts_value >= 0) - priv->rts_thresh = rts_value; - - err = orinoco_commit(priv); - - orinoco_unlock(priv, &flags); - } - - return err; -} - -const struct cfg80211_ops orinoco_cfg_ops = { - .change_virtual_intf = orinoco_change_vif, - .set_monitor_channel = orinoco_set_monitor_channel, - .scan = orinoco_scan, - .set_wiphy_params = orinoco_set_wiphy_params, -}; diff --git a/drivers/net/wireless/intersil/orinoco/cfg.h b/drivers/net/wireless/intersil/orinoco/cfg.h deleted file mode 100644 index 3ddc96a06c..0000000000 --- a/drivers/net/wireless/intersil/orinoco/cfg.h +++ /dev/null @@ -1,15 +0,0 @@ -/* cfg80211 support. - * - * See copyright notice in main.c - */ -#ifndef ORINOCO_CFG_H -#define ORINOCO_CFG_H - -#include <net/cfg80211.h> - -extern const struct cfg80211_ops orinoco_cfg_ops; - -void orinoco_wiphy_init(struct wiphy *wiphy); -int orinoco_wiphy_register(struct wiphy *wiphy); - -#endif /* ORINOCO_CFG_H */ diff --git a/drivers/net/wireless/intersil/orinoco/fw.c b/drivers/net/wireless/intersil/orinoco/fw.c deleted file mode 100644 index 015af78288..0000000000 --- a/drivers/net/wireless/intersil/orinoco/fw.c +++ /dev/null @@ -1,387 +0,0 @@ -/* Firmware file reading and download helpers - * - * See copyright notice in main.c - */ -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/firmware.h> -#include <linux/device.h> -#include <linux/module.h> - -#include "hermes.h" -#include "hermes_dld.h" -#include "orinoco.h" - -#include "fw.h" - -/* End markers (for Symbol firmware only) */ -#define TEXT_END 0x1A /* End of text header */ - -struct fw_info { - char *pri_fw; - char *sta_fw; - char *ap_fw; - u32 pda_addr; - u16 pda_size; -}; - -static const struct fw_info orinoco_fw[] = { - { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, - { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, - { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } -}; -MODULE_FIRMWARE("agere_sta_fw.bin"); -MODULE_FIRMWARE("agere_ap_fw.bin"); -MODULE_FIRMWARE("prism_sta_fw.bin"); -MODULE_FIRMWARE("prism_ap_fw.bin"); -MODULE_FIRMWARE("symbol_sp24t_prim_fw"); -MODULE_FIRMWARE("symbol_sp24t_sec_fw"); - -/* Structure used to access fields in FW - * Make sure LE decoding macros are used - */ -struct orinoco_fw_header { - char hdr_vers[6]; /* ASCII string for header version */ - __le16 headersize; /* Total length of header */ - __le32 entry_point; /* NIC entry point */ - __le32 blocks; /* Number of blocks to program */ - __le32 block_offset; /* Offset of block data from eof header */ - __le32 pdr_offset; /* Offset to PDR data from eof header */ - __le32 pri_offset; /* Offset to primary plug data */ - __le32 compat_offset; /* Offset to compatibility data*/ - char signature[]; /* FW signature length headersize-20 */ -} __packed; - -/* Check the range of various header entries. Return a pointer to a - * description of the problem, or NULL if everything checks out. */ -static const char *validate_fw(const struct orinoco_fw_header *hdr, size_t len) -{ - u16 hdrsize; - - if (len < sizeof(*hdr)) - return "image too small"; - if (memcmp(hdr->hdr_vers, "HFW", 3) != 0) - return "format not recognised"; - - hdrsize = le16_to_cpu(hdr->headersize); - if (hdrsize > len) - return "bad headersize"; - if ((hdrsize + le32_to_cpu(hdr->block_offset)) > len) - return "bad block offset"; - if ((hdrsize + le32_to_cpu(hdr->pdr_offset)) > len) - return "bad PDR offset"; - if ((hdrsize + le32_to_cpu(hdr->pri_offset)) > len) - return "bad PRI offset"; - if ((hdrsize + le32_to_cpu(hdr->compat_offset)) > len) - return "bad compat offset"; - - /* TODO: consider adding a checksum or CRC to the firmware format */ - return NULL; -} - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) -static inline const struct firmware * -orinoco_cached_fw_get(struct orinoco_private *priv, bool primary) -{ - if (primary) - return priv->cached_pri_fw; - else - return priv->cached_fw; -} -#else -#define orinoco_cached_fw_get(priv, primary) (NULL) -#endif - -/* Download either STA or AP firmware into the card. */ -static int -orinoco_dl_firmware(struct orinoco_private *priv, - const struct fw_info *fw, - int ap) -{ - /* Plug Data Area (PDA) */ - __le16 *pda; - - struct hermes *hw = &priv->hw; - const struct firmware *fw_entry; - const struct orinoco_fw_header *hdr; - const unsigned char *first_block; - const void *end; - const char *firmware; - const char *fw_err; - struct device *dev = priv->dev; - int err = 0; - - pda = kzalloc(fw->pda_size, GFP_KERNEL); - if (!pda) - return -ENOMEM; - - if (ap) - firmware = fw->ap_fw; - else - firmware = fw->sta_fw; - - dev_dbg(dev, "Attempting to download firmware %s\n", firmware); - - /* Read current plug data */ - err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size); - dev_dbg(dev, "Read PDA returned %d\n", err); - if (err) - goto free; - - if (!orinoco_cached_fw_get(priv, false)) { - err = request_firmware(&fw_entry, firmware, priv->dev); - - if (err) { - dev_err(dev, "Cannot find firmware %s\n", firmware); - err = -ENOENT; - goto free; - } - } else - fw_entry = orinoco_cached_fw_get(priv, false); - - hdr = (const struct orinoco_fw_header *) fw_entry->data; - - fw_err = validate_fw(hdr, fw_entry->size); - if (fw_err) { - dev_warn(dev, "Invalid firmware image detected (%s). " - "Aborting download\n", fw_err); - err = -EINVAL; - goto abort; - } - - /* Enable aux port to allow programming */ - err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point)); - dev_dbg(dev, "Program init returned %d\n", err); - if (err != 0) - goto abort; - - /* Program data */ - first_block = (fw_entry->data + - le16_to_cpu(hdr->headersize) + - le32_to_cpu(hdr->block_offset)); - end = fw_entry->data + fw_entry->size; - - err = hermes_program(hw, first_block, end); - dev_dbg(dev, "Program returned %d\n", err); - if (err != 0) - goto abort; - - /* Update production data */ - first_block = (fw_entry->data + - le16_to_cpu(hdr->headersize) + - le32_to_cpu(hdr->pdr_offset)); - - err = hermes_apply_pda_with_defaults(hw, first_block, end, pda, - &pda[fw->pda_size / sizeof(*pda)]); - dev_dbg(dev, "Apply PDA returned %d\n", err); - if (err) - goto abort; - - /* Tell card we've finished */ - err = hw->ops->program_end(hw); - dev_dbg(dev, "Program end returned %d\n", err); - if (err != 0) - goto abort; - - /* Check if we're running */ - dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw)); - -abort: - /* If we requested the firmware, release it. */ - if (!orinoco_cached_fw_get(priv, false)) - release_firmware(fw_entry); - -free: - kfree(pda); - return err; -} - -/* - * Process a firmware image - stop the card, load the firmware, reset - * the card and make sure it responds. For the secondary firmware take - * care of the PDA - read it and then write it on top of the firmware. - */ -static int -symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, - const unsigned char *image, const void *end, - int secondary) -{ - struct hermes *hw = &priv->hw; - int ret = 0; - const unsigned char *ptr; - const unsigned char *first_block; - - /* Plug Data Area (PDA) */ - __le16 *pda = NULL; - - /* Binary block begins after the 0x1A marker */ - ptr = image; - while (*ptr++ != TEXT_END); - first_block = ptr; - - /* Read the PDA from EEPROM */ - if (secondary) { - pda = kzalloc(fw->pda_size, GFP_KERNEL); - if (!pda) - return -ENOMEM; - - ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size); - if (ret) - goto free; - } - - /* Stop the firmware, so that it can be safely rewritten */ - if (priv->stop_fw) { - ret = priv->stop_fw(priv, 1); - if (ret) - goto free; - } - - /* Program the adapter with new firmware */ - ret = hermes_program(hw, first_block, end); - if (ret) - goto free; - - /* Write the PDA to the adapter */ - if (secondary) { - size_t len = hermes_blocks_length(first_block, end); - ptr = first_block + len; - ret = hermes_apply_pda(hw, ptr, end, pda, - &pda[fw->pda_size / sizeof(*pda)]); - kfree(pda); - if (ret) - return ret; - } - - /* Run the firmware */ - if (priv->stop_fw) { - ret = priv->stop_fw(priv, 0); - if (ret) - return ret; - } - - /* Reset hermes chip and make sure it responds */ - ret = hw->ops->init(hw); - - /* hermes_reset() should return 0 with the secondary firmware */ - if (secondary && ret != 0) - return -ENODEV; - - /* And this should work with any firmware */ - if (!hermes_present(hw)) - return -ENODEV; - - return 0; - -free: - kfree(pda); - return ret; -} - - -/* - * Download the firmware into the card, this also does a PCMCIA soft - * reset on the card, to make sure it's in a sane state. - */ -static int -symbol_dl_firmware(struct orinoco_private *priv, - const struct fw_info *fw) -{ - struct device *dev = priv->dev; - int ret; - const struct firmware *fw_entry; - - if (!orinoco_cached_fw_get(priv, true)) { - if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { - dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw); - return -ENOENT; - } - } else - fw_entry = orinoco_cached_fw_get(priv, true); - - /* Load primary firmware */ - ret = symbol_dl_image(priv, fw, fw_entry->data, - fw_entry->data + fw_entry->size, 0); - - if (!orinoco_cached_fw_get(priv, true)) - release_firmware(fw_entry); - if (ret) { - dev_err(dev, "Primary firmware download failed\n"); - return ret; - } - - if (!orinoco_cached_fw_get(priv, false)) { - if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { - dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw); - return -ENOENT; - } - } else - fw_entry = orinoco_cached_fw_get(priv, false); - - /* Load secondary firmware */ - ret = symbol_dl_image(priv, fw, fw_entry->data, - fw_entry->data + fw_entry->size, 1); - if (!orinoco_cached_fw_get(priv, false)) - release_firmware(fw_entry); - if (ret) - dev_err(dev, "Secondary firmware download failed\n"); - - return ret; -} - -int orinoco_download(struct orinoco_private *priv) -{ - int err = 0; - /* Reload firmware */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* case FIRMWARE_TYPE_INTERSIL: */ - err = orinoco_dl_firmware(priv, - &orinoco_fw[priv->firmware_type], 0); - break; - - case FIRMWARE_TYPE_SYMBOL: - err = symbol_dl_firmware(priv, - &orinoco_fw[priv->firmware_type]); - break; - case FIRMWARE_TYPE_INTERSIL: - break; - } - /* TODO: if we fail we probably need to reinitialise - * the driver */ - - return err; -} - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) -void orinoco_cache_fw(struct orinoco_private *priv, int ap) -{ - const struct firmware *fw_entry = NULL; - const char *pri_fw; - const char *fw; - - pri_fw = orinoco_fw[priv->firmware_type].pri_fw; - if (ap) - fw = orinoco_fw[priv->firmware_type].ap_fw; - else - fw = orinoco_fw[priv->firmware_type].sta_fw; - - if (pri_fw) { - if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0) - priv->cached_pri_fw = fw_entry; - } - - if (fw) { - if (request_firmware(&fw_entry, fw, priv->dev) == 0) - priv->cached_fw = fw_entry; - } -} - -void orinoco_uncache_fw(struct orinoco_private *priv) -{ - release_firmware(priv->cached_pri_fw); - release_firmware(priv->cached_fw); - priv->cached_pri_fw = NULL; - priv->cached_fw = NULL; -} -#endif diff --git a/drivers/net/wireless/intersil/orinoco/fw.h b/drivers/net/wireless/intersil/orinoco/fw.h deleted file mode 100644 index aca63e3c4b..0000000000 --- a/drivers/net/wireless/intersil/orinoco/fw.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Firmware file reading and download helpers - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_FW_H_ -#define _ORINOCO_FW_H_ - -/* Forward declations */ -struct orinoco_private; - -int orinoco_download(struct orinoco_private *priv); - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) -void orinoco_cache_fw(struct orinoco_private *priv, int ap); -void orinoco_uncache_fw(struct orinoco_private *priv); -#else -#define orinoco_cache_fw(priv, ap) do { } while (0) -#define orinoco_uncache_fw(priv) do { } while (0) -#endif - -#endif /* _ORINOCO_FW_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/hermes.c b/drivers/net/wireless/intersil/orinoco/hermes.c deleted file mode 100644 index 4888286727..0000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes.c +++ /dev/null @@ -1,778 +0,0 @@ -/* hermes.c - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no - * particular order). - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia. - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#include <linux/net.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> - -#include "hermes.h" - -/* These are maximum timeouts. Most often, card wil react much faster */ -#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ -#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ -#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */ -#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ - -/* - * AUX port access. To unlock the AUX port write the access keys to the - * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL - * register. Then read it and make sure it's HERMES_AUX_ENABLED. - */ -#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ -#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ -#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ -#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */ - -#define HERMES_AUX_PW0 0xFE01 -#define HERMES_AUX_PW1 0xDC23 -#define HERMES_AUX_PW2 0xBA45 - -/* HERMES_CMD_DOWNLD */ -#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD) - -/* - * Debugging helpers - */ - -#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \ - printk(stuff); } while (0) - -#undef HERMES_DEBUG -#ifdef HERMES_DEBUG - -#define DEBUG(lvl, stuff...) if ((lvl) <= HERMES_DEBUG) DMSG(stuff) - -#else /* ! HERMES_DEBUG */ - -#define DEBUG(lvl, stuff...) do { } while (0) - -#endif /* ! HERMES_DEBUG */ - -static const struct hermes_ops hermes_ops_local; - -/* - * Internal functions - */ - -/* Issue a command to the chip. Waiting for it to complete is the caller's - problem. - - Returns -EBUSY if the command register is busy, 0 on success. - - Callable from any context. -*/ -static int hermes_issue_cmd(struct hermes *hw, u16 cmd, u16 param0, - u16 param1, u16 param2) -{ - int k = CMD_BUSY_TIMEOUT; - u16 reg; - - /* First wait for the command register to unbusy */ - reg = hermes_read_regn(hw, CMD); - while ((reg & HERMES_CMD_BUSY) && k) { - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - if (reg & HERMES_CMD_BUSY) - return -EBUSY; - - hermes_write_regn(hw, PARAM2, param2); - hermes_write_regn(hw, PARAM1, param1); - hermes_write_regn(hw, PARAM0, param0); - hermes_write_regn(hw, CMD, cmd); - - return 0; -} - -/* - * Function definitions - */ - -/* For doing cmds that wipe the magic constant in SWSUPPORT0 */ -static int hermes_doicmd_wait(struct hermes *hw, u16 cmd, - u16 parm0, u16 parm1, u16 parm2, - struct hermes_response *resp) -{ - int err = 0; - int k; - u16 status, reg; - - err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_INIT_TIMEOUT; - while ((!(reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - - if (!hermes_present(hw)) { - DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (!(reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %p: " - "Timeout waiting for card to reset (reg=0x%04x)!\n", - hw->iobase, reg); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - if (resp) { - resp->status = status; - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - } - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - if (status & HERMES_STATUS_RESULT) - err = -EIO; -out: - return err; -} - -void hermes_struct_init(struct hermes *hw, void __iomem *address, - int reg_spacing) -{ - hw->iobase = address; - hw->reg_spacing = reg_spacing; - hw->inten = 0x0; - hw->eeprom_pda = false; - hw->ops = &hermes_ops_local; -} -EXPORT_SYMBOL(hermes_struct_init); - -static int hermes_init(struct hermes *hw) -{ - u16 reg; - int err = 0; - int k; - - /* We don't want to be interrupted while resetting the chipset */ - hw->inten = 0x0; - hermes_write_regn(hw, INTEN, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - /* Normally it's a "can't happen" for the command register to - be busy when we go to issue a command because we are - serializing all commands. However we want to have some - chance of resetting the card even if it gets into a stupid - state, so we actually wait to see if the command register - will unbusy itself here. */ - k = CMD_BUSY_TIMEOUT; - reg = hermes_read_regn(hw, CMD); - while (k && (reg & HERMES_CMD_BUSY)) { - if (reg == 0xffff) /* Special case - the card has probably been - removed, so don't wait for the timeout */ - return -ENODEV; - - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* No need to explicitly handle the timeout - if we've timed - out hermes_issue_cmd() will probably return -EBUSY below */ - - /* According to the documentation, EVSTAT may contain - obsolete event occurrence information. We have to acknowledge - it by writing EVACK. */ - reg = hermes_read_regn(hw, EVSTAT); - hermes_write_regn(hw, EVACK, reg); - - /* We don't use hermes_docmd_wait here, because the reset wipes - the magic constant in SWSUPPORT0 away, and it gets confused */ - err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL); - - return err; -} - -/* Issue a command to the chip, and (busy!) wait for it to - * complete. - * - * Returns: - * < 0 on internal error - * 0 on success - * > 0 on error returned by the firmware - * - * Callable from any context, but locking is your problem. */ -static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp) -{ - int err; - int k; - u16 reg; - u16 status; - - err = hermes_issue_cmd(hw, cmd, parm0, 0, 0); - if (err) { - if (!hermes_present(hw)) { - if (net_ratelimit()) - printk(KERN_WARNING "hermes @ %p: " - "Card removed while issuing command " - "0x%04x.\n", hw->iobase, cmd); - err = -ENODEV; - } else - if (net_ratelimit()) - printk(KERN_ERR "hermes @ %p: " - "Error %d issuing command 0x%04x.\n", - hw->iobase, err, cmd); - goto out; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_COMPL_TIMEOUT; - while ((!(reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (!hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %p: Card removed " - "while waiting for command 0x%04x completion.\n", - hw->iobase, cmd); - err = -ENODEV; - goto out; - } - - if (!(reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %p: Timeout waiting for " - "command 0x%04x completion.\n", hw->iobase, cmd); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - if (resp) { - resp->status = status; - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - } - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - if (status & HERMES_STATUS_RESULT) - err = -EIO; - - out: - return err; -} - -static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid) -{ - int err = 0; - int k; - u16 reg; - - if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX)) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = ALLOC_COMPL_TIMEOUT; - while ((!(reg & HERMES_EV_ALLOC)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (!hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %p: " - "Card removed waiting for frame allocation.\n", - hw->iobase); - return -ENODEV; - } - - if (!(reg & HERMES_EV_ALLOC)) { - printk(KERN_ERR "hermes @ %p: " - "Timeout waiting for frame allocation\n", - hw->iobase); - return -ETIMEDOUT; - } - - *fid = hermes_read_regn(hw, ALLOCFID); - hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); - - return 0; -} - -/* Set up a BAP to read a particular chunk of data from card's internal buffer. - * - * Returns: - * < 0 on internal failure (errno) - * 0 on success - * > 0 on error - * from firmware - * - * Callable from any context */ -static int hermes_bap_seek(struct hermes *hw, int bap, u16 id, u16 offset) -{ - int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; - int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; - int k; - u16 reg; - - /* Paranoia.. */ - if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2)) - return -EINVAL; - - k = HERMES_BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ((reg & HERMES_OFFSET_BUSY) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg & HERMES_OFFSET_BUSY) - return -ETIMEDOUT; - - /* Now we actually set up the transfer */ - hermes_write_reg(hw, sreg, id); - hermes_write_reg(hw, oreg, offset); - - /* Wait for the BAP to be ready */ - k = HERMES_BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg != offset) { - printk(KERN_ERR "hermes @ %p: BAP%d offset %s: " - "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap, - (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error", - reg, id, offset); - - if (reg & HERMES_OFFSET_BUSY) - return -ETIMEDOUT; - - return -EIO; /* error or wrong offset */ - } - - return 0; -} - -/* Read a block of data from the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. len - * must be even. - * - * Returns: - * < 0 on internal failure (errno) - * 0 on success - * > 0 on error from firmware - */ -static int hermes_bap_pread(struct hermes *hw, int bap, void *buf, int len, - u16 id, u16 offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if ((len < 0) || (len % 2)) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_read_words(hw, dreg, buf, len / 2); - - out: - return err; -} - -/* Write a block of data to the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. - * - * Returns: - * < 0 on internal failure (errno) - * 0 on success - * > 0 on error from firmware - */ -static int hermes_bap_pwrite(struct hermes *hw, int bap, const void *buf, - int len, u16 id, u16 offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len < 0) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_write_bytes(hw, dreg, buf, len); - - out: - return err; -} - -/* Read a Length-Type-Value record from the card. - * - * If length is NULL, we ignore the length read from the card, and - * read the entire buffer regardless. This is useful because some of - * the configuration records appear to have incorrect lengths in - * practice. - * - * Callable from user or bh context. */ -static int hermes_read_ltv(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf) -{ - int err = 0; - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - u16 rlength, rtype; - unsigned nwords; - - if (bufsize % 2) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); - if (err) - return err; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - return err; - - rlength = hermes_read_reg(hw, dreg); - - if (!rlength) - return -ENODATA; - - rtype = hermes_read_reg(hw, dreg); - - if (length) - *length = rlength; - - if (rtype != rid) - printk(KERN_WARNING "hermes @ %p: %s(): " - "rid (0x%04x) does not match type (0x%04x)\n", - hw->iobase, __func__, rid, rtype); - if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize) - printk(KERN_WARNING "hermes @ %p: " - "Truncating LTV record from %d to %d bytes. " - "(rid=0x%04x, len=0x%04x)\n", hw->iobase, - HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength); - - nwords = min((unsigned)rlength - 1, bufsize / 2); - hermes_read_words(hw, dreg, buf, nwords); - - return 0; -} - -static int hermes_write_ltv(struct hermes *hw, int bap, u16 rid, - u16 length, const void *value) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - unsigned count; - - if (length == 0) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - return err; - - hermes_write_reg(hw, dreg, length); - hermes_write_reg(hw, dreg, rid); - - count = length - 1; - - hermes_write_bytes(hw, dreg, value, count << 1); - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, - rid, NULL); - - return err; -} - -/*** Hermes AUX control ***/ - -static inline void -hermes_aux_setaddr(struct hermes *hw, u32 addr) -{ - hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); - hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); -} - -static inline int -hermes_aux_control(struct hermes *hw, int enabled) -{ - int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED; - int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE; - int i; - - /* Already open? */ - if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state) - return 0; - - hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); - hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); - hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); - hermes_write_reg(hw, HERMES_CONTROL, action); - - for (i = 0; i < 20; i++) { - udelay(10); - if (hermes_read_reg(hw, HERMES_CONTROL) == - desired_state) - return 0; - } - - return -EBUSY; -} - -/*** Hermes programming ***/ - -/* About to start programming data (Hermes I) - * offset is the entry point - * - * Spectrum_cs' Symbol fw does not require this - * wl_lkm Agere fw does - * Don't know about intersil - */ -static int hermesi_program_init(struct hermes *hw, u32 offset) -{ - int err; - - /* Disable interrupts?*/ - /*hw->inten = 0x0;*/ - /*hermes_write_regn(hw, INTEN, 0);*/ - /*hermes_set_irqmask(hw, 0);*/ - - /* Acknowledge any outstanding command */ - hermes_write_regn(hw, EVACK, 0xFFFF); - - /* Using init_cmd_wait rather than cmd_wait */ - err = hw->ops->init_cmd_wait(hw, - 0x0100 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - if (err) - return err; - - err = hw->ops->init_cmd_wait(hw, - 0x0000 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - if (err) - return err; - - err = hermes_aux_control(hw, 1); - pr_debug("AUX enable returned %d\n", err); - - if (err) - return err; - - pr_debug("Enabling volatile, EP 0x%08x\n", offset); - err = hw->ops->init_cmd_wait(hw, - HERMES_PROGRAM_ENABLE_VOLATILE, - offset & 0xFFFFu, - offset >> 16, - 0, - NULL); - pr_debug("PROGRAM_ENABLE returned %d\n", err); - - return err; -} - -/* Done programming data (Hermes I) - * - * Spectrum_cs' Symbol fw does not require this - * wl_lkm Agere fw does - * Don't know about intersil - */ -static int hermesi_program_end(struct hermes *hw) -{ - struct hermes_response resp; - int rc = 0; - int err; - - rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); - - pr_debug("PROGRAM_DISABLE returned %d, " - "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", - rc, resp.resp0, resp.resp1, resp.resp2); - - if ((rc == 0) && - ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) - rc = -EIO; - - err = hermes_aux_control(hw, 0); - pr_debug("AUX disable returned %d\n", err); - - /* Acknowledge any outstanding command */ - hermes_write_regn(hw, EVACK, 0xFFFF); - - /* Reinitialise, ignoring return */ - (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - - return rc ? rc : err; -} - -static int hermes_program_bytes(struct hermes *hw, const char *data, - u32 addr, u32 len) -{ - /* wl lkm splits the programming into chunks of 2000 bytes. - * This restriction appears to come from USB. The PCMCIA - * adapters can program the whole lot in one go */ - hermes_aux_setaddr(hw, addr); - hermes_write_bytes(hw, HERMES_AUXDATA, data, len); - return 0; -} - -/* Read PDA from the adapter */ -static int hermes_read_pda(struct hermes *hw, __le16 *pda, u32 pda_addr, - u16 pda_len) -{ - int ret; - u16 pda_size; - u16 data_len = pda_len; - __le16 *data = pda; - - if (hw->eeprom_pda) { - /* PDA of spectrum symbol is in eeprom */ - - /* Issue command to read EEPROM */ - ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); - if (ret) - return ret; - } else { - /* wl_lkm does not include PDA size in the PDA area. - * We will pad the information into pda, so other routines - * don't have to be modified */ - pda[0] = cpu_to_le16(pda_len - 2); - /* Includes CFG_PROD_DATA but not itself */ - pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ - data_len = pda_len - 4; - data = pda + 2; - } - - /* Open auxiliary port */ - ret = hermes_aux_control(hw, 1); - pr_debug("AUX enable returned %d\n", ret); - if (ret) - return ret; - - /* Read PDA */ - hermes_aux_setaddr(hw, pda_addr); - hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2); - - /* Close aux port */ - ret = hermes_aux_control(hw, 0); - pr_debug("AUX disable returned %d\n", ret); - - /* Check PDA length */ - pda_size = le16_to_cpu(pda[0]); - pr_debug("Actual PDA length %d, Max allowed %d\n", - pda_size, pda_len); - if (pda_size > pda_len) - return -EINVAL; - - return 0; -} - -static void hermes_lock_irqsave(spinlock_t *lock, - unsigned long *flags) __acquires(lock) -{ - spin_lock_irqsave(lock, *flags); -} - -static void hermes_unlock_irqrestore(spinlock_t *lock, - unsigned long *flags) __releases(lock) -{ - spin_unlock_irqrestore(lock, *flags); -} - -static void hermes_lock_irq(spinlock_t *lock) __acquires(lock) -{ - spin_lock_irq(lock); -} - -static void hermes_unlock_irq(spinlock_t *lock) __releases(lock) -{ - spin_unlock_irq(lock); -} - -/* Hermes operations for local buses */ -static const struct hermes_ops hermes_ops_local = { - .init = hermes_init, - .cmd_wait = hermes_docmd_wait, - .init_cmd_wait = hermes_doicmd_wait, - .allocate = hermes_allocate, - .read_ltv = hermes_read_ltv, - .read_ltv_pr = hermes_read_ltv, - .write_ltv = hermes_write_ltv, - .bap_pread = hermes_bap_pread, - .bap_pwrite = hermes_bap_pwrite, - .read_pda = hermes_read_pda, - .program_init = hermesi_program_init, - .program_end = hermesi_program_end, - .program = hermes_program_bytes, - .lock_irqsave = hermes_lock_irqsave, - .unlock_irqrestore = hermes_unlock_irqrestore, - .lock_irq = hermes_lock_irq, - .unlock_irq = hermes_unlock_irq, -}; diff --git a/drivers/net/wireless/intersil/orinoco/hermes.h b/drivers/net/wireless/intersil/orinoco/hermes.h deleted file mode 100644 index 3dc561a5cb..0000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes.h +++ /dev/null @@ -1,534 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* hermes.h - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism I & II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver. - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia. - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * - * Portions taken from hfa384x.h. - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#ifndef _HERMES_H -#define _HERMES_H - -/* Notes on locking: - * - * As a module of low level hardware access routines, there is no - * locking. Users of this module should ensure that they serialize - * access to the hermes structure, and to the hardware -*/ - -#include <linux/if_ether.h> -#include <linux/io.h> - -/* - * Limits and constants - */ -#define HERMES_ALLOC_LEN_MIN (4) -#define HERMES_ALLOC_LEN_MAX (2400) -#define HERMES_LTV_LEN_MAX (34) -#define HERMES_BAP_DATALEN_MAX (4096) -#define HERMES_BAP_OFFSET_MAX (4096) -#define HERMES_PORTID_MAX (7) -#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX + 1) -#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ -#define HERMES_PDA_RECS_MAX (200) /* a guess */ -#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ -#define HERMES_SCANRESULT_MAX (35) -#define HERMES_CHINFORESULT_MAX (8) -#define HERMES_MAX_MULTICAST (16) -#define HERMES_MAGIC (0x7d1f) - -/* - * Hermes register offsets - */ -#define HERMES_CMD (0x00) -#define HERMES_PARAM0 (0x02) -#define HERMES_PARAM1 (0x04) -#define HERMES_PARAM2 (0x06) -#define HERMES_STATUS (0x08) -#define HERMES_RESP0 (0x0A) -#define HERMES_RESP1 (0x0C) -#define HERMES_RESP2 (0x0E) -#define HERMES_INFOFID (0x10) -#define HERMES_RXFID (0x20) -#define HERMES_ALLOCFID (0x22) -#define HERMES_TXCOMPLFID (0x24) -#define HERMES_SELECT0 (0x18) -#define HERMES_OFFSET0 (0x1C) -#define HERMES_DATA0 (0x36) -#define HERMES_SELECT1 (0x1A) -#define HERMES_OFFSET1 (0x1E) -#define HERMES_DATA1 (0x38) -#define HERMES_EVSTAT (0x30) -#define HERMES_INTEN (0x32) -#define HERMES_EVACK (0x34) -#define HERMES_CONTROL (0x14) -#define HERMES_SWSUPPORT0 (0x28) -#define HERMES_SWSUPPORT1 (0x2A) -#define HERMES_SWSUPPORT2 (0x2C) -#define HERMES_AUXPAGE (0x3A) -#define HERMES_AUXOFFSET (0x3C) -#define HERMES_AUXDATA (0x3E) - -/* - * CMD register bitmasks - */ -#define HERMES_CMD_BUSY (0x8000) -#define HERMES_CMD_AINFO (0x7f00) -#define HERMES_CMD_MACPORT (0x0700) -#define HERMES_CMD_RECL (0x0100) -#define HERMES_CMD_WRITE (0x0100) -#define HERMES_CMD_PROGMODE (0x0300) -#define HERMES_CMD_CMDCODE (0x003f) - -/* - * STATUS register bitmasks - */ -#define HERMES_STATUS_RESULT (0x7f00) -#define HERMES_STATUS_CMDCODE (0x003f) - -/* - * OFFSET register bitmasks - */ -#define HERMES_OFFSET_BUSY (0x8000) -#define HERMES_OFFSET_ERR (0x4000) -#define HERMES_OFFSET_DATAOFF (0x0ffe) - -/* - * Event register bitmasks (INTEN, EVSTAT, EVACK) - */ -#define HERMES_EV_TICK (0x8000) -#define HERMES_EV_WTERR (0x4000) -#define HERMES_EV_INFDROP (0x2000) -#define HERMES_EV_INFO (0x0080) -#define HERMES_EV_DTIM (0x0020) -#define HERMES_EV_CMD (0x0010) -#define HERMES_EV_ALLOC (0x0008) -#define HERMES_EV_TXEXC (0x0004) -#define HERMES_EV_TX (0x0002) -#define HERMES_EV_RX (0x0001) - -/* - * Command codes - */ -/*--- Controller Commands ----------------------------*/ -#define HERMES_CMD_INIT (0x0000) -#define HERMES_CMD_ENABLE (0x0001) -#define HERMES_CMD_DISABLE (0x0002) -#define HERMES_CMD_DIAG (0x0003) - -/*--- Buffer Mgmt Commands ---------------------------*/ -#define HERMES_CMD_ALLOC (0x000A) -#define HERMES_CMD_TX (0x000B) - -/*--- Regulate Commands ------------------------------*/ -#define HERMES_CMD_NOTIFY (0x0010) -#define HERMES_CMD_INQUIRE (0x0011) - -/*--- Configure Commands -----------------------------*/ -#define HERMES_CMD_ACCESS (0x0021) -#define HERMES_CMD_DOWNLD (0x0022) - -/*--- Serial I/O Commands ----------------------------*/ -#define HERMES_CMD_READMIF (0x0030) -#define HERMES_CMD_WRITEMIF (0x0031) - -/*--- Debugging Commands -----------------------------*/ -#define HERMES_CMD_TEST (0x0038) - - -/* Test command arguments */ -#define HERMES_TEST_SET_CHANNEL 0x0800 -#define HERMES_TEST_MONITOR 0x0b00 -#define HERMES_TEST_STOP 0x0f00 - -/* Authentication algorithms */ -#define HERMES_AUTH_OPEN 1 -#define HERMES_AUTH_SHARED_KEY 2 - -/* WEP settings */ -#define HERMES_WEP_PRIVACY_INVOKED 0x0001 -#define HERMES_WEP_EXCL_UNENCRYPTED 0x0002 -#define HERMES_WEP_HOST_ENCRYPT 0x0010 -#define HERMES_WEP_HOST_DECRYPT 0x0080 - -/* Symbol hostscan options */ -#define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001 -#define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002 -#define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040 -#define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080 - -/* - * Frame structures and constants - */ - -#define HERMES_DESCRIPTOR_OFFSET 0 -#define HERMES_802_11_OFFSET (14) -#define HERMES_802_3_OFFSET (14 + 32) -#define HERMES_802_2_OFFSET (14 + 32 + 14) -#define HERMES_TXCNTL2_OFFSET (HERMES_802_3_OFFSET - 2) - -#define HERMES_RXSTAT_ERR (0x0003) -#define HERMES_RXSTAT_BADCRC (0x0001) -#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) -#define HERMES_RXSTAT_MIC (0x0010) /* Frame contains MIC */ -#define HERMES_RXSTAT_MACPORT (0x0700) -#define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */ -#define HERMES_RXSTAT_MIC_KEY_ID (0x1800) /* MIC key used */ -#define HERMES_RXSTAT_MSGTYPE (0xE000) -#define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */ -#define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */ -#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ - -/* Shift amount for key ID in RXSTAT and TXCTRL */ -#define HERMES_MIC_KEY_ID_SHIFT 11 - -struct hermes_tx_descriptor { - __le16 status; - __le16 reserved1; - __le16 reserved2; - __le32 sw_support; - u8 retry_count; - u8 tx_rate; - __le16 tx_control; -} __packed; - -#define HERMES_TXSTAT_RETRYERR (0x0001) -#define HERMES_TXSTAT_AGEDERR (0x0002) -#define HERMES_TXSTAT_DISCON (0x0004) -#define HERMES_TXSTAT_FORMERR (0x0008) - -#define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */ -#define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */ -#define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */ -#define HERMES_TXCTRL_MIC (0x0010) /* 802.3 + TKIP */ -#define HERMES_TXCTRL_MIC_KEY_ID (0x1800) /* MIC Key ID mask */ -#define HERMES_TXCTRL_ALT_RTRY (0x0020) - -/* Inquiry constants and data types */ - -#define HERMES_INQ_TALLIES (0xF100) -#define HERMES_INQ_SCAN (0xF101) -#define HERMES_INQ_CHANNELINFO (0xF102) -#define HERMES_INQ_HOSTSCAN (0xF103) -#define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104) -#define HERMES_INQ_LINKSTATUS (0xF200) -#define HERMES_INQ_SEC_STAT_AGERE (0xF202) - -struct hermes_tallies_frame { - __le16 TxUnicastFrames; - __le16 TxMulticastFrames; - __le16 TxFragments; - __le16 TxUnicastOctets; - __le16 TxMulticastOctets; - __le16 TxDeferredTransmissions; - __le16 TxSingleRetryFrames; - __le16 TxMultipleRetryFrames; - __le16 TxRetryLimitExceeded; - __le16 TxDiscards; - __le16 RxUnicastFrames; - __le16 RxMulticastFrames; - __le16 RxFragments; - __le16 RxUnicastOctets; - __le16 RxMulticastOctets; - __le16 RxFCSErrors; - __le16 RxDiscards_NoBuffer; - __le16 TxDiscardsWrongSA; - __le16 RxWEPUndecryptable; - __le16 RxMsgInMsgFragments; - __le16 RxMsgInBadMsgFragments; - /* Those last are probably not available in very old firmwares */ - __le16 RxDiscards_WEPICVError; - __le16 RxDiscards_WEPExcluded; -} __packed; - -/* Grabbed from wlan-ng - Thanks Mark... - Jean II - * This is the result of a scan inquiry command */ -/* Structure describing info about an Access Point */ -struct prism2_scan_apinfo { - __le16 channel; /* Channel where the AP sits */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ - u8 rates[10]; /* Bit rate supported */ - __le16 proberesp_rate; /* Data rate of the response frame */ - __le16 atim; /* ATIM window time, Kus (hostscan only) */ -} __packed; - -/* Same stuff for the Lucent/Agere card. - * Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */ -struct agere_scan_apinfo { - __le16 channel; /* Channel where the AP sits */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ -} __packed; - -/* Moustafa: Scan structure for Symbol cards */ -struct symbol_scan_apinfo { - u8 channel; /* Channel where the AP sits */ - u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ - __le16 rates[5]; /* Bit rate supported */ - __le16 basic_rates; /* Basic rates bitmask */ - u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ - u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ -} __packed; - -union hermes_scan_info { - struct agere_scan_apinfo a; - struct prism2_scan_apinfo p; - struct symbol_scan_apinfo s; -}; - -/* Extended scan struct for HERMES_INQ_CHANNELINFO. - * wl_lkm calls this an ACS scan (Automatic Channel Select). - * Keep out of union hermes_scan_info because it is much bigger than - * the older scan structures. */ -struct agere_ext_scan_info { - __le16 reserved0; - - u8 noise; - u8 level; - u8 rx_flow; - u8 rate; - __le16 reserved1[2]; - - __le16 frame_control; - __le16 dur_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - __le16 sequence; - u8 addr4[ETH_ALEN]; - - __le16 data_length; - - /* Next 3 fields do not get filled in. */ - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - __le16 len_type; - - __le64 timestamp; - __le16 beacon_interval; - __le16 capabilities; - u8 data[]; -} __packed; - -#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) -#define HERMES_LINKSTATUS_CONNECTED (0x0001) -#define HERMES_LINKSTATUS_DISCONNECTED (0x0002) -#define HERMES_LINKSTATUS_AP_CHANGE (0x0003) -#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004) -#define HERMES_LINKSTATUS_AP_IN_RANGE (0x0005) -#define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006) - -struct hermes_linkstatus { - __le16 linkstatus; /* Link status */ -} __packed; - -struct hermes_response { - u16 status, resp0, resp1, resp2; -}; - -/* "ID" structure - used for ESSID and station nickname */ -struct hermes_idstring { - __le16 len; - __le16 val[16]; -} __packed; - -struct hermes_multicast { - u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; -} __packed; - -/* Timeouts */ -#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */ - -struct hermes; - -/* Functions to access hardware */ -struct hermes_ops { - int (*init)(struct hermes *hw); - int (*cmd_wait)(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp); - int (*init_cmd_wait)(struct hermes *hw, u16 cmd, - u16 parm0, u16 parm1, u16 parm2, - struct hermes_response *resp); - int (*allocate)(struct hermes *hw, u16 size, u16 *fid); - int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen, - u16 *length, void *buf); - int (*read_ltv_pr)(struct hermes *hw, int bap, u16 rid, - unsigned buflen, u16 *length, void *buf); - int (*write_ltv)(struct hermes *hw, int bap, u16 rid, - u16 length, const void *value); - int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len, - u16 id, u16 offset); - int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf, - int len, u16 id, u16 offset); - int (*read_pda)(struct hermes *hw, __le16 *pda, - u32 pda_addr, u16 pda_len); - int (*program_init)(struct hermes *hw, u32 entry_point); - int (*program_end)(struct hermes *hw); - int (*program)(struct hermes *hw, const char *buf, - u32 addr, u32 len); - void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags); - void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags); - void (*lock_irq)(spinlock_t *lock); - void (*unlock_irq)(spinlock_t *lock); -}; - -/* Basic control structure */ -struct hermes { - void __iomem *iobase; - int reg_spacing; -#define HERMES_16BIT_REGSPACING 0 -#define HERMES_32BIT_REGSPACING 1 - u16 inten; /* Which interrupts should be enabled? */ - bool eeprom_pda; - const struct hermes_ops *ops; - void *priv; -}; - -/* Register access convenience macros */ -#define hermes_read_reg(hw, off) \ - (ioread16((hw)->iobase + ((off) << (hw)->reg_spacing))) -#define hermes_write_reg(hw, off, val) \ - (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing))) -#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name) -#define hermes_write_regn(hw, name, val) \ - hermes_write_reg((hw), HERMES_##name, (val)) - -/* Function prototypes */ -void hermes_struct_init(struct hermes *hw, void __iomem *address, - int reg_spacing); - -/* Inline functions */ - -static inline int hermes_present(struct hermes *hw) -{ - return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; -} - -static inline void hermes_set_irqmask(struct hermes *hw, u16 events) -{ - hw->inten = events; - hermes_write_regn(hw, INTEN, events); -} - -static inline int hermes_enable_port(struct hermes *hw, int port) -{ - return hw->ops->cmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), - 0, NULL); -} - -static inline int hermes_disable_port(struct hermes *hw, int port) -{ - return hw->ops->cmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), - 0, NULL); -} - -/* Initiate an INQUIRE command (tallies or scan). The result will come as an - * information frame in __orinoco_ev_info() */ -static inline int hermes_inquire(struct hermes *hw, u16 rid) -{ - return hw->ops->cmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL); -} - -#define HERMES_BYTES_TO_RECLEN(n) ((((n) + 1) / 2) + 1) -#define HERMES_RECLEN_TO_BYTES(n) (((n) - 1) * 2) - -/* Note that for the next two, the count is in 16-bit words, not bytes */ -static inline void hermes_read_words(struct hermes *hw, int off, - void *buf, unsigned count) -{ - off = off << hw->reg_spacing; - ioread16_rep(hw->iobase + off, buf, count); -} - -static inline void hermes_write_bytes(struct hermes *hw, int off, - const char *buf, unsigned count) -{ - off = off << hw->reg_spacing; - iowrite16_rep(hw->iobase + off, buf, count >> 1); - if (unlikely(count & 1)) - iowrite8(buf[count - 1], hw->iobase + off); -} - -static inline void hermes_clear_words(struct hermes *hw, int off, - unsigned count) -{ - unsigned i; - - off = off << hw->reg_spacing; - - for (i = 0; i < count; i++) - iowrite16(0, hw->iobase + off); -} - -#define HERMES_READ_RECORD(hw, bap, rid, buf) \ - (hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf))) -#define HERMES_READ_RECORD_PR(hw, bap, rid, buf) \ - (hw->ops->read_ltv_pr((hw), (bap), (rid), sizeof(*buf), NULL, (buf))) -#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ - (hw->ops->write_ltv((hw), (bap), (rid), \ - HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf))) - -static inline int hermes_read_wordrec(struct hermes *hw, int bap, u16 rid, - u16 *word) -{ - __le16 rec; - int err; - - err = HERMES_READ_RECORD(hw, bap, rid, &rec); - *word = le16_to_cpu(rec); - return err; -} - -static inline int hermes_read_wordrec_pr(struct hermes *hw, int bap, u16 rid, - u16 *word) -{ - __le16 rec; - int err; - - err = HERMES_READ_RECORD_PR(hw, bap, rid, &rec); - *word = le16_to_cpu(rec); - return err; -} - -static inline int hermes_write_wordrec(struct hermes *hw, int bap, u16 rid, - u16 word) -{ - __le16 rec = cpu_to_le16(word); - return HERMES_WRITE_RECORD(hw, bap, rid, &rec); -} - -#endif /* _HERMES_H */ diff --git a/drivers/net/wireless/intersil/orinoco/hermes_dld.c b/drivers/net/wireless/intersil/orinoco/hermes_dld.c deleted file mode 100644 index dbeadfcfef..0000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes_dld.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Hermes download helper. - * - * This helper: - * - is capable of writing to the volatile area of the hermes device - * - is currently not capable of writing to non-volatile areas - * - provide helpers to identify and update plugin data - * - is not capable of interpreting a fw image directly. That is up to - * the main card driver. - * - deals with Hermes I devices. It can probably be modified to deal - * with Hermes II devices - * - * Copyright (C) 2007, David Kilroy - * - * Plug data code slightly modified from spectrum_cs driver - * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org> - * Portions based on information in wl_lkm_718 Agere driver - * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include "hermes.h" -#include "hermes_dld.h" - -#define PFX "hermes_dld: " - -/* End markers used in dblocks */ -#define PDI_END 0x00000000 /* End of PDA */ -#define BLOCK_END 0xFFFFFFFF /* Last image block */ -#define TEXT_END 0x1A /* End of text header */ - -/* - * The following structures have little-endian fields denoted by - * the leading underscore. Don't access them directly - use inline - * functions defined below. - */ - -/* - * The binary image to be downloaded consists of series of data blocks. - * Each block has the following structure. - */ -struct dblock { - __le32 addr; /* adapter address where to write the block */ - __le16 len; /* length of the data only, in bytes */ - char data[]; /* data to be written */ -} __packed; - -/* - * Plug Data References are located in the image after the last data - * block. They refer to areas in the adapter memory where the plug data - * items with matching ID should be written. - */ -struct pdr { - __le32 id; /* record ID */ - __le32 addr; /* adapter address where to write the data */ - __le32 len; /* expected length of the data, in bytes */ - char next[]; /* next PDR starts here */ -} __packed; - -/* - * Plug Data Items are located in the EEPROM read from the adapter by - * primary firmware. They refer to the device-specific data that should - * be plugged into the secondary firmware. - */ -struct pdi { - __le16 len; /* length of ID and data, in words */ - __le16 id; /* record ID */ - char data[]; /* plug data */ -} __packed; - -/*** FW data block access functions ***/ - -static inline u32 -dblock_addr(const struct dblock *blk) -{ - return le32_to_cpu(blk->addr); -} - -static inline u32 -dblock_len(const struct dblock *blk) -{ - return le16_to_cpu(blk->len); -} - -/*** PDR Access functions ***/ - -static inline u32 -pdr_id(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->id); -} - -static inline u32 -pdr_addr(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->addr); -} - -static inline u32 -pdr_len(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->len); -} - -/*** PDI Access functions ***/ - -static inline u32 -pdi_id(const struct pdi *pdi) -{ - return le16_to_cpu(pdi->id); -} - -/* Return length of the data only, in bytes */ -static inline u32 -pdi_len(const struct pdi *pdi) -{ - return 2 * (le16_to_cpu(pdi->len) - 1); -} - -/*** Plug Data Functions ***/ - -/* - * Scan PDR for the record with the specified RECORD_ID. - * If it's not found, return NULL. - */ -static const struct pdr * -hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end) -{ - const struct pdr *pdr = first_pdr; - - end -= sizeof(struct pdr); - - while (((void *) pdr <= end) && - (pdr_id(pdr) != PDI_END)) { - /* - * PDR area is currently not terminated by PDI_END. - * It's followed by CRC records, which have the type - * field where PDR has length. The type can be 0 or 1. - */ - if (pdr_len(pdr) < 2) - return NULL; - - /* If the record ID matches, we are done */ - if (pdr_id(pdr) == record_id) - return pdr; - - pdr = (struct pdr *) pdr->next; - } - return NULL; -} - -/* Scan production data items for a particular entry */ -static const struct pdi * -hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end) -{ - const struct pdi *pdi = first_pdi; - - end -= sizeof(struct pdi); - - while (((void *) pdi <= end) && - (pdi_id(pdi) != PDI_END)) { - - /* If the record ID matches, we are done */ - if (pdi_id(pdi) == record_id) - return pdi; - - pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; - } - return NULL; -} - -/* Process one Plug Data Item - find corresponding PDR and plug it */ -static int -hermes_plug_pdi(struct hermes *hw, const struct pdr *first_pdr, - const struct pdi *pdi, const void *pdr_end) -{ - const struct pdr *pdr; - - /* Find the PDR corresponding to this PDI */ - pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end); - - /* No match is found, safe to ignore */ - if (!pdr) - return 0; - - /* Lengths of the data in PDI and PDR must match */ - if (pdi_len(pdi) != pdr_len(pdr)) - return -EINVAL; - - /* do the actual plugging */ - hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi)); - - return 0; -} - -/* Parse PDA and write the records into the adapter - * - * Attempt to write every records that is in the specified pda - * which also has a valid production data record for the firmware. - */ -int hermes_apply_pda(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end) -{ - int ret; - const struct pdi *pdi; - const struct pdr *pdr; - - pdr = (const struct pdr *) first_pdr; - pda_end -= sizeof(struct pdi); - - /* Go through every PDI and plug them into the adapter */ - pdi = (const struct pdi *) (pda + 2); - while (((void *) pdi <= pda_end) && - (pdi_id(pdi) != PDI_END)) { - ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end); - if (ret) - return ret; - - /* Increment to the next PDI */ - pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)]; - } - return 0; -} - -/* Identify the total number of bytes in all blocks - * including the header data. - */ -size_t -hermes_blocks_length(const char *first_block, const void *end) -{ - const struct dblock *blk = (const struct dblock *) first_block; - int total_len = 0; - int len; - - end -= sizeof(*blk); - - /* Skip all blocks to locate Plug Data References - * (Spectrum CS) */ - while (((void *) blk <= end) && - (dblock_addr(blk) != BLOCK_END)) { - len = dblock_len(blk); - total_len += sizeof(*blk) + len; - blk = (struct dblock *) &blk->data[len]; - } - - return total_len; -} - -/*** Hermes programming ***/ - -/* Program the data blocks */ -int hermes_program(struct hermes *hw, const char *first_block, const void *end) -{ - const struct dblock *blk; - u32 blkaddr; - u32 blklen; - int err = 0; - - blk = (const struct dblock *) first_block; - - if ((void *) blk > (end - sizeof(*blk))) - return -EIO; - - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - - while ((blkaddr != BLOCK_END) && - (((void *) blk + blklen) <= end)) { - pr_debug(PFX "Programming block of length %d " - "to address 0x%08x\n", blklen, blkaddr); - - err = hw->ops->program(hw, blk->data, blkaddr, blklen); - if (err) - break; - - blk = (const struct dblock *) &blk->data[blklen]; - - if ((void *) blk > (end - sizeof(*blk))) - return -EIO; - - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - } - return err; -} - -/*** Default plugging data for Hermes I ***/ -/* Values from wl_lkm_718/hcf/dhf.c */ - -#define DEFINE_DEFAULT_PDR(pid, length, data) \ -static const struct { \ - __le16 len; \ - __le16 id; \ - u8 val[length]; \ -} __packed default_pdr_data_##pid = { \ - cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ - sizeof(__le16)) - 1), \ - cpu_to_le16(pid), \ - data \ -} - -#define DEFAULT_PDR(pid) default_pdr_data_##pid - -/* HWIF Compatibility */ -DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00"); - -/* PPPPSign */ -DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00"); - -/* PPPPProf */ -DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00"); - -/* Antenna diversity */ -DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F"); - -/* Modem VCO band Set-up */ -DEFINE_DEFAULT_PDR(0x0160, 28, - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00"); - -/* Modem Rx Gain Table Values */ -DEFINE_DEFAULT_PDR(0x0161, 256, - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3E\01\x3E\x01\x3D\x01" - "\x3D\x01\x3C\01\x3C\x01\x3B\x01" - "\x3B\x01\x3A\01\x3A\x01\x39\x01" - "\x39\x01\x38\01\x38\x01\x37\x01" - "\x37\x01\x36\01\x36\x01\x35\x01" - "\x35\x01\x34\01\x34\x01\x33\x01" - "\x33\x01\x32\x01\x32\x01\x31\x01" - "\x31\x01\x30\x01\x30\x01\x7B\x01" - "\x7B\x01\x7A\x01\x7A\x01\x79\x01" - "\x79\x01\x78\x01\x78\x01\x77\x01" - "\x77\x01\x76\x01\x76\x01\x75\x01" - "\x75\x01\x74\x01\x74\x01\x73\x01" - "\x73\x01\x72\x01\x72\x01\x71\x01" - "\x71\x01\x70\x01\x70\x01\x68\x01" - "\x68\x01\x67\x01\x67\x01\x66\x01" - "\x66\x01\x65\x01\x65\x01\x57\x01" - "\x57\x01\x56\x01\x56\x01\x55\x01" - "\x55\x01\x54\x01\x54\x01\x53\x01" - "\x53\x01\x52\x01\x52\x01\x51\x01" - "\x51\x01\x50\x01\x50\x01\x48\x01" - "\x48\x01\x47\x01\x47\x01\x46\x01" - "\x46\x01\x45\x01\x45\x01\x44\x01" - "\x44\x01\x43\x01\x43\x01\x42\x01" - "\x42\x01\x41\x01\x41\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01"); - -/* Write PDA according to certain rules. - * - * For every production data record, look for a previous setting in - * the pda, and use that. - * - * For certain records, use defaults if they are not found in pda. - */ -int hermes_apply_pda_with_defaults(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end) -{ - const struct pdr *pdr = (const struct pdr *) first_pdr; - const struct pdi *first_pdi = (const struct pdi *) &pda[2]; - const struct pdi *pdi; - const struct pdi *default_pdi = NULL; - const struct pdi *outdoor_pdi; - int record_id; - - pdr_end -= sizeof(struct pdr); - - while (((void *) pdr <= pdr_end) && - (pdr_id(pdr) != PDI_END)) { - /* - * For spectrum_cs firmwares, - * PDR area is currently not terminated by PDI_END. - * It's followed by CRC records, which have the type - * field where PDR has length. The type can be 0 or 1. - */ - if (pdr_len(pdr) < 2) - break; - record_id = pdr_id(pdr); - - pdi = hermes_find_pdi(first_pdi, record_id, pda_end); - if (pdi) - pr_debug(PFX "Found record 0x%04x at %p\n", - record_id, pdi); - - switch (record_id) { - case 0x110: /* Modem REFDAC values */ - case 0x120: /* Modem VGDAC values */ - outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1, - pda_end); - default_pdi = NULL; - if (outdoor_pdi) { - pdi = outdoor_pdi; - pr_debug(PFX - "Using outdoor record 0x%04x at %p\n", - record_id + 1, pdi); - } - break; - case 0x5: /* HWIF Compatibility */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005); - break; - case 0x108: /* PPPPSign */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108); - break; - case 0x109: /* PPPPProf */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109); - break; - case 0x150: /* Antenna diversity */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150); - break; - case 0x160: /* Modem VCO band Set-up */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160); - break; - case 0x161: /* Modem Rx Gain Table Values */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161); - break; - default: - default_pdi = NULL; - break; - } - if (!pdi && default_pdi) { - /* Use default */ - pdi = default_pdi; - pr_debug(PFX "Using default record 0x%04x at %p\n", - record_id, pdi); - } - - if (pdi) { - /* Lengths of the data in PDI and PDR must match */ - if ((pdi_len(pdi) == pdr_len(pdr)) && - ((void *) pdi->data + pdi_len(pdi) < pda_end)) { - /* do the actual plugging */ - hw->ops->program(hw, pdi->data, pdr_addr(pdr), - pdi_len(pdi)); - } - } - - pdr++; - } - return 0; -} diff --git a/drivers/net/wireless/intersil/orinoco/hermes_dld.h b/drivers/net/wireless/intersil/orinoco/hermes_dld.h deleted file mode 100644 index b5377e232c..0000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes_dld.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2007, David Kilroy - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ -#ifndef _HERMES_DLD_H -#define _HERMES_DLD_H - -#include "hermes.h" - -int hermesi_program_init(struct hermes *hw, u32 offset); -int hermesi_program_end(struct hermes *hw); -int hermes_program(struct hermes *hw, const char *first_block, const void *end); - -int hermes_read_pda(struct hermes *hw, - __le16 *pda, - u32 pda_addr, - u16 pda_len, - int use_eeprom); -int hermes_apply_pda(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end); -int hermes_apply_pda_with_defaults(struct hermes *hw, - const char *first_pdr, - const void *pdr_end, - const __le16 *pda, - const void *pda_end); - -size_t hermes_blocks_length(const char *first_block, const void *end); - -#endif /* _HERMES_DLD_H */ diff --git a/drivers/net/wireless/intersil/orinoco/hermes_rid.h b/drivers/net/wireless/intersil/orinoco/hermes_rid.h deleted file mode 100644 index 42eb67dea1..0000000000 --- a/drivers/net/wireless/intersil/orinoco/hermes_rid.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef _HERMES_RID_H -#define _HERMES_RID_H - -/* - * Configuration RIDs - */ -#define HERMES_RID_CNFPORTTYPE 0xFC00 -#define HERMES_RID_CNFOWNMACADDR 0xFC01 -#define HERMES_RID_CNFDESIREDSSID 0xFC02 -#define HERMES_RID_CNFOWNCHANNEL 0xFC03 -#define HERMES_RID_CNFOWNSSID 0xFC04 -#define HERMES_RID_CNFOWNATIMWINDOW 0xFC05 -#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 -#define HERMES_RID_CNFMAXDATALEN 0xFC07 -#define HERMES_RID_CNFWDSADDRESS 0xFC08 -#define HERMES_RID_CNFPMENABLED 0xFC09 -#define HERMES_RID_CNFPMEPS 0xFC0A -#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B -#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C -#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D -#define HERMES_RID_CNFOWNNAME 0xFC0E -#define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10 -#define HERMES_RID_CNFWDSADDRESS1 0xFC11 -#define HERMES_RID_CNFWDSADDRESS2 0xFC12 -#define HERMES_RID_CNFWDSADDRESS3 0xFC13 -#define HERMES_RID_CNFWDSADDRESS4 0xFC14 -#define HERMES_RID_CNFWDSADDRESS5 0xFC15 -#define HERMES_RID_CNFWDSADDRESS6 0xFC16 -#define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17 -#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 -#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 -#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 -#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22 -#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 -#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 -#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 -#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 -#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 -#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 -#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 -#define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 -#define HERMES_RID_CNFAUTHENTICATION 0xFC2A -#define HERMES_RID_CNFMAXASSOCSTA 0xFC2B -#define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B -#define HERMES_RID_CNFTXCONTROL 0xFC2C -#define HERMES_RID_CNFROAMINGMODE 0xFC2D -#define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E -#define HERMES_RID_CNFRCVCRCERROR 0xFC30 -#define HERMES_RID_CNFMMLIFE 0xFC31 -#define HERMES_RID_CNFALTRETRYCOUNT 0xFC32 -#define HERMES_RID_CNFBEACONINT 0xFC33 -#define HERMES_RID_CNFAPPCFINFO 0xFC34 -#define HERMES_RID_CNFSTAPCFINFO 0xFC35 -#define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37 -#define HERMES_RID_CNFTIMCTRL 0xFC40 -#define HERMES_RID_CNFTHIRTY2TALLY 0xFC42 -#define HERMES_RID_CNFENHSECURITY 0xFC43 -#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 -#define HERMES_RID_CNFCREATEIBSS 0xFC81 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 -#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 -#define HERMES_RID_CNFTXRATECONTROL 0xFC84 -#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 -#define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A -#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96 -#define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97 -#define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98 -#define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99 -#define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A -#define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B -#define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C -#define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D -#define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB -#define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0 -#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 -#define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 -#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 -#define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 -#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 -#define HERMES_RID_CNFBASICRATES 0xFCB3 -#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 -#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4 -#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5 -#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6 -#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7 -#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8 -#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9 -#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA -#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB -#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2 -#define HERMES_RID_CNFDISASSOCIATE 0xFCC8 -#define HERMES_RID_CNFTICKTIME 0xFCE0 -#define HERMES_RID_CNFSCANREQUEST 0xFCE1 -#define HERMES_RID_CNFJOINREQUEST 0xFCE2 -#define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3 -#define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4 -#define HERMES_RID_CNFHOSTSCAN 0xFCE5 - -/* - * Information RIDs - */ -#define HERMES_RID_MAXLOADTIME 0xFD00 -#define HERMES_RID_DOWNLOADBUFFER 0xFD01 -#define HERMES_RID_PRIID 0xFD02 -#define HERMES_RID_PRISUPRANGE 0xFD03 -#define HERMES_RID_CFIACTRANGES 0xFD04 -#define HERMES_RID_NICSERNUM 0xFD0A -#define HERMES_RID_NICID 0xFD0B -#define HERMES_RID_MFISUPRANGE 0xFD0C -#define HERMES_RID_CFISUPRANGE 0xFD0D -#define HERMES_RID_CHANNELLIST 0xFD10 -#define HERMES_RID_REGULATORYDOMAINS 0xFD11 -#define HERMES_RID_TEMPTYPE 0xFD12 -#define HERMES_RID_CIS 0xFD13 -#define HERMES_RID_STAID 0xFD20 -#define HERMES_RID_STASUPRANGE 0xFD21 -#define HERMES_RID_MFIACTRANGES 0xFD22 -#define HERMES_RID_CFIACTRANGES2 0xFD23 -#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 -#define HERMES_RID_PORTSTATUS 0xFD40 -#define HERMES_RID_CURRENTSSID 0xFD41 -#define HERMES_RID_CURRENTBSSID 0xFD42 -#define HERMES_RID_COMMSQUALITY 0xFD43 -#define HERMES_RID_CURRENTTXRATE 0xFD44 -#define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45 -#define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46 -#define HERMES_RID_PROTOCOLRSPTIME 0xFD47 -#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 -#define HERMES_RID_LONGRETRYLIMIT 0xFD49 -#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A -#define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B -#define HERMES_RID_CFPOLLABLE 0xFD4C -#define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D -#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F -#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51 -#define HERMES_RID_CURRENTTXRATE1 0xFD80 -#define HERMES_RID_CURRENTTXRATE2 0xFD81 -#define HERMES_RID_CURRENTTXRATE3 0xFD82 -#define HERMES_RID_CURRENTTXRATE4 0xFD83 -#define HERMES_RID_CURRENTTXRATE5 0xFD84 -#define HERMES_RID_CURRENTTXRATE6 0xFD85 -#define HERMES_RID_OWNMACADDR 0xFD86 -#define HERMES_RID_SCANRESULTSTABLE 0xFD88 -#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89 -#define HERMES_RID_CURRENT_WPA_IE 0xFD8A -#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B -#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C -#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D -#define HERMES_RID_TXQUEUEEMPTY 0xFD91 -#define HERMES_RID_PHYTYPE 0xFDC0 -#define HERMES_RID_CURRENTCHANNEL 0xFDC1 -#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 -#define HERMES_RID_CCAMODE 0xFDC3 -#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 -#define HERMES_RID_BUILDSEQ 0xFFFE -#define HERMES_RID_FWID 0xFFFF - -#endif diff --git a/drivers/net/wireless/intersil/orinoco/hw.c b/drivers/net/wireless/intersil/orinoco/hw.c deleted file mode 100644 index 4fcca08e50..0000000000 --- a/drivers/net/wireless/intersil/orinoco/hw.c +++ /dev/null @@ -1,1362 +0,0 @@ -/* Encapsulate basic setting changes and retrieval on Hermes hardware - * - * See copyright notice in main.c - */ -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/if_arp.h> -#include <linux/ieee80211.h> -#include <linux/wireless.h> -#include <net/cfg80211.h> -#include "hermes.h" -#include "hermes_rid.h" -#include "orinoco.h" - -#include "hw.h" - -#define SYMBOL_MAX_VER_LEN (14) - -/* Symbol firmware has a bug allocating buffers larger than this */ -#define TX_NICBUF_SIZE_BUG 1585 - -/********************************************************************/ -/* Data tables */ -/********************************************************************/ - -/* This tables gives the actual meanings of the bitrate IDs returned - * by the firmware. */ -static const struct { - int bitrate; /* in 100s of kilobits */ - int automatic; - u16 agere_txratectrl; - u16 intersil_txratectrl; -} bitrate_table[] = { - {110, 1, 3, 15}, /* Entry 0 is the default */ - {10, 0, 1, 1}, - {10, 1, 1, 1}, - {20, 0, 2, 2}, - {20, 1, 6, 3}, - {55, 0, 4, 4}, - {55, 1, 7, 7}, - {110, 0, 5, 8}, -}; -#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) - -/* Firmware version encoding */ -struct comp_id { - u16 id, variant, major, minor; -} __packed; - -static inline enum fwtype determine_firmware_type(struct comp_id *nic_id) -{ - if (nic_id->id < 0x8000) - return FIRMWARE_TYPE_AGERE; - else if (nic_id->id == 0x8000 && nic_id->major == 0) - return FIRMWARE_TYPE_SYMBOL; - else - return FIRMWARE_TYPE_INTERSIL; -} - -/* Set priv->firmware type, determine firmware properties - * This function can be called before we have registerred with netdev, - * so all errors go out with dev_* rather than printk - * - * If non-NULL stores a firmware description in fw_name. - * If non-NULL stores a HW version in hw_ver - * - * These are output via generic cfg80211 ethtool support. - */ -int determine_fw_capabilities(struct orinoco_private *priv, - char *fw_name, size_t fw_name_len, - u32 *hw_ver) -{ - struct device *dev = priv->dev; - struct hermes *hw = &priv->hw; - int err; - struct comp_id nic_id, sta_id; - unsigned int firmver; - char tmp[SYMBOL_MAX_VER_LEN + 1] __attribute__((aligned(2))); - - /* Get the hardware version */ - err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_NICID, &nic_id); - if (err) { - dev_err(dev, "Cannot read hardware identity: error %d\n", - err); - return err; - } - - le16_to_cpus(&nic_id.id); - le16_to_cpus(&nic_id.variant); - le16_to_cpus(&nic_id.major); - le16_to_cpus(&nic_id.minor); - dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n", - nic_id.id, nic_id.variant, nic_id.major, nic_id.minor); - - if (hw_ver) - *hw_ver = (((nic_id.id & 0xff) << 24) | - ((nic_id.variant & 0xff) << 16) | - ((nic_id.major & 0xff) << 8) | - (nic_id.minor & 0xff)); - - priv->firmware_type = determine_firmware_type(&nic_id); - - /* Get the firmware version */ - err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_STAID, &sta_id); - if (err) { - dev_err(dev, "Cannot read station identity: error %d\n", - err); - return err; - } - - le16_to_cpus(&sta_id.id); - le16_to_cpus(&sta_id.variant); - le16_to_cpus(&sta_id.major); - le16_to_cpus(&sta_id.minor); - dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n", - sta_id.id, sta_id.variant, sta_id.major, sta_id.minor); - - switch (sta_id.id) { - case 0x15: - dev_err(dev, "Primary firmware is active\n"); - return -ENODEV; - case 0x14b: - dev_err(dev, "Tertiary firmware is active\n"); - return -ENODEV; - case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ - case 0x21: /* Symbol Spectrum24 Trilogy */ - break; - default: - dev_notice(dev, "Unknown station ID, please report\n"); - break; - } - - /* Default capabilities */ - priv->has_sensitivity = 1; - priv->has_mwo = 0; - priv->has_preamble = 0; - priv->has_port3 = 1; - priv->has_ibss = 1; - priv->has_wep = 0; - priv->has_big_wep = 0; - priv->has_alt_txcntl = 0; - priv->has_ext_scan = 0; - priv->has_wpa = 0; - priv->do_fw_download = 0; - - /* Determine capabilities from the firmware version */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, - ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ - if (fw_name) - snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d", - sta_id.major, sta_id.minor); - - firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; - - priv->has_ibss = (firmver >= 0x60006); - priv->has_wep = (firmver >= 0x40020); - priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell - Gold cards from the others? */ - priv->has_mwo = (firmver >= 0x60000); - priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ - priv->ibss_port = 1; - priv->has_hostscan = (firmver >= 0x8000a); - priv->do_fw_download = 1; - priv->broken_monitor = (firmver >= 0x80000); - priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_wpa = (firmver >= 0x9002a); - /* Tested with Agere firmware : - * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II - * Tested CableTron firmware : 4.32 => Anton */ - break; - case FIRMWARE_TYPE_SYMBOL: - /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ - /* Intel MAC : 00:02:B3:* */ - /* 3Com MAC : 00:50:DA:* */ - memset(tmp, 0, sizeof(tmp)); - /* Get the Symbol firmware version */ - err = hw->ops->read_ltv_pr(hw, USER_BAP, - HERMES_RID_SECONDARYVERSION_SYMBOL, - SYMBOL_MAX_VER_LEN, NULL, &tmp); - if (err) { - dev_warn(dev, "Error %d reading Symbol firmware info. " - "Wildly guessing capabilities...\n", err); - firmver = 0; - tmp[0] = '\0'; - } else { - /* The firmware revision is a string, the format is - * something like : "V2.20-01". - * Quick and dirty parsing... - Jean II - */ - firmver = ((tmp[1] - '0') << 16) - | ((tmp[3] - '0') << 12) - | ((tmp[4] - '0') << 8) - | ((tmp[6] - '0') << 4) - | (tmp[7] - '0'); - - tmp[SYMBOL_MAX_VER_LEN] = '\0'; - } - - if (fw_name) - snprintf(fw_name, fw_name_len, "Symbol %s", tmp); - - priv->has_ibss = (firmver >= 0x20000); - priv->has_wep = (firmver >= 0x15012); - priv->has_big_wep = (firmver >= 0x20000); - priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || - (firmver >= 0x29000 && firmver < 0x30000) || - firmver >= 0x31000; - priv->has_preamble = (firmver >= 0x20000); - priv->ibss_port = 4; - - /* Symbol firmware is found on various cards, but - * there has been no attempt to check firmware - * download on non-spectrum_cs based cards. - * - * Given that the Agere firmware download works - * differently, we should avoid doing a firmware - * download with the Symbol algorithm on non-spectrum - * cards. - * - * For now we can identify a spectrum_cs based card - * because it has a firmware reset function. - */ - priv->do_fw_download = (priv->stop_fw != NULL); - - priv->broken_disableport = (firmver == 0x25013) || - (firmver >= 0x30000 && firmver <= 0x31000); - priv->has_hostscan = (firmver >= 0x31001) || - (firmver >= 0x29057 && firmver < 0x30000); - /* Tested with Intel firmware : 0x20015 => Jean II */ - /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ - break; - case FIRMWARE_TYPE_INTERSIL: - /* D-Link, Linksys, Adtron, ZoomAir, and many others... - * Samsung, Compaq 100/200 and Proxim are slightly - * different and less well tested */ - /* D-Link MAC : 00:40:05:* */ - /* Addtron MAC : 00:90:D1:* */ - if (fw_name) - snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d", - sta_id.major, sta_id.minor, sta_id.variant); - - firmver = ((unsigned long)sta_id.major << 16) | - ((unsigned long)sta_id.minor << 8) | sta_id.variant; - - priv->has_ibss = (firmver >= 0x000700); /* FIXME */ - priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); - priv->has_pm = (firmver >= 0x000700); - priv->has_hostscan = (firmver >= 0x010301); - - if (firmver >= 0x000800) - priv->ibss_port = 0; - else { - dev_notice(dev, "Intersil firmware earlier than v0.8.x" - " - several features not supported\n"); - priv->ibss_port = 1; - } - break; - } - if (fw_name) - dev_info(dev, "Firmware determined as %s\n", fw_name); - -#ifndef CONFIG_HERMES_PRISM - if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { - dev_err(dev, "Support for Prism chipset is not enabled\n"); - return -ENODEV; - } -#endif - - return 0; -} - -/* Read settings from EEPROM into our private structure. - * MAC address gets dropped into callers buffer - * Can be called before netdev registration. - */ -int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) -{ - struct device *dev = priv->dev; - struct hermes_idstring nickbuf; - struct hermes *hw = &priv->hw; - int len; - int err; - u16 reclen; - - /* Get the MAC address */ - err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - ETH_ALEN, NULL, dev_addr); - if (err) { - dev_warn(dev, "Failed to read MAC address!\n"); - goto out; - } - - dev_dbg(dev, "MAC address %pM\n", dev_addr); - - /* Get the station name */ - err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - sizeof(nickbuf), &reclen, &nickbuf); - if (err) { - dev_err(dev, "failed to read station name\n"); - goto out; - } - if (nickbuf.len) - len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); - else - len = min(IW_ESSID_MAX_SIZE, 2 * reclen); - memcpy(priv->nick, &nickbuf.val, len); - priv->nick[len] = '\0'; - - dev_dbg(dev, "Station name \"%s\"\n", priv->nick); - - /* Get allowed channels */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CHANNELLIST, - &priv->channel_mask); - if (err) { - dev_err(dev, "Failed to read channel list!\n"); - goto out; - } - - /* Get initial AP density */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, - &priv->ap_density); - if (err || priv->ap_density < 1 || priv->ap_density > 3) - priv->has_sensitivity = 0; - - /* Get initial RTS threshold */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - &priv->rts_thresh); - if (err) { - dev_err(dev, "Failed to read RTS threshold!\n"); - goto out; - } - - /* Get initial fragmentation settings */ - if (priv->has_mwo) - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - &priv->mwo_robust); - else - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - &priv->frag_thresh); - if (err) { - dev_err(dev, "Failed to read fragmentation settings!\n"); - goto out; - } - - /* Power management setup */ - if (priv->has_pm) { - priv->pm_on = 0; - priv->pm_mcast = 1; - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - &priv->pm_period); - if (err) { - dev_err(dev, "Failed to read power management " - "period!\n"); - goto out; - } - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - &priv->pm_timeout); - if (err) { - dev_err(dev, "Failed to read power management " - "timeout!\n"); - goto out; - } - } - - /* Preamble setup */ - if (priv->has_preamble) { - err = hermes_read_wordrec_pr(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - &priv->preamble); - if (err) { - dev_err(dev, "Failed to read preamble setup\n"); - goto out; - } - } - - /* Retry settings */ - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, - &priv->short_retry_limit); - if (err) { - dev_err(dev, "Failed to read short retry limit\n"); - goto out; - } - - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, - &priv->long_retry_limit); - if (err) { - dev_err(dev, "Failed to read long retry limit\n"); - goto out; - } - - err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, - &priv->retry_lifetime); - if (err) { - dev_err(dev, "Failed to read max retry lifetime\n"); - goto out; - } - -out: - return err; -} - -/* Can be called before netdev registration */ -int orinoco_hw_allocate_fid(struct orinoco_private *priv) -{ - struct device *dev = priv->dev; - struct hermes *hw = &priv->hw; - int err; - - err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid); - if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { - /* Try workaround for old Symbol firmware bug */ - priv->nicbuf_size = TX_NICBUF_SIZE_BUG; - err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid); - - dev_warn(dev, "Firmware ALLOC bug detected " - "(old Symbol firmware?). Work around %s\n", - err ? "failed!" : "ok."); - } - - return err; -} - -int orinoco_get_bitratemode(int bitrate, int automatic) -{ - int ratemode = -1; - int i; - - if ((bitrate != 10) && (bitrate != 20) && - (bitrate != 55) && (bitrate != 110)) - return ratemode; - - for (i = 0; i < BITRATE_TABLE_SIZE; i++) { - if ((bitrate_table[i].bitrate == bitrate) && - (bitrate_table[i].automatic == automatic)) { - ratemode = i; - break; - } - } - return ratemode; -} - -void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic) -{ - BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); - - *bitrate = bitrate_table[ratemode].bitrate * 100000; - *automatic = bitrate_table[ratemode].automatic; -} - -int orinoco_hw_program_rids(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct wireless_dev *wdev = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - struct hermes_idstring idbuf; - - /* Set the MAC address */ - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - HERMES_BYTES_TO_RECLEN(ETH_ALEN), - dev->dev_addr); - if (err) { - printk(KERN_ERR "%s: Error %d setting MAC address\n", - dev->name, err); - return err; - } - - /* Set up the link mode */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, - priv->port_type); - if (err) { - printk(KERN_ERR "%s: Error %d setting port type\n", - dev->name, err); - return err; - } - /* Set the channel/frequency */ - if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFOWNCHANNEL, - priv->channel); - if (err) { - printk(KERN_ERR "%s: Error %d setting channel %d\n", - dev->name, err, priv->channel); - return err; - } - } - - if (priv->has_ibss) { - u16 createibss; - - if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { - printk(KERN_WARNING "%s: This firmware requires an " - "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); - /* With wvlan_cs, in this case, we would crash. - * hopefully, this driver will behave better... - * Jean II */ - createibss = 0; - } else { - createibss = priv->createibss; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFCREATEIBSS, - createibss); - if (err) { - printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", - dev->name, err); - return err; - } - } - - /* Set the desired BSSID */ - err = __orinoco_hw_set_wap(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting AP address\n", - dev->name, err); - return err; - } - - /* Set the desired ESSID */ - idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); - memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); - /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting OWNSSID\n", - dev->name, err); - return err; - } - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", - dev->name, err); - return err; - } - - /* Set the station name */ - idbuf.len = cpu_to_le16(strlen(priv->nick)); - memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - HERMES_BYTES_TO_RECLEN(strlen(priv->nick) + 2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting nickname\n", - dev->name, err); - return err; - } - - /* Set AP density */ - if (priv->has_sensitivity) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSYSTEMSCALE, - priv->ap_density); - if (err) { - printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " - "Disabling sensitivity control\n", - dev->name, err); - - priv->has_sensitivity = 0; - } - } - - /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting RTS threshold\n", - dev->name, err); - return err; - } - - /* Set fragmentation threshold or MWO robustness */ - if (priv->has_mwo) - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - priv->mwo_robust); - else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting fragmentation\n", - dev->name, err); - return err; - } - - /* Set bitrate */ - err = __orinoco_hw_set_bitrate(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting bitrate\n", - dev->name, err); - return err; - } - - /* Set power management */ - if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMENABLED, - priv->pm_on); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMULTICASTRECEIVE, - priv->pm_mcast); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - priv->pm_period); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - } - - /* Set preamble - only for Symbol so far... */ - if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - priv->preamble); - if (err) { - printk(KERN_ERR "%s: Error %d setting preamble\n", - dev->name, err); - return err; - } - } - - /* Set up encryption */ - if (priv->has_wep || priv->has_wpa) { - err = __orinoco_hw_setup_enc(priv); - if (err) { - printk(KERN_ERR "%s: Error %d activating encryption\n", - dev->name, err); - return err; - } - } - - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - /* Enable monitor mode */ - dev->type = ARPHRD_IEEE80211; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_MONITOR, 0, NULL); - } else { - /* Disable monitor mode */ - dev->type = ARPHRD_ETHER; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_STOP, 0, NULL); - } - if (err) - return err; - - /* Reset promiscuity / multicast*/ - priv->promiscuous = 0; - priv->mc_count = 0; - - /* Record mode change */ - wdev->iftype = priv->iw_mode; - - return 0; -} - -/* Get tsc from the firmware */ -int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) -{ - struct hermes *hw = &priv->hw; - int err = 0; - u8 tsc_arr[4][ORINOCO_SEQ_LEN]; - - if ((key < 0) || (key >= 4)) - return -EINVAL; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV, - sizeof(tsc_arr), NULL, &tsc_arr); - if (!err) - memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0])); - - return err; -} - -int __orinoco_hw_set_bitrate(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int ratemode = priv->bitratemode; - int err = 0; - - if (ratemode >= BITRATE_TABLE_SIZE) { - printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", - priv->ndev->name, ratemode); - return -EINVAL; - } - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[ratemode].agere_txratectrl); - break; - case FIRMWARE_TYPE_INTERSIL: - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[ratemode].intersil_txratectrl); - break; - default: - BUG(); - } - - return err; -} - -int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate) -{ - struct hermes *hw = &priv->hw; - int i; - int err = 0; - u16 val; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CURRENTTXRATE, &val); - if (err) - return err; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ - /* Note : in Lucent firmware, the return value of - * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, - * and therefore is totally different from the - * encoding of HERMES_RID_CNFTXRATECONTROL. - * Don't forget that 6Mb/s is really 5.5Mb/s */ - if (val == 6) - *bitrate = 5500000; - else - *bitrate = val * 1000000; - break; - case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - for (i = 0; i < BITRATE_TABLE_SIZE; i++) - if (bitrate_table[i].intersil_txratectrl == val) { - *bitrate = bitrate_table[i].bitrate * 100000; - break; - } - - if (i >= BITRATE_TABLE_SIZE) { - printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", - priv->ndev->name, val); - err = -EIO; - } - - break; - default: - BUG(); - } - - return err; -} - -/* Set fixed AP address */ -int __orinoco_hw_set_wap(struct orinoco_private *priv) -{ - int roaming_flag; - int err = 0; - struct hermes *hw = &priv->hw; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* not supported */ - break; - case FIRMWARE_TYPE_INTERSIL: - if (priv->bssid_fixed) - roaming_flag = 2; - else - roaming_flag = 1; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFROAMINGMODE, - roaming_flag); - break; - case FIRMWARE_TYPE_SYMBOL: - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFMANDATORYBSSID_SYMBOL, - &priv->desired_bssid); - break; - } - return err; -} - -/* Change the WEP keys and/or the current keys. Can be called - * either from __orinoco_hw_setup_enc() or directly from - * orinoco_ioctl_setiwencode(). In the later case the association - * with the AP is not broken (if the firmware can handle it), - * which is needed for 802.1x implementations. */ -int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err = 0; - int i; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - { - struct orinoco_key keys[ORINOCO_MAX_KEYS]; - - memset(&keys, 0, sizeof(keys)); - for (i = 0; i < ORINOCO_MAX_KEYS; i++) { - int len = min(priv->keys[i].key_len, - ORINOCO_MAX_KEY_SIZE); - memcpy(&keys[i].data, priv->keys[i].key, len); - if (len > SMALL_KEY_SIZE) - keys[i].len = cpu_to_le16(LARGE_KEY_SIZE); - else if (len > 0) - keys[i].len = cpu_to_le16(SMALL_KEY_SIZE); - else - keys[i].len = cpu_to_le16(0); - } - - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFWEPKEYS_AGERE, - &keys); - if (err) - return err; - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXKEY_AGERE, - priv->tx_key); - if (err) - return err; - break; - } - case FIRMWARE_TYPE_INTERSIL: - case FIRMWARE_TYPE_SYMBOL: - { - int keylen; - - /* Force uniform key length to work around - * firmware bugs */ - keylen = priv->keys[priv->tx_key].key_len; - - if (keylen > LARGE_KEY_SIZE) { - printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", - priv->ndev->name, priv->tx_key, keylen); - return -E2BIG; - } else if (keylen > SMALL_KEY_SIZE) - keylen = LARGE_KEY_SIZE; - else if (keylen > 0) - keylen = SMALL_KEY_SIZE; - else - keylen = 0; - - /* Write all 4 keys */ - for (i = 0; i < ORINOCO_MAX_KEYS; i++) { - u8 key[LARGE_KEY_SIZE] = { 0 }; - - memcpy(key, priv->keys[i].key, - priv->keys[i].key_len); - - err = hw->ops->write_ltv(hw, USER_BAP, - HERMES_RID_CNFDEFAULTKEY0 + i, - HERMES_BYTES_TO_RECLEN(keylen), - key); - if (err) - return err; - } - - /* Write the index of the key used in transmission */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPDEFAULTKEYID, - priv->tx_key); - if (err) - return err; - } - break; - } - - return 0; -} - -int __orinoco_hw_setup_enc(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err = 0; - int master_wep_flag; - int auth_flag; - int enc_flag; - - /* Setup WEP keys */ - if (priv->encode_alg == ORINOCO_ALG_WEP) - __orinoco_hw_setup_wepkeys(priv); - - if (priv->wep_restrict) - auth_flag = HERMES_AUTH_SHARED_KEY; - else - auth_flag = HERMES_AUTH_OPEN; - - if (priv->wpa_enabled) - enc_flag = 2; - else if (priv->encode_alg == ORINOCO_ALG_WEP) - enc_flag = 1; - else - enc_flag = 0; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->encode_alg == ORINOCO_ALG_WEP) { - /* Enable the shared-key authentication. */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFAUTHENTICATION_AGERE, - auth_flag); - if (err) - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPENABLED_AGERE, - enc_flag); - if (err) - return err; - - if (priv->has_wpa) { - /* Set WPA key management */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, - priv->key_mgmt); - if (err) - return err; - } - - break; - - case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->encode_alg == ORINOCO_ALG_WEP) { - if (priv->wep_restrict || - (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) - master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | - HERMES_WEP_EXCL_UNENCRYPTED; - else - master_wep_flag = HERMES_WEP_PRIVACY_INVOKED; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFAUTHENTICATION, - auth_flag); - if (err) - return err; - } else - master_wep_flag = 0; - - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) - master_wep_flag |= HERMES_WEP_HOST_DECRYPT; - - /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPFLAGS_INTERSIL, - master_wep_flag); - if (err) - return err; - - break; - } - - return 0; -} - -/* key must be 32 bytes, including the tx and rx MIC keys. - * rsc must be NULL or up to 8 bytes - * tsc must be NULL or up to 8 bytes - */ -int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, const u8 *key, size_t key_len, - const u8 *rsc, size_t rsc_len, - const u8 *tsc, size_t tsc_len) -{ - struct { - __le16 idx; - u8 rsc[ORINOCO_SEQ_LEN]; - struct { - u8 key[TKIP_KEYLEN]; - u8 tx_mic[MIC_KEYLEN]; - u8 rx_mic[MIC_KEYLEN]; - } tkip; - u8 tsc[ORINOCO_SEQ_LEN]; - } __packed buf; - struct hermes *hw = &priv->hw; - int ret; - int err; - int k; - u16 xmitting; - - key_idx &= 0x3; - - if (set_tx) - key_idx |= 0x8000; - - buf.idx = cpu_to_le16(key_idx); - if (key_len != sizeof(buf.tkip)) - return -EINVAL; - memcpy(&buf.tkip, key, sizeof(buf.tkip)); - - if (rsc_len > sizeof(buf.rsc)) - rsc_len = sizeof(buf.rsc); - - if (tsc_len > sizeof(buf.tsc)) - tsc_len = sizeof(buf.tsc); - - memset(buf.rsc, 0, sizeof(buf.rsc)); - memset(buf.tsc, 0, sizeof(buf.tsc)); - - if (rsc != NULL) - memcpy(buf.rsc, rsc, rsc_len); - - if (tsc != NULL) - memcpy(buf.tsc, tsc, tsc_len); - else - buf.tsc[4] = 0x10; - - /* Wait up to 100ms for tx queue to empty */ - for (k = 100; k > 0; k--) { - udelay(1000); - ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, - &xmitting); - if (ret || !xmitting) - break; - } - - if (k == 0) - ret = -ETIMEDOUT; - - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, - &buf); - - return ret ? ret : err; -} - -int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx) -{ - struct hermes *hw = &priv->hw; - int err; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, - key_idx); - if (err) - printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", - priv->ndev->name, err, key_idx); - return err; -} - -int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, - struct net_device *dev, - int mc_count, int promisc) -{ - struct hermes *hw = &priv->hw; - int err = 0; - - if (promisc != priv->promiscuous) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPROMISCUOUSMODE, - promisc); - if (err) { - printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", - priv->ndev->name, err); - } else - priv->promiscuous = promisc; - } - - /* If we're not in promiscuous mode, then we need to set the - * group address if either we want to multicast, or if we were - * multicasting and want to stop */ - if (!promisc && (mc_count || priv->mc_count)) { - struct netdev_hw_addr *ha; - struct hermes_multicast mclist; - int i = 0; - - netdev_for_each_mc_addr(ha, dev) { - if (i == mc_count) - break; - memcpy(mclist.addr[i++], ha->addr, ETH_ALEN); - } - - err = hw->ops->write_ltv(hw, USER_BAP, - HERMES_RID_CNFGROUPADDRESSES, - HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN), - &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - priv->ndev->name, err); - else - priv->mc_count = mc_count; - } - return err; -} - -/* Return : < 0 -> error code ; >= 0 -> length */ -int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE + 1]) -{ - struct hermes *hw = &priv->hw; - int err = 0; - struct hermes_idstring essidbuf; - char *p = (char *)(&essidbuf.val); - int len; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (strlen(priv->desired_essid) > 0) { - /* We read the desired SSID from the hardware rather - than from priv->desired_essid, just in case the - firmware is allowed to change it on us. I'm not - sure about this */ - /* My guess is that the OWNSSID should always be whatever - * we set to the card, whereas CURRENT_SSID is the one that - * may change... - Jean II */ - u16 rid; - - *active = 1; - - rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : - HERMES_RID_CNFDESIREDSSID; - - err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), - NULL, &essidbuf); - if (err) - goto fail_unlock; - } else { - *active = 0; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, - sizeof(essidbuf), NULL, &essidbuf); - if (err) - goto fail_unlock; - } - - len = le16_to_cpu(essidbuf.len); - BUG_ON(len > IW_ESSID_MAX_SIZE); - - memset(buf, 0, IW_ESSID_MAX_SIZE); - memcpy(buf, p, len); - err = len; - - fail_unlock: - orinoco_unlock(priv, &flags); - - return err; -} - -int orinoco_hw_get_freq(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err = 0; - u16 channel; - int freq = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, - &channel); - if (err) - goto out; - - /* Intersil firmware 1.3.5 returns 0 when the interface is down */ - if (channel == 0) { - err = -EBUSY; - goto out; - } - - if ((channel < 1) || (channel > NUM_CHANNELS)) { - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", - priv->ndev->name, channel); - err = -EBUSY; - goto out; - - } - freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); - - out: - orinoco_unlock(priv, &flags); - - if (err > 0) - err = -EBUSY; - return err ? err : freq; -} - -int orinoco_hw_get_bitratelist(struct orinoco_private *priv, - int *numrates, s32 *rates, int max) -{ - struct hermes *hw = &priv->hw; - struct hermes_idstring list; - unsigned char *p = (unsigned char *)&list.val; - int err = 0; - int num; - int i; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, - sizeof(list), NULL, &list); - orinoco_unlock(priv, &flags); - - if (err) - return err; - - num = le16_to_cpu(list.len); - *numrates = num; - num = min(num, max); - - for (i = 0; i < num; i++) - rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ - - return 0; -} - -int orinoco_hw_trigger_scan(struct orinoco_private *priv, - const struct cfg80211_ssid *ssid) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - unsigned long flags; - int err = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Scanning with port 0 disabled would fail */ - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - - /* In monitor mode, the scan results are always empty. - * Probe responses are passed to the driver as received - * frames and could be processed in software. */ - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - err = -EOPNOTSUPP; - goto out; - } - - if (priv->has_hostscan) { - switch (priv->firmware_type) { - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN_SYMBOL, - HERMES_HOSTSCAN_SYMBOL_ONCE | - HERMES_HOSTSCAN_SYMBOL_BCAST); - break; - case FIRMWARE_TYPE_INTERSIL: { - __le16 req[3]; - - req[0] = cpu_to_le16(0x3fff); /* All channels */ - req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ - req[2] = 0; /* Any ESSID */ - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN, &req); - break; - } - case FIRMWARE_TYPE_AGERE: - if (ssid->ssid_len > 0) { - struct hermes_idstring idbuf; - size_t len = ssid->ssid_len; - - idbuf.len = cpu_to_le16(len); - memcpy(idbuf.val, ssid->ssid, len); - - err = hw->ops->write_ltv(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - HERMES_BYTES_TO_RECLEN(len + 2), - &idbuf); - } else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - 0); /* Any ESSID */ - if (err) - break; - - if (priv->has_ext_scan) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANCHANNELS2GHZ, - 0x7FFF); - if (err) - goto out; - - err = hermes_inquire(hw, - HERMES_INQ_CHANNELINFO); - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - - break; - } - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -/* Disassociate from node with BSSID addr */ -int orinoco_hw_disassociate(struct orinoco_private *priv, - u8 *addr, u16 reason_code) -{ - struct hermes *hw = &priv->hw; - int err; - - struct { - u8 addr[ETH_ALEN]; - __le16 reason_code; - } __packed buf; - - /* Currently only supported by WPA enabled Agere fw */ - if (!priv->has_wpa) - return -EOPNOTSUPP; - - memcpy(buf.addr, addr, ETH_ALEN); - buf.reason_code = cpu_to_le16(reason_code); - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFDISASSOCIATE, - &buf); - return err; -} - -int orinoco_hw_get_current_bssid(struct orinoco_private *priv, - u8 *addr) -{ - struct hermes *hw = &priv->hw; - int err; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, addr); - - return err; -} diff --git a/drivers/net/wireless/intersil/orinoco/hw.h b/drivers/net/wireless/intersil/orinoco/hw.h deleted file mode 100644 index da5804dbdf..0000000000 --- a/drivers/net/wireless/intersil/orinoco/hw.h +++ /dev/null @@ -1,60 +0,0 @@ -/* Encapsulate basic setting changes on Hermes hardware - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_HW_H_ -#define _ORINOCO_HW_H_ - -#include <linux/types.h> -#include <linux/wireless.h> -#include <net/cfg80211.h> - -/* Hardware BAPs */ -#define USER_BAP 0 -#define IRQ_BAP 1 - -/* WEP key sizes */ -#define SMALL_KEY_SIZE 5 -#define LARGE_KEY_SIZE 13 - -/* Number of supported channels */ -#define NUM_CHANNELS 14 - -/* Forward declarations */ -struct orinoco_private; - -int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name, - size_t fw_name_len, u32 *hw_ver); -int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr); -int orinoco_hw_allocate_fid(struct orinoco_private *priv); -int orinoco_get_bitratemode(int bitrate, int automatic); -void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); - -int orinoco_hw_program_rids(struct orinoco_private *priv); -int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc); -int __orinoco_hw_set_bitrate(struct orinoco_private *priv); -int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate); -int __orinoco_hw_set_wap(struct orinoco_private *priv); -int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); -int __orinoco_hw_setup_enc(struct orinoco_private *priv); -int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, const u8 *key, size_t key_len, - const u8 *rsc, size_t rsc_len, - const u8 *tsc, size_t tsc_len); -int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); -int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, - struct net_device *dev, - int mc_count, int promisc); -int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE + 1]); -int orinoco_hw_get_freq(struct orinoco_private *priv); -int orinoco_hw_get_bitratelist(struct orinoco_private *priv, - int *numrates, s32 *rates, int max); -int orinoco_hw_trigger_scan(struct orinoco_private *priv, - const struct cfg80211_ssid *ssid); -int orinoco_hw_disassociate(struct orinoco_private *priv, - u8 *addr, u16 reason_code); -int orinoco_hw_get_current_bssid(struct orinoco_private *priv, - u8 *addr); - -#endif /* _ORINOCO_HW_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/main.c b/drivers/net/wireless/intersil/orinoco/main.c deleted file mode 100644 index 7df88d20ff..0000000000 --- a/drivers/net/wireless/intersil/orinoco/main.c +++ /dev/null @@ -1,2414 +0,0 @@ -/* main.c - (formerly known as dldwd_cs.c, orinoco_cs.c and orinoco.c) - * - * A driver for Hermes or Prism 2 chipset based PCMCIA wireless - * adaptors, with Lucent/Agere, Intersil or Symbol firmware. - * - * Current maintainers (as of 29 September 2003) are: - * Pavel Roskin <proski AT gnu.org> - * and David Gibson <hermes AT gibson.dropbear.id.au> - * - * (C) Copyright David Gibson, IBM Corporation 2001-2003. - * Copyright (C) 2000 David Gibson, Linuxcare Australia. - * With some help from : - * Copyright (C) 2001 Jean Tourrilhes, HP Labs - * Copyright (C) 2001 Benjamin Herrenschmidt - * - * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 - * - * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy - * AT fasta.fh-dortmund.de> - * http://www.stud.fh-dortmund.de/~andy/wvlan/ - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * <dahinds AT users.sourceforge.net>. Portions created by David - * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights - * Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. */ - -/* - * TODO - * o Handle de-encapsulation within network layer, provide 802.11 - * headers (patch from Thomas 'Dent' Mirlacher) - * o Fix possible races in SPY handling. - * o Disconnect wireless extensions from fundamental configuration. - * o (maybe) Software WEP support (patch from Stano Meduna). - * o (maybe) Use multiple Tx buffers - driver handling queue - * rather than firmware. - */ - -/* Locking and synchronization: - * - * The basic principle is that everything is serialized through a - * single spinlock, priv->lock. The lock is used in user, bh and irq - * context, so when taken outside hardirq context it should always be - * taken with interrupts disabled. The lock protects both the - * hardware and the struct orinoco_private. - * - * Another flag, priv->hw_unavailable indicates that the hardware is - * unavailable for an extended period of time (e.g. suspended, or in - * the middle of a hard reset). This flag is protected by the - * spinlock. All code which touches the hardware should check the - * flag after taking the lock, and if it is set, give up on whatever - * they are doing and drop the lock again. The orinoco_lock() - * function handles this (it unlocks and returns -EBUSY if - * hw_unavailable is non-zero). - */ - -#define DRIVER_NAME "orinoco" - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/suspend.h> -#include <linux/if_arp.h> -#include <linux/wireless.h> -#include <linux/ieee80211.h> -#include <net/iw_handler.h> -#include <net/cfg80211.h> - -#include "hermes_rid.h" -#include "hermes_dld.h" -#include "hw.h" -#include "scan.h" -#include "mic.h" -#include "fw.h" -#include "wext.h" -#include "cfg.h" -#include "main.h" - -#include "orinoco.h" - -/********************************************************************/ -/* Module information */ -/********************************************************************/ - -MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & " - "David Gibson <hermes@gibson.dropbear.id.au>"); -MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based " - "and similar wireless cards"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Level of debugging. Used in the macros in orinoco.h */ -#ifdef ORINOCO_DEBUG -int orinoco_debug = ORINOCO_DEBUG; -EXPORT_SYMBOL(orinoco_debug); -module_param(orinoco_debug, int, 0644); -MODULE_PARM_DESC(orinoco_debug, "Debug level"); -#endif - -static bool suppress_linkstatus; /* = 0 */ -module_param(suppress_linkstatus, bool, 0644); -MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes"); - -static int ignore_disconnect; /* = 0 */ -module_param(ignore_disconnect, int, 0644); -MODULE_PARM_DESC(ignore_disconnect, - "Don't report lost link to the network layer"); - -int force_monitor; /* = 0 */ -module_param(force_monitor, int, 0644); -MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); - -/********************************************************************/ -/* Internal constants */ -/********************************************************************/ - -/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ -static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; -#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) - -#define ORINOCO_MIN_MTU 256 -#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) - -#define MAX_IRQLOOPS_PER_IRQ 10 -#define MAX_IRQLOOPS_PER_JIFFY (20000 / HZ) /* Based on a guestimate of - * how many events the - * device could - * legitimately generate */ - -#define DUMMY_FID 0xFFFF - -/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ - HERMES_MAX_MULTICAST : 0)*/ -#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) - -#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \ - | HERMES_EV_TX | HERMES_EV_TXEXC \ - | HERMES_EV_WTERR | HERMES_EV_INFO \ - | HERMES_EV_INFDROP) - -/********************************************************************/ -/* Data types */ -/********************************************************************/ - -/* Beginning of the Tx descriptor, used in TxExc handling */ -struct hermes_txexc_data { - struct hermes_tx_descriptor desc; - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; -} __packed; - -/* Rx frame header except compatibility 802.3 header */ -struct hermes_rx_descriptor { - /* Control */ - __le16 status; - __le32 time; - u8 silence; - u8 signal; - u8 rate; - u8 rxflow; - __le32 reserved; - - /* 802.11 header */ - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 addr4[ETH_ALEN]; - - /* Data length */ - __le16 data_len; -} __packed; - -struct orinoco_rx_data { - struct hermes_rx_descriptor *desc; - struct sk_buff *skb; - struct list_head list; -}; - -struct orinoco_scan_data { - void *buf; - size_t len; - int type; - struct list_head list; -}; - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int __orinoco_set_multicast_list(struct net_device *dev); -static int __orinoco_up(struct orinoco_private *priv); -static int __orinoco_down(struct orinoco_private *priv); -static int __orinoco_commit(struct orinoco_private *priv); - -/********************************************************************/ -/* Internal helper functions */ -/********************************************************************/ - -void set_port_type(struct orinoco_private *priv) -{ - switch (priv->iw_mode) { - case NL80211_IFTYPE_STATION: - priv->port_type = 1; - priv->createibss = 0; - break; - case NL80211_IFTYPE_ADHOC: - if (priv->prefer_port3) { - priv->port_type = 3; - priv->createibss = 0; - } else { - priv->port_type = priv->ibss_port; - priv->createibss = 1; - } - break; - case NL80211_IFTYPE_MONITOR: - priv->port_type = 3; - priv->createibss = 0; - break; - default: - printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", - priv->ndev->name); - } -} - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -int orinoco_open(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int err; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = __orinoco_up(priv); - - if (!err) - priv->open = 1; - - orinoco_unlock(priv, &flags); - - return err; -} -EXPORT_SYMBOL(orinoco_open); - -int orinoco_stop(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - - /* We mustn't use orinoco_lock() here, because we need to be - able to close the interface even if hw_unavailable is set - (e.g. as we're released after a PC Card removal) */ - orinoco_lock_irq(priv); - - priv->open = 0; - - err = __orinoco_down(priv); - - orinoco_unlock_irq(priv); - - return err; -} -EXPORT_SYMBOL(orinoco_stop); - -void orinoco_set_multicast_list(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " - "called when hw_unavailable\n", dev->name); - return; - } - - __orinoco_set_multicast_list(dev); - orinoco_unlock(priv, &flags); -} -EXPORT_SYMBOL(orinoco_set_multicast_list); - -int orinoco_change_mtu(struct net_device *dev, int new_mtu) -{ - struct orinoco_private *priv = ndev_priv(dev); - - /* MTU + encapsulation + header length */ - if ((new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) > - (priv->nicbuf_size - ETH_HLEN)) - return -EINVAL; - - dev->mtu = new_mtu; - - return 0; -} -EXPORT_SYMBOL(orinoco_change_mtu); - -/********************************************************************/ -/* Tx path */ -/********************************************************************/ - -/* Add encapsulation and MIC to the existing SKB. - * The main xmit routine will then send the whole lot to the card. - * Need 8 bytes headroom - * Need 8 bytes tailroom - * - * With encapsulated ethernet II frame - * -------- - * 803.3 header (14 bytes) - * dst[6] - * -------- src[6] - * 803.3 header (14 bytes) len[2] - * dst[6] 803.2 header (8 bytes) - * src[6] encaps[6] - * len[2] <- leave alone -> len[2] - * -------- -------- <-- 0 - * Payload Payload - * ... ... - * - * -------- -------- - * MIC (8 bytes) - * -------- - * - * returns 0 on success, -ENOMEM on error. - */ -int orinoco_process_xmit_skb(struct sk_buff *skb, - struct net_device *dev, - struct orinoco_private *priv, - int *tx_control, - u8 *mic_buf) -{ - struct orinoco_tkip_key *key; - struct ethhdr *eh; - int do_mic; - - key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key; - - do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) && - (key != NULL)); - - if (do_mic) - *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | - HERMES_TXCTRL_MIC; - - eh = (struct ethhdr *)skb->data; - - /* Encapsulate Ethernet-II frames */ - if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ - struct header_struct { - struct ethhdr eth; /* 802.3 header */ - u8 encap[6]; /* 802.2 header */ - } __packed hdr; - int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN); - - if (skb_headroom(skb) < ENCAPS_OVERHEAD) { - if (net_ratelimit()) - printk(KERN_ERR - "%s: Not enough headroom for 802.2 headers %d\n", - dev->name, skb_headroom(skb)); - return -ENOMEM; - } - - /* Fill in new header */ - memcpy(&hdr.eth, eh, 2 * ETH_ALEN); - hdr.eth.h_proto = htons(len); - memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); - - /* Make room for the new header, and copy it in */ - eh = skb_push(skb, ENCAPS_OVERHEAD); - memcpy(eh, &hdr, sizeof(hdr)); - } - - /* Calculate Michael MIC */ - if (do_mic) { - size_t len = skb->len - ETH_HLEN; - u8 *mic = &mic_buf[0]; - - /* Have to write to an even address, so copy the spare - * byte across */ - if (skb->len % 2) { - *mic = skb->data[skb->len - 1]; - mic++; - } - - orinoco_mic(priv->tx_tfm_mic, key->tx_mic, - eh->h_dest, eh->h_source, 0 /* priority */, - skb->data + ETH_HLEN, - len, mic); - } - - return 0; -} -EXPORT_SYMBOL(orinoco_process_xmit_skb); - -static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct hermes *hw = &priv->hw; - int err = 0; - u16 txfid = priv->txfid; - int tx_control; - unsigned long flags; - u8 mic_buf[MICHAEL_MIC_LEN + 1]; - - if (!netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (netif_queue_stopped(dev)) { - printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (!netif_carrier_ok(dev) || - (priv->iw_mode == NL80211_IFTYPE_MONITOR)) { - /* Oops, the firmware hasn't established a connection, - silently drop the packet (this seems to be the - safest approach). */ - goto drop; - } - - /* Check packet length */ - if (skb->len < ETH_HLEN) - goto drop; - - tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - - err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control, - &mic_buf[0]); - if (err) - goto drop; - - if (priv->has_alt_txcntl) { - /* WPA enabled firmwares have tx_cntl at the end of - * the 802.11 header. So write zeroed descriptor and - * 802.11 header at the same time - */ - char desc[HERMES_802_3_OFFSET]; - __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET]; - - memset(&desc, 0, sizeof(desc)); - - *txcntl = cpu_to_le16(tx_control); - err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), - txfid, 0); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing Tx " - "descriptor to BAP\n", dev->name, err); - goto busy; - } - } else { - struct hermes_tx_descriptor desc; - - memset(&desc, 0, sizeof(desc)); - - desc.tx_control = cpu_to_le16(tx_control); - err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), - txfid, 0); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing Tx " - "descriptor to BAP\n", dev->name, err); - goto busy; - } - - /* Clear the 802.11 header and data length fields - some - * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused - * if this isn't done. */ - hermes_clear_words(hw, HERMES_DATA0, - HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); - } - - err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len, - txfid, HERMES_802_3_OFFSET); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet to BAP\n", - dev->name, err); - goto busy; - } - - if (tx_control & HERMES_TXCTRL_MIC) { - size_t offset = HERMES_802_3_OFFSET + skb->len; - size_t len = MICHAEL_MIC_LEN; - - if (offset % 2) { - offset--; - len++; - } - err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len, - txfid, offset); - if (err) { - printk(KERN_ERR "%s: Error %d writing MIC to BAP\n", - dev->name, err); - goto busy; - } - } - - /* Finally, we actually initiate the send */ - netif_stop_queue(dev); - - err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, - txfid, NULL); - if (err) { - netif_start_queue(dev); - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d transmitting packet\n", - dev->name, err); - goto busy; - } - - stats->tx_bytes += HERMES_802_3_OFFSET + skb->len; - goto ok; - - drop: - stats->tx_errors++; - stats->tx_dropped++; - - ok: - orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - - busy: - if (err == -EIO) - schedule_work(&priv->reset_work); - orinoco_unlock(priv, &flags); - return NETDEV_TX_BUSY; -} - -static void __orinoco_ev_alloc(struct net_device *dev, struct hermes *hw) -{ - struct orinoco_private *priv = ndev_priv(dev); - u16 fid = hermes_read_regn(hw, ALLOCFID); - - if (fid != priv->txfid) { - if (fid != DUMMY_FID) - printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", - dev->name, fid); - return; - } - - hermes_write_regn(hw, ALLOCFID, DUMMY_FID); -} - -static void __orinoco_ev_tx(struct net_device *dev, struct hermes *hw) -{ - dev->stats.tx_packets++; - - netif_wake_queue(dev); - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); -} - -static void __orinoco_ev_txexc(struct net_device *dev, struct hermes *hw) -{ - struct net_device_stats *stats = &dev->stats; - u16 fid = hermes_read_regn(hw, TXCOMPLFID); - u16 status; - struct hermes_txexc_data hdr; - int err = 0; - - if (fid == DUMMY_FID) - return; /* Nothing's really happened */ - - /* Read part of the frame header - we need status and addr1 */ - err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr, - sizeof(struct hermes_txexc_data), - fid, 0); - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); - stats->tx_errors++; - - if (err) { - printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " - "(FID=%04X error %d)\n", - dev->name, fid, err); - return; - } - - DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name, - err, fid); - - /* We produce a TXDROP event only for retry or lifetime - * exceeded, because that's the only status that really mean - * that this particular node went away. - * Other errors means that *we* screwed up. - Jean II */ - status = le16_to_cpu(hdr.desc.status); - if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { - union iwreq_data wrqu; - - /* Copy 802.11 dest address. - * We use the 802.11 header because the frame may - * not be 802.3 or may be mangled... - * In Ad-Hoc mode, it will be the node address. - * In managed mode, it will be most likely the AP addr - * User space will figure out how to convert it to - * whatever it needs (IP address or else). - * - Jean II */ - memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); - } - - netif_wake_queue(dev); -} - -void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct hermes *hw = &priv->hw; - - printk(KERN_WARNING "%s: Tx timeout! " - "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", - dev->name, hermes_read_regn(hw, ALLOCFID), - hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); - - stats->tx_errors++; - - schedule_work(&priv->reset_work); -} -EXPORT_SYMBOL(orinoco_tx_timeout); - -/********************************************************************/ -/* Rx path (data frames) */ -/********************************************************************/ - -/* Does the frame have a SNAP header indicating it should be - * de-encapsulated to Ethernet-II? */ -static inline int is_ethersnap(void *_hdr) -{ - u8 *hdr = _hdr; - - /* We de-encapsulate all packets which, a) have SNAP headers - * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header - * and where b) the OUI of the SNAP header is 00:00:00 or - * 00:00:f8 - we need both because different APs appear to use - * different OUIs for some reason */ - return (memcmp(hdr, &encaps_hdr, 5) == 0) - && ((hdr[5] == 0x00) || (hdr[5] == 0xf8)); -} - -static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, - int level, int noise) -{ - struct iw_quality wstats; - wstats.level = level - 0x95; - wstats.noise = noise - 0x95; - wstats.qual = (level > noise) ? (level - noise) : 0; - wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - /* Update spy records */ - wireless_spy_update(dev, mac, &wstats); -} - -static void orinoco_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct hermes_rx_descriptor *desc) -{ - struct orinoco_private *priv = ndev_priv(dev); - - /* Using spy support with lots of Rx packets, like in an - * infrastructure (AP), will really slow down everything, because - * the MAC address must be compared to each entry of the spy list. - * If the user really asks for it (set some address in the - * spy list), we do it, but he will pay the price. - * Note that to get here, you need both WIRELESS_SPY - * compiled in AND some addresses in the list !!! - */ - /* Note : gcc will optimise the whole section away if - * WIRELESS_SPY is not defined... - Jean II */ - if (SPY_NUMBER(priv)) { - orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN, - desc->signal, desc->silence); - } -} - -/* - * orinoco_rx_monitor - handle received monitor frames. - * - * Arguments: - * dev network device - * rxfid received FID - * desc rx descriptor of the frame - * - * Call context: interrupt - */ -static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, - struct hermes_rx_descriptor *desc) -{ - u32 hdrlen = 30; /* return full header by default */ - u32 datalen = 0; - u16 fc; - int err; - int len; - struct sk_buff *skb; - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct hermes *hw = &priv->hw; - - len = le16_to_cpu(desc->data_len); - - /* Determine the size of the header and the data */ - fc = le16_to_cpu(desc->frame_ctl); - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_TODS) - && (fc & IEEE80211_FCTL_FROMDS)) - hdrlen = 30; - else - hdrlen = 24; - datalen = len; - break; - case IEEE80211_FTYPE_MGMT: - hdrlen = 24; - datalen = len; - break; - case IEEE80211_FTYPE_CTL: - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PSPOLL: - case IEEE80211_STYPE_RTS: - case IEEE80211_STYPE_CFEND: - case IEEE80211_STYPE_CFENDACK: - hdrlen = 16; - break; - case IEEE80211_STYPE_CTS: - case IEEE80211_STYPE_ACK: - hdrlen = 10; - break; - } - break; - default: - /* Unknown frame type */ - break; - } - - /* sanity check the length */ - if (datalen > IEEE80211_MAX_DATA_LEN + 12) { - printk(KERN_DEBUG "%s: oversized monitor frame, " - "data length = %d\n", dev->name, datalen); - stats->rx_length_errors++; - goto update_stats; - } - - skb = dev_alloc_skb(hdrlen + datalen); - if (!skb) { - printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n", - dev->name); - goto update_stats; - } - - /* Copy the 802.11 header to the skb */ - skb_put_data(skb, &(desc->frame_ctl), hdrlen); - skb_reset_mac_header(skb); - - /* If any, copy the data from the card to the skb */ - if (datalen > 0) { - err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen), - ALIGN(datalen, 2), rxfid, - HERMES_802_2_OFFSET); - if (err) { - printk(KERN_ERR "%s: error %d reading monitor frame\n", - dev->name, err); - goto drop; - } - } - - skb->dev = dev; - skb->ip_summed = CHECKSUM_NONE; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = cpu_to_be16(ETH_P_802_2); - - stats->rx_packets++; - stats->rx_bytes += skb->len; - - netif_rx(skb); - return; - - drop: - dev_kfree_skb_irq(skb); - update_stats: - stats->rx_errors++; - stats->rx_dropped++; -} - -void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct iw_statistics *wstats = &priv->wstats; - struct sk_buff *skb = NULL; - u16 rxfid, status; - int length; - struct hermes_rx_descriptor *desc; - struct orinoco_rx_data *rx_data; - int err; - - desc = kmalloc(sizeof(*desc), GFP_ATOMIC); - if (!desc) - goto update_stats; - - rxfid = hermes_read_regn(hw, RXFID); - - err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc), - rxfid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading Rx descriptor. " - "Frame dropped.\n", dev->name, err); - goto update_stats; - } - - status = le16_to_cpu(desc->status); - - if (status & HERMES_RXSTAT_BADCRC) { - DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", - dev->name); - stats->rx_crc_errors++; - goto update_stats; - } - - /* Handle frames in monitor mode */ - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - orinoco_rx_monitor(dev, rxfid, desc); - goto out; - } - - if (status & HERMES_RXSTAT_UNDECRYPTABLE) { - DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", - dev->name); - wstats->discard.code++; - goto update_stats; - } - - length = le16_to_cpu(desc->data_len); - - /* Sanity checks */ - if (length < 3) { /* No for even an 802.2 LLC header */ - /* At least on Symbol firmware with PCF we get quite a - lot of these legitimately - Poll frames with no - data. */ - goto out; - } - if (length > IEEE80211_MAX_DATA_LEN) { - printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", - dev->name, length); - stats->rx_length_errors++; - goto update_stats; - } - - /* Payload size does not include Michael MIC. Increase payload - * size to read it together with the data. */ - if (status & HERMES_RXSTAT_MIC) - length += MICHAEL_MIC_LEN; - - /* We need space for the packet data itself, plus an ethernet - header, plus 2 bytes so we can align the IP header on a - 32bit boundary, plus 1 byte so we can read in odd length - packets from the card, which has an IO granularity of 16 - bits */ - skb = dev_alloc_skb(length + ETH_HLEN + 2 + 1); - if (!skb) { - printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", - dev->name); - goto update_stats; - } - - /* We'll prepend the header, so reserve space for it. The worst - case is no decapsulation, when 802.3 header is prepended and - nothing is removed. 2 is for aligning the IP header. */ - skb_reserve(skb, ETH_HLEN + 2); - - err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length), - ALIGN(length, 2), rxfid, - HERMES_802_2_OFFSET); - if (err) { - printk(KERN_ERR "%s: error %d reading frame. " - "Frame dropped.\n", dev->name, err); - goto drop; - } - - /* Add desc and skb to rx queue */ - rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC); - if (!rx_data) - goto drop; - - rx_data->desc = desc; - rx_data->skb = skb; - list_add_tail(&rx_data->list, &priv->rx_list); - tasklet_schedule(&priv->rx_tasklet); - - return; - -drop: - dev_kfree_skb_irq(skb); -update_stats: - stats->rx_errors++; - stats->rx_dropped++; -out: - kfree(desc); -} -EXPORT_SYMBOL(__orinoco_ev_rx); - -static void orinoco_rx(struct net_device *dev, - struct hermes_rx_descriptor *desc, - struct sk_buff *skb) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - u16 status, fc; - int length; - struct ethhdr *hdr; - - status = le16_to_cpu(desc->status); - length = le16_to_cpu(desc->data_len); - fc = le16_to_cpu(desc->frame_ctl); - - /* Calculate and check MIC */ - if (status & HERMES_RXSTAT_MIC) { - struct orinoco_tkip_key *key; - int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> - HERMES_MIC_KEY_ID_SHIFT); - u8 mic[MICHAEL_MIC_LEN]; - u8 *rxmic; - u8 *src = (fc & IEEE80211_FCTL_FROMDS) ? - desc->addr3 : desc->addr2; - - /* Extract Michael MIC from payload */ - rxmic = skb->data + skb->len - MICHAEL_MIC_LEN; - - skb_trim(skb, skb->len - MICHAEL_MIC_LEN); - length -= MICHAEL_MIC_LEN; - - key = (struct orinoco_tkip_key *) priv->keys[key_id].key; - - if (!key) { - printk(KERN_WARNING "%s: Received encrypted frame from " - "%pM using key %i, but key is not installed\n", - dev->name, src, key_id); - goto drop; - } - - orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src, - 0, /* priority or QoS? */ - skb->data, skb->len, &mic[0]); - - if (memcmp(mic, rxmic, - MICHAEL_MIC_LEN)) { - union iwreq_data wrqu; - struct iw_michaelmicfailure wxmic; - - printk(KERN_WARNING "%s: " - "Invalid Michael MIC in data frame from %pM, " - "using key %i\n", - dev->name, src, key_id); - - /* TODO: update stats */ - - /* Notify userspace */ - memset(&wxmic, 0, sizeof(wxmic)); - wxmic.flags = key_id & IW_MICFAILURE_KEY_ID; - wxmic.flags |= (desc->addr1[0] & 1) ? - IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE; - wxmic.src_addr.sa_family = ARPHRD_ETHER; - memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN); - - (void) orinoco_hw_get_tkip_iv(priv, key_id, - &wxmic.tsc[0]); - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = sizeof(wxmic); - wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, - (char *) &wxmic); - - goto drop; - } - } - - /* Handle decapsulation - * In most cases, the firmware tell us about SNAP frames. - * For some reason, the SNAP frames sent by LinkSys APs - * are not properly recognised by most firmwares. - * So, check ourselves */ - if (length >= ENCAPS_OVERHEAD && - (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || - ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || - is_ethersnap(skb->data))) { - /* These indicate a SNAP within 802.2 LLC within - 802.11 frame which we'll need to de-encapsulate to - the original EthernetII frame. */ - hdr = skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD); - } else { - /* 802.3 frame - prepend 802.3 header as is */ - hdr = skb_push(skb, ETH_HLEN); - hdr->h_proto = htons(length); - } - memcpy(hdr->h_dest, desc->addr1, ETH_ALEN); - if (fc & IEEE80211_FCTL_FROMDS) - memcpy(hdr->h_source, desc->addr3, ETH_ALEN); - else - memcpy(hdr->h_source, desc->addr2, ETH_ALEN); - - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - if (fc & IEEE80211_FCTL_TODS) - skb->pkt_type = PACKET_OTHERHOST; - - /* Process the wireless stats if needed */ - orinoco_stat_gather(dev, skb, desc); - - /* Pass the packet to the networking stack */ - netif_rx(skb); - stats->rx_packets++; - stats->rx_bytes += length; - - return; - - drop: - dev_kfree_skb(skb); - stats->rx_errors++; - stats->rx_dropped++; -} - -static void orinoco_rx_isr_tasklet(struct tasklet_struct *t) -{ - struct orinoco_private *priv = from_tasklet(priv, t, rx_tasklet); - struct net_device *dev = priv->ndev; - struct orinoco_rx_data *rx_data, *temp; - struct hermes_rx_descriptor *desc; - struct sk_buff *skb; - unsigned long flags; - - /* orinoco_rx requires the driver lock, and we also need to - * protect priv->rx_list, so just hold the lock over the - * lot. - * - * If orinoco_lock fails, we've unplugged the card. In this - * case just abort. */ - if (orinoco_lock(priv, &flags) != 0) - return; - - /* extract desc and skb from queue */ - list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { - desc = rx_data->desc; - skb = rx_data->skb; - list_del(&rx_data->list); - kfree(rx_data); - - orinoco_rx(dev, desc, skb); - - kfree(desc); - } - - orinoco_unlock(priv, &flags); -} - -/********************************************************************/ -/* Rx path (info frames) */ -/********************************************************************/ - -static void print_linkstatus(struct net_device *dev, u16 status) -{ - char *s; - - if (suppress_linkstatus) - return; - - switch (status) { - case HERMES_LINKSTATUS_NOT_CONNECTED: - s = "Not Connected"; - break; - case HERMES_LINKSTATUS_CONNECTED: - s = "Connected"; - break; - case HERMES_LINKSTATUS_DISCONNECTED: - s = "Disconnected"; - break; - case HERMES_LINKSTATUS_AP_CHANGE: - s = "AP Changed"; - break; - case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: - s = "AP Out of Range"; - break; - case HERMES_LINKSTATUS_AP_IN_RANGE: - s = "AP In Range"; - break; - case HERMES_LINKSTATUS_ASSOC_FAILED: - s = "Association Failed"; - break; - default: - s = "UNKNOWN"; - } - - printk(KERN_DEBUG "%s: New link status: %s (%04x)\n", - dev->name, s, status); -} - -/* Search scan results for requested BSSID, join it if found */ -static void orinoco_join_ap(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, join_work); - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - unsigned long flags; - struct join_req { - u8 bssid[ETH_ALEN]; - __le16 channel; - } __packed req; - const int atom_len = offsetof(struct prism2_scan_apinfo, atim); - struct prism2_scan_apinfo *atom = NULL; - int offset = 4; - int found = 0; - u8 *buf; - u16 len; - - /* Allocate buffer for scan results */ - buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL); - if (!buf) - return; - - if (orinoco_lock(priv, &flags) != 0) - goto fail_lock; - - /* Sanity checks in case user changed something in the meantime */ - if (!priv->bssid_fixed) - goto out; - - if (strlen(priv->desired_essid) == 0) - goto out; - - /* Read scan results from the firmware */ - err = hw->ops->read_ltv(hw, USER_BAP, - HERMES_RID_SCANRESULTSTABLE, - MAX_SCAN_LEN, &len, buf); - if (err) { - printk(KERN_ERR "%s: Cannot read scan results\n", - dev->name); - goto out; - } - - len = HERMES_RECLEN_TO_BYTES(len); - - /* Go through the scan results looking for the channel of the AP - * we were requested to join */ - for (; offset + atom_len <= len; offset += atom_len) { - atom = (struct prism2_scan_apinfo *) (buf + offset); - if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) { - found = 1; - break; - } - } - - if (!found) { - DEBUG(1, "%s: Requested AP not found in scan results\n", - dev->name); - goto out; - } - - memcpy(req.bssid, priv->desired_bssid, ETH_ALEN); - req.channel = atom->channel; /* both are little-endian */ - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST, - &req); - if (err) - printk(KERN_ERR "%s: Error issuing join request\n", dev->name); - - out: - orinoco_unlock(priv, &flags); - - fail_lock: - kfree(buf); -} - -/* Send new BSSID to userspace */ -static void orinoco_send_bssid_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, wrqu.ap_addr.sa_data); - if (err != 0) - return; - - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); -} - -static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - u8 buf[88]; - u8 *ie; - - if (!priv->has_wpa) - return; - - err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, - sizeof(buf), NULL, &buf); - if (err != 0) - return; - - ie = orinoco_get_wpa_ie(buf, sizeof(buf)); - if (ie) { - int rem = sizeof(buf) - (ie - &buf[0]); - wrqu.data.length = ie[1] + 2; - if (wrqu.data.length > rem) - wrqu.data.length = rem; - - if (wrqu.data.length) - /* Send event to user space */ - wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie); - } -} - -static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */ - u8 *ie; - - if (!priv->has_wpa) - return; - - err = hw->ops->read_ltv(hw, USER_BAP, - HERMES_RID_CURRENT_ASSOC_RESP_INFO, - sizeof(buf), NULL, &buf); - if (err != 0) - return; - - ie = orinoco_get_wpa_ie(buf, sizeof(buf)); - if (ie) { - int rem = sizeof(buf) - (ie - &buf[0]); - wrqu.data.length = ie[1] + 2; - if (wrqu.data.length > rem) - wrqu.data.length = rem; - - if (wrqu.data.length) - /* Send event to user space */ - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie); - } -} - -static void orinoco_send_wevents(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, wevent_work); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return; - - orinoco_send_assocreqie_wevent(priv); - orinoco_send_assocrespie_wevent(priv); - orinoco_send_bssid_wevent(priv); - - orinoco_unlock(priv, &flags); -} - -static void qbuf_scan(struct orinoco_private *priv, void *buf, - int len, int type) -{ - struct orinoco_scan_data *sd; - unsigned long flags; - - sd = kmalloc(sizeof(*sd), GFP_ATOMIC); - if (!sd) - return; - - sd->buf = buf; - sd->len = len; - sd->type = type; - - spin_lock_irqsave(&priv->scan_lock, flags); - list_add_tail(&sd->list, &priv->scan_list); - spin_unlock_irqrestore(&priv->scan_lock, flags); - - schedule_work(&priv->process_scan); -} - -static void qabort_scan(struct orinoco_private *priv) -{ - struct orinoco_scan_data *sd; - unsigned long flags; - - sd = kmalloc(sizeof(*sd), GFP_ATOMIC); - if (!sd) - return; - - sd->len = -1; /* Abort */ - - spin_lock_irqsave(&priv->scan_lock, flags); - list_add_tail(&sd->list, &priv->scan_list); - spin_unlock_irqrestore(&priv->scan_lock, flags); - - schedule_work(&priv->process_scan); -} - -static void orinoco_process_scan_results(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, process_scan); - struct orinoco_scan_data *sd, *temp; - unsigned long flags; - void *buf; - int len; - int type; - - spin_lock_irqsave(&priv->scan_lock, flags); - list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { - - buf = sd->buf; - len = sd->len; - type = sd->type; - - list_del(&sd->list); - spin_unlock_irqrestore(&priv->scan_lock, flags); - kfree(sd); - - if (len > 0) { - if (type == HERMES_INQ_CHANNELINFO) - orinoco_add_extscan_result(priv, buf, len); - else - orinoco_add_hostscan_results(priv, buf, len); - - kfree(buf); - } else { - /* Either abort or complete the scan */ - orinoco_scan_done(priv, (len < 0)); - } - - spin_lock_irqsave(&priv->scan_lock, flags); - } - spin_unlock_irqrestore(&priv->scan_lock, flags); -} - -void __orinoco_ev_info(struct net_device *dev, struct hermes *hw) -{ - struct orinoco_private *priv = ndev_priv(dev); - u16 infofid; - struct { - __le16 len; - __le16 type; - } __packed info; - int len, type; - int err; - - /* This is an answer to an INQUIRE command that we did earlier, - * or an information "event" generated by the card - * The controller return to us a pseudo frame containing - * the information in question - Jean II */ - infofid = hermes_read_regn(hw, INFOFID); - - /* Read the info frame header - don't try too hard */ - err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info), - infofid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading info frame. " - "Frame dropped.\n", dev->name, err); - return; - } - - len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len)); - type = le16_to_cpu(info.type); - - switch (type) { - case HERMES_INQ_TALLIES: { - struct hermes_tallies_frame tallies; - struct iw_statistics *wstats = &priv->wstats; - - if (len > sizeof(tallies)) { - printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n", - dev->name, len); - len = sizeof(tallies); - } - - err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len, - infofid, sizeof(info)); - if (err) - break; - - /* Increment our various counters */ - /* wstats->discard.nwid - no wrong BSSID stuff */ - wstats->discard.code += - le16_to_cpu(tallies.RxWEPUndecryptable); - if (len == sizeof(tallies)) - wstats->discard.code += - le16_to_cpu(tallies.RxDiscards_WEPICVError) + - le16_to_cpu(tallies.RxDiscards_WEPExcluded); - wstats->discard.misc += - le16_to_cpu(tallies.TxDiscardsWrongSA); - wstats->discard.fragment += - le16_to_cpu(tallies.RxMsgInBadMsgFragments); - wstats->discard.retries += - le16_to_cpu(tallies.TxRetryLimitExceeded); - /* wstats->miss.beacon - no match */ - } - break; - case HERMES_INQ_LINKSTATUS: { - struct hermes_linkstatus linkstatus; - u16 newstatus; - int connected; - - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) - break; - - if (len != sizeof(linkstatus)) { - printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", - dev->name, len); - break; - } - - err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len, - infofid, sizeof(info)); - if (err) - break; - newstatus = le16_to_cpu(linkstatus.linkstatus); - - /* Symbol firmware uses "out of range" to signal that - * the hostscan frame can be requested. */ - if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && - priv->firmware_type == FIRMWARE_TYPE_SYMBOL && - priv->has_hostscan && priv->scan_request) { - hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); - break; - } - - connected = (newstatus == HERMES_LINKSTATUS_CONNECTED) - || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) - || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE); - - if (connected) - netif_carrier_on(dev); - else if (!ignore_disconnect) - netif_carrier_off(dev); - - if (newstatus != priv->last_linkstatus) { - priv->last_linkstatus = newstatus; - print_linkstatus(dev, newstatus); - /* The info frame contains only one word which is the - * status (see hermes.h). The status is pretty boring - * in itself, that's why we export the new BSSID... - * Jean II */ - schedule_work(&priv->wevent_work); - } - } - break; - case HERMES_INQ_SCAN: - if (!priv->scan_request && priv->bssid_fixed && - priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { - schedule_work(&priv->join_work); - break; - } - fallthrough; - case HERMES_INQ_HOSTSCAN: - case HERMES_INQ_HOSTSCAN_SYMBOL: { - /* Result of a scanning. Contains information about - * cells in the vicinity - Jean II */ - unsigned char *buf; - - /* Sanity check */ - if (len > 4096) { - printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", - dev->name, len); - qabort_scan(priv); - break; - } - - /* Allocate buffer for results */ - buf = kmalloc(len, GFP_ATOMIC); - if (buf == NULL) { - /* No memory, so can't printk()... */ - qabort_scan(priv); - break; - } - - /* Read scan data */ - err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len, - infofid, sizeof(info)); - if (err) { - kfree(buf); - qabort_scan(priv); - break; - } - -#ifdef ORINOCO_DEBUG - { - int i; - printk(KERN_DEBUG "Scan result [%02X", buf[0]); - for (i = 1; i < (len * 2); i++) - printk(":%02X", buf[i]); - printk("]\n"); - } -#endif /* ORINOCO_DEBUG */ - - qbuf_scan(priv, buf, len, type); - } - break; - case HERMES_INQ_CHANNELINFO: - { - struct agere_ext_scan_info *bss; - - if (!priv->scan_request) { - printk(KERN_DEBUG "%s: Got chaninfo without scan, " - "len=%d\n", dev->name, len); - break; - } - - /* An empty result indicates that the scan is complete */ - if (len == 0) { - qbuf_scan(priv, NULL, len, type); - break; - } - - /* Sanity check */ - else if (len < (offsetof(struct agere_ext_scan_info, - data) + 2)) { - /* Drop this result now so we don't have to - * keep checking later */ - printk(KERN_WARNING - "%s: Ext scan results too short (%d bytes)\n", - dev->name, len); - break; - } - - bss = kmalloc(len, GFP_ATOMIC); - if (bss == NULL) - break; - - /* Read scan data */ - err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len, - infofid, sizeof(info)); - if (err) - kfree(bss); - else - qbuf_scan(priv, bss, len, type); - - break; - } - case HERMES_INQ_SEC_STAT_AGERE: - /* Security status (Agere specific) */ - /* Ignore this frame for now */ - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) - break; - fallthrough; - default: - printk(KERN_DEBUG "%s: Unknown information frame received: " - "type 0x%04x, length %d\n", dev->name, type, len); - /* We don't actually do anything about it */ - break; - } -} -EXPORT_SYMBOL(__orinoco_ev_info); - -static void __orinoco_ev_infdrop(struct net_device *dev, struct hermes *hw) -{ - if (net_ratelimit()) - printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name); -} - -/********************************************************************/ -/* Internal hardware control routines */ -/********************************************************************/ - -static int __orinoco_up(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - - netif_carrier_off(dev); /* just to make sure */ - - err = __orinoco_commit(priv); - if (err) { - printk(KERN_ERR "%s: Error %d configuring card\n", - dev->name, err); - return err; - } - - /* Fire things up again */ - hermes_set_irqmask(hw, ORINOCO_INTEN); - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_ERR "%s: Error %d enabling MAC port\n", - dev->name, err); - return err; - } - - netif_start_queue(dev); - - return 0; -} - -static int __orinoco_down(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - - netif_stop_queue(dev); - - if (!priv->hw_unavailable) { - if (!priv->broken_disableport) { - err = hermes_disable_port(hw, 0); - if (err) { - /* Some firmwares (e.g. Intersil 1.3.x) seem - * to have problems disabling the port, oh - * well, too bad. */ - printk(KERN_WARNING "%s: Error %d disabling MAC port\n", - dev->name, err); - priv->broken_disableport = 1; - } - } - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - } - - orinoco_scan_done(priv, true); - - /* firmware will have to reassociate */ - netif_carrier_off(dev); - priv->last_linkstatus = 0xffff; - - return 0; -} - -static int orinoco_reinit_firmware(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - int err; - - err = hw->ops->init(hw); - if (priv->do_fw_download && !err) { - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - } - if (!err) - err = orinoco_hw_allocate_fid(priv); - - return err; -} - -static int -__orinoco_set_multicast_list(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - int promisc, mc_count; - - /* The Hermes doesn't seem to have an allmulti mode, so we go - * into promiscuous mode and let the upper levels deal. */ - if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (netdev_mc_count(dev) > MAX_MULTICAST(priv))) { - promisc = 1; - mc_count = 0; - } else { - promisc = 0; - mc_count = netdev_mc_count(dev); - } - - err = __orinoco_hw_set_multicast_list(priv, dev, mc_count, promisc); - - return err; -} - -/* This must be called from user context, without locks held - use - * schedule_work() */ -void orinoco_reset(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, reset_work); - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - /* When the hardware becomes available again, whatever - * detects that is responsible for re-initializing - * it. So no need for anything further */ - return; - - netif_stop_queue(dev); - - /* Shut off interrupts. Depending on what state the hardware - * is in, this might not work, but we'll try anyway */ - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - priv->hw_unavailable++; - priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ - netif_carrier_off(dev); - - orinoco_unlock(priv, &flags); - - /* Scanning support: Notify scan cancellation */ - orinoco_scan_done(priv, true); - - if (priv->hard_reset) { - err = (*priv->hard_reset)(priv); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d " - "performing hard reset\n", dev->name, err); - goto disable; - } - } - - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", - dev->name, err); - goto disable; - } - - /* This has to be called from user context */ - orinoco_lock_irq(priv); - - priv->hw_unavailable--; - - /* priv->open or priv->hw_unavailable might have changed while - * we dropped the lock */ - if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(priv); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", - dev->name, err); - } else - netif_trans_update(dev); - } - - orinoco_unlock_irq(priv); - - return; - disable: - hermes_set_irqmask(hw, 0); - netif_device_detach(dev); - printk(KERN_ERR "%s: Device has been disabled!\n", dev->name); -} - -static int __orinoco_commit(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - int err = 0; - - /* If we've called commit, we are reconfiguring or bringing the - * interface up. Maintaining countermeasures across this would - * be confusing, so note that we've disabled them. The port will - * be enabled later in orinoco_commit or __orinoco_up. */ - priv->tkip_cm_active = 0; - - err = orinoco_hw_program_rids(priv); - - /* FIXME: what about netif_tx_lock */ - (void) __orinoco_set_multicast_list(dev); - - return err; -} - -/* Ensures configuration changes are applied. May result in a reset. - * The caller should hold priv->lock - */ -int orinoco_commit(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - - if (priv->broken_disableport) { - schedule_work(&priv->reset_work); - return 0; - } - - err = hermes_disable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to disable port " - "while reconfiguring card\n", dev->name); - priv->broken_disableport = 1; - goto out; - } - - err = __orinoco_commit(priv); - if (err) { - printk(KERN_WARNING "%s: Unable to reconfigure card\n", - dev->name); - goto out; - } - - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", - dev->name); - goto out; - } - - out: - if (err) { - printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); - schedule_work(&priv->reset_work); - err = 0; - } - return err; -} - -/********************************************************************/ -/* Interrupt handler */ -/********************************************************************/ - -static void __orinoco_ev_tick(struct net_device *dev, struct hermes *hw) -{ - printk(KERN_DEBUG "%s: TICK\n", dev->name); -} - -static void __orinoco_ev_wterr(struct net_device *dev, struct hermes *hw) -{ - /* This seems to happen a fair bit under load, but ignoring it - seems to work fine...*/ - printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", - dev->name); -} - -irqreturn_t orinoco_interrupt(int irq, void *dev_id) -{ - struct orinoco_private *priv = dev_id; - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int count = MAX_IRQLOOPS_PER_IRQ; - u16 evstat, events; - /* These are used to detect a runaway interrupt situation. - * - * If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, - * we panic and shut down the hardware - */ - /* jiffies value the last time we were called */ - static int last_irq_jiffy; /* = 0 */ - static int loops_this_jiffy; /* = 0 */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) { - /* If hw is unavailable - we don't know if the irq was - * for us or not */ - return IRQ_HANDLED; - } - - evstat = hermes_read_regn(hw, EVSTAT); - events = evstat & hw->inten; - if (!events) { - orinoco_unlock(priv, &flags); - return IRQ_NONE; - } - - if (jiffies != last_irq_jiffy) - loops_this_jiffy = 0; - last_irq_jiffy = jiffies; - - while (events && count--) { - if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { - printk(KERN_WARNING "%s: IRQ handler is looping too " - "much! Resetting.\n", dev->name); - /* Disable interrupts for now */ - hermes_set_irqmask(hw, 0); - schedule_work(&priv->reset_work); - break; - } - - /* Check the card hasn't been removed */ - if (!hermes_present(hw)) { - DEBUG(0, "orinoco_interrupt(): card removed\n"); - break; - } - - if (events & HERMES_EV_TICK) - __orinoco_ev_tick(dev, hw); - if (events & HERMES_EV_WTERR) - __orinoco_ev_wterr(dev, hw); - if (events & HERMES_EV_INFDROP) - __orinoco_ev_infdrop(dev, hw); - if (events & HERMES_EV_INFO) - __orinoco_ev_info(dev, hw); - if (events & HERMES_EV_RX) - __orinoco_ev_rx(dev, hw); - if (events & HERMES_EV_TXEXC) - __orinoco_ev_txexc(dev, hw); - if (events & HERMES_EV_TX) - __orinoco_ev_tx(dev, hw); - if (events & HERMES_EV_ALLOC) - __orinoco_ev_alloc(dev, hw); - - hermes_write_regn(hw, EVACK, evstat); - - evstat = hermes_read_regn(hw, EVSTAT); - events = evstat & hw->inten; - } - - orinoco_unlock(priv, &flags); - return IRQ_HANDLED; -} -EXPORT_SYMBOL(orinoco_interrupt); - -/********************************************************************/ -/* Power management */ -/********************************************************************/ -#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT) -static int orinoco_pm_notifier(struct notifier_block *notifier, - unsigned long pm_event, - void *unused) -{ - struct orinoco_private *priv = container_of(notifier, - struct orinoco_private, - pm_notifier); - - /* All we need to do is cache the firmware before suspend, and - * release it when we come out. - * - * Only need to do this if we're downloading firmware. */ - if (!priv->do_fw_download) - return NOTIFY_DONE; - - switch (pm_event) { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - orinoco_cache_fw(priv, 0); - break; - - case PM_POST_RESTORE: - /* Restore from hibernation failed. We need to clean - * up in exactly the same way, so fall through. */ - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - orinoco_uncache_fw(priv); - break; - - case PM_RESTORE_PREPARE: - default: - break; - } - - return NOTIFY_DONE; -} - -static void orinoco_register_pm_notifier(struct orinoco_private *priv) -{ - priv->pm_notifier.notifier_call = orinoco_pm_notifier; - register_pm_notifier(&priv->pm_notifier); -} - -static void orinoco_unregister_pm_notifier(struct orinoco_private *priv) -{ - unregister_pm_notifier(&priv->pm_notifier); -} -#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */ -#define orinoco_register_pm_notifier(priv) do { } while (0) -#define orinoco_unregister_pm_notifier(priv) do { } while (0) -#endif - -/********************************************************************/ -/* Initialization */ -/********************************************************************/ - -int orinoco_init(struct orinoco_private *priv) -{ - struct device *dev = priv->dev; - struct wiphy *wiphy = priv_to_wiphy(priv); - struct hermes *hw = &priv->hw; - int err = 0; - - /* No need to lock, the hw_unavailable flag is already set in - * alloc_orinocodev() */ - priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN; - - /* Initialize the firmware */ - err = hw->ops->init(hw); - if (err != 0) { - dev_err(dev, "Failed to initialize firmware (err = %d)\n", - err); - goto out; - } - - err = determine_fw_capabilities(priv, wiphy->fw_version, - sizeof(wiphy->fw_version), - &wiphy->hw_version); - if (err != 0) { - dev_err(dev, "Incompatible firmware, aborting\n"); - goto out; - } - - if (priv->do_fw_download) { -#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT - orinoco_cache_fw(priv, 0); -#endif - - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - - /* Check firmware version again */ - err = determine_fw_capabilities(priv, wiphy->fw_version, - sizeof(wiphy->fw_version), - &wiphy->hw_version); - if (err != 0) { - dev_err(dev, "Incompatible firmware, aborting\n"); - goto out; - } - } - - if (priv->has_port3) - dev_info(dev, "Ad-hoc demo mode supported\n"); - if (priv->has_ibss) - dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n"); - if (priv->has_wep) - dev_info(dev, "WEP supported, %s-bit key\n", - priv->has_big_wep ? "104" : "40"); - if (priv->has_wpa) { - dev_info(dev, "WPA-PSK supported\n"); - if (orinoco_mic_init(priv)) { - dev_err(dev, "Failed to setup MIC crypto algorithm. " - "Disabling WPA support\n"); - priv->has_wpa = 0; - } - } - - err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); - if (err) - goto out; - - err = orinoco_hw_allocate_fid(priv); - if (err) { - dev_err(dev, "Failed to allocate NIC buffer!\n"); - goto out; - } - - /* Set up the default configuration */ - priv->iw_mode = NL80211_IFTYPE_STATION; - /* By default use IEEE/IBSS ad-hoc mode if we have it */ - priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss); - set_port_type(priv); - priv->channel = 0; /* use firmware default */ - - priv->promiscuous = 0; - priv->encode_alg = ORINOCO_ALG_NONE; - priv->tx_key = 0; - priv->wpa_enabled = 0; - priv->tkip_cm_active = 0; - priv->key_mgmt = 0; - priv->wpa_ie_len = 0; - priv->wpa_ie = NULL; - - if (orinoco_wiphy_register(wiphy)) { - err = -ENODEV; - goto out; - } - - /* Make the hardware available, as long as it hasn't been - * removed elsewhere (e.g. by PCMCIA hot unplug) */ - orinoco_lock_irq(priv); - priv->hw_unavailable--; - orinoco_unlock_irq(priv); - - dev_dbg(dev, "Ready\n"); - - out: - return err; -} -EXPORT_SYMBOL(orinoco_init); - -static const struct net_device_ops orinoco_netdev_ops = { - .ndo_open = orinoco_open, - .ndo_stop = orinoco_stop, - .ndo_start_xmit = orinoco_xmit, - .ndo_set_rx_mode = orinoco_set_multicast_list, - .ndo_change_mtu = orinoco_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_tx_timeout = orinoco_tx_timeout, -}; - -/* Allocate private data. - * - * This driver has a number of structures associated with it - * netdev - Net device structure for each network interface - * wiphy - structure associated with wireless phy - * wireless_dev (wdev) - structure for each wireless interface - * hw - structure for hermes chip info - * card - card specific structure for use by the card driver - * (airport, orinoco_cs) - * priv - orinoco private data - * device - generic linux device structure - * - * +---------+ +---------+ - * | wiphy | | netdev | - * | +-------+ | +-------+ - * | | priv | | | wdev | - * | | +-----+ +-+-------+ - * | | | hw | - * | +-+-----+ - * | | card | - * +-+-------+ - * - * priv has a link to netdev and device - * wdev has a link to wiphy - */ -struct orinoco_private -*alloc_orinocodev(int sizeof_card, - struct device *device, - int (*hard_reset)(struct orinoco_private *), - int (*stop_fw)(struct orinoco_private *, int)) -{ - struct orinoco_private *priv; - struct wiphy *wiphy; - - /* allocate wiphy - * NOTE: We only support a single virtual interface - * but this may change when monitor mode is added - */ - wiphy = wiphy_new(&orinoco_cfg_ops, - sizeof(struct orinoco_private) + sizeof_card); - if (!wiphy) - return NULL; - - priv = wiphy_priv(wiphy); - priv->dev = device; - - if (sizeof_card) - priv->card = (void *)((unsigned long)priv - + sizeof(struct orinoco_private)); - else - priv->card = NULL; - - orinoco_wiphy_init(wiphy); - -#ifdef WIRELESS_SPY - priv->wireless_data.spy_data = &priv->spy_data; -#endif - - /* Set up default callbacks */ - priv->hard_reset = hard_reset; - priv->stop_fw = stop_fw; - - spin_lock_init(&priv->lock); - priv->open = 0; - priv->hw_unavailable = 1; /* orinoco_init() must clear this - * before anything else touches the - * hardware */ - INIT_WORK(&priv->reset_work, orinoco_reset); - INIT_WORK(&priv->join_work, orinoco_join_ap); - INIT_WORK(&priv->wevent_work, orinoco_send_wevents); - - INIT_LIST_HEAD(&priv->rx_list); - tasklet_setup(&priv->rx_tasklet, orinoco_rx_isr_tasklet); - - spin_lock_init(&priv->scan_lock); - INIT_LIST_HEAD(&priv->scan_list); - INIT_WORK(&priv->process_scan, orinoco_process_scan_results); - - priv->last_linkstatus = 0xffff; - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) - priv->cached_pri_fw = NULL; - priv->cached_fw = NULL; -#endif - - /* Register PM notifiers */ - orinoco_register_pm_notifier(priv); - - return priv; -} -EXPORT_SYMBOL(alloc_orinocodev); - -/* We can only support a single interface. We provide a separate - * function to set it up to distinguish between hardware - * initialisation and interface setup. - * - * The base_addr and irq parameters are passed on to netdev for use - * with SIOCGIFMAP. - */ -int orinoco_if_add(struct orinoco_private *priv, - unsigned long base_addr, - unsigned int irq, - const struct net_device_ops *ops) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct wireless_dev *wdev; - struct net_device *dev; - int ret; - - dev = alloc_etherdev(sizeof(struct wireless_dev)); - - if (!dev) - return -ENOMEM; - - /* Initialise wireless_dev */ - wdev = netdev_priv(dev); - wdev->wiphy = wiphy; - wdev->iftype = NL80211_IFTYPE_STATION; - - /* Setup / override net_device fields */ - dev->ieee80211_ptr = wdev; - dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->wireless_handlers = &orinoco_handler_def; -#ifdef WIRELESS_SPY - dev->wireless_data = &priv->wireless_data; -#endif - /* Default to standard ops if not set */ - if (ops) - dev->netdev_ops = ops; - else - dev->netdev_ops = &orinoco_netdev_ops; - - /* we use the default eth_mac_addr for setting the MAC addr */ - - /* Reserve space in skb for the SNAP header */ - dev->needed_headroom = ENCAPS_OVERHEAD; - - netif_carrier_off(dev); - - eth_hw_addr_set(dev, wiphy->perm_addr); - - dev->base_addr = base_addr; - dev->irq = irq; - - dev->min_mtu = ORINOCO_MIN_MTU; - dev->max_mtu = ORINOCO_MAX_MTU; - - SET_NETDEV_DEV(dev, priv->dev); - ret = register_netdev(dev); - if (ret) - goto fail; - - priv->ndev = dev; - - /* Report what we've done */ - dev_dbg(priv->dev, "Registered interface %s.\n", dev->name); - - return 0; - - fail: - free_netdev(dev); - return ret; -} -EXPORT_SYMBOL(orinoco_if_add); - -void orinoco_if_del(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - - unregister_netdev(dev); - free_netdev(dev); -} -EXPORT_SYMBOL(orinoco_if_del); - -void free_orinocodev(struct orinoco_private *priv) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct orinoco_rx_data *rx_data, *temp; - struct orinoco_scan_data *sd, *sdtemp; - - /* If the tasklet is scheduled when we call tasklet_kill it - * will run one final time. However the tasklet will only - * drain priv->rx_list if the hw is still available. */ - tasklet_kill(&priv->rx_tasklet); - - /* Explicitly drain priv->rx_list */ - list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { - list_del(&rx_data->list); - - dev_kfree_skb(rx_data->skb); - kfree(rx_data->desc); - kfree(rx_data); - } - - cancel_work_sync(&priv->process_scan); - /* Explicitly drain priv->scan_list */ - list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) { - list_del(&sd->list); - - if (sd->len > 0) - kfree(sd->buf); - kfree(sd); - } - - orinoco_unregister_pm_notifier(priv); - orinoco_uncache_fw(priv); - - priv->wpa_ie_len = 0; - kfree(priv->wpa_ie); - orinoco_mic_free(priv); - wiphy_free(wiphy); -} -EXPORT_SYMBOL(free_orinocodev); - -int orinoco_up(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - unsigned long flags; - int err; - - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware\n", - dev->name, err); - goto exit; - } - - netif_device_attach(dev); - priv->hw_unavailable--; - - if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card\n", - dev->name, err); - } - -exit: - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - return 0; -} -EXPORT_SYMBOL(orinoco_up); - -void orinoco_down(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - unsigned long flags; - int err; - - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - priv->hw_unavailable++; - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); -} -EXPORT_SYMBOL(orinoco_down); - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -/* Can't be declared "const" or the whole __initdata section will - * become const */ -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (David Gibson <hermes@gibson.dropbear.id.au>, " - "Pavel Roskin <proski@gnu.org>, et al)"; - -static int __init init_orinoco(void) -{ - printk(KERN_DEBUG "%s\n", version); - return 0; -} - -static void __exit exit_orinoco(void) -{ -} - -module_init(init_orinoco); -module_exit(exit_orinoco); diff --git a/drivers/net/wireless/intersil/orinoco/main.h b/drivers/net/wireless/intersil/orinoco/main.h deleted file mode 100644 index 5a8fec2613..0000000000 --- a/drivers/net/wireless/intersil/orinoco/main.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Exports from main to helper modules - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_MAIN_H_ -#define _ORINOCO_MAIN_H_ - -#include <linux/ieee80211.h> -#include "orinoco.h" - -/********************************************************************/ -/* Compile time configuration and compatibility stuff */ -/********************************************************************/ - -/* We do this this way to avoid ifdefs in the actual code */ -#ifdef WIRELESS_SPY -#define SPY_NUMBER(priv) (priv->spy_data.spy_number) -#else -#define SPY_NUMBER(priv) 0 -#endif /* WIRELESS_SPY */ - -/********************************************************************/ - -/* Export module parameter */ -extern int force_monitor; - -/* Forward declarations */ -struct net_device; -struct work_struct; - -void set_port_type(struct orinoco_private *priv); -int orinoco_commit(struct orinoco_private *priv); -void orinoco_reset(struct work_struct *work); - -/* Information element helpers - find a home for these... */ -#define WPA_OUI_TYPE "\x00\x50\xF2\x01" -#define WPA_SELECTOR_LEN 4 -static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) -{ - u8 *p = data; - while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { - if ((p[0] == WLAN_EID_VENDOR_SPECIFIC) && - (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) - return p; - p += p[1] + 2; - } - return NULL; -} - -#endif /* _ORINOCO_MAIN_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/mic.c b/drivers/net/wireless/intersil/orinoco/mic.c deleted file mode 100644 index a324bc4b79..0000000000 --- a/drivers/net/wireless/intersil/orinoco/mic.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Orinoco MIC helpers - * - * See copyright notice in main.c - */ -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/if_ether.h> -#include <linux/scatterlist.h> -#include <crypto/hash.h> - -#include "orinoco.h" -#include "mic.h" - -/********************************************************************/ -/* Michael MIC crypto setup */ -/********************************************************************/ -int orinoco_mic_init(struct orinoco_private *priv) -{ - priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(priv->tx_tfm_mic)) { - printk(KERN_DEBUG "%s: could not allocate " - "crypto API michael_mic\n", __func__); - priv->tx_tfm_mic = NULL; - return -ENOMEM; - } - - priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(priv->rx_tfm_mic)) { - printk(KERN_DEBUG "%s: could not allocate " - "crypto API michael_mic\n", __func__); - priv->rx_tfm_mic = NULL; - return -ENOMEM; - } - - return 0; -} - -void orinoco_mic_free(struct orinoco_private *priv) -{ - if (priv->tx_tfm_mic) - crypto_free_shash(priv->tx_tfm_mic); - if (priv->rx_tfm_mic) - crypto_free_shash(priv->rx_tfm_mic); -} - -int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key, - u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic) -{ - SHASH_DESC_ON_STACK(desc, tfm_michael); - u8 hdr[ETH_HLEN + 2]; /* size of header + padding */ - int err; - - if (tfm_michael == NULL) { - printk(KERN_WARNING "%s: tfm_michael == NULL\n", __func__); - return -1; - } - - /* Copy header into buffer. We need the padding on the end zeroed */ - memcpy(&hdr[0], da, ETH_ALEN); - memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN); - hdr[ETH_ALEN * 2] = priority; - hdr[ETH_ALEN * 2 + 1] = 0; - hdr[ETH_ALEN * 2 + 2] = 0; - hdr[ETH_ALEN * 2 + 3] = 0; - - desc->tfm = tfm_michael; - - err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN); - if (err) - return err; - - err = crypto_shash_init(desc); - if (err) - return err; - - err = crypto_shash_update(desc, hdr, sizeof(hdr)); - if (err) - return err; - - err = crypto_shash_update(desc, data, data_len); - if (err) - return err; - - err = crypto_shash_final(desc, mic); - shash_desc_zero(desc); - - return err; -} diff --git a/drivers/net/wireless/intersil/orinoco/mic.h b/drivers/net/wireless/intersil/orinoco/mic.h deleted file mode 100644 index e8724e8892..0000000000 --- a/drivers/net/wireless/intersil/orinoco/mic.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Orinoco MIC helpers - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_MIC_H_ -#define _ORINOCO_MIC_H_ - -#include <linux/types.h> -#include <crypto/hash.h> - -#define MICHAEL_MIC_LEN 8 - -/* Forward declarations */ -struct orinoco_private; -struct crypto_ahash; - -int orinoco_mic_init(struct orinoco_private *priv); -void orinoco_mic_free(struct orinoco_private *priv); -int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key, - u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic); - -#endif /* ORINOCO_MIC_H */ diff --git a/drivers/net/wireless/intersil/orinoco/orinoco.h b/drivers/net/wireless/intersil/orinoco/orinoco.h deleted file mode 100644 index cdd026af10..0000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco.h +++ /dev/null @@ -1,251 +0,0 @@ -/* orinoco.h - * - * Common definitions to all pieces of the various orinoco - * drivers - */ - -#ifndef _ORINOCO_H -#define _ORINOCO_H - -#define DRIVER_VERSION "0.15" - -#include <linux/interrupt.h> -#include <linux/suspend.h> -#include <linux/netdevice.h> -#include <linux/wireless.h> -#include <net/iw_handler.h> -#include <net/cfg80211.h> - -#include "hermes.h" - -/* To enable debug messages */ -/*#define ORINOCO_DEBUG 3*/ - -#define WIRELESS_SPY /* enable iwspy support */ - -#define MAX_SCAN_LEN 4096 - -#define ORINOCO_SEQ_LEN 8 -#define ORINOCO_MAX_KEY_SIZE 14 -#define ORINOCO_MAX_KEYS 4 - -struct orinoco_key { - __le16 len; /* always stored as little-endian */ - char data[ORINOCO_MAX_KEY_SIZE]; -} __packed; - -#define TKIP_KEYLEN 16 -#define MIC_KEYLEN 8 - -struct orinoco_tkip_key { - u8 tkip[TKIP_KEYLEN]; - u8 tx_mic[MIC_KEYLEN]; - u8 rx_mic[MIC_KEYLEN]; -}; - -enum orinoco_alg { - ORINOCO_ALG_NONE, - ORINOCO_ALG_WEP, - ORINOCO_ALG_TKIP -}; - -enum fwtype { - FIRMWARE_TYPE_AGERE, - FIRMWARE_TYPE_INTERSIL, - FIRMWARE_TYPE_SYMBOL -}; - -struct firmware; - -struct orinoco_private { - void *card; /* Pointer to card dependent structure */ - struct device *dev; - int (*hard_reset)(struct orinoco_private *); - int (*stop_fw)(struct orinoco_private *, int); - - struct ieee80211_supported_band band; - struct ieee80211_channel channels[14]; - u32 cipher_suites[3]; - - /* Synchronisation stuff */ - spinlock_t lock; - int hw_unavailable; - struct work_struct reset_work; - - /* Interrupt tasklets */ - struct tasklet_struct rx_tasklet; - struct list_head rx_list; - - /* driver state */ - int open; - u16 last_linkstatus; - struct work_struct join_work; - struct work_struct wevent_work; - - /* Net device stuff */ - struct net_device *ndev; - struct iw_statistics wstats; - - /* Hardware control variables */ - struct hermes hw; - u16 txfid; - - /* Capabilities of the hardware/firmware */ - enum fwtype firmware_type; - int ibss_port; - int nicbuf_size; - u16 channel_mask; - - /* Boolean capabilities */ - unsigned int has_ibss:1; - unsigned int has_port3:1; - unsigned int has_wep:1; - unsigned int has_big_wep:1; - unsigned int has_mwo:1; - unsigned int has_pm:1; - unsigned int has_preamble:1; - unsigned int has_sensitivity:1; - unsigned int has_hostscan:1; - unsigned int has_alt_txcntl:1; - unsigned int has_ext_scan:1; - unsigned int has_wpa:1; - unsigned int do_fw_download:1; - unsigned int broken_disableport:1; - unsigned int broken_monitor:1; - unsigned int prefer_port3:1; - - /* Configuration paramaters */ - enum nl80211_iftype iw_mode; - enum orinoco_alg encode_alg; - u16 wep_restrict, tx_key; - struct key_params keys[ORINOCO_MAX_KEYS]; - - int bitratemode; - char nick[IW_ESSID_MAX_SIZE + 1]; - char desired_essid[IW_ESSID_MAX_SIZE + 1]; - char desired_bssid[ETH_ALEN]; - int bssid_fixed; - u16 frag_thresh, mwo_robust; - u16 channel; - u16 ap_density, rts_thresh; - u16 pm_on, pm_mcast, pm_period, pm_timeout; - u16 preamble; - u16 short_retry_limit, long_retry_limit; - u16 retry_lifetime; -#ifdef WIRELESS_SPY - struct iw_spy_data spy_data; /* iwspy support */ - struct iw_public_data wireless_data; -#endif - - /* Configuration dependent variables */ - int port_type, createibss; - int promiscuous, mc_count; - - /* Scanning support */ - struct cfg80211_scan_request *scan_request; - struct work_struct process_scan; - struct list_head scan_list; - spinlock_t scan_lock; /* protects the scan list */ - - /* WPA support */ - u8 *wpa_ie; - int wpa_ie_len; - - struct crypto_shash *rx_tfm_mic; - struct crypto_shash *tx_tfm_mic; - - unsigned int wpa_enabled:1; - unsigned int tkip_cm_active:1; - unsigned int key_mgmt:3; - -#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) - /* Cached in memory firmware to use during ->resume. */ - const struct firmware *cached_pri_fw; - const struct firmware *cached_fw; -#endif - - struct notifier_block pm_notifier; -}; - -#ifdef ORINOCO_DEBUG -extern int orinoco_debug; -#define DEBUG(n, args...) do { \ - if (orinoco_debug > (n)) \ - printk(KERN_DEBUG args); \ -} while (0) -#else -#define DEBUG(n, args...) do { } while (0) -#endif /* ORINOCO_DEBUG */ - -/********************************************************************/ -/* Exported prototypes */ -/********************************************************************/ - -struct orinoco_private *alloc_orinocodev(int sizeof_card, struct device *device, - int (*hard_reset)(struct orinoco_private *), - int (*stop_fw)(struct orinoco_private *, int)); -void free_orinocodev(struct orinoco_private *priv); -int orinoco_init(struct orinoco_private *priv); -int orinoco_if_add(struct orinoco_private *priv, unsigned long base_addr, - unsigned int irq, const struct net_device_ops *ops); -void orinoco_if_del(struct orinoco_private *priv); -int orinoco_up(struct orinoco_private *priv); -void orinoco_down(struct orinoco_private *priv); -irqreturn_t orinoco_interrupt(int irq, void *dev_id); - -void __orinoco_ev_info(struct net_device *dev, struct hermes *hw); -void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw); - -int orinoco_process_xmit_skb(struct sk_buff *skb, - struct net_device *dev, - struct orinoco_private *priv, - int *tx_control, - u8 *mic); - -/* Common ndo functions exported for reuse by orinoco_usb */ -int orinoco_open(struct net_device *dev); -int orinoco_stop(struct net_device *dev); -void orinoco_set_multicast_list(struct net_device *dev); -int orinoco_change_mtu(struct net_device *dev, int new_mtu); -void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue); - -/********************************************************************/ -/* Locking and synchronization functions */ -/********************************************************************/ - -static inline int orinoco_lock(struct orinoco_private *priv, - unsigned long *flags) -{ - priv->hw.ops->lock_irqsave(&priv->lock, flags); - if (priv->hw_unavailable) { - DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n", - priv->ndev); - priv->hw.ops->unlock_irqrestore(&priv->lock, flags); - return -EBUSY; - } - return 0; -} - -static inline void orinoco_unlock(struct orinoco_private *priv, - unsigned long *flags) -{ - priv->hw.ops->unlock_irqrestore(&priv->lock, flags); -} - -static inline void orinoco_lock_irq(struct orinoco_private *priv) -{ - priv->hw.ops->lock_irq(&priv->lock); -} - -static inline void orinoco_unlock_irq(struct orinoco_private *priv) -{ - priv->hw.ops->unlock_irq(&priv->lock); -} - -/*** Navigate from net_device to orinoco_private ***/ -static inline struct orinoco_private *ndev_priv(struct net_device *dev) -{ - struct wireless_dev *wdev = netdev_priv(dev); - return wdev_priv(wdev); -} -#endif /* _ORINOCO_H */ diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c b/drivers/net/wireless/intersil/orinoco/orinoco_cs.c deleted file mode 100644 index 03bfd24826..0000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c +++ /dev/null @@ -1,350 +0,0 @@ -/* orinoco_cs.c (formerly known as dldwd_cs.c) - * - * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such - * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). - * It should also be usable on various Prism II based cards such as the - * Linksys, D-Link and Farallon Skyline. It should also work on Symbol - * cards such as the 3Com AirConnect and Ericsson WLAN. - * - * Copyright notice & release notes in file main.c - */ - -#define DRIVER_NAME "orinoco_cs" -#define PFX DRIVER_NAME ": " - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> - -#include "orinoco.h" - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>"); -MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco," - " Prism II based and similar wireless cards"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Module parameters */ - -/* Some D-Link cards have buggy CIS. They do work at 5v properly, but - * don't have any CIS entry for it. This workaround it... */ -static int ignore_cis_vcc; /* = 0 */ -module_param(ignore_cis_vcc, int, 0); -MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -/* PCMCIA specific device information (goes in the card field of - * struct orinoco_private */ -struct orinoco_pccard { - struct pcmcia_device *p_dev; - - /* Used to handle hard reset */ - /* yuck, we need this hack to work around the insanity of the - * PCMCIA layer */ - unsigned long hard_reset_in_progress; -}; - - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int orinoco_cs_config(struct pcmcia_device *link); -static void orinoco_cs_release(struct pcmcia_device *link); -static void orinoco_cs_detach(struct pcmcia_device *p_dev); - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -static int -orinoco_cs_hard_reset(struct orinoco_private *priv) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - int err; - - /* We need atomic ops here, because we're not holding the lock */ - set_bit(0, &card->hard_reset_in_progress); - - err = pcmcia_reset_card(link->socket); - if (err) - return err; - - msleep(100); - clear_bit(0, &card->hard_reset_in_progress); - - return 0; -} - -/********************************************************************/ -/* PCMCIA stuff */ -/********************************************************************/ - -static int -orinoco_cs_probe(struct pcmcia_device *link) -{ - struct orinoco_private *priv; - struct orinoco_pccard *card; - int ret; - - priv = alloc_orinocodev(sizeof(*card), &link->dev, - orinoco_cs_hard_reset, NULL); - if (!priv) - return -ENOMEM; - card = priv->card; - - /* Link both structures together */ - card->p_dev = link; - link->priv = priv; - - ret = orinoco_cs_config(link); - if (ret) - goto err_free_orinocodev; - - return 0; - -err_free_orinocodev: - free_orinocodev(priv); - return ret; -} - -static void orinoco_cs_detach(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - - orinoco_if_del(priv); - - orinoco_cs_release(link); - - wiphy_unregister(priv_to_wiphy(priv)); - free_orinocodev(priv); -} /* orinoco_cs_detach */ - -static int orinoco_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -}; - -static int -orinoco_cs_config(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct hermes *hw = &priv->hw; - int ret; - void __iomem *mem; - - link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC | - CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; - if (ignore_cis_vcc) - link->config_flags &= ~CONF_AUTO_CHECK_VCC; - ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL); - if (ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR PFX "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - goto failed; - } - - mem = ioport_map(link->resource[0]->start, - resource_size(link->resource[0])); - if (!mem) - goto failed; - - /* We initialize the hermes structure before completing PCMCIA - * configuration just in case the interrupt handler gets - * called. */ - hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); - - ret = pcmcia_request_irq(link, orinoco_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto failed; - } - - /* Register an interface with the stack */ - if (orinoco_if_add(priv, link->resource[0]->start, - link->irq, NULL) != 0) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto failed; - } - - return 0; - - failed: - orinoco_cs_release(link); - return -ENODEV; -} /* orinoco_cs_config */ - -static void -orinoco_cs_release(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - unsigned long flags; - - /* We're committed to taking the device away now, so mark the - * hardware as unavailable */ - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - priv->hw_unavailable++; - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - pcmcia_disable_device(link); - if (priv->hw.iobase) - ioport_unmap(priv->hw.iobase); -} /* orinoco_cs_release */ - -static int orinoco_cs_suspend(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct orinoco_pccard *card = priv->card; - - /* This is probably racy, but I can't think of - a better way, short of rewriting the PCMCIA - layer to not suck :-( */ - if (!test_bit(0, &card->hard_reset_in_progress)) - orinoco_down(priv); - - return 0; -} - -static int orinoco_cs_resume(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct orinoco_pccard *card = priv->card; - int err = 0; - - if (!test_bit(0, &card->hard_reset_in_progress)) - err = orinoco_up(priv); - - return err; -} - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -static const struct pcmcia_device_id orinoco_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ - PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */ - PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */ - PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */ - PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0003), /* ARtem Onair Comcard 11 */ - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */ - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */ - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */ - PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), - PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), - PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), - PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), - PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169), - PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb), - PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), - PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916), - PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3), - PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c), - PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077), - PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92), - PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a), - PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410), - PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3), - PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a), - PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767), - PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed), - PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9), - PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26), - PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b), - PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e), - PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.01", 0xd27deb1a), /* Lucent Orinoco */ -#ifdef CONFIG_HERMES_PRISM - /* Only entries that certainly identify Prism chipset */ - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */ - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */ - PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */ - PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */ - PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */ - PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */ - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */ - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */ - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */ - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */ - PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */ - PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */ - PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */ - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */ - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */ - PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5), - PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3), - PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), - PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), - PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146), - PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), - PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), - PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), - PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), - PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), - PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6), - PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264), - PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178), - PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757), - PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), - PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), - PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092), - PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2), - PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b), - PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39), - - /* This may be Agere or Intersil Firmware */ - PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), -#endif - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); - -static struct pcmcia_driver orinoco_driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - .probe = orinoco_cs_probe, - .remove = orinoco_cs_detach, - .id_table = orinoco_cs_ids, - .suspend = orinoco_cs_suspend, - .resume = orinoco_cs_resume, -}; -module_pcmcia_driver(orinoco_driver); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c b/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c deleted file mode 100644 index 18bd0d9876..0000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c +++ /dev/null @@ -1,314 +0,0 @@ -/* orinoco_nortel.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in - * Nortel emobility, Symbol LA-4113 and Symbol LA-4123. - * - * Copyright (C) 2002 Tobias Hoffmann - * (C) 2003 Christoph Jungegger <disdos@traum404.de> - * - * Some of this code is borrowed from orinoco_plx.c - * Copyright (C) 2001 Daniel Barlow - * Some of this code is borrowed from orinoco_pci.c - * Copyright (C) 2001 Jean Tourrilhes - * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing - * has been copied from it. linux-wlan-ng-0.1.10 is originally : - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#define DRIVER_NAME "orinoco_nortel" -#define PFX DRIVER_NAME ": " - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <pcmcia/cisreg.h> - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ - - -/* - * Do a soft reset of the card using the Configuration Option Register - * We need this to get going... - * This is the part of the code that is strongly inspired from wlan-ng - * - * Note bis : Don't try to access HERMES_CMD during the reset phase. - * It just won't work ! - */ -static int orinoco_nortel_cor_reset(struct orinoco_private *priv) -{ - struct orinoco_pci_card *card = priv->card; - - /* Assert the reset until the card notices */ - iowrite16(8, card->bridge_io + 2); - ioread16(card->attr_io + COR_OFFSET); - iowrite16(0x80, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Give time for the card to recover from this hard effort */ - iowrite16(0, card->attr_io + COR_OFFSET); - iowrite16(0, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Set COR as usual */ - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - - iowrite16(0x228, card->bridge_io + 2); - - return 0; -} - -static int orinoco_nortel_hw_init(struct orinoco_pci_card *card) -{ - int i; - u32 reg; - - /* Setup bridge */ - if (ioread16(card->bridge_io) & 1) { - printk(KERN_ERR PFX "brg1 answer1 wrong\n"); - return -EBUSY; - } - iowrite16(0x118, card->bridge_io + 2); - iowrite16(0x108, card->bridge_io + 2); - mdelay(30); - iowrite16(0x8, card->bridge_io + 2); - for (i = 0; i < 30; i++) { - mdelay(30); - if (ioread16(card->bridge_io) & 0x10) - break; - } - if (i == 30) { - printk(KERN_ERR PFX "brg1 timed out\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET) & 1) { - printk(KERN_ERR PFX "brg2 answer1 wrong\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) { - printk(KERN_ERR PFX "brg2 answer2 wrong\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) { - printk(KERN_ERR PFX "brg2 answer3 wrong\n"); - return -EBUSY; - } - - /* Set the PCMCIA COR register */ - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - reg = ioread16(card->attr_io + COR_OFFSET); - if (reg != COR_VALUE) { - printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n", - reg); - return -EBUSY; - } - - /* Set LEDs */ - iowrite16(1, card->bridge_io + 10); - return 0; -} - -static int orinoco_nortel_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io, *bridge_io, *attr_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 0, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - attr_io = pci_iomap(pdev, 1, 0); - if (!attr_io) { - printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); - err = -EIO; - goto fail_map_attr; - } - - hermes_io = pci_iomap(pdev, 2, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_nortel_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - card->bridge_io = bridge_io; - card->attr_io = attr_io; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_nortel_hw_init(card); - if (err) { - printk(KERN_ERR PFX "Hardware initialization failed\n"); - goto fail; - } - - err = orinoco_nortel_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail_wiphy; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail_wiphy: - wiphy_unregister(priv_to_wiphy(priv)); - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, attr_io); - - fail_map_attr: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_nortel_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct orinoco_pci_card *card = priv->card; - - /* Clear LEDs */ - iowrite16(0, card->bridge_io + 10); - - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(priv)); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->attr_io); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_nortel_id_table[] = { - /* Nortel emobility PCI */ - {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,}, - /* Symbol LA-4123 PCI */ - {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,}, - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table); - -static struct pci_driver orinoco_nortel_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_nortel_id_table, - .probe = orinoco_nortel_init_one, - .remove = orinoco_nortel_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)"; -MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>"); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the Nortel PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_nortel_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_nortel_driver); -} - -static void __exit orinoco_nortel_exit(void) -{ - pci_unregister_driver(&orinoco_nortel_driver); -} - -module_init(orinoco_nortel_init); -module_exit(orinoco_nortel_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c b/drivers/net/wireless/intersil/orinoco/orinoco_pci.c deleted file mode 100644 index 7e3a6dd60c..0000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c +++ /dev/null @@ -1,257 +0,0 @@ -/* orinoco_pci.c - * - * Driver for Prism 2.5/3 devices that have a direct PCI interface - * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge). - * The card contains only one PCI region, which contains all the usual - * hermes registers, as well as the COR register. - * - * Current maintainers are: - * Pavel Roskin <proski AT gnu.org> - * and David Gibson <hermes AT gibson.dropbear.id.au> - * - * Some of this code is borrowed from orinoco_plx.c - * Copyright (C) 2001 Daniel Barlow <dan AT telent.net> - * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing - * has been copied from it. linux-wlan-ng-0.1.10 is originally : - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * This file originally written by: - * Copyright (C) 2001 Jean Tourrilhes <jt AT hpl.hp.com> - * And is now maintained by: - * (C) Copyright David Gibson, IBM Corp. 2002-2003. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#define DRIVER_NAME "orinoco_pci" -#define PFX DRIVER_NAME ": " - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pci.h> - -#include "orinoco.h" -#include "orinoco_pci.h" - -/* Offset of the COR register of the PCI card */ -#define HERMES_PCI_COR (0x26) - -/* Bitmask to reset the card */ -#define HERMES_PCI_COR_MASK (0x0080) - -/* Magic timeouts for doing the reset. - * Those times are straight from wlan-ng, and it is claimed that they - * are necessary. Alan will kill me. Take your time and grab a coffee. */ -#define HERMES_PCI_COR_ONT (250) /* ms */ -#define HERMES_PCI_COR_OFFT (500) /* ms */ -#define HERMES_PCI_COR_BUSYT (500) /* ms */ - -/* - * Do a soft reset of the card using the Configuration Option Register - * We need this to get going... - * This is the part of the code that is strongly inspired from wlan-ng - * - * Note : This code is done with irq enabled. This mean that many - * interrupts will occur while we are there. This is why we use the - * jiffies to regulate time instead of a straight mdelay(). Usually we - * need only around 245 iteration of the loop to do 250 ms delay. - * - * Note bis : Don't try to access HERMES_CMD during the reset phase. - * It just won't work ! - */ -static int orinoco_pci_cor_reset(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - unsigned long timeout; - u16 reg; - - /* Assert the reset until the card notices */ - hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); - mdelay(HERMES_PCI_COR_ONT); - - /* Give time for the card to recover from this hard effort */ - hermes_write_regn(hw, PCI_COR, 0x0000); - mdelay(HERMES_PCI_COR_OFFT); - - /* The card is ready when it's no longer busy */ - timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int orinoco_pci_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - hermes_io = pci_iomap(pdev, 0, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot remap chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_pci_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_pci_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail_wiphy; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail_wiphy: - wiphy_unregister(priv_to_wiphy(priv)); - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_pci_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(priv)); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_pci_id_table[] = { - /* Intersil Prism 3 */ - {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, - /* Intersil Prism 2.5 */ - {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, - /* Samsung MagicLAN SWL-2210P */ - {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,}, - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table); - -static struct pci_driver orinoco_pci_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_pci_id_table, - .probe = orinoco_pci_init_one, - .remove = orinoco_pci_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Pavel Roskin <proski@gnu.org>," - " David Gibson <hermes@gibson.dropbear.id.au> &" - " Jean Tourrilhes <jt@hpl.hp.com>)"; -MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> &" - " David Gibson <hermes@gibson.dropbear.id.au>"); -MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_pci_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_pci_driver); -} - -static void __exit orinoco_pci_exit(void) -{ - pci_unregister_driver(&orinoco_pci_driver); -} - -module_init(orinoco_pci_init); -module_exit(orinoco_pci_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h b/drivers/net/wireless/intersil/orinoco/orinoco_pci.h deleted file mode 100644 index d49d940864..0000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h +++ /dev/null @@ -1,54 +0,0 @@ -/* orinoco_pci.h - * - * Common code for all Orinoco drivers for PCI devices, including - * both native PCI and PCMCIA-to-PCI bridges. - * - * Copyright (C) 2005, Pavel Roskin. - * See main.c for license. - */ - -#ifndef _ORINOCO_PCI_H -#define _ORINOCO_PCI_H - -#include <linux/netdevice.h> - -/* Driver specific data */ -struct orinoco_pci_card { - void __iomem *bridge_io; - void __iomem *attr_io; -}; - -static int __maybe_unused orinoco_pci_suspend(struct device *dev_d) -{ - struct pci_dev *pdev = to_pci_dev(dev_d); - struct orinoco_private *priv = pci_get_drvdata(pdev); - - orinoco_down(priv); - free_irq(pdev->irq, priv); - - return 0; -} - -static int __maybe_unused orinoco_pci_resume(struct device *dev_d) -{ - struct pci_dev *pdev = to_pci_dev(dev_d); - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; - int err; - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); - if (err) { - printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", - dev->name); - return -EBUSY; - } - - return orinoco_up(priv); -} - -static SIMPLE_DEV_PM_OPS(orinoco_pci_pm_ops, - orinoco_pci_suspend, - orinoco_pci_resume); - -#endif /* _ORINOCO_PCI_H */ diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c b/drivers/net/wireless/intersil/orinoco/orinoco_plx.c deleted file mode 100644 index 73e6ae1240..0000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c +++ /dev/null @@ -1,362 +0,0 @@ -/* orinoco_plx.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a PLX9052. - * - * Current maintainers are: - * Pavel Roskin <proski AT gnu.org> - * and David Gibson <hermes AT gibson.dropbear.id.au> - * - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * Copyright (C) 2001 Daniel Barlow - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * Here's the general details on how the PLX9052 adapter works: - * - * - Two PCI I/O address spaces, one 0x80 long which contains the - * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA - * slot I/O address space. - * - * - One PCI memory address space, mapped to the PCMCIA attribute space - * (containing the CIS). - * - * Using the later, you can read through the CIS data to make sure the - * card is compatible with the driver. Keep in mind that the PCMCIA - * spec specifies the CIS as the lower 8 bits of each word read from - * the CIS, so to read the bytes of the CIS, read every other byte - * (0,2,4,...). Passing that test, you need to enable the I/O address - * space on the PCMCIA card via the PCMCIA COR register. This is the - * first byte following the CIS. In my case (which may not have any - * relation to what's on the PRISM2 cards), COR was at offset 0x800 - * within the PCI memory space. Write 0x41 to the COR register to - * enable I/O mode and to select level triggered interrupts. To - * confirm you actually succeeded, read the COR register back and make - * sure it actually got set to 0x41, in case you have an unexpected - * card inserted. - * - * Following that, you can treat the second PCI I/O address space (the - * one that's not 0x80 in length) as the PCMCIA I/O space. - * - * Note that in the Eumitcom's source for their drivers, they register - * the interrupt as edge triggered when registering it with the - * Windows kernel. I don't recall how to register edge triggered on - * Linux (if it can be done at all). But in some experimentation, I - * don't see much operational difference between using either - * interrupt mode. Don't mess with the interrupt mode in the COR - * register though, as the PLX9052 wants level triggers with the way - * the serial EEPROM configures it on the WL11000. - * - * There's some other little quirks related to timing that I bumped - * into, but I don't recall right now. Also, there's two variants of - * the WL11000 I've seen, revision A1 and T2. These seem to differ - * slightly in the timings configured in the wait-state generator in - * the PLX9052. There have also been some comments from Eumitcom that - * cards shouldn't be hot swapped, apparently due to risk of cooking - * the PLX9052. I'm unsure why they believe this, as I can't see - * anything in the design that would really cause a problem, except - * for crashing drivers not written to expect it. And having developed - * drivers for the WL11000, I'd say it's quite tricky to write code - * that will successfully deal with a hot unplug. Very odd things - * happen on the I/O side of things. But anyway, be warned. Despite - * that, I've hot-swapped a number of times during debugging and - * driver development for various reasons (stuck WAIT# line after the - * radio card's firmware locks up). - */ - -#define DRIVER_NAME "orinoco_plx" -#define PFX DRIVER_NAME ": " - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <pcmcia/cisreg.h> - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ -#define COR_RESET (0x80) /* reset bit in the COR register */ -#define PLX_RESET_TIME (500) /* milliseconds */ - -#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ -#define PLX_INTCSR_INTEN (1 << 6) /* Interrupt Enable bit */ - -/* - * Do a soft reset of the card using the Configuration Option Register - */ -static int orinoco_plx_cor_reset(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - struct orinoco_pci_card *card = priv->card; - unsigned long timeout; - u16 reg; - - iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET); - mdelay(1); - - iowrite8(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + msecs_to_jiffies(PLX_RESET_TIME); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int orinoco_plx_hw_init(struct orinoco_pci_card *card) -{ - int i; - u32 csr_reg; - static const u8 cis_magic[] = { - 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67 - }; - - printk(KERN_DEBUG PFX "CIS: "); - for (i = 0; i < 16; i++) - printk("%02X:", ioread8(card->attr_io + (i << 1))); - printk("\n"); - - /* Verify whether a supported PC card is present */ - /* FIXME: we probably need to be smarted about this */ - for (i = 0; i < sizeof(cis_magic); i++) { - if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) { - printk(KERN_ERR PFX "The CIS value of Prism2 PC " - "card is unexpected\n"); - return -ENODEV; - } - } - - /* bjoern: We need to tell the card to enable interrupts, in - case the serial eprom didn't do this already. See the - PLX9052 data book, p8-1 and 8-24 for reference. */ - csr_reg = ioread32(card->bridge_io + PLX_INTCSR); - if (!(csr_reg & PLX_INTCSR_INTEN)) { - csr_reg |= PLX_INTCSR_INTEN; - iowrite32(csr_reg, card->bridge_io + PLX_INTCSR); - csr_reg = ioread32(card->bridge_io + PLX_INTCSR); - if (!(csr_reg & PLX_INTCSR_INTEN)) { - printk(KERN_ERR PFX "Cannot enable interrupts\n"); - return -EIO; - } - } - - return 0; -} - -static int orinoco_plx_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io, *attr_io, *bridge_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 1, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - attr_io = pci_iomap(pdev, 2, 0); - if (!attr_io) { - printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); - err = -EIO; - goto fail_map_attr; - } - - hermes_io = pci_iomap(pdev, 3, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_plx_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - card->bridge_io = bridge_io; - card->attr_io = attr_io; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_plx_hw_init(card); - if (err) { - printk(KERN_ERR PFX "Hardware initialization failed\n"); - goto fail; - } - - err = orinoco_plx_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail_wiphy; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail_wiphy: - wiphy_unregister(priv_to_wiphy(priv)); - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, attr_io); - - fail_map_attr: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_plx_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct orinoco_pci_card *card = priv->card; - - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(priv)); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->attr_io); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_plx_id_table[] = { - {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ - {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ - {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ - {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, - Eumitcom PCI WL11000, - Addtron AWA-100 */ - {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ - {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ - {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ - {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ - {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by - Brendan W. McAdams <rit AT jacked-in.org> */ - {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by - Damien Persohn <damien AT persohn.net> */ - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table); - -static struct pci_driver orinoco_plx_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_plx_id_table, - .probe = orinoco_plx_init_one, - .remove = orinoco_plx_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Pavel Roskin <proski@gnu.org>," - " David Gibson <hermes@gibson.dropbear.id.au>," - " Daniel Barlow <dan@telent.net>)"; -MODULE_AUTHOR("Daniel Barlow <dan@telent.net>"); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_plx_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_plx_driver); -} - -static void __exit orinoco_plx_exit(void) -{ - pci_unregister_driver(&orinoco_plx_driver); -} - -module_init(orinoco_plx_init); -module_exit(orinoco_plx_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c b/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c deleted file mode 100644 index 939d5a1dce..0000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c +++ /dev/null @@ -1,237 +0,0 @@ -/* orinoco_tmd.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a TMD7160. - * - * Copyright (C) 2003 Joerg Dorchain <joerg AT dorchain.net> - * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * The actual driving is done by main.c, this is just resource - * allocation stuff. - * - * This driver is modeled after the orinoco_plx driver. The main - * difference is that the TMD chip has only IO port ranges and doesn't - * provide access to the PCMCIA attribute space. - * - * Pheecom sells cards with the TMD chip as "ASIC version" - */ - -#define DRIVER_NAME "orinoco_tmd" -#define PFX DRIVER_NAME ": " - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <pcmcia/cisreg.h> - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ -#define COR_RESET (0x80) /* reset bit in the COR register */ -#define TMD_RESET_TIME (500) /* milliseconds */ - -/* - * Do a soft reset of the card using the Configuration Option Register - */ -static int orinoco_tmd_cor_reset(struct orinoco_private *priv) -{ - struct hermes *hw = &priv->hw; - struct orinoco_pci_card *card = priv->card; - unsigned long timeout; - u16 reg; - - iowrite8(COR_VALUE | COR_RESET, card->bridge_io); - mdelay(1); - - iowrite8(COR_VALUE, card->bridge_io); - mdelay(1); - - /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + msecs_to_jiffies(TMD_RESET_TIME); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - - -static int orinoco_tmd_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - void __iomem *hermes_io, *bridge_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 1, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - hermes_io = pci_iomap(pdev, 2, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - priv = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_tmd_cor_reset, NULL); - if (!priv) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - card = priv->card; - card->bridge_io = bridge_io; - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - DRIVER_NAME, priv); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_tmd_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = orinoco_init(priv); - if (err) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto fail; - } - - err = orinoco_if_add(priv, 0, 0, NULL); - if (err) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail; - } - - pci_set_drvdata(pdev, priv); - - return 0; - - fail: - free_irq(pdev->irq, priv); - - fail_irq: - free_orinocodev(priv); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void orinoco_tmd_remove_one(struct pci_dev *pdev) -{ - struct orinoco_private *priv = pci_get_drvdata(pdev); - struct orinoco_pci_card *card = priv->card; - - orinoco_if_del(priv); - free_irq(pdev->irq, priv); - free_orinocodev(priv); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static const struct pci_device_id orinoco_tmd_id_table[] = { - {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table); - -static struct pci_driver orinoco_tmd_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_tmd_id_table, - .probe = orinoco_tmd_init_one, - .remove = orinoco_tmd_remove_one, - .driver.pm = &orinoco_pci_pm_ops, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Joerg Dorchain <joerg@dorchain.net>)"; -MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>"); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_tmd_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_tmd_driver); -} - -static void __exit orinoco_tmd_exit(void) -{ - pci_unregister_driver(&orinoco_tmd_driver); -} - -module_init(orinoco_tmd_init); -module_exit(orinoco_tmd_exit); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c deleted file mode 100644 index 866e0230df..0000000000 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ /dev/null @@ -1,1787 +0,0 @@ -/* - * USB Orinoco driver - * - * Copyright (c) 2003 Manuel Estrada Sainz - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * Queueing code based on linux-wlan-ng 0.2.1-pre5 - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * The license is the same as above. - * - * Initialy based on USB Skeleton driver - 0.7 - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * NOTE: The original USB Skeleton driver is GPL, but all that code is - * gone so MPL/GPL applies. - */ - -#define DRIVER_NAME "orinoco_usb" -#define PFX DRIVER_NAME ": " - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/errno.h> -#include <linux/poll.h> -#include <linux/slab.h> -#include <linux/fcntl.h> -#include <linux/spinlock.h> -#include <linux/list.h> -#include <linux/usb.h> -#include <linux/timer.h> - -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/wireless.h> -#include <linux/firmware.h> -#include <linux/refcount.h> - -#include "mic.h" -#include "orinoco.h" - -#ifndef URB_ASYNC_UNLINK -#define URB_ASYNC_UNLINK 0 -#endif - -struct header_struct { - /* 802.3 */ - u8 dest[ETH_ALEN]; - u8 src[ETH_ALEN]; - __be16 len; - /* 802.2 */ - u8 dsap; - u8 ssap; - u8 ctrl; - /* SNAP */ - u8 oui[3]; - __be16 ethertype; -} __packed; - -struct ez_usb_fw { - u16 size; - const u8 *code; -}; - -static struct ez_usb_fw firmware = { - .size = 0, - .code = NULL, -}; - -/* Debugging macros */ -#undef err -#define err(format, arg...) \ - do { printk(KERN_ERR PFX format "\n", ## arg); } while (0) - -MODULE_FIRMWARE("orinoco_ezusb_fw"); - -/* - * Under some conditions, the card gets stuck and stops paying attention - * to the world (i.e. data communication stalls) until we do something to - * it. Sending an INQ_TALLIES command seems to be enough and should be - * harmless otherwise. This behaviour has been observed when using the - * driver on a systemimager client during installation. In the past a - * timer was used to send INQ_TALLIES commands when there was no other - * activity, but it was troublesome and was removed. - */ - -#define USB_COMPAQ_VENDOR_ID 0x049f /* Compaq Computer Corp. */ -#define USB_COMPAQ_WL215_ID 0x001f /* Compaq WL215 USB Adapter */ -#define USB_COMPAQ_W200_ID 0x0076 /* Compaq W200 USB Adapter */ -#define USB_HP_WL215_ID 0x0082 /* Compaq WL215 USB Adapter */ - -#define USB_MELCO_VENDOR_ID 0x0411 -#define USB_BUFFALO_L11_ID 0x0006 /* BUFFALO WLI-USB-L11 */ -#define USB_BUFFALO_L11G_WR_ID 0x000B /* BUFFALO WLI-USB-L11G-WR */ -#define USB_BUFFALO_L11G_ID 0x000D /* BUFFALO WLI-USB-L11G */ - -#define USB_LUCENT_VENDOR_ID 0x047E /* Lucent Technologies */ -#define USB_LUCENT_ORINOCO_ID 0x0300 /* Lucent/Agere Orinoco USB Client */ - -#define USB_AVAYA8_VENDOR_ID 0x0D98 -#define USB_AVAYAE_VENDOR_ID 0x0D9E -#define USB_AVAYA_WIRELESS_ID 0x0300 /* Avaya USB Wireless Card */ - -#define USB_AGERE_VENDOR_ID 0x0D4E /* Agere Systems */ -#define USB_AGERE_MODEL0801_ID 0x1000 /* USB Wireless Card Model 0801 */ -#define USB_AGERE_MODEL0802_ID 0x1001 /* USB Wireless Card Model 0802 */ -#define USB_AGERE_REBRANDED_ID 0x047A /* USB WLAN Card */ - -#define USB_ELSA_VENDOR_ID 0x05CC -#define USB_ELSA_AIRLANCER_ID 0x3100 /* ELSA AirLancer USB-11 */ - -#define USB_LEGEND_VENDOR_ID 0x0E7C -#define USB_LEGEND_JOYNET_ID 0x0300 /* Joynet USB WLAN Card */ - -#define USB_SAMSUNG_VENDOR_ID 0x04E8 -#define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */ -#define USB_SAMSUNG_SEW2001U2_ID 0x5B11 /* Samsung SEW-2001u Card */ -#define USB_SAMSUNG_SEW2003U_ID 0x7011 /* Samsung SEW-2003U Card */ - -#define USB_IGATE_VENDOR_ID 0x0681 -#define USB_IGATE_IGATE_11M_ID 0x0012 /* I-GATE 11M USB Card */ - -#define USB_FUJITSU_VENDOR_ID 0x0BF8 -#define USB_FUJITSU_E1100_ID 0x1002 /* connect2AIR WLAN E-1100 USB */ - -#define USB_2WIRE_VENDOR_ID 0x1630 -#define USB_2WIRE_WIRELESS_ID 0xff81 /* 2Wire USB Wireless adapter */ - - -#define EZUSB_REQUEST_FW_TRANS 0xA0 -#define EZUSB_REQUEST_TRIGGER 0xAA -#define EZUSB_REQUEST_TRIG_AC 0xAC -#define EZUSB_CPUCS_REG 0x7F92 - -#define EZUSB_RID_TX 0x0700 -#define EZUSB_RID_RX 0x0701 -#define EZUSB_RID_INIT1 0x0702 -#define EZUSB_RID_ACK 0x0710 -#define EZUSB_RID_READ_PDA 0x0800 -#define EZUSB_RID_PROG_INIT 0x0852 -#define EZUSB_RID_PROG_SET_ADDR 0x0853 -#define EZUSB_RID_PROG_BYTES 0x0854 -#define EZUSB_RID_PROG_END 0x0855 -#define EZUSB_RID_DOCMD 0x0860 - -/* Recognize info frames */ -#define EZUSB_IS_INFO(id) ((id >= 0xF000) && (id <= 0xF2FF)) - -#define EZUSB_MAGIC 0x0210 - -#define EZUSB_FRAME_DATA 1 -#define EZUSB_FRAME_CONTROL 2 - -#define DEF_TIMEOUT (3 * HZ) - -#define BULK_BUF_SIZE 2048 - -#define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet)) - -#define FW_BUF_SIZE 64 -#define FW_VAR_OFFSET_PTR 0x359 -#define FW_VAR_VALUE 0 -#define FW_HOLE_START 0x100 -#define FW_HOLE_END 0x300 - -struct ezusb_packet { - __le16 magic; /* 0x0210 */ - u8 req_reply_count; - u8 ans_reply_count; - __le16 frame_type; /* 0x01 for data frames, 0x02 otherwise */ - __le16 size; /* transport size */ - __le16 crc; /* CRC up to here */ - __le16 hermes_len; - __le16 hermes_rid; - u8 data[]; -} __packed; - -/* Table of devices that work or may work with this driver */ -static const struct usb_device_id ezusb_table[] = { - {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_WL215_ID)}, - {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_HP_WL215_ID)}, - {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_W200_ID)}, - {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11_ID)}, - {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_WR_ID)}, - {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_ID)}, - {USB_DEVICE(USB_LUCENT_VENDOR_ID, USB_LUCENT_ORINOCO_ID)}, - {USB_DEVICE(USB_AVAYA8_VENDOR_ID, USB_AVAYA_WIRELESS_ID)}, - {USB_DEVICE(USB_AVAYAE_VENDOR_ID, USB_AVAYA_WIRELESS_ID)}, - {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0801_ID)}, - {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0802_ID)}, - {USB_DEVICE(USB_ELSA_VENDOR_ID, USB_ELSA_AIRLANCER_ID)}, - {USB_DEVICE(USB_LEGEND_VENDOR_ID, USB_LEGEND_JOYNET_ID)}, - {USB_DEVICE_VER(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U1_ID, - 0, 0)}, - {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U2_ID)}, - {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2003U_ID)}, - {USB_DEVICE(USB_IGATE_VENDOR_ID, USB_IGATE_IGATE_11M_ID)}, - {USB_DEVICE(USB_FUJITSU_VENDOR_ID, USB_FUJITSU_E1100_ID)}, - {USB_DEVICE(USB_2WIRE_VENDOR_ID, USB_2WIRE_WIRELESS_ID)}, - {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_REBRANDED_ID)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, ezusb_table); - -/* Structure to hold all of our device specific stuff */ -struct ezusb_priv { - struct usb_device *udev; - struct net_device *dev; - struct mutex mtx; - spinlock_t req_lock; - struct list_head req_pending; - struct list_head req_active; - spinlock_t reply_count_lock; - u16 hermes_reg_fake[0x40]; - u8 *bap_buf; - struct urb *read_urb; - int read_pipe; - int write_pipe; - u8 reply_count; -}; - -enum ezusb_state { - EZUSB_CTX_START, - EZUSB_CTX_QUEUED, - EZUSB_CTX_REQ_SUBMITTED, - EZUSB_CTX_REQ_COMPLETE, - EZUSB_CTX_RESP_RECEIVED, - EZUSB_CTX_REQ_TIMEOUT, - EZUSB_CTX_REQ_FAILED, - EZUSB_CTX_RESP_TIMEOUT, - EZUSB_CTX_REQSUBMIT_FAIL, - EZUSB_CTX_COMPLETE, -}; - -struct request_context { - struct list_head list; - refcount_t refcount; - struct completion done; /* Signals that CTX is dead */ - int killed; - struct urb *outurb; /* OUT for req pkt */ - struct ezusb_priv *upriv; - struct ezusb_packet *buf; - int buf_length; - struct timer_list timer; /* Timeout handling */ - enum ezusb_state state; /* Current state */ - /* the RID that we will wait for */ - u16 out_rid; - u16 in_rid; -}; - - -/* Forward declarations */ -static void ezusb_ctx_complete(struct request_context *ctx); -static void ezusb_req_queue_run(struct ezusb_priv *upriv); -static void ezusb_bulk_in_callback(struct urb *urb); - -static inline u8 ezusb_reply_inc(u8 count) -{ - if (count < 0x7F) - return count + 1; - else - return 1; -} - -static void ezusb_request_context_put(struct request_context *ctx) -{ - if (!refcount_dec_and_test(&ctx->refcount)) - return; - - WARN_ON(!ctx->done.done); - BUG_ON(ctx->outurb->status == -EINPROGRESS); - BUG_ON(timer_pending(&ctx->timer)); - usb_free_urb(ctx->outurb); - kfree(ctx->buf); - kfree(ctx); -} - -static inline void ezusb_mod_timer(struct ezusb_priv *upriv, - struct timer_list *timer, - unsigned long expire) -{ - if (!upriv->udev) - return; - mod_timer(timer, expire); -} - -static void ezusb_request_timerfn(struct timer_list *t) -{ - struct request_context *ctx = from_timer(ctx, t, timer); - - ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; - if (usb_unlink_urb(ctx->outurb) == -EINPROGRESS) { - ctx->state = EZUSB_CTX_REQ_TIMEOUT; - } else { - ctx->state = EZUSB_CTX_RESP_TIMEOUT; - dev_dbg(&ctx->outurb->dev->dev, "couldn't unlink\n"); - refcount_inc(&ctx->refcount); - ctx->killed = 1; - ezusb_ctx_complete(ctx); - ezusb_request_context_put(ctx); - } -}; - -static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv, - u16 out_rid, u16 in_rid) -{ - struct request_context *ctx; - - ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC); - if (!ctx) - return NULL; - - ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC); - if (!ctx->buf) { - kfree(ctx); - return NULL; - } - ctx->outurb = usb_alloc_urb(0, GFP_ATOMIC); - if (!ctx->outurb) { - kfree(ctx->buf); - kfree(ctx); - return NULL; - } - - ctx->upriv = upriv; - ctx->state = EZUSB_CTX_START; - ctx->out_rid = out_rid; - ctx->in_rid = in_rid; - - refcount_set(&ctx->refcount, 1); - init_completion(&ctx->done); - - timer_setup(&ctx->timer, ezusb_request_timerfn, 0); - return ctx; -} - -static void ezusb_ctx_complete(struct request_context *ctx) -{ - struct ezusb_priv *upriv = ctx->upriv; - unsigned long flags; - - spin_lock_irqsave(&upriv->req_lock, flags); - - list_del_init(&ctx->list); - if (upriv->udev) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - ezusb_req_queue_run(upriv); - spin_lock_irqsave(&upriv->req_lock, flags); - } - - switch (ctx->state) { - case EZUSB_CTX_COMPLETE: - case EZUSB_CTX_REQSUBMIT_FAIL: - case EZUSB_CTX_REQ_FAILED: - case EZUSB_CTX_REQ_TIMEOUT: - case EZUSB_CTX_RESP_TIMEOUT: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - if ((ctx->out_rid == EZUSB_RID_TX) && upriv->dev) { - struct net_device *dev = upriv->dev; - struct net_device_stats *stats = &dev->stats; - - if (ctx->state != EZUSB_CTX_COMPLETE) - stats->tx_errors++; - else - stats->tx_packets++; - - netif_wake_queue(dev); - } - complete_all(&ctx->done); - ezusb_request_context_put(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - if (!upriv->udev) { - /* This is normal, as all request contexts get flushed - * when the device is disconnected */ - err("Called, CTX not terminating, but device gone"); - complete_all(&ctx->done); - ezusb_request_context_put(ctx); - break; - } - - err("Called, CTX not in terminating state."); - /* Things are really bad if this happens. Just leak - * the CTX because it may still be linked to the - * queue or the OUT urb may still be active. - * Just leaking at least prevents an Oops or Panic. - */ - break; - } -} - -/* - * ezusb_req_queue_run: - * Description: - * Note: Only one active CTX at any one time, because there's no - * other (reliable) way to match the response URB to the correct - * CTX. - */ -static void ezusb_req_queue_run(struct ezusb_priv *upriv) -{ - unsigned long flags; - struct request_context *ctx; - int result; - - spin_lock_irqsave(&upriv->req_lock, flags); - - if (!list_empty(&upriv->req_active)) - goto unlock; - - if (list_empty(&upriv->req_pending)) - goto unlock; - - ctx = - list_entry(upriv->req_pending.next, struct request_context, - list); - - if (!ctx->upriv->udev) - goto unlock; - - /* We need to split this off to avoid a race condition */ - list_move_tail(&ctx->list, &upriv->req_active); - - if (ctx->state == EZUSB_CTX_QUEUED) { - refcount_inc(&ctx->refcount); - result = usb_submit_urb(ctx->outurb, GFP_ATOMIC); - if (result) { - ctx->state = EZUSB_CTX_REQSUBMIT_FAIL; - - spin_unlock_irqrestore(&upriv->req_lock, flags); - - err("Fatal, failed to submit command urb." - " error=%d\n", result); - - ezusb_ctx_complete(ctx); - ezusb_request_context_put(ctx); - goto done; - } - - ctx->state = EZUSB_CTX_REQ_SUBMITTED; - ezusb_mod_timer(ctx->upriv, &ctx->timer, - jiffies + DEF_TIMEOUT); - } - - unlock: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - done: - return; -} - -static void ezusb_req_enqueue_run(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - unsigned long flags; - - spin_lock_irqsave(&upriv->req_lock, flags); - - if (!ctx->upriv->udev) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - goto done; - } - refcount_inc(&ctx->refcount); - list_add_tail(&ctx->list, &upriv->req_pending); - spin_unlock_irqrestore(&upriv->req_lock, flags); - - ctx->state = EZUSB_CTX_QUEUED; - ezusb_req_queue_run(upriv); - - done: - return; -} - -static void ezusb_request_out_callback(struct urb *urb) -{ - unsigned long flags; - enum ezusb_state state; - struct request_context *ctx = urb->context; - struct ezusb_priv *upriv = ctx->upriv; - - spin_lock_irqsave(&upriv->req_lock, flags); - - del_timer(&ctx->timer); - - if (ctx->killed) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - pr_warn("interrupt called with dead ctx\n"); - goto out; - } - - state = ctx->state; - - if (urb->status == 0) { - switch (state) { - case EZUSB_CTX_REQ_SUBMITTED: - if (ctx->in_rid) { - ctx->state = EZUSB_CTX_REQ_COMPLETE; - /* reply URB still pending */ - ezusb_mod_timer(upriv, &ctx->timer, - jiffies + DEF_TIMEOUT); - spin_unlock_irqrestore(&upriv->req_lock, - flags); - break; - } - fallthrough; - case EZUSB_CTX_RESP_RECEIVED: - /* IN already received before this OUT-ACK */ - ctx->state = EZUSB_CTX_COMPLETE; - spin_unlock_irqrestore(&upriv->req_lock, flags); - ezusb_ctx_complete(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - err("Unexpected state(0x%x, %d) in OUT URB", - state, urb->status); - break; - } - } else { - /* If someone cancels the OUT URB then its status - * should be either -ECONNRESET or -ENOENT. - */ - switch (state) { - case EZUSB_CTX_REQ_SUBMITTED: - case EZUSB_CTX_RESP_RECEIVED: - ctx->state = EZUSB_CTX_REQ_FAILED; - fallthrough; - - case EZUSB_CTX_REQ_FAILED: - case EZUSB_CTX_REQ_TIMEOUT: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - ezusb_ctx_complete(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - err("Unexpected state(0x%x, %d) in OUT URB", - state, urb->status); - break; - } - } - out: - ezusb_request_context_put(ctx); -} - -static void ezusb_request_in_callback(struct ezusb_priv *upriv, - struct urb *urb) -{ - struct ezusb_packet *ans = urb->transfer_buffer; - struct request_context *ctx = NULL; - enum ezusb_state state; - unsigned long flags; - - /* Find the CTX on the active queue that requested this URB */ - spin_lock_irqsave(&upriv->req_lock, flags); - if (upriv->udev) { - struct list_head *item; - - list_for_each(item, &upriv->req_active) { - struct request_context *c; - int reply_count; - - c = list_entry(item, struct request_context, list); - reply_count = - ezusb_reply_inc(c->buf->req_reply_count); - if ((ans->ans_reply_count == reply_count) - && (le16_to_cpu(ans->hermes_rid) == c->in_rid)) { - ctx = c; - break; - } - netdev_dbg(upriv->dev, "Skipped (0x%x/0x%x) (%d/%d)\n", - le16_to_cpu(ans->hermes_rid), c->in_rid, - ans->ans_reply_count, reply_count); - } - } - - if (ctx == NULL) { - spin_unlock_irqrestore(&upriv->req_lock, flags); - err("%s: got unexpected RID: 0x%04X", __func__, - le16_to_cpu(ans->hermes_rid)); - ezusb_req_queue_run(upriv); - return; - } - - /* The data we want is in the in buffer, exchange */ - urb->transfer_buffer = ctx->buf; - ctx->buf = (void *) ans; - ctx->buf_length = urb->actual_length; - - state = ctx->state; - switch (state) { - case EZUSB_CTX_REQ_SUBMITTED: - /* We have received our response URB before - * our request has been acknowledged. Do NOT - * destroy our CTX yet, because our OUT URB - * is still alive ... - */ - ctx->state = EZUSB_CTX_RESP_RECEIVED; - spin_unlock_irqrestore(&upriv->req_lock, flags); - - /* Let the machine continue running. */ - break; - - case EZUSB_CTX_REQ_COMPLETE: - /* This is the usual path: our request - * has already been acknowledged, and - * we have now received the reply. - */ - ctx->state = EZUSB_CTX_COMPLETE; - - /* Stop the intimer */ - del_timer(&ctx->timer); - spin_unlock_irqrestore(&upriv->req_lock, flags); - - /* Call the completion handler */ - ezusb_ctx_complete(ctx); - break; - - default: - spin_unlock_irqrestore(&upriv->req_lock, flags); - - pr_warn("Matched IN URB, unexpected context state(0x%x)\n", - state); - /* Throw this CTX away and try submitting another */ - del_timer(&ctx->timer); - ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; - usb_unlink_urb(ctx->outurb); - ezusb_req_queue_run(upriv); - break; - } /* switch */ -} - -typedef void (*ezusb_ctx_wait)(struct ezusb_priv *, struct request_context *); - -static void ezusb_req_ctx_wait_compl(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - switch (ctx->state) { - case EZUSB_CTX_QUEUED: - case EZUSB_CTX_REQ_SUBMITTED: - case EZUSB_CTX_REQ_COMPLETE: - case EZUSB_CTX_RESP_RECEIVED: - wait_for_completion(&ctx->done); - break; - default: - /* Done or failed - nothing to wait for */ - break; - } -} - -static void ezusb_req_ctx_wait_poll(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - int msecs; - - switch (ctx->state) { - case EZUSB_CTX_QUEUED: - case EZUSB_CTX_REQ_SUBMITTED: - case EZUSB_CTX_REQ_COMPLETE: - case EZUSB_CTX_RESP_RECEIVED: - /* If we get called from a timer or with our lock acquired, then - * we can't wait for the completion and have to poll. This won't - * happen if the USB controller completes the URB requests in - * BH. - */ - msecs = DEF_TIMEOUT * (1000 / HZ); - - while (!try_wait_for_completion(&ctx->done) && msecs--) - udelay(1000); - break; - default: - /* Done or failed - nothing to wait for */ - break; - } -} - -static void ezusb_req_ctx_wait_skip(struct ezusb_priv *upriv, - struct request_context *ctx) -{ - WARN(1, "Shouldn't be invoked for in_rid\n"); -} - -static inline u16 build_crc(struct ezusb_packet *data) -{ - u16 crc = 0; - u8 *bytes = (u8 *)data; - int i; - - for (i = 0; i < 8; i++) - crc = (crc << 1) + bytes[i]; - - return crc; -} - -/* - * ezusb_fill_req: - * - * if data == NULL and length > 0 the data is assumed to be already in - * the target buffer and only the header is filled. - * - */ -static int ezusb_fill_req(struct ezusb_packet *req, u16 length, u16 rid, - const void *data, u16 frame_type, u8 reply_count) -{ - int total_size = sizeof(*req) + length; - - BUG_ON(total_size > BULK_BUF_SIZE); - - req->magic = cpu_to_le16(EZUSB_MAGIC); - req->req_reply_count = reply_count; - req->ans_reply_count = 0; - req->frame_type = cpu_to_le16(frame_type); - req->size = cpu_to_le16(length + 4); - req->crc = cpu_to_le16(build_crc(req)); - req->hermes_len = cpu_to_le16(HERMES_BYTES_TO_RECLEN(length)); - req->hermes_rid = cpu_to_le16(rid); - if (data) - memcpy(req->data, data, length); - return total_size; -} - -static int ezusb_submit_in_urb(struct ezusb_priv *upriv) -{ - int retval = 0; - void *cur_buf = upriv->read_urb->transfer_buffer; - - if (upriv->read_urb->status == -EINPROGRESS) { - netdev_dbg(upriv->dev, "urb busy, not resubmiting\n"); - retval = -EBUSY; - goto exit; - } - usb_fill_bulk_urb(upriv->read_urb, upriv->udev, upriv->read_pipe, - cur_buf, BULK_BUF_SIZE, - ezusb_bulk_in_callback, upriv); - upriv->read_urb->transfer_flags = 0; - retval = usb_submit_urb(upriv->read_urb, GFP_ATOMIC); - if (retval) - err("%s submit failed %d", __func__, retval); - - exit: - return retval; -} - -static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset) -{ - int ret; - u8 *res_val = NULL; - - if (!upriv->udev) { - err("%s: !upriv->udev", __func__); - return -EFAULT; - } - - res_val = kmalloc(sizeof(*res_val), GFP_KERNEL); - - if (!res_val) - return -ENOMEM; - - *res_val = reset; /* avoid argument promotion */ - - ret = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_FW_TRANS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_OUT, EZUSB_CPUCS_REG, 0, res_val, - sizeof(*res_val), DEF_TIMEOUT); - - kfree(res_val); - - return ret; -} - -static int ezusb_firmware_download(struct ezusb_priv *upriv, - struct ez_usb_fw *fw) -{ - u8 *fw_buffer; - int retval, addr; - int variant_offset; - - fw_buffer = kmalloc(FW_BUF_SIZE, GFP_KERNEL); - if (!fw_buffer) { - printk(KERN_ERR PFX "Out of memory for firmware buffer.\n"); - return -ENOMEM; - } - /* - * This byte is 1 and should be replaced with 0. The offset is - * 0x10AD in version 0.0.6. The byte in question should follow - * the end of the code pointed to by the jump in the beginning - * of the firmware. Also, it is read by code located at 0x358. - */ - variant_offset = be16_to_cpup((__be16 *) &fw->code[FW_VAR_OFFSET_PTR]); - if (variant_offset >= fw->size) { - printk(KERN_ERR PFX "Invalid firmware variant offset: " - "0x%04x\n", variant_offset); - retval = -EINVAL; - goto fail; - } - - retval = ezusb_8051_cpucs(upriv, 1); - if (retval < 0) - goto fail; - for (addr = 0; addr < fw->size; addr += FW_BUF_SIZE) { - /* 0x100-0x300 should be left alone, it contains card - * specific data, like USB enumeration information */ - if ((addr >= FW_HOLE_START) && (addr < FW_HOLE_END)) - continue; - - memcpy(fw_buffer, &fw->code[addr], FW_BUF_SIZE); - if (variant_offset >= addr && - variant_offset < addr + FW_BUF_SIZE) { - netdev_dbg(upriv->dev, - "Patching card_variant byte at 0x%04X\n", - variant_offset); - fw_buffer[variant_offset - addr] = FW_VAR_VALUE; - } - retval = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_FW_TRANS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE - | USB_DIR_OUT, - addr, 0x0, - fw_buffer, FW_BUF_SIZE, - DEF_TIMEOUT); - - if (retval < 0) - goto fail; - } - retval = ezusb_8051_cpucs(upriv, 0); - if (retval < 0) - goto fail; - - goto exit; - fail: - printk(KERN_ERR PFX "Firmware download failed, error %d\n", - retval); - exit: - kfree(fw_buffer); - return retval; -} - -static int ezusb_access_ltv(struct ezusb_priv *upriv, - struct request_context *ctx, - u16 length, const void *data, u16 frame_type, - void *ans_buff, unsigned ans_size, u16 *ans_length, - ezusb_ctx_wait ezusb_ctx_wait_func) -{ - int req_size; - int retval = 0; - enum ezusb_state state; - - if (!upriv->udev) { - retval = -ENODEV; - goto exit; - } - - if (upriv->read_urb->status != -EINPROGRESS) - err("%s: in urb not pending", __func__); - - /* protect upriv->reply_count, guarantee sequential numbers */ - spin_lock_bh(&upriv->reply_count_lock); - req_size = ezusb_fill_req(ctx->buf, length, ctx->out_rid, data, - frame_type, upriv->reply_count); - usb_fill_bulk_urb(ctx->outurb, upriv->udev, upriv->write_pipe, - ctx->buf, req_size, - ezusb_request_out_callback, ctx); - - if (ctx->in_rid) - upriv->reply_count = ezusb_reply_inc(upriv->reply_count); - - ezusb_req_enqueue_run(upriv, ctx); - - spin_unlock_bh(&upriv->reply_count_lock); - - if (ctx->in_rid) - ezusb_ctx_wait_func(upriv, ctx); - - state = ctx->state; - switch (state) { - case EZUSB_CTX_COMPLETE: - retval = ctx->outurb->status; - break; - - case EZUSB_CTX_QUEUED: - case EZUSB_CTX_REQ_SUBMITTED: - if (!ctx->in_rid) - break; - fallthrough; - default: - err("%s: Unexpected context state %d", __func__, - state); - fallthrough; - case EZUSB_CTX_REQ_TIMEOUT: - case EZUSB_CTX_REQ_FAILED: - case EZUSB_CTX_RESP_TIMEOUT: - case EZUSB_CTX_REQSUBMIT_FAIL: - printk(KERN_ERR PFX "Access failed, resetting (state %d," - " reply_count %d)\n", state, upriv->reply_count); - upriv->reply_count = 0; - if (state == EZUSB_CTX_REQ_TIMEOUT - || state == EZUSB_CTX_RESP_TIMEOUT) { - printk(KERN_ERR PFX "ctx timed out\n"); - retval = -ETIMEDOUT; - } else { - printk(KERN_ERR PFX "ctx failed\n"); - retval = -EFAULT; - } - goto exit; - } - if (ctx->in_rid) { - struct ezusb_packet *ans = ctx->buf; - unsigned exp_len; - - if (ans->hermes_len != 0) - exp_len = le16_to_cpu(ans->hermes_len) * 2 + 12; - else - exp_len = 14; - - if (exp_len != ctx->buf_length) { - err("%s: length mismatch for RID 0x%04x: " - "expected %d, got %d", __func__, - ctx->in_rid, exp_len, ctx->buf_length); - retval = -EIO; - goto exit; - } - - if (ans_buff) - memcpy(ans_buff, ans->data, min(exp_len, ans_size)); - if (ans_length) - *ans_length = le16_to_cpu(ans->hermes_len); - } - exit: - ezusb_request_context_put(ctx); - return retval; -} - -static int __ezusb_write_ltv(struct hermes *hw, int bap, u16 rid, - u16 length, const void *data, - ezusb_ctx_wait ezusb_ctx_wait_func) -{ - struct ezusb_priv *upriv = hw->priv; - u16 frame_type; - struct request_context *ctx; - - if (length == 0) - return -EINVAL; - - length = HERMES_RECLEN_TO_BYTES(length); - - /* On memory mapped devices HERMES_RID_CNFGROUPADDRESSES can be - * set to be empty, but the USB bridge doesn't like it */ - if (length == 0) - return 0; - - ctx = ezusb_alloc_ctx(upriv, rid, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - if (rid == EZUSB_RID_TX) - frame_type = EZUSB_FRAME_DATA; - else - frame_type = EZUSB_FRAME_CONTROL; - - return ezusb_access_ltv(upriv, ctx, length, data, frame_type, - NULL, 0, NULL, ezusb_ctx_wait_func); -} - -static int ezusb_write_ltv(struct hermes *hw, int bap, u16 rid, - u16 length, const void *data) -{ - return __ezusb_write_ltv(hw, bap, rid, length, data, - ezusb_req_ctx_wait_poll); -} - -static int __ezusb_read_ltv(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf, - ezusb_ctx_wait ezusb_ctx_wait_func) - -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - - if (bufsize % 2) - return -EINVAL; - - ctx = ezusb_alloc_ctx(upriv, rid, rid); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL, - buf, bufsize, length, ezusb_req_ctx_wait_poll); -} - -static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf) -{ - return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf, - ezusb_req_ctx_wait_poll); -} - -static int ezusb_read_ltv_preempt(struct hermes *hw, int bap, u16 rid, - unsigned bufsize, u16 *length, void *buf) -{ - return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1, - u16 parm2, struct hermes_response *resp) -{ - WARN_ON_ONCE(1); - return -EINVAL; -} - -static int __ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp, - ezusb_ctx_wait ezusb_ctx_wait_func) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - - __le16 data[4] = { - cpu_to_le16(cmd), - cpu_to_le16(parm0), - 0, - 0, - }; - netdev_dbg(upriv->dev, "0x%04X, parm0 0x%04X\n", cmd, parm0); - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_ctx_wait_func); -} - -static int ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, - struct hermes_response *resp) -{ - return __ezusb_docmd_wait(hw, cmd, parm0, resp, ezusb_req_ctx_wait_poll); -} - -static int ezusb_bap_pread(struct hermes *hw, int bap, - void *buf, int len, u16 id, u16 offset) -{ - struct ezusb_priv *upriv = hw->priv; - struct ezusb_packet *ans = (void *) upriv->read_urb->transfer_buffer; - int actual_length = upriv->read_urb->actual_length; - - if (id == EZUSB_RID_RX) { - if ((sizeof(*ans) + offset + len) > actual_length) { - printk(KERN_ERR PFX "BAP read beyond buffer end " - "in rx frame\n"); - return -EINVAL; - } - memcpy(buf, ans->data + offset, len); - return 0; - } - - if (EZUSB_IS_INFO(id)) { - /* Include 4 bytes for length/type */ - if ((sizeof(*ans) + offset + len - 4) > actual_length) { - printk(KERN_ERR PFX "BAP read beyond buffer end " - "in info frame\n"); - return -EFAULT; - } - memcpy(buf, ans->data + offset - 4, len); - } else { - printk(KERN_ERR PFX "Unexpected fid 0x%04x\n", id); - return -EINVAL; - } - - return 0; -} - -static int ezusb_read_pda(struct hermes *hw, __le16 *pda, - u32 pda_addr, u16 pda_len) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - __le16 data[] = { - cpu_to_le16(pda_addr & 0xffff), - cpu_to_le16(pda_len - 4) - }; - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA); - if (!ctx) - return -ENOMEM; - - /* wl_lkm does not include PDA size in the PDA area. - * We will pad the information into pda, so other routines - * don't have to be modified */ - pda[0] = cpu_to_le16(pda_len - 2); - /* Includes CFG_PROD_DATA but not itself */ - pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ - - return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4, - NULL, ezusb_req_ctx_wait_compl); -} - -static int ezusb_program_init(struct hermes *hw, u32 entry_point) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - __le32 data = cpu_to_le32(entry_point); - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_program_end(struct hermes *hw) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, 0, NULL, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_program_bytes(struct hermes *hw, const char *buf, - u32 addr, u32 len) -{ - struct ezusb_priv *upriv = hw->priv; - struct request_context *ctx; - __le32 data = cpu_to_le32(addr); - int err; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); - if (err) - return err; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK); - if (!ctx) - return -ENOMEM; - - return ezusb_access_ltv(upriv, ctx, len, buf, - EZUSB_FRAME_CONTROL, NULL, 0, NULL, - ezusb_req_ctx_wait_compl); -} - -static int ezusb_program(struct hermes *hw, const char *buf, - u32 addr, u32 len) -{ - u32 ch_addr; - u32 ch_len; - int err = 0; - - /* We can only send 2048 bytes out of the bulk xmit at a time, - * so we have to split any programming into chunks of <2048 - * bytes. */ - - ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE; - ch_addr = addr; - - while (ch_addr < (addr + len)) { - pr_debug("Programming subblock of length %d " - "to address 0x%08x. Data @ %p\n", - ch_len, ch_addr, &buf[ch_addr - addr]); - - err = ezusb_program_bytes(hw, &buf[ch_addr - addr], - ch_addr, ch_len); - if (err) - break; - - ch_addr += ch_len; - ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ? - (addr + len - ch_addr) : MAX_DL_SIZE; - } - - return err; -} - -static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct ezusb_priv *upriv = priv->card; - u8 mic[MICHAEL_MIC_LEN + 1]; - int err = 0; - int tx_control; - unsigned long flags; - struct request_context *ctx; - u8 *buf; - int tx_size; - - if (!netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (netif_queue_stopped(dev)) { - printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_ERR - "%s: ezusb_xmit() called while hw_unavailable\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (!netif_carrier_ok(dev) || - (priv->iw_mode == NL80211_IFTYPE_MONITOR)) { - /* Oops, the firmware hasn't established a connection, - silently drop the packet (this seems to be the - safest approach). */ - goto drop; - } - - /* Check packet length */ - if (skb->len < ETH_HLEN) - goto drop; - - tx_control = 0; - - err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control, - &mic[0]); - if (err) - goto drop; - - ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0); - if (!ctx) - goto drop; - - memset(ctx->buf, 0, BULK_BUF_SIZE); - buf = ctx->buf->data; - - { - __le16 *tx_cntl = (__le16 *)buf; - *tx_cntl = cpu_to_le16(tx_control); - buf += sizeof(*tx_cntl); - } - - memcpy(buf, skb->data, skb->len); - buf += skb->len; - - if (tx_control & HERMES_TXCTRL_MIC) { - u8 *m = mic; - /* Mic has been offset so it can be copied to an even - * address. We're copying eveything anyway, so we - * don't need to copy that first byte. */ - if (skb->len % 2) - m++; - memcpy(buf, m, MICHAEL_MIC_LEN); - buf += MICHAEL_MIC_LEN; - } - - /* Finally, we actually initiate the send */ - netif_stop_queue(dev); - - /* The card may behave better if we send evenly sized usb transfers */ - tx_size = ALIGN(buf - ctx->buf->data, 2); - - err = ezusb_access_ltv(upriv, ctx, tx_size, NULL, - EZUSB_FRAME_DATA, NULL, 0, NULL, - ezusb_req_ctx_wait_skip); - - if (err) { - netif_start_queue(dev); - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d transmitting packet\n", - dev->name, err); - goto busy; - } - - netif_trans_update(dev); - stats->tx_bytes += skb->len; - goto ok; - - drop: - stats->tx_errors++; - stats->tx_dropped++; - - ok: - orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - - busy: - orinoco_unlock(priv, &flags); - return NETDEV_TX_BUSY; -} - -static int ezusb_allocate(struct hermes *hw, u16 size, u16 *fid) -{ - *fid = EZUSB_RID_TX; - return 0; -} - - -static int ezusb_hard_reset(struct orinoco_private *priv) -{ - struct ezusb_priv *upriv = priv->card; - int retval = ezusb_8051_cpucs(upriv, 1); - - if (retval < 0) { - err("Failed to reset"); - return retval; - } - - retval = ezusb_8051_cpucs(upriv, 0); - if (retval < 0) { - err("Failed to unreset"); - return retval; - } - - netdev_dbg(upriv->dev, "sending control message\n"); - retval = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_TRIGGER, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_OUT, 0x0, 0x0, NULL, 0, - DEF_TIMEOUT); - if (retval < 0) { - err("EZUSB_REQUEST_TRIGGER failed retval %d", retval); - return retval; - } -#if 0 - dbg("Sending EZUSB_REQUEST_TRIG_AC"); - retval = usb_control_msg(upriv->udev, - usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_TRIG_AC, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_OUT, 0x00FA, 0x0, NULL, 0, - DEF_TIMEOUT); - if (retval < 0) { - err("EZUSB_REQUEST_TRIG_AC failed retval %d", retval); - return retval; - } -#endif - - return 0; -} - - -static int ezusb_init(struct hermes *hw) -{ - struct ezusb_priv *upriv = hw->priv; - int retval; - - if (!upriv) - return -EINVAL; - - upriv->reply_count = 0; - /* Write the MAGIC number on the simulated registers to keep - * orinoco.c happy */ - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - hermes_write_regn(hw, RXFID, EZUSB_RID_RX); - - usb_kill_urb(upriv->read_urb); - ezusb_submit_in_urb(upriv); - - retval = __ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1, - HERMES_BYTES_TO_RECLEN(2), "\x10\x00", - ezusb_req_ctx_wait_compl); - if (retval < 0) { - printk(KERN_ERR PFX "EZUSB_RID_INIT1 error %d\n", retval); - return retval; - } - - retval = __ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL, - ezusb_req_ctx_wait_compl); - if (retval < 0) { - printk(KERN_ERR PFX "HERMES_CMD_INIT error %d\n", retval); - return retval; - } - - return 0; -} - -static void ezusb_bulk_in_callback(struct urb *urb) -{ - struct ezusb_priv *upriv = (struct ezusb_priv *) urb->context; - struct ezusb_packet *ans = urb->transfer_buffer; - u16 crc; - u16 hermes_rid; - - if (upriv->udev == NULL) - return; - - if (urb->status == -ETIMEDOUT) { - /* When a device gets unplugged we get this every time - * we resubmit, flooding the logs. Since we don't use - * USB timeouts, it shouldn't happen any other time*/ - pr_warn("%s: urb timed out, not resubmitting\n", __func__); - return; - } - if (urb->status == -ECONNABORTED) { - pr_warn("%s: connection abort, resubmitting urb\n", - __func__); - goto resubmit; - } - if ((urb->status == -EILSEQ) - || (urb->status == -ENOENT) - || (urb->status == -ECONNRESET)) { - netdev_dbg(upriv->dev, "status %d, not resubmiting\n", - urb->status); - return; - } - if (urb->status) - netdev_dbg(upriv->dev, "status: %d length: %d\n", - urb->status, urb->actual_length); - if (urb->actual_length < sizeof(*ans)) { - err("%s: short read, ignoring", __func__); - goto resubmit; - } - crc = build_crc(ans); - if (le16_to_cpu(ans->crc) != crc) { - err("CRC error, ignoring packet"); - goto resubmit; - } - - hermes_rid = le16_to_cpu(ans->hermes_rid); - if ((hermes_rid != EZUSB_RID_RX) && !EZUSB_IS_INFO(hermes_rid)) { - ezusb_request_in_callback(upriv, urb); - } else if (upriv->dev) { - struct net_device *dev = upriv->dev; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - - if (hermes_rid == EZUSB_RID_RX) { - __orinoco_ev_rx(dev, hw); - } else { - hermes_write_regn(hw, INFOFID, - le16_to_cpu(ans->hermes_rid)); - __orinoco_ev_info(dev, hw); - } - } - - resubmit: - if (upriv->udev) - ezusb_submit_in_urb(upriv); -} - -static inline void ezusb_delete(struct ezusb_priv *upriv) -{ - struct list_head *item; - struct list_head *tmp_item; - unsigned long flags; - - BUG_ON(!upriv); - - mutex_lock(&upriv->mtx); - - upriv->udev = NULL; /* No timer will be rearmed from here */ - - usb_kill_urb(upriv->read_urb); - - spin_lock_irqsave(&upriv->req_lock, flags); - list_for_each_safe(item, tmp_item, &upriv->req_active) { - struct request_context *ctx; - int err; - - ctx = list_entry(item, struct request_context, list); - refcount_inc(&ctx->refcount); - - ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; - err = usb_unlink_urb(ctx->outurb); - - spin_unlock_irqrestore(&upriv->req_lock, flags); - if (err == -EINPROGRESS) - wait_for_completion(&ctx->done); - - del_timer_sync(&ctx->timer); - /* FIXME: there is an slight chance for the irq handler to - * be running */ - if (!list_empty(&ctx->list)) - ezusb_ctx_complete(ctx); - - ezusb_request_context_put(ctx); - spin_lock_irqsave(&upriv->req_lock, flags); - } - spin_unlock_irqrestore(&upriv->req_lock, flags); - - list_for_each_safe(item, tmp_item, &upriv->req_pending) - ezusb_ctx_complete(list_entry(item, - struct request_context, list)); - - if (upriv->read_urb && upriv->read_urb->status == -EINPROGRESS) - printk(KERN_ERR PFX "Some URB in progress\n"); - - mutex_unlock(&upriv->mtx); - - if (upriv->read_urb) { - kfree(upriv->read_urb->transfer_buffer); - usb_free_urb(upriv->read_urb); - } - kfree(upriv->bap_buf); - if (upriv->dev) { - struct orinoco_private *priv = ndev_priv(upriv->dev); - orinoco_if_del(priv); - wiphy_unregister(priv_to_wiphy(upriv)); - free_orinocodev(priv); - } -} - -static void ezusb_lock_irqsave(spinlock_t *lock, - unsigned long *flags) __acquires(lock) -{ - spin_lock_bh(lock); -} - -static void ezusb_unlock_irqrestore(spinlock_t *lock, - unsigned long *flags) __releases(lock) -{ - spin_unlock_bh(lock); -} - -static void ezusb_lock_irq(spinlock_t *lock) __acquires(lock) -{ - spin_lock_bh(lock); -} - -static void ezusb_unlock_irq(spinlock_t *lock) __releases(lock) -{ - spin_unlock_bh(lock); -} - -static const struct hermes_ops ezusb_ops = { - .init = ezusb_init, - .cmd_wait = ezusb_docmd_wait, - .init_cmd_wait = ezusb_doicmd_wait, - .allocate = ezusb_allocate, - .read_ltv = ezusb_read_ltv, - .read_ltv_pr = ezusb_read_ltv_preempt, - .write_ltv = ezusb_write_ltv, - .bap_pread = ezusb_bap_pread, - .read_pda = ezusb_read_pda, - .program_init = ezusb_program_init, - .program_end = ezusb_program_end, - .program = ezusb_program, - .lock_irqsave = ezusb_lock_irqsave, - .unlock_irqrestore = ezusb_unlock_irqrestore, - .lock_irq = ezusb_lock_irq, - .unlock_irq = ezusb_unlock_irq, -}; - -static const struct net_device_ops ezusb_netdev_ops = { - .ndo_open = orinoco_open, - .ndo_stop = orinoco_stop, - .ndo_start_xmit = ezusb_xmit, - .ndo_set_rx_mode = orinoco_set_multicast_list, - .ndo_change_mtu = orinoco_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_tx_timeout = orinoco_tx_timeout, -}; - -static int ezusb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct orinoco_private *priv; - struct hermes *hw; - struct ezusb_priv *upriv = NULL; - struct usb_interface_descriptor *iface_desc; - struct usb_endpoint_descriptor *ep; - const struct firmware *fw_entry = NULL; - int retval = 0; - int i; - - priv = alloc_orinocodev(sizeof(*upriv), &udev->dev, - ezusb_hard_reset, NULL); - if (!priv) { - err("Couldn't allocate orinocodev"); - retval = -ENOMEM; - goto exit; - } - - hw = &priv->hw; - - upriv = priv->card; - - mutex_init(&upriv->mtx); - spin_lock_init(&upriv->reply_count_lock); - - spin_lock_init(&upriv->req_lock); - INIT_LIST_HEAD(&upriv->req_pending); - INIT_LIST_HEAD(&upriv->req_active); - - upriv->udev = udev; - - hw->iobase = (void __force __iomem *) &upriv->hermes_reg_fake; - hw->reg_spacing = HERMES_16BIT_REGSPACING; - hw->priv = upriv; - hw->ops = &ezusb_ops; - - /* set up the endpoint information */ - /* check out the endpoints */ - - iface_desc = &interface->cur_altsetting->desc; - for (i = 0; i < iface_desc->bNumEndpoints; ++i) { - ep = &interface->cur_altsetting->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(ep)) { - /* we found a bulk in endpoint */ - if (upriv->read_urb != NULL) { - pr_warn("Found a second bulk in ep, ignored\n"); - continue; - } - - upriv->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!upriv->read_urb) - goto error; - if (le16_to_cpu(ep->wMaxPacketSize) != 64) - pr_warn("bulk in: wMaxPacketSize!= 64\n"); - if (ep->bEndpointAddress != (2 | USB_DIR_IN)) - pr_warn("bulk in: bEndpointAddress: %d\n", - ep->bEndpointAddress); - upriv->read_pipe = usb_rcvbulkpipe(udev, - ep-> - bEndpointAddress); - upriv->read_urb->transfer_buffer = - kmalloc(BULK_BUF_SIZE, GFP_KERNEL); - if (!upriv->read_urb->transfer_buffer) { - err("Couldn't allocate IN buffer"); - goto error; - } - } - - if (usb_endpoint_is_bulk_out(ep)) { - /* we found a bulk out endpoint */ - if (upriv->bap_buf != NULL) { - pr_warn("Found a second bulk out ep, ignored\n"); - continue; - } - - if (le16_to_cpu(ep->wMaxPacketSize) != 64) - pr_warn("bulk out: wMaxPacketSize != 64\n"); - if (ep->bEndpointAddress != 2) - pr_warn("bulk out: bEndpointAddress: %d\n", - ep->bEndpointAddress); - upriv->write_pipe = usb_sndbulkpipe(udev, - ep-> - bEndpointAddress); - upriv->bap_buf = kmalloc(BULK_BUF_SIZE, GFP_KERNEL); - if (!upriv->bap_buf) { - err("Couldn't allocate bulk_out_buffer"); - goto error; - } - } - } - if (!upriv->bap_buf || !upriv->read_urb) { - err("Didn't find the required bulk endpoints"); - goto error; - } - - if (request_firmware(&fw_entry, "orinoco_ezusb_fw", - &interface->dev) == 0) { - firmware.size = fw_entry->size; - firmware.code = fw_entry->data; - } - if (firmware.size && firmware.code) { - if (ezusb_firmware_download(upriv, &firmware) < 0) - goto error; - } else { - err("No firmware to download"); - goto error; - } - - if (ezusb_hard_reset(priv) < 0) { - err("Cannot reset the device"); - goto error; - } - - /* If the firmware is already downloaded orinoco.c will call - * ezusb_init but if the firmware is not already there, that will make - * the kernel very unstable, so we try initializing here and quit in - * case of error */ - if (ezusb_init(hw) < 0) { - err("Couldn't initialize the device"); - err("Firmware may not be downloaded or may be wrong."); - goto error; - } - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - err("orinoco_init() failed\n"); - goto error; - } - - if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) { - upriv->dev = NULL; - err("%s: orinoco_if_add() failed", __func__); - wiphy_unregister(priv_to_wiphy(priv)); - goto error; - } - upriv->dev = priv->ndev; - - goto exit; - - error: - ezusb_delete(upriv); - if (upriv->dev) { - /* upriv->dev was 0, so ezusb_delete() didn't free it */ - free_orinocodev(priv); - } - upriv = NULL; - retval = -EFAULT; - exit: - if (fw_entry) { - firmware.code = NULL; - firmware.size = 0; - release_firmware(fw_entry); - } - usb_set_intfdata(interface, upriv); - return retval; -} - - -static void ezusb_disconnect(struct usb_interface *intf) -{ - struct ezusb_priv *upriv = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - ezusb_delete(upriv); - printk(KERN_INFO PFX "Disconnected\n"); -} - - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver orinoco_driver = { - .name = DRIVER_NAME, - .probe = ezusb_probe, - .disconnect = ezusb_disconnect, - .id_table = ezusb_table, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(orinoco_driver); - -MODULE_AUTHOR("Manuel Estrada Sainz"); -MODULE_DESCRIPTION("Driver for Orinoco wireless LAN cards using EZUSB bridge"); -MODULE_LICENSE("Dual MPL/GPL"); diff --git a/drivers/net/wireless/intersil/orinoco/scan.c b/drivers/net/wireless/intersil/orinoco/scan.c deleted file mode 100644 index 6d1d084854..0000000000 --- a/drivers/net/wireless/intersil/orinoco/scan.c +++ /dev/null @@ -1,259 +0,0 @@ -/* Helpers for managing scan queues - * - * See copyright notice in main.c - */ - -#include <linux/gfp.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/ieee80211.h> -#include <net/cfg80211.h> - -#include "hermes.h" -#include "orinoco.h" -#include "main.h" - -#include "scan.h" - -#define ZERO_DBM_OFFSET 0x95 -#define MAX_SIGNAL_LEVEL 0x8A -#define MIN_SIGNAL_LEVEL 0x2F - -#define SIGNAL_TO_DBM(x) \ - (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \ - - ZERO_DBM_OFFSET) -#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100) - -static int symbol_build_supp_rates(u8 *buf, const __le16 *rates) -{ - int i; - u8 rate; - - buf[0] = WLAN_EID_SUPP_RATES; - for (i = 0; i < 5; i++) { - rate = le16_to_cpu(rates[i]); - /* NULL terminated */ - if (rate == 0x0) - break; - buf[i + 2] = rate; - } - buf[1] = i; - - return i + 2; -} - -static int prism_build_supp_rates(u8 *buf, const u8 *rates) -{ - int i; - - buf[0] = WLAN_EID_SUPP_RATES; - for (i = 0; i < 8; i++) { - /* NULL terminated */ - if (rates[i] == 0x0) - break; - buf[i + 2] = rates[i]; - } - buf[1] = i; - - /* We might still have another 2 rates, which need to go in - * extended supported rates */ - if (i == 8 && rates[i] > 0) { - buf[10] = WLAN_EID_EXT_SUPP_RATES; - for (; i < 10; i++) { - /* NULL terminated */ - if (rates[i] == 0x0) - break; - buf[i + 2] = rates[i]; - } - buf[11] = i - 8; - } - - return (i < 8) ? i + 2 : i + 4; -} - -static void orinoco_add_hostscan_result(struct orinoco_private *priv, - const union hermes_scan_info *bss) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct ieee80211_channel *channel; - struct cfg80211_bss *cbss; - u8 *ie; - u8 ie_buf[46]; - u64 timestamp; - s32 signal; - u16 capability; - u16 beacon_interval; - int ie_len; - int freq; - int len; - - len = le16_to_cpu(bss->a.essid_len); - - /* Reconstruct SSID and bitrate IEs to pass up */ - ie_buf[0] = WLAN_EID_SSID; - ie_buf[1] = len; - memcpy(&ie_buf[2], bss->a.essid, len); - - ie = ie_buf + len + 2; - ie_len = ie_buf[1] + 2; - switch (priv->firmware_type) { - case FIRMWARE_TYPE_SYMBOL: - ie_len += symbol_build_supp_rates(ie, bss->s.rates); - break; - - case FIRMWARE_TYPE_INTERSIL: - ie_len += prism_build_supp_rates(ie, bss->p.rates); - break; - - case FIRMWARE_TYPE_AGERE: - default: - break; - } - - freq = ieee80211_channel_to_frequency( - le16_to_cpu(bss->a.channel), NL80211_BAND_2GHZ); - channel = ieee80211_get_channel(wiphy, freq); - if (!channel) { - printk(KERN_DEBUG "Invalid channel designation %04X(%04X)", - bss->a.channel, freq); - return; /* Then ignore it for now */ - } - timestamp = 0; - capability = le16_to_cpu(bss->a.capabilities); - beacon_interval = le16_to_cpu(bss->a.beacon_interv); - signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level)); - - cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, - bss->a.bssid, timestamp, capability, - beacon_interval, ie_buf, ie_len, signal, - GFP_KERNEL); - cfg80211_put_bss(wiphy, cbss); -} - -void orinoco_add_extscan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *bss, - size_t len) -{ - struct wiphy *wiphy = priv_to_wiphy(priv); - struct ieee80211_channel *channel; - struct cfg80211_bss *cbss; - const u8 *ie; - u64 timestamp; - s32 signal; - u16 capability; - u16 beacon_interval; - size_t ie_len; - int chan, freq; - - ie_len = len - sizeof(*bss); - ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len); - chan = ie ? ie[2] : 0; - freq = ieee80211_channel_to_frequency(chan, NL80211_BAND_2GHZ); - channel = ieee80211_get_channel(wiphy, freq); - - timestamp = le64_to_cpu(bss->timestamp); - capability = le16_to_cpu(bss->capabilities); - beacon_interval = le16_to_cpu(bss->beacon_interval); - ie = bss->data; - signal = SIGNAL_TO_MBM(bss->level); - - cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, - bss->bssid, timestamp, capability, - beacon_interval, ie, ie_len, signal, - GFP_KERNEL); - cfg80211_put_bss(wiphy, cbss); -} - -void orinoco_add_hostscan_results(struct orinoco_private *priv, - unsigned char *buf, - size_t len) -{ - int offset; /* In the scan data */ - size_t atom_len; - bool abort = false; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - atom_len = sizeof(struct agere_scan_apinfo); - offset = 0; - break; - - case FIRMWARE_TYPE_SYMBOL: - /* Lack of documentation necessitates this hack. - * Different firmwares have 68 or 76 byte long atoms. - * We try modulo first. If the length divides by both, - * we check what would be the channel in the second - * frame for a 68-byte atom. 76-byte atoms have 0 there. - * Valid channel cannot be 0. */ - if (len % 76) - atom_len = 68; - else if (len % 68) - atom_len = 76; - else if (len >= 1292 && buf[68] == 0) - atom_len = 76; - else - atom_len = 68; - offset = 0; - break; - - case FIRMWARE_TYPE_INTERSIL: - offset = 4; - if (priv->has_hostscan) { - atom_len = le16_to_cpup((__le16 *)buf); - /* Sanity check for atom_len */ - if (atom_len < sizeof(struct prism2_scan_apinfo)) { - printk(KERN_ERR "%s: Invalid atom_len in scan " - "data: %zu\n", priv->ndev->name, - atom_len); - abort = true; - goto scan_abort; - } - } else - atom_len = offsetof(struct prism2_scan_apinfo, atim); - break; - - default: - abort = true; - goto scan_abort; - } - - /* Check that we got an whole number of atoms */ - if ((len - offset) % atom_len) { - printk(KERN_ERR "%s: Unexpected scan data length %zu, " - "atom_len %zu, offset %d\n", priv->ndev->name, len, - atom_len, offset); - abort = true; - goto scan_abort; - } - - /* Process the entries one by one */ - for (; offset + atom_len <= len; offset += atom_len) { - union hermes_scan_info *atom; - - atom = (union hermes_scan_info *) (buf + offset); - - orinoco_add_hostscan_result(priv, atom); - } - - scan_abort: - if (priv->scan_request) { - struct cfg80211_scan_info info = { - .aborted = abort, - }; - - cfg80211_scan_done(priv->scan_request, &info); - priv->scan_request = NULL; - } -} - -void orinoco_scan_done(struct orinoco_private *priv, bool abort) -{ - if (priv->scan_request) { - struct cfg80211_scan_info info = { - .aborted = abort, - }; - - cfg80211_scan_done(priv->scan_request, &info); - priv->scan_request = NULL; - } -} diff --git a/drivers/net/wireless/intersil/orinoco/scan.h b/drivers/net/wireless/intersil/orinoco/scan.h deleted file mode 100644 index 27281fb0a6..0000000000 --- a/drivers/net/wireless/intersil/orinoco/scan.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Helpers for managing scan queues - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_SCAN_H_ -#define _ORINOCO_SCAN_H_ - -/* Forward declarations */ -struct orinoco_private; -struct agere_ext_scan_info; - -/* Add scan results */ -void orinoco_add_extscan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *atom, - size_t len); -void orinoco_add_hostscan_results(struct orinoco_private *dev, - unsigned char *buf, - size_t len); -void orinoco_scan_done(struct orinoco_private *priv, bool abort); - -#endif /* _ORINOCO_SCAN_H_ */ diff --git a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c b/drivers/net/wireless/intersil/orinoco/spectrum_cs.c deleted file mode 100644 index 841d623c62..0000000000 --- a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as - * Symbol Wireless Networker LA4137, CompactFlash cards by Socket - * Communications and Intel PRO/Wireless 2011B. - * - * The driver implements Symbol firmware download. The rest is handled - * in hermes.c and main.c. - * - * Utilities for downloading the Symbol firmware are available at - * http://sourceforge.net/projects/orinoco/ - * - * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org> - * Portions based on orinoco_cs.c: - * Copyright (C) David Gibson, Linuxcare Australia - * Portions based on Spectrum24tDnld.c from original spectrum24 driver: - * Copyright (C) Symbol Technologies. - * - * See copyright notice in file main.c. - */ - -#define DRIVER_NAME "spectrum_cs" -#define PFX DRIVER_NAME ": " - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> - -#include "orinoco.h" - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"); -MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Module parameters */ - -/* Some D-Link cards have buggy CIS. They do work at 5v properly, but - * don't have any CIS entry for it. This workaround it... */ -static int ignore_cis_vcc; /* = 0 */ -module_param(ignore_cis_vcc, int, 0); -MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -/* PCMCIA specific device information (goes in the card field of - * struct orinoco_private */ -struct orinoco_pccard { - struct pcmcia_device *p_dev; -}; - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int spectrum_cs_config(struct pcmcia_device *link); -static void spectrum_cs_release(struct pcmcia_device *link); - -/* Constants for the CISREG_CCSR register */ -#define HCR_RUN 0x07 /* run firmware after reset */ -#define HCR_IDLE 0x0E /* don't run firmware after reset */ -#define HCR_MEM16 0x10 /* memory width bit, should be preserved */ - - -/* - * Reset the card using configuration registers COR and CCSR. - * If IDLE is 1, stop the firmware, so that it can be safely rewritten. - */ -static int -spectrum_reset(struct pcmcia_device *link, int idle) -{ - int ret; - u8 save_cor; - u8 ccsr; - - /* Doing it if hardware is gone is guaranteed crash */ - if (!pcmcia_dev_present(link)) - return -ENODEV; - - /* Save original COR value */ - ret = pcmcia_read_config_byte(link, CISREG_COR, &save_cor); - if (ret) - goto failed; - - /* Soft-Reset card */ - ret = pcmcia_write_config_byte(link, CISREG_COR, - (save_cor | COR_SOFT_RESET)); - if (ret) - goto failed; - udelay(1000); - - /* Read CCSR */ - ret = pcmcia_read_config_byte(link, CISREG_CCSR, &ccsr); - if (ret) - goto failed; - - /* - * Start or stop the firmware. Memory width bit should be - * preserved from the value we've just read. - */ - ccsr = (idle ? HCR_IDLE : HCR_RUN) | (ccsr & HCR_MEM16); - ret = pcmcia_write_config_byte(link, CISREG_CCSR, ccsr); - if (ret) - goto failed; - udelay(1000); - - /* Restore original COR configuration index */ - ret = pcmcia_write_config_byte(link, CISREG_COR, - (save_cor & ~COR_SOFT_RESET)); - if (ret) - goto failed; - udelay(1000); - return 0; - -failed: - return -ENODEV; -} - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -static int -spectrum_cs_hard_reset(struct orinoco_private *priv) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - - /* Soft reset using COR and HCR */ - spectrum_reset(link, 0); - - return 0; -} - -static int -spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - - return spectrum_reset(link, idle); -} - -/********************************************************************/ -/* PCMCIA stuff */ -/********************************************************************/ - -static int -spectrum_cs_probe(struct pcmcia_device *link) -{ - struct orinoco_private *priv; - struct orinoco_pccard *card; - int ret; - - priv = alloc_orinocodev(sizeof(*card), &link->dev, - spectrum_cs_hard_reset, - spectrum_cs_stop_firmware); - if (!priv) - return -ENOMEM; - card = priv->card; - - /* Link both structures together */ - card->p_dev = link; - link->priv = priv; - - ret = spectrum_cs_config(link); - if (ret) - goto err_free_orinocodev; - - return 0; - -err_free_orinocodev: - free_orinocodev(priv); - return ret; -} - -static void spectrum_cs_detach(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - - orinoco_if_del(priv); - - spectrum_cs_release(link); - - free_orinocodev(priv); -} /* spectrum_cs_detach */ - -static int spectrum_cs_config_check(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -}; - -static int -spectrum_cs_config(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - struct hermes *hw = &priv->hw; - int ret; - void __iomem *mem; - - link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC | - CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; - if (ignore_cis_vcc) - link->config_flags &= ~CONF_AUTO_CHECK_VCC; - ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL); - if (ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR PFX "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - goto failed; - } - - mem = ioport_map(link->resource[0]->start, - resource_size(link->resource[0])); - if (!mem) - goto failed; - - /* We initialize the hermes structure before completing PCMCIA - * configuration just in case the interrupt handler gets - * called. */ - hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); - hw->eeprom_pda = true; - - ret = pcmcia_request_irq(link, orinoco_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* Reset card */ - if (spectrum_cs_hard_reset(priv) != 0) - goto failed; - - /* Initialise the main driver */ - if (orinoco_init(priv) != 0) { - printk(KERN_ERR PFX "orinoco_init() failed\n"); - goto failed; - } - - /* Register an interface with the stack */ - if (orinoco_if_add(priv, link->resource[0]->start, - link->irq, NULL) != 0) { - printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto failed; - } - - return 0; - - failed: - spectrum_cs_release(link); - return -ENODEV; -} /* spectrum_cs_config */ - -static void -spectrum_cs_release(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - unsigned long flags; - - /* We're committed to taking the device away now, so mark the - * hardware as unavailable */ - priv->hw.ops->lock_irqsave(&priv->lock, &flags); - priv->hw_unavailable++; - priv->hw.ops->unlock_irqrestore(&priv->lock, &flags); - - pcmcia_disable_device(link); - if (priv->hw.iobase) - ioport_unmap(priv->hw.iobase); -} /* spectrum_cs_release */ - - -static int -spectrum_cs_suspend(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - - /* Mark the device as stopped, to block IO until later */ - orinoco_down(priv); - - return 0; -} - -static int -spectrum_cs_resume(struct pcmcia_device *link) -{ - struct orinoco_private *priv = link->priv; - int err = orinoco_up(priv); - - return err; -} - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -static const struct pcmcia_device_id spectrum_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */ - PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ - PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids); - -static struct pcmcia_driver orinoco_driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - .probe = spectrum_cs_probe, - .remove = spectrum_cs_detach, - .suspend = spectrum_cs_suspend, - .resume = spectrum_cs_resume, - .id_table = spectrum_cs_ids, -}; -module_pcmcia_driver(orinoco_driver); diff --git a/drivers/net/wireless/intersil/orinoco/wext.c b/drivers/net/wireless/intersil/orinoco/wext.c deleted file mode 100644 index dea1ff0443..0000000000 --- a/drivers/net/wireless/intersil/orinoco/wext.c +++ /dev/null @@ -1,1428 +0,0 @@ -/* Wireless extensions support. - * - * See copyright notice in main.c - */ -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/if_arp.h> -#include <linux/wireless.h> -#include <linux/ieee80211.h> -#include <linux/etherdevice.h> -#include <net/iw_handler.h> -#include <net/cfg80211.h> -#include <net/cfg80211-wext.h> - -#include "hermes.h" -#include "hermes_rid.h" -#include "orinoco.h" - -#include "hw.h" -#include "mic.h" -#include "scan.h" -#include "main.h" - -#include "wext.h" - -#define MAX_RID_LEN 1024 - -/* Helper routine to record keys - * It is called under orinoco_lock so it may not sleep */ -static int orinoco_set_key(struct orinoco_private *priv, int index, - enum orinoco_alg alg, const u8 *key, int key_len, - const u8 *seq, int seq_len) -{ - kfree_sensitive(priv->keys[index].key); - kfree_sensitive(priv->keys[index].seq); - - if (key_len) { - priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC); - if (!priv->keys[index].key) - goto nomem; - } else - priv->keys[index].key = NULL; - - if (seq_len) { - priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC); - if (!priv->keys[index].seq) - goto free_key; - } else - priv->keys[index].seq = NULL; - - priv->keys[index].key_len = key_len; - priv->keys[index].seq_len = seq_len; - - if (key_len) - memcpy((void *)priv->keys[index].key, key, key_len); - if (seq_len) - memcpy((void *)priv->keys[index].seq, seq, seq_len); - - switch (alg) { - case ORINOCO_ALG_TKIP: - priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP; - break; - - case ORINOCO_ALG_WEP: - priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ? - WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40; - break; - - case ORINOCO_ALG_NONE: - default: - priv->keys[index].cipher = 0; - break; - } - - return 0; - -free_key: - kfree(priv->keys[index].key); - priv->keys[index].key = NULL; - -nomem: - priv->keys[index].key_len = 0; - priv->keys[index].seq_len = 0; - priv->keys[index].cipher = 0; - - return -ENOMEM; -} - -static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - struct iw_statistics *wstats = &priv->wstats; - int err; - unsigned long flags; - - if (!netif_device_present(dev)) { - printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", - dev->name); - return NULL; /* FIXME: Can we do better than this? */ - } - - /* If busy, return the old stats. Returning NULL may cause - * the interface to disappear from /proc/net/wireless */ - if (orinoco_lock(priv, &flags) != 0) - return wstats; - - /* We can't really wait for the tallies inquiry command to - * complete, so we just use the previous results and trigger - * a new tallies inquiry command for next time - Jean II */ - /* FIXME: Really we should wait for the inquiry to come back - - * as it is the stats we give don't make a whole lot of sense. - * Unfortunately, it's not clear how to do that within the - * wireless extensions framework: I think we're in user - * context, but a lock seems to be held by the time we get in - * here so we're not safe to sleep here. */ - hermes_inquire(hw, HERMES_INQ_TALLIES); - - if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { - memset(&wstats->qual, 0, sizeof(wstats->qual)); - /* If a spy address is defined, we report stats of the - * first spy address - Jean II */ - if (SPY_NUMBER(priv)) { - wstats->qual.qual = priv->spy_data.spy_stat[0].qual; - wstats->qual.level = priv->spy_data.spy_stat[0].level; - wstats->qual.noise = priv->spy_data.spy_stat[0].noise; - wstats->qual.updated = - priv->spy_data.spy_stat[0].updated; - } - } else { - struct { - __le16 qual, signal, noise, unused; - } __packed cq; - - err = HERMES_READ_RECORD(hw, USER_BAP, - HERMES_RID_COMMSQUALITY, &cq); - - if (!err) { - wstats->qual.qual = (int)le16_to_cpu(cq.qual); - wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; - wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; - wstats->qual.updated = - IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - } - } - - orinoco_unlock(priv, &flags); - return wstats; -} - -/********************************************************************/ -/* Wireless extensions */ -/********************************************************************/ - -static int orinoco_ioctl_setwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct orinoco_private *priv = ndev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Enable automatic roaming - no sanity checks are needed */ - if (is_zero_ether_addr(ap_addr->sa_data) || - is_broadcast_ether_addr(ap_addr->sa_data)) { - priv->bssid_fixed = 0; - eth_zero_addr(priv->desired_bssid); - - /* "off" means keep existing connection */ - if (ap_addr->sa_data[0] == 0) { - __orinoco_hw_set_wap(priv); - err = 0; - } - goto out; - } - - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) { - printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't " - "support manual roaming\n", - dev->name); - err = -EOPNOTSUPP; - goto out; - } - - if (priv->iw_mode != NL80211_IFTYPE_STATION) { - printk(KERN_WARNING "%s: Manual roaming supported only in " - "managed mode\n", dev->name); - err = -EOPNOTSUPP; - goto out; - } - - /* Intersil firmware hangs without Desired ESSID */ - if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL && - strlen(priv->desired_essid) == 0) { - printk(KERN_WARNING "%s: Desired ESSID must be set for " - "manual roaming\n", dev->name); - err = -EOPNOTSUPP; - goto out; - } - - /* Finally, enable manual roaming */ - priv->bssid_fixed = 1; - memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN); - - out: - orinoco_unlock(priv, &flags); - return err; -} - -static int orinoco_ioctl_getwap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct orinoco_private *priv = ndev_priv(dev); - - int err = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - ap_addr->sa_family = ARPHRD_ETHER; - err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data); - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_setiwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - struct orinoco_private *priv = ndev_priv(dev); - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - int setindex = priv->tx_key; - enum orinoco_alg encode_alg = priv->encode_alg; - int restricted = priv->wep_restrict; - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (!priv->has_wep) - return -EOPNOTSUPP; - - if (erq->pointer) { - /* We actually have a key to set - check its length */ - if (erq->length > LARGE_KEY_SIZE) - return -E2BIG; - - if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep) - return -E2BIG; - } - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Clear any TKIP key we have */ - if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP)) - (void) orinoco_clear_tkip_key(priv, setindex); - - if (erq->length > 0) { - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) - index = priv->tx_key; - - /* Switch on WEP if off */ - if (encode_alg != ORINOCO_ALG_WEP) { - setindex = index; - encode_alg = ORINOCO_ALG_WEP; - } - } else { - /* Important note : if the user do "iwconfig eth0 enc off", - * we will arrive there with an index of -1. This is valid - * but need to be taken care off... Jean II */ - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) { - if ((index != -1) || (erq->flags == 0)) { - err = -EINVAL; - goto out; - } - } else { - /* Set the index : Check that the key is valid */ - if (priv->keys[index].key_len == 0) { - err = -EINVAL; - goto out; - } - setindex = index; - } - } - - if (erq->flags & IW_ENCODE_DISABLED) - encode_alg = ORINOCO_ALG_NONE; - if (erq->flags & IW_ENCODE_OPEN) - restricted = 0; - if (erq->flags & IW_ENCODE_RESTRICTED) - restricted = 1; - - if (erq->pointer && erq->length > 0) { - err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf, - erq->length, NULL, 0); - } - priv->tx_key = setindex; - - /* Try fast key change if connected and only keys are changed */ - if ((priv->encode_alg == encode_alg) && - (priv->wep_restrict == restricted) && - netif_carrier_ok(dev)) { - err = __orinoco_hw_setup_wepkeys(priv); - /* No need to commit if successful */ - goto out; - } - - priv->encode_alg = encode_alg; - priv->wep_restrict = restricted; - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getiwencode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - struct orinoco_private *priv = ndev_priv(dev); - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - unsigned long flags; - - if (!priv->has_wep) - return -EOPNOTSUPP; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) - index = priv->tx_key; - - erq->flags = 0; - if (!priv->encode_alg) - erq->flags |= IW_ENCODE_DISABLED; - erq->flags |= index + 1; - - if (priv->wep_restrict) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - erq->length = priv->keys[index].key_len; - - memcpy(keybuf, priv->keys[index].key, erq->length); - - orinoco_unlock(priv, &flags); - return 0; -} - -static int orinoco_ioctl_setessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *essidbuf) -{ - struct iw_point *erq = &wrqu->essid; - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - - /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it - * anyway... - Jean II */ - - /* Hum... Should not use Wireless Extension constant (may change), - * should use our own... - Jean II */ - if (erq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */ - memset(priv->desired_essid, 0, sizeof(priv->desired_essid)); - - /* If not ANY, get the new ESSID */ - if (erq->flags) - memcpy(priv->desired_essid, essidbuf, erq->length); - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getessid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *essidbuf) -{ - struct iw_point *erq = &wrqu->essid; - struct orinoco_private *priv = ndev_priv(dev); - int active; - int err = 0; - unsigned long flags; - - if (netif_running(dev)) { - err = orinoco_hw_get_essid(priv, &active, essidbuf); - if (err < 0) - return err; - erq->length = err; - } else { - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE); - erq->length = strlen(priv->desired_essid); - orinoco_unlock(priv, &flags); - } - - erq->flags = 1; - - return 0; -} - -static int orinoco_ioctl_setfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *frq = &wrqu->freq; - struct orinoco_private *priv = ndev_priv(dev); - int chan = -1; - unsigned long flags; - int err = -EINPROGRESS; /* Call commit handler */ - - /* In infrastructure mode the AP sets the channel */ - if (priv->iw_mode == NL80211_IFTYPE_STATION) - return -EBUSY; - - if ((frq->e == 0) && (frq->m <= 1000)) { - /* Setting by channel number */ - chan = frq->m; - } else { - /* Setting by frequency */ - int denom = 1; - int i; - - /* Calculate denominator to rescale to MHz */ - for (i = 0; i < (6 - frq->e); i++) - denom *= 10; - - chan = ieee80211_frequency_to_channel(frq->m / denom); - } - - if ((chan < 1) || (chan > NUM_CHANNELS) || - !(priv->channel_mask & (1 << (chan - 1)))) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->channel = chan; - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - /* Fast channel change - no commit if successful */ - struct hermes *hw = &priv->hw; - err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_SET_CHANNEL, - chan, NULL); - } - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getfreq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_freq *frq = &wrqu->freq; - struct orinoco_private *priv = ndev_priv(dev); - int tmp; - - /* Locking done in there */ - tmp = orinoco_hw_get_freq(priv); - if (tmp < 0) - return tmp; - - frq->m = tmp * 100000; - frq->e = 1; - - return 0; -} - -static int orinoco_ioctl_getsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *srq = &wrqu->sens; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - u16 val; - int err; - unsigned long flags; - - if (!priv->has_sensitivity) - return -EOPNOTSUPP; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFSYSTEMSCALE, &val); - orinoco_unlock(priv, &flags); - - if (err) - return err; - - srq->value = val; - srq->fixed = 0; /* auto */ - - return 0; -} - -static int orinoco_ioctl_setsens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *srq = &wrqu->sens; - struct orinoco_private *priv = ndev_priv(dev); - int val = srq->value; - unsigned long flags; - - if (!priv->has_sensitivity) - return -EOPNOTSUPP; - - if ((val < 1) || (val > 3)) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - priv->ap_density = val; - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_setrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct orinoco_private *priv = ndev_priv(dev); - int ratemode; - int bitrate; /* 100s of kilobits */ - unsigned long flags; - - /* As the user space doesn't know our highest rate, it uses -1 - * to ask us to set the highest rate. Test it using "iwconfig - * ethX rate auto" - Jean II */ - if (rrq->value == -1) - bitrate = 110; - else { - if (rrq->value % 100000) - return -EINVAL; - bitrate = rrq->value / 100000; - } - - ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed); - - if (ratemode == -1) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - priv->bitratemode = ratemode; - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; -} - -static int orinoco_ioctl_getrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - int bitrate, automatic; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic); - - /* If the interface is running we try to find more about the - current mode */ - if (netif_running(dev)) { - int act_bitrate; - int lerr; - - /* Ignore errors if we can't get the actual bitrate */ - lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate); - if (!lerr) - bitrate = act_bitrate; - } - - orinoco_unlock(priv, &flags); - - rrq->value = bitrate; - rrq->fixed = !automatic; - rrq->disabled = 0; - - return err; -} - -static int orinoco_ioctl_setpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *prq = &wrqu->power; - struct orinoco_private *priv = ndev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (prq->disabled) { - priv->pm_on = 0; - } else { - switch (prq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - priv->pm_mcast = 0; - priv->pm_on = 1; - break; - case IW_POWER_ALL_R: - priv->pm_mcast = 1; - priv->pm_on = 1; - break; - case IW_POWER_ON: - /* No flags : but we may have a value - Jean II */ - break; - default: - err = -EINVAL; - goto out; - } - - if (prq->flags & IW_POWER_TIMEOUT) { - priv->pm_on = 1; - priv->pm_timeout = prq->value / 1000; - } - if (prq->flags & IW_POWER_PERIOD) { - priv->pm_on = 1; - priv->pm_period = prq->value / 1000; - } - /* It's valid to not have a value if we are just toggling - * the flags... Jean II */ - if (!priv->pm_on) { - err = -EINVAL; - goto out; - } - } - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_param *prq = &wrqu->power; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - int err = 0; - u16 enable, period, timeout, mcast; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMENABLED, &enable); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, &period); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, &timeout); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMULTICASTRECEIVE, &mcast); - if (err) - goto out; - - prq->disabled = !enable; - /* Note : by default, display the period */ - if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - prq->flags = IW_POWER_TIMEOUT; - prq->value = timeout * 1000; - } else { - prq->flags = IW_POWER_PERIOD; - prq->value = period * 1000; - } - if (mcast) - prq->flags |= IW_POWER_ALL_R; - else - prq->flags |= IW_POWER_UNICAST_R; - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, alg = ext->alg, set_key = 1; - unsigned long flags; - int err = -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Determine and validate the key index */ - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if ((idx < 1) || (idx > 4)) - goto out; - idx--; - } else - idx = priv->tx_key; - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) { - /* Clear any TKIP TX key we had */ - (void) orinoco_clear_tkip_key(priv, priv->tx_key); - } - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - priv->tx_key = idx; - set_key = ((alg == IW_ENCODE_ALG_TKIP) || - (ext->key_len > 0)) ? 1 : 0; - } - - if (set_key) { - /* Set the requested key first */ - switch (alg) { - case IW_ENCODE_ALG_NONE: - priv->encode_alg = ORINOCO_ALG_NONE; - err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE, - NULL, 0, NULL, 0); - break; - - case IW_ENCODE_ALG_WEP: - if (ext->key_len <= 0) - goto out; - - priv->encode_alg = ORINOCO_ALG_WEP; - err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP, - ext->key, ext->key_len, NULL, 0); - break; - - case IW_ENCODE_ALG_TKIP: - { - u8 *tkip_iv = NULL; - - if (!priv->has_wpa || - (ext->key_len > sizeof(struct orinoco_tkip_key))) - goto out; - - priv->encode_alg = ORINOCO_ALG_TKIP; - - if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - tkip_iv = &ext->rx_seq[0]; - - err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP, - ext->key, ext->key_len, tkip_iv, - ORINOCO_SEQ_LEN); - - err = __orinoco_hw_set_tkip_key(priv, idx, - ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, - priv->keys[idx].key, priv->keys[idx].key_len, - tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); - if (err) - printk(KERN_ERR "%s: Error %d setting TKIP key" - "\n", dev->name, err); - - goto out; - } - default: - goto out; - } - } - err = -EINPROGRESS; - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - unsigned long flags; - int err; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = -EINVAL; - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - goto out; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if ((idx < 1) || (idx > 4)) - goto out; - idx--; - } else - idx = priv->tx_key; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - switch (priv->encode_alg) { - case ORINOCO_ALG_NONE: - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - encoding->flags |= IW_ENCODE_DISABLED; - break; - case ORINOCO_ALG_WEP: - ext->alg = IW_ENCODE_ALG_WEP; - ext->key_len = min(priv->keys[idx].key_len, max_key_len); - memcpy(ext->key, priv->keys[idx].key, ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - break; - case ORINOCO_ALG_TKIP: - ext->alg = IW_ENCODE_ALG_TKIP; - ext->key_len = min(priv->keys[idx].key_len, max_key_len); - memcpy(ext->key, priv->keys[idx].key, ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - break; - } - - err = 0; - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - struct iw_param *param = &wrqu->param; - unsigned long flags; - int ret = -EINPROGRESS; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_PRIVACY_INVOKED: - case IW_AUTH_DROP_UNENCRYPTED: - /* - * orinoco does not use these parameters - */ - break; - - case IW_AUTH_MFP: - /* Management Frame Protection not supported. - * Only fail if set to required. - */ - if (param->value == IW_AUTH_MFP_REQUIRED) - ret = -EINVAL; - break; - - case IW_AUTH_KEY_MGMT: - /* wl_lkm implies value 2 == PSK for Hermes I - * which ties in with WEXT - * no other hints tho :( - */ - priv->key_mgmt = param->value; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - /* When countermeasures are enabled, shut down the - * card; when disabled, re-enable the card. This must - * take effect immediately. - * - * TODO: Make sure that the EAPOL message is getting - * out before card disabled - */ - if (param->value) { - priv->tkip_cm_active = 1; - ret = hermes_disable_port(hw, 0); - } else { - priv->tkip_cm_active = 0; - ret = hermes_enable_port(hw, 0); - } - break; - - case IW_AUTH_80211_AUTH_ALG: - if (param->value & IW_AUTH_ALG_SHARED_KEY) - priv->wep_restrict = 1; - else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) - priv->wep_restrict = 0; - else - ret = -EINVAL; - break; - - case IW_AUTH_WPA_ENABLED: - if (priv->has_wpa) { - priv->wpa_enabled = param->value ? 1 : 0; - } else { - if (param->value) - ret = -EOPNOTSUPP; - /* else silently accept disable of WPA */ - priv->wpa_enabled = 0; - } - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_param *param = &wrqu->param; - unsigned long flags; - int ret = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_KEY_MGMT: - param->value = priv->key_mgmt; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - param->value = priv->tkip_cm_active; - break; - - case IW_AUTH_80211_AUTH_ALG: - if (priv->wep_restrict) - param->value = IW_AUTH_ALG_SHARED_KEY; - else - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = priv->wpa_enabled; - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_set_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - u8 *buf; - unsigned long flags; - - /* cut off at IEEE80211_MAX_DATA_LEN */ - if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || - (wrqu->data.length && (extra == NULL))) - return -EINVAL; - - if (wrqu->data.length) { - buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - } else - buf = NULL; - - if (orinoco_lock(priv, &flags) != 0) { - kfree(buf); - return -EBUSY; - } - - kfree(priv->wpa_ie); - priv->wpa_ie = buf; - priv->wpa_ie_len = wrqu->data.length; - - if (priv->wpa_ie) { - /* Looks like wl_lkm wants to check the auth alg, and - * somehow pass it to the firmware. - * Instead it just calls the key mgmt rid - * - we do this in set auth. - */ - } - - orinoco_unlock(priv, &flags); - return 0; -} - -static int orinoco_ioctl_get_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int err = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) { - wrqu->data.length = 0; - goto out; - } - - if (wrqu->data.length < priv->wpa_ie_len) { - err = -E2BIG; - goto out; - } - - wrqu->data.length = priv->wpa_ie_len; - memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); - -out: - orinoco_unlock(priv, &flags); - return err; -} - -static int orinoco_ioctl_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - struct iw_mlme *mlme = (struct iw_mlme *)extra; - unsigned long flags; - int ret = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - /* silently ignore */ - break; - - case IW_MLME_DISASSOC: - - ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data, - mlme->reason_code); - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_reset(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) { - printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); - - /* Firmware reset */ - orinoco_reset(&priv->reset_work); - } else { - printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); - - schedule_work(&priv->reset_work); - } - - return 0; -} - -static int orinoco_ioctl_setibssport(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) - -{ - struct orinoco_private *priv = ndev_priv(dev); - int val = *((int *) extra); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->ibss_port = val; - - /* Actually update the mode we are using */ - set_port_type(priv); - - orinoco_unlock(priv, &flags); - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getibssport(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int *val = (int *) extra; - - *val = priv->ibss_port; - return 0; -} - -static int orinoco_ioctl_setport3(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int val = *((int *) extra); - int err = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (val) { - case 0: /* Try to do IEEE ad-hoc mode */ - if (!priv->has_ibss) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 0; - - break; - - case 1: /* Try to do Lucent proprietary ad-hoc mode */ - if (!priv->has_port3) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 1; - break; - - default: - err = -EINVAL; - } - - if (!err) { - /* Actually update the mode we are using */ - set_port_type(priv); - err = -EINPROGRESS; - } - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getport3(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int *val = (int *) extra; - - *val = priv->prefer_port3; - return 0; -} - -static int orinoco_ioctl_setpreamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int val; - - if (!priv->has_preamble) - return -EOPNOTSUPP; - - /* 802.11b has recently defined some short preamble. - * Basically, the Phy header has been reduced in size. - * This increase performance, especially at high rates - * (the preamble is transmitted at 1Mb/s), unfortunately - * this give compatibility troubles... - Jean II */ - val = *((int *) extra); - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (val) - priv->preamble = 1; - else - priv->preamble = 0; - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getpreamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int *val = (int *) extra; - - if (!priv->has_preamble) - return -EOPNOTSUPP; - - *val = priv->preamble; - return 0; -} - -/* ioctl interface to hermes_read_ltv() - * To use with iwpriv, pass the RID as the token argument, e.g. - * iwpriv get_rid [0xfc00] - * At least Wireless Tools 25 is required to use iwpriv. - * For Wireless Tools 25 and 26 append "dummy" are the end. */ -static int orinoco_ioctl_getrid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_point *data = &wrqu->data; - struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; - int rid = data->flags; - u16 length; - int err; - unsigned long flags; - - /* It's a "get" function, but we don't want users to access the - * WEP key and other raw firmware data */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (rid < 0xfc00 || rid > 0xffff) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length, - extra); - if (err) - goto out; - - data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length), - MAX_RID_LEN); - - out: - orinoco_unlock(priv, &flags); - return err; -} - - -/* Commit handler, called after set operations */ -static int orinoco_ioctl_commit(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - int err = 0; - - if (!priv->open) - return 0; - - if (orinoco_lock(priv, &flags) != 0) - return err; - - err = orinoco_commit(priv); - - orinoco_unlock(priv, &flags); - return err; -} - -static const struct iw_priv_args orinoco_privtab[] = { - { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, - { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, - { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_port3" }, - { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_port3" }, - { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_preamble" }, - { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_preamble" }, - { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_ibssport" }, - { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_ibssport" }, - { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN, - "get_rid" }, -}; - - -/* - * Structures to export the Wireless Handlers - */ - -static const iw_handler orinoco_handler[] = { - IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), - IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname), - IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), - IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), - IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode), - IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode), - IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), - IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), - IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), - IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), - IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan), - IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan), - IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), - IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), - IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), - IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), - IW_HANDLER(SIOCSIWRTS, cfg80211_wext_siwrts), - IW_HANDLER(SIOCGIWRTS, cfg80211_wext_giwrts), - IW_HANDLER(SIOCSIWFRAG, cfg80211_wext_siwfrag), - IW_HANDLER(SIOCGIWFRAG, cfg80211_wext_giwfrag), - IW_HANDLER(SIOCGIWRETRY, cfg80211_wext_giwretry), - IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode), - IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), - IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), - IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), - IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), - IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), - IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), - IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), - IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), - IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), - IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), -}; - - -/* - Added typecasting since we no longer use iwreq_data -- Moustafa - */ -static const iw_handler orinoco_private_handler[] = { - [0] = orinoco_ioctl_reset, - [1] = orinoco_ioctl_reset, - [2] = orinoco_ioctl_setport3, - [3] = orinoco_ioctl_getport3, - [4] = orinoco_ioctl_setpreamble, - [5] = orinoco_ioctl_getpreamble, - [6] = orinoco_ioctl_setibssport, - [7] = orinoco_ioctl_getibssport, - [9] = orinoco_ioctl_getrid, -}; - -const struct iw_handler_def orinoco_handler_def = { - .num_standard = ARRAY_SIZE(orinoco_handler), - .num_private = ARRAY_SIZE(orinoco_private_handler), - .num_private_args = ARRAY_SIZE(orinoco_privtab), - .standard = orinoco_handler, - .private = orinoco_private_handler, - .private_args = orinoco_privtab, - .get_wireless_stats = orinoco_get_wireless_stats, -}; diff --git a/drivers/net/wireless/intersil/orinoco/wext.h b/drivers/net/wireless/intersil/orinoco/wext.h deleted file mode 100644 index 1479f4e26d..0000000000 --- a/drivers/net/wireless/intersil/orinoco/wext.h +++ /dev/null @@ -1,13 +0,0 @@ -/* Wireless extensions support. - * - * See copyright notice in main.c - */ -#ifndef _ORINOCO_WEXT_H_ -#define _ORINOCO_WEXT_H_ - -#include <net/iw_handler.h> - -/* Structure defining all our WEXT handlers */ -extern const struct iw_handler_def orinoco_handler_def; - -#endif /* _ORINOCO_WEXT_H_ */ diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c index b52cce3811..c4fe70e05b 100644 --- a/drivers/net/wireless/intersil/p54/fwio.c +++ b/drivers/net/wireless/intersil/p54/fwio.c @@ -125,7 +125,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) "FW rev %s - Softmac protocol %x.%x\n", fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); snprintf(dev->wiphy->fw_version, sizeof(dev->wiphy->fw_version), - "%s - %x.%x", fw_version, + "%.19s - %x.%x", fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); } diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index ce0179b8ab..0073b5e0f9 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -700,6 +700,7 @@ static struct spi_driver p54spi_driver = { module_spi_driver(p54spi_driver); +MODULE_DESCRIPTION("Prism54 SPI wireless driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>"); MODULE_ALIAS("spi:cx3110x"); diff --git a/drivers/net/wireless/legacy/Kconfig b/drivers/net/wireless/legacy/Kconfig deleted file mode 100644 index 3a52759412..0000000000 --- a/drivers/net/wireless/legacy/Kconfig +++ /dev/null @@ -1,55 +0,0 @@ -config PCMCIA_RAYCS - tristate "Aviator/Raytheon 2.4GHz wireless support" - depends on PCMCIA - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - help - Say Y here if you intend to attach an Aviator/Raytheon PCMCIA - (PC-card) wireless Ethernet networking card to your computer. - Please read the file - <file:Documentation/networking/device_drivers/wifi/ray_cs.rst> for - details. - - To compile this driver as a module, choose M here: the module will be - called ray_cs. If unsure, say N. - -config PCMCIA_WL3501 - tristate "Planet WL3501 PCMCIA cards" - depends on CFG80211 && PCMCIA - select WIRELESS_EXT - select WEXT_SPY - help - A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. - It has basic support for Linux wireless extensions and initial - micro support for ethtool. - -config USB_NET_RNDIS_WLAN - tristate "Wireless RNDIS USB support" - depends on USB - depends on CFG80211 - select USB_NET_DRIVERS - select USB_USBNET - select USB_NET_CDCETHER - select USB_NET_RNDIS_HOST - help - This is a driver for wireless RNDIS devices. - These are USB based adapters found in devices such as: - - Buffalo WLI-U2-KG125S - U.S. Robotics USR5421 - Belkin F5D7051 - Linksys WUSB54GSv2 - Linksys WUSB54GSC - Asus WL169gE - Eminent EM4045 - BT Voyager 1055 - Linksys WUSB54GSv1 - U.S. Robotics USR5420 - BUFFALO WLI-USB-G54 - - All of these devices are based on Broadcom 4320 chip which is the - only wireless RNDIS chip known to date. - - If you choose to build a module, it'll be called rndis_wlan. - diff --git a/drivers/net/wireless/legacy/Makefile b/drivers/net/wireless/legacy/Makefile deleted file mode 100644 index 36878f080b..0000000000 --- a/drivers/net/wireless/legacy/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# 16-bit wireless PCMCIA client drivers -obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o -obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o - -obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o - diff --git a/drivers/net/wireless/legacy/ray_cs.c b/drivers/net/wireless/legacy/ray_cs.c deleted file mode 100644 index c95a79e01c..0000000000 --- a/drivers/net/wireless/legacy/ray_cs.c +++ /dev/null @@ -1,2824 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/*============================================================================= - * - * A PCMCIA client driver for the Raylink wireless LAN card. - * The starting point for this module was the skeleton.c in the - * PCMCIA 2.9.12 package written by David Hinds, dahinds@users.sourceforge.net - * - * Copyright (c) 1998 Corey Thomas (corey@world.std.com) - * - * Changes: - * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000 - * - reorganize kmallocs in ray_attach, checking all for failure - * and releasing the previous allocations if one fails - * - * Daniele Bellucci <bellucda@tiscali.it> - 07/10/2003 - * - Audit copy_to_user in ioctl(SIOCGIWESSID) - * -=============================================================================*/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/proc_fs.h> -#include <linux/ptrace.h> -#include <linux/seq_file.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/if_arp.h> -#include <linux/ioport.h> -#include <linux/skbuff.h> -#include <linux/ieee80211.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> - -#include <linux/wireless.h> -#include <net/iw_handler.h> - -#include <asm/io.h> -#include <asm/byteorder.h> -#include <linux/uaccess.h> - -/* Warning : these stuff will slow down the driver... */ -#define WIRELESS_SPY /* Enable spying addresses */ -/* Definitions we need for spy */ -typedef struct iw_statistics iw_stats; -typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */ - -#include "rayctl.h" -#include "ray_cs.h" - - -/** Prototypes based on PCMCIA skeleton driver *******************************/ -static int ray_config(struct pcmcia_device *link); -static void ray_release(struct pcmcia_device *link); -static void ray_detach(struct pcmcia_device *p_dev); - -/***** Prototypes indicated by device structure ******************************/ -static int ray_dev_close(struct net_device *dev); -static int ray_dev_config(struct net_device *dev, struct ifmap *map); -static struct net_device_stats *ray_get_stats(struct net_device *dev); -static int ray_dev_init(struct net_device *dev); - -static int ray_open(struct net_device *dev); -static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void ray_update_multi_list(struct net_device *dev, int all); -static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, - unsigned char *data, int len); -static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, - UCHAR msg_type, unsigned char *data); -static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len); -static iw_stats *ray_get_wireless_stats(struct net_device *dev); -static const struct iw_handler_def ray_handler_def; - -/***** Prototypes for raylink functions **************************************/ -static void authenticate(ray_dev_t *local); -static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type); -static void authenticate_timeout(struct timer_list *t); -static int get_free_ccs(ray_dev_t *local); -static int get_free_tx_ccs(ray_dev_t *local); -static void init_startup_params(ray_dev_t *local); -static int parse_addr(char *in_str, UCHAR *out); -static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, UCHAR type); -static int ray_init(struct net_device *dev); -static int interrupt_ecf(ray_dev_t *local, int ccs); -static void ray_reset(struct net_device *dev); -static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len); -static void verify_dl_startup(struct timer_list *t); - -/* Prototypes for interrpt time functions **********************************/ -static irqreturn_t ray_interrupt(int reg, void *dev_id); -static void clear_interrupt(ray_dev_t *local); -static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len); -static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len); -static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs); -static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs); -static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len); -static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len); -static void associate(ray_dev_t *local); - -/* Card command functions */ -static int dl_startup_params(struct net_device *dev); -static void join_net(struct timer_list *t); -static void start_net(struct timer_list *t); - -/*===========================================================================*/ -/* Parameters that can be set with 'insmod' */ - -/* ADHOC=0, Infrastructure=1 */ -static int net_type = ADHOC; - -/* Hop dwell time in Kus (1024 us units defined by 802.11) */ -static int hop_dwell = 128; - -/* Beacon period in Kus */ -static int beacon_period = 256; - -/* power save mode (0 = off, 1 = save power) */ -static int psm; - -/* String for network's Extended Service Set ID. 32 Characters max */ -static char *essid; - -/* Default to encapsulation unless translation requested */ -static bool translate = true; - -static int country = USA; - -static int sniffer; - -static int bc; - -/* 48 bit physical card address if overriding card's real physical - * address is required. Since IEEE 802.11 addresses are 48 bits - * like ethernet, an int can't be used, so a string is used. To - * allow use of addresses starting with a decimal digit, the first - * character must be a letter and will be ignored. This letter is - * followed by up to 12 hex digits which are the address. If less - * than 12 digits are used, the address will be left filled with 0's. - * Note that bit 0 of the first byte is the broadcast bit, and evil - * things will happen if it is not 0 in a card address. - */ -static char *phy_addr = NULL; - -static unsigned int ray_mem_speed = 500; - -/* WARNING: THIS DRIVER IS NOT CAPABLE OF HANDLING MULTIPLE DEVICES! */ -static struct pcmcia_device *this_device = NULL; - -MODULE_AUTHOR("Corey Thomas <corey@world.std.com>"); -MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver"); -MODULE_LICENSE("GPL"); - -module_param(net_type, int, 0); -module_param(hop_dwell, int, 0); -module_param(beacon_period, int, 0); -module_param(psm, int, 0); -module_param(essid, charp, 0); -module_param(translate, bool, 0); -module_param(country, int, 0); -module_param(sniffer, int, 0); -module_param(bc, int, 0); -module_param(phy_addr, charp, 0); -module_param(ray_mem_speed, int, 0); - -static const UCHAR b5_default_startup_parms[] = { - 0, 0, /* Adhoc station */ - 'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, /* Active scan, CA Mode */ - 0, 0, 0, 0, 0, 0, /* No default MAC addr */ - 0x7f, 0xff, /* Frag threshold */ - 0x00, 0x80, /* Hop time 128 Kus */ - 0x01, 0x00, /* Beacon period 256 Kus */ - 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout */ - 0x1d, 0x82, 0x4e, /* SIFS, DIFS, PIFS */ - 0x7f, 0xff, /* RTS threshold */ - 0x04, 0xe2, 0x38, 0xA4, /* scan_dwell, max_scan_dwell */ - 0x05, /* assoc resp timeout thresh */ - 0x08, 0x02, 0x08, /* adhoc, infra, super cycle max */ - 0, /* Promiscuous mode */ - 0x0c, 0x0bd, /* Unique word */ - 0x32, /* Slot time */ - 0xff, 0xff, /* roam-low snr, low snr count */ - 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ - 0x01, 0x0b, 0x4f, /* USA, hop pattern, hop pat length */ -/* b4 - b5 differences start here */ - 0x00, 0x3f, /* CW max */ - 0x00, 0x0f, /* CW min */ - 0x04, 0x08, /* Noise gain, limit offset */ - 0x28, 0x28, /* det rssi, med busy offsets */ - 7, /* det sync thresh */ - 0, 2, 2, /* test mode, min, max */ - 0, /* allow broadcast SSID probe resp */ - 0, 0, /* privacy must start, can join */ - 2, 0, 0, 0, 0, 0, 0, 0 /* basic rate set */ -}; - -static const UCHAR b4_default_startup_parms[] = { - 0, 0, /* Adhoc station */ - 'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, /* Active scan, CA Mode */ - 0, 0, 0, 0, 0, 0, /* No default MAC addr */ - 0x7f, 0xff, /* Frag threshold */ - 0x02, 0x00, /* Hop time */ - 0x00, 0x01, /* Beacon period */ - 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout */ - 0x1d, 0x82, 0xce, /* SIFS, DIFS, PIFS */ - 0x7f, 0xff, /* RTS threshold */ - 0xfb, 0x1e, 0xc7, 0x5c, /* scan_dwell, max_scan_dwell */ - 0x05, /* assoc resp timeout thresh */ - 0x04, 0x02, 0x4, /* adhoc, infra, super cycle max */ - 0, /* Promiscuous mode */ - 0x0c, 0x0bd, /* Unique word */ - 0x4e, /* Slot time (TBD seems wrong) */ - 0xff, 0xff, /* roam-low snr, low snr count */ - 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ - 0x01, 0x0b, 0x4e, /* USA, hop pattern, hop pat length */ -/* b4 - b5 differences start here */ - 0x3f, 0x0f, /* CW max, min */ - 0x04, 0x08, /* Noise gain, limit offset */ - 0x28, 0x28, /* det rssi, med busy offsets */ - 7, /* det sync thresh */ - 0, 2, 2, /* test mode, min, max */ - 0, /* rx/tx delay */ - 0, 0, 0, 0, 0, 0, /* current BSS id */ - 0 /* hop set */ -}; - -/*===========================================================================*/ -static const u8 eth2_llc[] = { 0xaa, 0xaa, 3, 0, 0, 0 }; - -static const char hop_pattern_length[] = { 1, - USA_HOP_MOD, EUROPE_HOP_MOD, - JAPAN_HOP_MOD, KOREA_HOP_MOD, - SPAIN_HOP_MOD, FRANCE_HOP_MOD, - ISRAEL_HOP_MOD, AUSTRALIA_HOP_MOD, - JAPAN_TEST_HOP_MOD -}; - -static const char rcsid[] = - "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>"; - -static const struct net_device_ops ray_netdev_ops = { - .ndo_init = ray_dev_init, - .ndo_open = ray_open, - .ndo_stop = ray_dev_close, - .ndo_start_xmit = ray_dev_start_xmit, - .ndo_set_config = ray_dev_config, - .ndo_get_stats = ray_get_stats, - .ndo_set_rx_mode = set_multicast_list, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int ray_probe(struct pcmcia_device *p_dev) -{ - ray_dev_t *local; - struct net_device *dev; - int ret; - - dev_dbg(&p_dev->dev, "ray_attach()\n"); - - /* Allocate space for private device-specific data */ - dev = alloc_etherdev(sizeof(ray_dev_t)); - if (!dev) - return -ENOMEM; - - local = netdev_priv(dev); - local->finder = p_dev; - - /* The io structure describes IO port mapping. None used here */ - p_dev->resource[0]->end = 0; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - - /* General socket configuration */ - p_dev->config_flags |= CONF_ENABLE_IRQ; - p_dev->config_index = 1; - - p_dev->priv = dev; - - local->finder = p_dev; - local->card_status = CARD_INSERTED; - local->authentication_state = UNAUTHENTICATED; - local->num_multi = 0; - dev_dbg(&p_dev->dev, "ray_attach p_dev = %p, dev = %p, local = %p, intr = %p\n", - p_dev, dev, local, &ray_interrupt); - - /* Raylink entries in the device structure */ - dev->netdev_ops = &ray_netdev_ops; - dev->wireless_handlers = &ray_handler_def; -#ifdef WIRELESS_SPY - local->wireless_data.spy_data = &local->spy_data; - dev->wireless_data = &local->wireless_data; -#endif /* WIRELESS_SPY */ - - - dev_dbg(&p_dev->dev, "ray_cs ray_attach calling ether_setup.)\n"); - netif_stop_queue(dev); - - timer_setup(&local->timer, NULL, 0); - - this_device = p_dev; - ret = ray_config(p_dev); - if (ret) - goto err_free_dev; - - return 0; - -err_free_dev: - free_netdev(dev); - return ret; -} - -static void ray_detach(struct pcmcia_device *link) -{ - struct net_device *dev; - - dev_dbg(&link->dev, "ray_detach\n"); - - this_device = NULL; - dev = link->priv; - - ray_release(link); - - if (link->priv) { - unregister_netdev(dev); - free_netdev(dev); - } - dev_dbg(&link->dev, "ray_cs ray_detach ending\n"); -} /* ray_detach */ - -#define MAX_TUPLE_SIZE 128 -static int ray_config(struct pcmcia_device *link) -{ - int ret = 0; - int i; - struct net_device *dev = link->priv; - ray_dev_t *local = netdev_priv(dev); - - dev_dbg(&link->dev, "ray_config\n"); - - /* Determine card type and firmware version */ - printk(KERN_INFO "ray_cs Detected: %s%s%s%s\n", - link->prod_id[0] ? link->prod_id[0] : " ", - link->prod_id[1] ? link->prod_id[1] : " ", - link->prod_id[2] ? link->prod_id[2] : " ", - link->prod_id[3] ? link->prod_id[3] : " "); - - /* Now allocate an interrupt line. Note that this does not - actually assign a handler to the interrupt. - */ - ret = pcmcia_request_irq(link, ray_interrupt); - if (ret) - goto failed; - dev->irq = link->irq; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - -/*** Set up 32k window for shared memory (transmit and control) ************/ - link->resource[2]->flags |= WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; - link->resource[2]->start = 0; - link->resource[2]->end = 0x8000; - ret = pcmcia_request_window(link, link->resource[2], ray_mem_speed); - if (ret) - goto failed; - ret = pcmcia_map_mem_page(link, link->resource[2], 0); - if (ret) - goto failed; - local->sram = ioremap(link->resource[2]->start, - resource_size(link->resource[2])); - if (!local->sram) - goto failed; - -/*** Set up 16k window for shared memory (receive buffer) ***************/ - link->resource[3]->flags |= - WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; - link->resource[3]->start = 0; - link->resource[3]->end = 0x4000; - ret = pcmcia_request_window(link, link->resource[3], ray_mem_speed); - if (ret) - goto failed; - ret = pcmcia_map_mem_page(link, link->resource[3], 0x8000); - if (ret) - goto failed; - local->rmem = ioremap(link->resource[3]->start, - resource_size(link->resource[3])); - if (!local->rmem) - goto failed; - -/*** Set up window for attribute memory ***********************************/ - link->resource[4]->flags |= - WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT; - link->resource[4]->start = 0; - link->resource[4]->end = 0x1000; - ret = pcmcia_request_window(link, link->resource[4], ray_mem_speed); - if (ret) - goto failed; - ret = pcmcia_map_mem_page(link, link->resource[4], 0); - if (ret) - goto failed; - local->amem = ioremap(link->resource[4]->start, - resource_size(link->resource[4])); - if (!local->amem) - goto failed; - - dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram); - dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem); - dev_dbg(&link->dev, "ray_config amem=%p\n", local->amem); - if (ray_init(dev) < 0) { - ray_release(link); - return -ENODEV; - } - - SET_NETDEV_DEV(dev, &link->dev); - i = register_netdev(dev); - if (i != 0) { - printk("ray_config register_netdev() failed\n"); - ray_release(link); - return i; - } - - printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n", - dev->name, dev->irq, dev->dev_addr); - - return 0; - -failed: - ray_release(link); - return -ENODEV; -} /* ray_config */ - -static inline struct ccs __iomem *ccs_base(ray_dev_t *dev) -{ - return dev->sram + CCS_BASE; -} - -static inline struct rcs __iomem *rcs_base(ray_dev_t *dev) -{ - /* - * This looks nonsensical, since there is a separate - * RCS_BASE. But the difference between a "struct rcs" - * and a "struct ccs" ends up being in the _index_ off - * the base, so the base pointer is the same for both - * ccs/rcs. - */ - return dev->sram + CCS_BASE; -} - -/*===========================================================================*/ -static int ray_init(struct net_device *dev) -{ - int i; - struct ccs __iomem *pccs; - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - dev_dbg(&link->dev, "ray_init(0x%p)\n", dev); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_init - device not present\n"); - return -1; - } - - local->net_type = net_type; - local->sta_type = TYPE_STA; - - /* Copy the startup results to local memory */ - memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE, - sizeof(struct startup_res_6)); - - /* Check Power up test status and get mac address from card */ - if (local->startup_res.startup_word != 0x80) { - printk(KERN_INFO "ray_init ERROR card status = %2x\n", - local->startup_res.startup_word); - local->card_status = CARD_INIT_ERROR; - return -1; - } - - local->fw_ver = local->startup_res.firmware_version[0]; - local->fw_bld = local->startup_res.firmware_version[1]; - local->fw_var = local->startup_res.firmware_version[2]; - dev_dbg(&link->dev, "ray_init firmware version %d.%d\n", local->fw_ver, - local->fw_bld); - - local->tib_length = 0x20; - if ((local->fw_ver == 5) && (local->fw_bld >= 30)) - local->tib_length = local->startup_res.tib_length; - dev_dbg(&link->dev, "ray_init tib_length = 0x%02x\n", local->tib_length); - /* Initialize CCS's to buffer free state */ - pccs = ccs_base(local); - for (i = 0; i < NUMBER_OF_CCS; i++) { - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - } - init_startup_params(local); - - /* copy mac address to startup parameters */ - if (!parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) { - memcpy(&local->sparm.b4.a_mac_addr, - &local->startup_res.station_addr, ADDRLEN); - } - - clear_interrupt(local); /* Clear any interrupt from the card */ - local->card_status = CARD_AWAITING_PARAM; - dev_dbg(&link->dev, "ray_init ending\n"); - return 0; -} /* ray_init */ - -/*===========================================================================*/ -/* Download startup parameters to the card and command it to read them */ -static int dl_startup_params(struct net_device *dev) -{ - int ccsindex; - ray_dev_t *local = netdev_priv(dev); - struct ccs __iomem *pccs; - struct pcmcia_device *link = local->finder; - - dev_dbg(&link->dev, "dl_startup_params entered\n"); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs dl_startup_params - device not present\n"); - return -1; - } - - /* Copy parameters to host to ECF area */ - if (local->fw_ver == 0x55) - memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4, - sizeof(struct b4_startup_params)); - else - memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5, - sizeof(struct b5_startup_params)); - - /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) < 0) - return -1; - local->dl_param_ccs = ccsindex; - pccs = ccs_base(local) + ccsindex; - writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); - dev_dbg(&link->dev, "dl_startup_params start ccsindex = %d\n", - local->dl_param_ccs); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - printk(KERN_INFO "ray dl_startup_params failed - " - "ECF not ready for intr\n"); - local->card_status = CARD_DL_PARAM_ERROR; - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return -2; - } - local->card_status = CARD_DL_PARAM; - /* Start kernel timer to wait for dl startup to complete. */ - local->timer.expires = jiffies + HZ / 2; - local->timer.function = verify_dl_startup; - add_timer(&local->timer); - dev_dbg(&link->dev, - "ray_cs dl_startup_params started timer for verify_dl_startup\n"); - return 0; -} /* dl_startup_params */ - -/*===========================================================================*/ -static void init_startup_params(ray_dev_t *local) -{ - int i; - - if (country > JAPAN_TEST) - country = USA; - else if (country < USA) - country = USA; - /* structure for hop time and beacon period is defined here using - * New 802.11D6.1 format. Card firmware is still using old format - * until version 6. - * Before After - * a_hop_time ms byte a_hop_time ms byte - * a_hop_time 2s byte a_hop_time ls byte - * a_hop_time ls byte a_beacon_period ms byte - * a_beacon_period a_beacon_period ls byte - * - * a_hop_time = uS a_hop_time = KuS - * a_beacon_period = hops a_beacon_period = KuS - *//* 64ms = 010000 */ - if (local->fw_ver == 0x55) { - memcpy(&local->sparm.b4, b4_default_startup_parms, - sizeof(struct b4_startup_params)); - /* Translate sane kus input values to old build 4/5 format */ - /* i = hop time in uS truncated to 3 bytes */ - i = (hop_dwell * 1024) & 0xffffff; - local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff; - local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff; - local->sparm.b4.a_beacon_period[0] = 0; - local->sparm.b4.a_beacon_period[1] = - ((beacon_period / hop_dwell) - 1) & 0xff; - local->sparm.b4.a_curr_country_code = country; - local->sparm.b4.a_hop_pattern_length = - hop_pattern_length[(int)country] - 1; - if (bc) { - local->sparm.b4.a_ack_timeout = 0x50; - local->sparm.b4.a_sifs = 0x3f; - } - } else { /* Version 5 uses real kus values */ - memcpy((UCHAR *) &local->sparm.b5, b5_default_startup_parms, - sizeof(struct b5_startup_params)); - - local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff; - local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff; - local->sparm.b5.a_beacon_period[0] = - (beacon_period >> 8) & 0xff; - local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff; - if (psm) - local->sparm.b5.a_power_mgt_state = 1; - local->sparm.b5.a_curr_country_code = country; - local->sparm.b5.a_hop_pattern_length = - hop_pattern_length[(int)country]; - } - - local->sparm.b4.a_network_type = net_type & 0x01; - local->sparm.b4.a_acting_as_ap_status = TYPE_STA; - - if (essid != NULL) - strscpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE); -} /* init_startup_params */ - -/*===========================================================================*/ -static void verify_dl_startup(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs; - UCHAR status; - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs verify_dl_startup - device not present\n"); - return; - } -#if 0 - { - int i; - printk(KERN_DEBUG - "verify_dl_startup parameters sent via ccs %d:\n", - local->dl_param_ccs); - for (i = 0; i < sizeof(struct b5_startup_params); i++) { - printk(" %2x", - (unsigned int)readb(local->sram + - HOST_TO_ECF_BASE + i)); - } - printk("\n"); - } -#endif - - status = readb(&pccs->buffer_status); - if (status != CCS_BUFFER_FREE) { - printk(KERN_INFO - "Download startup params failed. Status = %d\n", - status); - local->card_status = CARD_DL_PARAM_ERROR; - return; - } - if (local->sparm.b4.a_network_type == ADHOC) - start_net(&local->timer); - else - join_net(&local->timer); -} /* end verify_dl_startup */ - -/*===========================================================================*/ -/* Command card to start a network */ -static void start_net(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - struct ccs __iomem *pccs; - int ccsindex; - struct pcmcia_device *link = local->finder; - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs start_net - device not present\n"); - return; - } - /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) < 0) - return; - pccs = ccs_base(local) + ccsindex; - writeb(CCS_START_NETWORK, &pccs->cmd); - writeb(0, &pccs->var.start_network.update_param); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray start net failed - card not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return; - } - local->card_status = CARD_DOING_ACQ; -} /* end start_net */ - -/*===========================================================================*/ -/* Command card to join a network */ -static void join_net(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - - struct ccs __iomem *pccs; - int ccsindex; - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs join_net - device not present\n"); - return; - } - /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) < 0) - return; - pccs = ccs_base(local) + ccsindex; - writeb(CCS_JOIN_NETWORK, &pccs->cmd); - writeb(0, &pccs->var.join_network.update_param); - writeb(0, &pccs->var.join_network.net_initiated); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray join net failed - card not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return; - } - local->card_status = CARD_DOING_ACQ; -} - - -static void ray_release(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - ray_dev_t *local = netdev_priv(dev); - - dev_dbg(&link->dev, "ray_release\n"); - - del_timer_sync(&local->timer); - - if (local->sram) - iounmap(local->sram); - if (local->rmem) - iounmap(local->rmem); - if (local->amem) - iounmap(local->amem); - pcmcia_disable_device(link); - - dev_dbg(&link->dev, "ray_release ending\n"); -} - -static int ray_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int ray_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) { - ray_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - -/*===========================================================================*/ -static int ray_dev_init(struct net_device *dev) -{ -#ifdef RAY_IMMEDIATE_INIT - int i; -#endif /* RAY_IMMEDIATE_INIT */ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - - dev_dbg(&link->dev, "ray_dev_init(dev=%p)\n", dev); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_dev_init - device not present\n"); - return -1; - } -#ifdef RAY_IMMEDIATE_INIT - /* Download startup parameters */ - if ((i = dl_startup_params(dev)) < 0) { - printk(KERN_INFO "ray_dev_init dl_startup_params failed - " - "returns 0x%x\n", i); - return -1; - } -#else /* RAY_IMMEDIATE_INIT */ - /* Postpone the card init so that we can still configure the card, - * for example using the Wireless Extensions. The init will happen - * in ray_open() - Jean II */ - dev_dbg(&link->dev, - "ray_dev_init: postponing card init to ray_open() ; Status = %d\n", - local->card_status); -#endif /* RAY_IMMEDIATE_INIT */ - - /* copy mac and broadcast addresses to linux device */ - eth_hw_addr_set(dev, local->sparm.b4.a_mac_addr); - eth_broadcast_addr(dev->broadcast); - - dev_dbg(&link->dev, "ray_dev_init ending\n"); - return 0; -} - -/*===========================================================================*/ -static int ray_dev_config(struct net_device *dev, struct ifmap *map) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - /* Dummy routine to satisfy device structure */ - dev_dbg(&link->dev, "ray_dev_config(dev=%p,ifmap=%p)\n", dev, map); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_dev_config - device not present\n"); - return -1; - } - - return 0; -} - -/*===========================================================================*/ -static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - short length = skb->len; - - if (!pcmcia_dev_present(link)) { - dev_dbg(&link->dev, "ray_dev_start_xmit - device not present\n"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - dev_dbg(&link->dev, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev); - if (local->authentication_state == NEED_TO_AUTH) { - dev_dbg(&link->dev, "ray_cs Sending authentication request.\n"); - if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) { - local->authentication_state = AUTHENTICATED; - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - } - } - - if (length < ETH_ZLEN) { - if (skb_padto(skb, ETH_ZLEN)) - return NETDEV_TX_OK; - length = ETH_ZLEN; - } - switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) { - case XMIT_NO_CCS: - case XMIT_NEED_AUTH: - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - case XMIT_NO_INTR: - case XMIT_MSG_BAD: - case XMIT_OK: - default: - dev_kfree_skb(skb); - } - - return NETDEV_TX_OK; -} /* ray_dev_start_xmit */ - -/*===========================================================================*/ -static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, - UCHAR msg_type) -{ - ray_dev_t *local = netdev_priv(dev); - struct ccs __iomem *pccs; - int ccsindex; - int offset; - struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */ - short int addr; /* Address of xmit buffer in card space */ - - pr_debug("ray_hw_xmit(data=%p, len=%d, dev=%p)\n", data, len, dev); - if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) { - printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n", - len); - return XMIT_MSG_BAD; - } - switch (ccsindex = get_free_tx_ccs(local)) { - case ECCSBUSY: - pr_debug("ray_hw_xmit tx_ccs table busy\n"); - fallthrough; - case ECCSFULL: - pr_debug("ray_hw_xmit No free tx ccs\n"); - fallthrough; - case ECARDGONE: - netif_stop_queue(dev); - return XMIT_NO_CCS; - default: - break; - } - addr = TX_BUF_BASE + (ccsindex << 11); - - if (msg_type == DATA_TYPE) { - local->stats.tx_bytes += len; - local->stats.tx_packets++; - } - - ptx = local->sram + addr; - - ray_build_header(local, ptx, msg_type, data); - if (translate) { - offset = translate_frame(local, ptx, data, len); - } else { /* Encapsulate frame */ - /* TBD TIB length will move address of ptx->var */ - memcpy_toio(&ptx->var, data, len); - offset = 0; - } - - /* fill in the CCS */ - pccs = ccs_base(local) + ccsindex; - len += TX_HEADER_LENGTH + offset; - writeb(CCS_TX_REQUEST, &pccs->cmd); - writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]); - writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]); - writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]); - writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]); -/* TBD still need psm_cam? */ - writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode); - writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate); - writeb(0, &pccs->var.tx_request.antenna); - pr_debug("ray_hw_xmit default_tx_rate = 0x%x\n", - local->net_default_tx_rate); - - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - pr_debug("ray_hw_xmit failed - ECF not ready for intr\n"); -/* TBD very inefficient to copy packet to buffer, and then not - send it, but the alternative is to queue the messages and that - won't be done for a while. Maybe set tbusy until a CCS is free? -*/ - writeb(CCS_BUFFER_FREE, &pccs->buffer_status); - return XMIT_NO_INTR; - } - return XMIT_OK; -} /* end ray_hw_xmit */ - -/*===========================================================================*/ -static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, - unsigned char *data, int len) -{ - __be16 proto = ((struct ethhdr *)data)->h_proto; - if (ntohs(proto) >= ETH_P_802_3_MIN) { /* DIX II ethernet frame */ - pr_debug("ray_cs translate_frame DIX II\n"); - /* Copy LLC header to card buffer */ - memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); - memcpy_toio(((void __iomem *)&ptx->var) + sizeof(eth2_llc), - (UCHAR *) &proto, 2); - if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) { - /* This is the selective translation table, only 2 entries */ - writeb(0xf8, - &((struct snaphdr_t __iomem *)ptx->var)->org[2]); - } - /* Copy body of ethernet packet without ethernet header */ - memcpy_toio((void __iomem *)&ptx->var + - sizeof(struct snaphdr_t), data + ETH_HLEN, - len - ETH_HLEN); - return (int)sizeof(struct snaphdr_t) - ETH_HLEN; - } else { /* already 802 type, and proto is length */ - pr_debug("ray_cs translate_frame 802\n"); - if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */ - pr_debug("ray_cs translate_frame evil IPX\n"); - memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); - return 0 - ETH_HLEN; - } - memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); - return 0 - ETH_HLEN; - } - /* TBD do other frame types */ -} /* end translate_frame */ - -/*===========================================================================*/ -static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, - UCHAR msg_type, unsigned char *data) -{ - writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1); -/*** IEEE 802.11 Address field assignments ************* - TODS FROMDS addr_1 addr_2 addr_3 addr_4 -Adhoc 0 0 dest src (terminal) BSSID N/A -AP to Terminal 0 1 dest AP(BSSID) source N/A -Terminal to AP 1 0 AP(BSSID) src (terminal) dest N/A -AP to AP 1 1 dest AP src AP dest source -*******************************************************/ - if (local->net_type == ADHOC) { - writeb(0, &ptx->mac.frame_ctl_2); - memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, - ADDRLEN); - memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source, - ADDRLEN); - memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); - } else { /* infrastructure */ - - if (local->sparm.b4.a_acting_as_ap_status) { - writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2); - memcpy_toio(ptx->mac.addr_1, - ((struct ethhdr *)data)->h_dest, ADDRLEN); - memcpy_toio(ptx->mac.addr_2, local->bss_id, 6); - memcpy_toio(ptx->mac.addr_3, - ((struct ethhdr *)data)->h_source, ADDRLEN); - } else { /* Terminal */ - - writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2); - memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN); - memcpy_toio(ptx->mac.addr_2, - ((struct ethhdr *)data)->h_source, ADDRLEN); - memcpy_toio(ptx->mac.addr_3, - ((struct ethhdr *)data)->h_dest, ADDRLEN); - } - } -} /* end encapsulate_frame */ - -/*====================================================================*/ - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get protocol name - */ -static int ray_get_name(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - strcpy(wrqu->name, "IEEE 802.11-FH"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set frequency - */ -static int ray_set_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* Setting by channel number */ - if ((wrqu->freq.m > USA_HOP_MOD) || (wrqu->freq.e > 0)) - err = -EOPNOTSUPP; - else - local->sparm.b5.a_hop_pattern = wrqu->freq.m; - - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get frequency - */ -static int ray_get_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - wrqu->freq.m = local->sparm.b5.a_hop_pattern; - wrqu->freq.e = 0; - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set ESSID - */ -static int ray_set_essid(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* Check if we asked for `any' */ - if (wrqu->essid.flags == 0) - /* Corey : can you do that ? */ - return -EOPNOTSUPP; - - /* Check the size of the string */ - if (wrqu->essid.length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - /* Set the ESSID in the card */ - memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE); - memcpy(local->sparm.b5.a_current_ess_id, extra, wrqu->essid.length); - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get ESSID - */ -static int ray_get_essid(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - UCHAR tmp[IW_ESSID_MAX_SIZE + 1]; - - /* Get the essid that was set */ - memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); - memcpy(tmp, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); - tmp[IW_ESSID_MAX_SIZE] = '\0'; - - /* Push it out ! */ - wrqu->essid.length = strlen(tmp); - wrqu->essid.flags = 1; /* active */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get AP address - */ -static int ray_get_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - memcpy(wrqu->ap_addr.sa_data, local->bss_id, ETH_ALEN); - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Bit-Rate - */ -static int ray_set_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* Check if rate is in range */ - if ((wrqu->bitrate.value != 1000000) && (wrqu->bitrate.value != 2000000)) - return -EINVAL; - - /* Hack for 1.5 Mb/s instead of 2 Mb/s */ - if ((local->fw_ver == 0x55) && /* Please check */ - (wrqu->bitrate.value == 2000000)) - local->net_default_tx_rate = 3; - else - local->net_default_tx_rate = wrqu->bitrate.value / 500000; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Bit-Rate - */ -static int ray_get_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - if (local->net_default_tx_rate == 3) - wrqu->bitrate.value = 2000000; /* Hum... */ - else - wrqu->bitrate.value = local->net_default_tx_rate * 500000; - wrqu->bitrate.fixed = 0; /* We are in auto mode */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set RTS threshold - */ -static int ray_set_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int rthr = wrqu->rts.value; - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* if(wrq->u.rts.fixed == 0) we should complain */ - if (wrqu->rts.disabled) - rthr = 32767; - else { - if ((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */ - return -EINVAL; - } - local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF; - local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF; - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get RTS threshold - */ -static int ray_get_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - wrqu->rts.value = (local->sparm.b5.a_rts_threshold[0] << 8) - + local->sparm.b5.a_rts_threshold[1]; - wrqu->rts.disabled = (wrqu->rts.value == 32767); - wrqu->rts.fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Fragmentation threshold - */ -static int ray_set_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int fthr = wrqu->frag.value; - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - /* if(wrq->u.frag.fixed == 0) should complain */ - if (wrqu->frag.disabled) - fthr = 32767; - else { - if ((fthr < 256) || (fthr > 2347)) /* To check out ! */ - return -EINVAL; - } - local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF; - local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF; - - return -EINPROGRESS; /* Call commit handler */ -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Fragmentation threshold - */ -static int ray_get_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - wrqu->frag.value = (local->sparm.b5.a_frag_threshold[0] << 8) - + local->sparm.b5.a_frag_threshold[1]; - wrqu->frag.disabled = (wrqu->frag.value == 32767); - wrqu->frag.fixed = 1; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set Mode of Operation - */ -static int ray_set_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - char card_mode = 1; - - /* Reject if card is already initialised */ - if (local->card_status != CARD_AWAITING_PARAM) - return -EBUSY; - - switch (wrqu->mode) { - case IW_MODE_ADHOC: - card_mode = 0; - fallthrough; - case IW_MODE_INFRA: - local->sparm.b5.a_network_type = card_mode; - break; - default: - err = -EINVAL; - } - - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get Mode of Operation - */ -static int ray_get_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - ray_dev_t *local = netdev_priv(dev); - - if (local->sparm.b5.a_network_type) - wrqu->mode = IW_MODE_INFRA; - else - wrqu->mode = IW_MODE_ADHOC; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get range info - */ -static int ray_get_range(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - - memset(range, 0, sizeof(struct iw_range)); - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(struct iw_range); - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 9; - - /* Set information in the range struct */ - range->throughput = 1.1 * 1000 * 1000; /* Put the right number here */ - range->num_channels = hop_pattern_length[(int)country]; - range->num_frequency = 0; - range->max_qual.qual = 0; - range->max_qual.level = 255; /* What's the correct value ? */ - range->max_qual.noise = 255; /* Idem */ - range->num_bitrates = 2; - range->bitrate[0] = 1000000; /* 1 Mb/s */ - range->bitrate[1] = 2000000; /* 2 Mb/s */ - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : set framing mode - */ -static int ray_set_framing(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - translate = !!*(extra); /* Set framing mode */ - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get framing mode - */ -static int ray_get_framing(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - *(extra) = translate; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get country - */ -static int ray_get_country(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - *(extra) = country; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Commit handler : called after a bunch of SET operations - */ -static int ray_commit(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Stats handler : return Wireless Stats - */ -static iw_stats *ray_get_wireless_stats(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - struct status __iomem *p = local->sram + STATUS_BASE; - - local->wstats.status = local->card_status; -#ifdef WIRELESS_SPY - if ((local->spy_data.spy_number > 0) - && (local->sparm.b5.a_network_type == 0)) { - /* Get it from the first node in spy list */ - local->wstats.qual.qual = local->spy_data.spy_stat[0].qual; - local->wstats.qual.level = local->spy_data.spy_stat[0].level; - local->wstats.qual.noise = local->spy_data.spy_stat[0].noise; - local->wstats.qual.updated = - local->spy_data.spy_stat[0].updated; - } -#endif /* WIRELESS_SPY */ - - if (pcmcia_dev_present(link)) { - local->wstats.qual.noise = readb(&p->rxnoise); - local->wstats.qual.updated |= 4; - } - - return &local->wstats; -} /* end ray_get_wireless_stats */ - -/*------------------------------------------------------------------*/ -/* - * Structures to export the Wireless Handlers - */ - -static const iw_handler ray_handler[] = { - IW_HANDLER(SIOCSIWCOMMIT, ray_commit), - IW_HANDLER(SIOCGIWNAME, ray_get_name), - IW_HANDLER(SIOCSIWFREQ, ray_set_freq), - IW_HANDLER(SIOCGIWFREQ, ray_get_freq), - IW_HANDLER(SIOCSIWMODE, ray_set_mode), - IW_HANDLER(SIOCGIWMODE, ray_get_mode), - IW_HANDLER(SIOCGIWRANGE, ray_get_range), -#ifdef WIRELESS_SPY - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), -#endif /* WIRELESS_SPY */ - IW_HANDLER(SIOCGIWAP, ray_get_wap), - IW_HANDLER(SIOCSIWESSID, ray_set_essid), - IW_HANDLER(SIOCGIWESSID, ray_get_essid), - IW_HANDLER(SIOCSIWRATE, ray_set_rate), - IW_HANDLER(SIOCGIWRATE, ray_get_rate), - IW_HANDLER(SIOCSIWRTS, ray_set_rts), - IW_HANDLER(SIOCGIWRTS, ray_get_rts), - IW_HANDLER(SIOCSIWFRAG, ray_set_frag), - IW_HANDLER(SIOCGIWFRAG, ray_get_frag), -}; - -#define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */ -#define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1 /* Get framing mode */ -#define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */ - -static const iw_handler ray_private_handler[] = { - [0] = ray_set_framing, - [1] = ray_get_framing, - [3] = ray_get_country, -}; - -static const struct iw_priv_args ray_private_args[] = { -/* cmd, set_args, get_args, name */ - {SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, - "set_framing"}, - {SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - "get_framing"}, - {SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - "get_country"}, -}; - -static const struct iw_handler_def ray_handler_def = { - .num_standard = ARRAY_SIZE(ray_handler), - .num_private = ARRAY_SIZE(ray_private_handler), - .num_private_args = ARRAY_SIZE(ray_private_args), - .standard = ray_handler, - .private = ray_private_handler, - .private_args = ray_private_args, - .get_wireless_stats = ray_get_wireless_stats, -}; - -/*===========================================================================*/ -static int ray_open(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link; - link = local->finder; - - dev_dbg(&link->dev, "ray_open('%s')\n", dev->name); - - if (link->open == 0) - local->num_multi = 0; - link->open++; - - /* If the card is not started, time to start it ! - Jean II */ - if (local->card_status == CARD_AWAITING_PARAM) { - int i; - - dev_dbg(&link->dev, "ray_open: doing init now !\n"); - - /* Download startup parameters */ - if ((i = dl_startup_params(dev)) < 0) { - printk(KERN_INFO - "ray_dev_init dl_startup_params failed - " - "returns 0x%x\n", i); - return -1; - } - } - - if (sniffer) - netif_stop_queue(dev); - else - netif_start_queue(dev); - - dev_dbg(&link->dev, "ray_open ending\n"); - return 0; -} /* end ray_open */ - -/*===========================================================================*/ -static int ray_dev_close(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link; - link = local->finder; - - dev_dbg(&link->dev, "ray_dev_close('%s')\n", dev->name); - - link->open--; - netif_stop_queue(dev); - - /* In here, we should stop the hardware (stop card from beeing active) - * and set local->card_status to CARD_AWAITING_PARAM, so that while the - * card is closed we can chage its configuration. - * Probably also need a COR reset to get sane state - Jean II */ - - return 0; -} /* end ray_dev_close */ - -/*===========================================================================*/ -static void ray_reset(struct net_device *dev) -{ - pr_debug("ray_reset entered\n"); -} - -/*===========================================================================*/ -/* Cause a firmware interrupt if it is ready for one */ -/* Return nonzero if not ready */ -static int interrupt_ecf(ray_dev_t *local, int ccs) -{ - int i = 50; - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs interrupt_ecf - device not present\n"); - return -1; - } - dev_dbg(&link->dev, "interrupt_ecf(local=%p, ccs = 0x%x\n", local, ccs); - - while (i && - (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & - ECF_INTR_SET)) - i--; - if (i == 0) { - dev_dbg(&link->dev, "ray_cs interrupt_ecf card not ready for interrupt\n"); - return -1; - } - /* Fill the mailbox, then kick the card */ - writeb(ccs, local->sram + SCB_BASE); - writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET); - return 0; -} /* interrupt_ecf */ - -/*===========================================================================*/ -/* Get next free transmit CCS */ -/* Return - index of current tx ccs */ -static int get_free_tx_ccs(ray_dev_t *local) -{ - int i; - struct ccs __iomem *pccs = ccs_base(local); - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs get_free_tx_ccs - device not present\n"); - return ECARDGONE; - } - - if (test_and_set_bit(0, &local->tx_ccs_lock)) { - dev_dbg(&link->dev, "ray_cs tx_ccs_lock busy\n"); - return ECCSBUSY; - } - - for (i = 0; i < NUMBER_OF_TX_CCS; i++) { - if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) { - writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status); - writeb(CCS_END_LIST, &(pccs + i)->link); - local->tx_ccs_lock = 0; - return i; - } - } - local->tx_ccs_lock = 0; - dev_dbg(&link->dev, "ray_cs ERROR no free tx CCS for raylink card\n"); - return ECCSFULL; -} /* get_free_tx_ccs */ - -/*===========================================================================*/ -/* Get next free CCS */ -/* Return - index of current ccs */ -static int get_free_ccs(ray_dev_t *local) -{ - int i; - struct ccs __iomem *pccs = ccs_base(local); - struct pcmcia_device *link = local->finder; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs get_free_ccs - device not present\n"); - return ECARDGONE; - } - if (test_and_set_bit(0, &local->ccs_lock)) { - dev_dbg(&link->dev, "ray_cs ccs_lock busy\n"); - return ECCSBUSY; - } - - for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) { - if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) { - writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status); - writeb(CCS_END_LIST, &(pccs + i)->link); - local->ccs_lock = 0; - return i; - } - } - local->ccs_lock = 0; - dev_dbg(&link->dev, "ray_cs ERROR no free CCS for raylink card\n"); - return ECCSFULL; -} /* get_free_ccs */ - -/*===========================================================================*/ -static void authenticate_timeout(struct timer_list *t) -{ - ray_dev_t *local = from_timer(local, t, timer); - del_timer(&local->timer); - printk(KERN_INFO "ray_cs Authentication with access point failed" - " - timeout\n"); - join_net(&local->timer); -} - -/*===========================================================================*/ -static int parse_addr(char *in_str, UCHAR *out) -{ - int i, k; - int len; - - if (in_str == NULL) - return 0; - len = strnlen(in_str, ADDRLEN * 2 + 1) - 1; - if (len < 1) - return 0; - memset(out, 0, ADDRLEN); - - i = 5; - - while (len > 0) { - if ((k = hex_to_bin(in_str[len--])) != -1) - out[i] = k; - else - return 0; - - if (len == 0) - break; - if ((k = hex_to_bin(in_str[len--])) != -1) - out[i] += k << 4; - else - return 0; - if (!i--) - break; - } - return 1; -} - -/*===========================================================================*/ -static struct net_device_stats *ray_get_stats(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - struct status __iomem *p = local->sram + STATUS_BASE; - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs net_device_stats - device not present\n"); - return &local->stats; - } - if (readb(&p->mrx_overflow_for_host)) { - local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow)); - writeb(0, &p->mrx_overflow); - writeb(0, &p->mrx_overflow_for_host); - } - if (readb(&p->mrx_checksum_error_for_host)) { - local->stats.rx_crc_errors += - swab16(readw(&p->mrx_checksum_error)); - writeb(0, &p->mrx_checksum_error); - writeb(0, &p->mrx_checksum_error_for_host); - } - if (readb(&p->rx_hec_error_for_host)) { - local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error)); - writeb(0, &p->rx_hec_error); - writeb(0, &p->rx_hec_error_for_host); - } - return &local->stats; -} - -/*===========================================================================*/ -static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, - int len) -{ - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - int ccsindex; - int i; - struct ccs __iomem *pccs; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_update_parm - device not present\n"); - return; - } - - if ((ccsindex = get_free_ccs(local)) < 0) { - dev_dbg(&link->dev, "ray_update_parm - No free ccs\n"); - return; - } - pccs = ccs_base(local) + ccsindex; - writeb(CCS_UPDATE_PARAMS, &pccs->cmd); - writeb(objid, &pccs->var.update_param.object_id); - writeb(1, &pccs->var.update_param.number_objects); - writeb(0, &pccs->var.update_param.failure_cause); - for (i = 0; i < len; i++) { - writeb(value[i], local->sram + HOST_TO_ECF_BASE); - } - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - } -} - -/*===========================================================================*/ -static void ray_update_multi_list(struct net_device *dev, int all) -{ - int ccsindex; - struct ccs __iomem *pccs; - ray_dev_t *local = netdev_priv(dev); - struct pcmcia_device *link = local->finder; - void __iomem *p = local->sram + HOST_TO_ECF_BASE; - - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_update_multi_list - device not present\n"); - return; - } else - dev_dbg(&link->dev, "ray_update_multi_list(%p)\n", dev); - if ((ccsindex = get_free_ccs(local)) < 0) { - dev_dbg(&link->dev, "ray_update_multi - No free ccs\n"); - return; - } - pccs = ccs_base(local) + ccsindex; - writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd); - - if (all) { - writeb(0xff, &pccs->var); - local->num_multi = 0xff; - } else { - struct netdev_hw_addr *ha; - int i = 0; - - /* Copy the kernel's list of MC addresses to card */ - netdev_for_each_mc_addr(ha, dev) { - memcpy_toio(p, ha->addr, ETH_ALEN); - dev_dbg(&link->dev, "ray_update_multi add addr %pm\n", - ha->addr); - p += ETH_ALEN; - i++; - } - if (i > 256 / ADDRLEN) - i = 256 / ADDRLEN; - writeb((UCHAR) i, &pccs->var); - dev_dbg(&link->dev, "ray_cs update_multi %d addresses in list\n", i); - /* Interrupt the firmware to process the command */ - local->num_multi = i; - } - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, - "ray_cs update_multi failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - } -} /* end ray_update_multi_list */ - -/*===========================================================================*/ -static void set_multicast_list(struct net_device *dev) -{ - ray_dev_t *local = netdev_priv(dev); - UCHAR promisc; - - pr_debug("ray_cs set_multicast_list(%p)\n", dev); - - if (dev->flags & IFF_PROMISC) { - if (local->sparm.b5.a_promiscuous_mode == 0) { - pr_debug("ray_cs set_multicast_list promisc on\n"); - local->sparm.b5.a_promiscuous_mode = 1; - promisc = 1; - ray_update_parm(dev, OBJID_promiscuous_mode, - &promisc, sizeof(promisc)); - } - } else { - if (local->sparm.b5.a_promiscuous_mode == 1) { - pr_debug("ray_cs set_multicast_list promisc off\n"); - local->sparm.b5.a_promiscuous_mode = 0; - promisc = 0; - ray_update_parm(dev, OBJID_promiscuous_mode, - &promisc, sizeof(promisc)); - } - } - - if (dev->flags & IFF_ALLMULTI) - ray_update_multi_list(dev, 1); - else { - if (local->num_multi != netdev_mc_count(dev)) - ray_update_multi_list(dev, 0); - } -} /* end set_multicast_list */ - -/*============================================================================= - * All routines below here are run at interrupt time. -=============================================================================*/ -static irqreturn_t ray_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct pcmcia_device *link; - ray_dev_t *local; - struct ccs __iomem *pccs; - struct rcs __iomem *prcs; - UCHAR rcsindex; - UCHAR tmp; - UCHAR cmd; - UCHAR status; - UCHAR memtmp[ESSID_SIZE + 1]; - - - if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */ - return IRQ_NONE; - - pr_debug("ray_cs: interrupt for *dev=%p\n", dev); - - local = netdev_priv(dev); - link = local->finder; - if (!pcmcia_dev_present(link)) { - pr_debug( - "ray_cs interrupt from device not present or suspended.\n"); - return IRQ_NONE; - } - rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index); - - if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { - dev_dbg(&link->dev, "ray_cs interrupt bad rcsindex = 0x%x\n", rcsindex); - clear_interrupt(local); - return IRQ_HANDLED; - } - if (rcsindex < NUMBER_OF_CCS) { /* If it's a returned CCS */ - pccs = ccs_base(local) + rcsindex; - cmd = readb(&pccs->cmd); - status = readb(&pccs->buffer_status); - switch (cmd) { - case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */ - del_timer(&local->timer); - if (status == CCS_COMMAND_COMPLETE) { - dev_dbg(&link->dev, - "ray_cs interrupt download_startup_parameters OK\n"); - } else { - dev_dbg(&link->dev, - "ray_cs interrupt download_startup_parameters fail\n"); - } - break; - case CCS_UPDATE_PARAMS: - dev_dbg(&link->dev, "ray_cs interrupt update params done\n"); - if (status != CCS_COMMAND_COMPLETE) { - tmp = - readb(&pccs->var.update_param. - failure_cause); - dev_dbg(&link->dev, - "ray_cs interrupt update params failed - reason %d\n", - tmp); - } - break; - case CCS_REPORT_PARAMS: - dev_dbg(&link->dev, "ray_cs interrupt report params done\n"); - break; - case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */ - dev_dbg(&link->dev, - "ray_cs interrupt CCS Update Multicast List done\n"); - break; - case CCS_UPDATE_POWER_SAVINGS_MODE: - dev_dbg(&link->dev, - "ray_cs interrupt update power save mode done\n"); - break; - case CCS_START_NETWORK: - case CCS_JOIN_NETWORK: - memcpy(memtmp, local->sparm.b4.a_current_ess_id, - ESSID_SIZE); - memtmp[ESSID_SIZE] = '\0'; - - if (status == CCS_COMMAND_COMPLETE) { - if (readb - (&pccs->var.start_network.net_initiated) == - 1) { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" started\n", - memtmp); - } else { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" joined\n", - memtmp); - } - memcpy_fromio(&local->bss_id, - pccs->var.start_network.bssid, - ADDRLEN); - - if (local->fw_ver == 0x55) - local->net_default_tx_rate = 3; - else - local->net_default_tx_rate = - readb(&pccs->var.start_network. - net_default_tx_rate); - local->encryption = - readb(&pccs->var.start_network.encryption); - if (!sniffer && (local->net_type == INFRA) - && !(local->sparm.b4.a_acting_as_ap_status)) { - authenticate(local); - } - local->card_status = CARD_ACQ_COMPLETE; - } else { - local->card_status = CARD_ACQ_FAILED; - - del_timer(&local->timer); - local->timer.expires = jiffies + HZ * 5; - if (status == CCS_START_NETWORK) { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" start failed\n", - memtmp); - local->timer.function = start_net; - } else { - dev_dbg(&link->dev, - "ray_cs interrupt network \"%s\" join failed\n", - memtmp); - local->timer.function = join_net; - } - add_timer(&local->timer); - } - break; - case CCS_START_ASSOCIATION: - if (status == CCS_COMMAND_COMPLETE) { - local->card_status = CARD_ASSOC_COMPLETE; - dev_dbg(&link->dev, "ray_cs association successful\n"); - } else { - dev_dbg(&link->dev, "ray_cs association failed,\n"); - local->card_status = CARD_ASSOC_FAILED; - join_net(&local->timer); - } - break; - case CCS_TX_REQUEST: - if (status == CCS_COMMAND_COMPLETE) { - dev_dbg(&link->dev, - "ray_cs interrupt tx request complete\n"); - } else { - dev_dbg(&link->dev, - "ray_cs interrupt tx request failed\n"); - } - if (!sniffer) - netif_start_queue(dev); - netif_wake_queue(dev); - break; - case CCS_TEST_MEMORY: - dev_dbg(&link->dev, "ray_cs interrupt mem test done\n"); - break; - case CCS_SHUTDOWN: - dev_dbg(&link->dev, - "ray_cs interrupt Unexpected CCS returned - Shutdown\n"); - break; - case CCS_DUMP_MEMORY: - dev_dbg(&link->dev, "ray_cs interrupt dump memory done\n"); - break; - case CCS_START_TIMER: - dev_dbg(&link->dev, - "ray_cs interrupt DING - raylink timer expired\n"); - break; - default: - dev_dbg(&link->dev, - "ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n", - rcsindex, cmd); - } - writeb(CCS_BUFFER_FREE, &pccs->buffer_status); - } else { /* It's an RCS */ - - prcs = rcs_base(local) + rcsindex; - - switch (readb(&prcs->interrupt_id)) { - case PROCESS_RX_PACKET: - ray_rx(dev, local, prcs); - break; - case REJOIN_NET_COMPLETE: - dev_dbg(&link->dev, "ray_cs interrupt rejoin net complete\n"); - local->card_status = CARD_ACQ_COMPLETE; - /* do we need to clear tx buffers CCS's? */ - if (local->sparm.b4.a_network_type == ADHOC) { - if (!sniffer) - netif_start_queue(dev); - } else { - memcpy_fromio(&local->bss_id, - prcs->var.rejoin_net_complete. - bssid, ADDRLEN); - dev_dbg(&link->dev, "ray_cs new BSSID = %pm\n", - local->bss_id); - if (!sniffer) - authenticate(local); - } - break; - case ROAMING_INITIATED: - dev_dbg(&link->dev, "ray_cs interrupt roaming initiated\n"); - netif_stop_queue(dev); - local->card_status = CARD_DOING_ACQ; - break; - case JAPAN_CALL_SIGN_RXD: - dev_dbg(&link->dev, "ray_cs interrupt japan call sign rx\n"); - break; - default: - dev_dbg(&link->dev, - "ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n", - rcsindex, - (unsigned int)readb(&prcs->interrupt_id)); - break; - } - writeb(CCS_BUFFER_FREE, &prcs->buffer_status); - } - clear_interrupt(local); - return IRQ_HANDLED; -} /* ray_interrupt */ - -/*===========================================================================*/ -static void ray_rx(struct net_device *dev, ray_dev_t *local, - struct rcs __iomem *prcs) -{ - int rx_len; - unsigned int pkt_addr; - void __iomem *pmsg; - pr_debug("ray_rx process rx packet\n"); - - /* Calculate address of packet within Rx buffer */ - pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8) - + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END; - /* Length of first packet fragment */ - rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8) - + readb(&prcs->var.rx_packet.rx_data_length[1]); - - local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev); - pmsg = local->rmem + pkt_addr; - switch (readb(pmsg)) { - case DATA_TYPE: - pr_debug("ray_rx data type\n"); - rx_data(dev, prcs, pkt_addr, rx_len); - break; - case AUTHENTIC_TYPE: - pr_debug("ray_rx authentic type\n"); - if (sniffer) - rx_data(dev, prcs, pkt_addr, rx_len); - else - rx_authenticate(local, prcs, pkt_addr, rx_len); - break; - case DEAUTHENTIC_TYPE: - pr_debug("ray_rx deauth type\n"); - if (sniffer) - rx_data(dev, prcs, pkt_addr, rx_len); - else - rx_deauthenticate(local, prcs, pkt_addr, rx_len); - break; - case NULL_MSG_TYPE: - pr_debug("ray_cs rx NULL msg\n"); - break; - case BEACON_TYPE: - pr_debug("ray_rx beacon type\n"); - if (sniffer) - rx_data(dev, prcs, pkt_addr, rx_len); - - copy_from_rx_buff(local, (UCHAR *) &local->last_bcn, pkt_addr, - rx_len < sizeof(struct beacon_rx) ? - rx_len : sizeof(struct beacon_rx)); - - local->beacon_rxed = 1; - /* Get the statistics so the card counters never overflow */ - ray_get_stats(dev); - break; - default: - pr_debug("ray_cs unknown pkt type %2x\n", - (unsigned int)readb(pmsg)); - break; - } - -} /* end ray_rx */ - -/*===========================================================================*/ -static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len) -{ - struct sk_buff *skb = NULL; - struct rcs __iomem *prcslink = prcs; - ray_dev_t *local = netdev_priv(dev); - UCHAR *rx_ptr; - int total_len; - int tmp; -#ifdef WIRELESS_SPY - int siglev = local->last_rsl; - u_char linksrcaddr[ETH_ALEN]; /* Other end of the wireless link */ -#endif - - if (!sniffer) { - if (translate) { -/* TBD length needs fixing for translated header */ - if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || - rx_len > - (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + - FCS_LEN)) { - pr_debug( - "ray_cs invalid packet length %d received\n", - rx_len); - return; - } - } else { /* encapsulated ethernet */ - - if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || - rx_len > - (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + - FCS_LEN)) { - pr_debug( - "ray_cs invalid packet length %d received\n", - rx_len); - return; - } - } - } - pr_debug("ray_cs rx_data packet\n"); - /* If fragmented packet, verify sizes of fragments add up */ - if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { - pr_debug("ray_cs rx'ed fragment\n"); - tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8) - + readb(&prcs->var.rx_packet.totalpacketlength[1]); - total_len = tmp; - prcslink = prcs; - do { - tmp -= - (readb(&prcslink->var.rx_packet.rx_data_length[0]) - << 8) - + readb(&prcslink->var.rx_packet.rx_data_length[1]); - if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) - == 0xFF || tmp < 0) - break; - prcslink = rcs_base(local) - + readb(&prcslink->link_field); - } while (1); - - if (tmp < 0) { - pr_debug( - "ray_cs rx_data fragment lengths don't add up\n"); - local->stats.rx_dropped++; - release_frag_chain(local, prcs); - return; - } - } else { /* Single unfragmented packet */ - total_len = rx_len; - } - - skb = dev_alloc_skb(total_len + 5); - if (skb == NULL) { - pr_debug("ray_cs rx_data could not allocate skb\n"); - local->stats.rx_dropped++; - if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) - release_frag_chain(local, prcs); - return; - } - skb_reserve(skb, 2); /* Align IP on 16 byte (TBD check this) */ - - pr_debug("ray_cs rx_data total_len = %x, rx_len = %x\n", total_len, - rx_len); - -/************************/ - /* Reserve enough room for the whole damn packet. */ - rx_ptr = skb_put(skb, total_len); - /* Copy the whole packet to sk_buff */ - rx_ptr += - copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len); - /* Get source address */ -#ifdef WIRELESS_SPY - skb_copy_from_linear_data_offset(skb, - offsetof(struct mac_header, addr_2), - linksrcaddr, ETH_ALEN); -#endif - /* Now, deal with encapsulation/translation/sniffer */ - if (!sniffer) { - if (!translate) { - /* Encapsulated ethernet, so just lop off 802.11 MAC header */ -/* TBD reserve skb_reserve( skb, RX_MAC_HEADER_LENGTH); */ - skb_pull(skb, RX_MAC_HEADER_LENGTH); - } else { - /* Do translation */ - untranslate(local, skb, total_len); - } - } else { /* sniffer mode, so just pass whole packet */ - } - -/************************/ - /* Now pick up the rest of the fragments if any */ - tmp = 17; - if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { - prcslink = prcs; - pr_debug("ray_cs rx_data in fragment loop\n"); - do { - prcslink = rcs_base(local) - + - readb(&prcslink->var.rx_packet.next_frag_rcs_index); - rx_len = - ((readb(&prcslink->var.rx_packet.rx_data_length[0]) - << 8) - + - readb(&prcslink->var.rx_packet.rx_data_length[1])) - & RX_BUFF_END; - pkt_addr = - ((readb(&prcslink->var.rx_packet.rx_data_ptr[0]) << - 8) - + readb(&prcslink->var.rx_packet.rx_data_ptr[1])) - & RX_BUFF_END; - - rx_ptr += - copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len); - - } while (tmp-- && - readb(&prcslink->var.rx_packet.next_frag_rcs_index) != - 0xFF); - release_frag_chain(local, prcs); - } - - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - local->stats.rx_packets++; - local->stats.rx_bytes += total_len; - - /* Gather signal strength per address */ -#ifdef WIRELESS_SPY - /* For the Access Point or the node having started the ad-hoc net - * note : ad-hoc work only in some specific configurations, but we - * kludge in ray_get_wireless_stats... */ - if (!memcmp(linksrcaddr, local->bss_id, ETH_ALEN)) { - /* Update statistics */ - /*local->wstats.qual.qual = none ? */ - local->wstats.qual.level = siglev; - /*local->wstats.qual.noise = none ? */ - local->wstats.qual.updated = 0x2; - } - /* Now, update the spy stuff */ - { - struct iw_quality wstats; - wstats.level = siglev; - /* wstats.noise = none ? */ - /* wstats.qual = none ? */ - wstats.updated = 0x2; - /* Update spy records */ - wireless_spy_update(dev, linksrcaddr, &wstats); - } -#endif /* WIRELESS_SPY */ -} /* end rx_data */ - -/*===========================================================================*/ -static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) -{ - snaphdr_t *psnap = (snaphdr_t *) (skb->data + RX_MAC_HEADER_LENGTH); - struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data; - __be16 type = *(__be16 *) psnap->ethertype; - int delta; - struct ethhdr *peth; - UCHAR srcaddr[ADDRLEN]; - UCHAR destaddr[ADDRLEN]; - static const UCHAR org_bridge[3] = { 0, 0, 0xf8 }; - static const UCHAR org_1042[3] = { 0, 0, 0 }; - - memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN); - memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN); - -#if 0 - if { - print_hex_dump(KERN_DEBUG, "skb->data before untranslate: ", - DUMP_PREFIX_NONE, 16, 1, - skb->data, 64, true); - printk(KERN_DEBUG - "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n", - ntohs(type), psnap->dsap, psnap->ssap, psnap->ctrl, - psnap->org[0], psnap->org[1], psnap->org[2]); - printk(KERN_DEBUG "untranslate skb->data = %p\n", skb->data); - } -#endif - - if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) { - /* not a snap type so leave it alone */ - pr_debug("ray_cs untranslate NOT SNAP %02x %02x %02x\n", - psnap->dsap, psnap->ssap, psnap->ctrl); - - delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); - } else { /* Its a SNAP */ - if (memcmp(psnap->org, org_bridge, 3) == 0) { - /* EtherII and nuke the LLC */ - pr_debug("ray_cs untranslate Bridge encap\n"); - delta = RX_MAC_HEADER_LENGTH - + sizeof(struct snaphdr_t) - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = type; - } else if (memcmp(psnap->org, org_1042, 3) == 0) { - switch (ntohs(type)) { - case ETH_P_IPX: - case ETH_P_AARP: - pr_debug("ray_cs untranslate RFC IPX/AARP\n"); - delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = - htons(len - RX_MAC_HEADER_LENGTH); - break; - default: - pr_debug("ray_cs untranslate RFC default\n"); - delta = RX_MAC_HEADER_LENGTH + - sizeof(struct snaphdr_t) - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = type; - break; - } - } else { - printk("ray_cs untranslate very confused by packet\n"); - delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; - peth = (struct ethhdr *)(skb->data + delta); - peth->h_proto = type; - } - } -/* TBD reserve skb_reserve(skb, delta); */ - skb_pull(skb, delta); - pr_debug("untranslate after skb_pull(%d), skb->data = %p\n", delta, - skb->data); - memcpy(peth->h_dest, destaddr, ADDRLEN); - memcpy(peth->h_source, srcaddr, ADDRLEN); -#if 0 - { - int i; - printk(KERN_DEBUG "skb->data after untranslate:"); - for (i = 0; i < 64; i++) - printk("%02x ", skb->data[i]); - printk("\n"); - } -#endif -} /* end untranslate */ - -/*===========================================================================*/ -/* Copy data from circular receive buffer to PC memory. - * dest = destination address in PC memory - * pkt_addr = source address in receive buffer - * len = length of packet to copy - */ -static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, - int length) -{ - int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1); - if (wrap_bytes <= 0) { - memcpy_fromio(dest, local->rmem + pkt_addr, length); - } else { /* Packet wrapped in circular buffer */ - - memcpy_fromio(dest, local->rmem + pkt_addr, - length - wrap_bytes); - memcpy_fromio(dest + length - wrap_bytes, local->rmem, - wrap_bytes); - } - return length; -} - -/*===========================================================================*/ -static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs) -{ - struct rcs __iomem *prcslink = prcs; - int tmp = 17; - unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index); - - while (tmp--) { - writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); - if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { - pr_debug("ray_cs interrupt bad rcsindex = 0x%x\n", - rcsindex); - break; - } - prcslink = rcs_base(local) + rcsindex; - rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index); - } - writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); -} - -/*===========================================================================*/ -static void authenticate(ray_dev_t *local) -{ - struct pcmcia_device *link = local->finder; - dev_dbg(&link->dev, "ray_cs Starting authentication.\n"); - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs authenticate - device not present\n"); - return; - } - - del_timer(&local->timer); - if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) { - local->timer.function = join_net; - } else { - local->timer.function = authenticate_timeout; - } - local->timer.expires = jiffies + HZ * 2; - add_timer(&local->timer); - local->authentication_state = AWAITING_RESPONSE; -} /* end authenticate */ - -/*===========================================================================*/ -static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len) -{ - UCHAR buff[256]; - struct ray_rx_msg *msg = (struct ray_rx_msg *) buff; - - del_timer(&local->timer); - - copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); - /* if we are trying to get authenticated */ - if (local->sparm.b4.a_network_type == ADHOC) { - pr_debug("ray_cs rx_auth var= %6ph\n", msg->var); - if (msg->var[2] == 1) { - pr_debug("ray_cs Sending authentication response.\n"); - if (!build_auth_frame - (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) { - local->authentication_state = NEED_TO_AUTH; - memcpy(local->auth_id, msg->mac.addr_2, - ADDRLEN); - } - } - } else { /* Infrastructure network */ - - if (local->authentication_state == AWAITING_RESPONSE) { - /* Verify authentication sequence #2 and success */ - if (msg->var[2] == 2) { - if ((msg->var[3] | msg->var[4]) == 0) { - pr_debug("Authentication successful\n"); - local->card_status = CARD_AUTH_COMPLETE; - associate(local); - local->authentication_state = - AUTHENTICATED; - } else { - pr_debug("Authentication refused\n"); - local->card_status = CARD_AUTH_REFUSED; - join_net(&local->timer); - local->authentication_state = - UNAUTHENTICATED; - } - } - } - } - -} /* end rx_authenticate */ - -/*===========================================================================*/ -static void associate(ray_dev_t *local) -{ - struct ccs __iomem *pccs; - struct pcmcia_device *link = local->finder; - struct net_device *dev = link->priv; - int ccsindex; - if (!(pcmcia_dev_present(link))) { - dev_dbg(&link->dev, "ray_cs associate - device not present\n"); - return; - } - /* If no tx buffers available, return */ - if ((ccsindex = get_free_ccs(local)) < 0) { -/* TBD should never be here but... what if we are? */ - dev_dbg(&link->dev, "ray_cs associate - No free ccs\n"); - return; - } - dev_dbg(&link->dev, "ray_cs Starting association with access point\n"); - pccs = ccs_base(local) + ccsindex; - /* fill in the CCS */ - writeb(CCS_START_ASSOCIATION, &pccs->cmd); - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - - del_timer(&local->timer); - local->timer.expires = jiffies + HZ * 2; - local->timer.function = join_net; - add_timer(&local->timer); - local->card_status = CARD_ASSOC_FAILED; - return; - } - if (!sniffer) - netif_start_queue(dev); - -} /* end associate */ - -/*===========================================================================*/ -static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, - unsigned int pkt_addr, int rx_len) -{ -/* UCHAR buff[256]; - struct ray_rx_msg *msg = (struct ray_rx_msg *) buff; -*/ - pr_debug("Deauthentication frame received\n"); - local->authentication_state = UNAUTHENTICATED; - /* Need to reauthenticate or rejoin depending on reason code */ -/* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); - */ -} - -/*===========================================================================*/ -static void clear_interrupt(ray_dev_t *local) -{ - writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET); -} - -/*===========================================================================*/ -#ifdef CONFIG_PROC_FS -#define MAXDATA (PAGE_SIZE - 80) - -static const char *card_status[] = { - "Card inserted - uninitialized", /* 0 */ - "Card not downloaded", /* 1 */ - "Waiting for download parameters", /* 2 */ - "Card doing acquisition", /* 3 */ - "Acquisition complete", /* 4 */ - "Authentication complete", /* 5 */ - "Association complete", /* 6 */ - "???", "???", "???", "???", /* 7 8 9 10 undefined */ - "Card init error", /* 11 */ - "Download parameters error", /* 12 */ - "???", /* 13 */ - "Acquisition failed", /* 14 */ - "Authentication refused", /* 15 */ - "Association failed" /* 16 */ -}; - -static const char *nettype[] = { "Adhoc", "Infra " }; -static const char *framing[] = { "Encapsulation", "Translation" } - -; -/*===========================================================================*/ -static int ray_cs_proc_show(struct seq_file *m, void *v) -{ -/* Print current values which are not available via other means - * eg ifconfig - */ - int i; - struct pcmcia_device *link; - struct net_device *dev; - ray_dev_t *local; - UCHAR *p; - struct freq_hop_element *pfh; - UCHAR c[33]; - - link = this_device; - if (!link) - return 0; - dev = link->priv; - if (!dev) - return 0; - local = netdev_priv(dev); - if (!local) - return 0; - - seq_puts(m, "Raylink Wireless LAN driver status\n"); - seq_printf(m, "%s\n", rcsid); - /* build 4 does not report version, and field is 0x55 after memtest */ - seq_puts(m, "Firmware version = "); - if (local->fw_ver == 0x55) - seq_puts(m, "4 - Use dump_cis for more details\n"); - else - seq_printf(m, "%2d.%02d.%02d\n", - local->fw_ver, local->fw_bld, local->fw_var); - - for (i = 0; i < 32; i++) - c[i] = local->sparm.b5.a_current_ess_id[i]; - c[32] = 0; - seq_printf(m, "%s network ESSID = \"%s\"\n", - nettype[local->sparm.b5.a_network_type], c); - - p = local->bss_id; - seq_printf(m, "BSSID = %pM\n", p); - - seq_printf(m, "Country code = %d\n", - local->sparm.b5.a_curr_country_code); - - i = local->card_status; - if (i < 0) - i = 10; - if (i > 16) - i = 10; - seq_printf(m, "Card status = %s\n", card_status[i]); - - seq_printf(m, "Framing mode = %s\n", framing[translate]); - - seq_printf(m, "Last pkt signal lvl = %d\n", local->last_rsl); - - if (local->beacon_rxed) { - /* Pull some fields out of last beacon received */ - seq_printf(m, "Beacon Interval = %d Kus\n", - local->last_bcn.beacon_intvl[0] - + 256 * local->last_bcn.beacon_intvl[1]); - - p = local->last_bcn.elements; - if (p[0] == C_ESSID_ELEMENT_ID) - p += p[1] + 2; - else { - seq_printf(m, - "Parse beacon failed at essid element id = %d\n", - p[0]); - return 0; - } - - if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) { - seq_puts(m, "Supported rate codes = "); - for (i = 2; i < p[1] + 2; i++) - seq_printf(m, "0x%02x ", p[i]); - seq_putc(m, '\n'); - p += p[1] + 2; - } else { - seq_puts(m, "Parse beacon failed at rates element\n"); - return 0; - } - - if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) { - pfh = (struct freq_hop_element *)p; - seq_printf(m, "Hop dwell = %d Kus\n", - pfh->dwell_time[0] + - 256 * pfh->dwell_time[1]); - seq_printf(m, "Hop set = %d\n", - pfh->hop_set); - seq_printf(m, "Hop pattern = %d\n", - pfh->hop_pattern); - seq_printf(m, "Hop index = %d\n", - pfh->hop_index); - p += p[1] + 2; - } else { - seq_puts(m, - "Parse beacon failed at FH param element\n"); - return 0; - } - } else { - seq_puts(m, "No beacons received\n"); - } - return 0; -} -#endif -/*===========================================================================*/ -static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) -{ - int addr; - struct ccs __iomem *pccs; - struct tx_msg __iomem *ptx; - int ccsindex; - - /* If no tx buffers available, return */ - if ((ccsindex = get_free_tx_ccs(local)) < 0) { - pr_debug("ray_cs send authenticate - No free tx ccs\n"); - return -1; - } - - pccs = ccs_base(local) + ccsindex; - - /* Address in card space */ - addr = TX_BUF_BASE + (ccsindex << 11); - /* fill in the CCS */ - writeb(CCS_TX_REQUEST, &pccs->cmd); - writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr); - writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1); - writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length); - writeb(TX_AUTHENTICATE_LENGTH_LSB, - pccs->var.tx_request.tx_data_length + 1); - writeb(0, &pccs->var.tx_request.pow_sav_mode); - - ptx = local->sram + addr; - /* fill in the mac header */ - writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1); - writeb(0, &ptx->mac.frame_ctl_2); - - memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN); - memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN); - memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); - - /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */ - memset_io(ptx->var, 0, 6); - writeb(auth_type & 0xff, ptx->var + 2); - - /* Interrupt the firmware to process the command */ - if (interrupt_ecf(local, ccsindex)) { - pr_debug( - "ray_cs send authentication request failed - ECF not ready for intr\n"); - writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); - return -1; - } - return 0; -} /* End build_auth_frame */ - -/*===========================================================================*/ -#ifdef CONFIG_PROC_FS -static ssize_t ray_cs_essid_proc_write(struct file *file, - const char __user *buffer, size_t count, loff_t *pos) -{ - static char proc_essid[33]; - unsigned int len = count; - - if (len > 32) - len = 32; - memset(proc_essid, 0, 33); - if (copy_from_user(proc_essid, buffer, len)) - return -EFAULT; - essid = proc_essid; - return count; -} - -static const struct proc_ops ray_cs_essid_proc_ops = { - .proc_write = ray_cs_essid_proc_write, - .proc_lseek = noop_llseek, -}; - -static ssize_t int_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - static char proc_number[10]; - char *p; - int nr, len; - - if (!count) - return 0; - - if (count > 9) - return -EINVAL; - if (copy_from_user(proc_number, buffer, count)) - return -EFAULT; - p = proc_number; - nr = 0; - len = count; - do { - unsigned int c = *p - '0'; - if (c > 9) - return -EINVAL; - nr = nr * 10 + c; - p++; - } while (--len); - *(int *)pde_data(file_inode(file)) = nr; - return count; -} - -static const struct proc_ops int_proc_ops = { - .proc_write = int_proc_write, - .proc_lseek = noop_llseek, -}; -#endif - -static const struct pcmcia_device_id ray_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000), - PCMCIA_DEVICE_NULL, -}; - -MODULE_DEVICE_TABLE(pcmcia, ray_ids); - -static struct pcmcia_driver ray_driver = { - .owner = THIS_MODULE, - .name = "ray_cs", - .probe = ray_probe, - .remove = ray_detach, - .id_table = ray_ids, - .suspend = ray_suspend, - .resume = ray_resume, -}; - -static int __init init_ray_cs(void) -{ - int rc; - - pr_debug("%s\n", rcsid); - rc = pcmcia_register_driver(&ray_driver); - pr_debug("raylink init_module register_pcmcia_driver returns 0x%x\n", - rc); - if (rc) - return rc; - -#ifdef CONFIG_PROC_FS - proc_mkdir("driver/ray_cs", NULL); - - proc_create_single("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_show); - proc_create("driver/ray_cs/essid", 0200, NULL, &ray_cs_essid_proc_ops); - proc_create_data("driver/ray_cs/net_type", 0200, NULL, &int_proc_ops, - &net_type); - proc_create_data("driver/ray_cs/translate", 0200, NULL, &int_proc_ops, - &translate); -#endif - translate = !!translate; - return 0; -} /* init_ray_cs */ - -/*===========================================================================*/ - -static void __exit exit_ray_cs(void) -{ - pr_debug("ray_cs: cleanup_module\n"); - -#ifdef CONFIG_PROC_FS - remove_proc_subtree("driver/ray_cs", NULL); -#endif - - pcmcia_unregister_driver(&ray_driver); -} /* exit_ray_cs */ - -module_init(init_ray_cs); -module_exit(exit_ray_cs); - -/*===========================================================================*/ diff --git a/drivers/net/wireless/legacy/ray_cs.h b/drivers/net/wireless/legacy/ray_cs.h deleted file mode 100644 index 0609d86250..0000000000 --- a/drivers/net/wireless/legacy/ray_cs.h +++ /dev/null @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Raytheon wireless LAN PCMCIA card driver for Linux - A PCMCIA client driver for the Raylink wireless network card - Written by Corey Thomas -*/ - -#ifndef _RAY_CS_H_ -#define _RAY_CS_H_ - -struct beacon_rx { - struct mac_header mac; - UCHAR timestamp[8]; - UCHAR beacon_intvl[2]; - UCHAR capability[2]; - UCHAR elements[sizeof(struct essid_element) - + sizeof(struct rates_element) - + sizeof(struct freq_hop_element) - + sizeof(struct japan_call_sign_element) - + sizeof(struct tim_element)]; -}; - -/* Return values for get_free{,_tx}_ccs */ -#define ECCSFULL (-1) -#define ECCSBUSY (-2) -#define ECARDGONE (-3) - -typedef struct ray_dev_t { - int card_status; - int authentication_state; - void __iomem *sram; /* pointer to beginning of shared RAM */ - void __iomem *amem; /* pointer to attribute mem window */ - void __iomem *rmem; /* pointer to receive buffer window */ - struct pcmcia_device *finder; /* pointer back to struct pcmcia_device for card */ - struct timer_list timer; - unsigned long tx_ccs_lock; - unsigned long ccs_lock; - int dl_param_ccs; - union { - struct b4_startup_params b4; - struct b5_startup_params b5; - } sparm; - int timeout_flag; - UCHAR supported_rates[8]; - UCHAR japan_call_sign[12]; - struct startup_res_6 startup_res; - int num_multi; - /* Network parameters from start/join */ - UCHAR bss_id[6]; - UCHAR auth_id[6]; - UCHAR net_default_tx_rate; - UCHAR encryption; - struct net_device_stats stats; - - UCHAR net_type; - UCHAR sta_type; - UCHAR fw_ver; - UCHAR fw_bld; - UCHAR fw_var; - UCHAR ASIC_version; - UCHAR assoc_id[2]; - UCHAR tib_length; - UCHAR last_rsl; - int beacon_rxed; - struct beacon_rx last_bcn; - iw_stats wstats; /* Wireless specific stats */ -#ifdef WIRELESS_SPY - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; -#endif /* WIRELESS_SPY */ - -} ray_dev_t; -/*****************************************************************************/ - -#endif /* _RAY_CS_H_ */ diff --git a/drivers/net/wireless/legacy/rayctl.h b/drivers/net/wireless/legacy/rayctl.h deleted file mode 100644 index 1f3bde8ac7..0000000000 --- a/drivers/net/wireless/legacy/rayctl.h +++ /dev/null @@ -1,734 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _RAYCTL_H_ -#define _RAYCTL_H_ - -typedef unsigned char UCHAR; - -/****** IEEE 802.11 constants ************************************************/ -#define ADDRLEN 6 -/* Frame control 1 bit fields */ -#define PROTOCOL_VER 0x00 -#define DATA_TYPE 0x08 -#define ASSOC_REQ_TYPE 0x00 -#define ASSOC_RESP_TYPE 0x10 -#define REASSOC_REQ_TYPE 0x20 -#define REASSOC_RESP_TYPE 0x30 -#define NULL_MSG_TYPE 0x48 -#define BEACON_TYPE 0x80 -#define DISASSOC_TYPE 0xA0 -#define PSPOLL_TYPE 0xA4 -#define AUTHENTIC_TYPE 0xB0 -#define DEAUTHENTIC_TYPE 0xC0 -/* Frame control 2 bit fields */ -#define FC2_TO_DS 0x01 -#define FC2_FROM_DS 0x02 -#define FC2_MORE_FRAG 0x04 -#define FC2_RETRY 0x08 -#define FC2_PSM 0x10 -#define FC2_MORE_DATA 0x20 -#define FC2_WEP 0x40 -#define FC2_ORDER 0x80 -/*****************************************************************************/ -/* 802.11 element ID's and lengths */ -#define C_BP_CAPABILITY_ESS 0x01 -#define C_BP_CAPABILITY_IBSS 0x02 -#define C_BP_CAPABILITY_CF_POLLABLE 0x04 -#define C_BP_CAPABILITY_CF_POLL_REQUEST 0x08 -#define C_BP_CAPABILITY_PRIVACY 0x10 - -#define C_ESSID_ELEMENT_ID 0 -#define C_ESSID_ELEMENT_MAX_LENGTH 32 - -#define C_SUPPORTED_RATES_ELEMENT_ID 1 -#define C_SUPPORTED_RATES_ELEMENT_LENGTH 2 - -#define C_FH_PARAM_SET_ELEMENT_ID 2 -#define C_FH_PARAM_SET_ELEMENT_LNGTH 5 - -#define C_CF_PARAM_SET_ELEMENT_ID 4 -#define C_CF_PARAM_SET_ELEMENT_LNGTH 6 - -#define C_TIM_ELEMENT_ID 5 -#define C_TIM_BITMAP_LENGTH 251 -#define C_TIM_BMCAST_BIT 0x01 - -#define C_IBSS_ELEMENT_ID 6 -#define C_IBSS_ELEMENT_LENGTH 2 - -#define C_JAPAN_CALL_SIGN_ELEMENT_ID 51 -#define C_JAPAN_CALL_SIGN_ELEMENT_LNGTH 12 - -#define C_DISASSOC_REASON_CODE_LEN 2 -#define C_DISASSOC_REASON_CODE_DEFAULT 8 - -#define C_CRC_LEN 4 -#define C_NUM_SUPPORTED_RATES 8 -/****** IEEE 802.11 mac header for type data packets *************************/ -struct mac_header { - UCHAR frame_ctl_1; - UCHAR frame_ctl_2; - UCHAR duration_lsb; - UCHAR duration_msb; - UCHAR addr_1[ADDRLEN]; - UCHAR addr_2[ADDRLEN]; - UCHAR addr_3[ADDRLEN]; - UCHAR seq_frag_num[2]; -/* UCHAR addr_4[ADDRLEN]; *//* only present for AP to AP (TO DS and FROM DS */ -}; -/****** IEEE 802.11 frame element structures *********************************/ -struct essid_element -{ - UCHAR id; - UCHAR length; - UCHAR text[C_ESSID_ELEMENT_MAX_LENGTH]; -}; -struct rates_element -{ - UCHAR id; - UCHAR length; - UCHAR value[8]; -}; -struct freq_hop_element -{ - UCHAR id; - UCHAR length; - UCHAR dwell_time[2]; - UCHAR hop_set; - UCHAR hop_pattern; - UCHAR hop_index; -}; -struct tim_element -{ - UCHAR id; - UCHAR length; - UCHAR dtim_count; - UCHAR dtim_period; - UCHAR bitmap_control; - UCHAR tim[C_TIM_BITMAP_LENGTH]; -}; -struct ibss_element -{ - UCHAR id; - UCHAR length; - UCHAR atim_window[2]; -}; -struct japan_call_sign_element -{ - UCHAR id; - UCHAR length; - UCHAR call_sign[12]; -}; -/****** Beacon message structures ********************************************/ -/* .elements is a large lump of max size because elements are variable size */ -struct infra_beacon -{ - UCHAR timestamp[8]; - UCHAR beacon_intvl[2]; - UCHAR capability[2]; - UCHAR elements[sizeof(struct essid_element) - + sizeof(struct rates_element) - + sizeof(struct freq_hop_element) - + sizeof(struct japan_call_sign_element) - + sizeof(struct tim_element)]; -}; -struct adhoc_beacon -{ - UCHAR timestamp[8]; - UCHAR beacon_intvl[2]; - UCHAR capability[2]; - UCHAR elements[sizeof(struct essid_element) - + sizeof(struct rates_element) - + sizeof(struct freq_hop_element) - + sizeof(struct japan_call_sign_element) - + sizeof(struct ibss_element)]; -}; -/*****************************************************************************/ -/*****************************************************************************/ -/* #define C_MAC_HDR_2_WEP 0x40 */ -/* TX/RX CCS constants */ -#define TX_HEADER_LENGTH 0x1C -#define RX_MAC_HEADER_LENGTH 0x18 -#define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6) -#define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) -#define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) -#define TX_DEAUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 2) -#define TX_DEAUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) -#define TX_DEAUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) -#define FCS_LEN 4 - -#define ADHOC 0 -#define INFRA 1 - -#define TYPE_STA 0 -#define TYPE_AP 1 - -#define PASSIVE_SCAN 1 -#define ACTIVE_SCAN 1 - -#define PSM_CAM 0 - -/* Country codes */ -#define USA 1 -#define EUROPE 2 -#define JAPAN 3 -#define KOREA 4 -#define SPAIN 5 -#define FRANCE 6 -#define ISRAEL 7 -#define AUSTRALIA 8 -#define JAPAN_TEST 9 - -/* Hop pattern lengths */ -#define USA_HOP_MOD 79 -#define EUROPE_HOP_MOD 79 -#define JAPAN_HOP_MOD 23 -#define KOREA_HOP_MOD 23 -#define SPAIN_HOP_MOD 27 -#define FRANCE_HOP_MOD 35 -#define ISRAEL_HOP_MOD 35 -#define AUSTRALIA_HOP_MOD 47 -#define JAPAN_TEST_HOP_MOD 23 - -#define ESSID_SIZE 32 -/**********************************************************************/ -/* CIS Register Constants */ -#define CIS_OFFSET 0x0f00 -/* Configuration Option Register (0x0F00) */ -#define COR_OFFSET 0x00 -#define COR_SOFT_RESET 0x80 -#define COR_LEVEL_IRQ 0x40 -#define COR_CONFIG_NUM 0x01 -#define COR_DEFAULT (COR_LEVEL_IRQ | COR_CONFIG_NUM) - -/* Card Configuration and Status Register (0x0F01) */ -#define CCSR_OFFSET 0x01 -#define CCSR_HOST_INTR_PENDING 0x01 -#define CCSR_POWER_DOWN 0x04 - -/* HCS Interrupt Register (0x0F05) */ -#define HCS_INTR_OFFSET 0x05 -/* #define HCS_INTR_OFFSET 0x0A */ -#define HCS_INTR_CLEAR 0x00 - -/* ECF Interrupt Register (0x0F06) */ -#define ECF_INTR_OFFSET 0x06 -/* #define ECF_INTR_OFFSET 0x0C */ -#define ECF_INTR_SET 0x01 - -/* Authorization Register 0 (0x0F08) */ -#define AUTH_0_ON 0x57 - -/* Authorization Register 1 (0x0F09) */ -#define AUTH_1_ON 0x82 - -/* Program Mode Register (0x0F0A) */ -#define PC2PM 0x02 -#define PC2CAL 0x10 -#define PC2MLSE 0x20 - -/* PC Test Mode Register (0x0F0B) */ -#define PC_TEST_MODE 0x08 - -/* Frequency Control Word (0x0F10) */ -/* Range 0x02 - 0xA6 */ - -/* Test Mode Control 1-4 (0x0F14 - 0x0F17) */ - -/**********************************************************************/ - -/* Shared RAM Area */ -#define SCB_BASE 0x0000 -#define STATUS_BASE 0x0100 -#define HOST_TO_ECF_BASE 0x0200 -#define ECF_TO_HOST_BASE 0x0300 -#define CCS_BASE 0x0400 -#define RCS_BASE 0x0800 -#define INFRA_TIM_BASE 0x0C00 -#define SSID_LIST_BASE 0x0D00 -#define TX_BUF_BASE 0x1000 -#define RX_BUF_BASE 0x8000 - -#define NUMBER_OF_CCS 64 -#define NUMBER_OF_RCS 64 -/*#define NUMBER_OF_TX_CCS 14 */ -#define NUMBER_OF_TX_CCS 14 - -#define TX_BUF_SIZE (2048 - sizeof(struct tx_msg)) -#define RX_BUFF_END 0x3FFF -/* Values for buffer_status */ -#define CCS_BUFFER_FREE 0 -#define CCS_BUFFER_BUSY 1 -#define CCS_COMMAND_COMPLETE 2 -#define CCS_COMMAND_FAILED 3 - -/* Values for cmd */ -#define CCS_DOWNLOAD_STARTUP_PARAMS 1 -#define CCS_UPDATE_PARAMS 2 -#define CCS_REPORT_PARAMS 3 -#define CCS_UPDATE_MULTICAST_LIST 4 -#define CCS_UPDATE_POWER_SAVINGS_MODE 5 -#define CCS_START_NETWORK 6 -#define CCS_JOIN_NETWORK 7 -#define CCS_START_ASSOCIATION 8 -#define CCS_TX_REQUEST 9 -#define CCS_TEST_MEMORY 0xa -#define CCS_SHUTDOWN 0xb -#define CCS_DUMP_MEMORY 0xc -#define CCS_START_TIMER 0xe -#define CCS_LAST_CMD CCS_START_TIMER - -/* Values for link field */ -#define CCS_END_LIST 0xff - -/* values for buffer_status field */ -#define RCS_BUFFER_FREE 0 -#define RCS_BUFFER_BUSY 1 -#define RCS_COMPLETE 2 -#define RCS_FAILED 3 -#define RCS_BUFFER_RELEASE 0xFF - -/* values for interrupt_id field */ -#define PROCESS_RX_PACKET 0x80 /* */ -#define REJOIN_NET_COMPLETE 0x81 /* RCS ID: Rejoin Net Complete */ -#define ROAMING_INITIATED 0x82 /* RCS ID: Roaming Initiated */ -#define JAPAN_CALL_SIGN_RXD 0x83 /* RCS ID: New Japan Call Sign */ - -/*****************************************************************************/ -/* Memory types for dump memory command */ -#define C_MEM_PROG 0 -#define C_MEM_XDATA 1 -#define C_MEM_SFR 2 -#define C_MEM_IDATA 3 - -/*** Return values for hw_xmit **********/ -#define XMIT_OK (0) -#define XMIT_MSG_BAD (-1) -#define XMIT_NO_CCS (-2) -#define XMIT_NO_INTR (-3) -#define XMIT_NEED_AUTH (-4) - -/*** Values for card status */ -#define CARD_INSERTED (0) - -#define CARD_AWAITING_PARAM (1) -#define CARD_INIT_ERROR (11) - -#define CARD_DL_PARAM (2) -#define CARD_DL_PARAM_ERROR (12) - -#define CARD_DOING_ACQ (3) - -#define CARD_ACQ_COMPLETE (4) -#define CARD_ACQ_FAILED (14) - -#define CARD_AUTH_COMPLETE (5) -#define CARD_AUTH_REFUSED (15) - -#define CARD_ASSOC_COMPLETE (6) -#define CARD_ASSOC_FAILED (16) - -/*** Values for authentication_state ***********************************/ -#define UNAUTHENTICATED (0) -#define AWAITING_RESPONSE (1) -#define AUTHENTICATED (2) -#define NEED_TO_AUTH (3) - -/*** Values for authentication type ************************************/ -#define OPEN_AUTH_REQUEST (1) -#define OPEN_AUTH_RESPONSE (2) -#define BROADCAST_DEAUTH (0xc0) -/*** Values for timer functions ****************************************/ -#define TODO_NOTHING (0) -#define TODO_VERIFY_DL_START (-1) -#define TODO_START_NET (-2) -#define TODO_JOIN_NET (-3) -#define TODO_AUTHENTICATE_TIMEOUT (-4) -#define TODO_SEND_CCS (-5) -/***********************************************************************/ -/* Parameter passing structure for update/report parameter CCS's */ -struct object_id { - void *object_addr; - unsigned char object_length; -}; - -#define OBJID_network_type 0 -#define OBJID_acting_as_ap_status 1 -#define OBJID_current_ess_id 2 -#define OBJID_scanning_mode 3 -#define OBJID_power_mgt_state 4 -#define OBJID_mac_address 5 -#define OBJID_frag_threshold 6 -#define OBJID_hop_time 7 -#define OBJID_beacon_period 8 -#define OBJID_dtim_period 9 -#define OBJID_retry_max 10 -#define OBJID_ack_timeout 11 -#define OBJID_sifs 12 -#define OBJID_difs 13 -#define OBJID_pifs 14 -#define OBJID_rts_threshold 15 -#define OBJID_scan_dwell_time 16 -#define OBJID_max_scan_dwell_time 17 -#define OBJID_assoc_resp_timeout 18 -#define OBJID_adhoc_scan_cycle_max 19 -#define OBJID_infra_scan_cycle_max 20 -#define OBJID_infra_super_cycle_max 21 -#define OBJID_promiscuous_mode 22 -#define OBJID_unique_word 23 -#define OBJID_slot_time 24 -#define OBJID_roaming_low_snr 25 -#define OBJID_low_snr_count_thresh 26 -#define OBJID_infra_missed_bcn 27 -#define OBJID_adhoc_missed_bcn 28 -#define OBJID_curr_country_code 29 -#define OBJID_hop_pattern 30 -#define OBJID_reserved 31 -#define OBJID_cw_max_msb 32 -#define OBJID_cw_min_msb 33 -#define OBJID_noise_filter_gain 34 -#define OBJID_noise_limit_offset 35 -#define OBJID_det_rssi_thresh_offset 36 -#define OBJID_med_busy_thresh_offset 37 -#define OBJID_det_sync_thresh 38 -#define OBJID_test_mode 39 -#define OBJID_test_min_chan_num 40 -#define OBJID_test_max_chan_num 41 -#define OBJID_allow_bcast_ID_prbrsp 42 -#define OBJID_privacy_must_start 43 -#define OBJID_privacy_can_join 44 -#define OBJID_basic_rate_set 45 - -/**** Configuration/Status/Control Area ***************************/ -/* System Control Block (SCB) Area - * Located at Shared RAM offset 0 - */ -struct scb { - UCHAR ccs_index; - UCHAR rcs_index; -}; - -/****** Status area at Shared RAM offset 0x0100 ******************************/ -struct status { - UCHAR mrx_overflow_for_host; /* 0=ECF may write, 1=host may write*/ - UCHAR mrx_checksum_error_for_host; /* 0=ECF may write, 1=host may write*/ - UCHAR rx_hec_error_for_host; /* 0=ECF may write, 1=host may write*/ - UCHAR reserved1; - short mrx_overflow; /* ECF increments on rx overflow */ - short mrx_checksum_error; /* ECF increments on rx CRC error */ - short rx_hec_error; /* ECF incs on mac header CRC error */ - UCHAR rxnoise; /* Average RSL measurement */ -}; - -/****** Host-to-ECF Data Area at Shared RAM offset 0x200 *********************/ -struct host_to_ecf_area { - -}; - -/****** ECF-to-Host Data Area at Shared RAM offset 0x0300 ********************/ -struct startup_res_518 { - UCHAR startup_word; - UCHAR station_addr[ADDRLEN]; - UCHAR calc_prog_chksum; - UCHAR calc_cis_chksum; - UCHAR ecf_spare[7]; - UCHAR japan_call_sign[12]; -}; - -struct startup_res_6 { - UCHAR startup_word; - UCHAR station_addr[ADDRLEN]; - UCHAR reserved; - UCHAR supp_rates[8]; - UCHAR japan_call_sign[12]; - UCHAR calc_prog_chksum; - UCHAR calc_cis_chksum; - UCHAR firmware_version[3]; - UCHAR asic_version; - UCHAR tib_length; -}; - -struct start_join_net_params { - UCHAR net_type; - UCHAR ssid[ESSID_SIZE]; - UCHAR reserved; - UCHAR privacy_can_join; -}; - -/****** Command Control Structure area at Shared ram offset 0x0400 ***********/ -/* Structures for command specific parameters (ccs.var) */ -struct update_param_cmd { - UCHAR object_id; - UCHAR number_objects; - UCHAR failure_cause; -}; -struct report_param_cmd { - UCHAR object_id; - UCHAR number_objects; - UCHAR failure_cause; - UCHAR length; -}; -struct start_network_cmd { - UCHAR update_param; - UCHAR bssid[ADDRLEN]; - UCHAR net_initiated; - UCHAR net_default_tx_rate; - UCHAR encryption; -}; -struct join_network_cmd { - UCHAR update_param; - UCHAR bssid[ADDRLEN]; - UCHAR net_initiated; - UCHAR net_default_tx_rate; - UCHAR encryption; -}; -struct tx_requested_cmd { - - UCHAR tx_data_ptr[2]; - UCHAR tx_data_length[2]; - UCHAR host_reserved[2]; - UCHAR reserved[3]; - UCHAR tx_rate; - UCHAR pow_sav_mode; - UCHAR retries; - UCHAR antenna; -}; -struct tx_requested_cmd_4 { - - UCHAR tx_data_ptr[2]; - UCHAR tx_data_length[2]; - UCHAR dest_addr[ADDRLEN]; - UCHAR pow_sav_mode; - UCHAR retries; - UCHAR station_id; -}; -struct memory_dump_cmd { - UCHAR memory_type; - UCHAR memory_ptr[2]; - UCHAR length; -}; -struct update_association_cmd { - UCHAR status; - UCHAR aid[2]; -}; -struct start_timer_cmd { - UCHAR duration[2]; -}; - -struct ccs { - UCHAR buffer_status; /* 0 = buffer free, 1 = buffer busy */ - /* 2 = command complete, 3 = failed */ - UCHAR cmd; /* command to ECF */ - UCHAR link; /* link to next CCS, FF=end of list */ - /* command specific parameters */ - union { - char reserved[13]; - struct update_param_cmd update_param; - struct report_param_cmd report_param; - UCHAR nummulticast; - UCHAR mode; - struct start_network_cmd start_network; - struct join_network_cmd join_network; - struct tx_requested_cmd tx_request; - struct memory_dump_cmd memory_dump; - struct update_association_cmd update_assoc; - struct start_timer_cmd start_timer; - } var; -}; - -/*****************************************************************************/ -/* Transmit buffer structures */ -struct tib_structure { - UCHAR ccs_index; - UCHAR psm; - UCHAR pass_fail; - UCHAR retry_count; - UCHAR max_retries; - UCHAR frags_remaining; - UCHAR no_rb; - UCHAR rts_reqd; - UCHAR csma_tx_cntrl_2; - UCHAR sifs_tx_cntrl_2; - UCHAR tx_dma_addr_1[2]; - UCHAR tx_dma_addr_2[2]; - UCHAR var_dur_2mhz[2]; - UCHAR var_dur_1mhz[2]; - UCHAR max_dur_2mhz[2]; - UCHAR max_dur_1mhz[2]; - UCHAR hdr_len; - UCHAR max_frag_len[2]; - UCHAR var_len[2]; - UCHAR phy_hdr_4; - UCHAR mac_hdr_1; - UCHAR mac_hdr_2; - UCHAR sid[2]; -}; - -struct phy_header { - UCHAR sfd[2]; - UCHAR hdr_3; - UCHAR hdr_4; -}; -struct ray_rx_msg { - struct mac_header mac; - UCHAR var[]; -}; - -struct tx_msg { - struct tib_structure tib; - struct phy_header phy; - struct mac_header mac; - UCHAR var[]; -}; - -/****** ECF Receive Control Structure (RCS) Area at Shared RAM offset 0x0800 */ -/* Structures for command specific parameters (rcs.var) */ -struct rx_packet_cmd { - UCHAR rx_data_ptr[2]; - UCHAR rx_data_length[2]; - UCHAR rx_sig_lev; - UCHAR next_frag_rcs_index; - UCHAR totalpacketlength[2]; -}; -struct rejoin_net_cmplt_cmd { - UCHAR reserved; - UCHAR bssid[ADDRLEN]; -}; -struct japan_call_sign_rxd { - UCHAR rxd_call_sign[8]; - UCHAR reserved[5]; -}; - -struct rcs { - UCHAR buffer_status; - UCHAR interrupt_id; - UCHAR link_field; - /* command specific parameters */ - union { - UCHAR reserved[13]; - struct rx_packet_cmd rx_packet; - struct rejoin_net_cmplt_cmd rejoin_net_complete; - struct japan_call_sign_rxd japan_call_sign; - } var; -}; - -/****** Startup parameter structures for both versions of firmware ***********/ -struct b4_startup_params { - UCHAR a_network_type; /* C_ADHOC, C_INFRA */ - UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */ - UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */ - UCHAR a_scanning_mode; /* passive 0, active 1 */ - UCHAR a_power_mgt_state; /* CAM 0, */ - UCHAR a_mac_addr[ADDRLEN]; /* */ - UCHAR a_frag_threshold[2]; /* 512 */ - UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */ - UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */ - UCHAR a_dtim_period; /* in beacons */ - UCHAR a_retry_max; /* */ - UCHAR a_ack_timeout; /* */ - UCHAR a_sifs; /* */ - UCHAR a_difs; /* */ - UCHAR a_pifs; /* */ - UCHAR a_rts_threshold[2]; /* */ - UCHAR a_scan_dwell_time[2]; /* */ - UCHAR a_max_scan_dwell_time[2]; /* */ - UCHAR a_assoc_resp_timeout_thresh; /* */ - UCHAR a_adhoc_scan_cycle_max; /* */ - UCHAR a_infra_scan_cycle_max; /* */ - UCHAR a_infra_super_scan_cycle_max; /* */ - UCHAR a_promiscuous_mode; /* */ - UCHAR a_unique_word[2]; /* */ - UCHAR a_slot_time; /* */ - UCHAR a_roaming_low_snr_thresh; /* */ - UCHAR a_low_snr_count_thresh; /* */ - UCHAR a_infra_missed_bcn_thresh; /* */ - UCHAR a_adhoc_missed_bcn_thresh; /* */ - UCHAR a_curr_country_code; /* C_USA */ - UCHAR a_hop_pattern; /* */ - UCHAR a_hop_pattern_length; /* */ -/* b4 - b5 differences start here */ - UCHAR a_cw_max; /* */ - UCHAR a_cw_min; /* */ - UCHAR a_noise_filter_gain; /* */ - UCHAR a_noise_limit_offset; /* */ - UCHAR a_det_rssi_thresh_offset; /* */ - UCHAR a_med_busy_thresh_offset; /* */ - UCHAR a_det_sync_thresh; /* */ - UCHAR a_test_mode; /* */ - UCHAR a_test_min_chan_num; /* */ - UCHAR a_test_max_chan_num; /* */ - UCHAR a_rx_tx_delay; /* */ - UCHAR a_current_bss_id[ADDRLEN]; /* */ - UCHAR a_hop_set; /* */ -}; -struct b5_startup_params { - UCHAR a_network_type; /* C_ADHOC, C_INFRA */ - UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */ - UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */ - UCHAR a_scanning_mode; /* passive 0, active 1 */ - UCHAR a_power_mgt_state; /* CAM 0, */ - UCHAR a_mac_addr[ADDRLEN]; /* */ - UCHAR a_frag_threshold[2]; /* 512 */ - UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */ - UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */ - UCHAR a_dtim_period; /* in beacons */ - UCHAR a_retry_max; /* 4 */ - UCHAR a_ack_timeout; /* */ - UCHAR a_sifs; /* */ - UCHAR a_difs; /* */ - UCHAR a_pifs; /* */ - UCHAR a_rts_threshold[2]; /* */ - UCHAR a_scan_dwell_time[2]; /* */ - UCHAR a_max_scan_dwell_time[2]; /* */ - UCHAR a_assoc_resp_timeout_thresh; /* */ - UCHAR a_adhoc_scan_cycle_max; /* */ - UCHAR a_infra_scan_cycle_max; /* */ - UCHAR a_infra_super_scan_cycle_max; /* */ - UCHAR a_promiscuous_mode; /* */ - UCHAR a_unique_word[2]; /* */ - UCHAR a_slot_time; /* */ - UCHAR a_roaming_low_snr_thresh; /* */ - UCHAR a_low_snr_count_thresh; /* */ - UCHAR a_infra_missed_bcn_thresh; /* */ - UCHAR a_adhoc_missed_bcn_thresh; /* */ - UCHAR a_curr_country_code; /* C_USA */ - UCHAR a_hop_pattern; /* */ - UCHAR a_hop_pattern_length; /* */ -/* b4 - b5 differences start here */ - UCHAR a_cw_max[2]; /* */ - UCHAR a_cw_min[2]; /* */ - UCHAR a_noise_filter_gain; /* */ - UCHAR a_noise_limit_offset; /* */ - UCHAR a_det_rssi_thresh_offset; /* */ - UCHAR a_med_busy_thresh_offset; /* */ - UCHAR a_det_sync_thresh; /* */ - UCHAR a_test_mode; /* */ - UCHAR a_test_min_chan_num; /* */ - UCHAR a_test_max_chan_num; /* */ - UCHAR a_allow_bcast_SSID_probe_rsp; - UCHAR a_privacy_must_start; - UCHAR a_privacy_can_join; - UCHAR a_basic_rate_set[8]; -}; - -/*****************************************************************************/ -#define RAY_IOCG_PARMS (SIOCDEVPRIVATE) -#define RAY_IOCS_PARMS (SIOCDEVPRIVATE + 1) -#define RAY_DO_CMD (SIOCDEVPRIVATE + 2) - -/****** ethernet <-> 802.11 translation **************************************/ -typedef struct snaphdr_t -{ - UCHAR dsap; - UCHAR ssap; - UCHAR ctrl; - UCHAR org[3]; - UCHAR ethertype[2]; -} snaphdr_t; - -#define BRIDGE_ENCAP 0xf80000 -#define RFC1042_ENCAP 0 -#define SNAP_ID 0x0003aaaa -#define RAY_IPX_TYPE 0x8137 -#define APPLEARP_TYPE 0x80f3 -/*****************************************************************************/ -#endif /* _RAYCTL_H_ */ diff --git a/drivers/net/wireless/legacy/rndis_wlan.c b/drivers/net/wireless/legacy/rndis_wlan.c deleted file mode 100644 index e7fea7ded6..0000000000 --- a/drivers/net/wireless/legacy/rndis_wlan.c +++ /dev/null @@ -1,3760 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Driver for RNDIS based USB wireless devices. - * - * Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net> - * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@iki.fi> - * - * Portions of this file are based on NDISwrapper project, - * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani - * http://ndiswrapper.sourceforge.net/ - */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mutex.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> -#include <linux/ieee80211.h> -#include <linux/if_arp.h> -#include <linux/ctype.h> -#include <linux/spinlock.h> -#include <linux/slab.h> -#include <net/cfg80211.h> -#include <linux/usb/usbnet.h> -#include <linux/usb/rndis_host.h> - - -/* NOTE: All these are settings for Broadcom chipset */ -static char modparam_country[4] = "EU"; -module_param_string(country, modparam_country, 4, 0444); -MODULE_PARM_DESC(country, "Country code (ISO 3166-1 alpha-2), default: EU"); - -static int modparam_frameburst = 1; -module_param_named(frameburst, modparam_frameburst, int, 0444); -MODULE_PARM_DESC(frameburst, "enable frame bursting (default: on)"); - -static int modparam_afterburner = 0; -module_param_named(afterburner, modparam_afterburner, int, 0444); -MODULE_PARM_DESC(afterburner, - "enable afterburner aka '125 High Speed Mode' (default: off)"); - -static int modparam_power_save = 0; -module_param_named(power_save, modparam_power_save, int, 0444); -MODULE_PARM_DESC(power_save, - "set power save mode: 0=off, 1=on, 2=fast (default: off)"); - -static int modparam_power_output = 3; -module_param_named(power_output, modparam_power_output, int, 0444); -MODULE_PARM_DESC(power_output, - "set power output: 0=25%, 1=50%, 2=75%, 3=100% (default: 100%)"); - -static int modparam_roamtrigger = -70; -module_param_named(roamtrigger, modparam_roamtrigger, int, 0444); -MODULE_PARM_DESC(roamtrigger, - "set roaming dBm trigger: -80=optimize for distance, " - "-60=bandwidth (default: -70)"); - -static int modparam_roamdelta = 1; -module_param_named(roamdelta, modparam_roamdelta, int, 0444); -MODULE_PARM_DESC(roamdelta, - "set roaming tendency: 0=aggressive, 1=moderate, " - "2=conservative (default: moderate)"); - -static int modparam_workaround_interval; -module_param_named(workaround_interval, modparam_workaround_interval, - int, 0444); -MODULE_PARM_DESC(workaround_interval, - "set stall workaround interval in msecs (0=disabled) (default: 0)"); - -/* Typical noise/maximum signal level values taken from ndiswrapper iw_ndis.h */ -#define WL_NOISE -96 /* typical noise level in dBm */ -#define WL_SIGMAX -32 /* typical maximum signal level in dBm */ - - -/* Assume that Broadcom 4320 (only chipset at time of writing known to be - * based on wireless rndis) has default txpower of 13dBm. - * This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications. - * 100% : 20 mW ~ 13dBm - * 75% : 15 mW ~ 12dBm - * 50% : 10 mW ~ 10dBm - * 25% : 5 mW ~ 7dBm - */ -#define BCM4320_DEFAULT_TXPOWER_DBM_100 13 -#define BCM4320_DEFAULT_TXPOWER_DBM_75 12 -#define BCM4320_DEFAULT_TXPOWER_DBM_50 10 -#define BCM4320_DEFAULT_TXPOWER_DBM_25 7 - -/* Known device types */ -#define RNDIS_UNKNOWN 0 -#define RNDIS_BCM4320A 1 -#define RNDIS_BCM4320B 2 - - -/* NDIS data structures. Taken from wpa_supplicant driver_ndis.c - * slightly modified for datatype endianess, etc - */ -#define NDIS_802_11_LENGTH_SSID 32 -#define NDIS_802_11_LENGTH_RATES 8 -#define NDIS_802_11_LENGTH_RATES_EX 16 - -enum ndis_80211_net_type { - NDIS_80211_TYPE_FREQ_HOP, - NDIS_80211_TYPE_DIRECT_SEQ, - NDIS_80211_TYPE_OFDM_A, - NDIS_80211_TYPE_OFDM_G -}; - -enum ndis_80211_net_infra { - NDIS_80211_INFRA_ADHOC, - NDIS_80211_INFRA_INFRA, - NDIS_80211_INFRA_AUTO_UNKNOWN -}; - -enum ndis_80211_auth_mode { - NDIS_80211_AUTH_OPEN, - NDIS_80211_AUTH_SHARED, - NDIS_80211_AUTH_AUTO_SWITCH, - NDIS_80211_AUTH_WPA, - NDIS_80211_AUTH_WPA_PSK, - NDIS_80211_AUTH_WPA_NONE, - NDIS_80211_AUTH_WPA2, - NDIS_80211_AUTH_WPA2_PSK -}; - -enum ndis_80211_encr_status { - NDIS_80211_ENCR_WEP_ENABLED, - NDIS_80211_ENCR_DISABLED, - NDIS_80211_ENCR_WEP_KEY_ABSENT, - NDIS_80211_ENCR_NOT_SUPPORTED, - NDIS_80211_ENCR_TKIP_ENABLED, - NDIS_80211_ENCR_TKIP_KEY_ABSENT, - NDIS_80211_ENCR_CCMP_ENABLED, - NDIS_80211_ENCR_CCMP_KEY_ABSENT -}; - -enum ndis_80211_priv_filter { - NDIS_80211_PRIV_ACCEPT_ALL, - NDIS_80211_PRIV_8021X_WEP -}; - -enum ndis_80211_status_type { - NDIS_80211_STATUSTYPE_AUTHENTICATION, - NDIS_80211_STATUSTYPE_MEDIASTREAMMODE, - NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST, - NDIS_80211_STATUSTYPE_RADIOSTATE, -}; - -enum ndis_80211_media_stream_mode { - NDIS_80211_MEDIA_STREAM_OFF, - NDIS_80211_MEDIA_STREAM_ON -}; - -enum ndis_80211_radio_status { - NDIS_80211_RADIO_STATUS_ON, - NDIS_80211_RADIO_STATUS_HARDWARE_OFF, - NDIS_80211_RADIO_STATUS_SOFTWARE_OFF, -}; - -enum ndis_80211_addkey_bits { - NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28), - NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29), - NDIS_80211_ADDKEY_PAIRWISE_KEY = cpu_to_le32(1 << 30), - NDIS_80211_ADDKEY_TRANSMIT_KEY = cpu_to_le32(1 << 31) -}; - -enum ndis_80211_addwep_bits { - NDIS_80211_ADDWEP_PERCLIENT_KEY = cpu_to_le32(1 << 30), - NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31) -}; - -enum ndis_80211_power_mode { - NDIS_80211_POWER_MODE_CAM, - NDIS_80211_POWER_MODE_MAX_PSP, - NDIS_80211_POWER_MODE_FAST_PSP, -}; - -enum ndis_80211_pmkid_cand_list_flag_bits { - NDIS_80211_PMKID_CAND_PREAUTH = cpu_to_le32(1 << 0) -}; - -struct ndis_80211_auth_request { - __le32 length; - u8 bssid[ETH_ALEN]; - u8 padding[2]; - __le32 flags; -} __packed; - -struct ndis_80211_pmkid_candidate { - u8 bssid[ETH_ALEN]; - u8 padding[2]; - __le32 flags; -} __packed; - -struct ndis_80211_pmkid_cand_list { - __le32 version; - __le32 num_candidates; - struct ndis_80211_pmkid_candidate candidate_list[]; -} __packed; - -struct ndis_80211_status_indication { - __le32 status_type; - union { - __le32 media_stream_mode; - __le32 radio_status; - DECLARE_FLEX_ARRAY(struct ndis_80211_auth_request, auth_request); - struct ndis_80211_pmkid_cand_list cand_list; - } u; -} __packed; - -struct ndis_80211_ssid { - __le32 length; - u8 essid[NDIS_802_11_LENGTH_SSID]; -} __packed; - -struct ndis_80211_conf_freq_hop { - __le32 length; - __le32 hop_pattern; - __le32 hop_set; - __le32 dwell_time; -} __packed; - -struct ndis_80211_conf { - __le32 length; - __le32 beacon_period; - __le32 atim_window; - __le32 ds_config; - struct ndis_80211_conf_freq_hop fh_config; -} __packed; - -struct ndis_80211_bssid_ex { - __le32 length; - u8 mac[ETH_ALEN]; - u8 padding[2]; - struct ndis_80211_ssid ssid; - __le32 privacy; - __le32 rssi; - __le32 net_type; - struct ndis_80211_conf config; - __le32 net_infra; - u8 rates[NDIS_802_11_LENGTH_RATES_EX]; - __le32 ie_length; - u8 ies[]; -} __packed; - -struct ndis_80211_bssid_list_ex { - __le32 num_items; - u8 bssid_data[]; -} __packed; - -struct ndis_80211_fixed_ies { - u8 timestamp[8]; - __le16 beacon_interval; - __le16 capabilities; -} __packed; - -struct ndis_80211_wep_key { - __le32 size; - __le32 index; - __le32 length; - u8 material[32]; -} __packed; - -struct ndis_80211_key { - __le32 size; - __le32 index; - __le32 length; - u8 bssid[ETH_ALEN]; - u8 padding[6]; - u8 rsc[8]; - u8 material[32]; -} __packed; - -struct ndis_80211_remove_key { - __le32 size; - __le32 index; - u8 bssid[ETH_ALEN]; - u8 padding[2]; -} __packed; - -struct ndis_config_param { - __le32 name_offs; - __le32 name_length; - __le32 type; - __le32 value_offs; - __le32 value_length; -} __packed; - -struct ndis_80211_assoc_info { - __le32 length; - __le16 req_ies; - struct req_ie { - __le16 capa; - __le16 listen_interval; - u8 cur_ap_address[ETH_ALEN]; - } req_ie; - __le32 req_ie_length; - __le32 offset_req_ies; - __le16 resp_ies; - struct resp_ie { - __le16 capa; - __le16 status_code; - __le16 assoc_id; - } resp_ie; - __le32 resp_ie_length; - __le32 offset_resp_ies; -} __packed; - -struct ndis_80211_capability { - __le32 length; - __le32 version; - __le32 num_pmkids; - __le32 num_auth_encr_pair; -} __packed; - -struct ndis_80211_bssid_info { - u8 bssid[ETH_ALEN]; - u8 pmkid[16]; -} __packed; - -struct ndis_80211_pmkid { - __le32 length; - __le32 bssid_info_count; - struct ndis_80211_bssid_info bssid_info[]; -} __packed; - -/* - * private data - */ -#define CAP_MODE_80211A 1 -#define CAP_MODE_80211B 2 -#define CAP_MODE_80211G 4 -#define CAP_MODE_MASK 7 - -#define WORK_LINK_UP 0 -#define WORK_LINK_DOWN 1 -#define WORK_SET_MULTICAST_LIST 2 - -#define RNDIS_WLAN_ALG_NONE 0 -#define RNDIS_WLAN_ALG_WEP (1<<0) -#define RNDIS_WLAN_ALG_TKIP (1<<1) -#define RNDIS_WLAN_ALG_CCMP (1<<2) - -#define RNDIS_WLAN_NUM_KEYS 4 -#define RNDIS_WLAN_KEY_MGMT_NONE 0 -#define RNDIS_WLAN_KEY_MGMT_802_1X (1<<0) -#define RNDIS_WLAN_KEY_MGMT_PSK (1<<1) - -#define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) - -static const struct ieee80211_channel rndis_channels[] = { - { .center_freq = 2412 }, - { .center_freq = 2417 }, - { .center_freq = 2422 }, - { .center_freq = 2427 }, - { .center_freq = 2432 }, - { .center_freq = 2437 }, - { .center_freq = 2442 }, - { .center_freq = 2447 }, - { .center_freq = 2452 }, - { .center_freq = 2457 }, - { .center_freq = 2462 }, - { .center_freq = 2467 }, - { .center_freq = 2472 }, - { .center_freq = 2484 }, -}; - -static const struct ieee80211_rate rndis_rates[] = { - { .bitrate = 10 }, - { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60 }, - { .bitrate = 90 }, - { .bitrate = 120 }, - { .bitrate = 180 }, - { .bitrate = 240 }, - { .bitrate = 360 }, - { .bitrate = 480 }, - { .bitrate = 540 } -}; - -static const u32 rndis_cipher_suites[] = { - WLAN_CIPHER_SUITE_WEP40, - WLAN_CIPHER_SUITE_WEP104, - WLAN_CIPHER_SUITE_TKIP, - WLAN_CIPHER_SUITE_CCMP, -}; - -struct rndis_wlan_encr_key { - int len; - u32 cipher; - u8 material[32]; - u8 bssid[ETH_ALEN]; - bool pairwise; - bool tx_key; -}; - -/* RNDIS device private data */ -struct rndis_wlan_private { - struct usbnet *usbdev; - - struct wireless_dev wdev; - - struct cfg80211_scan_request *scan_request; - - struct workqueue_struct *workqueue; - struct delayed_work dev_poller_work; - struct delayed_work scan_work; - struct work_struct work; - struct mutex command_lock; - unsigned long work_pending; - int last_qual; - s32 cqm_rssi_thold; - u32 cqm_rssi_hyst; - int last_cqm_event_rssi; - - struct ieee80211_supported_band band; - struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; - struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; - u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; - - int device_type; - int caps; - int multicast_size; - - /* module parameters */ - char param_country[4]; - int param_frameburst; - int param_afterburner; - int param_power_save; - int param_power_output; - int param_roamtrigger; - int param_roamdelta; - u32 param_workaround_interval; - - /* hardware state */ - bool radio_on; - int power_mode; - int infra_mode; - bool connected; - u8 bssid[ETH_ALEN]; - u32 current_command_oid; - - /* encryption stuff */ - u8 encr_tx_key_index; - struct rndis_wlan_encr_key encr_keys[RNDIS_WLAN_NUM_KEYS]; - int wpa_version; - - u8 command_buffer[COMMAND_BUFFER_SIZE]; -}; - -/* - * cfg80211 ops - */ -static int rndis_change_virtual_intf(struct wiphy *wiphy, - struct net_device *dev, - enum nl80211_iftype type, - struct vif_params *params); - -static int rndis_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request); - -static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); - -static int rndis_set_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, - int mbm); -static int rndis_get_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - int *dbm); - -static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme); - -static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code); - -static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params); - -static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); - -static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr, struct key_params *params); - -static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr); - -static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool unicast, - bool multicast); - -static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, - const u8 *mac, struct station_info *sinfo); - -static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, - int idx, u8 *mac, struct station_info *sinfo); - -static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa); - -static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa); - -static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev); - -static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, - bool enabled, int timeout); - -static int rndis_set_cqm_rssi_config(struct wiphy *wiphy, - struct net_device *dev, - s32 rssi_thold, u32 rssi_hyst); - -static const struct cfg80211_ops rndis_config_ops = { - .change_virtual_intf = rndis_change_virtual_intf, - .scan = rndis_scan, - .set_wiphy_params = rndis_set_wiphy_params, - .set_tx_power = rndis_set_tx_power, - .get_tx_power = rndis_get_tx_power, - .connect = rndis_connect, - .disconnect = rndis_disconnect, - .join_ibss = rndis_join_ibss, - .leave_ibss = rndis_leave_ibss, - .add_key = rndis_add_key, - .del_key = rndis_del_key, - .set_default_key = rndis_set_default_key, - .get_station = rndis_get_station, - .dump_station = rndis_dump_station, - .set_pmksa = rndis_set_pmksa, - .del_pmksa = rndis_del_pmksa, - .flush_pmksa = rndis_flush_pmksa, - .set_power_mgmt = rndis_set_power_mgmt, - .set_cqm_rssi_config = rndis_set_cqm_rssi_config, -}; - -static void *rndis_wiphy_privid = &rndis_wiphy_privid; - - -static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) -{ - return (struct rndis_wlan_private *)dev->driver_priv; -} - -static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) -{ - switch (priv->param_power_output) { - default: - case 3: - return BCM4320_DEFAULT_TXPOWER_DBM_100; - case 2: - return BCM4320_DEFAULT_TXPOWER_DBM_75; - case 1: - return BCM4320_DEFAULT_TXPOWER_DBM_50; - case 0: - return BCM4320_DEFAULT_TXPOWER_DBM_25; - } -} - -static bool is_wpa_key(struct rndis_wlan_private *priv, u8 idx) -{ - int cipher = priv->encr_keys[idx].cipher; - - return (cipher == WLAN_CIPHER_SUITE_CCMP || - cipher == WLAN_CIPHER_SUITE_TKIP); -} - -static int rndis_cipher_to_alg(u32 cipher) -{ - switch (cipher) { - default: - return RNDIS_WLAN_ALG_NONE; - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - return RNDIS_WLAN_ALG_WEP; - case WLAN_CIPHER_SUITE_TKIP: - return RNDIS_WLAN_ALG_TKIP; - case WLAN_CIPHER_SUITE_CCMP: - return RNDIS_WLAN_ALG_CCMP; - } -} - -static int rndis_akm_suite_to_key_mgmt(u32 akm_suite) -{ - switch (akm_suite) { - default: - return RNDIS_WLAN_KEY_MGMT_NONE; - case WLAN_AKM_SUITE_8021X: - return RNDIS_WLAN_KEY_MGMT_802_1X; - case WLAN_AKM_SUITE_PSK: - return RNDIS_WLAN_KEY_MGMT_PSK; - } -} - -#ifdef DEBUG -static const char *oid_to_string(u32 oid) -{ - switch (oid) { -#define OID_STR(oid) case oid: return(#oid) - /* from rndis_host.h */ - OID_STR(RNDIS_OID_802_3_PERMANENT_ADDRESS); - OID_STR(RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE); - OID_STR(RNDIS_OID_GEN_CURRENT_PACKET_FILTER); - OID_STR(RNDIS_OID_GEN_PHYSICAL_MEDIUM); - - /* from rndis_wlan.c */ - OID_STR(RNDIS_OID_GEN_LINK_SPEED); - OID_STR(RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER); - - OID_STR(RNDIS_OID_GEN_XMIT_OK); - OID_STR(RNDIS_OID_GEN_RCV_OK); - OID_STR(RNDIS_OID_GEN_XMIT_ERROR); - OID_STR(RNDIS_OID_GEN_RCV_ERROR); - OID_STR(RNDIS_OID_GEN_RCV_NO_BUFFER); - - OID_STR(RNDIS_OID_802_3_CURRENT_ADDRESS); - OID_STR(RNDIS_OID_802_3_MULTICAST_LIST); - OID_STR(RNDIS_OID_802_3_MAXIMUM_LIST_SIZE); - - OID_STR(RNDIS_OID_802_11_BSSID); - OID_STR(RNDIS_OID_802_11_SSID); - OID_STR(RNDIS_OID_802_11_INFRASTRUCTURE_MODE); - OID_STR(RNDIS_OID_802_11_ADD_WEP); - OID_STR(RNDIS_OID_802_11_REMOVE_WEP); - OID_STR(RNDIS_OID_802_11_DISASSOCIATE); - OID_STR(RNDIS_OID_802_11_AUTHENTICATION_MODE); - OID_STR(RNDIS_OID_802_11_PRIVACY_FILTER); - OID_STR(RNDIS_OID_802_11_BSSID_LIST_SCAN); - OID_STR(RNDIS_OID_802_11_ENCRYPTION_STATUS); - OID_STR(RNDIS_OID_802_11_ADD_KEY); - OID_STR(RNDIS_OID_802_11_REMOVE_KEY); - OID_STR(RNDIS_OID_802_11_ASSOCIATION_INFORMATION); - OID_STR(RNDIS_OID_802_11_CAPABILITY); - OID_STR(RNDIS_OID_802_11_PMKID); - OID_STR(RNDIS_OID_802_11_NETWORK_TYPES_SUPPORTED); - OID_STR(RNDIS_OID_802_11_NETWORK_TYPE_IN_USE); - OID_STR(RNDIS_OID_802_11_TX_POWER_LEVEL); - OID_STR(RNDIS_OID_802_11_RSSI); - OID_STR(RNDIS_OID_802_11_RSSI_TRIGGER); - OID_STR(RNDIS_OID_802_11_FRAGMENTATION_THRESHOLD); - OID_STR(RNDIS_OID_802_11_RTS_THRESHOLD); - OID_STR(RNDIS_OID_802_11_SUPPORTED_RATES); - OID_STR(RNDIS_OID_802_11_CONFIGURATION); - OID_STR(RNDIS_OID_802_11_POWER_MODE); - OID_STR(RNDIS_OID_802_11_BSSID_LIST); -#undef OID_STR - } - - return "?"; -} -#else -static const char *oid_to_string(u32 oid) -{ - return "?"; -} -#endif - -/* translate error code */ -static int rndis_error_status(__le32 rndis_status) -{ - int ret = -EINVAL; - switch (le32_to_cpu(rndis_status)) { - case RNDIS_STATUS_SUCCESS: - ret = 0; - break; - case RNDIS_STATUS_FAILURE: - case RNDIS_STATUS_INVALID_DATA: - ret = -EINVAL; - break; - case RNDIS_STATUS_NOT_SUPPORTED: - ret = -EOPNOTSUPP; - break; - case RNDIS_STATUS_ADAPTER_NOT_READY: - case RNDIS_STATUS_ADAPTER_NOT_OPEN: - ret = -EBUSY; - break; - } - return ret; -} - -static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); - union { - void *buf; - struct rndis_msg_hdr *header; - struct rndis_query *get; - struct rndis_query_c *get_c; - } u; - int ret; - size_t buflen, resplen, respoffs, copylen; - - buflen = *len + sizeof(*u.get); - if (buflen < CONTROL_BUFFER_SIZE) - buflen = CONTROL_BUFFER_SIZE; - - if (buflen > COMMAND_BUFFER_SIZE) { - u.buf = kmalloc(buflen, GFP_KERNEL); - if (!u.buf) - return -ENOMEM; - } else { - u.buf = priv->command_buffer; - } - - mutex_lock(&priv->command_lock); - - memset(u.get, 0, sizeof *u.get); - u.get->msg_type = cpu_to_le32(RNDIS_MSG_QUERY); - u.get->msg_len = cpu_to_le32(sizeof *u.get); - u.get->oid = cpu_to_le32(oid); - - priv->current_command_oid = oid; - ret = rndis_command(dev, u.header, buflen); - priv->current_command_oid = 0; - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n", - __func__, oid_to_string(oid), ret, - le32_to_cpu(u.get_c->status)); - - if (ret == 0) { - resplen = le32_to_cpu(u.get_c->len); - respoffs = le32_to_cpu(u.get_c->offset) + 8; - - if (respoffs > buflen) { - /* Device returned data offset outside buffer, error. */ - netdev_dbg(dev->net, - "%s(%s): received invalid data offset: %zu > %zu\n", - __func__, oid_to_string(oid), respoffs, buflen); - - ret = -EINVAL; - goto exit_unlock; - } - - copylen = min(resplen, buflen - respoffs); - - if (copylen > *len) - copylen = *len; - - memcpy(data, u.buf + respoffs, copylen); - - *len = resplen; - - ret = rndis_error_status(u.get_c->status); - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n", - __func__, oid_to_string(oid), - le32_to_cpu(u.get_c->status), ret); - } - -exit_unlock: - mutex_unlock(&priv->command_lock); - - if (u.buf != priv->command_buffer) - kfree(u.buf); - return ret; -} - -static int rndis_set_oid(struct usbnet *dev, u32 oid, const void *data, - int len) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); - union { - void *buf; - struct rndis_msg_hdr *header; - struct rndis_set *set; - struct rndis_set_c *set_c; - } u; - int ret, buflen; - - buflen = len + sizeof(*u.set); - if (buflen < CONTROL_BUFFER_SIZE) - buflen = CONTROL_BUFFER_SIZE; - - if (buflen > COMMAND_BUFFER_SIZE) { - u.buf = kmalloc(buflen, GFP_KERNEL); - if (!u.buf) - return -ENOMEM; - } else { - u.buf = priv->command_buffer; - } - - mutex_lock(&priv->command_lock); - - memset(u.set, 0, sizeof *u.set); - u.set->msg_type = cpu_to_le32(RNDIS_MSG_SET); - u.set->msg_len = cpu_to_le32(sizeof(*u.set) + len); - u.set->oid = cpu_to_le32(oid); - u.set->len = cpu_to_le32(len); - u.set->offset = cpu_to_le32(sizeof(*u.set) - 8); - u.set->handle = cpu_to_le32(0); - memcpy(u.buf + sizeof(*u.set), data, len); - - priv->current_command_oid = oid; - ret = rndis_command(dev, u.header, buflen); - priv->current_command_oid = 0; - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n", - __func__, oid_to_string(oid), ret, - le32_to_cpu(u.set_c->status)); - - if (ret == 0) { - ret = rndis_error_status(u.set_c->status); - - if (ret < 0) - netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n", - __func__, oid_to_string(oid), - le32_to_cpu(u.set_c->status), ret); - } - - mutex_unlock(&priv->command_lock); - - if (u.buf != priv->command_buffer) - kfree(u.buf); - return ret; -} - -static int rndis_reset(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_reset *reset; - int ret; - - mutex_lock(&priv->command_lock); - - reset = (void *)priv->command_buffer; - memset(reset, 0, sizeof(*reset)); - reset->msg_type = cpu_to_le32(RNDIS_MSG_RESET); - reset->msg_len = cpu_to_le32(sizeof(*reset)); - priv->current_command_oid = 0; - ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE); - - mutex_unlock(&priv->command_lock); - - if (ret < 0) - return ret; - return 0; -} - -/* - * Specs say that we can only set config parameters only soon after device - * initialization. - * value_type: 0 = u32, 2 = unicode string - */ -static int rndis_set_config_parameter(struct usbnet *dev, char *param, - int value_type, void *value) -{ - struct ndis_config_param *infobuf; - int value_len, info_len, param_len, ret, i; - __le16 *unibuf; - __le32 *dst_value; - - if (value_type == 0) - value_len = sizeof(__le32); - else if (value_type == 2) - value_len = strlen(value) * sizeof(__le16); - else - return -EINVAL; - - param_len = strlen(param) * sizeof(__le16); - info_len = sizeof(*infobuf) + param_len + value_len; - -#ifdef DEBUG - info_len += 12; -#endif - infobuf = kmalloc(info_len, GFP_KERNEL); - if (!infobuf) - return -ENOMEM; - -#ifdef DEBUG - info_len -= 12; - /* extra 12 bytes are for padding (debug output) */ - memset(infobuf, 0xCC, info_len + 12); -#endif - - if (value_type == 2) - netdev_dbg(dev->net, "setting config parameter: %s, value: %s\n", - param, (u8 *)value); - else - netdev_dbg(dev->net, "setting config parameter: %s, value: %d\n", - param, *(u32 *)value); - - infobuf->name_offs = cpu_to_le32(sizeof(*infobuf)); - infobuf->name_length = cpu_to_le32(param_len); - infobuf->type = cpu_to_le32(value_type); - infobuf->value_offs = cpu_to_le32(sizeof(*infobuf) + param_len); - infobuf->value_length = cpu_to_le32(value_len); - - /* simple string to unicode string conversion */ - unibuf = (void *)infobuf + sizeof(*infobuf); - for (i = 0; i < param_len / sizeof(__le16); i++) - unibuf[i] = cpu_to_le16(param[i]); - - if (value_type == 2) { - unibuf = (void *)infobuf + sizeof(*infobuf) + param_len; - for (i = 0; i < value_len / sizeof(__le16); i++) - unibuf[i] = cpu_to_le16(((u8 *)value)[i]); - } else { - dst_value = (void *)infobuf + sizeof(*infobuf) + param_len; - *dst_value = cpu_to_le32(*(u32 *)value); - } - -#ifdef DEBUG - netdev_dbg(dev->net, "info buffer (len: %d)\n", info_len); - for (i = 0; i < info_len; i += 12) { - u32 *tmp = (u32 *)((u8 *)infobuf + i); - netdev_dbg(dev->net, "%08X:%08X:%08X\n", - cpu_to_be32(tmp[0]), - cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2])); - } -#endif - - ret = rndis_set_oid(dev, RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER, - infobuf, info_len); - if (ret != 0) - netdev_dbg(dev->net, "setting rndis config parameter failed, %d\n", - ret); - - kfree(infobuf); - return ret; -} - -static int rndis_set_config_parameter_str(struct usbnet *dev, - char *param, char *value) -{ - return rndis_set_config_parameter(dev, param, 2, value); -} - -/* - * data conversion functions - */ -static int level_to_qual(int level) -{ - int qual = 100 * (level - WL_NOISE) / (WL_SIGMAX - WL_NOISE); - return qual >= 0 ? (qual <= 100 ? qual : 100) : 0; -} - -/* - * common functions - */ -static int set_infra_mode(struct usbnet *usbdev, int mode); -static void restore_keys(struct usbnet *usbdev); -static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, - bool *matched); - -static int rndis_start_bssid_list_scan(struct usbnet *usbdev) -{ - __le32 tmp; - - /* Note: RNDIS_OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */ - tmp = cpu_to_le32(1); - return rndis_set_oid(usbdev, RNDIS_OID_802_11_BSSID_LIST_SCAN, &tmp, - sizeof(tmp)); -} - -static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret; - - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_SSID, - ssid, sizeof(*ssid)); - if (ret < 0) { - netdev_warn(usbdev->net, "setting SSID failed (%08X)\n", ret); - return ret; - } - if (ret == 0) { - priv->radio_on = true; - netdev_dbg(usbdev->net, "%s(): radio_on = true\n", __func__); - } - - return ret; -} - -static int set_bssid(struct usbnet *usbdev, const u8 *bssid) -{ - int ret; - - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_BSSID, - bssid, ETH_ALEN); - if (ret < 0) { - netdev_warn(usbdev->net, "setting BSSID[%pM] failed (%08X)\n", - bssid, ret); - return ret; - } - - return ret; -} - -static int clear_bssid(struct usbnet *usbdev) -{ - static const u8 broadcast_mac[ETH_ALEN] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - - return set_bssid(usbdev, broadcast_mac); -} - -static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) -{ - int ret, len; - - len = ETH_ALEN; - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_BSSID, - bssid, &len); - - if (ret != 0) - eth_zero_addr(bssid); - - return ret; -} - -static int get_association_info(struct usbnet *usbdev, - struct ndis_80211_assoc_info *info, int len) -{ - return rndis_query_oid(usbdev, - RNDIS_OID_802_11_ASSOCIATION_INFORMATION, - info, &len); -} - -static bool is_associated(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - u8 bssid[ETH_ALEN]; - - if (!priv->radio_on) - return false; - - return (get_bssid(usbdev, bssid) == 0 && !is_zero_ether_addr(bssid)); -} - -static int disassociate(struct usbnet *usbdev, bool reset_ssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_ssid ssid; - int i, ret = 0; - - if (priv->radio_on) { - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_DISASSOCIATE, - NULL, 0); - if (ret == 0) { - priv->radio_on = false; - netdev_dbg(usbdev->net, "%s(): radio_on = false\n", - __func__); - - if (reset_ssid) - msleep(100); - } - } - - /* disassociate causes radio to be turned off; if reset_ssid - * is given, set random ssid to enable radio */ - if (reset_ssid) { - /* Set device to infrastructure mode so we don't get ad-hoc - * 'media connect' indications with the random ssid. - */ - set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - - ssid.length = cpu_to_le32(sizeof(ssid.essid)); - get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2); - ssid.essid[0] = 0x1; - ssid.essid[1] = 0xff; - for (i = 2; i < sizeof(ssid.essid); i++) - ssid.essid[i] = 0x1 + (ssid.essid[i] * 0xfe / 0xff); - ret = set_essid(usbdev, &ssid); - } - return ret; -} - -static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, - enum nl80211_auth_type auth_type, int keymgmt) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tmp; - int auth_mode, ret; - - netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x authalg=0x%x keymgmt=0x%x\n", - __func__, wpa_version, auth_type, keymgmt); - - if (wpa_version & NL80211_WPA_VERSION_2) { - if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) - auth_mode = NDIS_80211_AUTH_WPA2; - else - auth_mode = NDIS_80211_AUTH_WPA2_PSK; - } else if (wpa_version & NL80211_WPA_VERSION_1) { - if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) - auth_mode = NDIS_80211_AUTH_WPA; - else if (keymgmt & RNDIS_WLAN_KEY_MGMT_PSK) - auth_mode = NDIS_80211_AUTH_WPA_PSK; - else - auth_mode = NDIS_80211_AUTH_WPA_NONE; - } else if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) - auth_mode = NDIS_80211_AUTH_SHARED; - else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) - auth_mode = NDIS_80211_AUTH_OPEN; - else if (auth_type == NL80211_AUTHTYPE_AUTOMATIC) - auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; - else - return -ENOTSUPP; - - tmp = cpu_to_le32(auth_mode); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_AUTHENTICATION_MODE, - &tmp, sizeof(tmp)); - if (ret != 0) { - netdev_warn(usbdev->net, "setting auth mode failed (%08X)\n", - ret); - return ret; - } - - priv->wpa_version = wpa_version; - - return 0; -} - -static int set_priv_filter(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tmp; - - netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x\n", - __func__, priv->wpa_version); - - if (priv->wpa_version & NL80211_WPA_VERSION_2 || - priv->wpa_version & NL80211_WPA_VERSION_1) - tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); - else - tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); - - return rndis_set_oid(usbdev, - RNDIS_OID_802_11_PRIVACY_FILTER, &tmp, - sizeof(tmp)); -} - -static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) -{ - __le32 tmp; - int encr_mode, ret; - - netdev_dbg(usbdev->net, "%s(): cipher_pair=0x%x cipher_group=0x%x\n", - __func__, pairwise, groupwise); - - if (pairwise & RNDIS_WLAN_ALG_CCMP) - encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; - else if (pairwise & RNDIS_WLAN_ALG_TKIP) - encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; - else if (pairwise & RNDIS_WLAN_ALG_WEP) - encr_mode = NDIS_80211_ENCR_WEP_ENABLED; - else if (groupwise & RNDIS_WLAN_ALG_CCMP) - encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; - else if (groupwise & RNDIS_WLAN_ALG_TKIP) - encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; - else - encr_mode = NDIS_80211_ENCR_DISABLED; - - tmp = cpu_to_le32(encr_mode); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_ENCRYPTION_STATUS, &tmp, - sizeof(tmp)); - if (ret != 0) { - netdev_warn(usbdev->net, "setting encr mode failed (%08X)\n", - ret); - return ret; - } - - return 0; -} - -static int set_infra_mode(struct usbnet *usbdev, int mode) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tmp; - int ret; - - netdev_dbg(usbdev->net, "%s(): infra_mode=0x%x\n", - __func__, priv->infra_mode); - - tmp = cpu_to_le32(mode); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_INFRASTRUCTURE_MODE, - &tmp, sizeof(tmp)); - if (ret != 0) { - netdev_warn(usbdev->net, "setting infra mode failed (%08X)\n", - ret); - return ret; - } - - /* NDIS drivers clear keys when infrastructure mode is - * changed. But Linux tools assume otherwise. So set the - * keys */ - restore_keys(usbdev); - - priv->infra_mode = mode; - return 0; -} - -static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) -{ - __le32 tmp; - - netdev_dbg(usbdev->net, "%s(): %i\n", __func__, rts_threshold); - - if (rts_threshold == -1 || rts_threshold > 2347) - rts_threshold = 2347; - - tmp = cpu_to_le32(rts_threshold); - return rndis_set_oid(usbdev, - RNDIS_OID_802_11_RTS_THRESHOLD, - &tmp, sizeof(tmp)); -} - -static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) -{ - __le32 tmp; - - netdev_dbg(usbdev->net, "%s(): %i\n", __func__, frag_threshold); - - if (frag_threshold < 256 || frag_threshold > 2346) - frag_threshold = 2346; - - tmp = cpu_to_le32(frag_threshold); - return rndis_set_oid(usbdev, - RNDIS_OID_802_11_FRAGMENTATION_THRESHOLD, - &tmp, sizeof(tmp)); -} - -static void set_default_iw_params(struct usbnet *usbdev) -{ - set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, - RNDIS_WLAN_KEY_MGMT_NONE); - set_priv_filter(usbdev); - set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); -} - -static int deauthenticate(struct usbnet *usbdev) -{ - int ret; - - ret = disassociate(usbdev, true); - set_default_iw_params(usbdev); - return ret; -} - -static int set_channel(struct usbnet *usbdev, int channel) -{ - struct ndis_80211_conf config; - unsigned int dsconfig; - int len, ret; - - netdev_dbg(usbdev->net, "%s(%d)\n", __func__, channel); - - /* this OID is valid only when not associated */ - if (is_associated(usbdev)) - return 0; - - dsconfig = 1000 * - ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); - - len = sizeof(config); - ret = rndis_query_oid(usbdev, - RNDIS_OID_802_11_CONFIGURATION, - &config, &len); - if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): querying configuration failed\n", - __func__); - return ret; - } - - config.ds_config = cpu_to_le32(dsconfig); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_CONFIGURATION, - &config, sizeof(config)); - - netdev_dbg(usbdev->net, "%s(): %d -> %d\n", __func__, channel, ret); - - return ret; -} - -static struct ieee80211_channel *get_current_channel(struct usbnet *usbdev, - u32 *beacon_period) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ieee80211_channel *channel; - struct ndis_80211_conf config; - int len, ret; - - /* Get channel and beacon interval */ - len = sizeof(config); - ret = rndis_query_oid(usbdev, - RNDIS_OID_802_11_CONFIGURATION, - &config, &len); - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_CONFIGURATION -> %d\n", - __func__, ret); - if (ret < 0) - return NULL; - - channel = ieee80211_get_channel(priv->wdev.wiphy, - KHZ_TO_MHZ(le32_to_cpu(config.ds_config))); - if (!channel) - return NULL; - - if (beacon_period) - *beacon_period = le32_to_cpu(config.beacon_period); - return channel; -} - -/* index must be 0 - N, as per NDIS */ -static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, - u8 index) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_wep_key ndis_key; - u32 cipher; - int ret; - - netdev_dbg(usbdev->net, "%s(idx: %d, len: %d)\n", - __func__, index, key_len); - - if (index >= RNDIS_WLAN_NUM_KEYS) - return -EINVAL; - - if (key_len == 5) - cipher = WLAN_CIPHER_SUITE_WEP40; - else if (key_len == 13) - cipher = WLAN_CIPHER_SUITE_WEP104; - else - return -EINVAL; - - memset(&ndis_key, 0, sizeof(ndis_key)); - - ndis_key.size = cpu_to_le32(sizeof(ndis_key)); - ndis_key.length = cpu_to_le32(key_len); - ndis_key.index = cpu_to_le32(index); - memcpy(&ndis_key.material, key, key_len); - - if (index == priv->encr_tx_key_index) { - ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; - ret = set_encr_mode(usbdev, RNDIS_WLAN_ALG_WEP, - RNDIS_WLAN_ALG_NONE); - if (ret) - netdev_warn(usbdev->net, "encryption couldn't be enabled (%08X)\n", - ret); - } - - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_ADD_WEP, &ndis_key, - sizeof(ndis_key)); - if (ret != 0) { - netdev_warn(usbdev->net, "adding encryption key %d failed (%08X)\n", - index + 1, ret); - return ret; - } - - priv->encr_keys[index].len = key_len; - priv->encr_keys[index].cipher = cipher; - memcpy(&priv->encr_keys[index].material, key, key_len); - eth_broadcast_addr(priv->encr_keys[index].bssid); - - return 0; -} - -static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, - u8 index, const u8 *addr, const u8 *rx_seq, - int seq_len, u32 cipher, __le32 flags) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_key ndis_key; - bool is_addr_ok; - int ret; - - if (index >= RNDIS_WLAN_NUM_KEYS) { - netdev_dbg(usbdev->net, "%s(): index out of range (%i)\n", - __func__, index); - return -EINVAL; - } - if (key_len > sizeof(ndis_key.material) || key_len < 0) { - netdev_dbg(usbdev->net, "%s(): key length out of range (%i)\n", - __func__, key_len); - return -EINVAL; - } - if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) { - if (!rx_seq || seq_len <= 0) { - netdev_dbg(usbdev->net, "%s(): recv seq flag without buffer\n", - __func__); - return -EINVAL; - } - if (rx_seq && seq_len > sizeof(ndis_key.rsc)) { - netdev_dbg(usbdev->net, "%s(): too big recv seq buffer\n", __func__); - return -EINVAL; - } - } - - is_addr_ok = addr && !is_zero_ether_addr(addr) && - !is_broadcast_ether_addr(addr); - if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) { - netdev_dbg(usbdev->net, "%s(): pairwise but bssid invalid (%pM)\n", - __func__, addr); - return -EINVAL; - } - - netdev_dbg(usbdev->net, "%s(%i): flags:%i%i%i\n", - __func__, index, - !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), - !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY), - !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)); - - memset(&ndis_key, 0, sizeof(ndis_key)); - - ndis_key.size = cpu_to_le32(sizeof(ndis_key) - - sizeof(ndis_key.material) + key_len); - ndis_key.length = cpu_to_le32(key_len); - ndis_key.index = cpu_to_le32(index) | flags; - - if (cipher == WLAN_CIPHER_SUITE_TKIP && key_len == 32) { - /* wpa_supplicant gives us the Michael MIC RX/TX keys in - * different order than NDIS spec, so swap the order here. */ - memcpy(ndis_key.material, key, 16); - memcpy(ndis_key.material + 16, key + 24, 8); - memcpy(ndis_key.material + 24, key + 16, 8); - } else - memcpy(ndis_key.material, key, key_len); - - if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) - memcpy(ndis_key.rsc, rx_seq, seq_len); - - if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { - /* pairwise key */ - memcpy(ndis_key.bssid, addr, ETH_ALEN); - } else { - /* group key */ - if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) - eth_broadcast_addr(ndis_key.bssid); - else - get_bssid(usbdev, ndis_key.bssid); - } - - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_ADD_KEY, &ndis_key, - le32_to_cpu(ndis_key.size)); - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_ADD_KEY -> %08X\n", - __func__, ret); - if (ret != 0) - return ret; - - memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); - priv->encr_keys[index].len = key_len; - priv->encr_keys[index].cipher = cipher; - memcpy(&priv->encr_keys[index].material, key, key_len); - if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) - memcpy(&priv->encr_keys[index].bssid, ndis_key.bssid, ETH_ALEN); - else - eth_broadcast_addr(priv->encr_keys[index].bssid); - - if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY) - priv->encr_tx_key_index = index; - - return 0; -} - -static int restore_key(struct usbnet *usbdev, u8 key_idx) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_wlan_encr_key key; - - if (is_wpa_key(priv, key_idx)) - return 0; - - key = priv->encr_keys[key_idx]; - - netdev_dbg(usbdev->net, "%s(): %i:%i\n", __func__, key_idx, key.len); - - if (key.len == 0) - return 0; - - return add_wep_key(usbdev, key.material, key.len, key_idx); -} - -static void restore_keys(struct usbnet *usbdev) -{ - int i; - - for (i = 0; i < 4; i++) - restore_key(usbdev, i); -} - -static void clear_key(struct rndis_wlan_private *priv, u8 idx) -{ - memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx])); -} - -/* remove_key is for both wep and wpa */ -static int remove_key(struct usbnet *usbdev, u8 index, const u8 *bssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_remove_key remove_key; - __le32 keyindex; - bool is_wpa; - int ret; - - if (index >= RNDIS_WLAN_NUM_KEYS) - return -ENOENT; - - if (priv->encr_keys[index].len == 0) - return 0; - - is_wpa = is_wpa_key(priv, index); - - netdev_dbg(usbdev->net, "%s(): %i:%s:%i\n", - __func__, index, is_wpa ? "wpa" : "wep", - priv->encr_keys[index].len); - - clear_key(priv, index); - - if (is_wpa) { - remove_key.size = cpu_to_le32(sizeof(remove_key)); - remove_key.index = cpu_to_le32(index); - if (bssid) { - /* pairwise key */ - if (!is_broadcast_ether_addr(bssid)) - remove_key.index |= - NDIS_80211_ADDKEY_PAIRWISE_KEY; - memcpy(remove_key.bssid, bssid, - sizeof(remove_key.bssid)); - } else - memset(remove_key.bssid, 0xff, - sizeof(remove_key.bssid)); - - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_REMOVE_KEY, - &remove_key, sizeof(remove_key)); - if (ret != 0) - return ret; - } else { - keyindex = cpu_to_le32(index); - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_11_REMOVE_WEP, - &keyindex, sizeof(keyindex)); - if (ret != 0) { - netdev_warn(usbdev->net, - "removing encryption key %d failed (%08X)\n", - index, ret); - return ret; - } - } - - /* if it is transmit key, disable encryption */ - if (index == priv->encr_tx_key_index) - set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); - - return 0; -} - -static void set_multicast_list(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct netdev_hw_addr *ha; - __le32 filter, basefilter; - int ret; - char *mc_addrs = NULL; - int mc_count; - - basefilter = filter = cpu_to_le32(RNDIS_PACKET_TYPE_DIRECTED | - RNDIS_PACKET_TYPE_BROADCAST); - - if (usbdev->net->flags & IFF_PROMISC) { - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_PROMISCUOUS | - RNDIS_PACKET_TYPE_ALL_LOCAL); - } else if (usbdev->net->flags & IFF_ALLMULTI) { - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); - } - - if (filter != basefilter) - goto set_filter; - - /* - * mc_list should be accessed holding the lock, so copy addresses to - * local buffer first. - */ - netif_addr_lock_bh(usbdev->net); - mc_count = netdev_mc_count(usbdev->net); - if (mc_count > priv->multicast_size) { - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); - } else if (mc_count) { - int i = 0; - - mc_addrs = kmalloc_array(mc_count, ETH_ALEN, GFP_ATOMIC); - if (!mc_addrs) { - netif_addr_unlock_bh(usbdev->net); - return; - } - - netdev_for_each_mc_addr(ha, usbdev->net) - memcpy(mc_addrs + i++ * ETH_ALEN, - ha->addr, ETH_ALEN); - } - netif_addr_unlock_bh(usbdev->net); - - if (filter != basefilter) - goto set_filter; - - if (mc_count) { - ret = rndis_set_oid(usbdev, - RNDIS_OID_802_3_MULTICAST_LIST, - mc_addrs, mc_count * ETH_ALEN); - kfree(mc_addrs); - if (ret == 0) - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_MULTICAST); - else - filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); - - netdev_dbg(usbdev->net, "RNDIS_OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n", - mc_count, priv->multicast_size, ret); - } - -set_filter: - ret = rndis_set_oid(usbdev, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, &filter, - sizeof(filter)); - if (ret < 0) { - netdev_warn(usbdev->net, "couldn't set packet filter: %08x\n", - le32_to_cpu(filter)); - } - - netdev_dbg(usbdev->net, "RNDIS_OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d\n", - le32_to_cpu(filter), ret); -} - -#ifdef DEBUG -static void debug_print_pmkids(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - const char *func_str) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int i, len, count, max_pmkids, entry_len; - - max_pmkids = priv->wdev.wiphy->max_num_pmkids; - len = le32_to_cpu(pmkids->length); - count = le32_to_cpu(pmkids->bssid_info_count); - - entry_len = (count > 0) ? (len - sizeof(*pmkids)) / count : -1; - - netdev_dbg(usbdev->net, "%s(): %d PMKIDs (data len: %d, entry len: " - "%d)\n", func_str, count, len, entry_len); - - if (count > max_pmkids) - count = max_pmkids; - - for (i = 0; i < count; i++) { - u32 *tmp = (u32 *)pmkids->bssid_info[i].pmkid; - - netdev_dbg(usbdev->net, "%s(): bssid: %pM, " - "pmkid: %08X:%08X:%08X:%08X\n", - func_str, pmkids->bssid_info[i].bssid, - cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - } -} -#else -static void debug_print_pmkids(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - const char *func_str) -{ - return; -} -#endif - -static struct ndis_80211_pmkid *get_device_pmkids(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_pmkid *pmkids; - int len, ret, max_pmkids; - - max_pmkids = priv->wdev.wiphy->max_num_pmkids; - len = struct_size(pmkids, bssid_info, max_pmkids); - - pmkids = kzalloc(len, GFP_KERNEL); - if (!pmkids) - return ERR_PTR(-ENOMEM); - - pmkids->length = cpu_to_le32(len); - pmkids->bssid_info_count = cpu_to_le32(max_pmkids); - - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_PMKID, - pmkids, &len); - if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_PMKID(%d, %d)" - " -> %d\n", __func__, len, max_pmkids, ret); - - kfree(pmkids); - return ERR_PTR(ret); - } - - if (le32_to_cpu(pmkids->bssid_info_count) > max_pmkids) - pmkids->bssid_info_count = cpu_to_le32(max_pmkids); - - debug_print_pmkids(usbdev, pmkids, __func__); - - return pmkids; -} - -static int set_device_pmkids(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids) -{ - int ret, len, num_pmkids; - - num_pmkids = le32_to_cpu(pmkids->bssid_info_count); - len = struct_size(pmkids, bssid_info, num_pmkids); - pmkids->length = cpu_to_le32(len); - - debug_print_pmkids(usbdev, pmkids, __func__); - - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_PMKID, pmkids, - le32_to_cpu(pmkids->length)); - if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_PMKID(%d, %d) -> %d" - "\n", __func__, len, num_pmkids, ret); - } - - kfree(pmkids); - return ret; -} - -static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - struct cfg80211_pmksa *pmksa, - int max_pmkids) -{ - int i, err; - unsigned int count; - - count = le32_to_cpu(pmkids->bssid_info_count); - - if (count > max_pmkids) - count = max_pmkids; - - for (i = 0; i < count; i++) - if (ether_addr_equal(pmkids->bssid_info[i].bssid, - pmksa->bssid)) - break; - - /* pmkid not found */ - if (i == count) { - netdev_dbg(usbdev->net, "%s(): bssid not found (%pM)\n", - __func__, pmksa->bssid); - err = -ENOENT; - goto error; - } - - for (; i + 1 < count; i++) - pmkids->bssid_info[i] = pmkids->bssid_info[i + 1]; - - count--; - pmkids->length = cpu_to_le32(struct_size(pmkids, bssid_info, count)); - pmkids->bssid_info_count = cpu_to_le32(count); - - return pmkids; -error: - kfree(pmkids); - return ERR_PTR(err); -} - -static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev, - struct ndis_80211_pmkid *pmkids, - struct cfg80211_pmksa *pmksa, - int max_pmkids) -{ - struct ndis_80211_pmkid *new_pmkids; - int i, err, newlen; - unsigned int count; - - count = le32_to_cpu(pmkids->bssid_info_count); - - if (count > max_pmkids) - count = max_pmkids; - - /* update with new pmkid */ - for (i = 0; i < count; i++) { - if (!ether_addr_equal(pmkids->bssid_info[i].bssid, - pmksa->bssid)) - continue; - - memcpy(pmkids->bssid_info[i].pmkid, pmksa->pmkid, - WLAN_PMKID_LEN); - - return pmkids; - } - - /* out of space, return error */ - if (i == max_pmkids) { - netdev_dbg(usbdev->net, "%s(): out of space\n", __func__); - err = -ENOSPC; - goto error; - } - - /* add new pmkid */ - newlen = struct_size(pmkids, bssid_info, count + 1); - - new_pmkids = krealloc(pmkids, newlen, GFP_KERNEL); - if (!new_pmkids) { - err = -ENOMEM; - goto error; - } - pmkids = new_pmkids; - - pmkids->length = cpu_to_le32(newlen); - pmkids->bssid_info_count = cpu_to_le32(count + 1); - - memcpy(pmkids->bssid_info[count].bssid, pmksa->bssid, ETH_ALEN); - memcpy(pmkids->bssid_info[count].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); - - return pmkids; -error: - kfree(pmkids); - return ERR_PTR(err); -} - -/* - * cfg80211 ops - */ -static int rndis_change_virtual_intf(struct wiphy *wiphy, - struct net_device *dev, - enum nl80211_iftype type, - struct vif_params *params) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - int mode; - - switch (type) { - case NL80211_IFTYPE_ADHOC: - mode = NDIS_80211_INFRA_ADHOC; - break; - case NL80211_IFTYPE_STATION: - mode = NDIS_80211_INFRA_INFRA; - break; - default: - return -EINVAL; - } - - priv->wdev.iftype = type; - - return set_infra_mode(usbdev, mode); -} - -static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - int err; - - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { - err = set_frag_threshold(usbdev, wiphy->frag_threshold); - if (err < 0) - return err; - } - - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - err = set_rts_threshold(usbdev, wiphy->rts_threshold); - if (err < 0) - return err; - } - - return 0; -} - -static int rndis_set_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, - int mbm) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "%s(): type:0x%x mbm:%i\n", - __func__, type, mbm); - - if (mbm < 0 || (mbm % 100)) - return -ENOTSUPP; - - /* Device doesn't support changing txpower after initialization, only - * turn off/on radio. Support 'auto' mode and setting same dBm that is - * currently used. - */ - if (type == NL80211_TX_POWER_AUTOMATIC || - MBM_TO_DBM(mbm) == get_bcm4320_power_dbm(priv)) { - if (!priv->radio_on) - disassociate(usbdev, true); /* turn on radio */ - - return 0; - } - - return -ENOTSUPP; -} - -static int rndis_get_tx_power(struct wiphy *wiphy, - struct wireless_dev *wdev, - int *dbm) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - *dbm = get_bcm4320_power_dbm(priv); - - netdev_dbg(usbdev->net, "%s(): dbm:%i\n", __func__, *dbm); - - return 0; -} - -#define SCAN_DELAY_JIFFIES (6 * HZ) -static int rndis_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request) -{ - struct net_device *dev = request->wdev->netdev; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret; - int delay = SCAN_DELAY_JIFFIES; - - netdev_dbg(usbdev->net, "cfg80211.scan\n"); - - /* Get current bssid list from device before new scan, as new scan - * clears internal bssid list. - */ - rndis_check_bssid_list(usbdev, NULL, NULL); - - if (priv->scan_request && priv->scan_request != request) - return -EBUSY; - - priv->scan_request = request; - - ret = rndis_start_bssid_list_scan(usbdev); - if (ret == 0) { - if (priv->device_type == RNDIS_BCM4320A) - delay = HZ; - - /* Wait before retrieving scan results from device */ - queue_delayed_work(priv->workqueue, &priv->scan_work, delay); - } - - return ret; -} - -static bool rndis_bss_info_update(struct usbnet *usbdev, - struct ndis_80211_bssid_ex *bssid) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ieee80211_channel *channel; - struct cfg80211_bss *bss; - s32 signal; - u64 timestamp; - u16 capability; - u16 beacon_interval; - struct ndis_80211_fixed_ies *fixed; - int ie_len, bssid_len; - u8 *ie; - - netdev_dbg(usbdev->net, " found bssid: '%.32s' [%pM], len: %d\n", - bssid->ssid.essid, bssid->mac, le32_to_cpu(bssid->length)); - - /* parse bssid structure */ - bssid_len = le32_to_cpu(bssid->length); - - if (bssid_len < sizeof(struct ndis_80211_bssid_ex) + - sizeof(struct ndis_80211_fixed_ies)) - return false; - - fixed = (struct ndis_80211_fixed_ies *)bssid->ies; - - ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies)); - ie_len = min(bssid_len - (int)sizeof(*bssid), - (int)le32_to_cpu(bssid->ie_length)); - ie_len -= sizeof(struct ndis_80211_fixed_ies); - if (ie_len < 0) - return false; - - /* extract data for cfg80211_inform_bss */ - channel = ieee80211_get_channel(priv->wdev.wiphy, - KHZ_TO_MHZ(le32_to_cpu(bssid->config.ds_config))); - if (!channel) - return false; - - signal = level_to_qual(le32_to_cpu(bssid->rssi)); - timestamp = le64_to_cpu(*(__le64 *)fixed->timestamp); - capability = le16_to_cpu(fixed->capabilities); - beacon_interval = le16_to_cpu(fixed->beacon_interval); - - bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, - CFG80211_BSS_FTYPE_UNKNOWN, bssid->mac, - timestamp, capability, beacon_interval, - ie, ie_len, signal, GFP_KERNEL); - cfg80211_put_bss(priv->wdev.wiphy, bss); - - return (bss != NULL); -} - -static struct ndis_80211_bssid_ex *next_bssid_list_item( - struct ndis_80211_bssid_ex *bssid, - int *bssid_len, void *buf, int len) -{ - void *buf_end, *bssid_end; - - buf_end = (char *)buf + len; - bssid_end = (char *)bssid + *bssid_len; - - if ((int)(buf_end - bssid_end) < sizeof(bssid->length)) { - *bssid_len = 0; - return NULL; - } else { - bssid = (void *)((char *)bssid + *bssid_len); - *bssid_len = le32_to_cpu(bssid->length); - return bssid; - } -} - -static bool check_bssid_list_item(struct ndis_80211_bssid_ex *bssid, - int bssid_len, void *buf, int len) -{ - void *buf_end, *bssid_end; - - if (!bssid || bssid_len <= 0 || bssid_len > len) - return false; - - buf_end = (char *)buf + len; - bssid_end = (char *)bssid + bssid_len; - - return (int)(buf_end - bssid_end) >= 0 && (int)(bssid_end - buf) >= 0; -} - -static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, - bool *matched) -{ - void *buf = NULL; - struct ndis_80211_bssid_list_ex *bssid_list; - struct ndis_80211_bssid_ex *bssid; - int ret = -EINVAL, len, count, bssid_len, real_count, new_len; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - len = CONTROL_BUFFER_SIZE; -resize_buf: - buf = kzalloc(len, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto out; - } - - /* BSSID-list might have got bigger last time we checked, keep - * resizing until it won't get any bigger. - */ - new_len = len; - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_BSSID_LIST, - buf, &new_len); - if (ret != 0 || new_len < sizeof(struct ndis_80211_bssid_list_ex)) - goto out; - - if (new_len > len) { - len = new_len; - kfree(buf); - goto resize_buf; - } - - len = new_len; - - bssid_list = buf; - count = le32_to_cpu(bssid_list->num_items); - real_count = 0; - netdev_dbg(usbdev->net, "%s(): buflen: %d\n", __func__, len); - - bssid_len = 0; - bssid = next_bssid_list_item((void *)bssid_list->bssid_data, - &bssid_len, buf, len); - - /* Device returns incorrect 'num_items'. Workaround by ignoring the - * received 'num_items' and walking through full bssid buffer instead. - */ - while (check_bssid_list_item(bssid, bssid_len, buf, len)) { - if (rndis_bss_info_update(usbdev, bssid) && match_bssid && - matched) { - if (ether_addr_equal(bssid->mac, match_bssid)) - *matched = true; - } - - real_count++; - bssid = next_bssid_list_item(bssid, &bssid_len, buf, len); - } - - netdev_dbg(usbdev->net, "%s(): num_items from device: %d, really found:" - " %d\n", __func__, count, real_count); - -out: - kfree(buf); - return ret; -} - -static void rndis_get_scan_results(struct work_struct *work) -{ - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, scan_work.work); - struct usbnet *usbdev = priv->usbdev; - struct cfg80211_scan_info info = {}; - int ret; - - netdev_dbg(usbdev->net, "get_scan_results\n"); - - if (!priv->scan_request) - return; - - ret = rndis_check_bssid_list(usbdev, NULL, NULL); - - info.aborted = ret < 0; - cfg80211_scan_done(priv->scan_request, &info); - - priv->scan_request = NULL; -} - -static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ieee80211_channel *channel = sme->channel; - struct ndis_80211_ssid ssid; - int pairwise = RNDIS_WLAN_ALG_NONE; - int groupwise = RNDIS_WLAN_ALG_NONE; - int keymgmt = RNDIS_WLAN_KEY_MGMT_NONE; - int length, i, ret, chan = -1; - - if (channel) - chan = ieee80211_frequency_to_channel(channel->center_freq); - - groupwise = rndis_cipher_to_alg(sme->crypto.cipher_group); - for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) - pairwise |= - rndis_cipher_to_alg(sme->crypto.ciphers_pairwise[i]); - - if (sme->crypto.n_ciphers_pairwise > 0 && - pairwise == RNDIS_WLAN_ALG_NONE) { - netdev_err(usbdev->net, "Unsupported pairwise cipher\n"); - return -ENOTSUPP; - } - - for (i = 0; i < sme->crypto.n_akm_suites; i++) - keymgmt |= - rndis_akm_suite_to_key_mgmt(sme->crypto.akm_suites[i]); - - if (sme->crypto.n_akm_suites > 0 && - keymgmt == RNDIS_WLAN_KEY_MGMT_NONE) { - netdev_err(usbdev->net, "Invalid keymgmt\n"); - return -ENOTSUPP; - } - - netdev_dbg(usbdev->net, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:0x%x]:0x%x)\n", - sme->ssid, sme->bssid, chan, - sme->privacy, sme->crypto.wpa_versions, sme->auth_type, - groupwise, pairwise, keymgmt); - - if (is_associated(usbdev)) - disassociate(usbdev, false); - - ret = set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_infra_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - ret = set_auth_mode(usbdev, sme->crypto.wpa_versions, sme->auth_type, - keymgmt); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_auth_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - set_priv_filter(usbdev); - - ret = set_encr_mode(usbdev, pairwise, groupwise); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_encr_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - if (channel) { - ret = set_channel(usbdev, chan); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_channel failed, %d\n", - ret); - goto err_turn_radio_on; - } - } - - if (sme->key && ((groupwise | pairwise) & RNDIS_WLAN_ALG_WEP)) { - priv->encr_tx_key_index = sme->key_idx; - ret = add_wep_key(usbdev, sme->key, sme->key_len, sme->key_idx); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: add_wep_key failed, %d (%d, %d)\n", - ret, sme->key_len, sme->key_idx); - goto err_turn_radio_on; - } - } - - if (sme->bssid && !is_zero_ether_addr(sme->bssid) && - !is_broadcast_ether_addr(sme->bssid)) { - ret = set_bssid(usbdev, sme->bssid); - if (ret < 0) { - netdev_dbg(usbdev->net, "connect: set_bssid failed, %d\n", - ret); - goto err_turn_radio_on; - } - } else - clear_bssid(usbdev); - - length = sme->ssid_len; - if (length > NDIS_802_11_LENGTH_SSID) - length = NDIS_802_11_LENGTH_SSID; - - memset(&ssid, 0, sizeof(ssid)); - ssid.length = cpu_to_le32(length); - memcpy(ssid.essid, sme->ssid, length); - - /* Pause and purge rx queue, so we don't pass packets before - * 'media connect'-indication. - */ - usbnet_pause_rx(usbdev); - usbnet_purge_paused_rxq(usbdev); - - ret = set_essid(usbdev, &ssid); - if (ret < 0) - netdev_dbg(usbdev->net, "connect: set_essid failed, %d\n", ret); - return ret; - -err_turn_radio_on: - disassociate(usbdev, true); - - return ret; -} - -static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "cfg80211.disconnect(%d)\n", reason_code); - - priv->connected = false; - eth_zero_addr(priv->bssid); - - return deauthenticate(usbdev); -} - -static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ieee80211_channel *channel = params->chandef.chan; - struct ndis_80211_ssid ssid; - enum nl80211_auth_type auth_type; - int ret, alg, length, chan = -1; - - if (channel) - chan = ieee80211_frequency_to_channel(channel->center_freq); - - /* TODO: How to handle ad-hoc encryption? - * connect() has *key, join_ibss() doesn't. RNDIS requires key to be - * pre-shared for encryption (open/shared/wpa), is key set before - * join_ibss? Which auth_type to use (not in params)? What about WPA? - */ - if (params->privacy) { - auth_type = NL80211_AUTHTYPE_SHARED_KEY; - alg = RNDIS_WLAN_ALG_WEP; - } else { - auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; - alg = RNDIS_WLAN_ALG_NONE; - } - - netdev_dbg(usbdev->net, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)\n", - params->ssid, params->bssid, chan, params->privacy); - - if (is_associated(usbdev)) - disassociate(usbdev, false); - - ret = set_infra_mode(usbdev, NDIS_80211_INFRA_ADHOC); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_infra_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - ret = set_auth_mode(usbdev, 0, auth_type, RNDIS_WLAN_KEY_MGMT_NONE); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_auth_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - set_priv_filter(usbdev); - - ret = set_encr_mode(usbdev, alg, RNDIS_WLAN_ALG_NONE); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_encr_mode failed, %d\n", - ret); - goto err_turn_radio_on; - } - - if (channel) { - ret = set_channel(usbdev, chan); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_channel failed, %d\n", - ret); - goto err_turn_radio_on; - } - } - - if (params->bssid && !is_zero_ether_addr(params->bssid) && - !is_broadcast_ether_addr(params->bssid)) { - ret = set_bssid(usbdev, params->bssid); - if (ret < 0) { - netdev_dbg(usbdev->net, "join_ibss: set_bssid failed, %d\n", - ret); - goto err_turn_radio_on; - } - } else - clear_bssid(usbdev); - - length = params->ssid_len; - if (length > NDIS_802_11_LENGTH_SSID) - length = NDIS_802_11_LENGTH_SSID; - - memset(&ssid, 0, sizeof(ssid)); - ssid.length = cpu_to_le32(length); - memcpy(ssid.essid, params->ssid, length); - - /* Don't need to pause rx queue for ad-hoc. */ - usbnet_purge_paused_rxq(usbdev); - usbnet_resume_rx(usbdev); - - ret = set_essid(usbdev, &ssid); - if (ret < 0) - netdev_dbg(usbdev->net, "join_ibss: set_essid failed, %d\n", - ret); - return ret; - -err_turn_radio_on: - disassociate(usbdev, true); - - return ret; -} - -static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "cfg80211.leave_ibss()\n"); - - priv->connected = false; - eth_zero_addr(priv->bssid); - - return deauthenticate(usbdev); -} - -static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr, struct key_params *params) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - __le32 flags; - - netdev_dbg(usbdev->net, "%s(%i, %pM, %08x)\n", - __func__, key_index, mac_addr, params->cipher); - - switch (params->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - return add_wep_key(usbdev, params->key, params->key_len, - key_index); - case WLAN_CIPHER_SUITE_TKIP: - case WLAN_CIPHER_SUITE_CCMP: - flags = 0; - - if (params->seq && params->seq_len > 0) - flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; - if (mac_addr) - flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY | - NDIS_80211_ADDKEY_TRANSMIT_KEY; - - return add_wpa_key(usbdev, params->key, params->key_len, - key_index, mac_addr, params->seq, - params->seq_len, params->cipher, flags); - default: - netdev_dbg(usbdev->net, "%s(): unsupported cipher %08x\n", - __func__, params->cipher); - return -ENOTSUPP; - } -} - -static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - netdev_dbg(usbdev->net, "%s(%i, %pM)\n", __func__, key_index, mac_addr); - - return remove_key(usbdev, key_index, mac_addr); -} - -static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, - int link_id, u8 key_index, bool unicast, - bool multicast) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct rndis_wlan_encr_key key; - - netdev_dbg(usbdev->net, "%s(%i)\n", __func__, key_index); - - if (key_index >= RNDIS_WLAN_NUM_KEYS) - return -ENOENT; - - priv->encr_tx_key_index = key_index; - - if (is_wpa_key(priv, key_index)) - return 0; - - key = priv->encr_keys[key_index]; - - return add_wep_key(usbdev, key.material, key.len, key_index); -} - -static void rndis_fill_station_info(struct usbnet *usbdev, - struct station_info *sinfo) -{ - __le32 linkspeed, rssi; - int ret, len; - - memset(sinfo, 0, sizeof(*sinfo)); - - len = sizeof(linkspeed); - ret = rndis_query_oid(usbdev, RNDIS_OID_GEN_LINK_SPEED, &linkspeed, &len); - if (ret == 0) { - sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); - } - - len = sizeof(rssi); - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, - &rssi, &len); - if (ret == 0) { - sinfo->signal = level_to_qual(le32_to_cpu(rssi)); - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); - } -} - -static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, - const u8 *mac, struct station_info *sinfo) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - if (!ether_addr_equal(priv->bssid, mac)) - return -ENOENT; - - rndis_fill_station_info(usbdev, sinfo); - - return 0; -} - -static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, - int idx, u8 *mac, struct station_info *sinfo) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - if (idx != 0) - return -ENOENT; - - memcpy(mac, priv->bssid, ETH_ALEN); - - rndis_fill_station_info(usbdev, sinfo); - - return 0; -} - -static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ndis_80211_pmkid *pmkids; - u32 *tmp = (u32 *)pmksa->pmkid; - - netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__, - pmksa->bssid, - cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - - pmkids = get_device_pmkids(usbdev); - if (IS_ERR(pmkids)) { - /* couldn't read PMKID cache from device */ - return PTR_ERR(pmkids); - } - - pmkids = update_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids); - if (IS_ERR(pmkids)) { - /* not found, list full, etc */ - return PTR_ERR(pmkids); - } - - return set_device_pmkids(usbdev, pmkids); -} - -static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_pmksa *pmksa) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ndis_80211_pmkid *pmkids; - u32 *tmp = (u32 *)pmksa->pmkid; - - netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__, - pmksa->bssid, - cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - - pmkids = get_device_pmkids(usbdev); - if (IS_ERR(pmkids)) { - /* Couldn't read PMKID cache from device */ - return PTR_ERR(pmkids); - } - - pmkids = remove_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids); - if (IS_ERR(pmkids)) { - /* not found, etc */ - return PTR_ERR(pmkids); - } - - return set_device_pmkids(usbdev, pmkids); -} - -static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - struct ndis_80211_pmkid pmkid; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - memset(&pmkid, 0, sizeof(pmkid)); - - pmkid.length = cpu_to_le32(sizeof(pmkid)); - pmkid.bssid_info_count = cpu_to_le32(0); - - return rndis_set_oid(usbdev, RNDIS_OID_802_11_PMKID, - &pmkid, sizeof(pmkid)); -} - -static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, - bool enabled, int timeout) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - int power_mode; - __le32 mode; - int ret; - - if (priv->device_type != RNDIS_BCM4320B) - return -ENOTSUPP; - - netdev_dbg(usbdev->net, "%s(): %s, %d\n", __func__, - enabled ? "enabled" : "disabled", - timeout); - - if (enabled) - power_mode = NDIS_80211_POWER_MODE_FAST_PSP; - else - power_mode = NDIS_80211_POWER_MODE_CAM; - - if (power_mode == priv->power_mode) - return 0; - - priv->power_mode = power_mode; - - mode = cpu_to_le32(power_mode); - ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_POWER_MODE, - &mode, sizeof(mode)); - - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_POWER_MODE -> %d\n", - __func__, ret); - - return ret; -} - -static int rndis_set_cqm_rssi_config(struct wiphy *wiphy, - struct net_device *dev, - s32 rssi_thold, u32 rssi_hyst) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - - priv->cqm_rssi_thold = rssi_thold; - priv->cqm_rssi_hyst = rssi_hyst; - priv->last_cqm_event_rssi = 0; - - return 0; -} - -static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, - struct ndis_80211_assoc_info *info) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ieee80211_channel *channel; - struct ndis_80211_ssid ssid; - struct cfg80211_bss *bss; - s32 signal; - u64 timestamp; - u16 capability; - u32 beacon_period = 0; - __le32 rssi; - u8 ie_buf[34]; - int len, ret, ie_len; - - /* Get signal quality, in case of error use rssi=0 and ignore error. */ - len = sizeof(rssi); - rssi = 0; - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, - &rssi, &len); - signal = level_to_qual(le32_to_cpu(rssi)); - - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_RSSI -> %d, " - "rssi:%d, qual: %d\n", __func__, ret, le32_to_cpu(rssi), - level_to_qual(le32_to_cpu(rssi))); - - /* Get AP capabilities */ - if (info) { - capability = le16_to_cpu(info->resp_ie.capa); - } else { - /* Set atleast ESS/IBSS capability */ - capability = (priv->infra_mode == NDIS_80211_INFRA_INFRA) ? - WLAN_CAPABILITY_ESS : WLAN_CAPABILITY_IBSS; - } - - /* Get channel and beacon interval */ - channel = get_current_channel(usbdev, &beacon_period); - if (!channel) { - netdev_warn(usbdev->net, "%s(): could not get channel.\n", - __func__); - return; - } - - /* Get SSID, in case of error, use zero length SSID and ignore error. */ - len = sizeof(ssid); - memset(&ssid, 0, sizeof(ssid)); - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_SSID, - &ssid, &len); - netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_SSID -> %d, len: %d, ssid: " - "'%.32s'\n", __func__, ret, - le32_to_cpu(ssid.length), ssid.essid); - - if (le32_to_cpu(ssid.length) > 32) - ssid.length = cpu_to_le32(32); - - ie_buf[0] = WLAN_EID_SSID; - ie_buf[1] = le32_to_cpu(ssid.length); - memcpy(&ie_buf[2], ssid.essid, le32_to_cpu(ssid.length)); - - ie_len = le32_to_cpu(ssid.length) + 2; - - /* no tsf */ - timestamp = 0; - - netdev_dbg(usbdev->net, "%s(): channel:%d(freq), bssid:[%pM], tsf:%d, " - "capa:%x, beacon int:%d, resp_ie(len:%d, essid:'%.32s'), " - "signal:%d\n", __func__, (channel ? channel->center_freq : -1), - bssid, (u32)timestamp, capability, beacon_period, ie_len, - ssid.essid, signal); - - bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, - CFG80211_BSS_FTYPE_UNKNOWN, bssid, - timestamp, capability, beacon_period, - ie_buf, ie_len, signal, GFP_KERNEL); - cfg80211_put_bss(priv->wdev.wiphy, bss); -} - -/* - * workers, indication handlers, device poller - */ -static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct ndis_80211_assoc_info *info = NULL; - u8 bssid[ETH_ALEN]; - unsigned int resp_ie_len, req_ie_len; - unsigned int offset; - u8 *req_ie, *resp_ie; - int ret; - bool roamed = false; - bool match_bss; - - if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) { - /* received media connect indication while connected, either - * device reassociated with same AP or roamed to new. */ - roamed = true; - } - - req_ie_len = 0; - resp_ie_len = 0; - req_ie = NULL; - resp_ie = NULL; - - if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { - info = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); - if (!info) { - /* No memory? Try resume work later */ - set_bit(WORK_LINK_UP, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); - return; - } - - /* Get association info IEs from device. */ - ret = get_association_info(usbdev, info, CONTROL_BUFFER_SIZE); - if (!ret) { - req_ie_len = le32_to_cpu(info->req_ie_length); - if (req_ie_len > CONTROL_BUFFER_SIZE) - req_ie_len = CONTROL_BUFFER_SIZE; - if (req_ie_len != 0) { - offset = le32_to_cpu(info->offset_req_ies); - - if (offset > CONTROL_BUFFER_SIZE) - offset = CONTROL_BUFFER_SIZE; - - req_ie = (u8 *)info + offset; - - if (offset + req_ie_len > CONTROL_BUFFER_SIZE) - req_ie_len = - CONTROL_BUFFER_SIZE - offset; - } - - resp_ie_len = le32_to_cpu(info->resp_ie_length); - if (resp_ie_len > CONTROL_BUFFER_SIZE) - resp_ie_len = CONTROL_BUFFER_SIZE; - if (resp_ie_len != 0) { - offset = le32_to_cpu(info->offset_resp_ies); - - if (offset > CONTROL_BUFFER_SIZE) - offset = CONTROL_BUFFER_SIZE; - - resp_ie = (u8 *)info + offset; - - if (offset + resp_ie_len > CONTROL_BUFFER_SIZE) - resp_ie_len = - CONTROL_BUFFER_SIZE - offset; - } - } else { - /* Since rndis_wlan_craft_connected_bss() might use info - * later and expects info to contain valid data if - * non-null, free info and set NULL here. - */ - kfree(info); - info = NULL; - } - } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC)) - return; - - ret = get_bssid(usbdev, bssid); - if (ret < 0) - memset(bssid, 0, sizeof(bssid)); - - netdev_dbg(usbdev->net, "link up work: [%pM]%s\n", - bssid, roamed ? " roamed" : ""); - - /* Internal bss list in device should contain at least the currently - * connected bss and we can get it to cfg80211 with - * rndis_check_bssid_list(). - * - * NDIS spec says: "If the device is associated, but the associated - * BSSID is not in its BSSID scan list, then the driver must add an - * entry for the BSSID at the end of the data that it returns in - * response to query of RNDIS_OID_802_11_BSSID_LIST." - * - * NOTE: Seems to be true for BCM4320b variant, but not BCM4320a. - */ - match_bss = false; - rndis_check_bssid_list(usbdev, bssid, &match_bss); - - if (!is_zero_ether_addr(bssid) && !match_bss) { - /* Couldn't get bss from device, we need to manually craft bss - * for cfg80211. - */ - rndis_wlan_craft_connected_bss(usbdev, bssid, info); - } - - if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { - if (!roamed) { - cfg80211_connect_result(usbdev->net, bssid, req_ie, - req_ie_len, resp_ie, - resp_ie_len, 0, GFP_KERNEL); - } else { - struct cfg80211_roam_info roam_info = { - .links[0].channel = - get_current_channel(usbdev, NULL), - .links[0].bssid = bssid, - .req_ie = req_ie, - .req_ie_len = req_ie_len, - .resp_ie = resp_ie, - .resp_ie_len = resp_ie_len, - }; - - cfg80211_roamed(usbdev->net, &roam_info, GFP_KERNEL); - } - } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) - cfg80211_ibss_joined(usbdev->net, bssid, - get_current_channel(usbdev, NULL), - GFP_KERNEL); - - kfree(info); - - priv->connected = true; - memcpy(priv->bssid, bssid, ETH_ALEN); - - usbnet_resume_rx(usbdev); - netif_carrier_on(usbdev->net); -} - -static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - if (priv->connected) { - priv->connected = false; - eth_zero_addr(priv->bssid); - - deauthenticate(usbdev); - - cfg80211_disconnected(usbdev->net, 0, NULL, 0, true, GFP_KERNEL); - } - - netif_carrier_off(usbdev->net); -} - -static void rndis_wlan_worker(struct work_struct *work) -{ - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, work); - struct usbnet *usbdev = priv->usbdev; - - if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) - rndis_wlan_do_link_up_work(usbdev); - - if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) - rndis_wlan_do_link_down_work(usbdev); - - if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) - set_multicast_list(usbdev); -} - -static void rndis_wlan_set_multicast_list(struct net_device *dev) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) - return; - - set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); -} - -static void rndis_wlan_auth_indication(struct usbnet *usbdev, - struct ndis_80211_status_indication *indication, - int len) -{ - u8 *buf; - const char *type; - int flags, buflen, key_id; - bool pairwise_error, group_error; - struct ndis_80211_auth_request *auth_req; - enum nl80211_key_type key_type; - - /* must have at least one array entry */ - if (len < offsetof(struct ndis_80211_status_indication, u) + - sizeof(struct ndis_80211_auth_request)) { - netdev_info(usbdev->net, "authentication indication: too short message (%i)\n", - len); - return; - } - - buf = (void *)&indication->u.auth_request[0]; - buflen = len - offsetof(struct ndis_80211_status_indication, u); - - while (buflen >= sizeof(*auth_req)) { - auth_req = (void *)buf; - if (buflen < le32_to_cpu(auth_req->length)) - return; - type = "unknown"; - flags = le32_to_cpu(auth_req->flags); - pairwise_error = false; - group_error = false; - - if (flags & 0x1) - type = "reauth request"; - if (flags & 0x2) - type = "key update request"; - if (flags & 0x6) { - pairwise_error = true; - type = "pairwise_error"; - } - if (flags & 0xe) { - group_error = true; - type = "group_error"; - } - - netdev_info(usbdev->net, "authentication indication: %s (0x%08x)\n", - type, le32_to_cpu(auth_req->flags)); - - if (pairwise_error) { - key_type = NL80211_KEYTYPE_PAIRWISE; - key_id = -1; - - cfg80211_michael_mic_failure(usbdev->net, - auth_req->bssid, - key_type, key_id, NULL, - GFP_KERNEL); - } - - if (group_error) { - key_type = NL80211_KEYTYPE_GROUP; - key_id = -1; - - cfg80211_michael_mic_failure(usbdev->net, - auth_req->bssid, - key_type, key_id, NULL, - GFP_KERNEL); - } - - buflen -= le32_to_cpu(auth_req->length); - buf += le32_to_cpu(auth_req->length); - } -} - -static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, - struct ndis_80211_status_indication *indication, - int len) -{ - struct ndis_80211_pmkid_cand_list *cand_list; - int list_len, expected_len, i; - - if (len < offsetof(struct ndis_80211_status_indication, u) + - sizeof(struct ndis_80211_pmkid_cand_list)) { - netdev_info(usbdev->net, "pmkid candidate list indication: too short message (%i)\n", - len); - return; - } - - list_len = le32_to_cpu(indication->u.cand_list.num_candidates) * - sizeof(struct ndis_80211_pmkid_candidate); - expected_len = sizeof(struct ndis_80211_pmkid_cand_list) + list_len + - offsetof(struct ndis_80211_status_indication, u); - - if (len < expected_len) { - netdev_info(usbdev->net, "pmkid candidate list indication: list larger than buffer (%i < %i)\n", - len, expected_len); - return; - } - - cand_list = &indication->u.cand_list; - - netdev_info(usbdev->net, "pmkid candidate list indication: version %i, candidates %i\n", - le32_to_cpu(cand_list->version), - le32_to_cpu(cand_list->num_candidates)); - - if (le32_to_cpu(cand_list->version) != 1) - return; - - for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) { - struct ndis_80211_pmkid_candidate *cand = - &cand_list->candidate_list[i]; - bool preauth = !!(cand->flags & NDIS_80211_PMKID_CAND_PREAUTH); - - netdev_dbg(usbdev->net, "cand[%i]: flags: 0x%08x, preauth: %d, bssid: %pM\n", - i, le32_to_cpu(cand->flags), preauth, cand->bssid); - - cfg80211_pmksa_candidate_notify(usbdev->net, i, cand->bssid, - preauth, GFP_ATOMIC); - } -} - -static void rndis_wlan_media_specific_indication(struct usbnet *usbdev, - struct rndis_indicate *msg, int buflen) -{ - struct ndis_80211_status_indication *indication; - unsigned int len, offset; - - offset = offsetof(struct rndis_indicate, status) + - le32_to_cpu(msg->offset); - len = le32_to_cpu(msg->length); - - if (len < 8) { - netdev_info(usbdev->net, "media specific indication, ignore too short message (%i < 8)\n", - len); - return; - } - - if (len > buflen || offset > buflen || offset + len > buflen) { - netdev_info(usbdev->net, "media specific indication, too large to fit to buffer (%i > %i)\n", - offset + len, buflen); - return; - } - - indication = (void *)((u8 *)msg + offset); - - switch (le32_to_cpu(indication->status_type)) { - case NDIS_80211_STATUSTYPE_RADIOSTATE: - netdev_info(usbdev->net, "radio state indication: %i\n", - le32_to_cpu(indication->u.radio_status)); - return; - - case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE: - netdev_info(usbdev->net, "media stream mode indication: %i\n", - le32_to_cpu(indication->u.media_stream_mode)); - return; - - case NDIS_80211_STATUSTYPE_AUTHENTICATION: - rndis_wlan_auth_indication(usbdev, indication, len); - return; - - case NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST: - rndis_wlan_pmkid_cand_list_indication(usbdev, indication, len); - return; - - default: - netdev_info(usbdev->net, "media specific indication: unknown status type 0x%08x\n", - le32_to_cpu(indication->status_type)); - } -} - -static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_indicate *msg = ind; - - switch (le32_to_cpu(msg->status)) { - case RNDIS_STATUS_MEDIA_CONNECT: - if (priv->current_command_oid == RNDIS_OID_802_11_ADD_KEY) { - /* RNDIS_OID_802_11_ADD_KEY causes sometimes extra - * "media connect" indications which confuses driver - * and userspace to think that device is - * roaming/reassociating when it isn't. - */ - netdev_dbg(usbdev->net, "ignored RNDIS_OID_802_11_ADD_KEY triggered 'media connect'\n"); - return; - } - - usbnet_pause_rx(usbdev); - - netdev_info(usbdev->net, "media connect\n"); - - /* queue work to avoid recursive calls into rndis_command */ - set_bit(WORK_LINK_UP, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); - break; - - case RNDIS_STATUS_MEDIA_DISCONNECT: - netdev_info(usbdev->net, "media disconnect\n"); - - /* queue work to avoid recursive calls into rndis_command */ - set_bit(WORK_LINK_DOWN, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); - break; - - case RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION: - rndis_wlan_media_specific_indication(usbdev, msg, buflen); - break; - - default: - netdev_info(usbdev->net, "indication: 0x%08x\n", - le32_to_cpu(msg->status)); - break; - } -} - -static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy) -{ - struct { - __le32 num_items; - __le32 items[8]; - } networks_supported; - struct ndis_80211_capability caps; - int len, retval, i, n; - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - /* determine supported modes */ - len = sizeof(networks_supported); - retval = rndis_query_oid(usbdev, - RNDIS_OID_802_11_NETWORK_TYPES_SUPPORTED, - &networks_supported, &len); - if (!retval) { - n = le32_to_cpu(networks_supported.num_items); - if (n > 8) - n = 8; - for (i = 0; i < n; i++) { - switch (le32_to_cpu(networks_supported.items[i])) { - case NDIS_80211_TYPE_FREQ_HOP: - case NDIS_80211_TYPE_DIRECT_SEQ: - priv->caps |= CAP_MODE_80211B; - break; - case NDIS_80211_TYPE_OFDM_A: - priv->caps |= CAP_MODE_80211A; - break; - case NDIS_80211_TYPE_OFDM_G: - priv->caps |= CAP_MODE_80211G; - break; - } - } - } - - /* get device 802.11 capabilities, number of PMKIDs */ - len = sizeof(caps); - retval = rndis_query_oid(usbdev, - RNDIS_OID_802_11_CAPABILITY, - &caps, &len); - if (!retval) { - netdev_dbg(usbdev->net, "RNDIS_OID_802_11_CAPABILITY -> len %d, " - "ver %d, pmkids %d, auth-encr-pairs %d\n", - le32_to_cpu(caps.length), - le32_to_cpu(caps.version), - le32_to_cpu(caps.num_pmkids), - le32_to_cpu(caps.num_auth_encr_pair)); - wiphy->max_num_pmkids = le32_to_cpu(caps.num_pmkids); - } else - wiphy->max_num_pmkids = 0; - - return retval; -} - -static void rndis_do_cqm(struct usbnet *usbdev, s32 rssi) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - enum nl80211_cqm_rssi_threshold_event event; - int thold, hyst, last_event; - - if (priv->cqm_rssi_thold >= 0 || rssi >= 0) - return; - if (priv->infra_mode != NDIS_80211_INFRA_INFRA) - return; - - last_event = priv->last_cqm_event_rssi; - thold = priv->cqm_rssi_thold; - hyst = priv->cqm_rssi_hyst; - - if (rssi < thold && (last_event == 0 || rssi < last_event - hyst)) - event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; - else if (rssi > thold && (last_event == 0 || rssi > last_event + hyst)) - event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; - else - return; - - priv->last_cqm_event_rssi = rssi; - cfg80211_cqm_rssi_notify(usbdev->net, event, rssi, GFP_KERNEL); -} - -#define DEVICE_POLLER_JIFFIES (HZ) -static void rndis_device_poller(struct work_struct *work) -{ - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, - dev_poller_work.work); - struct usbnet *usbdev = priv->usbdev; - __le32 rssi, tmp; - int len, ret, j; - int update_jiffies = DEVICE_POLLER_JIFFIES; - void *buf; - - /* Only check/do workaround when connected. Calling is_associated() - * also polls device with rndis_command() and catches for media link - * indications. - */ - if (!is_associated(usbdev)) { - /* Workaround bad scanning in BCM4320a devices with active - * background scanning when not associated. - */ - if (priv->device_type == RNDIS_BCM4320A && priv->radio_on && - !priv->scan_request) { - /* Get previous scan results */ - rndis_check_bssid_list(usbdev, NULL, NULL); - - /* Initiate new scan */ - rndis_start_bssid_list_scan(usbdev); - } - - goto end; - } - - len = sizeof(rssi); - ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, - &rssi, &len); - if (ret == 0) { - priv->last_qual = level_to_qual(le32_to_cpu(rssi)); - rndis_do_cqm(usbdev, le32_to_cpu(rssi)); - } - - netdev_dbg(usbdev->net, "dev-poller: RNDIS_OID_802_11_RSSI -> %d, rssi:%d, qual: %d\n", - ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi))); - - /* Workaround transfer stalls on poor quality links. - * TODO: find right way to fix these stalls (as stalls do not happen - * with ndiswrapper/windows driver). */ - if (priv->param_workaround_interval > 0 && priv->last_qual <= 25) { - /* Decrease stats worker interval to catch stalls. - * faster. Faster than 400-500ms causes packet loss, - * Slower doesn't catch stalls fast enough. - */ - j = msecs_to_jiffies(priv->param_workaround_interval); - if (j > DEVICE_POLLER_JIFFIES) - j = DEVICE_POLLER_JIFFIES; - else if (j <= 0) - j = 1; - update_jiffies = j; - - /* Send scan OID. Use of both OIDs is required to get device - * working. - */ - tmp = cpu_to_le32(1); - rndis_set_oid(usbdev, - RNDIS_OID_802_11_BSSID_LIST_SCAN, - &tmp, sizeof(tmp)); - - len = CONTROL_BUFFER_SIZE; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - goto end; - - rndis_query_oid(usbdev, - RNDIS_OID_802_11_BSSID_LIST, - buf, &len); - kfree(buf); - } - -end: - if (update_jiffies >= HZ) - update_jiffies = round_jiffies_relative(update_jiffies); - else { - j = round_jiffies_relative(update_jiffies); - if (abs(j - update_jiffies) <= 10) - update_jiffies = j; - } - - queue_delayed_work(priv->workqueue, &priv->dev_poller_work, - update_jiffies); -} - -/* - * driver/device initialization - */ -static void rndis_copy_module_params(struct usbnet *usbdev, int device_type) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - priv->device_type = device_type; - - priv->param_country[0] = modparam_country[0]; - priv->param_country[1] = modparam_country[1]; - priv->param_country[2] = 0; - priv->param_frameburst = modparam_frameburst; - priv->param_afterburner = modparam_afterburner; - priv->param_power_save = modparam_power_save; - priv->param_power_output = modparam_power_output; - priv->param_roamtrigger = modparam_roamtrigger; - priv->param_roamdelta = modparam_roamdelta; - - priv->param_country[0] = toupper(priv->param_country[0]); - priv->param_country[1] = toupper(priv->param_country[1]); - /* doesn't support EU as country code, use FI instead */ - if (!strcmp(priv->param_country, "EU")) - strcpy(priv->param_country, "FI"); - - if (priv->param_power_save < 0) - priv->param_power_save = 0; - else if (priv->param_power_save > 2) - priv->param_power_save = 2; - - if (priv->param_power_output < 0) - priv->param_power_output = 0; - else if (priv->param_power_output > 3) - priv->param_power_output = 3; - - if (priv->param_roamtrigger < -80) - priv->param_roamtrigger = -80; - else if (priv->param_roamtrigger > -60) - priv->param_roamtrigger = -60; - - if (priv->param_roamdelta < 0) - priv->param_roamdelta = 0; - else if (priv->param_roamdelta > 2) - priv->param_roamdelta = 2; - - if (modparam_workaround_interval < 0) - priv->param_workaround_interval = 500; - else - priv->param_workaround_interval = modparam_workaround_interval; -} - -static int unknown_early_init(struct usbnet *usbdev) -{ - /* copy module parameters for unknown so that iwconfig reports txpower - * and workaround parameter is copied to private structure correctly. - */ - rndis_copy_module_params(usbdev, RNDIS_UNKNOWN); - - /* This is unknown device, so do not try set configuration parameters. - */ - - return 0; -} - -static int bcm4320a_early_init(struct usbnet *usbdev) -{ - /* copy module parameters for bcm4320a so that iwconfig reports txpower - * and workaround parameter is copied to private structure correctly. - */ - rndis_copy_module_params(usbdev, RNDIS_BCM4320A); - - /* bcm4320a doesn't handle configuration parameters well. Try - * set any and you get partially zeroed mac and broken device. - */ - - return 0; -} - -static int bcm4320b_early_init(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - char buf[8]; - - rndis_copy_module_params(usbdev, RNDIS_BCM4320B); - - /* Early initialization settings, setting these won't have effect - * if called after generic_rndis_bind(). - */ - - rndis_set_config_parameter_str(usbdev, "Country", priv->param_country); - rndis_set_config_parameter_str(usbdev, "FrameBursting", - priv->param_frameburst ? "1" : "0"); - rndis_set_config_parameter_str(usbdev, "Afterburner", - priv->param_afterburner ? "1" : "0"); - sprintf(buf, "%d", priv->param_power_save); - rndis_set_config_parameter_str(usbdev, "PowerSaveMode", buf); - sprintf(buf, "%d", priv->param_power_output); - rndis_set_config_parameter_str(usbdev, "PwrOut", buf); - sprintf(buf, "%d", priv->param_roamtrigger); - rndis_set_config_parameter_str(usbdev, "RoamTrigger", buf); - sprintf(buf, "%d", priv->param_roamdelta); - rndis_set_config_parameter_str(usbdev, "RoamDelta", buf); - - return 0; -} - -/* same as rndis_netdev_ops but with local multicast handler */ -static const struct net_device_ops rndis_wlan_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_get_stats64 = dev_get_tstats64, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = rndis_wlan_set_multicast_list, -}; - -static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) -{ - struct wiphy *wiphy; - struct rndis_wlan_private *priv; - int retval, len; - __le32 tmp; - - /* allocate wiphy and rndis private data - * NOTE: We only support a single virtual interface, so wiphy - * and wireless_dev are somewhat synonymous for this device. - */ - wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wlan_private)); - if (!wiphy) - return -ENOMEM; - - priv = wiphy_priv(wiphy); - usbdev->net->ieee80211_ptr = &priv->wdev; - priv->wdev.wiphy = wiphy; - priv->wdev.iftype = NL80211_IFTYPE_STATION; - - /* These have to be initialized before calling generic_rndis_bind(). - * Otherwise we'll be in big trouble in rndis_wlan_early_init(). - */ - usbdev->driver_priv = priv; - priv->usbdev = usbdev; - - mutex_init(&priv->command_lock); - - /* because rndis_command() sleeps we need to use workqueue */ - priv->workqueue = create_singlethread_workqueue("rndis_wlan"); - if (!priv->workqueue) { - wiphy_free(wiphy); - return -ENOMEM; - } - INIT_WORK(&priv->work, rndis_wlan_worker); - INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); - INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); - - /* try bind rndis_host */ - retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS); - if (retval < 0) - goto fail; - - /* generic_rndis_bind set packet filter to multicast_all+ - * promisc mode which doesn't work well for our devices (device - * picks up rssi to closest station instead of to access point). - * - * rndis_host wants to avoid all OID as much as possible - * so do promisc/multicast handling in rndis_wlan. - */ - usbdev->net->netdev_ops = &rndis_wlan_netdev_ops; - - tmp = cpu_to_le32(RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST); - retval = rndis_set_oid(usbdev, - RNDIS_OID_GEN_CURRENT_PACKET_FILTER, - &tmp, sizeof(tmp)); - - len = sizeof(tmp); - retval = rndis_query_oid(usbdev, - RNDIS_OID_802_3_MAXIMUM_LIST_SIZE, - &tmp, &len); - priv->multicast_size = le32_to_cpu(tmp); - if (retval < 0 || priv->multicast_size < 0) - priv->multicast_size = 0; - if (priv->multicast_size > 0) - usbdev->net->flags |= IFF_MULTICAST; - else - usbdev->net->flags &= ~IFF_MULTICAST; - - /* fill-out wiphy structure and register w/ cfg80211 */ - memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN); - wiphy->privid = rndis_wiphy_privid; - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) - | BIT(NL80211_IFTYPE_ADHOC); - wiphy->max_scan_ssids = 1; - - /* TODO: fill-out band/encr information based on priv->caps */ - rndis_wlan_get_caps(usbdev, wiphy); - - memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); - memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); - priv->band.channels = priv->channels; - priv->band.n_channels = ARRAY_SIZE(rndis_channels); - priv->band.bitrates = priv->rates; - priv->band.n_bitrates = ARRAY_SIZE(rndis_rates); - wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; - wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; - - memcpy(priv->cipher_suites, rndis_cipher_suites, - sizeof(rndis_cipher_suites)); - wiphy->cipher_suites = priv->cipher_suites; - wiphy->n_cipher_suites = ARRAY_SIZE(rndis_cipher_suites); - - set_wiphy_dev(wiphy, &usbdev->udev->dev); - - if (wiphy_register(wiphy)) { - retval = -ENODEV; - goto fail; - } - - set_default_iw_params(usbdev); - - priv->power_mode = -1; - - /* set default rts/frag */ - rndis_set_wiphy_params(wiphy, - WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD); - - /* turn radio off on init */ - priv->radio_on = false; - disassociate(usbdev, false); - netif_carrier_off(usbdev->net); - - return 0; - -fail: - cancel_delayed_work_sync(&priv->dev_poller_work); - cancel_delayed_work_sync(&priv->scan_work); - cancel_work_sync(&priv->work); - destroy_workqueue(priv->workqueue); - - wiphy_free(wiphy); - return retval; -} - -static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - /* turn radio off */ - disassociate(usbdev, false); - - cancel_delayed_work_sync(&priv->dev_poller_work); - cancel_delayed_work_sync(&priv->scan_work); - cancel_work_sync(&priv->work); - destroy_workqueue(priv->workqueue); - - rndis_unbind(usbdev, intf); - - wiphy_unregister(priv->wdev.wiphy); - wiphy_free(priv->wdev.wiphy); -} - -static int rndis_wlan_reset(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int retval; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - retval = rndis_reset(usbdev); - if (retval) - netdev_warn(usbdev->net, "rndis_reset failed: %d\n", retval); - - /* rndis_reset cleared multicast list, so restore here. - (set_multicast_list() also turns on current packet filter) */ - set_multicast_list(usbdev); - - queue_delayed_work(priv->workqueue, &priv->dev_poller_work, - round_jiffies_relative(DEVICE_POLLER_JIFFIES)); - - return deauthenticate(usbdev); -} - -static int rndis_wlan_stop(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int retval; - __le32 filter; - - netdev_dbg(usbdev->net, "%s()\n", __func__); - - retval = disassociate(usbdev, false); - - priv->work_pending = 0; - cancel_delayed_work_sync(&priv->dev_poller_work); - cancel_delayed_work_sync(&priv->scan_work); - cancel_work_sync(&priv->work); - flush_workqueue(priv->workqueue); - - if (priv->scan_request) { - struct cfg80211_scan_info info = { - .aborted = true, - }; - - cfg80211_scan_done(priv->scan_request, &info); - priv->scan_request = NULL; - } - - /* Set current packet filter zero to block receiving data packets from - device. */ - filter = 0; - rndis_set_oid(usbdev, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, &filter, - sizeof(filter)); - - return retval; -} - -static const struct driver_info bcm4320b_info = { - .description = "Wireless RNDIS device, BCM4320b based", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | - FLAG_AVOID_UNLINK_URBS, - .bind = rndis_wlan_bind, - .unbind = rndis_wlan_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, - .reset = rndis_wlan_reset, - .stop = rndis_wlan_stop, - .early_init = bcm4320b_early_init, - .indication = rndis_wlan_indication, -}; - -static const struct driver_info bcm4320a_info = { - .description = "Wireless RNDIS device, BCM4320a based", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | - FLAG_AVOID_UNLINK_URBS, - .bind = rndis_wlan_bind, - .unbind = rndis_wlan_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, - .reset = rndis_wlan_reset, - .stop = rndis_wlan_stop, - .early_init = bcm4320a_early_init, - .indication = rndis_wlan_indication, -}; - -static const struct driver_info rndis_wlan_info = { - .description = "Wireless RNDIS device", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | - FLAG_AVOID_UNLINK_URBS, - .bind = rndis_wlan_bind, - .unbind = rndis_wlan_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, - .tx_fixup = rndis_tx_fixup, - .reset = rndis_wlan_reset, - .stop = rndis_wlan_stop, - .early_init = unknown_early_init, - .indication = rndis_wlan_indication, -}; - -/*-------------------------------------------------------------------------*/ - -static const struct usb_device_id products [] = { -#define RNDIS_MASTER_INTERFACE \ - .bInterfaceClass = USB_CLASS_COMM, \ - .bInterfaceSubClass = 2 /* ACM */, \ - .bInterfaceProtocol = 0x0ff - -/* INF driver for these devices have DriverVer >= 4.xx.xx.xx and many custom - * parameters available. Chipset marked as 'BCM4320SKFBG' in NDISwrapper-wiki. - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0411, - .idProduct = 0x00bc, /* Buffalo WLI-U2-KG125S */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0baf, - .idProduct = 0x011b, /* U.S. Robotics USR5421 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x050d, - .idProduct = 0x011b, /* Belkin F5D7051 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x1799, /* Belkin has two vendor ids */ - .idProduct = 0x011b, /* Belkin F5D7051 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x13b1, - .idProduct = 0x0014, /* Linksys WUSB54GSv2 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x13b1, - .idProduct = 0x0026, /* Linksys WUSB54GSC */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0b05, - .idProduct = 0x1717, /* Asus WL169gE */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0a5c, - .idProduct = 0xd11b, /* Eminent EM4045 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x1690, - .idProduct = 0x0715, /* BT Voyager 1055 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320b_info, -}, -/* These devices have DriverVer < 4.xx.xx.xx and do not have any custom - * parameters available, hardware probably contain older firmware version with - * no way of updating. Chipset marked as 'BCM4320????' in NDISwrapper-wiki. - */ -{ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x13b1, - .idProduct = 0x000e, /* Linksys WUSB54GSv1 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320a_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0baf, - .idProduct = 0x0111, /* U.S. Robotics USR5420 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320a_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0411, - .idProduct = 0x004b, /* BUFFALO WLI-USB-G54 */ - RNDIS_MASTER_INTERFACE, - .driver_info = (unsigned long) &bcm4320a_info, -}, -/* Generic Wireless RNDIS devices that we don't have exact - * idVendor/idProduct/chip yet. - */ -{ - /* RNDIS is MSFT's un-official variant of CDC ACM */ - USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_wlan_info, -}, { - /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ - USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_wlan_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver rndis_wlan_driver = { - .name = "rndis_wlan", - .id_table = products, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(rndis_wlan_driver); - -MODULE_AUTHOR("Bjorge Dijkstra"); -MODULE_AUTHOR("Jussi Kivilinna"); -MODULE_DESCRIPTION("Driver for RNDIS based USB Wireless adapters"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/net/wireless/legacy/wl3501.h b/drivers/net/wireless/legacy/wl3501.h deleted file mode 100644 index 91f276dd22..0000000000 --- a/drivers/net/wireless/legacy/wl3501.h +++ /dev/null @@ -1,615 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __WL3501_H__ -#define __WL3501_H__ - -#include <linux/spinlock.h> -#include <linux/ieee80211.h> - -/* define for WLA 2.0 */ -#define WL3501_BLKSZ 256 -/* - * ID for input Signals of DRIVER block - * bit[7-5] is block ID: 000 - * bit[4-0] is signal ID -*/ -enum wl3501_signals { - WL3501_SIG_ALARM, - WL3501_SIG_MD_CONFIRM, - WL3501_SIG_MD_IND, - WL3501_SIG_ASSOC_CONFIRM, - WL3501_SIG_ASSOC_IND, - WL3501_SIG_AUTH_CONFIRM, - WL3501_SIG_AUTH_IND, - WL3501_SIG_DEAUTH_CONFIRM, - WL3501_SIG_DEAUTH_IND, - WL3501_SIG_DISASSOC_CONFIRM, - WL3501_SIG_DISASSOC_IND, - WL3501_SIG_GET_CONFIRM, - WL3501_SIG_JOIN_CONFIRM, - WL3501_SIG_PWR_MGMT_CONFIRM, - WL3501_SIG_REASSOC_CONFIRM, - WL3501_SIG_REASSOC_IND, - WL3501_SIG_SCAN_CONFIRM, - WL3501_SIG_SET_CONFIRM, - WL3501_SIG_START_CONFIRM, - WL3501_SIG_RESYNC_CONFIRM, - WL3501_SIG_SITE_CONFIRM, - WL3501_SIG_SAVE_CONFIRM, - WL3501_SIG_RFTEST_CONFIRM, -/* - * ID for input Signals of MLME block - * bit[7-5] is block ID: 010 - * bit[4-0] is signal ID - */ - WL3501_SIG_ASSOC_REQ = 0x20, - WL3501_SIG_AUTH_REQ, - WL3501_SIG_DEAUTH_REQ, - WL3501_SIG_DISASSOC_REQ, - WL3501_SIG_GET_REQ, - WL3501_SIG_JOIN_REQ, - WL3501_SIG_PWR_MGMT_REQ, - WL3501_SIG_REASSOC_REQ, - WL3501_SIG_SCAN_REQ, - WL3501_SIG_SET_REQ, - WL3501_SIG_START_REQ, - WL3501_SIG_MD_REQ, - WL3501_SIG_RESYNC_REQ, - WL3501_SIG_SITE_REQ, - WL3501_SIG_SAVE_REQ, - WL3501_SIG_RF_TEST_REQ, - WL3501_SIG_MM_CONFIRM = 0x60, - WL3501_SIG_MM_IND, -}; - -enum wl3501_mib_attribs { - WL3501_MIB_ATTR_STATION_ID, - WL3501_MIB_ATTR_AUTH_ALGORITHMS, - WL3501_MIB_ATTR_AUTH_TYPE, - WL3501_MIB_ATTR_MEDIUM_OCCUPANCY_LIMIT, - WL3501_MIB_ATTR_CF_POLLABLE, - WL3501_MIB_ATTR_CFP_PERIOD, - WL3501_MIB_ATTR_CFPMAX_DURATION, - WL3501_MIB_ATTR_AUTH_RESP_TMOUT, - WL3501_MIB_ATTR_RX_DTIMS, - WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, - WL3501_MIB_ATTR_PRIV_INVOKED, - WL3501_MIB_ATTR_WEP_DEFAULT_KEYS, - WL3501_MIB_ATTR_WEP_DEFAULT_KEY_ID, - WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, - WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, - WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, - WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, - WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, - WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, - WL3501_MIB_ATTR_MAC_ADDR, - WL3501_MIB_ATTR_GROUP_ADDRS, - WL3501_MIB_ATTR_RTS_THRESHOLD, - WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, - WL3501_MIB_ATTR_LONG_RETRY_LIMIT, - WL3501_MIB_ATTR_FRAG_THRESHOLD, - WL3501_MIB_ATTR_MAX_TX_MSDU_LIFETIME, - WL3501_MIB_ATTR_MAX_RX_LIFETIME, - WL3501_MIB_ATTR_MANUFACTURER_ID, - WL3501_MIB_ATTR_PRODUCT_ID, - WL3501_MIB_ATTR_TX_FRAG_COUNT, - WL3501_MIB_ATTR_MULTICAST_TX_FRAME_COUNT, - WL3501_MIB_ATTR_FAILED_COUNT, - WL3501_MIB_ATTR_RX_FRAG_COUNT, - WL3501_MIB_ATTR_MULTICAST_RX_COUNT, - WL3501_MIB_ATTR_FCS_ERROR_COUNT, - WL3501_MIB_ATTR_RETRY_COUNT, - WL3501_MIB_ATTR_MULTIPLE_RETRY_COUNT, - WL3501_MIB_ATTR_RTS_SUCCESS_COUNT, - WL3501_MIB_ATTR_RTS_FAILURE_COUNT, - WL3501_MIB_ATTR_ACK_FAILURE_COUNT, - WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, - WL3501_MIB_ATTR_PHY_TYPE, - WL3501_MIB_ATTR_REG_DOMAINS_SUPPORT, - WL3501_MIB_ATTR_CURRENT_REG_DOMAIN, - WL3501_MIB_ATTR_SLOT_TIME, - WL3501_MIB_ATTR_CCA_TIME, - WL3501_MIB_ATTR_RX_TX_TURNAROUND_TIME, - WL3501_MIB_ATTR_TX_PLCP_DELAY, - WL3501_MIB_ATTR_RX_TX_SWITCH_TIME, - WL3501_MIB_ATTR_TX_RAMP_ON_TIME, - WL3501_MIB_ATTR_TX_RF_DELAY, - WL3501_MIB_ATTR_SIFS_TIME, - WL3501_MIB_ATTR_RX_RF_DELAY, - WL3501_MIB_ATTR_RX_PLCP_DELAY, - WL3501_MIB_ATTR_MAC_PROCESSING_DELAY, - WL3501_MIB_ATTR_TX_RAMP_OFF_TIME, - WL3501_MIB_ATTR_PREAMBLE_LEN, - WL3501_MIB_ATTR_PLCP_HEADER_LEN, - WL3501_MIB_ATTR_MPDU_DURATION_FACTOR, - WL3501_MIB_ATTR_AIR_PROPAGATION_TIME, - WL3501_MIB_ATTR_TEMP_TYPE, - WL3501_MIB_ATTR_CW_MIN, - WL3501_MIB_ATTR_CW_MAX, - WL3501_MIB_ATTR_SUPPORT_DATA_RATES_TX, - WL3501_MIB_ATTR_SUPPORT_DATA_RATES_RX, - WL3501_MIB_ATTR_MPDU_MAX_LEN, - WL3501_MIB_ATTR_SUPPORT_TX_ANTENNAS, - WL3501_MIB_ATTR_CURRENT_TX_ANTENNA, - WL3501_MIB_ATTR_SUPPORT_RX_ANTENNAS, - WL3501_MIB_ATTR_DIVERSITY_SUPPORT, - WL3501_MIB_ATTR_DIVERSITY_SELECTION_RS, - WL3501_MIB_ATTR_NR_SUPPORTED_PWR_LEVELS, - WL3501_MIB_ATTR_TX_PWR_LEVEL1, - WL3501_MIB_ATTR_TX_PWR_LEVEL2, - WL3501_MIB_ATTR_TX_PWR_LEVEL3, - WL3501_MIB_ATTR_TX_PWR_LEVEL4, - WL3501_MIB_ATTR_TX_PWR_LEVEL5, - WL3501_MIB_ATTR_TX_PWR_LEVEL6, - WL3501_MIB_ATTR_TX_PWR_LEVEL7, - WL3501_MIB_ATTR_TX_PWR_LEVEL8, - WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, - WL3501_MIB_ATTR_CURRENT_CHAN, - WL3501_MIB_ATTR_CCA_MODE_SUPPORTED, - WL3501_MIB_ATTR_CURRENT_CCA_MODE, - WL3501_MIB_ATTR_ED_THRESHOLD, - WL3501_MIB_ATTR_SINTHESIZER_LOCKED, - WL3501_MIB_ATTR_CURRENT_PWR_STATE, - WL3501_MIB_ATTR_DOZE_TURNON_TIME, - WL3501_MIB_ATTR_RCR33, - WL3501_MIB_ATTR_DEFAULT_CHAN, - WL3501_MIB_ATTR_SSID, - WL3501_MIB_ATTR_PWR_MGMT_ENABLE, - WL3501_MIB_ATTR_NET_CAPABILITY, - WL3501_MIB_ATTR_ROUTING, -}; - -enum wl3501_net_type { - WL3501_NET_TYPE_INFRA, - WL3501_NET_TYPE_ADHOC, - WL3501_NET_TYPE_ANY_BSS, -}; - -enum wl3501_scan_type { - WL3501_SCAN_TYPE_ACTIVE, - WL3501_SCAN_TYPE_PASSIVE, -}; - -enum wl3501_tx_result { - WL3501_TX_RESULT_SUCCESS, - WL3501_TX_RESULT_NO_BSS, - WL3501_TX_RESULT_RETRY_LIMIT, -}; - -enum wl3501_sys_type { - WL3501_SYS_TYPE_OPEN, - WL3501_SYS_TYPE_SHARE_KEY, -}; - -enum wl3501_status { - WL3501_STATUS_SUCCESS, - WL3501_STATUS_INVALID, - WL3501_STATUS_TIMEOUT, - WL3501_STATUS_REFUSED, - WL3501_STATUS_MANY_REQ, - WL3501_STATUS_ALREADY_BSS, -}; - -#define WL3501_MGMT_CAPABILITY_ESS 0x0001 /* see 802.11 p.58 */ -#define WL3501_MGMT_CAPABILITY_IBSS 0x0002 /* - " - */ -#define WL3501_MGMT_CAPABILITY_CF_POLLABLE 0x0004 /* - " - */ -#define WL3501_MGMT_CAPABILITY_CF_POLL_REQUEST 0x0008 /* - " - */ -#define WL3501_MGMT_CAPABILITY_PRIVACY 0x0010 /* - " - */ - -#define IW_REG_DOMAIN_FCC 0x10 /* Channel 1 to 11 USA */ -#define IW_REG_DOMAIN_DOC 0x20 /* Channel 1 to 11 Canada */ -#define IW_REG_DOMAIN_ETSI 0x30 /* Channel 1 to 13 Europe */ -#define IW_REG_DOMAIN_SPAIN 0x31 /* Channel 10 to 11 Spain */ -#define IW_REG_DOMAIN_FRANCE 0x32 /* Channel 10 to 13 France */ -#define IW_REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ -#define IW_REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan */ -#define IW_REG_DOMAIN_ISRAEL 0x50 /* Channel 3 - 9 Israel */ - -#define IW_MGMT_RATE_LABEL_MANDATORY 128 /* MSB */ - -enum iw_mgmt_rate_labels { - IW_MGMT_RATE_LABEL_1MBIT = 2, - IW_MGMT_RATE_LABEL_2MBIT = 4, - IW_MGMT_RATE_LABEL_5_5MBIT = 11, - IW_MGMT_RATE_LABEL_11MBIT = 22, -}; - -enum iw_mgmt_info_element_ids { - IW_MGMT_INFO_ELEMENT_SSID, /* Service Set Identity */ - IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - IW_MGMT_INFO_ELEMENT_FH_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_CS_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_CS_TIM, /* Traffic Information Map */ - IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, - /* 7-15: Reserved, unused */ - IW_MGMT_INFO_ELEMENT_CHALLENGE_TEXT = 16, - /* 17-31 Reserved for challenge text extension */ - /* 32-255 Reserved, unused */ -}; - -struct iw_mgmt_info_element { - u8 id; /* one of enum iw_mgmt_info_element_ids, - but sizeof(enum) > sizeof(u8) :-( */ - u8 len; - u8 data[]; -} __packed; - -struct iw_mgmt_essid_pset { - struct iw_mgmt_info_element el; - u8 essid[IW_ESSID_MAX_SIZE]; -} __packed; - -/* - * According to 802.11 Wireless Networks, the definitive guide - O'Reilly - * Pg 75 - */ -#define IW_DATA_RATE_MAX_LABELS 8 - -struct iw_mgmt_data_rset { - struct iw_mgmt_info_element el; - u8 data_rate_labels[IW_DATA_RATE_MAX_LABELS]; -} __packed; - -struct iw_mgmt_ds_pset { - struct iw_mgmt_info_element el; - u8 chan; -} __packed; - -struct iw_mgmt_cf_pset { - struct iw_mgmt_info_element el; - u8 cfp_count; - u8 cfp_period; - u16 cfp_max_duration; - u16 cfp_dur_remaining; -} __packed; - -struct iw_mgmt_ibss_pset { - struct iw_mgmt_info_element el; - u16 atim_window; -} __packed; - -struct wl3501_tx_hdr { - u16 tx_cnt; - u8 sync[16]; - u16 sfd; - u8 signal; - u8 service; - u16 len; - u16 crc16; - u16 frame_ctrl; - u16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq_ctrl; - u8 addr4[ETH_ALEN]; -}; - -struct wl3501_rx_hdr { - u16 rx_next_blk; - u16 rc_next_frame_blk; - u8 rx_blk_ctrl; - u8 rx_next_frame; - u8 rx_next_frame1; - u8 rssi; - char time[8]; - u8 signal; - u8 service; - u16 len; - u16 crc16; - u16 frame_ctrl; - u16 duration; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq; - u8 addr4[ETH_ALEN]; -}; - -struct wl3501_start_req { - u16 next_blk; - u8 sig_id; - u8 bss_type; - u16 beacon_period; - u16 dtim_period; - u16 probe_delay; - u16 cap_info; - struct iw_mgmt_essid_pset ssid; - struct iw_mgmt_data_rset bss_basic_rset; - struct iw_mgmt_data_rset operational_rset; - struct iw_mgmt_cf_pset cf_pset; - struct iw_mgmt_ds_pset ds_pset; - struct iw_mgmt_ibss_pset ibss_pset; -}; - -struct wl3501_assoc_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 timeout; - u16 cap_info; - u16 listen_interval; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_assoc_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_assoc_ind { - u16 next_blk; - u8 sig_id; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_auth_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 type; - u16 timeout; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_auth_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 type; - u16 status; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_get_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 mib_attrib; -}; - -struct wl3501_get_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 mib_status; - u16 mib_attrib; - u8 mib_value[100]; -}; - -struct wl3501_req { - u16 beacon_period; - u16 dtim_period; - u16 cap_info; - u8 bss_type; - u8 bssid[ETH_ALEN]; - struct iw_mgmt_essid_pset ssid; - struct iw_mgmt_ds_pset ds_pset; - struct iw_mgmt_cf_pset cf_pset; - struct iw_mgmt_ibss_pset ibss_pset; - struct iw_mgmt_data_rset bss_basic_rset; -}; - -struct wl3501_join_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - struct iw_mgmt_data_rset operational_rset; - u16 reserved2; - u16 timeout; - u16 probe_delay; - u8 timestamp[8]; - u8 local_time[8]; - struct wl3501_req req; -}; - -struct wl3501_join_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_pwr_mgmt_req { - u16 next_blk; - u8 sig_id; - u8 pwr_save; - u8 wake_up; - u8 receive_dtims; -}; - -struct wl3501_pwr_mgmt_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_scan_req { - u16 next_blk; - u8 sig_id; - u8 bss_type; - u16 probe_delay; - u16 min_chan_time; - u16 max_chan_time; - u8 chan_list[14]; - u8 bssid[ETH_ALEN]; - struct iw_mgmt_essid_pset ssid; - enum wl3501_scan_type scan_type; -}; - -struct wl3501_scan_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; - char timestamp[8]; - char localtime[8]; - struct wl3501_req req; - u8 rssi; -}; - -struct wl3501_start_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_md_req { - u16 next_blk; - u8 sig_id; - u8 routing; - u16 data; - u16 size; - u8 pri; - u8 service_class; - struct { - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - } addr; -}; - -struct wl3501_md_ind { - u16 next_blk; - u8 sig_id; - u8 routing; - u16 data; - u16 size; - u8 reception; - u8 pri; - u8 service_class; - struct { - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - } addr; -}; - -struct wl3501_md_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 data; - u8 status; - u8 pri; - u8 service_class; -}; - -struct wl3501_resync_req { - u16 next_blk; - u8 sig_id; -}; - -/* Definitions for supporting clone adapters. */ -/* System Interface Registers (SIR space) */ -#define WL3501_NIC_GCR ((u8)0x00) /* SIR0 - General Conf Register */ -#define WL3501_NIC_BSS ((u8)0x01) /* SIR1 - Bank Switching Select Reg */ -#define WL3501_NIC_LMAL ((u8)0x02) /* SIR2 - Local Mem addr Reg [7:0] */ -#define WL3501_NIC_LMAH ((u8)0x03) /* SIR3 - Local Mem addr Reg [14:8] */ -#define WL3501_NIC_IODPA ((u8)0x04) /* SIR4 - I/O Data Port A */ -#define WL3501_NIC_IODPB ((u8)0x05) /* SIR5 - I/O Data Port B */ -#define WL3501_NIC_IODPC ((u8)0x06) /* SIR6 - I/O Data Port C */ -#define WL3501_NIC_IODPD ((u8)0x07) /* SIR7 - I/O Data Port D */ - -/* Bits in GCR */ -#define WL3501_GCR_SWRESET ((u8)0x80) -#define WL3501_GCR_CORESET ((u8)0x40) -#define WL3501_GCR_DISPWDN ((u8)0x20) -#define WL3501_GCR_ECWAIT ((u8)0x10) -#define WL3501_GCR_ECINT ((u8)0x08) -#define WL3501_GCR_INT2EC ((u8)0x04) -#define WL3501_GCR_ENECINT ((u8)0x02) -#define WL3501_GCR_DAM ((u8)0x01) - -/* Bits in BSS (Bank Switching Select Register) */ -#define WL3501_BSS_FPAGE0 ((u8)0x20) /* Flash memory page0 */ -#define WL3501_BSS_FPAGE1 ((u8)0x28) -#define WL3501_BSS_FPAGE2 ((u8)0x30) -#define WL3501_BSS_FPAGE3 ((u8)0x38) -#define WL3501_BSS_SPAGE0 ((u8)0x00) /* SRAM page0 */ -#define WL3501_BSS_SPAGE1 ((u8)0x08) -#define WL3501_BSS_SPAGE2 ((u8)0x10) -#define WL3501_BSS_SPAGE3 ((u8)0x18) - -/* Define Driver Interface */ -/* Refer IEEE 802.11 */ -/* Tx packet header, include PLCP and MPDU */ -/* Tx PLCP Header */ -struct wl3501_80211_tx_plcp_hdr { - u8 sync[16]; - u16 sfd; - u8 signal; - u8 service; - u16 len; - u16 crc16; -} __packed; - -struct wl3501_80211_tx_hdr { - struct wl3501_80211_tx_plcp_hdr pclp_hdr; - struct ieee80211_hdr mac_hdr; -} __packed __aligned(2); - -/* - Reserve the beginning Tx space for descriptor use. - - TxBlockOffset --> *----*----*----*----* \ - (TxFreeDesc) | 0 | 1 | 2 | 3 | \ - | 4 | 5 | 6 | 7 | | - | 8 | 9 | 10 | 11 | TX_DESC * 20 - | 12 | 13 | 14 | 15 | | - | 16 | 17 | 18 | 19 | / - TxBufferBegin --> *----*----*----*----* / - (TxBufferHead) | | - (TxBufferTail) | | - | Send Buffer | - | | - | | - *-------------------* - TxBufferEnd -------------------------/ - -*/ - -struct wl3501_card { - int base_addr; - u8 mac_addr[ETH_ALEN]; - spinlock_t lock; - wait_queue_head_t wait; - struct wl3501_get_confirm sig_get_confirm; - struct wl3501_pwr_mgmt_confirm sig_pwr_mgmt_confirm; - u16 tx_buffer_size; - u16 tx_buffer_head; - u16 tx_buffer_tail; - u16 tx_buffer_cnt; - u16 esbq_req_start; - u16 esbq_req_end; - u16 esbq_req_head; - u16 esbq_req_tail; - u16 esbq_confirm_start; - u16 esbq_confirm_end; - u16 esbq_confirm; - struct iw_mgmt_essid_pset essid; - struct iw_mgmt_essid_pset keep_essid; - u8 bssid[ETH_ALEN]; - int net_type; - char nick[32]; - char card_name[32]; - char firmware_date[32]; - u8 chan; - u8 cap_info; - u16 start_seg; - u16 bss_cnt; - u16 join_sta_bss; - u8 rssi; - u8 adhoc_times; - u8 reg_domain; - u8 version[2]; - struct wl3501_scan_confirm bss_set[20]; - - struct iw_statistics wstats; - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; - struct pcmcia_device *p_dev; -}; -#endif diff --git a/drivers/net/wireless/legacy/wl3501_cs.c b/drivers/net/wireless/legacy/wl3501_cs.c deleted file mode 100644 index c45c4b7cbb..0000000000 --- a/drivers/net/wireless/legacy/wl3501_cs.c +++ /dev/null @@ -1,2036 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * WL3501 Wireless LAN PCMCIA Card Driver for Linux - * Written originally for Linux 2.0.30 by Fox Chen, mhchen@golf.ccl.itri.org.tw - * Ported to 2.2, 2.4 & 2.5 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> - * Wireless extensions in 2.4 by Gustavo Niemeyer <niemeyer@conectiva.com> - * - * References used by Fox Chen while writing the original driver for 2.0.30: - * - * 1. WL24xx packet drivers (tooasm.asm) - * 2. Access Point Firmware Interface Specification for IEEE 802.11 SUTRO - * 3. IEEE 802.11 - * 4. Linux network driver (/usr/src/linux/drivers/net) - * 5. ISA card driver - wl24.c - * 6. Linux PCMCIA skeleton driver - skeleton.c - * 7. Linux PCMCIA 3c589 network driver - 3c589_cs.c - * - * Tested with WL2400 firmware 1.2, Linux 2.0.30, and pcmcia-cs-2.9.12 - * 1. Performance: about 165 Kbytes/sec in TCP/IP with Ad-Hoc mode. - * rsh 192.168.1.3 "dd if=/dev/zero bs=1k count=1000" > /dev/null - * (Specification 2M bits/sec. is about 250 Kbytes/sec., but we must deduct - * ETHER/IP/UDP/TCP header, and acknowledgement overhead) - * - * Tested with Planet AP in 2.4.17, 184 Kbytes/s in UDP in Infrastructure mode, - * 173 Kbytes/s in TCP. - * - * Tested with Planet AP in 2.5.73-bk, 216 Kbytes/s in Infrastructure mode - * with a SMP machine (dual pentium 100), using pktgen, 432 pps (pkt_size = 60) - */ - -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/in.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/fcntl.h> -#include <linux/if_arp.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/wireless.h> -#include <net/cfg80211.h> - -#include <net/iw_handler.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> - -#include <asm/io.h> -#include <linux/uaccess.h> - -#include "wl3501.h" - -#ifndef __i386__ -#define slow_down_io() -#endif - -/* For rough constant delay */ -#define WL3501_NOPLOOP(n) { int x = 0; while (x++ < n) slow_down_io(); } - - - -#define wl3501_outb(a, b) { outb(a, b); slow_down_io(); } -#define wl3501_outb_p(a, b) { outb_p(a, b); slow_down_io(); } -#define wl3501_outsb(a, b, c) { outsb(a, b, c); slow_down_io(); } - -#define WL3501_RELEASE_TIMEOUT (25 * HZ) -#define WL3501_MAX_ADHOC_TRIES 16 - -#define WL3501_RESUME 0 -#define WL3501_SUSPEND 1 - -static int wl3501_config(struct pcmcia_device *link); -static void wl3501_release(struct pcmcia_device *link); - -static const struct { - int reg_domain; - int min, max, deflt; -} iw_channel_table[] = { - { - .reg_domain = IW_REG_DOMAIN_FCC, - .min = 1, - .max = 11, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_DOC, - .min = 1, - .max = 11, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_ETSI, - .min = 1, - .max = 13, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_SPAIN, - .min = 10, - .max = 11, - .deflt = 10, - }, - { - .reg_domain = IW_REG_DOMAIN_FRANCE, - .min = 10, - .max = 13, - .deflt = 10, - }, - { - .reg_domain = IW_REG_DOMAIN_MKK, - .min = 14, - .max = 14, - .deflt = 14, - }, - { - .reg_domain = IW_REG_DOMAIN_MKK1, - .min = 1, - .max = 14, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_ISRAEL, - .min = 3, - .max = 9, - .deflt = 9, - }, -}; - -/** - * iw_valid_channel - validate channel in regulatory domain - * @reg_domain: regulatory domain - * @channel: channel to validate - * - * Returns 0 if invalid in the specified regulatory domain, non-zero if valid. - */ -static int iw_valid_channel(int reg_domain, int channel) -{ - int i, rc = 0; - - for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) - if (reg_domain == iw_channel_table[i].reg_domain) { - rc = channel >= iw_channel_table[i].min && - channel <= iw_channel_table[i].max; - break; - } - return rc; -} - -/** - * iw_default_channel - get default channel for a regulatory domain - * @reg_domain: regulatory domain - * - * Returns the default channel for a regulatory domain - */ -static int iw_default_channel(int reg_domain) -{ - int i, rc = 1; - - for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) - if (reg_domain == iw_channel_table[i].reg_domain) { - rc = iw_channel_table[i].deflt; - break; - } - return rc; -} - -static void iw_set_mgmt_info_element(enum iw_mgmt_info_element_ids id, - struct iw_mgmt_info_element *el, - void *value, int len) -{ - el->id = id; - el->len = len; - memcpy(el->data, value, len); -} - -static void iw_copy_mgmt_info_element(struct iw_mgmt_info_element *to, - struct iw_mgmt_info_element *from) -{ - iw_set_mgmt_info_element(from->id, to, from->data, from->len); -} - -static inline void wl3501_switch_page(struct wl3501_card *this, u8 page) -{ - wl3501_outb(page, this->base_addr + WL3501_NIC_BSS); -} - -/* - * Get Ethernet MAC address. - * - * WARNING: We switch to FPAGE0 and switc back again. - * Making sure there is no other WL function beening called by ISR. - */ -static int wl3501_get_flash_mac_addr(struct wl3501_card *this) -{ - int base_addr = this->base_addr; - - /* get MAC addr */ - wl3501_outb(WL3501_BSS_FPAGE3, base_addr + WL3501_NIC_BSS); /* BSS */ - wl3501_outb(0x00, base_addr + WL3501_NIC_LMAL); /* LMAL */ - wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); /* LMAH */ - - /* wait for reading EEPROM */ - WL3501_NOPLOOP(100); - this->mac_addr[0] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[1] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[2] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[3] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[4] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[5] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->reg_domain = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - wl3501_outb(WL3501_BSS_FPAGE0, base_addr + WL3501_NIC_BSS); - wl3501_outb(0x04, base_addr + WL3501_NIC_LMAL); - wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); - WL3501_NOPLOOP(100); - this->version[0] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->version[1] = inb(base_addr + WL3501_NIC_IODPA); - /* switch to SRAM Page 0 (for safety) */ - wl3501_switch_page(this, WL3501_BSS_SPAGE0); - - /* The MAC addr should be 00:60:... */ - return this->mac_addr[0] == 0x00 && this->mac_addr[1] == 0x60; -} - -/** - * wl3501_set_to_wla - Move 'size' bytes from PC to card - * @this: Card - * @dest: Card addressing space - * @src: PC addressing space - * @size: Bytes to move - * - * Move 'size' bytes from PC to card. (Shouldn't be interrupted) - */ -static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, - int size) -{ - /* switch to SRAM Page 0 */ - wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : - WL3501_BSS_SPAGE0); - /* set LMAL and LMAH */ - wl3501_outb(dest & 0xff, this->base_addr + WL3501_NIC_LMAL); - wl3501_outb(((dest >> 8) & 0x7f), this->base_addr + WL3501_NIC_LMAH); - - /* rep out to Port A */ - wl3501_outsb(this->base_addr + WL3501_NIC_IODPA, src, size); -} - -/** - * wl3501_get_from_wla - Move 'size' bytes from card to PC - * @this: Card - * @src: Card addressing space - * @dest: PC addressing space - * @size: Bytes to move - * - * Move 'size' bytes from card to PC. (Shouldn't be interrupted) - */ -static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, - int size) -{ - /* switch to SRAM Page 0 */ - wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : - WL3501_BSS_SPAGE0); - /* set LMAL and LMAH */ - wl3501_outb(src & 0xff, this->base_addr + WL3501_NIC_LMAL); - wl3501_outb((src >> 8) & 0x7f, this->base_addr + WL3501_NIC_LMAH); - - /* rep get from Port A */ - insb(this->base_addr + WL3501_NIC_IODPA, dest, size); -} - -/* - * Get/Allocate a free Tx Data Buffer - * - * *--------------*-----------------*----------------------------------* - * | PLCP | MAC Header | DST SRC Data ... | - * | (24 bytes) | (30 bytes) | (6) (6) (Ethernet Row Data) | - * *--------------*-----------------*----------------------------------* - * \ \- IEEE 802.11 -/ \-------------- len --------------/ - * \-struct wl3501_80211_tx_hdr--/ \-------- Ethernet Frame -------/ - * - * Return = Position in Card - */ -static u16 wl3501_get_tx_buffer(struct wl3501_card *this, u16 len) -{ - u16 next, blk_cnt = 0, zero = 0; - u16 full_len = sizeof(struct wl3501_80211_tx_hdr) + len; - u16 ret = 0; - - if (full_len > this->tx_buffer_cnt * 254) - goto out; - ret = this->tx_buffer_head; - while (full_len) { - if (full_len < 254) - full_len = 0; - else - full_len -= 254; - wl3501_get_from_wla(this, this->tx_buffer_head, &next, - sizeof(next)); - if (!full_len) - wl3501_set_to_wla(this, this->tx_buffer_head, &zero, - sizeof(zero)); - this->tx_buffer_head = next; - blk_cnt++; - /* if buffer is not enough */ - if (!next && full_len) { - this->tx_buffer_head = ret; - ret = 0; - goto out; - } - } - this->tx_buffer_cnt -= blk_cnt; -out: - return ret; -} - -/* - * Free an allocated Tx Buffer. ptr must be correct position. - */ -static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr) -{ - /* check if all space is not free */ - if (!this->tx_buffer_head) - this->tx_buffer_head = ptr; - else - wl3501_set_to_wla(this, this->tx_buffer_tail, - &ptr, sizeof(ptr)); - while (ptr) { - u16 next; - - this->tx_buffer_cnt++; - wl3501_get_from_wla(this, ptr, &next, sizeof(next)); - this->tx_buffer_tail = ptr; - ptr = next; - } -} - -static int wl3501_esbq_req_test(struct wl3501_card *this) -{ - u8 tmp = 0; - - wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp)); - return tmp & 0x80; -} - -static void wl3501_esbq_req(struct wl3501_card *this, u16 *ptr) -{ - u16 tmp = 0; - - wl3501_set_to_wla(this, this->esbq_req_head, ptr, 2); - wl3501_set_to_wla(this, this->esbq_req_head + 2, &tmp, sizeof(tmp)); - this->esbq_req_head += 4; - if (this->esbq_req_head >= this->esbq_req_end) - this->esbq_req_head = this->esbq_req_start; -} - -static int wl3501_esbq_exec(struct wl3501_card *this, void *sig, int sig_size) -{ - int rc = -EIO; - - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sig_size); - if (ptr) { - wl3501_set_to_wla(this, ptr, sig, sig_size); - wl3501_esbq_req(this, &ptr); - rc = 0; - } - } - return rc; -} - -static int wl3501_request_mib(struct wl3501_card *this, u8 index, void *bf) -{ - struct wl3501_get_req sig = { - .sig_id = WL3501_SIG_GET_REQ, - .mib_attrib = index, - }; - unsigned long flags; - int rc = -EIO; - - spin_lock_irqsave(&this->lock, flags); - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); - if (ptr) { - wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); - wl3501_esbq_req(this, &ptr); - this->sig_get_confirm.mib_status = 255; - rc = 0; - } - } - spin_unlock_irqrestore(&this->lock, flags); - - return rc; -} - -static int wl3501_get_mib_value(struct wl3501_card *this, u8 index, - void *bf, int size) -{ - int rc; - - rc = wl3501_request_mib(this, index, bf); - if (rc) - return rc; - - rc = wait_event_interruptible(this->wait, - this->sig_get_confirm.mib_status != 255); - if (rc) - return rc; - - memcpy(bf, this->sig_get_confirm.mib_value, size); - return 0; -} - -static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend) -{ - struct wl3501_pwr_mgmt_req sig = { - .sig_id = WL3501_SIG_PWR_MGMT_REQ, - .pwr_save = suspend, - .wake_up = !suspend, - .receive_dtims = 10, - }; - unsigned long flags; - int rc = -EIO; - - spin_lock_irqsave(&this->lock, flags); - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); - if (ptr) { - wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); - wl3501_esbq_req(this, &ptr); - this->sig_pwr_mgmt_confirm.status = 255; - spin_unlock_irqrestore(&this->lock, flags); - rc = wait_event_interruptible(this->wait, - this->sig_pwr_mgmt_confirm.status != 255); - printk(KERN_INFO "%s: %s status=%d\n", __func__, - suspend ? "suspend" : "resume", - this->sig_pwr_mgmt_confirm.status); - goto out; - } - } - spin_unlock_irqrestore(&this->lock, flags); -out: - return rc; -} - -/** - * wl3501_send_pkt - Send a packet. - * @this: Card - * @data: Ethernet raw frame. (e.g. data[0] - data[5] is Dest MAC Addr, - * data[6] - data[11] is Src MAC Addr) - * @len: Packet length - * Ref: IEEE 802.11 - */ -static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len) -{ - u16 bf, sig_bf, next, tmplen, pktlen; - struct wl3501_md_req sig = { - .sig_id = WL3501_SIG_MD_REQ, - }; - size_t sig_addr_len = sizeof(sig.addr); - u8 *pdata = (char *)data; - int rc = -EIO; - - if (wl3501_esbq_req_test(this)) { - sig_bf = wl3501_get_tx_buffer(this, sizeof(sig)); - rc = -ENOMEM; - if (!sig_bf) /* No free buffer available */ - goto out; - bf = wl3501_get_tx_buffer(this, len + 26 + 24); - if (!bf) { - /* No free buffer available */ - wl3501_free_tx_buffer(this, sig_bf); - goto out; - } - rc = 0; - memcpy(&sig.addr, pdata, sig_addr_len); - pktlen = len - sig_addr_len; - pdata += sig_addr_len; - sig.data = bf; - if (((*pdata) * 256 + (*(pdata + 1))) > 1500) { - u8 addr4[ETH_ALEN] = { - [0] = 0xAA, [1] = 0xAA, [2] = 0x03, [4] = 0x00, - }; - - wl3501_set_to_wla(this, bf + 2 + - offsetof(struct wl3501_tx_hdr, addr4), - addr4, sizeof(addr4)); - sig.size = pktlen + 24 + 4 + 6; - if (pktlen > (254 - sizeof(struct wl3501_tx_hdr))) { - tmplen = 254 - sizeof(struct wl3501_tx_hdr); - pktlen -= tmplen; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, - bf + 2 + sizeof(struct wl3501_tx_hdr), - pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } else { - sig.size = pktlen + 24 + 4 - 2; - pdata += 2; - pktlen -= 2; - if (pktlen > (254 - sizeof(struct wl3501_tx_hdr) + 6)) { - tmplen = 254 - sizeof(struct wl3501_tx_hdr) + 6; - pktlen -= tmplen; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, bf + 2 + - offsetof(struct wl3501_tx_hdr, addr4), - pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } - while (pktlen > 0) { - if (pktlen > 254) { - tmplen = 254; - pktlen -= 254; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, bf + 2, pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } - wl3501_set_to_wla(this, sig_bf, &sig, sizeof(sig)); - wl3501_esbq_req(this, &sig_bf); - } -out: - return rc; -} - -static int wl3501_mgmt_resync(struct wl3501_card *this) -{ - struct wl3501_resync_req sig = { - .sig_id = WL3501_SIG_RESYNC_REQ, - }; - - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static inline int wl3501_fw_bss_type(struct wl3501_card *this) -{ - return this->net_type == IW_MODE_INFRA ? WL3501_NET_TYPE_INFRA : - WL3501_NET_TYPE_ADHOC; -} - -static inline int wl3501_fw_cap_info(struct wl3501_card *this) -{ - return this->net_type == IW_MODE_INFRA ? WL3501_MGMT_CAPABILITY_ESS : - WL3501_MGMT_CAPABILITY_IBSS; -} - -static int wl3501_mgmt_scan(struct wl3501_card *this, u16 chan_time) -{ - struct wl3501_scan_req sig = { - .sig_id = WL3501_SIG_SCAN_REQ, - .scan_type = WL3501_SCAN_TYPE_ACTIVE, - .probe_delay = 0x10, - .min_chan_time = chan_time, - .max_chan_time = chan_time, - .bss_type = wl3501_fw_bss_type(this), - }; - - this->bss_cnt = this->join_sta_bss = 0; - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas) -{ - struct wl3501_join_req sig = { - .sig_id = WL3501_SIG_JOIN_REQ, - .timeout = 10, - .req.ds_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - .len = 1, - }, - .chan = this->chan, - }, - }; - - memcpy(&sig.req, &this->bss_set[stas].req, sizeof(sig.req)); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_start(struct wl3501_card *this) -{ - struct wl3501_start_req sig = { - .sig_id = WL3501_SIG_START_REQ, - .beacon_period = 400, - .dtim_period = 1, - .ds_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - .len = 1, - }, - .chan = this->chan, - }, - .bss_basic_rset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - .len = 2, - }, - .data_rate_labels = { - [0] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_1MBIT, - [1] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_2MBIT, - }, - }, - .operational_rset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - .len = 2, - }, - .data_rate_labels = { - [0] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_1MBIT, - [1] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_2MBIT, - }, - }, - .ibss_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, - .len = 2, - }, - .atim_window = 10, - }, - .bss_type = wl3501_fw_bss_type(this), - .cap_info = wl3501_fw_cap_info(this), - }; - - iw_copy_mgmt_info_element(&sig.ssid.el, &this->essid.el); - iw_copy_mgmt_info_element(&this->keep_essid.el, &this->essid.el); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr) -{ - u16 i = 0; - int matchflag = 0; - struct wl3501_scan_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) { - pr_debug("success"); - if ((this->net_type == IW_MODE_INFRA && - (sig.req.cap_info & WL3501_MGMT_CAPABILITY_ESS)) || - (this->net_type == IW_MODE_ADHOC && - (sig.req.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) || - this->net_type == IW_MODE_AUTO) { - if (!this->essid.el.len) - matchflag = 1; - else if (this->essid.el.len == 3 && - !memcmp(this->essid.essid, "ANY", 3)) - matchflag = 1; - else if (this->essid.el.len != sig.req.ssid.el.len) - matchflag = 0; - else if (memcmp(this->essid.essid, sig.req.ssid.essid, - this->essid.el.len)) - matchflag = 0; - else - matchflag = 1; - if (matchflag) { - for (i = 0; i < this->bss_cnt; i++) { - if (ether_addr_equal_unaligned(this->bss_set[i].req.bssid, - sig.req.bssid)) { - matchflag = 0; - break; - } - } - } - if (matchflag && (i < 20)) { - memcpy(&this->bss_set[i].req, - &sig.req, sizeof(sig.req)); - this->bss_cnt++; - this->rssi = sig.rssi; - this->bss_set[i].rssi = sig.rssi; - } - } - } else if (sig.status == WL3501_STATUS_TIMEOUT) { - pr_debug("timeout"); - this->join_sta_bss = 0; - for (i = this->join_sta_bss; i < this->bss_cnt; i++) - if (!wl3501_mgmt_join(this, i)) - break; - this->join_sta_bss = i; - if (this->join_sta_bss == this->bss_cnt) { - if (this->net_type == IW_MODE_INFRA) - wl3501_mgmt_scan(this, 100); - else { - this->adhoc_times++; - if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) - wl3501_mgmt_start(this); - else - wl3501_mgmt_scan(this, 100); - } - } - } -} - -/** - * wl3501_block_interrupt - Mask interrupt from SUTRO - * @this: Card - * - * Mask interrupt from SUTRO. (i.e. SUTRO cannot interrupt the HOST) - * Return: 1 if interrupt is originally enabled - */ -static int wl3501_block_interrupt(struct wl3501_card *this) -{ - u8 old = inb(this->base_addr + WL3501_NIC_GCR); - u8 new = old & (~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC | - WL3501_GCR_ENECINT)); - - wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); - return old & WL3501_GCR_ENECINT; -} - -/** - * wl3501_unblock_interrupt - Enable interrupt from SUTRO - * @this: Card - * - * Enable interrupt from SUTRO. (i.e. SUTRO can interrupt the HOST) - * Return: 1 if interrupt is originally enabled - */ -static int wl3501_unblock_interrupt(struct wl3501_card *this) -{ - u8 old = inb(this->base_addr + WL3501_NIC_GCR); - u8 new = (old & ~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC)) | - WL3501_GCR_ENECINT; - - wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); - return old & WL3501_GCR_ENECINT; -} - -/** - * wl3501_receive - Receive data from Receive Queue. - * - * Receive data from Receive Queue. - * - * @this: card - * @bf: address of host - * @size: size of buffer. - */ -static u16 wl3501_receive(struct wl3501_card *this, u8 *bf, u16 size) -{ - u16 next_addr, next_addr1; - u8 *data = bf + 12; - - size -= 12; - wl3501_get_from_wla(this, this->start_seg + 2, - &next_addr, sizeof(next_addr)); - if (size > WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)) { - wl3501_get_from_wla(this, - this->start_seg + - sizeof(struct wl3501_rx_hdr), data, - WL3501_BLKSZ - - sizeof(struct wl3501_rx_hdr)); - size -= WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); - data += WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); - } else { - wl3501_get_from_wla(this, - this->start_seg + - sizeof(struct wl3501_rx_hdr), - data, size); - size = 0; - } - while (size > 0) { - if (size > WL3501_BLKSZ - 5) { - wl3501_get_from_wla(this, next_addr + 5, data, - WL3501_BLKSZ - 5); - size -= WL3501_BLKSZ - 5; - data += WL3501_BLKSZ - 5; - wl3501_get_from_wla(this, next_addr + 2, &next_addr1, - sizeof(next_addr1)); - next_addr = next_addr1; - } else { - wl3501_get_from_wla(this, next_addr + 5, data, size); - size = 0; - } - } - return 0; -} - -static void wl3501_esbq_req_free(struct wl3501_card *this) -{ - u8 tmp; - u16 addr; - - if (this->esbq_req_head == this->esbq_req_tail) - goto out; - wl3501_get_from_wla(this, this->esbq_req_tail + 3, &tmp, sizeof(tmp)); - if (!(tmp & 0x80)) - goto out; - wl3501_get_from_wla(this, this->esbq_req_tail, &addr, sizeof(addr)); - wl3501_free_tx_buffer(this, addr); - this->esbq_req_tail += 4; - if (this->esbq_req_tail >= this->esbq_req_end) - this->esbq_req_tail = this->esbq_req_start; -out: - return; -} - -static int wl3501_esbq_confirm(struct wl3501_card *this) -{ - u8 tmp; - - wl3501_get_from_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); - return tmp & 0x80; -} - -static void wl3501_online(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - - printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n", - dev->name, this->bssid); - netif_wake_queue(dev); -} - -static void wl3501_esbq_confirm_done(struct wl3501_card *this) -{ - u8 tmp = 0; - - wl3501_set_to_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); - this->esbq_confirm += 4; - if (this->esbq_confirm >= this->esbq_confirm_end) - this->esbq_confirm = this->esbq_confirm_start; -} - -static int wl3501_mgmt_auth(struct wl3501_card *this) -{ - struct wl3501_auth_req sig = { - .sig_id = WL3501_SIG_AUTH_REQ, - .type = WL3501_SYS_TYPE_OPEN, - .timeout = 1000, - }; - - pr_debug("entry"); - memcpy(sig.mac_addr, this->bssid, ETH_ALEN); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_association(struct wl3501_card *this) -{ - struct wl3501_assoc_req sig = { - .sig_id = WL3501_SIG_ASSOC_REQ, - .timeout = 1000, - .listen_interval = 5, - .cap_info = this->cap_info, - }; - - pr_debug("entry"); - memcpy(sig.mac_addr, this->bssid, ETH_ALEN); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr) -{ - struct wl3501_card *this = netdev_priv(dev); - struct wl3501_join_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) { - if (this->net_type == IW_MODE_INFRA) { - if (this->join_sta_bss < this->bss_cnt) { - const int i = this->join_sta_bss; - memcpy(this->bssid, - this->bss_set[i].req.bssid, ETH_ALEN); - this->chan = this->bss_set[i].req.ds_pset.chan; - iw_copy_mgmt_info_element(&this->keep_essid.el, - &this->bss_set[i].req.ssid.el); - wl3501_mgmt_auth(this); - } - } else { - const int i = this->join_sta_bss; - - memcpy(&this->bssid, &this->bss_set[i].req.bssid, ETH_ALEN); - this->chan = this->bss_set[i].req.ds_pset.chan; - iw_copy_mgmt_info_element(&this->keep_essid.el, - &this->bss_set[i].req.ssid.el); - wl3501_online(dev); - } - } else { - int i; - this->join_sta_bss++; - for (i = this->join_sta_bss; i < this->bss_cnt; i++) - if (!wl3501_mgmt_join(this, i)) - break; - this->join_sta_bss = i; - if (this->join_sta_bss == this->bss_cnt) { - if (this->net_type == IW_MODE_INFRA) - wl3501_mgmt_scan(this, 100); - else { - this->adhoc_times++; - if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) - wl3501_mgmt_start(this); - else - wl3501_mgmt_scan(this, 100); - } - } - } -} - -static inline void wl3501_alarm_interrupt(struct net_device *dev, - struct wl3501_card *this) -{ - if (this->net_type == IW_MODE_INFRA) { - printk(KERN_INFO "Wireless LAN offline\n"); - netif_stop_queue(dev); - wl3501_mgmt_resync(this); - } -} - -static inline void wl3501_md_confirm_interrupt(struct net_device *dev, - struct wl3501_card *this, - u16 addr) -{ - struct wl3501_md_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - wl3501_free_tx_buffer(this, sig.data); - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); -} - -static inline void wl3501_md_ind_interrupt(struct net_device *dev, - struct wl3501_card *this, u16 addr) -{ - struct wl3501_md_ind sig; - struct sk_buff *skb; - u8 rssi, addr4[ETH_ALEN]; - u16 pkt_len; - - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - this->start_seg = sig.data; - wl3501_get_from_wla(this, - sig.data + offsetof(struct wl3501_rx_hdr, rssi), - &rssi, sizeof(rssi)); - this->rssi = rssi <= 63 ? (rssi * 100) / 64 : 255; - - wl3501_get_from_wla(this, - sig.data + - offsetof(struct wl3501_rx_hdr, addr4), - &addr4, sizeof(addr4)); - if (!(addr4[0] == 0xAA && addr4[1] == 0xAA && - addr4[2] == 0x03 && addr4[4] == 0x00)) { - printk(KERN_INFO "Unsupported packet type!\n"); - return; - } - pkt_len = sig.size + 12 - 24 - 4 - 6; - - skb = dev_alloc_skb(pkt_len + 5); - - if (!skb) { - printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n", - dev->name, pkt_len); - dev->stats.rx_dropped++; - } else { - skb->dev = dev; - skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */ - skb_copy_to_linear_data(skb, (unsigned char *)&sig.addr, - sizeof(sig.addr)); - wl3501_receive(this, skb->data, pkt_len); - skb_put(skb, pkt_len); - skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - netif_rx(skb); - } -} - -static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this, - u16 addr, void *sig, int size) -{ - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &this->sig_get_confirm, - sizeof(this->sig_get_confirm)); - wake_up(&this->wait); -} - -static inline void wl3501_start_confirm_interrupt(struct net_device *dev, - struct wl3501_card *this, - u16 addr) -{ - struct wl3501_start_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) - netif_wake_queue(dev); -} - -static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, - u16 addr) -{ - struct wl3501_card *this = netdev_priv(dev); - struct wl3501_assoc_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - - if (sig.status == WL3501_STATUS_SUCCESS) - wl3501_online(dev); -} - -static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this, - u16 addr) -{ - struct wl3501_auth_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - - if (sig.status == WL3501_STATUS_SUCCESS) - wl3501_mgmt_association(this); - else - wl3501_mgmt_resync(this); -} - -static inline void wl3501_rx_interrupt(struct net_device *dev) -{ - int morepkts; - u16 addr; - u8 sig_id; - struct wl3501_card *this = netdev_priv(dev); - - pr_debug("entry"); -loop: - morepkts = 0; - if (!wl3501_esbq_confirm(this)) - goto free; - wl3501_get_from_wla(this, this->esbq_confirm, &addr, sizeof(addr)); - wl3501_get_from_wla(this, addr + 2, &sig_id, sizeof(sig_id)); - - switch (sig_id) { - case WL3501_SIG_DEAUTH_IND: - case WL3501_SIG_DISASSOC_IND: - case WL3501_SIG_ALARM: - wl3501_alarm_interrupt(dev, this); - break; - case WL3501_SIG_MD_CONFIRM: - wl3501_md_confirm_interrupt(dev, this, addr); - break; - case WL3501_SIG_MD_IND: - wl3501_md_ind_interrupt(dev, this, addr); - break; - case WL3501_SIG_GET_CONFIRM: - wl3501_get_confirm_interrupt(this, addr, - &this->sig_get_confirm, - sizeof(this->sig_get_confirm)); - break; - case WL3501_SIG_PWR_MGMT_CONFIRM: - wl3501_get_confirm_interrupt(this, addr, - &this->sig_pwr_mgmt_confirm, - sizeof(this->sig_pwr_mgmt_confirm)); - break; - case WL3501_SIG_START_CONFIRM: - wl3501_start_confirm_interrupt(dev, this, addr); - break; - case WL3501_SIG_SCAN_CONFIRM: - wl3501_mgmt_scan_confirm(this, addr); - break; - case WL3501_SIG_JOIN_CONFIRM: - wl3501_mgmt_join_confirm(dev, addr); - break; - case WL3501_SIG_ASSOC_CONFIRM: - wl3501_assoc_confirm_interrupt(dev, addr); - break; - case WL3501_SIG_AUTH_CONFIRM: - wl3501_auth_confirm_interrupt(this, addr); - break; - case WL3501_SIG_RESYNC_CONFIRM: - wl3501_mgmt_resync(this); /* FIXME: should be resync_confirm */ - break; - } - wl3501_esbq_confirm_done(this); - morepkts = 1; - /* free request if necessary */ -free: - wl3501_esbq_req_free(this); - if (morepkts) - goto loop; -} - -static inline void wl3501_ack_interrupt(struct wl3501_card *this) -{ - wl3501_outb(WL3501_GCR_ECINT, this->base_addr + WL3501_NIC_GCR); -} - -/** - * wl3501_interrupt - Hardware interrupt from card. - * @irq: Interrupt number - * @dev_id: net_device - * - * We must acknowledge the interrupt as soon as possible, and block the - * interrupt from the same card immediately to prevent re-entry. - * - * Before accessing the Control_Status_Block, we must lock SUTRO first. - * On the other hand, to prevent SUTRO from malfunctioning, we must - * unlock the SUTRO as soon as possible. - */ -static irqreturn_t wl3501_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct wl3501_card *this; - - this = netdev_priv(dev); - spin_lock(&this->lock); - wl3501_ack_interrupt(this); - wl3501_block_interrupt(this); - wl3501_rx_interrupt(dev); - wl3501_unblock_interrupt(this); - spin_unlock(&this->lock); - - return IRQ_HANDLED; -} - -static int wl3501_reset_board(struct wl3501_card *this) -{ - u8 tmp = 0; - int i, rc = 0; - - /* Coreset */ - wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); - wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); - wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); - - /* Reset SRAM 0x480 to zero */ - wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); - - /* Start up */ - wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); - - WL3501_NOPLOOP(1024 * 50); - - wl3501_unblock_interrupt(this); /* acme: was commented */ - - /* Polling Self_Test_Status */ - for (i = 0; i < 10000; i++) { - wl3501_get_from_wla(this, 0x480, &tmp, sizeof(tmp)); - - if (tmp == 'W') { - /* firmware complete all test successfully */ - tmp = 'A'; - wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); - goto out; - } - WL3501_NOPLOOP(10); - } - printk(KERN_WARNING "%s: failed to reset the board!\n", __func__); - rc = -ENODEV; -out: - return rc; -} - -static int wl3501_init_firmware(struct wl3501_card *this) -{ - u16 ptr, next; - int rc = wl3501_reset_board(this); - - if (rc) - goto fail; - this->card_name[0] = '\0'; - wl3501_get_from_wla(this, 0x1a00, - this->card_name, sizeof(this->card_name)); - this->card_name[sizeof(this->card_name) - 1] = '\0'; - this->firmware_date[0] = '\0'; - wl3501_get_from_wla(this, 0x1a40, - this->firmware_date, sizeof(this->firmware_date)); - this->firmware_date[sizeof(this->firmware_date) - 1] = '\0'; - /* Switch to SRAM Page 0 */ - wl3501_switch_page(this, WL3501_BSS_SPAGE0); - /* Read parameter from card */ - wl3501_get_from_wla(this, 0x482, &this->esbq_req_start, 2); - wl3501_get_from_wla(this, 0x486, &this->esbq_req_end, 2); - wl3501_get_from_wla(this, 0x488, &this->esbq_confirm_start, 2); - wl3501_get_from_wla(this, 0x48c, &this->esbq_confirm_end, 2); - wl3501_get_from_wla(this, 0x48e, &this->tx_buffer_head, 2); - wl3501_get_from_wla(this, 0x492, &this->tx_buffer_size, 2); - this->esbq_req_tail = this->esbq_req_head = this->esbq_req_start; - this->esbq_req_end += this->esbq_req_start; - this->esbq_confirm = this->esbq_confirm_start; - this->esbq_confirm_end += this->esbq_confirm_start; - /* Initial Tx Buffer */ - this->tx_buffer_cnt = 1; - ptr = this->tx_buffer_head; - next = ptr + WL3501_BLKSZ; - while ((next - this->tx_buffer_head) < this->tx_buffer_size) { - this->tx_buffer_cnt++; - wl3501_set_to_wla(this, ptr, &next, sizeof(next)); - ptr = next; - next = ptr + WL3501_BLKSZ; - } - rc = 0; - next = 0; - wl3501_set_to_wla(this, ptr, &next, sizeof(next)); - this->tx_buffer_tail = ptr; -out: - return rc; -fail: - printk(KERN_WARNING "%s: failed!\n", __func__); - goto out; -} - -static int wl3501_close(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link; - link = this->p_dev; - - spin_lock_irqsave(&this->lock, flags); - link->open--; - - /* Stop wl3501_hard_start_xmit() from now on */ - netif_stop_queue(dev); - wl3501_ack_interrupt(this); - - /* Mask interrupts from the SUTRO */ - wl3501_block_interrupt(this); - - printk(KERN_INFO "%s: WL3501 closed\n", dev->name); - spin_unlock_irqrestore(&this->lock, flags); - return 0; -} - -/** - * wl3501_reset - Reset the SUTRO. - * @dev: network device - * - * It is almost the same as wl3501_open(). In fact, we may just wl3501_close() - * and wl3501_open() again, but I wouldn't like to free_irq() when the driver - * is running. It seems to be dangerous. - */ -static int wl3501_reset(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - int rc = -ENODEV; - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - wl3501_block_interrupt(this); - - if (wl3501_init_firmware(this)) { - printk(KERN_WARNING "%s: Can't initialize Firmware!\n", - dev->name); - /* Free IRQ, and mark IRQ as unused */ - free_irq(dev->irq, dev); - goto out; - } - - /* - * Queue has to be started only when the Card is Started - */ - netif_stop_queue(dev); - this->adhoc_times = 0; - wl3501_ack_interrupt(this); - wl3501_unblock_interrupt(this); - wl3501_mgmt_scan(this, 100); - pr_debug("%s: device reset", dev->name); - rc = 0; -out: - spin_unlock_irqrestore(&this->lock, flags); - return rc; -} - -static void wl3501_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct net_device_stats *stats = &dev->stats; - int rc; - - stats->tx_errors++; - rc = wl3501_reset(dev); - if (rc) - printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", - dev->name, rc); - else { - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); - } -} - -/* - * Return : 0 - OK - * 1 - Could not transmit (dev_queue_xmit will queue it) - * and try to sent it later - */ -static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - int enabled, rc; - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - enabled = wl3501_block_interrupt(this); - rc = wl3501_send_pkt(this, skb->data, skb->len); - if (enabled) - wl3501_unblock_interrupt(this); - if (rc) { - ++dev->stats.tx_dropped; - netif_stop_queue(dev); - } else { - ++dev->stats.tx_packets; - dev->stats.tx_bytes += skb->len; - dev_kfree_skb_irq(skb); - - if (this->tx_buffer_cnt < 2) - netif_stop_queue(dev); - } - spin_unlock_irqrestore(&this->lock, flags); - return NETDEV_TX_OK; -} - -static int wl3501_open(struct net_device *dev) -{ - int rc = -ENODEV; - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link; - link = this->p_dev; - - spin_lock_irqsave(&this->lock, flags); - if (!pcmcia_dev_present(link)) - goto out; - netif_device_attach(dev); - link->open++; - - /* Initial WL3501 firmware */ - pr_debug("%s: Initialize WL3501 firmware...", dev->name); - if (wl3501_init_firmware(this)) - goto fail; - /* Initial device variables */ - this->adhoc_times = 0; - /* Acknowledge Interrupt, for cleaning last state */ - wl3501_ack_interrupt(this); - - /* Enable interrupt from card after all */ - wl3501_unblock_interrupt(this); - wl3501_mgmt_scan(this, 100); - rc = 0; - pr_debug("%s: WL3501 opened", dev->name); - printk(KERN_INFO "%s: Card Name: %s\n" - "%s: Firmware Date: %s\n", - dev->name, this->card_name, - dev->name, this->firmware_date); -out: - spin_unlock_irqrestore(&this->lock, flags); - return rc; -fail: - printk(KERN_WARNING "%s: Can't initialize firmware!\n", dev->name); - goto out; -} - -static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - struct iw_statistics *wstats = &this->wstats; - u32 value; /* size checked: it is u32 */ - - memset(wstats, 0, sizeof(*wstats)); - wstats->status = netif_running(dev); - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RETRY_COUNT, - &value, sizeof(value))) - wstats->discard.retries = value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FAILED_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_FAILURE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_ACK_FAILURE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - return wstats; -} - -/** - * wl3501_detach - deletes a driver "instance" - * @link: FILL_IN - * - * This deletes a driver "instance". The device is de-registered with Card - * Services. If it has been released, all local data structures are freed. - * Otherwise, the structures will be freed when the device is released. - */ -static void wl3501_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - /* If the device is currently configured and active, we won't actually - * delete it yet. Instead, it is marked so that when the release() - * function is called, that will trigger a proper detach(). */ - - while (link->open > 0) - wl3501_close(dev); - - netif_device_detach(dev); - wl3501_release(link); - - unregister_netdev(dev); - free_netdev(dev); -} - -static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - strscpy(wrqu->name, "IEEE 802.11-DS", sizeof(wrqu->name)); - return 0; -} - -static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int channel = wrqu->freq.m; - int rc = -EINVAL; - - if (iw_valid_channel(this->reg_domain, channel)) { - this->chan = channel; - rc = wl3501_reset(dev); - } - return rc; -} - -static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->freq.m = 100000 * - ieee80211_channel_to_frequency(this->chan, NL80211_BAND_2GHZ); - wrqu->freq.e = 1; - return 0; -} - -static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int rc = -EINVAL; - - if (wrqu->mode == IW_MODE_INFRA || - wrqu->mode == IW_MODE_ADHOC || - wrqu->mode == IW_MODE_AUTO) { - struct wl3501_card *this = netdev_priv(dev); - - this->net_type = wrqu->mode; - rc = wl3501_reset(dev); - } - return rc; -} - -static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->mode = this->net_type; - return 0; -} - -static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->sens.value = this->rssi; - wrqu->sens.disabled = !wrqu->sens.value; - wrqu->sens.fixed = 1; - return 0; -} - -static int wl3501_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(*range); - - /* Set all the info we don't care or don't know about to zero */ - memset(range, 0, sizeof(*range)); - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 1; - range->throughput = 2 * 1000 * 1000; /* ~2 Mb/s */ - /* FIXME: study the code to fill in more fields... */ - return 0; -} - -static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int rc = -EINVAL; - - /* FIXME: we support other ARPHRDs...*/ - if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) - goto out; - if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data)) { - /* FIXME: rescan? */ - } else - memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); - /* FIXME: rescan? deassoc & scan? */ - rc = 0; -out: - return rc; -} - -static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN); - return 0; -} - -static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * FIXME: trigger scanning with a reset, yes, I'm lazy - */ - return wl3501_reset(dev); -} - -static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int i; - char *current_ev = extra; - struct iw_event iwe; - - for (i = 0; i < this->bss_cnt; ++i) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].req.bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_ADDR_LEN); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - iwe.u.data.length = this->bss_set[i].req.ssid.el.len; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, - this->bss_set[i].req.ssid.essid); - iwe.cmd = SIOCGIWMODE; - iwe.u.mode = this->bss_set[i].req.bss_type; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_UINT_LEN); - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = this->bss_set[i].req.ds_pset.chan; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_FREQ_LEN); - iwe.cmd = SIOCGIWENCODE; - if (this->bss_set[i].req.cap_info & WL3501_MGMT_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, NULL); - } - /* Length of data */ - wrqu->data.length = (current_ev - extra); - wrqu->data.flags = 0; /* FIXME: set properly these flags */ - return 0; -} - -static int wl3501_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - if (wrqu->data.flags) { - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, - &this->essid.el, - extra, wrqu->data.length); - } else { /* We accept any ESSID */ - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, - &this->essid.el, "ANY", 3); - } - return wl3501_reset(dev); -} - -static int wl3501_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - wrqu->essid.flags = 1; - wrqu->essid.length = this->essid.el.len; - memcpy(extra, this->essid.essid, this->essid.el.len); - spin_unlock_irqrestore(&this->lock, flags); - return 0; -} - -static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - if (wrqu->data.length > sizeof(this->nick)) - return -E2BIG; - strscpy(this->nick, extra, wrqu->data.length); - return 0; -} - -static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - strscpy(extra, this->nick, 32); - wrqu->data.length = strlen(extra); - return 0; -} - -static int wl3501_get_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * FIXME: have to see from where to get this info, perhaps this card - * works at 1 Mbit/s too... for now leave at 2 Mbit/s that is the most - * common with the Planet Access Points. -acme - */ - wrqu->bitrate.value = 2000000; - wrqu->bitrate.fixed = 1; - return 0; -} - -static int wl3501_get_rts_threshold(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD, - &threshold, sizeof(threshold)); - if (!rc) { - wrqu->rts.value = threshold; - wrqu->rts.disabled = threshold >= 2347; - wrqu->rts.fixed = 1; - } - return rc; -} - -static int wl3501_get_frag_threshold(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD, - &threshold, sizeof(threshold)); - if (!rc) { - wrqu->frag.value = threshold; - wrqu->frag.disabled = threshold >= 2346; - wrqu->frag.fixed = 1; - } - return rc; -} - -static int wl3501_get_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 txpow; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, - &txpow, sizeof(txpow)); - if (!rc) { - wrqu->txpower.value = txpow; - wrqu->txpower.disabled = 0; - /* - * From the MIB values I think this can be configurable, - * as it lists several tx power levels -acme - */ - wrqu->txpower.fixed = 0; - wrqu->txpower.flags = IW_TXPOW_MWATT; - } - return rc; -} - -static int wl3501_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 retry; /* size checked: it is u8 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_LONG_RETRY_LIMIT, - &retry, sizeof(retry)); - if (rc) - goto out; - if (wrqu->retry.flags & IW_RETRY_LONG) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - goto set_value; - } - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, - &retry, sizeof(retry)); - if (rc) - goto out; - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; -set_value: - wrqu->retry.value = retry; - wrqu->retry.disabled = 0; -out: - return rc; -} - -static int wl3501_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 implemented, restricted, keys[100], len_keys, tocopy; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, - &implemented, sizeof(implemented)); - if (rc) - goto out; - if (!implemented) { - wrqu->encoding.flags = IW_ENCODE_DISABLED; - goto out; - } - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, - &restricted, sizeof(restricted)); - if (rc) - goto out; - wrqu->encoding.flags = restricted ? IW_ENCODE_RESTRICTED : - IW_ENCODE_OPEN; - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, - &len_keys, sizeof(len_keys)); - if (rc) - goto out; - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, - keys, len_keys); - if (rc) - goto out; - tocopy = min_t(u16, len_keys, wrqu->encoding.length); - tocopy = min_t(u8, tocopy, 100); - wrqu->encoding.length = tocopy; - memcpy(extra, keys, tocopy); -out: - return rc; -} - -static int wl3501_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 pwr_state; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_CURRENT_PWR_STATE, - &pwr_state, sizeof(pwr_state)); - if (rc) - goto out; - wrqu->power.disabled = !pwr_state; - wrqu->power.flags = IW_POWER_ON; -out: - return rc; -} - -static const iw_handler wl3501_handler[] = { - IW_HANDLER(SIOCGIWNAME, wl3501_get_name), - IW_HANDLER(SIOCSIWFREQ, wl3501_set_freq), - IW_HANDLER(SIOCGIWFREQ, wl3501_get_freq), - IW_HANDLER(SIOCSIWMODE, wl3501_set_mode), - IW_HANDLER(SIOCGIWMODE, wl3501_get_mode), - IW_HANDLER(SIOCGIWSENS, wl3501_get_sens), - IW_HANDLER(SIOCGIWRANGE, wl3501_get_range), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, wl3501_set_wap), - IW_HANDLER(SIOCGIWAP, wl3501_get_wap), - IW_HANDLER(SIOCSIWSCAN, wl3501_set_scan), - IW_HANDLER(SIOCGIWSCAN, wl3501_get_scan), - IW_HANDLER(SIOCSIWESSID, wl3501_set_essid), - IW_HANDLER(SIOCGIWESSID, wl3501_get_essid), - IW_HANDLER(SIOCSIWNICKN, wl3501_set_nick), - IW_HANDLER(SIOCGIWNICKN, wl3501_get_nick), - IW_HANDLER(SIOCGIWRATE, wl3501_get_rate), - IW_HANDLER(SIOCGIWRTS, wl3501_get_rts_threshold), - IW_HANDLER(SIOCGIWFRAG, wl3501_get_frag_threshold), - IW_HANDLER(SIOCGIWTXPOW, wl3501_get_txpow), - IW_HANDLER(SIOCGIWRETRY, wl3501_get_retry), - IW_HANDLER(SIOCGIWENCODE, wl3501_get_encode), - IW_HANDLER(SIOCGIWPOWER, wl3501_get_power), -}; - -static const struct iw_handler_def wl3501_handler_def = { - .num_standard = ARRAY_SIZE(wl3501_handler), - .standard = (iw_handler *)wl3501_handler, - .get_wireless_stats = wl3501_get_wireless_stats, -}; - -static const struct net_device_ops wl3501_netdev_ops = { - .ndo_open = wl3501_open, - .ndo_stop = wl3501_close, - .ndo_start_xmit = wl3501_hard_start_xmit, - .ndo_tx_timeout = wl3501_tx_timeout, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int wl3501_probe(struct pcmcia_device *p_dev) -{ - struct net_device *dev; - struct wl3501_card *this; - int ret; - - /* The io structure describes IO port mapping */ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags = IO_DATA_PATH_WIDTH_8; - - /* General socket configuration */ - p_dev->config_flags = CONF_ENABLE_IRQ; - p_dev->config_index = 1; - - dev = alloc_etherdev(sizeof(struct wl3501_card)); - if (!dev) - return -ENOMEM; - - dev->netdev_ops = &wl3501_netdev_ops; - dev->watchdog_timeo = 5 * HZ; - - this = netdev_priv(dev); - this->wireless_data.spy_data = &this->spy_data; - this->p_dev = p_dev; - dev->wireless_data = &this->wireless_data; - dev->wireless_handlers = &wl3501_handler_def; - netif_stop_queue(dev); - p_dev->priv = dev; - - ret = wl3501_config(p_dev); - if (ret) - goto out_free_etherdev; - - return 0; - -out_free_etherdev: - free_netdev(dev); - return ret; -} - -static int wl3501_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - int i = 0, j, ret; - struct wl3501_card *this; - - /* Try allocating IO ports. This tries a few fixed addresses. If you - * want, you can also read the card's config table to pick addresses -- - * see the serial driver for an example. */ - link->io_lines = 5; - - for (j = 0x280; j < 0x400; j += 0x20) { - /* The '^0x300' is so that we probe 0x300-0x3ff first, then - * 0x200-0x2ff, and so on, because this seems safer */ - link->resource[0]->start = j; - link->resource[1]->start = link->resource[0]->start + 0x10; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - if (i != 0) - goto failed; - - /* Now allocate an interrupt line. Note that this does not actually - * assign a handler to the interrupt. */ - - ret = pcmcia_request_irq(link, wl3501_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - SET_NETDEV_DEV(dev, &link->dev); - if (register_netdev(dev)) { - printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n"); - goto failed; - } - - this = netdev_priv(dev); - - this->base_addr = dev->base_addr; - - if (!wl3501_get_flash_mac_addr(this)) { - printk(KERN_WARNING "%s: Can't read MAC addr in flash ROM?\n", - dev->name); - unregister_netdev(dev); - goto failed; - } - - eth_hw_addr_set(dev, this->mac_addr); - - /* print probe information */ - printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, " - "MAC addr in flash ROM:%pM\n", - dev->name, this->base_addr, (int)dev->irq, - dev->dev_addr); - /* - * Initialize card parameters - added by jss - */ - this->net_type = IW_MODE_INFRA; - this->bss_cnt = 0; - this->join_sta_bss = 0; - this->adhoc_times = 0; - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el, - "ANY", 3); - this->card_name[0] = '\0'; - this->firmware_date[0] = '\0'; - this->rssi = 255; - this->chan = iw_default_channel(this->reg_domain); - strscpy(this->nick, "Planet WL3501", sizeof(this->nick)); - spin_lock_init(&this->lock); - init_waitqueue_head(&this->wait); - netif_start_queue(dev); - return 0; - -failed: - wl3501_release(link); - return -ENODEV; -} - -static void wl3501_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static int wl3501_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND); - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int wl3501_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME); - if (link->open) { - wl3501_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -static const struct pcmcia_device_id wl3501_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, wl3501_ids); - -static struct pcmcia_driver wl3501_driver = { - .owner = THIS_MODULE, - .name = "wl3501_cs", - .probe = wl3501_probe, - .remove = wl3501_detach, - .id_table = wl3501_ids, - .suspend = wl3501_suspend, - .resume = wl3501_resume, -}; -module_pcmcia_driver(wl3501_driver); - -MODULE_AUTHOR("Fox Chen <mhchen@golf.ccl.itri.org.tw>, " - "Arnaldo Carvalho de Melo <acme@conectiva.com.br>," - "Gustavo Niemeyer <niemeyer@conectiva.com>"); -MODULE_DESCRIPTION("Planet wl3501 wireless driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig index c7d02adb3e..36b234bc5b 100644 --- a/drivers/net/wireless/marvell/libertas/Kconfig +++ b/drivers/net/wireless/marvell/libertas/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" + depends on USB || MMC || SPI depends on CFG80211 select LIB80211 select FW_LOADER @@ -13,12 +14,6 @@ config LIBERTAS_USB help A driver for Marvell Libertas 8388 USB devices. -config LIBERTAS_CS - tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" - depends on LIBERTAS && PCMCIA && HAS_IOPORT_MAP - help - A driver for Marvell Libertas 8385 CompactFlash devices. - config LIBERTAS_SDIO tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards" depends on LIBERTAS && MMC diff --git a/drivers/net/wireless/marvell/libertas/Makefile b/drivers/net/wireless/marvell/libertas/Makefile index 41b9b440a5..2ac04f4d61 100644 --- a/drivers/net/wireless/marvell/libertas/Makefile +++ b/drivers/net/wireless/marvell/libertas/Makefile @@ -17,6 +17,5 @@ libertas_spi-objs += if_spi.o obj-$(CONFIG_LIBERTAS) += libertas.o obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o -obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o obj-$(CONFIG_LIBERTAS_SPI) += libertas_spi.o diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c deleted file mode 100644 index 4103f15bca..0000000000 --- a/drivers/net/wireless/marvell/libertas/if_cs.c +++ /dev/null @@ -1,957 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - - Driver for the Marvell 8385 based compact flash WLAN cards. - - (C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de> - - -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/moduleparam.h> -#include <linux/firmware.h> -#include <linux/netdevice.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/ds.h> - -#include <linux/io.h> - -#define DRV_NAME "libertas_cs" - -#include "decl.h" -#include "defs.h" -#include "dev.h" - - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>"); -MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); -MODULE_LICENSE("GPL"); - - - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -struct if_cs_card { - struct pcmcia_device *p_dev; - struct lbs_private *priv; - void __iomem *iobase; - bool align_regs; - u32 model; -}; - - -enum { - MODEL_UNKNOWN = 0x00, - MODEL_8305 = 0x01, - MODEL_8381 = 0x02, - MODEL_8385 = 0x03 -}; - -static const struct lbs_fw_table fw_table[] = { - { MODEL_8305, "libertas/cf8305.bin", NULL }, - { MODEL_8305, "libertas_cs_helper.fw", NULL }, - { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" }, - { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" }, - { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" }, - { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" }, - { 0, NULL, NULL } -}; -MODULE_FIRMWARE("libertas/cf8305.bin"); -MODULE_FIRMWARE("libertas/cf8381_helper.bin"); -MODULE_FIRMWARE("libertas/cf8381.bin"); -MODULE_FIRMWARE("libertas/cf8385_helper.bin"); -MODULE_FIRMWARE("libertas/cf8385.bin"); -MODULE_FIRMWARE("libertas_cs_helper.fw"); -MODULE_FIRMWARE("libertas_cs.fw"); - - -/********************************************************************/ -/* Hardware access */ -/********************************************************************/ - -/* This define enables wrapper functions which allow you - to dump all register accesses. You normally won't this, - except for development */ -/* #define DEBUG_IO */ - -#ifdef DEBUG_IO -static int debug_output = 0; -#else -/* This way the compiler optimizes the printk's away */ -#define debug_output 0 -#endif - -static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg) -{ - unsigned int val = ioread8(card->iobase + reg); - if (debug_output) - printk(KERN_INFO "inb %08x<%02x\n", reg, val); - return val; -} -static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg) -{ - unsigned int val = ioread16(card->iobase + reg); - if (debug_output) - printk(KERN_INFO "inw %08x<%04x\n", reg, val); - return val; -} -static inline void if_cs_read16_rep( - struct if_cs_card *card, - uint reg, - void *buf, - unsigned long count) -{ - if (debug_output) - printk(KERN_INFO "insw %08x<(0x%lx words)\n", - reg, count); - ioread16_rep(card->iobase + reg, buf, count); -} - -static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val) -{ - if (debug_output) - printk(KERN_INFO "outb %08x>%02x\n", reg, val); - iowrite8(val, card->iobase + reg); -} - -static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val) -{ - if (debug_output) - printk(KERN_INFO "outw %08x>%04x\n", reg, val); - iowrite16(val, card->iobase + reg); -} - -static inline void if_cs_write16_rep( - struct if_cs_card *card, - uint reg, - const void *buf, - unsigned long count) -{ - if (debug_output) - printk(KERN_INFO "outsw %08x>(0x%lx words)\n", - reg, count); - iowrite16_rep(card->iobase + reg, buf, count); -} - - -/* - * I know that polling/delaying is frowned upon. However, this procedure - * with polling is needed while downloading the firmware. At this stage, - * the hardware does unfortunately not create any interrupts. - * - * Fortunately, this function is never used once the firmware is in - * the card. :-) - * - * As a reference, see the "Firmware Specification v5.1", page 18 - * and 19. I did not follow their suggested timing to the word, - * but this works nice & fast anyway. - */ -static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg) -{ - int i; - - for (i = 0; i < 100000; i++) { - u8 val = if_cs_read8(card, addr); - if (val == reg) - return 0; - udelay(5); - } - return -ETIME; -} - - - -/* - * First the bitmasks for the host/card interrupt/status registers: - */ -#define IF_CS_BIT_TX 0x0001 -#define IF_CS_BIT_RX 0x0002 -#define IF_CS_BIT_COMMAND 0x0004 -#define IF_CS_BIT_RESP 0x0008 -#define IF_CS_BIT_EVENT 0x0010 -#define IF_CS_BIT_MASK 0x001f - - - -/* - * It's not really clear to me what the host status register is for. It - * needs to be set almost in union with "host int cause". The following - * bits from above are used: - * - * IF_CS_BIT_TX driver downloaded a data packet - * IF_CS_BIT_RX driver got a data packet - * IF_CS_BIT_COMMAND driver downloaded a command - * IF_CS_BIT_RESP not used (has some meaning with powerdown) - * IF_CS_BIT_EVENT driver read a host event - */ -#define IF_CS_HOST_STATUS 0x00000000 - -/* - * With the host int cause register can the host (that is, Linux) cause - * an interrupt in the firmware, to tell the firmware about those events: - * - * IF_CS_BIT_TX a data packet has been downloaded - * IF_CS_BIT_RX a received data packet has retrieved - * IF_CS_BIT_COMMAND a firmware block or a command has been downloaded - * IF_CS_BIT_RESP not used (has some meaning with powerdown) - * IF_CS_BIT_EVENT a host event (link lost etc) has been retrieved - */ -#define IF_CS_HOST_INT_CAUSE 0x00000002 - -/* - * The host int mask register is used to enable/disable interrupt. However, - * I have the suspicion that disabled interrupts are lost. - */ -#define IF_CS_HOST_INT_MASK 0x00000004 - -/* - * Used to send or receive data packets: - */ -#define IF_CS_WRITE 0x00000016 -#define IF_CS_WRITE_LEN 0x00000014 -#define IF_CS_READ 0x00000010 -#define IF_CS_READ_LEN 0x00000024 - -/* - * Used to send commands (and to send firmware block) and to - * receive command responses: - */ -#define IF_CS_CMD 0x0000001A -#define IF_CS_CMD_LEN 0x00000018 -#define IF_CS_RESP 0x00000012 -#define IF_CS_RESP_LEN 0x00000030 - -/* - * The card status registers shows what the card/firmware actually - * accepts: - * - * IF_CS_BIT_TX you may send a data packet - * IF_CS_BIT_RX you may retrieve a data packet - * IF_CS_BIT_COMMAND you may send a command - * IF_CS_BIT_RESP you may retrieve a command response - * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc) - * - * When reading this register several times, you will get back the same - * results --- with one exception: the IF_CS_BIT_EVENT clear itself - * automatically. - * - * Not that we don't rely on BIT_RX,_BIT_RESP or BIT_EVENT because - * we handle this via the card int cause register. - */ -#define IF_CS_CARD_STATUS 0x00000020 -#define IF_CS_CARD_STATUS_MASK 0x7f00 - -/* - * The card int cause register is used by the card/firmware to notify us - * about the following events: - * - * IF_CS_BIT_TX a data packet has successfully been sentx - * IF_CS_BIT_RX a data packet has been received and can be retrieved - * IF_CS_BIT_COMMAND not used - * IF_CS_BIT_RESP the firmware has a command response for us - * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc) - */ -#define IF_CS_CARD_INT_CAUSE 0x00000022 - -/* - * This is used to for handshaking with the card's bootloader/helper image - * to synchronize downloading of firmware blocks. - */ -#define IF_CS_SQ_READ_LOW 0x00000028 -#define IF_CS_SQ_HELPER_OK 0x10 - -/* - * The scratch register tells us ... - * - * IF_CS_SCRATCH_BOOT_OK the bootloader runs - * IF_CS_SCRATCH_HELPER_OK the helper firmware already runs - */ -#define IF_CS_SCRATCH 0x0000003F -#define IF_CS_SCRATCH_BOOT_OK 0x00 -#define IF_CS_SCRATCH_HELPER_OK 0x5a - -/* - * Used to detect ancient chips: - */ -#define IF_CS_PRODUCT_ID 0x0000001C -#define IF_CS_CF8385_B1_REV 0x12 -#define IF_CS_CF8381_B3_REV 0x04 -#define IF_CS_CF8305_B1_REV 0x03 - -/* - * Used to detect other cards than CF8385 since their revisions of silicon - * doesn't match those from CF8385, eg. CF8381 B3 works with this driver. - */ -#define CF8305_MANFID 0x02db -#define CF8305_CARDID 0x8103 -#define CF8381_MANFID 0x02db -#define CF8381_CARDID 0x6064 -#define CF8385_MANFID 0x02df -#define CF8385_CARDID 0x8103 - -/* - * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when - * that gets fixed. Currently there's no way to access it from the probe hook. - */ -static inline u32 get_model(u16 manf_id, u16 card_id) -{ - /* NOTE: keep in sync with if_cs_ids */ - if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID) - return MODEL_8305; - else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID) - return MODEL_8381; - else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID) - return MODEL_8385; - return MODEL_UNKNOWN; -} - -/********************************************************************/ -/* I/O and interrupt handling */ -/********************************************************************/ - -static inline void if_cs_enable_ints(struct if_cs_card *card) -{ - if_cs_write16(card, IF_CS_HOST_INT_MASK, 0); -} - -static inline void if_cs_disable_ints(struct if_cs_card *card) -{ - if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK); -} - -/* - * Called from if_cs_host_to_card to send a command to the hardware - */ -static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - int ret = -1; - int loops = 0; - - if_cs_disable_ints(card); - - /* Is hardware ready? */ - while (1) { - u16 status = if_cs_read16(card, IF_CS_CARD_STATUS); - if (status & IF_CS_BIT_COMMAND) - break; - if (++loops > 100) { - netdev_err(priv->dev, "card not ready for commands\n"); - goto done; - } - mdelay(1); - } - - if_cs_write16(card, IF_CS_CMD_LEN, nb); - - if_cs_write16_rep(card, IF_CS_CMD, buf, nb / 2); - /* Are we supposed to transfer an odd amount of bytes? */ - if (nb & 1) - if_cs_write8(card, IF_CS_CMD, buf[nb-1]); - - /* "Assert the download over interrupt command in the Host - * status register" */ - if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - - /* "Assert the download over interrupt command in the Card - * interrupt case register" */ - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - ret = 0; - -done: - if_cs_enable_ints(card); - return ret; -} - -/* - * Called from if_cs_host_to_card to send a data to the hardware - */ -static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - u16 status; - - if_cs_disable_ints(card); - - status = if_cs_read16(card, IF_CS_CARD_STATUS); - BUG_ON((status & IF_CS_BIT_TX) == 0); - - if_cs_write16(card, IF_CS_WRITE_LEN, nb); - - /* write even number of bytes, then odd byte if necessary */ - if_cs_write16_rep(card, IF_CS_WRITE, buf, nb / 2); - if (nb & 1) - if_cs_write8(card, IF_CS_WRITE, buf[nb-1]); - - if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX); - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX); - if_cs_enable_ints(card); -} - -/* - * Get the command result out of the card. - */ -static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) -{ - unsigned long flags; - int ret = -1; - u16 status; - - /* is hardware ready? */ - status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); - if ((status & IF_CS_BIT_RESP) == 0) { - netdev_err(priv->dev, "no cmd response in card\n"); - *len = 0; - goto out; - } - - *len = if_cs_read16(priv->card, IF_CS_RESP_LEN); - if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { - netdev_err(priv->dev, - "card cmd buffer has invalid # of bytes (%d)\n", - *len); - goto out; - } - - /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_RESP, data, *len/sizeof(u16)); - if (*len & 1) - data[*len-1] = if_cs_read8(priv->card, IF_CS_RESP); - - /* This is a workaround for a firmware that reports too much - * bytes */ - *len -= 8; - ret = 0; - - /* Clear this flag again */ - spin_lock_irqsave(&priv->driver_lock, flags); - priv->dnld_sent = DNLD_RES_RECEIVED; - spin_unlock_irqrestore(&priv->driver_lock, flags); - -out: - return ret; -} - -static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) -{ - struct sk_buff *skb = NULL; - u16 len; - u8 *data; - - len = if_cs_read16(priv->card, IF_CS_READ_LEN); - if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { - netdev_err(priv->dev, - "card data buffer has invalid # of bytes (%d)\n", - len); - priv->dev->stats.rx_dropped++; - goto dat_err; - } - - skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2); - if (!skb) - goto out; - skb_put(skb, len); - skb_reserve(skb, 2);/* 16 byte align */ - data = skb->data; - - /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16)); - if (len & 1) - data[len-1] = if_cs_read8(priv->card, IF_CS_READ); - -dat_err: - if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX); - if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX); - -out: - return skb; -} - -static irqreturn_t if_cs_interrupt(int irq, void *data) -{ - struct if_cs_card *card = data; - struct lbs_private *priv = card->priv; - u16 cause; - - /* Ask card interrupt cause register if there is something for us */ - cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE); - lbs_deb_cs("cause 0x%04x\n", cause); - - if (cause == 0) { - /* Not for us */ - return IRQ_NONE; - } - - if (cause == 0xffff) { - /* Read in junk, the card has probably been removed */ - card->priv->surpriseremoved = 1; - return IRQ_HANDLED; - } - - if (cause & IF_CS_BIT_RX) { - struct sk_buff *skb; - lbs_deb_cs("rx packet\n"); - skb = if_cs_receive_data(priv); - if (skb) - lbs_process_rxed_packet(priv, skb); - } - - if (cause & IF_CS_BIT_TX) { - lbs_deb_cs("tx done\n"); - lbs_host_to_card_done(priv); - } - - if (cause & IF_CS_BIT_RESP) { - unsigned long flags; - u8 i; - - lbs_deb_cs("cmd resp\n"); - spin_lock_irqsave(&priv->driver_lock, flags); - i = (priv->resp_idx == 0) ? 1 : 0; - spin_unlock_irqrestore(&priv->driver_lock, flags); - - BUG_ON(priv->resp_len[i]); - if_cs_receive_cmdres(priv, priv->resp_buf[i], - &priv->resp_len[i]); - - spin_lock_irqsave(&priv->driver_lock, flags); - lbs_notify_command_response(priv, i); - spin_unlock_irqrestore(&priv->driver_lock, flags); - } - - if (cause & IF_CS_BIT_EVENT) { - u16 status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); - if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, - IF_CS_BIT_EVENT); - lbs_queue_event(priv, (status & IF_CS_CARD_STATUS_MASK) >> 8); - } - - /* Clear interrupt cause */ - if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK); - - return IRQ_HANDLED; -} - - - - -/********************************************************************/ -/* Firmware */ -/********************************************************************/ - -/* - * Tries to program the helper firmware. - * - * Return 0 on success - */ -static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) -{ - int ret = 0; - int sent = 0; - u8 scratch; - - /* - * This is the only place where an unaligned register access happens on - * the CF8305 card, therefore for the sake of speed of the driver, we do - * the alignment correction here. - */ - if (card->align_regs) - scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8; - else - scratch = if_cs_read8(card, IF_CS_SCRATCH); - - /* "If the value is 0x5a, the firmware is already - * downloaded successfully" - */ - if (scratch == IF_CS_SCRATCH_HELPER_OK) - goto done; - - /* "If the value is != 00, it is invalid value of register */ - if (scratch != IF_CS_SCRATCH_BOOT_OK) { - ret = -ENODEV; - goto done; - } - - lbs_deb_cs("helper size %td\n", fw->size); - - /* "Set the 5 bytes of the helper image to 0" */ - /* Not needed, this contains an ARM branch instruction */ - - for (;;) { - /* "the number of bytes to send is 256" */ - int count = 256; - int remain = fw->size - sent; - - if (remain < count) - count = remain; - - /* - * "write the number of bytes to be sent to the I/O Command - * write length register" - */ - if_cs_write16(card, IF_CS_CMD_LEN, count); - - /* "write this to I/O Command port register as 16 bit writes */ - if (count) - if_cs_write16_rep(card, IF_CS_CMD, - &fw->data[sent], - count >> 1); - - /* - * "Assert the download over interrupt command in the Host - * status register" - */ - if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - - /* - * "Assert the download over interrupt command in the Card - * interrupt case register" - */ - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - - /* - * "The host polls the Card Status register ... for 50 ms before - * declaring a failure" - */ - ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, - IF_CS_BIT_COMMAND); - if (ret < 0) { - pr_err("can't download helper at 0x%x, ret %d\n", - sent, ret); - goto done; - } - - if (count == 0) - break; - - sent += count; - } - -done: - return ret; -} - - -static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) -{ - int ret = 0; - int retry = 0; - int len = 0; - int sent; - - lbs_deb_cs("fw size %td\n", fw->size); - - ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, - IF_CS_SQ_HELPER_OK); - if (ret < 0) { - pr_err("helper firmware doesn't answer\n"); - goto done; - } - - for (sent = 0; sent < fw->size; sent += len) { - len = if_cs_read16(card, IF_CS_SQ_READ_LOW); - if (len & 1) { - retry++; - pr_info("odd, need to retry this firmware block\n"); - } else { - retry = 0; - } - - if (retry > 20) { - pr_err("could not download firmware\n"); - ret = -ENODEV; - goto done; - } - if (retry) { - sent -= len; - } - - - if_cs_write16(card, IF_CS_CMD_LEN, len); - - if_cs_write16_rep(card, IF_CS_CMD, - &fw->data[sent], - (len+1) >> 1); - if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - - ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, - IF_CS_BIT_COMMAND); - if (ret < 0) { - pr_err("can't download firmware at 0x%x\n", sent); - goto done; - } - } - - ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a); - if (ret < 0) - pr_err("firmware download failed\n"); - -done: - return ret; -} - -static void if_cs_prog_firmware(struct lbs_private *priv, int ret, - const struct firmware *helper, - const struct firmware *mainfw) -{ - struct if_cs_card *card = priv->card; - - if (ret) { - pr_err("failed to find firmware (%d)\n", ret); - return; - } - - /* Load the firmware */ - ret = if_cs_prog_helper(card, helper); - if (ret == 0 && (card->model != MODEL_8305)) - ret = if_cs_prog_real(card, mainfw); - if (ret) - return; - - /* Now actually get the IRQ */ - ret = request_irq(card->p_dev->irq, if_cs_interrupt, - IRQF_SHARED, DRV_NAME, card); - if (ret) { - pr_err("error in request_irq\n"); - return; - } - - /* - * Clear any interrupt cause that happened while sending - * firmware/initializing card - */ - if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); - if_cs_enable_ints(card); - - /* And finally bring the card up */ - priv->fw_ready = 1; - if (lbs_start_card(priv) != 0) { - pr_err("could not activate card\n"); - free_irq(card->p_dev->irq, card); - } -} - - -/********************************************************************/ -/* Callback functions for libertas.ko */ -/********************************************************************/ - -/* Send commands or data packets to the card */ -static int if_cs_host_to_card(struct lbs_private *priv, - u8 type, - u8 *buf, - u16 nb) -{ - int ret = -1; - - switch (type) { - case MVMS_DAT: - priv->dnld_sent = DNLD_DATA_SENT; - if_cs_send_data(priv, buf, nb); - ret = 0; - break; - case MVMS_CMD: - priv->dnld_sent = DNLD_CMD_SENT; - ret = if_cs_send_cmd(priv, buf, nb); - break; - default: - netdev_err(priv->dev, "%s: unsupported type %d\n", - __func__, type); - } - - return ret; -} - - -static void if_cs_release(struct pcmcia_device *p_dev) -{ - struct if_cs_card *card = p_dev->priv; - - free_irq(p_dev->irq, card); - pcmcia_disable_device(p_dev); - if (card->iobase) - ioport_unmap(card->iobase); -} - - -static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - if (p_dev->resource[1]->end) { - pr_err("wrong CIS (check number of IO windows)\n"); - return -ENODEV; - } - - /* This reserves IO space but doesn't actually enable it */ - return pcmcia_request_io(p_dev); -} - -static int if_cs_probe(struct pcmcia_device *p_dev) -{ - int ret = -ENOMEM; - unsigned int prod_id; - struct lbs_private *priv; - struct if_cs_card *card; - - card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL); - if (!card) - goto out; - - card->p_dev = p_dev; - p_dev->priv = card; - - p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) { - pr_err("error in pcmcia_loop_config\n"); - goto out1; - } - - /* - * Allocate an interrupt line. Note that this does not assign - * a handler to the interrupt, unless the 'Handler' member of - * the irq structure is initialized. - */ - if (!p_dev->irq) - goto out1; - - /* Initialize io access */ - card->iobase = ioport_map(p_dev->resource[0]->start, - resource_size(p_dev->resource[0])); - if (!card->iobase) { - pr_err("error in ioport_map\n"); - ret = -EIO; - goto out1; - } - - ret = pcmcia_enable_device(p_dev); - if (ret) { - pr_err("error in pcmcia_enable_device\n"); - goto out2; - } - - /* Finally, report what we've done */ - lbs_deb_cs("irq %d, io %pR", p_dev->irq, p_dev->resource[0]); - - /* - * Most of the libertas cards can do unaligned register access, but some - * weird ones cannot. That's especially true for the CF8305 card. - */ - card->align_regs = false; - - card->model = get_model(p_dev->manf_id, p_dev->card_id); - if (card->model == MODEL_UNKNOWN) { - pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n", - p_dev->manf_id, p_dev->card_id); - ret = -ENODEV; - goto out2; - } - - /* Check if we have a current silicon */ - prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); - if (card->model == MODEL_8305) { - card->align_regs = true; - if (prod_id < IF_CS_CF8305_B1_REV) { - pr_err("8305 rev B0 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - } - - if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) { - pr_err("8381 rev B2 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - - if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) { - pr_err("8385 rev B0 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - - /* Make this card known to the libertas driver */ - priv = lbs_add_card(card, &p_dev->dev); - if (IS_ERR(priv)) { - ret = PTR_ERR(priv); - goto out2; - } - - /* Set up fields in lbs_private */ - card->priv = priv; - priv->card = card; - priv->hw_host_to_card = if_cs_host_to_card; - priv->enter_deep_sleep = NULL; - priv->exit_deep_sleep = NULL; - priv->reset_deep_sleep_wakeup = NULL; - - /* Get firmware */ - ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table, - if_cs_prog_firmware); - if (ret) { - pr_err("failed to find firmware (%d)\n", ret); - goto out3; - } - - goto out; - -out3: - lbs_remove_card(priv); -out2: - ioport_unmap(card->iobase); -out1: - pcmcia_disable_device(p_dev); -out: - return ret; -} - - -static void if_cs_detach(struct pcmcia_device *p_dev) -{ - struct if_cs_card *card = p_dev->priv; - - lbs_stop_card(card->priv); - lbs_remove_card(card->priv); - if_cs_disable_ints(card); - if_cs_release(p_dev); - kfree(card); -} - - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -static const struct pcmcia_device_id if_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID), - PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), - PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), - /* NOTE: keep in sync with get_model() */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); - -static struct pcmcia_driver lbs_driver = { - .owner = THIS_MODULE, - .name = DRV_NAME, - .probe = if_cs_probe, - .remove = if_cs_detach, - .id_table = if_cs_ids, -}; -module_pcmcia_driver(lbs_driver); diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 3756aa247e..9eff29a255 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -1244,8 +1244,6 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, u8 *pbuf, u32 upld_len) { struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf; - struct mwifiex_private *priv = - mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); uint16_t result = le16_to_cpu(cmd->result); uint16_t command = le16_to_cpu(cmd->command); uint16_t seq_num = le16_to_cpu(cmd->seq_num); @@ -1260,12 +1258,6 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n", command, result, le16_to_cpu(cmd->size), seq_num); - /* Get BSS number and corresponding priv */ - priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), - HostCmd_GET_BSS_TYPE(seq_num)); - if (!priv) - priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - /* Update sequence number */ seq_num = HostCmd_GET_SEQ_NO(seq_num); /* Clear RET_BIT from HostCmd */ diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c index a6e254a118..9d98a1908d 100644 --- a/drivers/net/wireless/marvell/mwifiex/join.c +++ b/drivers/net/wireless/marvell/mwifiex/join.c @@ -1427,8 +1427,8 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv, /* Check if the requested SSID is already joined */ if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len && - !mwifiex_ssid_cmp(&bss_desc->ssid, - &priv->curr_bss_params.bss_descriptor.ssid) && + cfg80211_ssid_eq(&bss_desc->ssid, + &priv->curr_bss_params.bss_descriptor.ssid) && (priv->curr_bss_params.bss_descriptor.bss_mode == NL80211_IFTYPE_ADHOC)) { mwifiex_dbg(priv->adapter, INFO, diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index d263eae607..318b42b189 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -1152,7 +1152,6 @@ void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, struct cmd_ctrl_node *cmd_node); int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); -s32 mwifiex_ssid_cmp(struct cfg80211_ssid *ssid1, struct cfg80211_ssid *ssid2); int mwifiex_associate(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 72904c2754..a2ddac363b 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -180,17 +180,6 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) } /* - * This function compares two SSIDs and checks if they match. - */ -s32 -mwifiex_ssid_cmp(struct cfg80211_ssid *ssid1, struct cfg80211_ssid *ssid2) -{ - if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len)) - return -1; - return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len); -} - -/* * This function checks if wapi is enabled in driver and scanned network is * compatible with it. */ diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index a2ad2b53f0..32a27fad7b 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -345,8 +345,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, /* Adhoc mode */ /* If the requested SSID matches current SSID, return */ if (bss_desc && bss_desc->ssid.ssid_len && - (!mwifiex_ssid_cmp(&priv->curr_bss_params.bss_descriptor. - ssid, &bss_desc->ssid))) { + cfg80211_ssid_eq(&priv->curr_bss_params.bss_descriptor.ssid, + &bss_desc->ssid)) { ret = 0; goto done; } diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index d3ab9572e7..515e6db410 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -687,7 +687,7 @@ static struct usb_driver mwifiex_usb_driver = { .suspend = mwifiex_usb_suspend, .resume = mwifiex_usb_resume, .soft_unbind = 1, - .drvwrap.driver = { + .driver = { .coredump = mwifiex_usb_coredump, }, }; diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 68ad915203..00230f1062 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -9,11 +9,11 @@ #if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) -#define Q_READ(_dev, _q, _field) ({ \ +#define Q_READ(_q, _field) ({ \ u32 _offset = offsetof(struct mt76_queue_regs, _field); \ u32 _val; \ if ((_q)->flags & MT_QFLAG_WED) \ - _val = mtk_wed_device_reg_read(&(_dev)->mmio.wed, \ + _val = mtk_wed_device_reg_read((_q)->wed, \ ((_q)->wed_regs + \ _offset)); \ else \ @@ -21,10 +21,10 @@ _val; \ }) -#define Q_WRITE(_dev, _q, _field, _val) do { \ +#define Q_WRITE(_q, _field, _val) do { \ u32 _offset = offsetof(struct mt76_queue_regs, _field); \ if ((_q)->flags & MT_QFLAG_WED) \ - mtk_wed_device_reg_write(&(_dev)->mmio.wed, \ + mtk_wed_device_reg_write((_q)->wed, \ ((_q)->wed_regs + _offset), \ _val); \ else \ @@ -33,8 +33,8 @@ #else -#define Q_READ(_dev, _q, _field) readl(&(_q)->regs->_field) -#define Q_WRITE(_dev, _q, _field, _val) writel(_val, &(_q)->regs->_field) +#define Q_READ(_q, _field) readl(&(_q)->regs->_field) +#define Q_WRITE(_q, _field, _val) writel(_val, &(_q)->regs->_field) #endif @@ -188,41 +188,67 @@ EXPORT_SYMBOL_GPL(mt76_free_pending_rxwi); static void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) { - Q_WRITE(dev, q, desc_base, q->desc_dma); - Q_WRITE(dev, q, ring_size, q->ndesc); - q->head = Q_READ(dev, q, dma_idx); + Q_WRITE(q, desc_base, q->desc_dma); + if (q->flags & MT_QFLAG_WED_RRO_EN) + Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc); + else + Q_WRITE(q, ring_size, q->ndesc); + q->head = Q_READ(q, dma_idx); q->tail = q->head; } static void -mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) +__mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, + bool reset_idx) { - int i; - if (!q || !q->ndesc) return; - /* clear descriptors */ - for (i = 0; i < q->ndesc; i++) - q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + if (!mt76_queue_is_wed_rro_ind(q)) { + int i; + + /* clear descriptors */ + for (i = 0; i < q->ndesc; i++) + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + } - Q_WRITE(dev, q, cpu_idx, 0); - Q_WRITE(dev, q, dma_idx, 0); + if (reset_idx) { + Q_WRITE(q, cpu_idx, 0); + Q_WRITE(q, dma_idx, 0); + } mt76_dma_sync_idx(dev, q); } +static void +mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) +{ + __mt76_dma_queue_reset(dev, q, true); +} + static int mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_buf *buf, void *data) { - struct mt76_desc *desc = &q->desc[q->head]; struct mt76_queue_entry *entry = &q->entry[q->head]; struct mt76_txwi_cache *txwi = NULL; - u32 buf1 = 0, ctrl; + struct mt76_desc *desc; int idx = q->head; + u32 buf1 = 0, ctrl; int rx_token; + if (mt76_queue_is_wed_rro_ind(q)) { + struct mt76_wed_rro_desc *rro_desc; + + rro_desc = (struct mt76_wed_rro_desc *)q->desc; + data = &rro_desc[q->head]; + goto done; + } + + desc = &q->desc[q->head]; ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + buf1 = FIELD_PREP(MT_DMA_CTL_SDP0_H, buf->addr >> 32); +#endif if (mt76_queue_is_wed_rx(q)) { txwi = mt76_get_rxwi(dev); @@ -244,6 +270,7 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); WRITE_ONCE(desc->info, 0); +done: entry->dma_addr[0] = buf->addr; entry->dma_len[0] = buf->len; entry->txwi = txwi; @@ -288,11 +315,18 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q, entry->dma_len[0] = buf[0].len; ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + info |= FIELD_PREP(MT_DMA_CTL_SDP0_H, buf[0].addr >> 32); +#endif if (i < nbufs - 1) { entry->dma_addr[1] = buf[1].addr; entry->dma_len[1] = buf[1].len; buf1 = buf[1].addr; ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + info |= FIELD_PREP(MT_DMA_CTL_SDP1_H, + buf[1].addr >> 32); +#endif if (buf[1].skip_unmap) entry->skip_buf1 = true; } @@ -343,7 +377,7 @@ static void mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q) { wmb(); - Q_WRITE(dev, q, cpu_idx, q->head); + Q_WRITE(q, cpu_idx, q->head); } static void @@ -359,7 +393,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) if (flush) last = -1; else - last = Q_READ(dev, q, dma_idx); + last = Q_READ(q, dma_idx); while (q->queued > 0 && q->tail != last) { mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry); @@ -371,7 +405,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) } if (!flush && q->tail == last) - last = Q_READ(dev, q, dma_idx); + last = Q_READ(q, dma_idx); } spin_unlock_bh(&q->cleanup_lock); @@ -392,19 +426,26 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, { struct mt76_queue_entry *e = &q->entry[idx]; struct mt76_desc *desc = &q->desc[idx]; - void *buf; + u32 ctrl, desc_info, buf1; + void *buf = e->buf; + + if (mt76_queue_is_wed_rro_ind(q)) + goto done; + ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); if (len) { - u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); *len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl); *more = !(ctrl & MT_DMA_CTL_LAST_SEC0); } + desc_info = le32_to_cpu(desc->info); if (info) - *info = le32_to_cpu(desc->info); + *info = desc_info; + + buf1 = le32_to_cpu(desc->buf1); + mt76_dma_should_drop_buf(drop, ctrl, buf1, desc_info); if (mt76_queue_is_wed_rx(q)) { - u32 buf1 = le32_to_cpu(desc->buf1); u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1); struct mt76_txwi_cache *t = mt76_rx_token_release(dev, token); @@ -420,23 +461,16 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, t->ptr = NULL; mt76_put_rxwi(dev, t); - - if (drop) { - u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); - - *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | - MT_DMA_CTL_DROP)); - + if (drop) *drop |= !!(buf1 & MT_DMA_CTL_WO_DROP); - } } else { - buf = e->buf; - e->buf = NULL; dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0], SKB_WITH_OVERHEAD(q->buf_size), page_pool_get_dma_dir(q->page_pool)); } +done: + e->buf = NULL; return buf; } @@ -450,11 +484,16 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush, if (!q->queued) return NULL; - if (flush) - q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); - else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) + if (mt76_queue_is_wed_rro_data(q)) return NULL; + if (!mt76_queue_is_wed_rro_ind(q)) { + if (flush) + q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); + else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) + return NULL; + } + q->tail = (q->tail + 1) % q->ndesc; q->queued--; @@ -606,11 +645,14 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, spin_lock_bh(&q->lock); while (q->queued < q->ndesc - 1) { + struct mt76_queue_buf qbuf = {}; enum dma_data_direction dir; - struct mt76_queue_buf qbuf; dma_addr_t addr; int offset; - void *buf; + void *buf = NULL; + + if (mt76_queue_is_wed_rro_ind(q)) + goto done; buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); if (!buf) @@ -621,6 +663,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, dma_sync_single_for_device(dev->dma_dev, addr, len, dir); qbuf.addr = addr + q->buf_offset; +done: qbuf.len = len - q->buf_offset; qbuf.skip_unmap = false; if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) { @@ -630,7 +673,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, frames++; } - if (frames) + if (frames || mt76_queue_is_wed_rx(q)) mt76_dma_kick_queue(dev, q); spin_unlock_bh(&q->lock); @@ -641,15 +684,14 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) { #ifdef CONFIG_NET_MEDIATEK_SOC_WED - struct mtk_wed_device *wed = &dev->mmio.wed; - int ret, type, ring; - u8 flags; + int ret = 0, type, ring; + u16 flags; if (!q || !q->ndesc) return -EINVAL; flags = q->flags; - if (!mtk_wed_device_active(wed)) + if (!q->wed || !mtk_wed_device_active(q->wed)) q->flags &= ~MT_QFLAG_WED; if (!(q->flags & MT_QFLAG_WED)) @@ -660,29 +702,52 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) switch (type) { case MT76_WED_Q_TX: - ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs, reset); + ret = mtk_wed_device_tx_ring_setup(q->wed, ring, q->regs, + reset); if (!ret) - q->wed_regs = wed->tx_ring[ring].reg_base; + q->wed_regs = q->wed->tx_ring[ring].reg_base; break; case MT76_WED_Q_TXFREE: /* WED txfree queue needs ring to be initialized before setup */ q->flags = 0; mt76_dma_queue_reset(dev, q); mt76_dma_rx_fill(dev, q, false); - q->flags = flags; - ret = mtk_wed_device_txfree_ring_setup(wed, q->regs); + ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs); if (!ret) - q->wed_regs = wed->txfree_ring.reg_base; + q->wed_regs = q->wed->txfree_ring.reg_base; break; case MT76_WED_Q_RX: - ret = mtk_wed_device_rx_ring_setup(wed, ring, q->regs, reset); + ret = mtk_wed_device_rx_ring_setup(q->wed, ring, q->regs, + reset); if (!ret) - q->wed_regs = wed->rx_ring[ring].reg_base; + q->wed_regs = q->wed->rx_ring[ring].reg_base; + break; + case MT76_WED_RRO_Q_DATA: + q->flags &= ~MT_QFLAG_WED; + __mt76_dma_queue_reset(dev, q, false); + mtk_wed_device_rro_rx_ring_setup(q->wed, ring, q->regs); + q->head = q->ndesc - 1; + q->queued = q->head; + break; + case MT76_WED_RRO_Q_MSDU_PG: + q->flags &= ~MT_QFLAG_WED; + __mt76_dma_queue_reset(dev, q, false); + mtk_wed_device_msdu_pg_rx_ring_setup(q->wed, ring, q->regs); + q->head = q->ndesc - 1; + q->queued = q->head; + break; + case MT76_WED_RRO_Q_IND: + q->flags &= ~MT_QFLAG_WED; + mt76_dma_queue_reset(dev, q); + mt76_dma_rx_fill(dev, q, false); + mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs); break; default: ret = -EINVAL; + break; } + q->flags = flags; return ret; #else @@ -706,11 +771,26 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, q->buf_size = bufsize; q->hw_idx = idx; - size = q->ndesc * sizeof(struct mt76_desc); - q->desc = dmam_alloc_coherent(dev->dma_dev, size, &q->desc_dma, GFP_KERNEL); + size = mt76_queue_is_wed_rro_ind(q) ? sizeof(struct mt76_wed_rro_desc) + : sizeof(struct mt76_desc); + q->desc = dmam_alloc_coherent(dev->dma_dev, q->ndesc * size, + &q->desc_dma, GFP_KERNEL); if (!q->desc) return -ENOMEM; + if (mt76_queue_is_wed_rro_ind(q)) { + struct mt76_wed_rro_desc *rro_desc; + int i; + + rro_desc = (struct mt76_wed_rro_desc *)q->desc; + for (i = 0; i < q->ndesc; i++) { + struct mt76_wed_rro_ind *cmd; + + cmd = (struct mt76_wed_rro_ind *)&rro_desc[i]; + cmd->magic_cnt = MT_DMA_WED_IND_CMD_CNT - 1; + } + } + size = q->ndesc * sizeof(*q->entry); q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL); if (!q->entry) @@ -724,8 +804,13 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, if (ret) return ret; - if (q->flags != MT_WED_Q_TXFREE) - mt76_dma_queue_reset(dev, q); + if (mtk_wed_device_active(&dev->mmio.wed)) { + if ((mtk_wed_get_rx_capa(&dev->mmio.wed) && mt76_queue_is_wed_rro(q)) || + mt76_queue_is_wed_tx_free(q)) + return 0; + } + + mt76_dma_queue_reset(dev, q); return 0; } @@ -747,7 +832,8 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) if (!buf) break; - mt76_put_page_pool_buf(buf, false); + if (!mt76_queue_is_wed_rro(q)) + mt76_put_page_pool_buf(buf, false); } while (1); spin_lock_bh(&q->lock); @@ -763,22 +849,31 @@ static void mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) { struct mt76_queue *q = &dev->q_rx[qid]; - int i; if (!q->ndesc) return; - for (i = 0; i < q->ndesc; i++) - q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + if (!mt76_queue_is_wed_rro_ind(q)) { + int i; + + for (i = 0; i < q->ndesc; i++) + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + } mt76_dma_rx_cleanup(dev, q); /* reset WED rx queues */ mt76_dma_wed_setup(dev, q, true); - if (q->flags != MT_WED_Q_TXFREE) { - mt76_dma_sync_idx(dev, q); - mt76_dma_rx_fill(dev, q, false); - } + + if (mt76_queue_is_wed_tx_free(q)) + return; + + if (mtk_wed_device_active(&dev->mmio.wed) && + mt76_queue_is_wed_rro(q)) + return; + + mt76_dma_sync_idx(dev, q); + mt76_dma_rx_fill(dev, q, false); } static void @@ -819,8 +914,8 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) bool more; if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) && - q->flags == MT_WED_Q_TXFREE) { - dma_idx = Q_READ(dev, q, dma_idx); + mt76_queue_is_wed_tx_free(q)) { + dma_idx = Q_READ(q, dma_idx); check_ddone = true; } @@ -830,7 +925,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) if (check_ddone) { if (q->tail == dma_idx) - dma_idx = Q_READ(dev, q, dma_idx); + dma_idx = Q_READ(q, dma_idx); if (q->tail == dma_idx) break; @@ -959,6 +1054,20 @@ void mt76_dma_attach(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_dma_attach); +void mt76_dma_wed_reset(struct mt76_dev *dev) +{ + struct mt76_mmio *mmio = &dev->mmio; + + if (!test_bit(MT76_STATE_WED_RESET, &dev->phy.state)) + return; + + complete(&mmio->wed_reset); + + if (!wait_for_completion_timeout(&mmio->wed_reset_complete, 3 * HZ)) + dev_err(dev->dev, "wed reset complete timeout\n"); +} +EXPORT_SYMBOL_GPL(mt76_dma_wed_reset); + void mt76_dma_cleanup(struct mt76_dev *dev) { int i; @@ -983,16 +1092,23 @@ void mt76_dma_cleanup(struct mt76_dev *dev) mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; + if (mtk_wed_device_active(&dev->mmio.wed) && + mt76_queue_is_wed_rro(q)) + continue; + netif_napi_del(&dev->napi[i]); mt76_dma_rx_cleanup(dev, q); page_pool_destroy(q->page_pool); } - mt76_free_pending_txwi(dev); - mt76_free_pending_rxwi(dev); - if (mtk_wed_device_active(&dev->mmio.wed)) mtk_wed_device_detach(&dev->mmio.wed); + + if (mtk_wed_device_active(&dev->mmio.wed_hif2)) + mtk_wed_device_detach(&dev->mmio.wed_hif2); + + mt76_free_pending_txwi(dev); + mt76_free_pending_rxwi(dev); } EXPORT_SYMBOL_GPL(mt76_dma_cleanup); diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index 1b090d78cd..c479cc6388 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -19,12 +19,23 @@ #define MT_DMA_CTL_TO_HOST_A BIT(12) #define MT_DMA_CTL_DROP BIT(14) #define MT_DMA_CTL_TOKEN GENMASK(31, 16) +#define MT_DMA_CTL_SDP1_H GENMASK(19, 16) +#define MT_DMA_CTL_SDP0_H GENMASK(3, 0) #define MT_DMA_CTL_WO_DROP BIT(8) #define MT_DMA_PPE_CPU_REASON GENMASK(15, 11) #define MT_DMA_PPE_ENTRY GENMASK(30, 16) +#define MT_DMA_INFO_DMA_FRAG BIT(9) #define MT_DMA_INFO_PPE_VLD BIT(31) +#define MT_DMA_CTL_PN_CHK_FAIL BIT(13) +#define MT_DMA_CTL_VER_MASK BIT(7) + +#define MT_DMA_RRO_EN BIT(13) + +#define MT_DMA_WED_IND_CMD_CNT 8 +#define MT_DMA_WED_IND_REASON GENMASK(15, 12) + #define MT_DMA_HDR_LEN 4 #define MT_RX_INFO_LEN 4 #define MT_FCE_INFO_LEN 4 @@ -37,6 +48,11 @@ struct mt76_desc { __le32 info; } __packed __aligned(4); +struct mt76_wed_rro_desc { + __le32 buf0; + __le32 buf1; +} __packed __aligned(4); + enum mt76_qsel { MT_QSEL_MGMT, MT_QSEL_HCCA, @@ -54,9 +70,47 @@ enum mt76_mcu_evt_type { EVT_EVENT_DFS_DETECT_RSP, }; +enum mt76_dma_wed_ind_reason { + MT_DMA_WED_IND_REASON_NORMAL, + MT_DMA_WED_IND_REASON_REPEAT, + MT_DMA_WED_IND_REASON_OLDPKT, +}; + int mt76_dma_rx_poll(struct napi_struct *napi, int budget); void mt76_dma_attach(struct mt76_dev *dev); void mt76_dma_cleanup(struct mt76_dev *dev); int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset); +void mt76_dma_wed_reset(struct mt76_dev *dev); + +static inline void +mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) +{ + dev->queue_ops->reset_q(dev, q); + if (mtk_wed_device_active(&dev->mmio.wed)) + mt76_dma_wed_setup(dev, q, true); +} + +static inline void +mt76_dma_should_drop_buf(bool *drop, u32 ctrl, u32 buf1, u32 info) +{ + if (!drop) + return; + + *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | MT_DMA_CTL_DROP)); + if (!(ctrl & MT_DMA_CTL_VER_MASK)) + return; + + switch (FIELD_GET(MT_DMA_WED_IND_REASON, buf1)) { + case MT_DMA_WED_IND_REASON_REPEAT: + *drop = true; + break; + case MT_DMA_WED_IND_REASON_OLDPKT: + *drop = !(info & MT_DMA_INFO_DMA_FRAG); + break; + default: + *drop = !!(ctrl & MT_DMA_CTL_PN_CHK_FAIL); + break; + } +} #endif diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 50820fe00b..0bc66cc19a 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -28,7 +28,7 @@ static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len) return 0; } -static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len) +int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len) { #ifdef CONFIG_MTD struct device_node *np = dev->dev->of_node; @@ -105,8 +105,10 @@ out_put_node: return -ENOENT; #endif } +EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd); -static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int len) +int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, + const char *cell_name, int len) { struct device_node *np = dev->dev->of_node; struct nvmem_cell *cell; @@ -114,7 +116,7 @@ static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int le size_t retlen; int ret = 0; - cell = of_nvmem_cell_get(np, "eeprom"); + cell = of_nvmem_cell_get(np, cell_name); if (IS_ERR(cell)) return PTR_ERR(cell); @@ -136,8 +138,9 @@ exit: return ret; } +EXPORT_SYMBOL_GPL(mt76_get_of_data_from_nvmem); -int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) +static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len) { struct device_node *np = dev->dev->of_node; int ret; @@ -149,13 +152,12 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) if (!ret) return 0; - ret = mt76_get_of_epprom_from_mtd(dev, eep, offset, len); + ret = mt76_get_of_data_from_mtd(dev, eep, 0, len); if (!ret) return 0; - return mt76_get_of_eeprom_from_nvmem(dev, eep, len); + return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len); } -EXPORT_SYMBOL_GPL(mt76_get_of_eeprom); void mt76_eeprom_override(struct mt76_phy *phy) @@ -379,7 +381,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, if (!np) return target_power; - txs_delta = mt76_get_txs_delta(np, hweight8(phy->antenna_mask)); + txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask)); val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val, @@ -412,6 +414,6 @@ mt76_eeprom_init(struct mt76_dev *dev, int len) if (!dev->eeprom.data) return -ENOMEM; - return !mt76_get_of_eeprom(dev, dev->eeprom.data, 0, len); + return !mt76_get_of_eeprom(dev, dev->eeprom.data, len); } EXPORT_SYMBOL_GPL(mt76_eeprom_init); diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 51a767121b..8a3a90d1bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -197,10 +197,33 @@ static int mt76_led_init(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; struct ieee80211_hw *hw = phy->hw; + struct device_node *np = dev->dev->of_node; if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) return 0; + np = of_get_child_by_name(np, "led"); + if (np) { + if (!of_device_is_available(np)) { + of_node_put(np); + dev_info(dev->dev, + "led registration was explicitly disabled by dts\n"); + return 0; + } + + if (phy == &dev->phy) { + int led_pin; + + if (!of_property_read_u32(np, "led-sources", &led_pin)) + phy->leds.pin = led_pin; + + phy->leds.al = + of_property_read_bool(np, "led-active-low"); + } + + of_node_put(np); + } + snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s", wiphy_name(hw->wiphy)); @@ -211,20 +234,8 @@ static int mt76_led_init(struct mt76_phy *phy) mt76_tpt_blink, ARRAY_SIZE(mt76_tpt_blink)); - if (phy == &dev->phy) { - struct device_node *np = dev->dev->of_node; - - np = of_get_child_by_name(np, "led"); - if (np) { - int led_pin; - - if (!of_property_read_u32(np, "led-sources", &led_pin)) - phy->leds.pin = led_pin; - phy->leds.al = of_property_read_bool(np, - "led-active-low"); - of_node_put(np); - } - } + dev_info(dev->dev, + "registering led '%s'\n", phy->leds.name); return led_classdev_register(dev->dev, &phy->leds.cdev); } @@ -1537,7 +1548,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) { struct mt76_phy *phy = hw->priv; - int n_chains = hweight8(phy->antenna_mask); + int n_chains = hweight16(phy->chainmask); int delta = mt76_tx_power_nss_delta(n_chains); *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); @@ -1725,7 +1736,7 @@ EXPORT_SYMBOL_GPL(mt76_get_antenna); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, - int ring_base, u32 flags) + int ring_base, void *wed, u32 flags) { struct mt76_queue *hwq; int err; @@ -1735,6 +1746,7 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, return ERR_PTR(-ENOMEM); hwq->flags = flags; + hwq->wed = wed; err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); if (err < 0) @@ -1842,3 +1854,19 @@ enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) return MT_DFS_STATE_ACTIVE; } EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data) +{ + struct mt76_phy *phy = hw->priv; + struct mtk_wed_device *wed = &phy->dev->mmio.wed; + + if (!mtk_wed_device_active(wed)) + return -EOPNOTSUPP; + + return mtk_wed_device_setup_tc(wed, netdev, type, type_data); +} +EXPORT_SYMBOL_GPL(mt76_net_setup_tc); +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 86e3d2ac4d..c3e0e23e01 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -4,6 +4,7 @@ */ #include "mt76.h" +#include "dma.h" #include "trace.h" static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset) @@ -84,6 +85,113 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, } EXPORT_SYMBOL_GPL(mt76_set_irq_mask); +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + int i; + + for (i = 0; i < dev->rx_token_size; i++) { + struct mt76_txwi_cache *t; + + t = mt76_rx_token_release(dev, i); + if (!t || !t->ptr) + continue; + + mt76_put_page_pool_buf(t->ptr, false); + t->ptr = NULL; + + mt76_put_rxwi(dev, t); + } + + mt76_free_pending_rxwi(dev); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_release_rx_buf); + +u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; + struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; + int i, len = SKB_WITH_OVERHEAD(q->buf_size); + struct mt76_txwi_cache *t = NULL; + + for (i = 0; i < size; i++) { + enum dma_data_direction dir; + dma_addr_t addr; + u32 offset; + int token; + void *buf; + + t = mt76_get_rxwi(dev); + if (!t) + goto unmap; + + buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); + if (!buf) + goto unmap; + + addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; + dir = page_pool_get_dma_dir(q->page_pool); + dma_sync_single_for_device(dev->dma_dev, addr, len, dir); + + desc->buf0 = cpu_to_le32(addr); + token = mt76_rx_token_consume(dev, buf, t, addr); + if (token < 0) { + mt76_put_page_pool_buf(buf, false); + goto unmap; + } + + token = FIELD_PREP(MT_DMA_CTL_TOKEN, token); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + token |= FIELD_PREP(MT_DMA_CTL_SDP0_H, addr >> 32); +#endif + desc->token |= cpu_to_le32(token); + desc++; + } + + return 0; + +unmap: + if (t) + mt76_put_rxwi(dev, t); + mt76_mmio_wed_release_rx_buf(wed); + + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_init_rx_buf); + +int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + spin_lock_bh(&dev->token_lock); + dev->token_size = wed->wlan.token_start; + spin_unlock_bh(&dev->token_lock); + + return !wait_event_timeout(dev->tx_wait, !dev->wed_token_count, HZ); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_enable); + +void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + spin_lock_bh(&dev->token_lock); + dev->token_size = dev->drv->token_size; + spin_unlock_bh(&dev->token_lock); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_disable); + +void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + complete(&dev->mmio.wed_reset_complete); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_reset_complete); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) { static const struct mt76_bus_ops mt76_mmio_ops = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a17b2fbd69..b20c34d5a0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -29,15 +29,22 @@ #define MT76_TOKEN_FREE_THR 64 #define MT_QFLAG_WED_RING GENMASK(1, 0) -#define MT_QFLAG_WED_TYPE GENMASK(3, 2) -#define MT_QFLAG_WED BIT(4) +#define MT_QFLAG_WED_TYPE GENMASK(4, 2) +#define MT_QFLAG_WED BIT(5) +#define MT_QFLAG_WED_RRO BIT(6) +#define MT_QFLAG_WED_RRO_EN BIT(7) #define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \ FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \ FIELD_PREP(MT_QFLAG_WED_RING, _n)) +#define __MT_WED_RRO_Q(_type, _n) (MT_QFLAG_WED_RRO | __MT_WED_Q(_type, _n)) + #define MT_WED_Q_TX(_n) __MT_WED_Q(MT76_WED_Q_TX, _n) #define MT_WED_Q_RX(_n) __MT_WED_Q(MT76_WED_Q_RX, _n) #define MT_WED_Q_TXFREE __MT_WED_Q(MT76_WED_Q_TXFREE, 0) +#define MT_WED_RRO_Q_DATA(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_DATA, _n) +#define MT_WED_RRO_Q_MSDU_PG(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_MSDU_PG, _n) +#define MT_WED_RRO_Q_IND __MT_WED_RRO_Q(MT76_WED_RRO_Q_IND, 0) struct mt76_dev; struct mt76_phy; @@ -59,6 +66,9 @@ enum mt76_wed_type { MT76_WED_Q_TX, MT76_WED_Q_TXFREE, MT76_WED_Q_RX, + MT76_WED_RRO_Q_DATA, + MT76_WED_RRO_Q_MSDU_PG, + MT76_WED_RRO_Q_IND, }; struct mt76_bus_ops { @@ -107,6 +117,16 @@ enum mt76_rxq_id { MT_RXQ_MAIN_WA, MT_RXQ_BAND2, MT_RXQ_BAND2_WA, + MT_RXQ_RRO_BAND0, + MT_RXQ_RRO_BAND1, + MT_RXQ_RRO_BAND2, + MT_RXQ_MSDU_PAGE_BAND0, + MT_RXQ_MSDU_PAGE_BAND1, + MT_RXQ_MSDU_PAGE_BAND2, + MT_RXQ_TXFREE_BAND0, + MT_RXQ_TXFREE_BAND1, + MT_RXQ_TXFREE_BAND2, + MT_RXQ_RRO_IND, __MT_RXQ_MAX }; @@ -163,7 +183,7 @@ struct mt76_queue_entry { struct urb *urb; int buf_sz; }; - u32 dma_addr[2]; + dma_addr_t dma_addr[2]; u16 dma_len[2]; u16 wcid; bool skip_buf0:1; @@ -184,6 +204,7 @@ struct mt76_queue { spinlock_t lock; spinlock_t cleanup_lock; struct mt76_queue_entry *entry; + struct mt76_rro_desc *rro_desc; struct mt76_desc *desc; u16 first; @@ -197,8 +218,9 @@ struct mt76_queue { u8 buf_offset; u8 hw_idx; - u8 flags; + u16 flags; + struct mtk_wed_device *wed; u32 wed_regs; dma_addr_t desc_dma; @@ -353,6 +375,17 @@ struct mt76_txq { bool aggr; }; +struct mt76_wed_rro_ind { + u32 se_id : 12; + u32 rsv : 4; + u32 start_sn : 12; + u32 ind_reason : 4; + u32 ind_cnt : 13; + u32 win_sz : 3; + u32 rsv2 : 13; + u32 magic_cnt : 3; +}; + struct mt76_txwi_cache { struct list_head list; dma_addr_t dma_addr; @@ -371,6 +404,7 @@ struct mt76_rx_tid { spinlock_t lock; struct delayed_work reorder_work; + u16 id; u16 head; u16 size; u16 nframes; @@ -602,6 +636,7 @@ struct mt76_mmio { u32 irqmask; struct mtk_wed_device wed; + struct mtk_wed_device wed_hif2; struct completion wed_reset; struct completion wed_reset_complete; }; @@ -1046,6 +1081,12 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); void mt76_pci_disable_aspm(struct pci_dev *pdev); +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + static inline u16 mt76_chip(struct mt76_dev *dev) { return dev->rev >> 16; @@ -1056,6 +1097,14 @@ static inline u16 mt76_rev(struct mt76_dev *dev) return dev->rev & 0xffff; } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size); +void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed); +int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed); +void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed); +void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) #define mt76xx_rev(dev) mt76_rev(&((dev)->mt76)) @@ -1101,19 +1150,22 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str, int mt76_eeprom_init(struct mt76_dev *dev, int len); void mt76_eeprom_override(struct mt76_phy *phy); -int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len); +int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len); +int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, + const char *cell_name, int len); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, - int ring_base, u32 flags); + int ring_base, void *wed, u32 flags); u16 mt76_calculate_default_rate(struct mt76_phy *phy, struct ieee80211_vif *vif, int rateidx); static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx, - int n_desc, int ring_base, u32 flags) + int n_desc, int ring_base, void *wed, + u32 flags) { struct mt76_queue *q; - q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, flags); + q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, wed, flags); if (IS_ERR(q)) return PTR_ERR(q); @@ -1127,7 +1179,7 @@ static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx, { struct mt76_queue *q; - q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, 0); + q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, NULL, 0); if (IS_ERR(q)) return PTR_ERR(q); @@ -1546,10 +1598,38 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, struct mt76_power_limits *dest, s8 target_power); -static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) +static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q) { return (q->flags & MT_QFLAG_WED) && - FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX; + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE; +} + +static inline bool mt76_queue_is_wed_rro(struct mt76_queue *q) +{ + return q->flags & MT_QFLAG_WED_RRO; +} + +static inline bool mt76_queue_is_wed_rro_ind(struct mt76_queue *q) +{ + return mt76_queue_is_wed_rro(q) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_IND; +} + +static inline bool mt76_queue_is_wed_rro_data(struct mt76_queue *q) +{ + return mt76_queue_is_wed_rro(q) && + (FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_DATA || + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_MSDU_PG); +} + +static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) +{ + if (!(q->flags & MT_QFLAG_WED)) + return false; + + return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX || + mt76_queue_is_wed_rro_ind(q) || mt76_queue_is_wed_rro_data(q); + } struct mt76_txwi_cache * diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c index 03ba11a61c..7a2f5d3856 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c @@ -173,13 +173,14 @@ int mt7603_dma_init(struct mt7603_dev *dev) for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i], - MT7603_TX_RING_SIZE, MT_TX_RING_BASE, 0); + MT7603_TX_RING_SIZE, MT_TX_RING_BASE, + NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, - MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, 0); + MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; @@ -189,12 +190,12 @@ int mt7603_dma_init(struct mt7603_dev *dev) return ret; ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_BEACON, MT_TX_HW_QUEUE_BCN, - MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0); + MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_CAB, MT_TX_HW_QUEUE_BMC, - MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0); + MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 89d738deea..e2146d30e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -728,6 +728,7 @@ const struct ieee80211_ops mt7603_ops = { .set_sar_specs = mt7603_set_sar_specs, }; +MODULE_DESCRIPTION("MediaTek MT7603E and MT76x8 wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); static int __init mt7603_init(void) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c index ba927033bb..ec02148a7f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c @@ -52,15 +52,12 @@ error: return ret; } -static int -mt76_wmac_remove(struct platform_device *pdev) +static void mt76_wmac_remove(struct platform_device *pdev) { struct mt76_dev *mdev = platform_get_drvdata(pdev); struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); mt7603_unregister_device(dev); - - return 0; } static const struct of_device_id of_wmac_match[] = { @@ -74,7 +71,7 @@ MODULE_FIRMWARE(MT7628_FIRMWARE_E2); struct platform_driver mt76_wmac_driver = { .probe = mt76_wmac_probe, - .remove = mt76_wmac_remove, + .remove_new = mt76_wmac_remove, .driver = { .name = "mt76_wmac", .of_match_table = of_wmac_match, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index 0ce01ccc5d..e7135b2f17 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -26,14 +26,14 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev) for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i], MT7615_TX_RING_SIZE / 2, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT7622_TXQ_MGMT, MT7615_TX_MGMT_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; @@ -55,7 +55,7 @@ mt7615_init_tx_queues(struct mt7615_dev *dev) return mt7622_init_tx_queues_multi(dev); ret = mt76_connac_init_tx_queues(&dev->mphy, 0, MT7615_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index dab16b5fc3..0971c164b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -1375,4 +1375,5 @@ const struct ieee80211_ops mt7615_ops = { }; EXPORT_SYMBOL_GPL(mt7615_ops); +MODULE_DESCRIPTION("MediaTek MT7615E and MT7663E wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 955974a821..ae34d019e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -453,7 +453,7 @@ mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb) else mphy = &dev->mt76.phy; - phy = (struct mt7615_phy *)mphy->priv; + phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); @@ -481,7 +481,7 @@ mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb) ieee80211_ready_on_channel(mphy->hw); - phy = (struct mt7615_phy *)mphy->priv; + phy = mphy->priv; phy->roc_grant = true; wake_up(&phy->roc_wait); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index ac036a0724..87a956ea3a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -270,4 +270,5 @@ static void __exit mt7615_exit(void) module_init(mt7615_init); module_exit(mt7615_exit); +MODULE_DESCRIPTION("MediaTek MT7615E MMIO helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c index 67cedd2555..9692890ba5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -253,4 +253,5 @@ module_sdio_driver(mt7663s_driver); MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_DESCRIPTION("MediaTek MT7663S (SDIO) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c index f13d1b4187..12e3e4a91d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c @@ -45,13 +45,11 @@ static int mt7622_wmac_probe(struct platform_device *pdev) return mt7615_mmio_probe(&pdev->dev, mem_base, irq, mt7615e_reg_map); } -static int mt7622_wmac_remove(struct platform_device *pdev) +static void mt7622_wmac_remove(struct platform_device *pdev) { struct mt7615_dev *dev = platform_get_drvdata(pdev); mt7615_unregister_device(dev); - - return 0; } static const struct of_device_id mt7622_wmac_of_match[] = { @@ -65,7 +63,7 @@ struct platform_driver mt7622_wmac_driver = { .of_match_table = mt7622_wmac_of_match, }, .probe = mt7622_wmac_probe, - .remove = mt7622_wmac_remove, + .remove_new = mt7622_wmac_remove, }; MODULE_FIRMWARE(MT7622_FIRMWARE_N9); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index 04963b9f74..df737e1ff2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -281,4 +281,5 @@ module_usb_driver(mt7663u_driver); MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_DESCRIPTION("MediaTek MT7663U (USB) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index 0052d103e2..820b395900 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -349,4 +349,5 @@ EXPORT_SYMBOL_GPL(mt7663_usb_sdio_register_device); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); +MODULE_DESCRIPTION("MediaTek MT7663 SDIO/USB helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 1f29d8cd90..fdde3d70b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -222,6 +222,11 @@ static inline bool is_mt7996(struct mt76_dev *dev) return mt76_chip(dev) == 0x7990; } +static inline bool is_mt7992(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7992; +} + static inline bool is_mt7622(struct mt76_dev *dev) { if (!IS_ENABLED(CONFIG_MT7622_WMAC)) @@ -391,7 +396,8 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss); int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, - int ring_base, u32 flags); + int ring_base, void *wed, u32 flags); + void mt76_connac_write_hw_txp(struct mt76_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 2250252b20..83dcd964bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h @@ -239,11 +239,13 @@ enum tx_mgnt_type { #define MT_TXD6_TX_SRC GENMASK(31, 30) #define MT_TXD6_VTA BIT(28) -#define MT_TXD6_BW GENMASK(25, 22) +#define MT_TXD6_FIXED_BW BIT(25) +#define MT_TXD6_BW GENMASK(24, 22) #define MT_TXD6_TX_RATE GENMASK(21, 16) #define MT_TXD6_TIMESTAMP_OFS_EN BIT(15) #define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10) #define MT_TXD6_MSDU_CNT GENMASK(9, 4) +#define MT_TXD6_MSDU_CNT_V2 GENMASK(15, 10) #define MT_TXD6_DIS_MAT BIT(3) #define MT_TXD6_DAS BIT(2) #define MT_TXD6_AMSDU_CAP BIT(1) @@ -259,6 +261,9 @@ enum tx_mgnt_type { #define MT_TXD9_WLAN_IDX GENMASK(23, 8) +#define MT_TXP_BUF_LEN GENMASK(11, 0) +#define MT_TXP_DMA_ADDR_H GENMASK(15, 12) + #define MT_TX_RATE_STBC BIT(14) #define MT_TX_RATE_NSS GENMASK(13, 10) #define MT_TX_RATE_MODE GENMASK(9, 6) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 93402d2c25..c7914643e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -256,11 +256,12 @@ void mt76_connac_txp_skb_unmap(struct mt76_dev *dev, EXPORT_SYMBOL_GPL(mt76_connac_txp_skb_unmap); int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, - int ring_base, u32 flags) + int ring_base, void *wed, u32 flags) { int i, err; - err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, flags); + err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, + wed, flags); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 633f562105..ae19174b46 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -66,8 +66,9 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || (is_mt7921(dev) && addr == 0x900000) || - (is_mt7925(dev) && addr == 0x900000) || - (is_mt7996(dev) && addr == 0x900000)) + (is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) || + (is_mt7996(dev) && addr == 0x900000) || + (is_mt7992(dev) && addr == 0x900000)) cmd = MCU_CMD(PATCH_START_REQ); else cmd = MCU_CMD(TARGET_ADDRESS_LEN_REQ); @@ -3159,4 +3160,5 @@ exit: EXPORT_SYMBOL_GPL(mt76_connac2_mcu_fill_message); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_DESCRIPTION("MediaTek MT76x connac layer helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index bf023f3170..657a4d1f85 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1035,7 +1035,9 @@ enum { MCU_UNI_EVENT_RDD_REPORT = 0x11, MCU_UNI_EVENT_ROC = 0x27, MCU_UNI_EVENT_TX_DONE = 0x2d, + MCU_UNI_EVENT_THERMAL = 0x35, MCU_UNI_EVENT_NIC_CAPAB = 0x43, + MCU_UNI_EVENT_WED_RRO = 0x57, MCU_UNI_EVENT_PER_STA_INFO = 0x6d, MCU_UNI_EVENT_ALL_STA_INFO = 0x6e, }; @@ -1261,6 +1263,7 @@ enum { MCU_UNI_CMD_CHANNEL_SWITCH = 0x34, MCU_UNI_CMD_THERMAL = 0x35, MCU_UNI_CMD_VOW = 0x37, + MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40, MCU_UNI_CMD_RRO = 0x57, MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58, MCU_UNI_CMD_PER_STA_INFO = 0x6d, @@ -1347,7 +1350,7 @@ enum { }; enum UNI_ALL_STA_INFO_TAG { - UNI_ALL_STA_TX_RATE, + UNI_ALL_STA_TXRX_RATE, UNI_ALL_STA_TX_STAT, UNI_ALL_STA_TXRX_ADM_STAT, UNI_ALL_STA_TXRX_AIR_TIME, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index c3a392a1a6..bcd24c9072 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -342,4 +342,5 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev) return 0; } +MODULE_DESCRIPTION("MediaTek MT76x EEPROM helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 9277ff38b7..293e66fa83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -302,6 +302,7 @@ static const struct pci_device_id mt76x0e_device_table[] = { MODULE_DEVICE_TABLE(pci, mt76x0e_device_table); MODULE_FIRMWARE(MT7610E_FIRMWARE); MODULE_FIRMWARE(MT7650E_FIRMWARE); +MODULE_DESCRIPTION("MediaTek MT76x0E (PCIe) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); static struct pci_driver mt76x0e_driver = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 0422c33235..dd042949cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -336,6 +336,7 @@ err: MODULE_DEVICE_TABLE(usb, mt76x0_device_table); MODULE_FIRMWARE(MT7610E_FIRMWARE); MODULE_FIRMWARE(MT7610U_FIRMWARE); +MODULE_DESCRIPTION("MediaTek MT76x0U (USB) wireless driver"); MODULE_LICENSE("GPL"); static struct usb_driver mt76x0_driver = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 9b5e3fb7b0..e5ad635d3c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -199,13 +199,14 @@ int mt76x02_dma_init(struct mt76x02_dev *dev) for (i = 0; i < IEEE80211_NUM_ACS; i++) { ret = mt76_init_tx_queue(&dev->mphy, i, mt76_ac_to_hwq(i), MT76x02_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, - MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, 0); + MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, + NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index 02da543dfc..b2cc449142 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -293,4 +293,5 @@ void mt76x02u_init_mcu(struct mt76_dev *dev) EXPORT_SYMBOL_GPL(mt76x02u_init_mcu); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>"); +MODULE_DESCRIPTION("MediaTek MT76x02 MCU helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 8a0e8124b8..8020446be3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -696,4 +696,5 @@ void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev) } EXPORT_SYMBOL_GPL(mt76x02_config_mac_addr_list); +MODULE_DESCRIPTION("MediaTek MT76x02 helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c index 8c01855885..1fe5f5a02f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c @@ -506,4 +506,5 @@ int mt76x2_eeprom_init(struct mt76x02_dev *dev) } EXPORT_SYMBOL_GPL(mt76x2_eeprom_init); +MODULE_DESCRIPTION("MediaTek MT76x2 EEPROM helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index df85ebc6e1..30959746e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -165,6 +165,7 @@ mt76x2e_resume(struct pci_dev *pdev) MODULE_DEVICE_TABLE(pci, mt76x2e_device_table); MODULE_FIRMWARE(MT7662_FIRMWARE); MODULE_FIRMWARE(MT7662_ROM_PATCH); +MODULE_DESCRIPTION("MediaTek MT76x2E (PCIe) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); static struct pci_driver mt76pci_driver = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 55068f3252..ca78e14251 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -147,4 +147,5 @@ static struct usb_driver mt76x2u_driver = { module_usb_driver(mt76x2u_driver); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>"); +MODULE_DESCRIPTION("MediaTek MT76x2U (USB) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 59a44d79aa..c91a1c5402 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -9,18 +9,20 @@ static int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc, int ring_base) { struct mt7915_dev *dev = phy->dev; + struct mtk_wed_device *wed = NULL; - if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { if (is_mt798x(&dev->mt76)) ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; else ring_base = MT_WED_TX_RING_BASE; idx -= MT_TXQ_ID(0); + wed = &dev->mt76.mmio.wed; } return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, ring_base, - MT_WED_Q_TX(idx)); + wed, MT_WED_Q_TX(idx)); } static int mt7915_poll_tx(struct napi_struct *napi, int budget) @@ -492,7 +494,8 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (mtk_wed_device_active(&mdev->mmio.wed) && is_mt7915(mdev)) { wa_rx_base = MT_WED_RX_RING_BASE; wa_rx_idx = MT7915_RXQ_MCU_WA; - dev->mt76.q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MCU_WA].wed = &mdev->mmio.wed; } else { wa_rx_base = MT_RXQ_RING_BASE(MT_RXQ_MCU_WA); wa_rx_idx = MT_RXQ_ID(MT_RXQ_MCU_WA); @@ -507,9 +510,10 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (!dev->phy.mt76->band_idx) { if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) { - dev->mt76.q_rx[MT_RXQ_MAIN].flags = + mdev->q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(MT7915_RXQ_BAND0); dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; + mdev->q_rx[MT_RXQ_MAIN].wed = &mdev->mmio.wed; } ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], @@ -528,6 +532,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (mtk_wed_device_active(&mdev->mmio.wed)) { mdev->q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MAIN_WA].wed = &mdev->mmio.wed; if (is_mt7916(mdev)) { wa_rx_base = MT_WED_RX_RING_BASE; wa_rx_idx = MT7915_RXQ_MCU_WA; @@ -544,9 +549,10 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (dev->dbdc_support || dev->phy.mt76->band_idx) { if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) { - dev->mt76.q_rx[MT_RXQ_BAND1].flags = + mdev->q_rx[MT_RXQ_BAND1].flags = MT_WED_Q_RX(MT7915_RXQ_BAND1); dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; + mdev->q_rx[MT_RXQ_BAND1].wed = &mdev->mmio.wed; } /* rx data queue for band1 */ @@ -581,28 +587,6 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) return 0; } -static void mt7915_dma_wed_reset(struct mt7915_dev *dev) -{ - struct mt76_dev *mdev = &dev->mt76; - - if (!test_bit(MT76_STATE_WED_RESET, &dev->mphy.state)) - return; - - complete(&mdev->mmio.wed_reset); - - if (!wait_for_completion_timeout(&dev->mt76.mmio.wed_reset_complete, - 3 * HZ)) - dev_err(dev->mt76.dev, "wed reset complete timeout\n"); -} - -static void -mt7915_dma_reset_tx_queue(struct mt7915_dev *dev, struct mt76_queue *q) -{ - mt76_queue_reset(dev, q); - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) - mt76_dma_wed_setup(&dev->mt76, q, true); -} - int mt7915_dma_reset(struct mt7915_dev *dev, bool force) { struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; @@ -630,20 +614,20 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force) mtk_wed_device_dma_reset(wed); mt7915_dma_disable(dev, force); - mt7915_dma_wed_reset(dev); + mt76_dma_wed_reset(&dev->mt76); /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) { - mt7915_dma_reset_tx_queue(dev, dev->mphy.q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]); if (mphy_ext) - mt7915_dma_reset_tx_queue(dev, mphy_ext->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, mphy_ext->q_tx[i]); } for (i = 0; i < __MT_MCUQ_MAX; i++) mt76_queue_reset(dev, dev->mt76.q_mcu[i]); mt76_for_each_q_rx(&dev->mt76, i) { - if (dev->mt76.q_rx[i].flags == MT_WED_Q_TXFREE) + if (mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) continue; mt76_queue_reset(dev, &dev->mt76.q_rx[i]); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 76be730846..3bb2643d1b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -11,6 +11,7 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) u8 *eeprom = mdev->eeprom.data; u32 val = eeprom[MT_EE_DO_PRE_CAL]; u32 offs; + int ret; if (!dev->flash_mode) return 0; @@ -25,7 +26,11 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2; - return mt76_get_of_eeprom(mdev, dev->cal, offs, val); + ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, val); + if (!ret) + return ret; + + return mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", val); } static int mt7915_check_eeprom(struct mt7915_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 81478289f1..cea2f6d905 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -275,10 +275,11 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev, mt7915_led_set_config(led_cdev, 0xff, 0); } -void mt7915_init_txpower(struct mt7915_dev *dev, - struct ieee80211_supported_band *sband) +static void __mt7915_init_txpower(struct mt7915_phy *phy, + struct ieee80211_supported_band *sband) { - int i, n_chains = hweight8(dev->mphy.antenna_mask); + struct mt7915_dev *dev = phy->dev; + int i, n_chains = hweight16(phy->mt76->chainmask); int nss_delta = mt76_tx_power_nss_delta(n_chains); int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band); struct mt76_power_limits limits; @@ -296,7 +297,7 @@ void mt7915_init_txpower(struct mt7915_dev *dev, } target_power += pwr_delta; - target_power = mt76_get_rate_power_limits(&dev->mphy, chan, + target_power = mt76_get_rate_power_limits(phy->mt76, chan, &limits, target_power); target_power += nss_delta; @@ -307,6 +308,19 @@ void mt7915_init_txpower(struct mt7915_dev *dev, } } +void mt7915_init_txpower(struct mt7915_phy *phy) +{ + if (!phy) + return; + + if (phy->mt76->cap.has_2ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_2g.sband); + if (phy->mt76->cap.has_5ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_5g.sband); + if (phy->mt76->cap.has_6ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_6g.sband); +} + static void mt7915_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) @@ -322,9 +336,7 @@ mt7915_regd_notifier(struct wiphy *wiphy, if (dev->mt76.region == NL80211_DFS_UNSET) mt7915_mcu_rdd_background_enable(phy, NULL); - mt7915_init_txpower(dev, &mphy->sband_2g.sband); - mt7915_init_txpower(dev, &mphy->sband_5g.sband); - mt7915_init_txpower(dev, &mphy->sband_6g.sband); + mt7915_init_txpower(phy); mphy->dfs_state = MT_DFS_STATE_UNKNOWN; mt7915_dfs_init_radar_detector(phy); @@ -442,6 +454,7 @@ mt7915_init_wiphy(struct mt7915_phy *phy) mt76_set_stream_caps(phy->mt76, true); mt7915_set_stream_vht_txbf_caps(phy); mt7915_set_stream_he_caps(phy); + mt7915_init_txpower(phy); wiphy->available_antennas_rx = phy->mt76->antenna_mask; wiphy->available_antennas_tx = phy->mt76->antenna_mask; @@ -703,9 +716,6 @@ static void mt7915_init_work(struct work_struct *work) mt7915_mcu_set_eeprom(dev); mt7915_mac_init(dev); - mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_6g.sband); mt7915_txbf_init(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 2222fb9aa1..b01edbed96 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1247,7 +1247,7 @@ mt7915_phy_get_nf(struct mt7915_phy *phy, int idx) void mt7915_update_channel(struct mt76_phy *mphy) { - struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv; + struct mt7915_phy *phy = mphy->priv; struct mt76_channel_state *state = mphy->chan_state; int nf; @@ -1401,8 +1401,8 @@ mt7915_mac_restart(struct mt7915_dev *dev) goto out; mt7915_mac_init(dev); - mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); + mt7915_init_txpower(&dev->phy); + mt7915_init_txpower(phy2); ret = mt7915_txbf_init(dev); if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 9d747eb8ab..df2d427979 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1654,20 +1654,6 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw, return 0; } - -static int -mt7915_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct net_device *netdev, enum tc_setup_type type, - void *type_data) -{ - struct mt7915_dev *dev = mt7915_hw_dev(hw); - struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - - if (!mtk_wed_device_active(wed)) - return -EOPNOTSUPP; - - return mtk_wed_device_setup_tc(wed, netdev, type, type_data); -} #endif const struct ieee80211_ops mt7915_ops = { @@ -1722,6 +1708,6 @@ const struct ieee80211_ops mt7915_ops = { .set_radar_background = mt7915_set_radar_background, #ifdef CONFIG_NET_MEDIATEK_SOC_WED .net_fill_forward_path = mt7915_net_fill_forward_path, - .net_setup_tc = mt7915_net_setup_tc, + .net_setup_tc = mt76_net_setup_tc, #endif }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b22f06d441..c67c4f6ca2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -269,7 +269,7 @@ mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; - phy = (struct mt7915_phy *)mphy->priv; + phy = mphy->priv; phy->throttle_state = t->ctrl.duty.duty_cycle; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 1592b5d675..b41ac4aace 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -519,7 +519,7 @@ static inline s8 mt7915_get_power_bound(struct mt7915_phy *phy, s8 txpower) { struct mt76_phy *mphy = phy->mt76; - int n_chains = hweight8(mphy->antenna_mask); + int n_chains = hweight16(mphy->chainmask); txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2); txpower -= mt76_tx_power_nss_delta(n_chains); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 04a49ef675..dceb505987 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -490,6 +490,11 @@ static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr) return dev->reg.map[i].maps + ofs; } + return 0; +} + +static u32 __mt7915_reg_remap_addr(struct mt7915_dev *dev, u32 addr) +{ if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) || (addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) || (addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END)) @@ -514,133 +519,63 @@ void mt7915_memcpy_fromio(struct mt7915_dev *dev, void *buf, u32 offset, { u32 addr = __mt7915_reg_addr(dev, offset); - memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); + if (addr) { + memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); + return; + } + + spin_lock_bh(&dev->reg_lock); + memcpy_fromio(buf, dev->mt76.mmio.regs + + __mt7915_reg_remap_addr(dev, offset), len); + spin_unlock_bh(&dev->reg_lock); } static u32 mt7915_rr(struct mt76_dev *mdev, u32 offset) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - u32 addr = __mt7915_reg_addr(dev, offset); + u32 addr = __mt7915_reg_addr(dev, offset), val; - return dev->bus_ops->rr(mdev, addr); -} + if (addr) + return dev->bus_ops->rr(mdev, addr); -static void mt7915_wr(struct mt76_dev *mdev, u32 offset, u32 val) -{ - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - u32 addr = __mt7915_reg_addr(dev, offset); + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rr(mdev, __mt7915_reg_remap_addr(dev, offset)); + spin_unlock_bh(&dev->reg_lock); - dev->bus_ops->wr(mdev, addr, val); + return val; } -static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) +static void mt7915_wr(struct mt76_dev *mdev, u32 offset, u32 val) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); u32 addr = __mt7915_reg_addr(dev, offset); - return dev->bus_ops->rmw(mdev, addr, mask, val); -} - -#ifdef CONFIG_NET_MEDIATEK_SOC_WED -static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - - spin_lock_bh(&dev->mt76.token_lock); - dev->mt76.token_size = wed->wlan.token_start; - spin_unlock_bh(&dev->mt76.token_lock); - - return !wait_event_timeout(dev->mt76.tx_wait, - !dev->mt76.wed_token_count, HZ); -} - -static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - - spin_lock_bh(&dev->mt76.token_lock); - dev->mt76.token_size = MT7915_TOKEN_SIZE; - spin_unlock_bh(&dev->mt76.token_lock); -} - -static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - int i; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - for (i = 0; i < dev->mt76.rx_token_size; i++) { - struct mt76_txwi_cache *t; - - t = mt76_rx_token_release(&dev->mt76, i); - if (!t || !t->ptr) - continue; - - mt76_put_page_pool_buf(t->ptr, false); - t->ptr = NULL; - - mt76_put_rxwi(&dev->mt76, t); + if (addr) { + dev->bus_ops->wr(mdev, addr, val); + return; } - mt76_free_pending_rxwi(&dev->mt76); + spin_lock_bh(&dev->reg_lock); + dev->bus_ops->wr(mdev, __mt7915_reg_remap_addr(dev, offset), val); + spin_unlock_bh(&dev->reg_lock); } -static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) +static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) { - struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; - struct mt76_txwi_cache *t = NULL; - struct mt7915_dev *dev; - struct mt76_queue *q; - int i, len; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - q = &dev->mt76.q_rx[MT_RXQ_MAIN]; - len = SKB_WITH_OVERHEAD(q->buf_size); - - for (i = 0; i < size; i++) { - enum dma_data_direction dir; - dma_addr_t addr; - u32 offset; - int token; - void *buf; - - t = mt76_get_rxwi(&dev->mt76); - if (!t) - goto unmap; - - buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); - if (!buf) - goto unmap; - - addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; - dir = page_pool_get_dma_dir(q->page_pool); - dma_sync_single_for_device(dev->mt76.dma_dev, addr, len, dir); - - desc->buf0 = cpu_to_le32(addr); - token = mt76_rx_token_consume(&dev->mt76, buf, t, addr); - if (token < 0) { - mt76_put_page_pool_buf(buf, false); - goto unmap; - } + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + u32 addr = __mt7915_reg_addr(dev, offset); - desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, - token)); - desc++; - } + if (addr) + return dev->bus_ops->rmw(mdev, addr, mask, val); - return 0; + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rmw(mdev, __mt7915_reg_remap_addr(dev, offset), mask, val); + spin_unlock_bh(&dev->reg_lock); -unmap: - if (t) - mt76_put_rxwi(&dev->mt76, t); - mt7915_mmio_wed_release_rx_buf(wed); - return -ENOMEM; + return val; } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed, struct mtk_wed_wo_rx_stats *stats) { @@ -694,13 +629,6 @@ out: return ret; } - -static void mt7915_mmio_wed_reset_complete(struct mtk_wed_device *wed) -{ - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); - - complete(&dev->mmio.wed_reset_complete); -} #endif int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, @@ -778,13 +706,13 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, } wed->wlan.init_buf = mt7915_wed_init_buf; - wed->wlan.offload_enable = mt7915_mmio_wed_offload_enable; - wed->wlan.offload_disable = mt7915_mmio_wed_offload_disable; - wed->wlan.init_rx_buf = mt7915_mmio_wed_init_rx_buf; - wed->wlan.release_rx_buf = mt7915_mmio_wed_release_rx_buf; + wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; + wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; + wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats; wed->wlan.reset = mt7915_mmio_wed_reset; - wed->wlan.reset_complete = mt7915_mmio_wed_reset_complete; + wed->wlan.reset_complete = mt76_mmio_wed_reset_complete; dev->mt76.rx_token_size = wed->wlan.rx_npkt; @@ -813,6 +741,7 @@ static int mt7915_mmio_init(struct mt76_dev *mdev, dev = container_of(mdev, struct mt7915_dev, mt76); mt76_mmio_init(&dev->mt76, mem_base); + spin_lock_init(&dev->reg_lock); switch (device_id) { case 0x7915: @@ -1064,4 +993,5 @@ static void __exit mt7915_exit(void) module_init(mt7915_init); module_exit(mt7915_exit); +MODULE_DESCRIPTION("MediaTek MT7915E MMIO helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index d317c523b2..6e79bc65f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -287,6 +287,7 @@ struct mt7915_dev { struct list_head sta_rc_list; struct list_head twt_list; + spinlock_t reg_lock; u32 hw_pattern; @@ -425,8 +426,7 @@ void mt7915_dma_cleanup(struct mt7915_dev *dev); int mt7915_dma_reset(struct mt7915_dev *dev, bool force); int mt7915_dma_start(struct mt7915_dev *dev, bool reset, bool wed_reset); int mt7915_txbf_init(struct mt7915_dev *dev); -void mt7915_init_txpower(struct mt7915_dev *dev, - struct ieee80211_supported_band *sband); +void mt7915_init_txpower(struct mt7915_phy *phy); void mt7915_reset(struct mt7915_dev *dev); int mt7915_run(struct ieee80211_hw *hw); int mt7915_mcu_init(struct mt7915_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c index 06e3d9db99..8b4809703e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c @@ -1282,13 +1282,11 @@ free_device: return ret; } -static int mt798x_wmac_remove(struct platform_device *pdev) +static void mt798x_wmac_remove(struct platform_device *pdev) { struct mt7915_dev *dev = platform_get_drvdata(pdev); mt7915_unregister_device(dev); - - return 0; } static const struct of_device_id mt798x_wmac_of_match[] = { @@ -1305,7 +1303,7 @@ struct platform_driver mt798x_wmac_driver = { .of_match_table = mt798x_wmac_of_match, }, .probe = mt798x_wmac_probe, - .remove = mt798x_wmac_remove, + .remove_new = mt798x_wmac_remove, }; MODULE_FIRMWARE(MT7986_FIRMWARE_WA); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 0645417e05..0d5adc5dda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1418,5 +1418,6 @@ const struct ieee80211_ops mt7921_ops = { }; EXPORT_SYMBOL_GPL(mt7921_ops); +MODULE_DESCRIPTION("MediaTek MT7921 core driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 18056045d9..8b4ce32a2c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -160,7 +160,7 @@ static void mt7921_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); @@ -1261,13 +1261,15 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, u8 alpha2[2]; u8 type[2]; u8 env_6g; - u8 rsvd[63]; + u8 mtcl_conf; + u8 rsvd[62]; } __packed req = { .ver = 1, .idx = idx, .env = env_cap, .env_6g = dev->phy.power_type, .acpi_conf = mt792x_acpi_get_flags(&dev->phy), + .mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2), }; int ret, valid_cnt = 0; u32 buf_len = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 5c4cc370e6..1cb2113399 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -12,7 +12,8 @@ #define MT7921_TX_FWDL_RING_SIZE 128 #define MT7921_RX_RING_SIZE 1536 -#define MT7921_RX_MCU_RING_SIZE 512 +#define MT7921_RX_MCU_RING_SIZE 8 +#define MT7921_RX_MCU_WA_RING_SIZE 512 #define MT7921_EEPROM_SIZE 3584 #define MT7921_TOKEN_SIZE 8192 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 4d04911245..82cf3ce90b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -171,7 +171,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev) /* init tx queue */ ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0, MT7921_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; @@ -200,7 +200,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev) /* Change mcu queue after firmware download */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], MT7921_RXQ_MCU_WM, - MT7921_RX_MCU_RING_SIZE, + MT7921_RX_MCU_WA_RING_SIZE, MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); if (ret) return ret; @@ -545,4 +545,5 @@ MODULE_FIRMWARE(MT7922_FIRMWARE_WM); MODULE_FIRMWARE(MT7922_ROM_PATCH); MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_DESCRIPTION("MediaTek MT7921E (PCIe) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c index 7591e54d28..a9ce1e746b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c @@ -323,5 +323,6 @@ static struct sdio_driver mt7921s_driver = { .drv.pm = pm_sleep_ptr(&mt7921s_pm_ops), }; module_sdio_driver(mt7921s_driver); +MODULE_DESCRIPTION("MediaTek MT7921S (SDIO) wireless driver"); MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c index e5258c74fc..8b7c03c475 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c @@ -336,5 +336,6 @@ static struct usb_driver mt7921u_driver = { }; module_usb_driver(mt7921u_driver); +MODULE_DESCRIPTION("MediaTek MT7921U (USB) wireless driver"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 6f0b18ae31..6179798a88 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -154,8 +154,7 @@ mt7925_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band, static void mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band, - struct ieee80211_sband_iftype_data *data, - enum nl80211_iftype iftype) + struct ieee80211_sband_iftype_data *data) { struct ieee80211_sta_eht_cap *eht_cap = &data->eht_cap; struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem; @@ -256,7 +255,7 @@ __mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy, data[n].types_mask = BIT(i); mt7925_init_he_caps(phy, band, &data[n], i); - mt7925_init_eht_caps(phy, band, &data[n], i); + mt7925_init_eht_caps(phy, band, &data[n]); n++; } @@ -1471,4 +1470,5 @@ const struct ieee80211_ops mt7925_ops = { EXPORT_SYMBOL_GPL(mt7925_ops); MODULE_AUTHOR("Deren Wu <deren.wu@mediatek.com>"); +MODULE_DESCRIPTION("MediaTek MT7925 core driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 8e72012472..e1dd89a7a7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -345,7 +345,7 @@ static void mt7925_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index bf02a15067..07b74d492c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -218,7 +218,7 @@ static int mt7925_dma_init(struct mt792x_dev *dev) /* init tx queue */ ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7925_TXQ_BAND0, MT7925_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; @@ -586,4 +586,5 @@ MODULE_FIRMWARE(MT7925_FIRMWARE_WM); MODULE_FIRMWARE(MT7925_ROM_PATCH); MODULE_AUTHOR("Deren Wu <deren.wu@mediatek.com>"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_DESCRIPTION("MediaTek MT7925E (PCIe) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c index 9b885c5b3e..1e0f094fc9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c @@ -329,4 +329,5 @@ static struct usb_driver mt7925u_driver = { module_usb_driver(mt7925u_driver); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_DESCRIPTION("MediaTek MT7925U (USB) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 36fae736dd..3c897b34aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -382,6 +382,7 @@ int mt792xe_mcu_fw_pmctrl(struct mt792x_dev *dev); int mt792x_init_acpi_sar(struct mt792x_dev *dev); int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default); u8 mt792x_acpi_get_flags(struct mt792x_phy *phy); +u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2); #else static inline int mt792x_init_acpi_sar(struct mt792x_dev *dev) { @@ -398,6 +399,11 @@ static inline u8 mt792x_acpi_get_flags(struct mt792x_phy *phy) { return 0; } + +static inline u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2) +{ + return 0xf; +} #endif #endif /* __MT7925_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c index c4e3bfcc51..8fee3d481d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c @@ -350,3 +350,56 @@ u8 mt792x_acpi_get_flags(struct mt792x_phy *phy) return flags; } EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags); + +static u8 +mt792x_acpi_get_mtcl_map(int row, int column, struct mt792x_asar_cl *cl) +{ + u8 config = 0; + + if (cl->cl6g[row] & BIT(column)) + config |= (cl->mode_6g & 0x3) << 2; + if (cl->version > 1 && cl->cl5g9[row] & BIT(column)) + config |= (cl->mode_5g9 & 0x3); + + return config; +} + +u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2) +{ + static const char * const cc_list_all[] = { + "00", "EU", "AR", "AU", "AZ", "BY", "BO", "BR", + "CA", "CL", "CN", "ID", "JP", "MY", "MX", "ME", + "MA", "NZ", "NG", "PH", "RU", "RS", "SG", "KR", + "TW", "TH", "UA", "GB", "US", "VN", "KH", "PY", + }; + static const char * const cc_list_eu[] = { + "AT", "BE", "BG", "CY", "CZ", "HR", "DK", "EE", + "FI", "FR", "DE", "GR", "HU", "IS", "IE", "IT", + "LV", "LI", "LT", "LU", "MT", "NL", "NO", "PL", + "PT", "RO", "MT", "SK", "SI", "ES", "CH", + }; + struct mt792x_acpi_sar *sar = phy->acpisar; + struct mt792x_asar_cl *cl; + int col, row, i; + + if (!sar) + return 0xf; + + cl = sar->countrylist; + if (!cl) + return 0xc; + + for (i = 0; i < ARRAY_SIZE(cc_list_all); i++) { + col = 7 - i % 8; + row = i / 8; + if (!memcmp(cc_list_all[i], alpha2, 2)) + return mt792x_acpi_get_mtcl_map(row, col, cl); + } + + for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++) + if (!memcmp(cc_list_eu[i], alpha2, 2)) + return mt792x_acpi_get_mtcl_map(0, 6, cl); + + return mt792x_acpi_get_mtcl_map(0, 7, cl); +} +EXPORT_SYMBOL_GPL(mt792x_acpi_get_mtcl_conf); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h index d6d332e863..2298983b63 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h @@ -77,6 +77,8 @@ struct mt792x_asar_cl { u8 version; u8 mode_6g; u8 cl6g[6]; + u8 mode_5g9; + u8 cl5g9[6]; } __packed; struct mt792x_asar_fg { diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index fb35eff6dc..9ac5161dff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -863,5 +863,6 @@ int mt792x_load_firmware(struct mt792x_dev *dev) } EXPORT_SYMBOL_GPL(mt792x_load_firmware); +MODULE_DESCRIPTION("MediaTek MT792x core driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c index 5d1f8229fd..eb29434abe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c @@ -223,7 +223,7 @@ static void mt792x_phy_update_channel(struct mt76_phy *mphy, int idx) { struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76); - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; struct mt76_channel_state *state; u64 busy_time, tx_time, rx_time, obss_time; int nf; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c index 2dd283caed..589a3efb9f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c @@ -314,5 +314,6 @@ void mt792xu_disconnect(struct usb_interface *usb_intf) } EXPORT_SYMBOL_GPL(mt792xu_disconnect); +MODULE_DESCRIPTION("MediaTek MT792x USB helpers"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c index 4d40ec7ff5..9bd953586b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c @@ -476,7 +476,7 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s) { struct mt76_mib_stats *mib = &phy->mib; static const char * const bw[] = { - "BW20", "BW40", "BW80", "BW160" + "BW20", "BW40", "BW80", "BW160", "BW320" }; /* Tx Beamformer monitor */ @@ -489,8 +489,9 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s) /* Tx Beamformer Rx feedback monitor */ seq_puts(s, "Tx Beamformer Rx feedback statistics: "); - seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ", + seq_printf(s, "All: %d, EHT: %d, HE: %d, VHT: %d, HT: %d, ", mib->tx_bf_rx_fb_all_cnt, + mib->tx_bf_rx_fb_eht_cnt, mib->tx_bf_rx_fb_he_cnt, mib->tx_bf_rx_fb_vht_cnt, mib->tx_bf_rx_fb_ht_cnt); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 586e247a1e..fe37110e66 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -7,6 +7,26 @@ #include "../dma.h" #include "mac.h" +int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc, + int ring_base, struct mtk_wed_device *wed) +{ + struct mt7996_dev *dev = phy->dev; + u32 flags = 0; + + if (mtk_wed_device_active(wed)) { + ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; + idx -= MT_TXQ_ID(0); + + if (phy->mt76->band_idx == MT_BAND2) + flags = MT_WED_Q_TX(0); + else + flags = MT_WED_Q_TX(idx); + } + + return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, + ring_base, wed, flags); +} + static int mt7996_poll_tx(struct napi_struct *napi, int budget) { struct mt7996_dev *dev; @@ -37,18 +57,51 @@ static void mt7996_dma_config(struct mt7996_dev *dev) RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7996_RXQ_MCU_WM); RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7996_RXQ_MCU_WA); - /* band0/band1 */ + /* mt7996: band0 and band1, mt7992: band0 */ RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7996_RXQ_BAND0); RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN, MT7996_RXQ_MCU_WA_MAIN); - /* band2 */ - RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); - RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); + if (is_mt7996(&dev->mt76)) { + /* mt7996 band2 */ + RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); + RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); + } else { + /* mt7992 band1 */ + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7996_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT, MT7996_RXQ_MCU_WA_EXT); + } + + if (dev->has_rro) { + /* band0 */ + RXQ_CONFIG(MT_RXQ_RRO_BAND0, WFDMA0, MT_INT_RX_DONE_RRO_BAND0, + MT7996_RXQ_RRO_BAND0); + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND0, + MT7996_RXQ_MSDU_PG_BAND0); + RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, MT_INT_RX_TXFREE_MAIN, + MT7996_RXQ_TXFREE0); + /* band1 */ + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND1, + MT7996_RXQ_MSDU_PG_BAND1); + /* band2 */ + RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0, MT_INT_RX_DONE_RRO_BAND2, + MT7996_RXQ_RRO_BAND2); + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND2, + MT7996_RXQ_MSDU_PG_BAND2); + RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0, MT_INT_RX_TXFREE_TRI, + MT7996_RXQ_TXFREE2); + + RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0, MT_INT_RX_DONE_RRO_IND, + MT7996_RXQ_RRO_IND); + } /* data tx queue */ TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); - TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); - TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2); + if (is_mt7996(&dev->mt76)) { + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); + TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2); + } else { + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); + } /* mcu tx queue */ MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7996_TXQ_MCU_WM); @@ -56,22 +109,57 @@ static void mt7996_dma_config(struct mt7996_dev *dev) MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7996_TXQ_FWDL); } +static u32 __mt7996_dma_prefetch_base(u16 *base, u8 depth) +{ + u32 ret = *base << 16 | depth; + + *base = *base + (depth << 4); + + return ret; +} + static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) { -#define PREFETCH(_base, _depth) ((_base) << 16 | (_depth)) + u16 base = 0; + u8 queue; + +#define PREFETCH(_depth) (__mt7996_dma_prefetch_base(&base, (_depth))) /* prefetch SRAM wrapping boundary for tx/rx ring. */ - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x0, 0x2)); - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x20, 0x2)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x40, 0x4)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x80, 0x4)); - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0xc0, 0x2)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0xe0, 0x4)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x120, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x140, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x160, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_WA) + ofs, PREFETCH(0x180, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x1a0, 0x10)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x2a0, 0x10)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x8)); + mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x8)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0x8)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x2)); + + queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2_WA : MT_RXQ_BAND1_WA; + mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x2)); + + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x10)); + + queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2 : MT_RXQ_BAND1; + mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x10)); + + if (dev->has_rro) { + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs, + PREFETCH(0x10)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND2) + ofs, + PREFETCH(0x10)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs, + PREFETCH(0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs, + PREFETCH(0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs, + PREFETCH(0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, + PREFETCH(0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, + PREFETCH(0x4)); + } +#undef PREFETCH mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1 + ofs, WF_WFDMA0_GLO_CFG_EXT1_CALC_MODE); } @@ -128,8 +216,9 @@ static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset) } } -void mt7996_dma_start(struct mt7996_dev *dev, bool reset) +void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) { + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; u32 hif1_ofs = 0; u32 irq_mask; @@ -138,37 +227,50 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset) /* enable WFDMA Tx/Rx */ if (!reset) { - mt76_set(dev, MT_WFDMA0_GLO_CFG, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_RX_DMA_EN | - MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA0_GLO_CFG_EXT_EN); + else + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 | + MT_WFDMA0_GLO_CFG_EXT_EN); if (dev->hif2) mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 | + MT_WFDMA0_GLO_CFG_EXT_EN); } /* enable interrupts for TX/RX rings */ - irq_mask = MT_INT_MCU_CMD; - if (reset) - goto done; - - irq_mask = MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; + irq_mask = MT_INT_MCU_CMD | MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; - if (!dev->mphy.band_idx) + if (mt7996_band_valid(dev, MT_BAND0)) irq_mask |= MT_INT_BAND0_RX_DONE; - if (dev->dbdc_support) + if (mt7996_band_valid(dev, MT_BAND1)) irq_mask |= MT_INT_BAND1_RX_DONE; - if (dev->tbtc_support) + if (mt7996_band_valid(dev, MT_BAND2)) irq_mask |= MT_INT_BAND2_RX_DONE; -done: + if (mtk_wed_device_active(wed) && wed_reset) { + u32 wed_irq_mask = irq_mask; + + wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1; + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); + mtk_wed_device_start(wed, wed_irq_mask); + } + + irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; + mt7996_irq_enable(dev, irq_mask); mt7996_irq_disable(dev, 0); } @@ -223,6 +325,12 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1, WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE); + /* WFDMA rx threshold */ + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH, 0xc000c); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH, 0x20); + if (dev->hif2) { /* GLO_CFG_EXT0 */ mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, @@ -234,24 +342,108 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE); mt76_set(dev, MT_WFDMA_HOST_CONFIG, - MT_WFDMA_HOST_CONFIG_PDMA_BAND); + MT_WFDMA_HOST_CONFIG_PDMA_BAND | + MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); + + /* AXI read outstanding number */ + mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL, + MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14); + + /* WFDMA rx threshold */ + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH + hif1_ofs, 0xc000c); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH + hif1_ofs, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH + hif1_ofs, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH + hif1_ofs, 0x20); } if (dev->hif2) { /* fix hardware limitation, pcie1's rx ring3 is not available * so, redirect pcie0 rx ring3 interrupt to pcie1 */ - mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, - MT_WFDMA0_RX_INT_SEL_RING3); + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + dev->has_rro) + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL + hif1_ofs, + MT_WFDMA0_RX_INT_SEL_RING6); + else + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, + MT_WFDMA0_RX_INT_SEL_RING3); + } - /* TODO: redirect rx ring6 interrupt to pcie0 for wed function */ + mt7996_dma_start(dev, reset, true); +} + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt7996_dma_rro_init(struct mt7996_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + u32 irq_mask; + int ret; + + /* ind cmd */ + mdev->q_rx[MT_RXQ_RRO_IND].flags = MT_WED_RRO_Q_IND; + mdev->q_rx[MT_RXQ_RRO_IND].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_RRO_IND], + MT_RXQ_ID(MT_RXQ_RRO_IND), + MT7996_RX_RING_SIZE, + 0, MT_RXQ_RRO_IND_RING_BASE); + if (ret) + return ret; + + /* rx msdu page queue for band0 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].flags = + MT_WED_RRO_Q_MSDU_PG(0) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0)); + if (ret) + return ret; + + if (mt7996_band_valid(dev, MT_BAND1)) { + /* rx msdu page queue for band1 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].flags = + MT_WED_RRO_Q_MSDU_PG(1) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1)); + if (ret) + return ret; } - mt7996_dma_start(dev, reset); + if (mt7996_band_valid(dev, MT_BAND2)) { + /* rx msdu page queue for band2 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].flags = + MT_WED_RRO_Q_MSDU_PG(2) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2)); + if (ret) + return ret; + } + + irq_mask = mdev->mmio.irqmask | MT_INT_RRO_RX_DONE | + MT_INT_TX_DONE_BAND2; + mt76_wr(dev, MT_INT_MASK_CSR, irq_mask); + mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false); + mt7996_irq_enable(dev, irq_mask); + + return 0; } +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ int mt7996_dma_init(struct mt7996_dev *dev) { + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2; + u32 rx_base; u32 hif1_ofs = 0; int ret; @@ -265,10 +457,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) mt7996_dma_disable(dev, true); /* init tx queue */ - ret = mt76_connac_init_tx_queues(dev->phy.mt76, - MT_TXQ_ID(dev->mphy.band_idx), - MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(0), 0); + ret = mt7996_init_tx_queues(&dev->phy, + MT_TXQ_ID(dev->mphy.band_idx), + MT7996_TX_RING_SIZE, + MT_TXQ_RING_BASE(0), + wed); if (ret) return ret; @@ -314,7 +507,12 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - /* rx data queue for band0 and band1 */ + /* rx data queue for band0 and mt7996 band1 */ + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) { + dev->mt76.q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(0); + dev->mt76.q_rx[MT_RXQ_MAIN].wed = wed; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT_RXQ_ID(MT_RXQ_MAIN), MT7996_RX_RING_SIZE, @@ -324,6 +522,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; /* tx free notify event from WA for band0 */ + if (mtk_wed_device_active(wed) && !dev->has_rro) { + dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN_WA], MT_RXQ_ID(MT_RXQ_MAIN_WA), MT7996_RX_MCU_RING_SIZE, @@ -332,19 +535,25 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { - /* rx data queue for band2 */ + if (mt7996_band_valid(dev, MT_BAND2)) { + /* rx data queue for mt7996 band2 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], MT_RXQ_ID(MT_RXQ_BAND2), MT7996_RX_RING_SIZE, MT_RX_BUF_SIZE, - MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs); + rx_base); if (ret) return ret; - /* tx free notify event from WA for band2 + /* tx free notify event from WA for mt7996 band2 * use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1 */ + if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) { + dev->mt76.q_rx[MT_RXQ_BAND2_WA].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_BAND2_WA].wed = wed_hif2; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2_WA], MT_RXQ_ID(MT_RXQ_BAND2_WA), MT7996_RX_MCU_RING_SIZE, @@ -352,6 +561,80 @@ int mt7996_dma_init(struct mt7996_dev *dev) MT_RXQ_RING_BASE(MT_RXQ_BAND2_WA)); if (ret) return ret; + } else if (mt7996_band_valid(dev, MT_BAND1)) { + /* rx data queue for mt7992 band1 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1) + hif1_ofs; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1], + MT_RXQ_ID(MT_RXQ_BAND1), + MT7996_RX_RING_SIZE, + MT_RX_BUF_SIZE, + rx_base); + if (ret) + return ret; + + /* tx free notify event from WA for mt7992 band1 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA], + MT_RXQ_ID(MT_RXQ_BAND1_WA), + MT7996_RX_MCU_RING_SIZE, + MT_RX_BUF_SIZE, + rx_base); + if (ret) + return ret; + } + + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) && + dev->has_rro) { + /* rx rro data queue for band0 */ + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].flags = + MT_WED_RRO_Q_DATA(0) | MT_QFLAG_WED_RRO_EN; + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].wed = wed; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0], + MT_RXQ_ID(MT_RXQ_RRO_BAND0), + MT7996_RX_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0)); + if (ret) + return ret; + + /* tx free notify event from WA for band0 */ + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed; + + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0], + MT_RXQ_ID(MT_RXQ_TXFREE_BAND0), + MT7996_RX_MCU_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0)); + if (ret) + return ret; + + if (mt7996_band_valid(dev, MT_BAND2)) { + /* rx rro data queue for band2 */ + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = + MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2], + MT_RXQ_ID(MT_RXQ_RRO_BAND2), + MT7996_RX_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs); + if (ret) + return ret; + + /* tx free notify event from MAC for band2 */ + if (mtk_wed_device_active(wed_hif2)) { + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].wed = wed_hif2; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2], + MT_RXQ_ID(MT_RXQ_TXFREE_BAND2), + MT7996_RX_MCU_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND2) + hif1_ofs); + if (ret) + return ret; + } } ret = mt76_init_queues(dev, mt76_dma_rx_poll); @@ -405,21 +688,33 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force) if (force) mt7996_wfsys_reset(dev); + if (dev->hif2 && mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_dma_reset(&dev->mt76.mmio.wed_hif2); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_dma_reset(&dev->mt76.mmio.wed); + mt7996_dma_disable(dev, force); + mt76_dma_wed_reset(&dev->mt76); /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) { - mt76_queue_reset(dev, dev->mphy.q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]); if (phy2) - mt76_queue_reset(dev, phy2->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, phy2->q_tx[i]); if (phy3) - mt76_queue_reset(dev, phy3->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, phy3->q_tx[i]); } for (i = 0; i < __MT_MCUQ_MAX; i++) mt76_queue_reset(dev, dev->mt76.q_mcu[i]); mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + if (mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]) || + mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) + continue; + mt76_queue_reset(dev, &dev->mt76.q_rx[i]); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 544b6c6f1e..4a82371182 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -14,7 +14,9 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev) switch (val) { case 0x7990: - return 0; + return is_mt7996(&dev->mt76) ? 0 : -EINVAL; + case 0x7992: + return is_mt7992(&dev->mt76) ? 0 : -EINVAL; default: return -EINVAL; } @@ -22,8 +24,14 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev) static char *mt7996_eeprom_name(struct mt7996_dev *dev) { - /* reserve for future variants */ - return MT7996_EEPROM_DEFAULT; + switch (mt76_chip(&dev->mt76)) { + case 0x7990: + return MT7996_EEPROM_DEFAULT; + case 0x7992: + return MT7992_EEPROM_DEFAULT; + default: + return MT7996_EEPROM_DEFAULT; + } } static int @@ -103,7 +111,8 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev) dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP); } - if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4) + if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4 || + is_mt7992(&dev->mt76)) dev->wtbl_size_group = 2; /* set default */ return 0; @@ -148,36 +157,49 @@ static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy) int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy) { - u8 path, nss, band_idx = phy->mt76->band_idx; + u8 path, rx_path, nss, band_idx = phy->mt76->band_idx; u8 *eeprom = dev->mt76.eeprom.data; struct mt76_phy *mphy = phy->mt76; + int max_path = 5, max_nss = 4; int ret; switch (band_idx) { case MT_BAND1: path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1, eeprom[MT_EE_WIFI_CONF + 2]); + rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND1, + eeprom[MT_EE_WIFI_CONF + 3]); nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1, eeprom[MT_EE_WIFI_CONF + 5]); break; case MT_BAND2: path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2, eeprom[MT_EE_WIFI_CONF + 2]); + rx_path = FIELD_GET(MT_EE_WIFI_CONF4_RX_PATH_BAND2, + eeprom[MT_EE_WIFI_CONF + 4]); nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2, eeprom[MT_EE_WIFI_CONF + 5]); break; default: path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0, eeprom[MT_EE_WIFI_CONF + 1]); + rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND0, + eeprom[MT_EE_WIFI_CONF + 3]); nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0, eeprom[MT_EE_WIFI_CONF + 4]); break; } - if (!path || path > 4) - path = 4; + if (!path || path > max_path) + path = max_path; + + if (!nss || nss > max_nss) + nss = max_nss; + + nss = min_t(u8, nss, path); - nss = min_t(u8, min_t(u8, 4, nss), path); + if (path != rx_path) + phy->has_aux_rx = true; mphy->antenna_mask = BIT(nss) - 1; mphy->chainmask = (BIT(path) - 1) << dev->chainshift[band_idx]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h index 0c749774f6..412d6e2f80 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h @@ -33,6 +33,9 @@ enum mt7996_eeprom_field { #define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3) #define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0) #define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(5, 3) +#define MT_EE_WIFI_CONF3_RX_PATH_BAND0 GENMASK(2, 0) +#define MT_EE_WIFI_CONF3_RX_PATH_BAND1 GENMASK(5, 3) +#define MT_EE_WIFI_CONF4_RX_PATH_BAND2 GENMASK(2, 0) #define MT_EE_WIFI_CONF4_STREAM_NUM_BAND0 GENMASK(5, 3) #define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(2, 0) #define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(5, 3) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index f8b61df15f..a929c657be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -5,6 +5,8 @@ #include <linux/etherdevice.h> #include <linux/of.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/thermal.h> #include "mt7996.h" #include "mac.h" @@ -43,6 +45,183 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; +static ssize_t mt7996_thermal_temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mt7996_phy *phy = dev_get_drvdata(dev); + int i = to_sensor_dev_attr(attr)->index; + int temperature; + + switch (i) { + case 0: + temperature = mt7996_mcu_get_temperature(phy); + if (temperature < 0) + return temperature; + /* display in millidegree celcius */ + return sprintf(buf, "%u\n", temperature * 1000); + case 1: + case 2: + return sprintf(buf, "%u\n", + phy->throttle_temp[i - 1] * 1000); + case 3: + return sprintf(buf, "%hhu\n", phy->throttle_state); + default: + return -EINVAL; + } +} + +static ssize_t mt7996_thermal_temp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mt7996_phy *phy = dev_get_drvdata(dev); + int ret, i = to_sensor_dev_attr(attr)->index; + long val; + + ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; + + mutex_lock(&phy->dev->mt76.mutex); + val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 40, 130); + + /* add a safety margin ~10 */ + if ((i - 1 == MT7996_CRIT_TEMP_IDX && + val > phy->throttle_temp[MT7996_MAX_TEMP_IDX] - 10) || + (i - 1 == MT7996_MAX_TEMP_IDX && + val - 10 < phy->throttle_temp[MT7996_CRIT_TEMP_IDX])) { + dev_err(phy->dev->mt76.dev, + "temp1_max shall be 10 degrees higher than temp1_crit."); + mutex_unlock(&phy->dev->mt76.mutex); + return -EINVAL; + } + + phy->throttle_temp[i - 1] = val; + mutex_unlock(&phy->dev->mt76.mutex); + + ret = mt7996_mcu_set_thermal_protect(phy, true); + if (ret) + return ret; + + return count; +} + +static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7996_thermal_temp, 0); +static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7996_thermal_temp, 1); +static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7996_thermal_temp, 2); +static SENSOR_DEVICE_ATTR_RO(throttle1, mt7996_thermal_temp, 3); + +static struct attribute *mt7996_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_throttle1.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(mt7996_hwmon); + +static int +mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = MT7996_CDEV_THROTTLE_MAX; + + return 0; +} + +static int +mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct mt7996_phy *phy = cdev->devdata; + + *state = phy->cdev_state; + + return 0; +} + +static int +mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct mt7996_phy *phy = cdev->devdata; + u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state; + int ret; + + if (state > MT7996_CDEV_THROTTLE_MAX) { + dev_err(phy->dev->mt76.dev, + "please specify a valid throttling state\n"); + return -EINVAL; + } + + if (state == phy->cdev_state) + return 0; + + /* cooling_device convention: 0 = no cooling, more = more cooling + * mcu convention: 1 = max cooling, more = less cooling + */ + ret = mt7996_mcu_set_thermal_throttling(phy, throttling); + if (ret) + return ret; + + phy->cdev_state = state; + + return 0; +} + +static const struct thermal_cooling_device_ops mt7996_thermal_ops = { + .get_max_state = mt7996_thermal_get_max_throttle_state, + .get_cur_state = mt7996_thermal_get_cur_throttle_state, + .set_cur_state = mt7996_thermal_set_cur_throttle_state, +}; + +static void mt7996_unregister_thermal(struct mt7996_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + + if (!phy->cdev) + return; + + sysfs_remove_link(&wiphy->dev.kobj, "cooling_device"); + thermal_cooling_device_unregister(phy->cdev); +} + +static int mt7996_thermal_init(struct mt7996_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct thermal_cooling_device *cdev; + struct device *hwmon; + const char *name; + + name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s", + wiphy_name(wiphy)); + + cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops); + if (!IS_ERR(cdev)) { + if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj, + "cooling_device") < 0) + thermal_cooling_device_unregister(cdev); + else + phy->cdev = cdev; + } + + /* initialize critical/maximum high temperature */ + phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP; + phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP; + + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, + mt7996_hwmon_groups); + + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + + return 0; +} + static void mt7996_led_set_config(struct led_classdev *led_cdev, u8 delay_on, u8 delay_off) { @@ -109,10 +288,11 @@ static void mt7996_led_set_brightness(struct led_classdev *led_cdev, mt7996_led_set_config(led_cdev, 0xff, 0); } -void mt7996_init_txpower(struct mt7996_dev *dev, - struct ieee80211_supported_band *sband) +static void __mt7996_init_txpower(struct mt7996_phy *phy, + struct ieee80211_supported_band *sband) { - int i, nss = hweight8(dev->mphy.antenna_mask); + struct mt7996_dev *dev = phy->dev; + int i, nss = hweight16(phy->mt76->chainmask); int nss_delta = mt76_tx_power_nss_delta(nss); int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band); struct mt76_power_limits limits; @@ -122,7 +302,7 @@ void mt7996_init_txpower(struct mt7996_dev *dev, int target_power = mt7996_eeprom_get_target_power(dev, chan); target_power += pwr_delta; - target_power = mt76_get_rate_power_limits(&dev->mphy, chan, + target_power = mt76_get_rate_power_limits(phy->mt76, chan, &limits, target_power); target_power += nss_delta; @@ -133,6 +313,19 @@ void mt7996_init_txpower(struct mt7996_dev *dev, } } +void mt7996_init_txpower(struct mt7996_phy *phy) +{ + if (!phy) + return; + + if (phy->mt76->cap.has_2ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_2g.sband); + if (phy->mt76->cap.has_5ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_5g.sband); + if (phy->mt76->cap.has_6ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_6g.sband); +} + static void mt7996_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) @@ -147,16 +340,14 @@ mt7996_regd_notifier(struct wiphy *wiphy, if (dev->mt76.region == NL80211_DFS_UNSET) mt7996_mcu_rdd_background_enable(phy, NULL); - mt7996_init_txpower(dev, &phy->mt76->sband_2g.sband); - mt7996_init_txpower(dev, &phy->mt76->sband_5g.sband); - mt7996_init_txpower(dev, &phy->mt76->sband_6g.sband); + mt7996_init_txpower(phy); phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; mt7996_dfs_init_radar_detector(phy); } static void -mt7996_init_wiphy(struct ieee80211_hw *hw) +mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) { struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt76_dev *mdev = &phy->dev->mt76; @@ -168,11 +359,14 @@ mt7996_init_wiphy(struct ieee80211_hw *hw) hw->max_rx_aggregation_subframes = max_subframes; hw->max_tx_aggregation_subframes = max_subframes; hw->netdev_features = NETIF_F_RXCSUM; + if (mtk_wed_device_active(wed)) + hw->netdev_features |= NETIF_F_HW_TC; hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; phy->slottime = 9; + phy->beacon_rate = -1; hw->sta_data_size = sizeof(struct mt7996_sta); hw->vif_data_size = sizeof(struct mt7996_vif); @@ -242,6 +436,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw) mt76_set_stream_caps(phy->mt76, true); mt7996_set_stream_vht_txbf_caps(phy); mt7996_set_stream_he_eht_caps(phy); + mt7996_init_txpower(phy); wiphy->available_antennas_rx = phy->mt76->antenna_mask; wiphy->available_antennas_tx = phy->mt76->antenna_mask; @@ -287,11 +482,12 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev) for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) { u16 rate = mt76_rates[i].hw_value; - u16 idx = MT7996_BASIC_RATES_TBL + i; + /* odd index for driver, even index for firmware */ + u16 idx = MT7996_BASIC_RATES_TBL + 2 * i; rate = FIELD_PREP(MT_TX_RATE_MODE, rate >> 8) | FIELD_PREP(MT_TX_RATE_IDX, rate & GENMASK(7, 0)); - mt7996_mac_set_fixed_rate_table(dev, idx, rate); + mt7996_mcu_set_fixed_rate_table(&dev->phy, idx, rate, false); } } @@ -317,9 +513,23 @@ void mt7996_mac_init(struct mt7996_dev *dev) mt76_rmw_field(dev, MT_DMA_TCRF1(2), MT_DMA_TCRF1_QIDX, 0); /* rro module init */ - mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); - mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); - mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); + if (is_mt7996(&dev->mt76)) + mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); + else + mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, + dev->hif2 ? 7 : 0); + + if (dev->has_rro) { + u16 timeout; + + timeout = mt76_rr(dev, MT_HW_REV) == MT_HW_REV1 ? 512 : 128; + mt7996_mcu_set_rro(dev, UNI_RRO_SET_FLUSH_TIMEOUT, timeout); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0); + } else { + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); + } mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_HW_PATH_HIF_VER, @@ -335,7 +545,8 @@ int mt7996_txbf_init(struct mt7996_dev *dev) { int ret; - if (dev->dbdc_support) { + if (mt7996_band_valid(dev, MT_BAND1) || + mt7996_band_valid(dev, MT_BAND2)) { ret = mt7996_mcu_set_txbf(dev, BF_MOD_EN_CTRL); if (ret) return ret; @@ -356,19 +567,18 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, struct mt76_phy *mphy; u32 mac_ofs, hif1_ofs = 0; int ret; + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - if (band != MT_BAND1 && band != MT_BAND2) - return 0; - - if ((band == MT_BAND1 && !dev->dbdc_support) || - (band == MT_BAND2 && !dev->tbtc_support)) + if (!mt7996_band_valid(dev, band) || band == MT_BAND0) return 0; if (phy) return 0; - if (band == MT_BAND2 && dev->hif2) + if (is_mt7996(&dev->mt76) && band == MT_BAND2 && dev->hif2) { hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); + wed = &dev->mt76.mmio.wed_hif2; + } mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7996_ops, band); if (!mphy) @@ -401,11 +611,12 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, mt76_eeprom_override(mphy); /* init wiphy according to mphy and phy */ - mt7996_init_wiphy(mphy->hw); - ret = mt76_connac_init_tx_queues(phy->mt76, - MT_TXQ_ID(band), - MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(band) + hif1_ofs, 0); + mt7996_init_wiphy(mphy->hw, wed); + ret = mt7996_init_tx_queues(mphy->priv, + MT_TXQ_ID(band), + MT7996_TX_RING_SIZE, + MT_TXQ_RING_BASE(band) + hif1_ofs, + wed); if (ret) goto error; @@ -414,10 +625,21 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (ret) goto error; + ret = mt7996_thermal_init(phy); + if (ret) + goto error; + ret = mt7996_init_debugfs(phy); if (ret) goto error; + if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) { + u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2; + + mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, irq_mask); + } + return 0; error: @@ -434,6 +656,8 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band) if (!phy) return; + mt7996_unregister_thermal(phy); + mphy = phy->dev->mt76.phys[band]; mt76_unregister_phy(mphy); ieee80211_free_hw(mphy->hw); @@ -447,9 +671,6 @@ static void mt7996_init_work(struct work_struct *work) mt7996_mcu_set_eeprom(dev); mt7996_mac_init(dev); - mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband); mt7996_txbf_init(dev); } @@ -462,16 +683,225 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev) msleep(20); } +static int mt7996_wed_rro_init(struct mt7996_dev *dev) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0; + struct mt7996_wed_rro_addr *addr; + void *ptr; + int i; + + if (!dev->has_rro) + return 0; + + if (!mtk_wed_device_active(wed)) + return 0; + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_BA_BITMAP_CR_SIZE, + &dev->wed_rro.ba_bitmap[i].phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.ba_bitmap[i].ptr = ptr; + } + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + int j; + + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr), + &dev->wed_rro.addr_elem[i].phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.addr_elem[i].ptr = ptr; + memset(dev->wed_rro.addr_elem[i].ptr, 0, + MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr)); + + addr = dev->wed_rro.addr_elem[i].ptr; + for (j = 0; j < MT7996_RRO_WINDOW_MAX_SIZE; j++) { + addr->signature = 0xff; + addr++; + } + + wed->wlan.ind_cmd.addr_elem_phys[i] = + dev->wed_rro.addr_elem[i].phy_addr; + } + + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr), + &dev->wed_rro.session.phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.session.ptr = ptr; + addr = dev->wed_rro.session.ptr; + for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { + addr->signature = 0xff; + addr++; + } + + /* rro hw init */ + /* TODO: remove line after WM has set */ + mt76_clear(dev, WF_RRO_AXI_MST_CFG, WF_RRO_AXI_MST_CFG_DIDX_OK); + + /* setup BA bitmap cache address */ + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0, + dev->wed_rro.ba_bitmap[0].phy_addr); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0, + dev->wed_rro.ba_bitmap[1].phy_addr); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0); + + /* setup Address element address */ + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + mt76_wr(dev, reg, dev->wed_rro.addr_elem[i].phy_addr >> 4); + reg += 4; + } + + /* setup Address element address - separate address segment mode */ + mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1, + MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE); + + wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6; + wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION; + wed->wlan.ind_cmd.particular_se_phys = dev->wed_rro.session.phy_addr; + wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN; + wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL; + + mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00); + mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1, + MT_RRO_IND_CMD_SIGNATURE_BASE1_EN); + + /* particular session configure */ + /* use max session idx + 1 as particular session id */ + mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr); + mt76_wr(dev, MT_RRO_PARTICULAR_CFG1, + MT_RRO_PARTICULAR_CONFG_EN | + FIELD_PREP(MT_RRO_PARTICULAR_SID, MT7996_RRO_MAX_SESSION)); + + /* interrupt enable */ + mt76_wr(dev, MT_RRO_HOST_INT_ENA, + MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA); + + /* rro ind cmd queue init */ + return mt7996_dma_rro_init(dev); +#else + return 0; +#endif +} + +static void mt7996_wed_rro_free(struct mt7996_dev *dev) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + int i; + + if (!dev->has_rro) + return; + + if (!mtk_wed_device_active(&dev->mt76.mmio.wed)) + return; + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { + if (!dev->wed_rro.ba_bitmap[i].ptr) + continue; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_BA_BITMAP_CR_SIZE, + dev->wed_rro.ba_bitmap[i].ptr, + dev->wed_rro.ba_bitmap[i].phy_addr); + } + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + if (!dev->wed_rro.addr_elem[i].ptr) + continue; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_SIZE * + sizeof(struct mt7996_wed_rro_addr), + dev->wed_rro.addr_elem[i].ptr, + dev->wed_rro.addr_elem[i].phy_addr); + } + + if (!dev->wed_rro.session.ptr) + return; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_LEN * + sizeof(struct mt7996_wed_rro_addr), + dev->wed_rro.session.ptr, + dev->wed_rro.session.phy_addr); +#endif +} + +static void mt7996_wed_rro_work(struct work_struct *work) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mt7996_dev *dev; + LIST_HEAD(list); + + dev = (struct mt7996_dev *)container_of(work, struct mt7996_dev, + wed_rro.work); + + spin_lock_bh(&dev->wed_rro.lock); + list_splice_init(&dev->wed_rro.poll_list, &list); + spin_unlock_bh(&dev->wed_rro.lock); + + while (!list_empty(&list)) { + struct mt7996_wed_rro_session_id *e; + int i; + + e = list_first_entry(&list, struct mt7996_wed_rro_session_id, + list); + list_del_init(&e->list); + + for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { + void *ptr = dev->wed_rro.session.ptr; + struct mt7996_wed_rro_addr *elem; + u32 idx, elem_id = i; + + if (e->id == MT7996_RRO_MAX_SESSION) + goto reset; + + idx = e->id / MT7996_RRO_BA_BITMAP_SESSION_SIZE; + if (idx >= ARRAY_SIZE(dev->wed_rro.addr_elem)) + goto out; + + ptr = dev->wed_rro.addr_elem[idx].ptr; + elem_id += + (e->id % MT7996_RRO_BA_BITMAP_SESSION_SIZE) * + MT7996_RRO_WINDOW_MAX_LEN; +reset: + elem = ptr + elem_id * sizeof(*elem); + elem->signature = 0xff; + } + mt7996_mcu_wed_rro_reset_sessions(dev, e->id); +out: + kfree(e); + } +#endif +} + static int mt7996_init_hardware(struct mt7996_dev *dev) { int ret, idx; mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); + if (is_mt7992(&dev->mt76)) { + mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND0), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0); + mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND1), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0); + } INIT_WORK(&dev->init_work, mt7996_init_work); - - dev->dbdc_support = true; - dev->tbtc_support = true; + INIT_WORK(&dev->wed_rro.work, mt7996_wed_rro_work); + INIT_LIST_HEAD(&dev->wed_rro.poll_list); + spin_lock_init(&dev->wed_rro.lock); ret = mt7996_dma_init(dev); if (ret) @@ -483,6 +913,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) if (ret) return ret; + ret = mt7996_wed_rro_init(dev); + if (ret) + return ret; + ret = mt7996_eeprom_init(dev); if (ret < 0) return ret; @@ -890,14 +1324,16 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; - mt7996_init_wiphy(hw); + mt7996_init_wiphy(hw, &dev->mt76.mmio.wed); ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) return ret; - ieee80211_queue_work(mt76_hw(dev), &dev->init_work); + ret = mt7996_thermal_init(&dev->phy); + if (ret) + return ret; ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1); if (ret) @@ -907,21 +1343,35 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); + dev->recovery.hw_init_done = true; ret = mt7996_init_debugfs(&dev->phy); if (ret) - return ret; + goto error; + + ret = mt7996_coredump_register(dev); + if (ret) + goto error; - return mt7996_coredump_register(dev); + return 0; + +error: + cancel_work_sync(&dev->init_work); + + return ret; } void mt7996_unregister_device(struct mt7996_dev *dev) { + cancel_work_sync(&dev->wed_rro.work); mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2); mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1); + mt7996_unregister_thermal(&dev->phy); mt7996_coredump_unregister(dev); mt76_unregister_device(&dev->mt76); + mt7996_wed_rro_free(dev); mt7996_mcu_exit(dev); mt7996_tx_token_put(dev); mt7996_dma_cleanup(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 7d33b0c895..0384fb059d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -102,7 +102,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) }; struct ieee80211_sta *sta; struct mt7996_sta *msta; - struct rate_info *rate; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; LIST_HEAD(sta_poll_list); int i; @@ -118,7 +117,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) u32 addr, val; u16 idx; s8 rssi[4]; - u8 bw; spin_lock_bh(&dev->mt76.sta_poll_lock); if (list_empty(&sta_poll_list)) { @@ -174,49 +172,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur); } - /* We don't support reading GI info from txs packets. - * For accurate tx status reporting and AQL improvement, - * we need to make sure that flags match so polling GI - * from per-sta counters directly. - */ - rate = &msta->wcid.rate; - - switch (rate->bw) { - case RATE_INFO_BW_320: - bw = IEEE80211_STA_RX_BW_320; - break; - case RATE_INFO_BW_160: - bw = IEEE80211_STA_RX_BW_160; - break; - case RATE_INFO_BW_80: - bw = IEEE80211_STA_RX_BW_80; - break; - case RATE_INFO_BW_40: - bw = IEEE80211_STA_RX_BW_40; - break; - default: - bw = IEEE80211_STA_RX_BW_20; - break; - } - - addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6); - val = mt76_rr(dev, addr); - if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) { - addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5); - val = mt76_rr(dev, addr); - rate->eht_gi = FIELD_GET(GENMASK(25, 24), val); - } else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) { - u8 offs = 24 + 2 * bw; - - rate->he_gi = (val & (0x3 << offs)) >> offs; - } else if (rate->flags & - (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) { - if (val & BIT(12 + bw)) - rate->flags |= RATE_INFO_FLAGS_SHORT_GI; - else - rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; - } - /* get signal strength of resp frames (CTS/BA/ACK) */ addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34); val = mt76_rr(dev, addr); @@ -248,17 +203,6 @@ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, mt76_clear(dev, addr, BIT(5)); } -void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev, - u8 tbl_idx, u16 rate_idx) -{ - u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx; - - mt76_wr(dev, MT_WTBL_ITDR0, rate_idx); - /* use wtbl spe idx */ - mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL); - mt76_wr(dev, MT_WTBL_ITCR, ctrl); -} - /* The HW does not translate the mac header to 802.3 for mesh point */ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) { @@ -449,8 +393,36 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev, return 0; } +static void +mt7996_wed_check_ppe(struct mt7996_dev *dev, struct mt76_queue *q, + struct mt7996_sta *msta, struct sk_buff *skb, + u32 info) +{ + struct ieee80211_vif *vif; + struct wireless_dev *wdev; + + if (!msta || !msta->vif) + return; + + if (!mt76_queue_is_wed_rx(q)) + return; + + if (!(info & MT_DMA_INFO_PPE_VLD)) + return; + + vif = container_of((void *)msta->vif, struct ieee80211_vif, + drv_priv); + wdev = ieee80211_vif_to_wdev(vif); + skb->dev = wdev->netdev; + + mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb, + FIELD_GET(MT_DMA_PPE_CPU_REASON, info), + FIELD_GET(MT_DMA_PPE_ENTRY, info)); +} + static int -mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) +mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, + struct sk_buff *skb, u32 *info) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; @@ -475,7 +447,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) u16 seq_ctrl = 0; __le16 fc = 0; int idx; + u8 hw_aggr = false; + struct mt7996_sta *msta = NULL; + hw_aggr = status->aggr; memset(status, 0, sizeof(*status)); band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1); @@ -502,8 +477,6 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) status->wcid = mt7996_rx_get_wcid(dev, idx, unicast); if (status->wcid) { - struct mt7996_sta *msta; - msta = container_of(status->wcid, struct mt7996_sta, wcid); spin_lock_bh(&dev->mt76.sta_poll_lock); if (list_empty(&msta->wcid.poll_list)) @@ -708,12 +681,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) } } else { status->flag |= RX_FLAG_8023; + mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb, + *info); } if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode); - if (!status->wcid || !ieee80211_is_data_qos(fc)) + if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr) return 0; status->aggr = unicast && @@ -757,6 +732,9 @@ mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi, FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); txwi[2] |= cpu_to_le32(val); + + if (wcid->amsdu) + txwi[3] |= cpu_to_le32(MT_TXD3_HW_AMSDU); } static void @@ -887,8 +865,6 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, val |= MT_TXD3_PROTECT_FRAME; if (info->flags & IEEE80211_TX_CTL_NO_ACK) val |= MT_TXD3_NO_ACK; - if (wcid->amsdu) - val |= MT_TXD3_HW_AMSDU; txwi[3] = cpu_to_le32(val); txwi[4] = 0; @@ -898,8 +874,11 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, val |= MT_TXD5_TX_STATUS_HOST; txwi[5] = cpu_to_le32(val); - val = MT_TXD6_DIS_MAT | MT_TXD6_DAS | - FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + val = MT_TXD6_DIS_MAT | MT_TXD6_DAS; + if (is_mt7996(&dev->mt76)) + val |= FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + else + val |= FIELD_PREP(MT_TXD6_MSDU_CNT_V2, 1); txwi[6] = cpu_to_le32(val); txwi[7] = 0; @@ -923,7 +902,8 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, idx = mvif->basic_rates_idx; } - txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx)); + val = FIELD_PREP(MT_TXD6_TX_RATE, idx) | MT_TXD6_FIXED_BW; + txwi[6] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } } @@ -963,8 +943,16 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE); for (i = 0; i < nbuf; i++) { + u16 len; + + len = FIELD_PREP(MT_TXP_BUF_LEN, tx_info->buf[i + 1].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + len |= FIELD_PREP(MT_TXP_DMA_ADDR_H, + tx_info->buf[i + 1].addr >> 32); +#endif + txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); - txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len); + txp->fw.len[i] = cpu_to_le16(len); } txp->fw.nbuf = nbuf; @@ -996,6 +984,29 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, return 0; } +u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id) +{ + struct mt76_connac_fw_txp *txp = ptr + MT_TXD_SIZE; + __le32 *txwi = ptr; + u32 val; + + memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp)); + + val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) | + FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT); + txwi[0] = cpu_to_le32(val); + + val = BIT(31) | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3); + txwi[1] = cpu_to_le32(val); + + txp->token = cpu_to_le16(token_id); + txp->nbuf = 1; + txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp)); + + return MT_TXD_SIZE + sizeof(*txp); +} + static void mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) { @@ -1257,6 +1268,8 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, goto out; rate.flags = RATE_INFO_FLAGS_VHT_MCS; + if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) + rate.flags |= RATE_INFO_FLAGS_SHORT_GI; break; case MT_PHY_TYPE_HE_SU: case MT_PHY_TYPE_HE_EXT_SU: @@ -1406,6 +1419,12 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, switch (type) { case PKT_TYPE_TXRX_NOTIFY: + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2) && + q == MT_RXQ_TXFREE_BAND2) { + dev_kfree_skb(skb); + break; + } + mt7996_mac_tx_free(dev, skb->data, skb->len); napi_consume_skb(skb, 1); break; @@ -1422,7 +1441,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, dev_kfree_skb(skb); break; case PKT_TYPE_NORMAL: - if (!mt7996_mac_fill_rx(dev, skb)) { + if (!mt7996_mac_fill_rx(dev, q, skb, info)) { mt76_rx(&dev->mt76, q, skb); return; } @@ -1528,7 +1547,7 @@ mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx) void mt7996_update_channel(struct mt76_phy *mphy) { - struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv; + struct mt7996_phy *phy = mphy->priv; struct mt76_channel_state *state = mphy->chan_state; int nf; @@ -1655,6 +1674,10 @@ mt7996_mac_restart(struct mt7996_dev *dev) /* disable all tx/rx napi */ mt76_worker_disable(&dev->mt76.tx_worker); mt76_for_each_q_rx(mdev, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&mdev->q_rx[i])) + continue; + if (mdev->q_rx[i].ndesc) napi_disable(&dev->mt76.napi[i]); } @@ -1668,6 +1691,10 @@ mt7996_mac_restart(struct mt7996_dev *dev) local_bh_disable(); mt76_for_each_q_rx(mdev, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&mdev->q_rx[i])) + continue; + if (mdev->q_rx[i].ndesc) { napi_enable(&dev->mt76.napi[i]); napi_schedule(&dev->mt76.napi[i]); @@ -1700,9 +1727,9 @@ mt7996_mac_restart(struct mt7996_dev *dev) goto out; mt7996_mac_init(dev); - mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband); + mt7996_init_txpower(&dev->phy); + mt7996_init_txpower(phy2); + mt7996_init_txpower(phy3); ret = mt7996_txbf_init(dev); if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { @@ -1757,6 +1784,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev) if (phy3) ieee80211_stop_queues(phy3->mt76->hw); + cancel_work_sync(&dev->wed_rro.work); cancel_delayed_work_sync(&dev->mphy.mac_work); if (phy2) cancel_delayed_work_sync(&phy2->mt76->mac_work); @@ -1839,6 +1867,13 @@ void mt7996_mac_reset_work(struct work_struct *work) dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.", wiphy_name(dev->mt76.hw->wiphy)); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_stop(&dev->mt76.mmio.wed_hif2); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_stop(&dev->mt76.mmio.wed); + ieee80211_stop_queues(mt76_hw(dev)); if (phy2) ieee80211_stop_queues(phy2->mt76->hw); @@ -1848,6 +1883,8 @@ void mt7996_mac_reset_work(struct work_struct *work) set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); + + cancel_work_sync(&dev->wed_rro.work); cancel_delayed_work_sync(&dev->mphy.mac_work); if (phy2) { set_bit(MT76_RESET, &phy2->mt76->state); @@ -1858,8 +1895,13 @@ void mt7996_mac_reset_work(struct work_struct *work) cancel_delayed_work_sync(&phy3->mt76->mac_work); } mt76_worker_disable(&dev->mt76.tx_worker); - mt76_for_each_q_rx(&dev->mt76, i) + mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) + continue; + napi_disable(&dev->mt76.napi[i]); + } napi_disable(&dev->mt76.tx_napi); mutex_lock(&dev->mt76.mutex); @@ -1880,7 +1922,28 @@ void mt7996_mac_reset_work(struct work_struct *work) mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); /* enable DMA Tx/Tx and interrupt */ - mt7996_dma_start(dev, false); + mt7996_dma_start(dev, false, false); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + u32 wed_irq_mask = MT_INT_RRO_RX_DONE | MT_INT_TX_DONE_BAND2 | + dev->mt76.mmio.irqmask; + + if (mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) + wed_irq_mask &= ~MT_INT_RX_DONE_RRO_IND; + + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); + + mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, wed_irq_mask, + true); + mt7996_irq_enable(dev, wed_irq_mask); + mt7996_irq_disable(dev, 0); + } + + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) { + mt76_wr(dev, MT_INT_PCIE1_MASK_CSR, MT_INT_TX_RX_DONE_EXT); + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, + MT_INT_TX_RX_DONE_EXT); + } clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_RESET, &dev->mphy.state); @@ -1891,6 +1954,10 @@ void mt7996_mac_reset_work(struct work_struct *work) local_bh_disable(); mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) + continue; + napi_enable(&dev->mt76.napi[i]); napi_schedule(&dev->mt76.napi[i]); } @@ -2190,7 +2257,9 @@ void mt7996_mac_sta_rc_work(struct work_struct *work) IEEE80211_RC_BW_CHANGED)) mt7996_mcu_add_rate_ctrl(dev, vif, sta, true); - /* TODO: smps change */ + if (changed & IEEE80211_RC_SMPS_CHANGED) + mt7996_mcu_set_fixed_field(dev, vif, sta, NULL, + RATE_PARAM_MMPS_UPDATE); spin_lock_bh(&dev->mt76.sta_poll_lock); } @@ -2215,6 +2284,7 @@ void mt7996_mac_work(struct work_struct *work) mt7996_mac_update_stats(phy); + mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_RATE); if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_ADM_STAT); mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_MSDU_COUNT); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 482a8f7d75..51deea84b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -51,6 +51,14 @@ int mt7996_run(struct ieee80211_hw *hw) if (ret) goto out; + ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX); + if (ret) + goto out; + + ret = mt7996_mcu_set_thermal_protect(phy, true); + if (ret) + goto out; + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, @@ -394,6 +402,13 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed) ieee80211_wake_queues(hw); } + if (changed & (IEEE80211_CONF_CHANGE_POWER | + IEEE80211_CONF_CHANGE_CHANNEL)) { + ret = mt7996_mcu_set_txpower_sku(phy); + if (ret) + return ret; + } + mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { @@ -520,24 +535,25 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; struct mt76_phy *mphy = hw->priv; u16 rate; - u8 i, idx, ht; + u8 i, idx; rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast); - ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM; - if (beacon && ht) { - struct mt7996_dev *dev = mt7996_hw_dev(hw); + if (beacon) { + struct mt7996_phy *phy = mphy->priv; + + /* odd index for driver, even index for firmware */ + idx = MT7996_BEACON_RATES_TBL + 2 * phy->mt76->band_idx; + if (phy->beacon_rate != rate) + mt7996_mcu_set_fixed_rate_table(phy, idx, rate, beacon); - /* must odd index */ - idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20); - mt7996_mac_set_fixed_rate_table(dev, idx, rate); return idx; } idx = FIELD_GET(MT_TX_RATE_IDX, rate); for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx) - return MT7996_BASIC_RATES_TBL + i; + return MT7996_BASIC_RATES_TBL + 2 * i; return mvif->basic_rates_idx; } @@ -962,8 +978,8 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) mt76_set_stream_caps(phy->mt76, true); mt7996_set_stream_vht_txbf_caps(phy); mt7996_set_stream_he_eht_caps(phy); + mt7996_mcu_set_txpower_sku(phy); - /* TODO: update bmc_wtbl spe_idx when antenna changes */ mutex_unlock(&dev->mt76.mutex); return 0; @@ -988,6 +1004,7 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw, sinfo->txrate.he_gi = txrate->he_gi; sinfo->txrate.he_dcm = txrate->he_dcm; sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; + sinfo->txrate.eht_gi = txrate->eht_gi; } sinfo->txrate.flags = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); @@ -1394,6 +1411,44 @@ out: return ret; } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +static int +mt7996_net_fill_forward_path(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct net_device_path_ctx *ctx, + struct net_device_path *path) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + + if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2) + wed = &dev->mt76.mmio.wed_hif2; + + if (!mtk_wed_device_active(wed)) + return -ENODEV; + + if (msta->wcid.idx > MT7996_WTBL_STA) + return -EIO; + + path->type = DEV_PATH_MTK_WDMA; + path->dev = ctx->dev; + path->mtk_wdma.wdma_idx = wed->wdma_idx; + path->mtk_wdma.bss = mvif->mt76.idx; + path->mtk_wdma.queue = 0; + path->mtk_wdma.wcid = msta->wcid.idx; + + path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed); + ctx->dev = NULL; + + return 0; +} + +#endif + const struct ieee80211_ops mt7996_ops = { .tx = mt7996_tx, .start = mt7996_start, @@ -1438,4 +1493,8 @@ const struct ieee80211_ops mt7996_ops = { .sta_add_debugfs = mt7996_sta_add_debugfs, #endif .set_radar_background = mt7996_set_radar_background, +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + .net_fill_forward_path = mt7996_net_fill_forward_path, + .net_setup_tc = mt76_net_setup_tc, +#endif }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 0586f5bd41..9e70b96008 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -10,6 +10,20 @@ #include "mac.h" #include "eeprom.h" +#define fw_name(_dev, name, ...) ({ \ + char *_fw; \ + switch (mt76_chip(&(_dev)->mt76)) { \ + case 0x7992: \ + _fw = MT7992_##name; \ + break; \ + case 0x7990: \ + default: \ + _fw = MT7996_##name; \ + break; \ + } \ + _fw; \ +}) + struct mt7996_patch_hdr { char build_date[16]; char platform[4]; @@ -449,6 +463,43 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) } } +static int +mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate) +{ + switch (mcu_rate->tx_mode) { + case MT_PHY_TYPE_CCK: + case MT_PHY_TYPE_OFDM: + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + case MT_PHY_TYPE_VHT: + if (mcu_rate->tx_gi) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + else + rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + if (mcu_rate->tx_gi > NL80211_RATE_INFO_HE_GI_3_2) + return -EINVAL; + rate->he_gi = mcu_rate->tx_gi; + break; + case MT_PHY_TYPE_EHT_SU: + case MT_PHY_TYPE_EHT_TRIG: + case MT_PHY_TYPE_EHT_MU: + if (mcu_rate->tx_gi > NL80211_RATE_INFO_EHT_GI_3_2) + return -EINVAL; + rate->eht_gi = mcu_rate->tx_gi; + break; + default: + return -EINVAL; + } + + return 0; +} + static void mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) { @@ -465,6 +516,16 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) struct mt76_wcid *wcid; switch (le16_to_cpu(res->tag)) { + case UNI_ALL_STA_TXRX_RATE: + wlan_idx = le16_to_cpu(res->rate[i].wlan_idx); + wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); + + if (!wcid) + break; + + if (mt7996_mcu_update_tx_gi(&wcid->rate, &res->rate[i])) + dev_err(dev->mt76.dev, "Failed to update TX GI\n"); + break; case UNI_ALL_STA_TXRX_ADM_STAT: wlan_idx = le16_to_cpu(res->adm_stat[i].wlan_idx); wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); @@ -498,6 +559,34 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) } static void +mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb) +{ +#define THERMAL_NOTIFY_TAG 0x4 +#define THERMAL_NOTIFY 0x2 + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7996_mcu_thermal_notify *n; + struct mt7996_phy *phy; + + n = (struct mt7996_mcu_thermal_notify *)skb->data; + + if (le16_to_cpu(n->tag) != THERMAL_NOTIFY_TAG) + return; + + if (n->event_id != THERMAL_NOTIFY) + return; + + if (n->band_idx > MT_BAND2) + return; + + mphy = dev->mt76.phys[n->band_idx]; + if (!mphy) + return; + + phy = (struct mt7996_phy *)mphy->priv; + phy->throttle_state = n->duty_percent; +} + +static void mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb) { struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; @@ -520,6 +609,9 @@ mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) case MCU_EVENT_EXT: mt7996_mcu_rx_ext_event(dev, skb); break; + case MCU_UNI_EVENT_THERMAL: + mt7996_mcu_rx_thermal_notify(dev, skb); + break; default: break; } @@ -527,6 +619,73 @@ mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) } static void +mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb) +{ + struct mt7996_mcu_wed_rro_event *event = (void *)skb->data; + + if (!dev->has_rro) + return; + + skb_pull(skb, sizeof(struct mt7996_mcu_rxd) + 4); + + switch (le16_to_cpu(event->tag)) { + case UNI_WED_RRO_BA_SESSION_STATUS: { + struct mt7996_mcu_wed_rro_ba_event *e; + + while (skb->len >= sizeof(*e)) { + struct mt76_rx_tid *tid; + struct mt76_wcid *wcid; + u16 idx; + + e = (void *)skb->data; + idx = le16_to_cpu(e->wlan_id); + if (idx >= ARRAY_SIZE(dev->mt76.wcid)) + break; + + wcid = rcu_dereference(dev->mt76.wcid[idx]); + if (!wcid || !wcid->sta) + break; + + if (e->tid >= ARRAY_SIZE(wcid->aggr)) + break; + + tid = rcu_dereference(wcid->aggr[e->tid]); + if (!tid) + break; + + tid->id = le16_to_cpu(e->id); + skb_pull(skb, sizeof(*e)); + } + break; + } + case UNI_WED_RRO_BA_SESSION_DELETE: { + struct mt7996_mcu_wed_rro_ba_delete_event *e; + + while (skb->len >= sizeof(*e)) { + struct mt7996_wed_rro_session_id *session; + + e = (void *)skb->data; + session = kzalloc(sizeof(*session), GFP_ATOMIC); + if (!session) + break; + + session->id = le16_to_cpu(e->session_id); + + spin_lock_bh(&dev->wed_rro.lock); + list_add_tail(&session->list, &dev->wed_rro.poll_list); + spin_unlock_bh(&dev->wed_rro.lock); + + ieee80211_queue_work(mt76_hw(dev), &dev->wed_rro.work); + skb_pull(skb, sizeof(*e)); + } + break; + } + default: + break; + } +} + +static void mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) { struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; @@ -544,6 +703,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) case MCU_UNI_EVENT_ALL_STA_INFO: mt7996_mcu_rx_all_sta_info_event(dev, skb); break; + case MCU_UNI_EVENT_WED_RRO: + mt7996_mcu_wed_rro_event(dev, skb); + break; default: break; } @@ -963,7 +1125,7 @@ int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif) } static int -mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, +mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif *mvif, struct ieee80211_ampdu_params *params, bool enable, bool tx) { @@ -972,7 +1134,7 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, struct sk_buff *skb; struct tlv *tlv; - skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid, + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mvif, wcid, MT7996_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -986,8 +1148,9 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, ba->ba_en = enable << params->tid; ba->amsdu = params->amsdu; ba->tid = params->tid; + ba->ba_rdd_rro = !tx && enable && dev->has_rro; - return mt76_mcu_skb_send_msg(dev, skb, + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } @@ -1002,8 +1165,7 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, if (enable && !params->amsdu) msta->wcid.amsdu = false; - return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, - enable, true); + return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, true); } int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, @@ -1013,8 +1175,7 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv; struct mt7996_vif *mvif = msta->vif; - return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, - enable, false); + return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, false); } static void @@ -1120,7 +1281,7 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) static void mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { - struct sta_rec_ht *ht; + struct sta_rec_ht_uni *ht; struct tlv *tlv; if (!sta->deflink.ht_cap.ht_supported) @@ -1128,8 +1289,12 @@ mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); - ht = (struct sta_rec_ht *)tlv; + ht = (struct sta_rec_ht_uni *)tlv; ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap); + ht->ampdu_param = u8_encode_bits(sta->deflink.ht_cap.ampdu_factor, + IEEE80211_HT_AMPDU_PARM_FACTOR) | + u8_encode_bits(sta->deflink.ht_cap.ampdu_density, + IEEE80211_HT_AMPDU_PARM_DENSITY); } static void @@ -1587,44 +1752,6 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb, } static void -mt7996_mcu_sta_phy_tlv(struct mt7996_dev *dev, struct sk_buff *skb, - struct ieee80211_vif *vif, struct ieee80211_sta *sta) -{ - struct sta_rec_phy *phy; - struct tlv *tlv; - u8 af = 0, mm = 0; - - if (!sta->deflink.ht_cap.ht_supported && !sta->deflink.he_6ghz_capa.capa) - return; - - tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); - - phy = (struct sta_rec_phy *)tlv; - if (sta->deflink.ht_cap.ht_supported) { - af = sta->deflink.ht_cap.ampdu_factor; - mm = sta->deflink.ht_cap.ampdu_density; - } - - if (sta->deflink.vht_cap.vht_supported) { - u8 vht_af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, - sta->deflink.vht_cap.cap); - - af = max_t(u8, af, vht_af); - } - - if (sta->deflink.he_6ghz_capa.capa) { - af = le16_get_bits(sta->deflink.he_6ghz_capa.capa, - IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); - mm = le16_get_bits(sta->deflink.he_6ghz_capa.capa, - IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); - } - - phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, af) | - FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, mm); - phy->max_ampdu_len = af; -} - -static void mt7996_mcu_sta_hdrt_tlv(struct mt7996_dev *dev, struct sk_buff *skb) { struct sta_rec_hdrt *hdrt; @@ -1712,14 +1839,13 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, MCU_WM_UNI_CMD(RA), true); } -static int -mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, void *data, u32 field) +int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *data, u32 field) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct sta_phy *phy = data; - struct sta_rec_ra_fixed *ra; + struct sta_phy_uni *phy = data; + struct sta_rec_ra_fixed_uni *ra; struct sk_buff *skb; struct tlv *tlv; @@ -1730,7 +1856,7 @@ mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra)); - ra = (struct sta_rec_ra_fixed *)tlv; + ra = (struct sta_rec_ra_fixed_uni *)tlv; switch (field) { case RATE_PARAM_AUTO: @@ -1742,6 +1868,9 @@ mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, if (phy) ra->phy = *phy; break; + case RATE_PARAM_MMPS_UPDATE: + ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode); + break; default: break; } @@ -1759,7 +1888,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; enum nl80211_band band = chandef->chan->band; - struct sta_phy phy = {}; + struct sta_phy_uni phy = {}; int ret, nrates = 0; #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \ @@ -1847,13 +1976,13 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev, struct cfg80211_chan_def *chandef = &mphy->chandef; struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; enum nl80211_band band = chandef->chan->band; - struct sta_rec_ra *ra; + struct sta_rec_ra_uni *ra; struct tlv *tlv; u32 supp_rate = sta->deflink.supp_rates[band]; u32 cap = sta->wme ? STA_CAP_WMM : 0; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); - ra = (struct sta_rec_ra *)tlv; + ra = (struct sta_rec_ra_uni *)tlv; ra->valid = true; ra->auto_rate = true; @@ -2030,8 +2159,6 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, /* tag order is in accordance with firmware dependency. */ if (sta) { - /* starec phy */ - mt7996_mcu_sta_phy_tlv(dev, skb, vif, sta); /* starec hdrt mode */ mt7996_mcu_sta_hdrt_tlv(dev, skb); /* starec bfer */ @@ -2538,7 +2665,7 @@ static int mt7996_load_patch(struct mt7996_dev *dev) return -EAGAIN; } - ret = request_firmware(&fw, MT7996_ROM_PATCH, dev->mt76.dev); + ret = request_firmware(&fw, fw_name(dev, ROM_PATCH), dev->mt76.dev); if (ret) goto out; @@ -2701,17 +2828,17 @@ static int mt7996_load_ram(struct mt7996_dev *dev) { int ret; - ret = __mt7996_load_ram(dev, "WM", MT7996_FIRMWARE_WM, + ret = __mt7996_load_ram(dev, "WM", fw_name(dev, FIRMWARE_WM), MT7996_RAM_TYPE_WM); if (ret) return ret; - ret = __mt7996_load_ram(dev, "DSP", MT7996_FIRMWARE_DSP, + ret = __mt7996_load_ram(dev, "DSP", fw_name(dev, FIRMWARE_DSP), MT7996_RAM_TYPE_DSP); if (ret) return ret; - return __mt7996_load_ram(dev, "WA", MT7996_FIRMWARE_WA, + return __mt7996_load_ram(dev, "WA", fw_name(dev, FIRMWARE_WA), MT7996_RAM_TYPE_WA); } @@ -2863,9 +2990,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev) { struct uni_header hdr = {}; struct sk_buff *skb; - int len, num; + int len, num, i; - num = 2 + 2 * (dev->dbdc_support + dev->tbtc_support); + num = 2 + 2 * (mt7996_band_valid(dev, MT_BAND1) + + mt7996_band_valid(dev, MT_BAND2)); len = sizeof(hdr) + num * sizeof(struct vow_rx_airtime); skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); if (!skb) @@ -2873,13 +3001,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev) skb_put_data(skb, &hdr, sizeof(hdr)); - mt7996_add_rx_airtime_tlv(skb, dev->mt76.phy.band_idx); - - if (dev->dbdc_support) - mt7996_add_rx_airtime_tlv(skb, MT_BAND1); - - if (dev->tbtc_support) - mt7996_add_rx_airtime_tlv(skb, MT_BAND2); + for (i = 0; i < __MT_MAX_BAND; i++) { + if (mt7996_band_valid(dev, i)) + mt7996_add_rx_airtime_tlv(skb, i); + } return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(VOW), true); @@ -3305,7 +3430,7 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), .tx_path_num = hweight16(phy->mt76->chainmask), - .rx_path = phy->mt76->chainmask >> dev->chainshift[band_idx], + .rx_path = mt7996_rx_chainmask(phy) >> dev->chainshift[band_idx], .band_idx = band_idx, .channel_band = ch_band[chandef->chan->band], }; @@ -3577,6 +3702,121 @@ out: return 0; } +int mt7996_mcu_get_temperature(struct mt7996_phy *phy) +{ +#define TEMPERATURE_QUERY 0 +#define GET_TEMPERATURE 0 + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + u8 rsv1; + u8 action; + u8 band_idx; + u8 rsv2; + } req = { + .tag = cpu_to_le16(TEMPERATURE_QUERY), + .len = cpu_to_le16(sizeof(req) - 4), + .action = GET_TEMPERATURE, + .band_idx = phy->mt76->band_idx, + }; + struct mt7996_mcu_thermal { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + __le32 rsv; + __le32 temperature; + } __packed * res; + struct sk_buff *skb; + int ret; + + ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + res = (void *)skb->data; + + return le32_to_cpu(res->temperature); +} + +int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state) +{ + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + struct mt7996_mcu_thermal_ctrl ctrl; + } __packed req = { + .tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG), + .len = cpu_to_le16(sizeof(req) - 4), + .ctrl = { + .band_idx = phy->mt76->band_idx, + }, + }; + int level, ret; + + /* set duty cycle and level */ + for (level = 0; level < 4; level++) { + req.ctrl.duty.duty_level = level; + req.ctrl.duty.duty_cycle = state; + state /= 2; + + ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), false); + if (ret) + return ret; + } + + return 0; +} + +int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable) +{ +#define SUSTAIN_PERIOD 10 + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + struct mt7996_mcu_thermal_ctrl ctrl; + struct mt7996_mcu_thermal_enable enable; + } __packed req = { + .len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)), + .ctrl = { + .band_idx = phy->mt76->band_idx, + .type.protect_type = 1, + .type.trigger_type = 1, + }, + }; + int ret; + + req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE); + + ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req) - sizeof(req.enable), false); + if (ret || !enable) + return ret; + + /* set high-temperature trigger threshold */ + req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE); + req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0]); + req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]); + req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD); + + req.len = cpu_to_le16(sizeof(req) - 4); + + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), false); +} + int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band) { struct { @@ -4039,6 +4279,35 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } +int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx, + u16 rate_idx, bool beacon) +{ +#define UNI_FIXED_RATE_TABLE_SET 0 +#define SPE_IXD_SELECT_TXD 0 +#define SPE_IXD_SELECT_BMC_WTBL 1 + struct mt7996_dev *dev = phy->dev; + struct fixed_rate_table_ctrl req = { + .tag = cpu_to_le16(UNI_FIXED_RATE_TABLE_SET), + .len = cpu_to_le16(sizeof(req) - 4), + .table_idx = table_idx, + .rate_idx = cpu_to_le16(rate_idx), + .gi = 1, + .he_ltf = 1, + }; + u8 band_idx = phy->mt76->band_idx; + + if (beacon) { + req.spe_idx_sel = SPE_IXD_SELECT_TXD; + req.spe_idx = 24 + band_idx; + phy->beacon_rate = rate_idx; + } else { + req.spe_idx_sel = SPE_IXD_SELECT_BMC_WTBL; + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(FIXED_RATE_TABLE), + &req, sizeof(req), false); +} + int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set) { struct { @@ -4094,14 +4363,12 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev) &req, sizeof(req), false); } -int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val) +int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) { struct { u8 __rsv1[4]; - __le16 tag; __le16 len; - union { struct { u8 type; @@ -4116,6 +4383,11 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val) u8 path; u8 __rsv2[3]; } __packed txfree_path; + struct { + __le16 flush_one; + __le16 flush_all; + u8 __rsv2[4]; + } __packed timeout; }; } __packed req = { .tag = cpu_to_le16(tag), @@ -4132,6 +4404,10 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val) case UNI_RRO_SET_TXFREE_PATH: req.txfree_path.path = val; break; + case UNI_RRO_SET_FLUSH_TIMEOUT: + req.timeout.flush_one = cpu_to_le16(val); + req.timeout.flush_all = cpu_to_le16(2 * val); + break; default: return -EINVAL; } @@ -4156,3 +4432,81 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag) return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(ALL_STA_INFO), &req, sizeof(req), false); } + +int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id) +{ + struct { + u8 __rsv[4]; + + __le16 tag; + __le16 len; + __le16 session_id; + u8 pad[4]; + } __packed req = { + .tag = cpu_to_le16(UNI_RRO_DEL_BA_SESSION), + .len = cpu_to_le16(sizeof(req) - 4), + .session_id = cpu_to_le16(id), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req, + sizeof(req), true); +} + +int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy) +{ +#define TX_POWER_LIMIT_TABLE_RATE 0 + struct mt7996_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; + struct tx_power_limit_table_ctrl { + u8 __rsv1[4]; + + __le16 tag; + __le16 len; + u8 power_ctrl_id; + u8 power_limit_type; + u8 band_idx; + } __packed req = { + .tag = cpu_to_le16(UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL), + .len = cpu_to_le16(sizeof(req) + MT7996_SKU_RATE_NUM - 4), + .power_ctrl_id = UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL, + .power_limit_type = TX_POWER_LIMIT_TABLE_RATE, + .band_idx = phy->mt76->band_idx, + }; + struct mt76_power_limits la = {}; + struct sk_buff *skb; + int i, tx_power; + + tx_power = mt7996_get_power_bound(phy, hw->conf.power_level); + tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, + &la, tx_power); + mphy->txpower_cur = tx_power; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + sizeof(req) + MT7996_SKU_RATE_NUM); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &req, sizeof(req)); + /* cck and ofdm */ + skb_put_data(skb, &la.cck, sizeof(la.cck)); + skb_put_data(skb, &la.ofdm, sizeof(la.ofdm)); + /* ht20 */ + skb_put_data(skb, &la.mcs[0], 8); + /* ht40 */ + skb_put_data(skb, &la.mcs[1], 9); + + /* vht */ + for (i = 0; i < 4; i++) { + skb_put_data(skb, &la.mcs[i], sizeof(la.mcs[i])); + skb_put_zero(skb, 2); /* padding */ + } + + /* he */ + skb_put_data(skb, &la.ru[0], sizeof(la.ru)); + /* eht */ + skb_put_data(skb, &la.eht[0], sizeof(la.eht)); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WM_UNI_CMD(TXPOWER), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 32ce57c8c4..36cacc495c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -30,6 +30,28 @@ struct mt7996_mcu_uni_event { __le32 status; /* 0: success, others: fail */ } __packed; +struct mt7996_mcu_thermal_ctrl { + u8 ctrl_id; + u8 band_idx; + union { + struct { + u8 protect_type; /* 1: duty admit, 2: radio off */ + u8 trigger_type; /* 0: low, 1: high */ + } __packed type; + struct { + u8 duty_level; /* level 0~3 */ + u8 duty_cycle; + } __packed duty; + }; +} __packed; + +struct mt7996_mcu_thermal_enable { + __le32 trigger_temp; + __le32 restore_temp; + __le16 sustain_time; + u8 rsv[2]; +} __packed; + struct mt7996_mcu_csa_notify { struct mt7996_mcu_rxd rxd; @@ -153,6 +175,27 @@ struct mt7996_mcu_mib { __le64 data; } __packed; +struct all_sta_trx_rate { + __le16 wlan_idx; + u8 __rsv1[2]; + u8 tx_mode; + u8 flags; + u8 tx_stbc; + u8 tx_gi; + u8 tx_bw; + u8 tx_ldpc; + u8 tx_mcs; + u8 tx_nss; + u8 rx_rate; + u8 rx_mode; + u8 rx_nsts; + u8 rx_gi; + u8 rx_coding; + u8 rx_stbc; + u8 rx_bw; + u8 __rsv2; +} __packed; + struct mt7996_mcu_all_sta_info_event { u8 rsv[4]; __le16 tag; @@ -163,22 +206,74 @@ struct mt7996_mcu_all_sta_info_event { u8 rsv3[4]; union { - struct { + DECLARE_FLEX_ARRAY(struct all_sta_trx_rate, rate); + DECLARE_FLEX_ARRAY(struct { __le16 wlan_idx; u8 rsv[2]; __le32 tx_bytes[IEEE80211_NUM_ACS]; __le32 rx_bytes[IEEE80211_NUM_ACS]; - } adm_stat[0] __packed; + } __packed, adm_stat); - struct { + DECLARE_FLEX_ARRAY(struct { __le16 wlan_idx; u8 rsv[2]; __le32 tx_msdu_cnt; __le32 rx_msdu_cnt; - } msdu_cnt[0] __packed; + } __packed, msdu_cnt); } __packed; } __packed; +struct mt7996_mcu_wed_rro_event { + struct mt7996_mcu_rxd rxd; + + u8 __rsv1[4]; + + __le16 tag; + __le16 len; +} __packed; + +struct mt7996_mcu_wed_rro_ba_event { + __le16 tag; + __le16 len; + + __le16 wlan_id; + u8 tid; + u8 __rsv1; + __le32 status; + __le16 id; + u8 __rsv2[2]; +} __packed; + +struct mt7996_mcu_wed_rro_ba_delete_event { + __le16 tag; + __le16 len; + + __le16 session_id; + u8 __rsv2[2]; +} __packed; + +enum { + UNI_WED_RRO_BA_SESSION_STATUS, + UNI_WED_RRO_BA_SESSION_TBL, + UNI_WED_RRO_BA_SESSION_DELETE, +}; + +struct mt7996_mcu_thermal_notify { + struct mt7996_mcu_rxd rxd; + + u8 __rsv1[4]; + + __le16 tag; + __le16 len; + + u8 event_id; + u8 band_idx; + u8 level_idx; + u8 duty_percent; + __le32 restore_temp; + u8 __rsv2[4]; +} __packed; + enum mt7996_chan_mib_offs { UNI_MIB_OBSS_AIRTIME = 26, UNI_MIB_NON_WIFI_TIME = 27, @@ -389,6 +484,15 @@ struct bss_mld_tlv { u8 __rsv[3]; } __packed; +struct sta_rec_ht_uni { + __le16 tag; + __le16 len; + __le16 ht_cap; + __le16 ht_cap_ext; + u8 ampdu_param; + u8 _rsv[3]; +} __packed; + struct sta_rec_ba_uni { __le16 tag; __le16 len; @@ -438,6 +542,73 @@ struct sta_rec_sec_uni { struct sec_key_uni key[2]; } __packed; +struct sta_phy_uni { + u8 type; + u8 flag; + u8 stbc; + u8 sgi; + u8 bw; + u8 ldpc; + u8 mcs; + u8 nss; + u8 he_ltf; + u8 rsv[3]; +}; + +struct sta_rec_ra_uni { + __le16 tag; + __le16 len; + + u8 valid; + u8 auto_rate; + u8 phy_mode; + u8 channel; + u8 bw; + u8 disable_cck; + u8 ht_mcs32; + u8 ht_gf; + u8 ht_mcs[4]; + u8 mmps_mode; + u8 gband_256; + u8 af; + u8 auth_wapi_mode; + u8 rate_len; + + u8 supp_mode; + u8 supp_cck_rate; + u8 supp_ofdm_rate; + __le32 supp_ht_mcs; + __le16 supp_vht_mcs[4]; + + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + __le32 sta_cap; + + struct sta_phy_uni phy; + u8 rx_rcpi[4]; +} __packed; + +struct sta_rec_ra_fixed_uni { + __le16 tag; + __le16 len; + + __le32 field; + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + struct sta_phy_uni phy; + + u8 spe_idx; + u8 short_preamble; + u8 is_5g; + u8 mmps_mode; +} __packed; + struct sta_rec_hdrt { __le16 tag; __le16 len; @@ -613,17 +784,16 @@ enum { #define MT7996_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct sta_rec_basic) + \ sizeof(struct sta_rec_bf) + \ - sizeof(struct sta_rec_ht) + \ + sizeof(struct sta_rec_ht_uni) + \ sizeof(struct sta_rec_he_v2) + \ sizeof(struct sta_rec_ba_uni) + \ sizeof(struct sta_rec_vht) + \ sizeof(struct sta_rec_uapsd) + \ sizeof(struct sta_rec_amsdu) + \ sizeof(struct sta_rec_bfee) + \ - sizeof(struct sta_rec_phy) + \ - sizeof(struct sta_rec_ra) + \ + sizeof(struct sta_rec_ra_uni) + \ sizeof(struct sta_rec_sec) + \ - sizeof(struct sta_rec_ra_fixed) + \ + sizeof(struct sta_rec_ra_fixed_uni) + \ sizeof(struct sta_rec_he_6g_capa) + \ sizeof(struct sta_rec_eht) + \ sizeof(struct sta_rec_hdrt) + \ @@ -639,6 +809,18 @@ enum { #define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \ MT7996_BEACON_UPDATE_SIZE) +static inline s8 +mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower) +{ + struct mt76_phy *mphy = phy->mt76; + int n_chains = hweight16(mphy->chainmask); + + txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2); + txpower -= mt76_tx_power_nss_delta(n_chains); + + return txpower; +} + enum { UNI_BAND_CONFIG_RADIO_ENABLE, UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, @@ -686,6 +868,8 @@ enum { UNI_RRO_GET_BA_SESSION_TABLE, UNI_RRO_SET_BYPASS_MODE, UNI_RRO_SET_TXFREE_PATH, + UNI_RRO_DEL_BA_SESSION, + UNI_RRO_SET_FLUSH_TIMEOUT }; enum{ @@ -700,6 +884,16 @@ enum{ }; enum { + UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6, + UNI_CMD_THERMAL_PROTECT_DISABLE, + UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG, +}; + +enum { + UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4, +}; + +enum { UNI_CMD_ACCESS_REG_BASIC = 0x0, UNI_CMD_ACCESS_RF_REG_BASIC, }; @@ -737,4 +931,24 @@ enum { #define MT7996_SEC_KEY_IDX GENMASK(2, 1) #define MT7996_SEC_IV BIT(3) +struct fixed_rate_table_ctrl { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + u8 table_idx; + u8 antenna_idx; + __le16 rate_idx; + u8 spe_idx_sel; + u8 spe_idx; + u8 gi; + u8 he_ltf; + bool ldpc; + bool txbf; + bool dynamic_bw; + + u8 _rsv2; +} __packed; + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 3a591a7b47..efd4a767eb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -6,10 +6,16 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/rtnetlink.h> #include "mt7996.h" #include "mac.h" +#include "mcu.h" #include "../trace.h" +#include "../dma.h" + +static bool wed_enable; +module_param(wed_enable, bool, 0644); static const struct __base mt7996_reg_base[] = { [WF_AGG_BASE] = { { 0x820e2000, 0x820f2000, 0x830e2000 } }, @@ -24,6 +30,58 @@ static const struct __base mt7996_reg_base[] = { [WF_RATE_BASE] = { { 0x820ee000, 0x820fe000, 0x830ee000 } }, }; +static const u32 mt7996_offs[] = { + [MIB_RVSR0] = 0x720, + [MIB_RVSR1] = 0x724, + [MIB_BTSCR5] = 0x788, + [MIB_BTSCR6] = 0x798, + [MIB_RSCR1] = 0x7ac, + [MIB_RSCR27] = 0x954, + [MIB_RSCR28] = 0x958, + [MIB_RSCR29] = 0x95c, + [MIB_RSCR30] = 0x960, + [MIB_RSCR31] = 0x964, + [MIB_RSCR33] = 0x96c, + [MIB_RSCR35] = 0x974, + [MIB_RSCR36] = 0x978, + [MIB_BSCR0] = 0x9cc, + [MIB_BSCR1] = 0x9d0, + [MIB_BSCR2] = 0x9d4, + [MIB_BSCR3] = 0x9d8, + [MIB_BSCR4] = 0x9dc, + [MIB_BSCR5] = 0x9e0, + [MIB_BSCR6] = 0x9e4, + [MIB_BSCR7] = 0x9e8, + [MIB_BSCR17] = 0xa10, + [MIB_TRDR1] = 0xa28, +}; + +static const u32 mt7992_offs[] = { + [MIB_RVSR0] = 0x760, + [MIB_RVSR1] = 0x764, + [MIB_BTSCR5] = 0x7c8, + [MIB_BTSCR6] = 0x7d8, + [MIB_RSCR1] = 0x7f0, + [MIB_RSCR27] = 0x998, + [MIB_RSCR28] = 0x99c, + [MIB_RSCR29] = 0x9a0, + [MIB_RSCR30] = 0x9a4, + [MIB_RSCR31] = 0x9a8, + [MIB_RSCR33] = 0x9b0, + [MIB_RSCR35] = 0x9b8, + [MIB_RSCR36] = 0x9bc, + [MIB_BSCR0] = 0xac8, + [MIB_BSCR1] = 0xacc, + [MIB_BSCR2] = 0xad0, + [MIB_BSCR3] = 0xad4, + [MIB_BSCR4] = 0xad8, + [MIB_BSCR5] = 0xadc, + [MIB_BSCR6] = 0xae0, + [MIB_BSCR7] = 0xae4, + [MIB_BSCR17] = 0xb0c, + [MIB_TRDR1] = 0xb24, +}; + static const struct __map mt7996_reg_map[] = { { 0x54000000, 0x02000, 0x1000 }, /* WFDMA_0 (PCIE0 MCU DMA0) */ { 0x55000000, 0x03000, 0x1000 }, /* WFDMA_1 (PCIE0 MCU DMA1) */ @@ -82,7 +140,6 @@ static u32 mt7996_reg_map_l1(struct mt7996_dev *dev, u32 addr) u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); - dev->reg_l1_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1, MT_HIF_REMAP_L1_MASK, FIELD_PREP(MT_HIF_REMAP_L1_MASK, base)); @@ -97,7 +154,6 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr) u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr); u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr); - dev->reg_l2_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2); dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2, MT_HIF_REMAP_L2_MASK, FIELD_PREP(MT_HIF_REMAP_L2_MASK, base)); @@ -107,26 +163,10 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr) return MT_HIF_REMAP_BASE_L2 + offset; } -static void mt7996_reg_remap_restore(struct mt7996_dev *dev) -{ - /* remap to ori status */ - if (unlikely(dev->reg_l1_backup)) { - dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L1, dev->reg_l1_backup); - dev->reg_l1_backup = 0; - } - - if (dev->reg_l2_backup) { - dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L2, dev->reg_l2_backup); - dev->reg_l2_backup = 0; - } -} - static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) { int i; - mt7996_reg_remap_restore(dev); - if (addr < 0x100000) return addr; @@ -143,6 +183,11 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) return dev->reg.map[i].mapped + ofs; } + return 0; +} + +static u32 __mt7996_reg_remap_addr(struct mt7996_dev *dev, u32 addr) +{ if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) || (addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) || (addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END)) @@ -167,28 +212,223 @@ void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, { u32 addr = __mt7996_reg_addr(dev, offset); - memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); + if (addr) { + memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); + return; + } + + spin_lock_bh(&dev->reg_lock); + memcpy_fromio(buf, dev->mt76.mmio.regs + + __mt7996_reg_remap_addr(dev, offset), len); + spin_unlock_bh(&dev->reg_lock); } static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + u32 addr = __mt7996_reg_addr(dev, offset), val; - return dev->bus_ops->rr(mdev, __mt7996_reg_addr(dev, offset)); + if (addr) + return dev->bus_ops->rr(mdev, addr); + + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rr(mdev, __mt7996_reg_remap_addr(dev, offset)); + spin_unlock_bh(&dev->reg_lock); + + return val; } static void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + u32 addr = __mt7996_reg_addr(dev, offset); + + if (addr) { + dev->bus_ops->wr(mdev, addr, val); + return; + } - dev->bus_ops->wr(mdev, __mt7996_reg_addr(dev, offset), val); + spin_lock_bh(&dev->reg_lock); + dev->bus_ops->wr(mdev, __mt7996_reg_remap_addr(dev, offset), val); + spin_unlock_bh(&dev->reg_lock); } static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + u32 addr = __mt7996_reg_addr(dev, offset); + + if (addr) + return dev->bus_ops->rmw(mdev, addr, mask, val); - return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val); + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rmw(mdev, __mt7996_reg_remap_addr(dev, offset), mask, val); + spin_unlock_bh(&dev->reg_lock); + + return val; +} + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +static int mt7996_mmio_wed_reset(struct mtk_wed_device *wed) +{ + struct mt76_dev *mdev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt76_phy *mphy = &dev->mphy; + int ret; + + ASSERT_RTNL(); + + if (test_and_set_bit(MT76_STATE_WED_RESET, &mphy->state)) + return -EBUSY; + + ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, UNI_CMD_SER_SET_RECOVER_L1, + mphy->band_idx); + if (ret) + goto out; + + rtnl_unlock(); + if (!wait_for_completion_timeout(&mdev->mmio.wed_reset, 20 * HZ)) { + dev_err(mdev->dev, "wed reset timeout\n"); + ret = -ETIMEDOUT; + } + rtnl_lock(); +out: + clear_bit(MT76_STATE_WED_RESET, &mphy->state); + + return ret; +} +#endif + +int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, + bool hif2, int *irq) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct pci_dev *pci_dev = pdev_ptr; + u32 hif1_ofs = 0; + + if (!wed_enable) + return 0; + + dev->has_rro = true; + + hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); + + if (hif2) + wed = &dev->mt76.mmio.wed_hif2; + + wed->wlan.pci_dev = pci_dev; + wed->wlan.bus_type = MTK_WED_BUS_PCIE; + + wed->wlan.base = devm_ioremap(dev->mt76.dev, + pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + wed->wlan.phy_base = pci_resource_start(pci_dev, 0); + + if (hif2) { + wed->wlan.wpdma_int = wed->wlan.phy_base + + MT_INT_PCIE1_SOURCE_CSR_EXT; + wed->wlan.wpdma_mask = wed->wlan.phy_base + + MT_INT_PCIE1_MASK_CSR; + wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs + + MT_TXQ_RING_BASE(0) + + MT7996_TXQ_BAND2 * MT_RING_SIZE; + if (dev->has_rro) { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE2 * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1; + } else { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1; + } + + wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG; + wed->wlan.wpdma_rx = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; + + wed->wlan.id = 0x7991; + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; + } else { + wed->wlan.hw_rro = dev->has_rro; /* default on */ + wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR; + wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR; + wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) + + MT7996_TXQ_BAND0 * MT_RING_SIZE; + + wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + MT_WFDMA0_GLO_CFG; + + wed->wlan.wpdma_rx = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; + + wed->wlan.wpdma_rx_rro[0] = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) + + MT7996_RXQ_RRO_BAND0 * MT_RING_SIZE; + wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) + + MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE; + wed->wlan.wpdma_rx_pg = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_MSDU_PG_BAND0) + + MT7996_RXQ_MSDU_PG_BAND0 * MT_RING_SIZE; + + wed->wlan.rx_nbuf = 65536; + wed->wlan.rx_npkt = dev->hif2 ? 32768 : 24576; + wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE); + + wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1; + wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1; + + wed->wlan.rro_rx_tbit[0] = ffs(MT_INT_RX_DONE_RRO_BAND0) - 1; + wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1; + + wed->wlan.rx_pg_tbit[0] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND0) - 1; + wed->wlan.rx_pg_tbit[1] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND1) - 1; + wed->wlan.rx_pg_tbit[2] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND2) - 1; + + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1; + wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1; + if (dev->has_rro) { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE0 * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1; + } else { + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; + } + dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt; + } + + wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE; + wed->wlan.token_start = MT7996_TOKEN_SIZE - wed->wlan.nbuf; + + wed->wlan.amsdu_max_subframes = 8; + wed->wlan.amsdu_max_len = 1536; + + wed->wlan.init_buf = mt7996_wed_init_buf; + wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; + wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; + wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; + if (!hif2) { + wed->wlan.reset = mt7996_mmio_wed_reset; + wed->wlan.reset_complete = mt76_mmio_wed_reset_complete; + } + + if (mtk_wed_device_attach(wed)) + return 0; + + *irq = wed->irq; + dev->mt76.dma_dev = wed->dev; + + return 1; +#else + return 0; +#endif } static int mt7996_mmio_init(struct mt76_dev *mdev, @@ -200,10 +440,18 @@ static int mt7996_mmio_init(struct mt76_dev *mdev, dev = container_of(mdev, struct mt7996_dev, mt76); mt76_mmio_init(&dev->mt76, mem_base); + spin_lock_init(&dev->reg_lock); switch (device_id) { case 0x7990: dev->reg.base = mt7996_reg_base; + dev->reg.offs_rev = mt7996_offs; + dev->reg.map = mt7996_reg_map; + dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map); + break; + case 0x7992: + dev->reg.base = mt7996_reg_base; + dev->reg.offs_rev = mt7992_offs; dev->reg.map = mt7996_reg_map; dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map); break; @@ -241,8 +489,17 @@ void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg, mdev->mmio.irqmask |= set; if (write_reg) { - mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); - mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); + if (mtk_wed_device_active(&mdev->mmio.wed)) { + mtk_wed_device_irq_set_mask(&mdev->mmio.wed, + mdev->mmio.irqmask); + if (mtk_wed_device_active(&mdev->mmio.wed_hif2)) { + mtk_wed_device_irq_set_mask(&mdev->mmio.wed_hif2, + mdev->mmio.irqmask); + } + } else { + mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); + mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); + } } spin_unlock_irqrestore(&mdev->mmio.irq_lock, flags); @@ -260,22 +517,36 @@ static void mt7996_rx_poll_complete(struct mt76_dev *mdev, static void mt7996_irq_tasklet(struct tasklet_struct *t) { struct mt7996_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet); + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2; u32 i, intr, mask, intr1; - mt76_wr(dev, MT_INT_MASK_CSR, 0); - if (dev->hif2) - mt76_wr(dev, MT_INT1_MASK_CSR, 0); - - intr = mt76_rr(dev, MT_INT_SOURCE_CSR); - intr &= dev->mt76.mmio.irqmask; - mt76_wr(dev, MT_INT_SOURCE_CSR, intr); - - if (dev->hif2) { - intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); - intr1 &= dev->mt76.mmio.irqmask; - mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); + if (dev->hif2 && mtk_wed_device_active(wed_hif2)) { + mtk_wed_device_irq_set_mask(wed_hif2, 0); + intr1 = mtk_wed_device_irq_get(wed_hif2, + dev->mt76.mmio.irqmask); + if (intr1 & MT_INT_RX_TXFREE_EXT) + napi_schedule(&dev->mt76.napi[MT_RXQ_TXFREE_BAND2]); + } - intr |= intr1; + if (mtk_wed_device_active(wed)) { + mtk_wed_device_irq_set_mask(wed, 0); + intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask); + intr |= (intr1 & ~MT_INT_RX_TXFREE_EXT); + } else { + mt76_wr(dev, MT_INT_MASK_CSR, 0); + if (dev->hif2) + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + intr &= dev->mt76.mmio.irqmask; + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + if (dev->hif2) { + intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); + intr1 &= dev->mt76.mmio.irqmask; + mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); + intr |= intr1; + } } trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); @@ -308,9 +579,17 @@ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance) { struct mt7996_dev *dev = dev_instance; - mt76_wr(dev, MT_INT_MASK_CSR, 0); - if (dev->hif2) - mt76_wr(dev, MT_INT1_MASK_CSR, 0); + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed, 0); + else + mt76_wr(dev, MT_INT_MASK_CSR, 0); + + if (dev->hif2) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed_hif2, 0); + else + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + } if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; @@ -391,4 +670,5 @@ static void __exit mt7996_exit(void) module_init(mt7996_init); module_exit(mt7996_exit); +MODULE_DESCRIPTION("MediaTek MT7996 MMIO helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 6733ee9744..36d1f247d5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -13,6 +13,7 @@ #define MT7996_MAX_INTERFACES 19 /* per-band */ #define MT7996_MAX_WMM_SETS 4 +#define MT7996_WTBL_BMC_SIZE (is_mt7992(&dev->mt76) ? 32 : 64) #define MT7996_WTBL_RESERVED (mt7996_wtbl_size(dev) - 1) #define MT7996_WTBL_STA (MT7996_WTBL_RESERVED - \ mt7996_max_interface_num(dev)) @@ -33,23 +34,55 @@ #define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin" #define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin" +#define MT7992_FIRMWARE_WA "mediatek/mt7996/mt7992_wa.bin" +#define MT7992_FIRMWARE_WM "mediatek/mt7996/mt7992_wm.bin" +#define MT7992_FIRMWARE_DSP "mediatek/mt7996/mt7992_dsp.bin" +#define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin" + #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin" +#define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom.bin" #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 #define MT7996_TOKEN_SIZE 16384 +#define MT7996_HW_TOKEN_SIZE 8192 #define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ +#define MT7996_SKU_RATE_NUM 417 + #define MT7996_MAX_TWT_AGRT 16 #define MT7996_MAX_STA_TWT_AGRT 8 #define MT7996_MIN_TWT_DUR 64 #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3) /* NOTE: used to map mt76_rates. idx may change if firmware expands table */ -#define MT7996_BASIC_RATES_TBL 11 +#define MT7996_BASIC_RATES_TBL 31 #define MT7996_BEACON_RATES_TBL 25 +#define MT7996_THERMAL_THROTTLE_MAX 100 +#define MT7996_CDEV_THROTTLE_MAX 99 +#define MT7996_CRIT_TEMP_IDX 0 +#define MT7996_MAX_TEMP_IDX 1 +#define MT7996_CRIT_TEMP 110 +#define MT7996_MAX_TEMP 120 + +#define MT7996_RRO_MAX_SESSION 1024 +#define MT7996_RRO_WINDOW_MAX_LEN 1024 +#define MT7996_RRO_ADDR_ELEM_LEN 128 +#define MT7996_RRO_BA_BITMAP_LEN 2 +#define MT7996_RRO_BA_BITMAP_CR_SIZE ((MT7996_RRO_MAX_SESSION * 128) / \ + MT7996_RRO_BA_BITMAP_LEN) +#define MT7996_RRO_BA_BITMAP_SESSION_SIZE (MT7996_RRO_MAX_SESSION / \ + MT7996_RRO_ADDR_ELEM_LEN) +#define MT7996_RRO_WINDOW_MAX_SIZE (MT7996_RRO_WINDOW_MAX_LEN * \ + MT7996_RRO_BA_BITMAP_SESSION_SIZE) + +#define MT7996_RX_BUF_SIZE (1800 + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +#define MT7996_RX_MSDU_PAGE_SIZE (128 + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) + struct mt7996_vif; struct mt7996_sta; struct mt7996_dfs_pulse; @@ -74,11 +107,21 @@ enum mt7996_rxq_id { MT7996_RXQ_MCU_WM = 0, MT7996_RXQ_MCU_WA, MT7996_RXQ_MCU_WA_MAIN = 2, - MT7996_RXQ_MCU_WA_EXT = 2,/* unused */ + MT7996_RXQ_MCU_WA_EXT = 3, /* for mt7992 */ MT7996_RXQ_MCU_WA_TRI = 3, MT7996_RXQ_BAND0 = 4, - MT7996_RXQ_BAND1 = 4,/* unused */ + MT7996_RXQ_BAND1 = 5, /* for mt7992 */ MT7996_RXQ_BAND2 = 5, + MT7996_RXQ_RRO_BAND0 = 8, + MT7996_RXQ_RRO_BAND1 = 8,/* unused */ + MT7996_RXQ_RRO_BAND2 = 6, + MT7996_RXQ_MSDU_PG_BAND0 = 10, + MT7996_RXQ_MSDU_PG_BAND1 = 11, + MT7996_RXQ_MSDU_PG_BAND2 = 12, + MT7996_RXQ_TXFREE0 = 9, + MT7996_RXQ_TXFREE1 = 9, + MT7996_RXQ_TXFREE2 = 7, + MT7996_RXQ_RRO_IND = 0, }; struct mt7996_twt_flow { @@ -147,6 +190,20 @@ struct mt7996_hif { int irq; }; +struct mt7996_wed_rro_addr { + u32 head_low; + u32 head_high : 4; + u32 count: 11; + u32 oor: 1; + u32 rsv : 8; + u32 signature : 8; +}; + +struct mt7996_wed_rro_session_id { + struct list_head list; + u16 id; +}; + struct mt7996_phy { struct mt76_phy *mt76; struct mt7996_dev *dev; @@ -155,6 +212,11 @@ struct mt7996_phy { struct ieee80211_vif *monitor_vif; + struct thermal_cooling_device *cdev; + u8 cdev_state; + u8 throttle_state; + u32 throttle_temp[2]; /* 0: critical high, 1: maximum */ + u32 rxfilter; u64 omac_mask; @@ -165,11 +227,15 @@ struct mt7996_phy { u8 rdd_state; + u16 beacon_rate; + u32 rx_ampdu_ts; u32 ampdu_ref; struct mt76_mib_stats mib; struct mt76_channel_state state_ts; + + bool has_aux_rx; }; struct mt7996_dev { @@ -222,10 +288,28 @@ struct mt7996_dev { u32 hw_pattern; - bool dbdc_support:1; - bool tbtc_support:1; bool flash_mode:1; bool has_eht:1; + bool has_rro:1; + + struct { + struct { + void *ptr; + dma_addr_t phy_addr; + } ba_bitmap[MT7996_RRO_BA_BITMAP_LEN]; + struct { + void *ptr; + dma_addr_t phy_addr; + } addr_elem[MT7996_RRO_ADDR_ELEM_LEN]; + struct { + void *ptr; + dma_addr_t phy_addr; + } session; + + struct work_struct work; + struct list_head poll_list; + spinlock_t lock; + } wed_rro; bool ibf; u8 fw_debug_wm; @@ -241,8 +325,7 @@ struct mt7996_dev { u8 n_agrt; } twt; - u32 reg_l1_backup; - u32 reg_l2_backup; + spinlock_t reg_lock; u8 wtbl_size_group; }; @@ -315,6 +398,20 @@ mt7996_phy3(struct mt7996_dev *dev) return __mt7996_phy(dev, MT_BAND2); } +static inline bool +mt7996_band_valid(struct mt7996_dev *dev, u8 band) +{ + if (is_mt7992(&dev->mt76)) + return band <= MT_BAND1; + + /* tri-band support */ + if (band <= MT_BAND2 && + mt76_get_field(dev, MT_PAD_GPIO, MT_PAD_GPIO_ADIE_COMB) <= 1) + return true; + + return band == MT_BAND0 || band == MT_BAND2; +} + extern const struct ieee80211_ops mt7996_ops; extern struct pci_driver mt7996_pci_driver; extern struct pci_driver mt7996_hif_driver; @@ -335,9 +432,10 @@ int mt7996_dma_init(struct mt7996_dev *dev); void mt7996_dma_reset(struct mt7996_dev *dev, bool force); void mt7996_dma_prefetch(struct mt7996_dev *dev); void mt7996_dma_cleanup(struct mt7996_dev *dev); -void mt7996_dma_start(struct mt7996_dev *dev, bool reset); -void mt7996_init_txpower(struct mt7996_dev *dev, - struct ieee80211_supported_band *sband); +void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset); +int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, + int n_desc, int ring_base, struct mtk_wed_device *wed); +void mt7996_init_txpower(struct mt7996_phy *phy); int mt7996_txbf_init(struct mt7996_dev *dev); void mt7996_reset(struct mt7996_dev *dev); int mt7996_run(struct ieee80211_hw *hw); @@ -374,6 +472,8 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag); int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif); int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, void *data, u16 version); +int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *data, u32 field); int mt7996_mcu_set_eeprom(struct mt7996_dev *dev); int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset); int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num); @@ -389,13 +489,19 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable); int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val); int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif); int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); +int mt7996_mcu_get_temperature(struct mt7996_phy *phy); +int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); +int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); +int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val); int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef); +int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx, + u16 rate_idx, bool beacon); int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set); int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans); -int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val); +int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val); int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3); int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl); int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level); @@ -403,15 +509,18 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev); void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb); void mt7996_mcu_exit(struct mt7996_dev *dev); int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); +int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) { - return MT7996_MAX_INTERFACES * (1 + dev->dbdc_support + dev->tbtc_support); + return min(MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) + + mt7996_band_valid(dev, MT_BAND2)), + MT7996_WTBL_BMC_SIZE); } static inline u16 mt7996_wtbl_size(struct mt7996_dev *dev) { - return (dev->wtbl_size_group << 8) + 64; + return (dev->wtbl_size_group << 8) + MT7996_WTBL_BMC_SIZE; } void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg, @@ -438,6 +547,18 @@ static inline void mt7996_irq_disable(struct mt7996_dev *dev, u32 mask) void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, size_t len); +static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy) +{ + int max_nss = hweight8(phy->mt76->hw->wiphy->available_antennas_tx); + int cur_nss = hweight8(phy->mt76->antenna_mask); + u16 tx_chainmask = phy->mt76->chainmask; + + if (cur_nss != max_nss) + return tx_chainmask; + + return tx_chainmask | (BIT(fls(tx_chainmask)) * phy->has_aux_rx); +} + void mt7996_mac_init(struct mt7996_dev *dev); u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw); bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask); @@ -446,8 +567,6 @@ void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy); void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band); void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, struct ieee80211_vif *vif, bool enable); -void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev, - u8 tbl_idx, u16 rate_idx); void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, @@ -497,5 +616,16 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); #endif +int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, + bool hif2, int *irq); +u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id); + +#ifdef CONFIG_MTK_DEBUG +int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); +#endif + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt7996_dma_rro_init(struct mt7996_dev *dev); +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index 67c0158962..0405618136 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -96,10 +96,10 @@ static int mt7996_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct pci_dev *hif2_dev; + struct mt7996_hif *hif2; struct mt7996_dev *dev; + int irq, hif2_irq, ret; struct mt76_dev *mdev; - struct mt7996_hif *hif2; - int irq, ret; ret = pcim_enable_device(pdev); if (ret) @@ -111,7 +111,11 @@ static int mt7996_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(36)); + if (ret) + return ret; + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; @@ -129,15 +133,22 @@ static int mt7996_pci_probe(struct pci_dev *pdev, mt7996_wfsys_reset(dev); hif2 = mt7996_pci_init_hif2(pdev); - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + ret = mt7996_mmio_wed_init(dev, pdev, false, &irq); if (ret < 0) - goto free_device; + goto free_wed_or_irq_vector; + + if (!ret) { + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free_device; + + irq = pdev->irq; + } - irq = pdev->irq; ret = devm_request_irq(mdev->dev, irq, mt7996_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) - goto free_irq_vector; + goto free_wed_or_irq_vector; mt76_wr(dev, MT_INT_MASK_CSR, 0); /* master switch of PCIe tnterrupt enable */ @@ -147,16 +158,25 @@ static int mt7996_pci_probe(struct pci_dev *pdev, hif2_dev = container_of(hif2->dev, struct pci_dev, dev); dev->hif2 = hif2; - ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, PCI_IRQ_ALL_TYPES); + ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &hif2_irq); if (ret < 0) - goto free_hif2; + goto free_hif2_wed_irq_vector; + + if (!ret) { + ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, + PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free_hif2; - dev->hif2->irq = hif2_dev->irq; - ret = devm_request_irq(mdev->dev, dev->hif2->irq, - mt7996_irq_handler, IRQF_SHARED, - KBUILD_MODNAME "-hif", dev); + dev->hif2->irq = hif2_dev->irq; + hif2_irq = dev->hif2->irq; + } + + ret = devm_request_irq(mdev->dev, hif2_irq, mt7996_irq_handler, + IRQF_SHARED, KBUILD_MODNAME "-hif", + dev); if (ret) - goto free_hif2_irq_vector; + goto free_hif2_wed_irq_vector; mt76_wr(dev, MT_INT1_MASK_CSR, 0); /* master switch of PCIe tnterrupt enable */ @@ -171,16 +191,23 @@ static int mt7996_pci_probe(struct pci_dev *pdev, free_hif2_irq: if (dev->hif2) - devm_free_irq(mdev->dev, dev->hif2->irq, dev); -free_hif2_irq_vector: - if (dev->hif2) - pci_free_irq_vectors(hif2_dev); + devm_free_irq(mdev->dev, hif2_irq, dev); +free_hif2_wed_irq_vector: + if (dev->hif2) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_detach(&dev->mt76.mmio.wed_hif2); + else + pci_free_irq_vectors(hif2_dev); + } free_hif2: if (dev->hif2) put_device(dev->hif2->dev); devm_free_irq(mdev->dev, irq, dev); -free_irq_vector: - pci_free_irq_vectors(pdev); +free_wed_or_irq_vector: + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_detach(&dev->mt76.mmio.wed); + else + pci_free_irq_vectors(pdev); free_device: mt76_free_device(&dev->mt76); @@ -225,3 +252,7 @@ MODULE_FIRMWARE(MT7996_FIRMWARE_WA); MODULE_FIRMWARE(MT7996_FIRMWARE_WM); MODULE_FIRMWARE(MT7996_FIRMWARE_DSP); MODULE_FIRMWARE(MT7996_ROM_PATCH); +MODULE_FIRMWARE(MT7992_FIRMWARE_WA); +MODULE_FIRMWARE(MT7992_FIRMWARE_WM); +MODULE_FIRMWARE(MT7992_FIRMWARE_DSP); +MODULE_FIRMWARE(MT7992_ROM_PATCH); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 0086a78666..47b429d8bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -19,6 +19,7 @@ struct __base { /* used to differentiate between generations */ struct mt7996_reg_desc { const struct __base *base; + const u32 *offs_rev; const struct __map *map; u32 map_size; }; @@ -39,6 +40,73 @@ enum base_rev { #define __BASE(_id, _band) (dev->reg.base[(_id)].band_base[(_band)]) +enum offs_rev { + MIB_RVSR0, + MIB_RVSR1, + MIB_BTSCR5, + MIB_BTSCR6, + MIB_RSCR1, + MIB_RSCR27, + MIB_RSCR28, + MIB_RSCR29, + MIB_RSCR30, + MIB_RSCR31, + MIB_RSCR33, + MIB_RSCR35, + MIB_RSCR36, + MIB_BSCR0, + MIB_BSCR1, + MIB_BSCR2, + MIB_BSCR3, + MIB_BSCR4, + MIB_BSCR5, + MIB_BSCR6, + MIB_BSCR7, + MIB_BSCR17, + MIB_TRDR1, + __MT_OFFS_MAX, +}; + +#define __OFFS(id) (dev->reg.offs_rev[(id)]) + +/* RRO TOP */ +#define MT_RRO_TOP_BASE 0xA000 +#define MT_RRO_TOP(ofs) (MT_RRO_TOP_BASE + (ofs)) + +#define MT_RRO_BA_BITMAP_BASE0 MT_RRO_TOP(0x8) +#define MT_RRO_BA_BITMAP_BASE1 MT_RRO_TOP(0xC) +#define WF_RRO_AXI_MST_CFG MT_RRO_TOP(0xB8) +#define WF_RRO_AXI_MST_CFG_DIDX_OK BIT(12) +#define MT_RRO_ADDR_ARRAY_BASE1 MT_RRO_TOP(0x34) +#define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE BIT(31) + +#define MT_RRO_IND_CMD_SIGNATURE_BASE0 MT_RRO_TOP(0x38) +#define MT_RRO_IND_CMD_SIGNATURE_BASE1 MT_RRO_TOP(0x3C) +#define MT_RRO_IND_CMD_0_CTRL0 MT_RRO_TOP(0x40) +#define MT_RRO_IND_CMD_SIGNATURE_BASE1_EN BIT(31) + +#define MT_RRO_PARTICULAR_CFG0 MT_RRO_TOP(0x5C) +#define MT_RRO_PARTICULAR_CFG1 MT_RRO_TOP(0x60) +#define MT_RRO_PARTICULAR_CONFG_EN BIT(31) +#define MT_RRO_PARTICULAR_SID GENMASK(30, 16) + +#define MT_RRO_BA_BITMAP_BASE_EXT0 MT_RRO_TOP(0x70) +#define MT_RRO_BA_BITMAP_BASE_EXT1 MT_RRO_TOP(0x74) +#define MT_RRO_HOST_INT_ENA MT_RRO_TOP(0x204) +#define MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA BIT(0) + +#define MT_RRO_ADDR_ELEM_SEG_ADDR0 MT_RRO_TOP(0x400) + +#define MT_RRO_ACK_SN_CTRL MT_RRO_TOP(0x50) +#define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16) +#define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0) + +#define MT_RRO_DBG_RD_CTRL MT_RRO_TOP(0xe0) +#define MT_RRO_DBG_RD_ADDR GENMASK(15, 0) +#define MT_RRO_DBG_RD_EXEC BIT(31) + +#define MT_RRO_DBG_RDAT_DW(_n) MT_RRO_TOP(0xf0 + (_n) * 0x4) + #define MT_MCU_INT_EVENT 0x2108 #define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) #define MT_MCU_INT_EVENT_DMA_INIT BIT(1) @@ -140,32 +208,32 @@ enum base_rev { #define MT_WF_MIB_BASE(_band) __BASE(WF_MIB_BASE, (_band)) #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) -#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, 0x9cc) -#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, 0x9d0) -#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, 0x9d4) -#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, 0x9d8) -#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, 0x9dc) -#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, 0x9e0) -#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, 0x9e4) -#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, 0x9e8) -#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, 0xa10) +#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR0)) +#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR1)) +#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR2)) +#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR3)) +#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR4)) +#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR5)) +#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR6)) +#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR7)) +#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR17)) #define MT_MIB_TSCR5(_band) MT_WF_MIB(_band, 0x6c4) #define MT_MIB_TSCR6(_band) MT_WF_MIB(_band, 0x6c8) #define MT_MIB_TSCR7(_band) MT_WF_MIB(_band, 0x6d0) -#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, 0x7ac) +#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR1)) /* rx mpdu counter, full 32 bits */ -#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, 0x964) -#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, 0x96c) +#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR31)) +#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR33)) #define MT_MIB_SDR6(_band) MT_WF_MIB(_band, 0x020) #define MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK GENMASK(15, 0) -#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, 0x720) +#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR0)) -#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, 0x974) -#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, 0x978) +#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR35)) +#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR36)) /* tx ampdu cnt, full 32 bits */ #define MT_MIB_TSCR0(_band) MT_WF_MIB(_band, 0x6b0) @@ -178,16 +246,16 @@ enum base_rev { #define MT_MIB_TSCR4(_band) MT_WF_MIB(_band, 0x6c0) /* rx ampdu count, 32-bit */ -#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, 0x954) +#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR27)) /* rx ampdu bytes count, 32-bit */ -#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, 0x958) +#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR28)) /* rx ampdu valid subframe count */ -#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, 0x95c) +#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR29)) /* rx ampdu valid subframe bytes count, 32bits */ -#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, 0x960) +#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR30)) /* remaining windows protected stats */ #define MT_MIB_SDR27(_band) MT_WF_MIB(_band, 0x080) @@ -196,18 +264,18 @@ enum base_rev { #define MT_MIB_SDR28(_band) MT_WF_MIB(_band, 0x084) #define MT_MIB_SDR28_TX_RWP_NEED_CNT GENMASK(15, 0) -#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, 0x724) +#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR1)) /* rx blockack count, 32 bits */ #define MT_MIB_TSCR1(_band) MT_WF_MIB(_band, 0x6b4) #define MT_MIB_BTSCR0(_band) MT_WF_MIB(_band, 0x5e0) -#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, 0x788) -#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, 0x798) +#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR5)) +#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR6)) #define MT_MIB_BFTFCR(_band) MT_WF_MIB(_band, 0x5d0) -#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0xa28 + ((n) << 2)) +#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, __OFFS(MIB_TRDR1) + ((n) << 2)) #define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2)) #define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 4)) & GENMASK(9, 0)) @@ -330,15 +398,22 @@ enum base_rev { #define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154) #define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3) +#define MT_WFDMA0_RX_INT_SEL_RING6 BIT(6) #define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4) #define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) #define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) -#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28) -#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) +#define MT_WFDMA0_GLO_CFG_EXT_EN BIT(26) +#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) +#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28) + +#define MT_WFDMA0_PAUSE_RX_Q_45_TH MT_WFDMA0(0x268) +#define MT_WFDMA0_PAUSE_RX_Q_67_TH MT_WFDMA0(0x26c) +#define MT_WFDMA0_PAUSE_RX_Q_89_TH MT_WFDMA0(0x270) +#define MT_WFDMA0_PAUSE_RX_Q_RRO_TH MT_WFDMA0(0x27c) #define WF_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0) #define WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD BIT(18) @@ -362,10 +437,14 @@ enum base_rev { #define MT_WFDMA_HOST_CONFIG MT_WFDMA_EXT_CSR(0x30) #define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0) +#define MT_WFDMA_HOST_CONFIG_BAND2_PCIE1 BIT(22) #define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44) #define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0) +#define MT_WFDMA_AXI_R2A_CTRL MT_WFDMA_EXT_CSR(0x500) +#define MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK GENMASK(4, 0) + #define MT_PCIE_RECOG_ID 0xd7090 #define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0) #define MT_PCIE_RECOG_ID_SEM BIT(31) @@ -374,6 +453,9 @@ enum base_rev { #define MT_WFDMA0_PCIE1_BASE 0xd8000 #define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) +#define MT_INT_PCIE1_SOURCE_CSR_EXT MT_WFDMA0_PCIE1(0x118) +#define MT_INT_PCIE1_MASK_CSR MT_WFDMA0_PCIE1(0x11c) + #define MT_WFDMA0_PCIE1_BUSY_ENA MT_WFDMA0_PCIE1(0x13c) #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) @@ -394,6 +476,7 @@ enum base_rev { #define MT_MCUQ_RING_BASE(q) (MT_Q_BASE(q) + 0x300) #define MT_TXQ_RING_BASE(q) (MT_Q_BASE(__TXQ(q)) + 0x300) #define MT_RXQ_RING_BASE(q) (MT_Q_BASE(__RXQ(q)) + 0x500) +#define MT_RXQ_RRO_IND_RING_BASE MT_RRO_TOP(0x40) #define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \ MT_MCUQ_ID(q) * 0x4) @@ -409,17 +492,27 @@ enum base_rev { #define MT_INT1_MASK_CSR MT_WFDMA0_PCIE1(0x204) #define MT_INT_RX_DONE_BAND0 BIT(12) -#define MT_INT_RX_DONE_BAND1 BIT(12) +#define MT_INT_RX_DONE_BAND1 BIT(13) /* for mt7992 */ #define MT_INT_RX_DONE_BAND2 BIT(13) #define MT_INT_RX_DONE_WM BIT(0) #define MT_INT_RX_DONE_WA BIT(1) #define MT_INT_RX_DONE_WA_MAIN BIT(2) -#define MT_INT_RX_DONE_WA_EXT BIT(2) +#define MT_INT_RX_DONE_WA_EXT BIT(3) /* for mt7992 */ #define MT_INT_RX_DONE_WA_TRI BIT(3) #define MT_INT_RX_TXFREE_MAIN BIT(17) #define MT_INT_RX_TXFREE_TRI BIT(15) +#define MT_INT_RX_DONE_BAND2_EXT BIT(23) +#define MT_INT_RX_TXFREE_EXT BIT(26) #define MT_INT_MCU_CMD BIT(29) +#define MT_INT_RX_DONE_RRO_BAND0 BIT(16) +#define MT_INT_RX_DONE_RRO_BAND1 BIT(16) +#define MT_INT_RX_DONE_RRO_BAND2 BIT(14) +#define MT_INT_RX_DONE_RRO_IND BIT(11) +#define MT_INT_RX_DONE_MSDU_PG_BAND0 BIT(18) +#define MT_INT_RX_DONE_MSDU_PG_BAND1 BIT(19) +#define MT_INT_RX_DONE_MSDU_PG_BAND2 BIT(23) + #define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)]) #define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)]) @@ -427,20 +520,31 @@ enum base_rev { MT_INT_RX(MT_RXQ_MCU_WA)) #define MT_INT_BAND0_RX_DONE (MT_INT_RX(MT_RXQ_MAIN) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) #define MT_INT_BAND1_RX_DONE (MT_INT_RX(MT_RXQ_BAND1) | \ MT_INT_RX(MT_RXQ_BAND1_WA) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) #define MT_INT_BAND2_RX_DONE (MT_INT_RX(MT_RXQ_BAND2) | \ MT_INT_RX(MT_RXQ_BAND2_WA) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) + +#define MT_INT_RRO_RX_DONE (MT_INT_RX(MT_RXQ_RRO_BAND0) | \ + MT_INT_RX(MT_RXQ_RRO_BAND1) | \ + MT_INT_RX(MT_RXQ_RRO_BAND2) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND0) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND1) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2)) #define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_MCU | \ MT_INT_BAND0_RX_DONE | \ MT_INT_BAND1_RX_DONE | \ - MT_INT_BAND2_RX_DONE) + MT_INT_BAND2_RX_DONE | \ + MT_INT_RRO_RX_DONE) #define MT_INT_TX_DONE_FWDL BIT(26) #define MT_INT_TX_DONE_MCU_WM BIT(27) @@ -449,6 +553,10 @@ enum base_rev { #define MT_INT_TX_DONE_BAND1 BIT(31) #define MT_INT_TX_DONE_BAND2 BIT(15) +#define MT_INT_TX_RX_DONE_EXT (MT_INT_TX_DONE_BAND2 | \ + MT_INT_RX_DONE_BAND2_EXT | \ + MT_INT_RX_TXFREE_EXT) + #define MT_INT_TX_DONE_MCU (MT_INT_TX_MCU(MT_MCUQ_WA) | \ MT_INT_TX_MCU(MT_MCUQ_WM) | \ MT_INT_TX_MCU(MT_MCUQ_FWDL)) @@ -552,7 +660,12 @@ enum base_rev { #define MT_TOP_MISC MT_TOP(0xf0) #define MT_TOP_MISC_FW_STATE GENMASK(2, 0) +#define MT_PAD_GPIO 0x700056f0 +#define MT_PAD_GPIO_ADIE_COMB GENMASK(16, 15) + #define MT_HW_REV 0x70010204 +#define MT_HW_REV1 0x8a00 + #define MT_WF_SUBSYS_RST 0x70028600 /* PCIE MAC */ @@ -601,4 +714,11 @@ enum base_rev { #define MT_MCU_WM_EXCP_LR_CTRL MT_MCU_WM_EXCP(0x200) #define MT_MCU_WM_EXCP_LR_LOG MT_MCU_WM_EXCP(0x204) +/* CONN AFE CTL CON */ +#define MT_AFE_CTL_BASE 0x18043000 +#define MT_AFE_CTL_BAND(_band, ofs) (MT_AFE_CTL_BASE + \ + ((_band) * 0x1000) + (ofs)) +#define MT_AFE_CTL_BAND_PLL_03(_band) MT_AFE_CTL_BAND(_band, 0x2c) +#define MT_AFE_CTL_BAND_PLL_03_MSB_EN BIT(1) + #endif diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index c52d550f0c..3e88798df0 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -672,4 +672,5 @@ EXPORT_SYMBOL_GPL(mt76s_init); MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_DESCRIPTION("MediaTek MT76x SDIO helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 1584665fe3..5a0bcb5071 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -1128,4 +1128,5 @@ int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf) EXPORT_SYMBOL_GPL(mt76u_init); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>"); +MODULE_DESCRIPTION("MediaTek MT76x USB helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c index fc76c66ff1..d6c01a2dd1 100644 --- a/drivers/net/wireless/mediatek/mt76/util.c +++ b/drivers/net/wireless/mediatek/mt76/util.c @@ -138,4 +138,5 @@ int __mt76_worker_fn(void *ptr) } EXPORT_SYMBOL_GPL(__mt76_worker_fn); +MODULE_DESCRIPTION("MediaTek MT76x helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index e9a047a8c7..f03fd15c0c 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -105,10 +105,9 @@ struct wilc_ch_list_elem { } __packed; static void cfg_scan_result(enum scan_event scan_event, - struct wilc_rcvd_net_info *info, void *user_void) + struct wilc_rcvd_net_info *info, + struct wilc_priv *priv) { - struct wilc_priv *priv = user_void; - if (!priv->cfg_scanning) return; @@ -162,9 +161,8 @@ static void cfg_scan_result(enum scan_event scan_event, } static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, - void *priv_data) + struct wilc_priv *priv) { - struct wilc_priv *priv = priv_data; struct net_device *dev = priv->dev; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wl = vif->wilc; @@ -286,9 +284,8 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) else scan_type = WILC_FW_PASSIVE_SCAN; - ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list, - request->n_channels, cfg_scan_result, (void *)priv, - request); + ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, + scan_ch_list, cfg_scan_result, request); if (ret) { priv->scan_req = NULL; @@ -412,9 +409,8 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, wfi_drv->conn_info.security = security; wfi_drv->conn_info.auth_type = auth_type; - wfi_drv->conn_info.ch = ch; wfi_drv->conn_info.conn_result = cfg_connect_result; - wfi_drv->conn_info.arg = priv; + wfi_drv->conn_info.priv = priv; wfi_drv->conn_info.param = join_params; if (sme->mfp == NL80211_MFP_OPTIONAL) @@ -1094,9 +1090,8 @@ static void wilc_wfi_mgmt_tx_complete(void *priv, int status) kfree(pv_data); } -static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie) +static void wilc_wfi_remain_on_channel_expired(struct wilc_vif *vif, u64 cookie) { - struct wilc_vif *vif = data; struct wilc_priv *priv = &vif->priv; struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params; @@ -1128,9 +1123,8 @@ static int remain_on_channel(struct wiphy *wiphy, if (id == 0) id = ++priv->inc_roc_cookie; - ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value, - wilc_wfi_remain_on_channel_expired, - (void *)vif); + ret = wilc_remain_on_channel(vif, id, chan->hw_value, + wilc_wfi_remain_on_channel_expired); if (ret) return ret; diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index e202013e6f..d2b8c26308 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -144,18 +144,19 @@ static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt) scan_req = &hif_drv->usr_scan_req; if (scan_req->scan_result) { - scan_req->scan_result(evt, NULL, scan_req->arg); + scan_req->scan_result(evt, NULL, scan_req->priv); scan_req->scan_result = NULL; } return result; } -int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, - u8 *ch_freq_list, u8 ch_list_len, +int wilc_scan(struct wilc_vif *vif, u8 scan_source, + u8 scan_type, u8 *ch_freq_list, void (*scan_result_fn)(enum scan_event, - struct wilc_rcvd_net_info *, void *), - void *user_arg, struct cfg80211_scan_request *request) + struct wilc_rcvd_net_info *, + struct wilc_priv *), + struct cfg80211_scan_request *request) { int result = 0; struct wid wid_list[WILC_SCAN_WID_LIST_SIZE]; @@ -164,6 +165,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, u8 *buffer; u8 valuesize = 0; u8 *search_ssid_vals = NULL; + const u8 ch_list_len = request->n_channels; struct host_if_drv *hif_drv = vif->hif_drv; if (hif_drv->hif_state >= HOST_IF_SCANNING && @@ -249,7 +251,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, index++; hif_drv->usr_scan_req.scan_result = scan_result_fn; - hif_drv->usr_scan_req.arg = user_arg; + hif_drv->usr_scan_req.priv = &vif->priv; result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index); if (result) { @@ -348,7 +350,7 @@ static void handle_connect_timeout(struct work_struct *work) if (hif_drv->conn_info.conn_result) { hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP, WILC_MAC_STATUS_DISCONNECTED, - hif_drv->conn_info.arg); + hif_drv->conn_info.priv); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); @@ -371,8 +373,9 @@ out: kfree(msg); } -void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, - struct cfg80211_crypto_settings *crypto) +struct wilc_join_bss_param * +wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto) { const u8 *ies_data, *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; @@ -557,7 +560,7 @@ static void handle_rcvd_ntwrk_info(struct work_struct *work) if (scan_req->scan_result) scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info, - scan_req->arg); + scan_req->priv); done: kfree(rcvd_info->mgmt); @@ -639,7 +642,7 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, del_timer(&hif_drv->connect_timer); conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status, - hif_drv->conn_info.arg); + hif_drv->conn_info.priv); if (mac_status == WILC_MAC_STATUS_CONNECTED && conn_info->status == WLAN_STATUS_SUCCESS) { @@ -669,7 +672,7 @@ void wilc_handle_disconnect(struct wilc_vif *vif) if (hif_drv->conn_info.conn_result) hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, - 0, hif_drv->conn_info.arg); + 0, hif_drv->conn_info.priv); eth_zero_addr(hif_drv->assoc_bssid); @@ -741,7 +744,7 @@ int wilc_disconnect(struct wilc_vif *vif) if (scan_req->scan_result) { del_timer(&hif_drv->scan_timer); - scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg); + scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->priv); scan_req->scan_result = NULL; } @@ -751,7 +754,7 @@ int wilc_disconnect(struct wilc_vif *vif) del_timer(&hif_drv->connect_timer); conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0, - conn_info->arg); + conn_info->priv); } else { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); } @@ -890,7 +893,7 @@ static int handle_remain_on_chan(struct wilc_vif *vif, if (result) return -EBUSY; - hif_drv->remain_on_ch.arg = hif_remain_ch->arg; + hif_drv->remain_on_ch.vif = hif_remain_ch->vif; hif_drv->remain_on_ch.expired = hif_remain_ch->expired; hif_drv->remain_on_ch.ch = hif_remain_ch->ch; hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie; @@ -927,7 +930,7 @@ static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie) } if (hif_drv->remain_on_ch.expired) { - hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg, + hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.vif, cookie); } } else { @@ -1550,7 +1553,7 @@ int wilc_deinit(struct wilc_vif *vif) if (hif_drv->usr_scan_req.scan_result) { hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL, - hif_drv->usr_scan_req.arg); + hif_drv->usr_scan_req.priv); hif_drv->usr_scan_req.scan_result = NULL; } @@ -1681,18 +1684,15 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) } } -int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, - u32 duration, u16 chan, - void (*expired)(void *, u64), - void *user_arg) +int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan, + void (*expired)(struct wilc_vif *, u64)) { struct wilc_remain_ch roc; int result; roc.ch = chan; roc.expired = expired; - roc.arg = user_arg; - roc.duration = duration; + roc.vif = vif; roc.cookie = cookie; result = handle_remain_on_chan(vif, &roc); if (result) diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h index 8e386db72e..0d380586b1 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.h +++ b/drivers/net/wireless/microchip/wilc1000/hif.h @@ -95,34 +95,37 @@ struct wilc_rcvd_net_info { struct ieee80211_mgmt *mgmt; }; +struct wilc_priv; struct wilc_user_scan_req { void (*scan_result)(enum scan_event evt, - struct wilc_rcvd_net_info *info, void *priv); - void *arg; + struct wilc_rcvd_net_info *info, + struct wilc_priv *priv); + struct wilc_priv *priv; u32 ch_cnt; }; +struct wilc_join_bss_param; struct wilc_conn_info { u8 bssid[ETH_ALEN]; u8 security; enum authtype auth_type; enum mfptype mfp_type; - u8 ch; u8 *req_ies; size_t req_ies_len; u8 *resp_ies; u16 resp_ies_len; u16 status; - void (*conn_result)(enum conn_event evt, u8 status, void *priv_data); - void *arg; - void *param; + void (*conn_result)(enum conn_event evt, u8 status, + struct wilc_priv *priv); + struct wilc_priv *priv; + struct wilc_join_bss_param *param; }; +struct wilc_vif; struct wilc_remain_ch { u16 ch; - u32 duration; - void (*expired)(void *priv, u64 cookie); - void *arg; + void (*expired)(struct wilc_vif *vif, u64 cookie); + struct wilc_vif *vif; u64 cookie; }; @@ -150,7 +153,6 @@ struct host_if_drv { u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE]; }; -struct wilc_vif; int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic, u8 mode, u8 cipher_mode, u8 index); @@ -171,11 +173,12 @@ int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, int wilc_disconnect(struct wilc_vif *vif); int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel); int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level); -int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, - u8 *ch_freq_list, u8 ch_list_len, +int wilc_scan(struct wilc_vif *vif, u8 scan_source, + u8 scan_type, u8 *ch_freq_list, void (*scan_result_fn)(enum scan_event, - struct wilc_rcvd_net_info *, void *), - void *user_arg, struct cfg80211_scan_request *request); + struct wilc_rcvd_net_info *, + struct wilc_priv *), + struct cfg80211_scan_request *request); int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *cfg_param); int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler); @@ -192,10 +195,8 @@ int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout); int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, u8 *mc_list); -int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, - u32 duration, u16 chan, - void (*expired)(void *, u64), - void *user_arg); +int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan, + void (*expired)(struct wilc_vif *, u64)); int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie); void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg); int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode, @@ -210,8 +211,9 @@ int wilc_set_external_auth_param(struct wilc_vif *vif, void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length); void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length); void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length); -void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, - struct cfg80211_crypto_settings *crypto); +struct wilc_join_bss_param * +wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto); int wilc_set_default_mgmt_key_index(struct wilc_vif *vif, u8 index); void wilc_handle_disconnect(struct wilc_vif *vif); diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 87fce5f418..6068699e44 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -996,5 +996,6 @@ error: return ERR_PTR(ret); } +MODULE_DESCRIPTION("Atmel WILC1000 core wireless driver"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(WILC1000_FW(WILC1000_API_VER)); diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c index 87948ba69a..d6d3946930 100644 --- a/drivers/net/wireless/microchip/wilc1000/sdio.c +++ b/drivers/net/wireless/microchip/wilc1000/sdio.c @@ -106,9 +106,10 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) size = cmd->count; if (cmd->use_global_buf) { - if (size > sizeof(u32)) - return -EINVAL; - + if (size > sizeof(u32)) { + ret = -EINVAL; + goto out; + } buf = sdio_priv->cmd53_buf; } @@ -123,7 +124,7 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) if (cmd->use_global_buf) memcpy(cmd->buffer, buf, size); } - +out: sdio_release_host(func); if (ret) @@ -983,4 +984,5 @@ static struct sdio_driver wilc_sdio_driver = { module_driver(wilc_sdio_driver, sdio_register_driver, sdio_unregister_driver); +MODULE_DESCRIPTION("Atmel WILC1000 SDIO wireless driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 4cf8586ed5..6a82b6ca27 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -273,6 +273,7 @@ static struct spi_driver wilc_spi_driver = { .remove = wilc_bus_remove, }; module_spi_driver(wilc_spi_driver); +MODULE_DESCRIPTION("Atmel WILC1000 SPI wireless driver"); MODULE_LICENSE("GPL"); static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800.h b/drivers/net/wireless/ralink/rt2x00/rt2800.h index 48521e4557..8930589b49 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h @@ -3194,4 +3194,8 @@ enum rt2800_eeprom_word { */ #define BCN_TBTT_OFFSET 64 +/* Watchdog type mask */ +#define RT2800_WATCHDOG_HANG BIT(0) +#define RT2800_WATCHDOG_DMA_BUSY BIT(1) + #endif /* RT2800_H */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 1926ffdffb..aaf31857ae 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -30,9 +30,10 @@ #include "rt2800lib.h" #include "rt2800.h" -static bool modparam_watchdog; -module_param_named(watchdog, modparam_watchdog, bool, S_IRUGO); -MODULE_PARM_DESC(watchdog, "Enable watchdog to detect tx/rx hangs and reset hardware if detected"); +static unsigned int modparam_watchdog = RT2800_WATCHDOG_DMA_BUSY; +module_param_named(watchdog, modparam_watchdog, uint, 0444); +MODULE_PARM_DESC(watchdog, "Enable watchdog to recover tx/rx hangs.\n" + "\t\t(0=disabled, 1=hang watchdog, 2=DMA watchdog(default), 3=both)"); /* * Register access. @@ -1261,15 +1262,12 @@ static void rt2800_update_survey(struct rt2x00_dev *rt2x00dev) chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC); } -void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) +static bool rt2800_watchdog_hung(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; bool hung_tx = false; bool hung_rx = false; - if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) - return; - rt2800_update_survey(rt2x00dev); queue_for_each(rt2x00dev, queue) { @@ -1297,18 +1295,72 @@ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) } } + if (!hung_tx && !hung_rx) + return false; + if (hung_tx) rt2x00_warn(rt2x00dev, "Watchdog TX hung detected\n"); if (hung_rx) rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n"); - if (hung_tx || hung_rx) { - queue_for_each(rt2x00dev, queue) - queue->wd_count = 0; + queue_for_each(rt2x00dev, queue) + queue->wd_count = 0; + + return true; +} + +static bool rt2800_watchdog_dma_busy(struct rt2x00_dev *rt2x00dev) +{ + bool busy_rx, busy_tx; + u32 reg_cfg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); + u32 reg_int = rt2800_register_read(rt2x00dev, INT_SOURCE_CSR); + + if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_RX_DMA_BUSY) && + rt2x00_get_field32(reg_int, INT_SOURCE_CSR_RX_COHERENT)) + rt2x00dev->rxdma_busy++; + else + rt2x00dev->rxdma_busy = 0; + + if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_TX_DMA_BUSY) && + rt2x00_get_field32(reg_int, INT_SOURCE_CSR_TX_COHERENT)) + rt2x00dev->txdma_busy++; + else + rt2x00dev->txdma_busy = 0; + + busy_rx = rt2x00dev->rxdma_busy > 30; + busy_tx = rt2x00dev->txdma_busy > 30; + + if (!busy_rx && !busy_tx) + return false; + + if (busy_rx) + rt2x00_warn(rt2x00dev, "Watchdog RX DMA busy detected\n"); + + if (busy_tx) + rt2x00_warn(rt2x00dev, "Watchdog TX DMA busy detected\n"); + + rt2x00dev->rxdma_busy = 0; + rt2x00dev->txdma_busy = 0; + + return true; +} + +void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) +{ + bool reset = false; + + if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) + return; + + if (rt2x00dev->link.watchdog & RT2800_WATCHDOG_DMA_BUSY) + reset = rt2800_watchdog_dma_busy(rt2x00dev); + if (rt2x00dev->link.watchdog & RT2800_WATCHDOG_HANG) + reset = rt2800_watchdog_hung(rt2x00dev) || reset; + + if (reset) ieee80211_restart_hw(rt2x00dev->hw); - } } EXPORT_SYMBOL_GPL(rt2800_watchdog); @@ -6048,7 +6100,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0); rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG); @@ -6061,7 +6113,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0); rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG); @@ -12013,11 +12065,13 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags); } - if (modparam_watchdog) { + rt2x00dev->link.watchdog = modparam_watchdog; + /* USB NICs don't support DMA watchdog as INT_SOURCE_CSR is invalid */ + if (rt2x00_is_usb(rt2x00dev)) + rt2x00dev->link.watchdog &= ~RT2800_WATCHDOG_DMA_BUSY; + if (rt2x00dev->link.watchdog) { __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags); rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100); - } else { - rt2x00dev->link.watchdog_disabled = true; } /* diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index aaaf993319..82af01448a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -334,7 +334,7 @@ struct link { */ struct delayed_work watchdog_work; unsigned int watchdog_interval; - bool watchdog_disabled; + unsigned int watchdog; /* * Work structure for scheduling periodic AGC adjustments. @@ -926,6 +926,9 @@ struct rt2x00_dev { */ u16 beacon_int; + /* Rx/Tx DMA busy watchdog counter */ + u16 rxdma_busy, txdma_busy; + /** * Timestamp of last received beacon */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c index 6cf7e7c997..fb23d409fb 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c @@ -384,7 +384,7 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev) struct link *link = &rt2x00dev->link; if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && - rt2x00dev->ops->lib->watchdog && !link->watchdog_disabled) + rt2x00dev->ops->lib->watchdog && link->watchdog) ieee80211_queue_delayed_work(rt2x00dev->hw, &link->watchdog_work, link->watchdog_interval); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index 98df0aef81..013003777f 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -416,9 +416,6 @@ static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags); else __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags); - if (tx_info->control.rts_cts_rate_idx >= 0) - rate = - ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info); } /* diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 7ce37fb4fd..1a8d715b7c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1402,10 +1402,6 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) sta_entry = (struct rtl_sta_info *)sta->drv_priv; - if (!sta_entry) { - rcu_read_unlock(); - return true; - } capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); tid = (capab & @@ -1760,8 +1756,6 @@ int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return -EINVAL; sta_entry = (struct rtl_sta_info *)sta->drv_priv; - if (!sta_entry) - return -ENXIO; tid_data = &sta_entry->tids[tid]; rtl_dbg(rtlpriv, COMP_SEND, DBG_DMESG, @@ -1818,8 +1812,6 @@ int rtl_rx_agg_start(struct ieee80211_hw *hw, } sta_entry = (struct rtl_sta_info *)sta->drv_priv; - if (!sta_entry) - return -ENXIO; tid_data = &sta_entry->tids[tid]; rtl_dbg(rtlpriv, COMP_RECV, DBG_DMESG, diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index b118df0352..96ce05bcf0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -64,13 +64,12 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; - u8 init_aspm; + u16 init_aspm; ppsc->reg_rfps_level = 0; ppsc->support_aspm = false; /*Update PCI ASPM setting */ - ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm; switch (rtlpci->const_pci_aspm) { case 0: /*No ASPM */ @@ -151,9 +150,10 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) /* toshiba aspm issue, toshiba will set aspm selfly * so we should not set aspm in driver */ - pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm); + pcie_capability_read_word(rtlpci->pdev, PCI_EXP_LNKCTL, &init_aspm); if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE && - init_aspm == 0x43) + ((u8)init_aspm) == (PCI_EXP_LNKCTL_ASPM_L0S | + PCI_EXP_LNKCTL_ASPM_L1 | PCI_EXP_LNKCTL_CCC)) ppsc->support_aspm = false; } @@ -203,7 +203,7 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) /*Retrieve original configuration settings. */ u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg; u16 aspmlevel = 0; - u8 tmp_u1b = 0; + u16 tmp_u1b = 0; if (!ppsc->support_aspm) return; @@ -221,10 +221,10 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) } /*for promising device will in L0 state after an I/O. */ - pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); + pcie_capability_read_word(rtlpci->pdev, PCI_EXP_LNKCTL, &tmp_u1b); /*Set corresponding value. */ - aspmlevel |= BIT(0) | BIT(1); + aspmlevel |= PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1; linkctrl_reg &= ~aspmlevel; _rtl_pci_platform_switch_device_pci_aspm(hw, linkctrl_reg); @@ -351,9 +351,8 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev, rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "Link Control Register =%x\n", pcipriv->ndis_adapter.linkctrl_reg); - pci_read_config_byte(pdev, 0x98, &tmp); - tmp |= BIT(4); - pci_write_config_byte(pdev, 0x98, tmp); + pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2, + PCI_EXP_DEVCTL2_COMP_TMOUT_DIS); tmp = 0x17; pci_write_config_byte(pdev, 0x70f, tmp); @@ -1969,7 +1968,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, */ if (bridge_pdev) { /*find bridge info if available */ - pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor; for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { if (bridge_pdev->vendor == pcibridge_vendors[tmp]) { pcipriv->ndis_adapter.pcibridge_vendor = tmp; diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h index d6307197df..e8fa022df8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.h +++ b/drivers/net/wireless/realtek/rtlwifi/pci.h @@ -44,18 +44,6 @@ #define ATI_DEVICE_ID 0x7914 #define AMD_VENDOR_ID 0x1022 -#define PCI_MAX_BRIDGE_NUMBER 255 -#define PCI_MAX_DEVICES 32 -#define PCI_MAX_FUNCTION 8 - -#define PCI_CONF_ADDRESS 0x0CF8 /*PCI Configuration Space Address */ -#define PCI_CONF_DATA 0x0CFC /*PCI Configuration Space Data */ - -#define PCI_CLASS_BRIDGE_DEV 0x06 -#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04 -#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10 -#define PCI_CAP_ID_EXP 0x10 - #define U1DONTCARE 0xFF #define U2DONTCARE 0xFFFF #define U4DONTCARE 0xFFFFFFFF @@ -113,11 +101,6 @@ enum pci_bridge_vendor { PCI_BRIDGE_VENDOR_MAX, }; -struct rtl_pci_capabilities_header { - u8 capability_id; - u8 next; -}; - /* In new TRX flow, Buffer_desc is new concept * But TX wifi info == TX descriptor in old flow * RX wifi info == RX descriptor in old flow @@ -195,7 +178,6 @@ struct rtl_pci { u32 reg_bcn_ctrl_val; /*ASPM*/ u8 const_pci_aspm; - u8 const_amdpci_aspm; u8 const_hwsw_rfoff_d3; u8 const_support_pciaspm; /*pci-e bridge */ @@ -233,8 +215,6 @@ struct mp_adapter { u8 pcibridge_funcnum; u8 pcibridge_vendor; - u16 pcibridge_vendorid; - u16 pcibridge_deviceid; bool amd_l1_patch; }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index b77937fe24..37bb59fa8b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -21,9 +21,6 @@ static void rtl88e_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c index 144ee780e1..3730613a39 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c @@ -1479,12 +1479,8 @@ EXPORT_SYMBOL(rtl92c_phy_lc_calibrate); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta) { - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - if (rtlphy->apk_done) - return; if (IS_92C_SERIAL(rtlhal->version)) _rtl92c_phy_ap_calibrate(hw, delta, true); else diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index e452275d87..e20f2bec45 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -24,9 +24,6 @@ static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index 11f319c971..afd685ed46 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -21,9 +21,6 @@ static void rtl92d_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c index 5a828a934f..17486e3f32 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c @@ -432,10 +432,8 @@ static void rtl92ee_dm_check_rssi_monitor(struct ieee80211_hw *hw) static void rtl92ee_dm_init_primary_cca_check(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct dynamic_primary_cca *primarycca = &rtlpriv->primarycca; - rtlhal->rts_en = 0; primarycca->dup_rts_flag = 0; primarycca->intf_flag = 0; primarycca->intf_type = 0; @@ -562,7 +560,7 @@ static void rtl92ee_dm_write_dynamic_cca(struct ieee80211_hw *hw, primarycca->mf_state = cur_mf_state; } -static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) +static void rtl92ee_dm_dynamic_primary_cca_check(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct false_alarm_statistics *falsealm_cnt = &rtlpriv->falsealm_cnt; @@ -615,13 +613,11 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); primarycca->pricca_flag = 1; primarycca->dup_rts_flag = 1; - rtlpriv->rtlhal.rts_en = 1; } else { primarycca->intf_type = 0; primarycca->intf_flag = 0; cur_mf_state = MF_USC_LSC; rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); - rtlpriv->rtlhal.rts_en = 0; primarycca->dup_rts_flag = 0; } } else if (sec_ch_offset == 1) { @@ -642,13 +638,11 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); primarycca->pricca_flag = 1; primarycca->dup_rts_flag = 1; - rtlpriv->rtlhal.rts_en = 1; } else { primarycca->intf_type = 0; primarycca->intf_flag = 0; cur_mf_state = MF_USC_LSC; rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); - rtlpriv->rtlhal.rts_en = 0; primarycca->dup_rts_flag = 0; } } @@ -660,7 +654,6 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) cur_mf_state = MF_USC_LSC; /* default */ rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); - rtlpriv->rtlhal.rts_en = 0; primarycca->dup_rts_flag = 0; primarycca->intf_type = 0; primarycca->intf_flag = 0; @@ -1090,7 +1083,7 @@ void rtl92ee_dm_watchdog(struct ieee80211_hw *hw) rtl92ee_dm_refresh_rate_adaptive_mask(hw); rtl92ee_dm_check_edca_turbo(hw); rtl92ee_dm_dynamic_atc_switch(hw); - rtl92ee_dm_dynamic_primary_cca_ckeck(hw); + rtl92ee_dm_dynamic_primary_cca_check(hw); } spin_unlock(&rtlpriv->locks.rf_ps_lock); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index ebb7abd0c9..d4da5cdc84 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -1320,7 +1320,6 @@ int rtl92ee_hw_init(struct ieee80211_hw *hw) err = 1; return err; } - rtlhal->rx_tag = 0; rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, 0x8000); err = rtl92ee_download_fw(hw, false); if (err) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index 011ce82efe..7bde20fdbe 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -24,9 +24,6 @@ static void rtl92ee_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /** * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index 30bce381c3..675bdd32fe 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -21,9 +21,6 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index c821436a19..dd7505e2f2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -26,9 +26,6 @@ static void rtl8723e_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /** * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 43b611d528..162c34f0e9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -26,9 +26,6 @@ static void rtl8723be_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c index 47b6c1aa36..d97c88ebce 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c @@ -17,7 +17,7 @@ u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw, rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask); originalvalue = rtl_read_dword(rtlpriv, regaddr); - bitshift = rtl8723_phy_calculate_bit_shift(bitmask); + bitshift = calculate_bit_shift(bitmask); returnvalue = (originalvalue & bitmask) >> bitshift; rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE, @@ -39,7 +39,7 @@ void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, if (bitmask != MASKDWORD) { originalvalue = rtl_read_dword(rtlpriv, regaddr); - bitshift = rtl8723_phy_calculate_bit_shift(bitmask); + bitshift = calculate_bit_shift(bitmask); data = ((originalvalue & (~bitmask)) | (data << bitshift)); } @@ -51,14 +51,6 @@ void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, } EXPORT_SYMBOL_GPL(rtl8723_phy_set_bb_reg); -u32 rtl8723_phy_calculate_bit_shift(u32 bitmask) -{ - u32 i = ffs(bitmask); - - return i ? i - 1 : 32; -} -EXPORT_SYMBOL_GPL(rtl8723_phy_calculate_bit_shift); - u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.h index edf1c52f0e..af85c32875 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.h @@ -27,7 +27,6 @@ u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, u32 data); -u32 rtl8723_phy_calculate_bit_shift(u32 bitmask); u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset); void rtl8723_phy_rf_serial_write(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 1633328bc3..f4b232f038 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -2270,67 +2270,27 @@ static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u16 cap_hdr; - u8 cap_pointer; - u8 cap_id = 0xff; - u8 pmcs_reg; - u8 cnt = 0; + struct pci_dev *pdev = rtlpci->pdev; + u16 pmcs_reg; + u8 pm_cap; - /* Get the Capability pointer first, - * the Capability Pointer is located at - * offset 0x34 from the Function Header */ - - pci_read_config_byte(rtlpci->pdev, 0x34, &cap_pointer); - rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, - "PCI configuration 0x34 = 0x%2x\n", cap_pointer); - - do { - pci_read_config_word(rtlpci->pdev, cap_pointer, &cap_hdr); - cap_id = cap_hdr & 0xFF; - - rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, - "in pci configuration, cap_pointer%x = %x\n", - cap_pointer, cap_id); - - if (cap_id == 0x01) { - break; - } else { - /* point to next Capability */ - cap_pointer = (cap_hdr >> 8) & 0xFF; - /* 0: end of pci capability, 0xff: invalid value */ - if (cap_pointer == 0x00 || cap_pointer == 0xff) { - cap_id = 0xff; - break; - } - } - } while (cnt++ < 200); - - if (cap_id == 0x01) { - /* Get the PM CSR (Control/Status Register), - * The PME_Status is located at PM Capatibility offset 5, bit 7 - */ - pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, &pmcs_reg); - - if (pmcs_reg & BIT(7)) { - /* PME event occured, clear the PM_Status by write 1 */ - pmcs_reg = pmcs_reg | BIT(7); - - pci_write_config_byte(rtlpci->pdev, cap_pointer + 5, - pmcs_reg); - /* Read it back to check */ - pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, - &pmcs_reg); - rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, - "Clear PME status 0x%2x to 0x%2x\n", - cap_pointer + 5, pmcs_reg); - } else { - rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, - "PME status(0x%2x) = 0x%2x\n", - cap_pointer + 5, pmcs_reg); - } - } else { + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (!pm_cap) { rtl_dbg(rtlpriv, COMP_INIT, DBG_WARNING, "Cannot find PME Capability\n"); + return; + } + + pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pmcs_reg); + if (pmcs_reg & PCI_PM_CTRL_PME_STATUS) { + /* Clear PME_Status with write */ + pci_write_config_word(pdev, pm_cap + PCI_PM_CTRL, pmcs_reg); + pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pmcs_reg); + rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, + "Cleared PME status, PMCS reg = 0x%4x\n", pmcs_reg); + } else { + rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, + "PMCS reg = 0x%4x\n", pmcs_reg); } } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index fa1839d8ee..1be51ea3f3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -27,13 +27,6 @@ static u32 _rtl8821ae_phy_rf_serial_read(struct ieee80211_hw *hw, static void _rtl8821ae_phy_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data); -static u32 _rtl8821ae_phy_calculate_bit_shift(u32 bitmask) -{ - if (WARN_ON_ONCE(!bitmask)) - return 0; - - return __ffs(bitmask); -} static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw); /*static bool _rtl8812ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);*/ static bool _rtl8821ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); @@ -106,7 +99,7 @@ u32 rtl8821ae_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask); originalvalue = rtl_read_dword(rtlpriv, regaddr); - bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask); + bitshift = calculate_bit_shift(bitmask); returnvalue = (originalvalue & bitmask) >> bitshift; rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE, @@ -127,7 +120,7 @@ void rtl8821ae_phy_set_bb_reg(struct ieee80211_hw *hw, if (bitmask != MASKDWORD) { originalvalue = rtl_read_dword(rtlpriv, regaddr); - bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask); + bitshift = calculate_bit_shift(bitmask); data = ((originalvalue & (~bitmask)) | ((data << bitshift) & bitmask)); } @@ -153,7 +146,7 @@ u32 rtl8821ae_phy_query_rf_reg(struct ieee80211_hw *hw, spin_lock(&rtlpriv->locks.rf_lock); original_value = _rtl8821ae_phy_rf_serial_read(hw, rfpath, regaddr); - bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask); + bitshift = calculate_bit_shift(bitmask); readback_value = (original_value & bitmask) >> bitshift; spin_unlock(&rtlpriv->locks.rf_lock); @@ -181,7 +174,7 @@ void rtl8821ae_phy_set_rf_reg(struct ieee80211_hw *hw, if (bitmask != RFREG_OFFSET_MASK) { original_value = _rtl8821ae_phy_rf_serial_read(hw, rfpath, regaddr); - bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask); + bitshift = calculate_bit_shift(bitmask); data = ((original_value & (~bitmask)) | (data << bitshift)); } @@ -2039,15 +2032,9 @@ static bool _rtl8821ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, /*don't need the hw_body*/ if (!_rtl8821ae_check_condition(hw, v1)) { i += 2; /* skip the pair of expression*/ - v1 = array[i]; v2 = array[i+1]; - v3 = array[i+2]; - while (v2 != 0xDEAD) { + while (v2 != 0xDEAD) i += 3; - v1 = array[i]; - v2 = array[i+1]; - v3 = array[i+2]; - } } } } @@ -3544,7 +3531,6 @@ u8 rtl8821ae_phy_sw_chnl(struct ieee80211_hw *hw) struct rtl_phy *rtlphy = &rtlpriv->phy; struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u32 timeout = 1000, timecount = 0; - u8 channel = rtlphy->current_channel; if (rtlphy->sw_chnl_inprogress) return 0; @@ -3567,8 +3553,6 @@ u8 rtl8821ae_phy_sw_chnl(struct ieee80211_hw *hw) rtl8821ae_phy_switch_wirelessband(hw, BAND_ON_2_4G); rtlphy->sw_chnl_inprogress = true; - if (channel == 0) - channel = 1; rtl_dbg(rtlpriv, COMP_SCAN, DBG_TRACE, "switch to channel%d, band type is %d\n", diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 0bca542e10..7b911695db 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -23,9 +23,6 @@ static void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - /** * ASPM PS mode. * 0 - Disable ASPM, diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 5d842cc394..d87cd2252e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1316,7 +1316,6 @@ struct rtl_phy { u8 sw_chnl_stage; u8 sw_chnl_step; u8 current_channel; - u8 h2c_box_num; u8 set_io_inprogress; u8 lck_inprogress; @@ -1329,9 +1328,6 @@ struct rtl_phy { s32 reg_ebc; s32 reg_ec4; s32 reg_ecc; - u8 rfpienable; - u8 reserve_0; - u16 reserve_1; u32 reg_c04, reg_c08, reg_874; u32 adda_backup[16]; u32 iqk_mac_backup[IQK_MAC_REG_NUM]; @@ -1345,7 +1341,6 @@ struct rtl_phy { struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM]; bool rfpi_enable; - bool iqk_in_progress; u8 pwrgroup_cnt; u8 cck_high_power; @@ -1383,7 +1378,6 @@ struct rtl_phy { [MAX_RF_PATH_NUM]; u32 rfreg_chnlval[2]; - bool apk_done; u32 reg_rf3c[2]; /* pathA / pathB */ u32 backup_rf_0x1a;/*92ee*/ @@ -1395,7 +1389,6 @@ struct rtl_phy { struct phy_parameters hwparam_tables[MAX_TAB]; u16 rf_pathmap; - u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/ enum rt_polarity_ctl polarity_ctl; }; @@ -1610,7 +1603,6 @@ struct rtl_hal { bool up_first_time; bool first_init; bool being_init_adapter; - bool bbrf_ready; bool mac_func_enable; bool pre_edcca_enable; struct bt_coexist_8723 hal_coex_8723; @@ -1623,9 +1615,7 @@ struct rtl_hal { u8 state; /*stop 0, start 1 */ u8 board_type; u8 package_type; - u8 external_pa; - u8 pa_mode; u8 pa_type_2g; u8 pa_type_5g; u8 lna_type_2g; @@ -1691,14 +1681,9 @@ struct rtl_hal { bool master_of_dmsp; bool slave_of_dmsp; - u16 rx_tag;/*for 92ee*/ - u8 rts_en; - /*for wowlan*/ - bool wow_enable; bool enter_pnp_sleep; bool wake_from_pnp_sleep; - bool wow_enabled; time64_t last_suspend_sec; u32 wowlan_fwsize; u8 *wowlan_firmware; @@ -2023,8 +2008,6 @@ struct rtl_ps_ctl { u32 cur_ps_level; u32 reg_rfps_level; - /*just for PCIE ASPM */ - u8 const_amdpci_aspm; bool pwrdown_mode; enum rf_pwrstate inactive_pwrstate; diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 35bc37a3c4..1b2ad81838 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -1314,8 +1314,8 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev) #ifdef CONFIG_RTW88_DEBUG -void __rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask, - const char *fmt, ...) +void rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask, + const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, @@ -1330,6 +1330,6 @@ void __rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask, va_end(args); } -EXPORT_SYMBOL(__rtw_dbg); +EXPORT_SYMBOL(rtw_dbg); #endif /* CONFIG_RTW88_DEBUG */ diff --git a/drivers/net/wireless/realtek/rtw88/debug.h b/drivers/net/wireless/realtek/rtw88/debug.h index a03ced11bb..f20c0471c8 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.h +++ b/drivers/net/wireless/realtek/rtw88/debug.h @@ -43,10 +43,8 @@ static inline void rtw_debugfs_init(struct rtw_dev *rtwdev) {} #ifdef CONFIG_RTW88_DEBUG __printf(3, 4) -void __rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask, - const char *fmt, ...); - -#define rtw_dbg(rtwdev, a...) __rtw_dbg(rtwdev, ##a) +void rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask, + const char *fmt, ...); static inline bool rtw_dbg_is_enabled(struct rtw_dev *rtwdev, enum rtw_debug_mask mask) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index acd78311c8..3f037ddcec 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -998,7 +998,7 @@ static u8 rtw_get_rsvd_page_probe_req_location(struct rtw_dev *rtwdev, if (rsvd_pkt->type != RSVD_PROBE_REQ) continue; if ((!ssid && !rsvd_pkt->ssid) || - rtw_ssid_equal(rsvd_pkt->ssid, ssid)) + cfg80211_ssid_eq(rsvd_pkt->ssid, ssid)) location = rsvd_pkt->page; } @@ -1015,7 +1015,7 @@ static u16 rtw_get_rsvd_page_probe_req_size(struct rtw_dev *rtwdev, if (rsvd_pkt->type != RSVD_PROBE_REQ) continue; if ((!ssid && !rsvd_pkt->ssid) || - rtw_ssid_equal(rsvd_pkt->ssid, ssid)) + cfg80211_ssid_eq(rsvd_pkt->ssid, ssid)) size = rsvd_pkt->probe_req_size; } diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 63673005c2..ffba6b88f3 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -2008,6 +2008,11 @@ static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev) efuse->ext_pa_5g = efuse->pa_type_5g & BIT(0) ? 1 : 0; efuse->ext_lna_2g = efuse->lna_type_5g & BIT(3) ? 1 : 0; + if (!is_valid_ether_addr(efuse->addr)) { + eth_random_addr(efuse->addr); + dev_warn(rtwdev->dev, "efuse MAC invalid, using random\n"); + } + out_disable: rtw_chip_efuse_disable(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index b6bfd4c02e..e14d1da439 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -2090,18 +2090,6 @@ static inline struct ieee80211_vif *rtwvif_to_vif(struct rtw_vif *rtwvif) return container_of(p, struct ieee80211_vif, drv_priv); } -static inline bool rtw_ssid_equal(struct cfg80211_ssid *a, - struct cfg80211_ssid *b) -{ - if (!a || !b || a->ssid_len != b->ssid_len) - return false; - - if (memcmp(a->ssid, b->ssid, a->ssid_len)) - return false; - - return true; -} - static inline void rtw_chip_efuse_grant_on(struct rtw_dev *rtwdev) { if (rtwdev->chip->ops->efuse_grant) diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index f63900b662..c02ac673be 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -656,9 +656,8 @@ void __rtw_tx_work(struct rtw_dev *rtwdev) list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->txqs, list) { struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); unsigned long frame_cnt; - unsigned long byte_cnt; - ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt); + ieee80211_txq_get_depth(txq, &frame_cnt, NULL); rtw_txq_push(rtwdev, rtwtxq, frame_cnt); list_del_init(&rtwtxq->list); diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c index 8aaf83a2a6..2e7326a8e3 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.c +++ b/drivers/net/wireless/realtek/rtw89/acpi.c @@ -12,27 +12,74 @@ static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00, 0x82, 0xBD, 0xFE, 0x86, 0x07, 0x80, 0x3A, 0xA7); -static int rtw89_acpi_dsm_get(struct rtw89_dev *rtwdev, union acpi_object *obj, - u8 *value) +static +int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj, + u8 *value) { - switch (obj->type) { - case ACPI_TYPE_INTEGER: - *value = (u8)obj->integer.value; - break; - case ACPI_TYPE_BUFFER: - *value = obj->buffer.pointer[0]; - break; - default: - rtw89_debug(rtwdev, RTW89_DBG_UNEXP, - "acpi dsm return unhandled type: %d\n", obj->type); + if (obj->type != ACPI_TYPE_INTEGER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect integer but type: %d\n", obj->type); return -EINVAL; } + *value = (u8)obj->integer.value; + return 0; +} + +static bool chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz *p) +{ + return p->signature[0] == 0x00 && + p->signature[1] == 0xE0 && + p->signature[2] == 0x4C; +} + +static +int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev, + union acpi_object *obj, + struct rtw89_acpi_policy_6ghz **policy_6ghz) +{ + const struct rtw89_acpi_policy_6ghz *ptr; + u32 expect_len; + u32 len; + + if (obj->type != ACPI_TYPE_BUFFER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect buffer but type: %d\n", obj->type); + return -EINVAL; + } + + len = obj->buffer.length; + if (len < sizeof(*ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", + __func__, len); + return -EINVAL; + } + + ptr = (typeof(ptr))obj->buffer.pointer; + if (!chk_acpi_policy_6ghz_sig(ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); + return -EINVAL; + } + + expect_len = struct_size(ptr, country_list, ptr->country_count); + if (len < expect_len) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: expect %u but length: %u\n", + __func__, expect_len, len); + return -EINVAL; + } + + *policy_6ghz = kmemdup(ptr, expect_len, GFP_KERNEL); + if (!*policy_6ghz) + return -ENOMEM; + + rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz: ", *policy_6ghz, + expect_len); return 0; } int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, - enum rtw89_acpi_dsm_func func, u8 *value) + enum rtw89_acpi_dsm_func func, + struct rtw89_acpi_dsm_result *res) { union acpi_object *obj; int ret; @@ -40,12 +87,16 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid, 0, func, NULL); if (!obj) { - rtw89_debug(rtwdev, RTW89_DBG_UNEXP, + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "acpi dsm fail to evaluate func: %d\n", func); return -ENOENT; } - ret = rtw89_acpi_dsm_get(rtwdev, obj, value); + if (func == RTW89_ACPI_DSM_FUNC_6G_BP) + ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj, + &res->u.policy_6ghz); + else + ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value); ACPI_FREE(obj); return ret; diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index ed74d8ceb7..fe85b40cf0 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -15,7 +15,37 @@ enum rtw89_acpi_dsm_func { RTW89_ACPI_DSM_FUNC_59G_EN = 6, }; +enum rtw89_acpi_policy_mode { + RTW89_ACPI_POLICY_BLOCK = 0, + RTW89_ACPI_POLICY_ALLOW = 1, +}; + +struct rtw89_acpi_country_code { + /* below are allowed: + * * ISO alpha2 country code + * * EU for countries in Europe + */ + char alpha2[2]; +} __packed; + +struct rtw89_acpi_policy_6ghz { + u8 signature[3]; + u8 rsvd; + u8 policy_mode; + u8 country_count; + struct rtw89_acpi_country_code country_list[] __counted_by(country_count); +} __packed; + +struct rtw89_acpi_dsm_result { + union { + u8 value; + /* caller needs to free it after using */ + struct rtw89_acpi_policy_6ghz *policy_6ghz; + } u; +}; + int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, - enum rtw89_acpi_dsm_func func, u8 *value); + enum rtw89_acpi_dsm_func func, + struct rtw89_acpi_dsm_result *res); #endif diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index f5301c2bbf..914c94988b 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -488,6 +488,20 @@ static int rtw89_cam_get_avail_addr_cam(struct rtw89_dev *rtwdev, return 0; } +static u8 rtw89_get_addr_cam_entry_size(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + switch (chip->chip_id) { + case RTL8852A: + case RTL8852B: + case RTL8851B: + return ADDR_CAM_ENT_SIZE; + default: + return ADDR_CAM_ENT_SHORT_SIZE; + } +} + int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, struct rtw89_addr_cam_entry *addr_cam, const struct rtw89_bssid_cam_entry *bssid_cam) @@ -509,7 +523,7 @@ int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, } addr_cam->addr_cam_idx = addr_cam_idx; - addr_cam->len = ADDR_CAM_ENT_SIZE; + addr_cam->len = rtw89_get_addr_cam_entry_size(rtwdev); addr_cam->offset = 0; addr_cam->valid = true; addr_cam->addr_mask = 0; diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index ace7bbf2cf..f37afb4cbb 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -6,6 +6,7 @@ #include "debug.h" #include "fw.h" #include "mac.h" +#include "phy.h" #include "ps.h" #include "reg.h" @@ -122,7 +123,8 @@ static const u32 cxtbl[] = { 0xea55556a, /* 21 */ 0xaafafafa, /* 22 */ 0xfafaaafa, /* 23 */ - 0xfafffaff /* 24 */ + 0xfafffaff, /* 24 */ + 0xea6a5a5a, /* 25 */ }; static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { @@ -246,6 +248,11 @@ struct rtw89_btc_btf_set_mon_reg { struct rtw89_btc_fbtc_mreg regs[] __counted_by(reg_num); } __packed; +struct _wl_rinfo_now { + u8 link_mode; + u32 dbcc_2g_phy: 2; +}; + enum btc_btf_set_cx_policy { CXPOLICY_TDMA = 0x0, CXPOLICY_SLOT = 0x1, @@ -262,6 +269,8 @@ enum btc_b2w_scoreboard { BTC_BSCB_RFK_RUN = BIT(5), BTC_BSCB_RFK_REQ = BIT(6), BTC_BSCB_LPS = BIT(7), + BTC_BSCB_BT_LNAB0 = BIT(8), + BTC_BSCB_BT_LNAB1 = BIT(10), BTC_BSCB_WLRFK = BIT(11), BTC_BSCB_BT_HILNA = BIT(13), BTC_BSCB_BT_CONNECT = BIT(16), @@ -405,11 +414,14 @@ enum btc_cx_poicy_type { /* TDMA Fix slot-8: W1:B1 = user-define */ BTC_CXP_FIX_TDW1B1 = (BTC_CXP_FIX << 8) | 8, - /* TDMA Fix slot-9: W1:B1 = 40:20 */ - BTC_CXP_FIX_TD4020 = (BTC_CXP_FIX << 8) | 9, - /* TDMA Fix slot-9: W1:B1 = 40:10 */ - BTC_CXP_FIX_TD4010ISO = (BTC_CXP_FIX << 8) | 10, + BTC_CXP_FIX_TD4010ISO = (BTC_CXP_FIX << 8) | 9, + + /* TDMA Fix slot-10: W1:B1 = 40:10 */ + BTC_CXP_FIX_TD4010ISO_DL = (BTC_CXP_FIX << 8) | 10, + + /* TDMA Fix slot-11: W1:B1 = 40:10 */ + BTC_CXP_FIX_TD4010ISO_UL = (BTC_CXP_FIX << 8) | 11, /* PS-TDMA Fix slot-0: W1:B1 = 30:30 */ BTC_CXP_PFIX_TD3030 = (BTC_CXP_PFIX << 8) | 0, @@ -710,7 +722,8 @@ static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type) if (type & BTC_RESET_CX) memset(cx, 0, sizeof(*cx)); - else if (type & BTC_RESET_BTINFO) /* only for BT enable */ + + if (type & BTC_RESET_BTINFO) /* only for BT enable */ memset(bt, 0, sizeof(*bt)); if (type & BTC_RESET_CTRL) { @@ -739,12 +752,115 @@ static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type) btc->dm.coex_info_map = BTC_COEX_INFO_ALL; btc->dm.wl_tx_limit.tx_time = BTC_MAX_TX_TIME_DEF; btc->dm.wl_tx_limit.tx_retry = BTC_MAX_TX_RETRY_DEF; + btc->dm.wl_pre_agc_rb = BTC_PREAGC_NOTFOUND; + btc->dm.wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_NOTFOUND; } if (type & BTC_RESET_MDINFO) memset(&btc->mdinfo, 0, sizeof(btc->mdinfo)); } +static u8 _search_reg_index(struct rtw89_dev *rtwdev, u8 mreg_num, u16 reg_type, u32 target) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + u8 i; + + for (i = 0; i < mreg_num; i++) + if (le16_to_cpu(chip->mon_reg[i].type) == reg_type && + le32_to_cpu(chip->mon_reg[i].offset) == target) { + return i; + } + return BTC_REG_NOTFOUND; +} + +static void _get_reg_status(struct rtw89_dev *rtwdev, u8 type, u8 *val) +{ + struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; + struct rtw89_btc_module *md = &btc->mdinfo; + union rtw89_btc_fbtc_mreg_val *pmreg; + u32 pre_agc_addr = R_BTC_BB_PRE_AGC_S1; + u32 reg_val; + u8 idx; + + if (md->ant.btg_pos == RF_PATH_A) + pre_agc_addr = R_BTC_BB_PRE_AGC_S0; + + switch (type) { + case BTC_CSTATUS_TXDIV_POS: + if (md->switch_type == BTC_SWITCH_INTERNAL) + *val = BTC_ANT_DIV_MAIN; + break; + case BTC_CSTATUS_RXDIV_POS: + if (md->switch_type == BTC_SWITCH_INTERNAL) + *val = BTC_ANT_DIV_MAIN; + break; + case BTC_CSTATUS_BB_GNT_MUX: + reg_val = rtw89_phy_read32(rtwdev, R_BTC_BB_BTG_RX); + *val = !(reg_val & B_BTC_BB_GNT_MUX); + break; + case BTC_CSTATUS_BB_GNT_MUX_MON: + if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid) + return; + + pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo; + if (ver->fcxmreg == 1) { + idx = _search_reg_index(rtwdev, pmreg->v1.reg_num, + REG_BB, R_BTC_BB_BTG_RX); + if (idx == BTC_REG_NOTFOUND) { + *val = BTC_BTGCTRL_BB_GNT_NOTFOUND; + } else { + reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]); + *val = !(reg_val & B_BTC_BB_GNT_MUX); + } + } else if (ver->fcxmreg == 2) { + idx = _search_reg_index(rtwdev, pmreg->v2.reg_num, + REG_BB, R_BTC_BB_BTG_RX); + if (idx == BTC_REG_NOTFOUND) { + *val = BTC_BTGCTRL_BB_GNT_NOTFOUND; + } else { + reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]); + *val = !(reg_val & B_BTC_BB_GNT_MUX); + } + } + break; + case BTC_CSTATUS_BB_PRE_AGC: + reg_val = rtw89_phy_read32(rtwdev, pre_agc_addr); + reg_val &= B_BTC_BB_PRE_AGC_MASK; + *val = (reg_val == B_BTC_BB_PRE_AGC_VAL); + break; + case BTC_CSTATUS_BB_PRE_AGC_MON: + if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid) + return; + + pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo; + if (ver->fcxmreg == 1) { + idx = _search_reg_index(rtwdev, pmreg->v1.reg_num, + REG_BB, pre_agc_addr); + if (idx == BTC_REG_NOTFOUND) { + *val = BTC_PREAGC_NOTFOUND; + } else { + reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]) & + B_BTC_BB_PRE_AGC_MASK; + *val = (reg_val == B_BTC_BB_PRE_AGC_VAL); + } + } else if (ver->fcxmreg == 2) { + idx = _search_reg_index(rtwdev, pmreg->v2.reg_num, + REG_BB, pre_agc_addr); + if (idx == BTC_REG_NOTFOUND) { + *val = BTC_PREAGC_NOTFOUND; + } else { + reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]) & + B_BTC_BB_PRE_AGC_MASK; + *val = (reg_val == B_BTC_BB_PRE_AGC_VAL); + } + } + break; + default: + break; + } +} + #define BTC_RPT_HDR_SIZE 3 #define BTC_CHK_WLSLOT_DRIFT_MAX 15 #define BTC_CHK_BTSLOT_DRIFT_MAX 15 @@ -1003,7 +1119,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, u16 wl_slot_set = 0, wl_slot_real = 0; u32 trace_step = btc->ctrl.trace_step, rpt_len = 0, diff_t = 0; u32 cnt_leak_slot, bt_slot_real, bt_slot_set, cnt_rx_imr; - u8 i; + u8 i, val = 0; rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): index:%d\n", @@ -1508,6 +1624,19 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, goto err; } break; + case BTC_RPT_TYPE_MREG: + _get_reg_status(rtwdev, BTC_CSTATUS_BB_GNT_MUX_MON, &val); + if (dm->wl_btg_rx == BTC_BTGCTRL_BB_GNT_FWCTRL) + dm->wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_FWCTRL; + else + dm->wl_btg_rx_rb = val; + + _get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC_MON, &val); + if (dm->wl_pre_agc == BTC_PREAGC_BB_FWCTRL) + dm->wl_pre_agc_rb = BTC_PREAGC_BB_FWCTRL; + else + dm->wl_pre_agc_rb = val; + break; case BTC_RPT_TYPE_BT_VER: case BTC_RPT_TYPE_BT_SCAN: case BTC_RPT_TYPE_BT_AFH: @@ -1576,13 +1705,13 @@ static void _append_tdma(struct rtw89_dev *rtwdev) if (ver->fcxtdma == 1) { v = (struct rtw89_btc_fbtc_tdma *)&tlv->val[0]; tlv->len = sizeof(*v); - memcpy(v, &dm->tdma, sizeof(*v)); + *v = dm->tdma; btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v); } else { tlv->len = sizeof(*v3); v3 = (struct rtw89_btc_fbtc_tdma_v3 *)&tlv->val[0]; v3->fver = ver->fcxtdma; - memcpy(&v3->tdma, &dm->tdma, sizeof(v3->tdma)); + v3->tdma = dm->tdma; btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v3); } @@ -2155,8 +2284,9 @@ static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, u8 level) struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_bt_info *bt = &btc->cx.bt; - if (bt->rf_para.rx_gain_freerun == level || - level > BTC_BT_RX_NORMAL_LVL) + if ((bt->rf_para.rx_gain_freerun == level || + level > BTC_BT_RX_NORMAL_LVL) && + (!rtwdev->chip->scbd || bt->lna_constrain == level)) return; bt->rf_para.rx_gain_freerun = level; @@ -2171,32 +2301,59 @@ static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, u8 level) else _write_scbd(rtwdev, BTC_WSCB_RXGAIN, true); - _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_LNA_CONSTRAIN, &level, 1); + _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_LNA_CONSTRAIN, &level, sizeof(level)); } static void _set_rf_trx_para(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_bt_link_info *b = &bt->link_info; + struct rtw89_btc_wl_smap *wl_smap = &wl->status.map; struct rtw89_btc_rf_trx_para para; u32 wl_stb_chg = 0; - u8 level_id = 0; + u8 level_id = 0, link_mode = 0, i, dbcc_2g_phy = 0; + + if (ver->fwlrole == 0) { + link_mode = wl->role_info.link_mode; + for (i = 0; i < RTW89_PHY_MAX; i++) { + if (wl->dbcc_info.real_band[i] == RTW89_BAND_2G) + dbcc_2g_phy = i; + } + } else if (ver->fwlrole == 1) { + link_mode = wl->role_info_v1.link_mode; + dbcc_2g_phy = wl->role_info_v1.dbcc_2g_phy; + } else if (ver->fwlrole == 2) { + link_mode = wl->role_info_v2.link_mode; + dbcc_2g_phy = wl->role_info_v2.dbcc_2g_phy; + } - if (!dm->freerun) { - /* fix LNA2 = level-5 for BT ACI issue at BTG */ + /* decide trx_para_level */ + if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { + /* fix LNA2 + TIA gain not change by GNT_BT */ if ((btc->dm.wl_btg_rx && b->profile_cnt.now != 0) || dm->bt_only == 1) - dm->trx_para_level = 1; + dm->trx_para_level = 1; /* for better BT ACI issue */ else dm->trx_para_level = 0; + } else { /* non-shared antenna */ + dm->trx_para_level = 5; + /* modify trx_para if WK 2.4G-STA-DL + bt link */ + if (b->profile_cnt.now != 0 && + link_mode == BTC_WLINK_2G_STA && + wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) { /* uplink */ + if (wl->rssi_level == 4 && bt->rssi_level > 2) + dm->trx_para_level = 6; + else if (wl->rssi_level == 3 && bt->rssi_level > 3) + dm->trx_para_level = 7; + } } - level_id = (u8)dm->trx_para_level; - + level_id = dm->trx_para_level; if (level_id >= chip->rf_para_dlink_num || level_id >= chip->rf_para_ulink_num) { rtw89_debug(rtwdev, RTW89_DBG_BTC, @@ -2210,25 +2367,26 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev) else para = chip->rf_para_dlink[level_id]; - if (para.wl_tx_power != RTW89_BTC_WL_DEF_TX_PWR) - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): wl_tx_power=%d\n", - __func__, para.wl_tx_power); - _set_wl_tx_power(rtwdev, para.wl_tx_power); - _set_wl_rx_gain(rtwdev, para.wl_rx_gain); - _set_bt_tx_power(rtwdev, para.bt_tx_power); - _set_bt_rx_gain(rtwdev, para.bt_rx_gain); - - if (bt->enable.now == 0 || wl->status.map.rf_off == 1 || - wl->status.map.lps == BTC_LPS_RF_OFF) + if (dm->fddt_train) { + _set_wl_rx_gain(rtwdev, 1); + _write_scbd(rtwdev, BTC_WSCB_RXGAIN, true); + } else { + _set_wl_tx_power(rtwdev, para.wl_tx_power); + _set_wl_rx_gain(rtwdev, para.wl_rx_gain); + _set_bt_tx_power(rtwdev, para.bt_tx_power); + _set_bt_rx_gain(rtwdev, para.bt_rx_gain); + } + + if (!bt->enable.now || dm->wl_only || wl_smap->rf_off || + wl_smap->lps == BTC_LPS_RF_OFF || + link_mode == BTC_WLINK_5G || + link_mode == BTC_WLINK_NOLINK || + (rtwdev->dbcc_en && dbcc_2g_phy != RTW89_PHY_1)) wl_stb_chg = 0; else wl_stb_chg = 1; if (wl_stb_chg != dm->wl_stb_chg) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): wl_stb_chg=%d\n", - __func__, wl_stb_chg); dm->wl_stb_chg = wl_stb_chg; chip->ops->btc_wl_s1_standby(rtwdev, dm->wl_stb_chg); } @@ -2661,9 +2819,17 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type) _slot_set(btc, CXST_W1, 40, tbl_w1, SLOT_ISO); _slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX); break; - case BTC_CXP_FIX_TD4020: - _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_MIX); - _slot_set(btc, CXST_B1, 20, tbl_b1, SLOT_MIX); + case BTC_CXP_FIX_TD4010ISO: + _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO); + _slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX); + break; + case BTC_CXP_FIX_TD4010ISO_DL: + _slot_set(btc, CXST_W1, 40, cxtbl[25], SLOT_ISO); + _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_ISO); + break; + case BTC_CXP_FIX_TD4010ISO_UL: + _slot_set(btc, CXST_W1, 40, cxtbl[20], SLOT_ISO); + _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_MIX); break; case BTC_CXP_FIX_TD7010: _slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO); @@ -3002,9 +3168,13 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO); _slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX); break; - case BTC_CXP_FIX_TD4020: - _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_MIX); - _slot_set(btc, CXST_B1, 20, tbl_b1, SLOT_MIX); + case BTC_CXP_FIX_TD4010ISO_DL: + _slot_set(btc, CXST_W1, 40, cxtbl[25], SLOT_ISO); + _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_ISO); + break; + case BTC_CXP_FIX_TD4010ISO_UL: + _slot_set(btc, CXST_W1, 40, cxtbl[20], SLOT_ISO); + _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_MIX); break; case BTC_CXP_FIX_TD7010: _slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO); @@ -3381,17 +3551,32 @@ static void _action_wl_init(struct rtw89_dev *rtwdev) _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_INIT); } -static void _action_wl_off(struct rtw89_dev *rtwdev) +static void _action_wl_off(struct rtw89_dev *rtwdev, u8 mode) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_wl_info *wl = &btc->cx.wl; rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__); - if (wl->status.map.rf_off || btc->dm.bt_only) + if (wl->status.map.rf_off || btc->dm.bt_only) { _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_WOFF); + } else if (wl->status.map.lps == BTC_LPS_RF_ON) { + if (wl->role_info.link_mode == BTC_WLINK_5G) + _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W5G); + else + _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); + } - _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF); + if (mode == BTC_WLINK_5G) { + _set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OFF); + } else if (wl->status.map.lps == BTC_LPS_RF_ON) { + if (btc->cx.bt.link_info.a2dp_desc.active) + _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF); + else + _set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_WL_OFF); + } else { + _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF); + } } static void _action_freerun(struct rtw89_dev *rtwdev) @@ -3426,31 +3611,25 @@ static void _action_bt_idle(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_bt_link_info *b = &btc->cx.bt.link_info; + struct rtw89_btc_wl_info *wl = &btc->cx.wl; _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */ switch (btc->cx.state_map) { case BTC_WBUSY_BNOSCAN: /*wl-busy + bt idle*/ - if (b->profile_cnt.now > 0) - _set_policy(rtwdev, BTC_CXP_FIX_TD4010, - BTC_ACT_BT_IDLE); + case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */ + if (b->status.map.connect) + _set_policy(rtwdev, BTC_CXP_FIX_TD4010, BTC_ACT_BT_IDLE); + else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL)) + _set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO_DL, BTC_ACT_BT_IDLE); else - _set_policy(rtwdev, BTC_CXP_FIX_TD4020, - BTC_ACT_BT_IDLE); + _set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO_UL, BTC_ACT_BT_IDLE); break; case BTC_WBUSY_BSCAN: /*wl-busy + bt-inq */ _set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_IDLE); break; - case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */ - if (b->profile_cnt.now > 0) - _set_policy(rtwdev, BTC_CXP_FIX_TD4010, - BTC_ACT_BT_IDLE); - else - _set_policy(rtwdev, BTC_CXP_FIX_TD4020, - BTC_ACT_BT_IDLE); - break; case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq */ _set_policy(rtwdev, BTC_CXP_FIX_TD5050, BTC_ACT_BT_IDLE); @@ -3617,7 +3796,7 @@ static void _action_bt_pan(struct rtw89_dev *rtwdev) _set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN); break; case BTC_WLINKING: /* wl-connecting + bt-PAN */ - _set_policy(rtwdev, BTC_CXP_FIX_TD4020, BTC_ACT_BT_PAN); + _set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO, BTC_ACT_BT_PAN); break; case BTC_WIDLE: /* wl-idle + bt-pan */ _set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN); @@ -3798,46 +3977,134 @@ static void _action_wl_rfk(struct rtw89_dev *rtwdev) static void _set_btg_ctrl(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; - const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; - struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info; struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1; struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2; + struct rtw89_btc_wl_role_info *wl_rinfo_v0 = &wl->role_info; struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info; - bool is_btg; - u8 mode; + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_btc_ver *ver = btc->ver; + struct rtw89_btc_bt_info *bt = &btc->cx.bt; + struct rtw89_btc_dm *dm = &btc->dm; + struct _wl_rinfo_now wl_rinfo; + u32 run_reason = btc->dm.run_reason; + u32 is_btg; + u8 i, val; if (btc->ctrl.manual) return; if (ver->fwlrole == 0) - mode = wl_rinfo->link_mode; + wl_rinfo.link_mode = wl_rinfo_v0->link_mode; else if (ver->fwlrole == 1) - mode = wl_rinfo_v1->link_mode; + wl_rinfo.link_mode = wl_rinfo_v1->link_mode; else if (ver->fwlrole == 2) - mode = wl_rinfo_v2->link_mode; + wl_rinfo.link_mode = wl_rinfo_v2->link_mode; else return; - /* notify halbb ignore GNT_BT or not for WL BB Rx-AGC control */ - if (mode == BTC_WLINK_5G) /* always 0 if 5G */ - is_btg = false; - else if (mode == BTC_WLINK_25G_DBCC && - wl_dinfo->real_band[RTW89_PHY_1] != RTW89_BAND_2G) - is_btg = false; + if (rtwdev->dbcc_en) { + if (ver->fwlrole == 0) { + for (i = 0; i < RTW89_PHY_MAX; i++) { + if (wl_dinfo->real_band[i] == RTW89_BAND_2G) + wl_rinfo.dbcc_2g_phy = i; + } + } else if (ver->fwlrole == 1) { + wl_rinfo.dbcc_2g_phy = wl_rinfo_v1->dbcc_2g_phy; + } else if (ver->fwlrole == 2) { + wl_rinfo.dbcc_2g_phy = wl_rinfo_v2->dbcc_2g_phy; + } else { + return; + } + } + + if (wl_rinfo.link_mode == BTC_WLINK_25G_MCC) + is_btg = BTC_BTGCTRL_BB_GNT_FWCTRL; + else if (!(bt->run_patch_code && bt->enable.now)) + is_btg = BTC_BTGCTRL_DISABLE; + else if (wl_rinfo.link_mode == BTC_WLINK_5G) + is_btg = BTC_BTGCTRL_DISABLE; + else if (dm->freerun) + is_btg = BTC_BTGCTRL_DISABLE; + else if (rtwdev->dbcc_en && wl_rinfo.dbcc_2g_phy != RTW89_PHY_1) + is_btg = BTC_BTGCTRL_DISABLE; else - is_btg = true; + is_btg = BTC_BTGCTRL_ENABLE; - if (btc->dm.run_reason != BTC_RSN_NTFY_INIT && - is_btg == btc->dm.wl_btg_rx) - return; + if (dm->wl_btg_rx_rb != dm->wl_btg_rx && + dm->wl_btg_rx_rb != BTC_BTGCTRL_BB_GNT_NOTFOUND) { + _get_reg_status(rtwdev, BTC_CSTATUS_BB_GNT_MUX, &val); + dm->wl_btg_rx_rb = val; + } + + if (run_reason == BTC_RSN_NTFY_INIT || + run_reason == BTC_RSN_NTFY_SWBAND || + dm->wl_btg_rx_rb != dm->wl_btg_rx || + is_btg != dm->wl_btg_rx) { + + dm->wl_btg_rx = is_btg; + + if (is_btg > BTC_BTGCTRL_ENABLE) + return; + + chip->ops->ctrl_btg_bt_rx(rtwdev, is_btg, RTW89_PHY_0); + } +} - btc->dm.wl_btg_rx = is_btg; +static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info; + struct rtw89_btc_wl_info *wl = &btc->cx.wl; + struct rtw89_btc_wl_role_info_v2 *wl_rinfo = &wl->role_info_v2; + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_btc_ver *ver = btc->ver; + struct rtw89_btc_bt_info *bt = &btc->cx.bt; + struct rtw89_btc_dm *dm = &btc->dm; + u8 is_preagc, val; - if (mode == BTC_WLINK_25G_MCC) + if (btc->ctrl.manual) return; - rtw89_ctrl_btg_bt_rx(rtwdev, is_btg, RTW89_PHY_0); + if (wl_rinfo->link_mode == BTC_WLINK_25G_MCC) + is_preagc = BTC_PREAGC_BB_FWCTRL; + else if (!(bt->run_patch_code && bt->enable.now)) + is_preagc = BTC_PREAGC_DISABLE; + else if (wl_rinfo->link_mode == BTC_WLINK_5G) + is_preagc = BTC_PREAGC_DISABLE; + else if (wl_rinfo->link_mode == BTC_WLINK_NOLINK || + btc->cx.bt.link_info.profile_cnt.now == 0) + is_preagc = BTC_PREAGC_DISABLE; + else if (dm->tdma_now.type != CXTDMA_OFF && + !bt_linfo->hfp_desc.exist && + !bt_linfo->hid_desc.exist && + dm->fddt_train == BTC_FDDT_DISABLE) + is_preagc = BTC_PREAGC_DISABLE; + else if (ver->fwlrole == 2 && wl_rinfo->dbcc_en && + wl_rinfo->dbcc_2g_phy != RTW89_PHY_1) + is_preagc = BTC_PREAGC_DISABLE; + else if (btc->mdinfo.ant.type == BTC_ANT_SHARED) + is_preagc = BTC_PREAGC_DISABLE; + else + is_preagc = BTC_PREAGC_ENABLE; + + if (dm->wl_pre_agc_rb != dm->wl_pre_agc && + dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND) { + _get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC, &val); + dm->wl_pre_agc_rb = val; + } + + if ((wl->coex_mode == BTC_MODE_NORMAL && + (dm->run_reason == BTC_RSN_NTFY_INIT || + dm->run_reason == BTC_RSN_NTFY_SWBAND || + dm->wl_pre_agc_rb != dm->wl_pre_agc)) || + is_preagc != dm->wl_pre_agc) { + dm->wl_pre_agc = is_preagc; + + if (is_preagc > BTC_PREAGC_ENABLE) + return; + chip->ops->ctrl_nbtg_bt_tx(rtwdev, dm->wl_pre_agc, RTW89_PHY_0); + } } struct rtw89_txtime_data { @@ -4024,6 +4291,7 @@ static void _action_common(struct rtw89_dev *rtwdev) struct rtw89_btc_wl_info *wl = &btc->cx.wl; _set_btg_ctrl(rtwdev); + _set_wl_preagc_ctrl(rtwdev); _set_wl_tx_limit(rtwdev); _set_bt_afh_info(rtwdev); _set_bt_rx_agc(rtwdev); @@ -5008,8 +5276,7 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update) return; } - if (!(val & BTC_BSCB_ON) || - btc->dm.cnt_dm[BTC_DCNT_BTCNT_HANG] >= BTC_CHK_HANG_MAX) + if (!(val & BTC_BSCB_ON)) bt->enable.now = 0; else bt->enable.now = 1; @@ -5035,6 +5302,9 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update) bt->btg_type = val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE; bt->link_info.a2dp_desc.exist = !!(val & BTC_BSCB_A2DP_ACT); + bt->lna_constrain = !!(val & BTC_BSCB_BT_LNAB0) + + !!(val & BTC_BSCB_BT_LNAB1) * 2 + 4; + /* if rfk run 1->0 */ if (bt->rfk_info.map.run && !(val & BTC_BSCB_RFK_RUN)) status_change = true; @@ -5128,17 +5398,28 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) } if (wl->status.map.rf_off_pre == wl->status.map.rf_off && - wl->status.map.lps_pre == wl->status.map.lps && - (reason == BTC_RSN_NTFY_POWEROFF || - reason == BTC_RSN_NTFY_RADIO_STATE)) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): return for WL rf off state no change!!\n", - __func__); - return; + wl->status.map.lps_pre == wl->status.map.lps) { + if (reason == BTC_RSN_NTFY_POWEROFF || + reason == BTC_RSN_NTFY_RADIO_STATE) { + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): return for WL rf off state no change!!\n", + __func__); + return; + } + if (wl->status.map.rf_off == 1 || + wl->status.map.lps == BTC_LPS_RF_OFF) { + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): return for WL rf off state!!\n", + __func__); + return; + } } + dm->freerun = false; dm->cnt_dm[BTC_DCNT_RUN]++; dm->fddt_train = BTC_FDDT_DISABLE; + btc->ctrl.igno_bt = false; + bt->scan_rx_low_pri = false; if (btc->ctrl.always_freerun) { _action_freerun(rtwdev); @@ -5153,15 +5434,11 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) } if (wl->status.map.rf_off || wl->status.map.lps || dm->bt_only) { - _action_wl_off(rtwdev); + _action_wl_off(rtwdev, mode); btc->ctrl.igno_bt = true; goto exit; } - btc->ctrl.igno_bt = false; - dm->freerun = false; - bt->scan_rx_low_pri = false; - if (reason == BTC_RSN_NTFY_INIT) { _action_wl_init(rtwdev); goto exit; @@ -5186,12 +5463,14 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) if (mode == BTC_WLINK_NOLINK || mode == BTC_WLINK_2G_STA || mode == BTC_WLINK_5G) { _action_wl_scan(rtwdev); + bt->scan_rx_low_pri = false; goto exit; } } if (wl->status.map.scan) { _action_wl_scan(rtwdev); + bt->scan_rx_low_pri = false; goto exit; } @@ -5308,6 +5587,7 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode) rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): mode=%d\n", __func__, mode); + wl->coex_mode = mode; dm->cnt_notify[BTC_NCNT_INIT_COEX]++; dm->wl_only = mode == BTC_MODE_WL ? 1 : 0; dm->bt_only = mode == BTC_MODE_BT ? 1 : 0; @@ -5352,6 +5632,10 @@ void rtw89_btc_ntfy_scan_start(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band) rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): phy_idx=%d, band=%d\n", __func__, phy_idx, band); + + if (phy_idx >= RTW89_PHY_MAX) + return; + btc->dm.cnt_notify[BTC_NCNT_SCAN_START]++; wl->status.map.scan = true; wl->scan_info.band[phy_idx] = band; @@ -5396,6 +5680,10 @@ void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band) rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): phy_idx=%d, band=%d\n", __func__, phy_idx, band); + + if (phy_idx >= RTW89_PHY_MAX) + return; + btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++; wl->scan_info.band[phy_idx] = band; @@ -5517,6 +5805,37 @@ void rtw89_btc_ntfy_icmp_packet_work(struct work_struct *work) mutex_unlock(&rtwdev->mutex); } +static u8 _update_bt_rssi_level(struct rtw89_dev *rtwdev, u8 rssi) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_bt_info *bt = &btc->cx.bt; + u8 *rssi_st, rssi_th, rssi_level = 0; + u8 i; + + /* for rssi locate in which {40, 36, 31, 28} + * if rssi >= 40% (-60dBm) --> rssi_level = 4 + * if 36% <= rssi < 40% --> rssi_level = 3 + * if 31% <= rssi < 36% --> rssi_level = 2 + * if 28% <= rssi < 31% --> rssi_level = 1 + * if rssi < 28% --> rssi_level = 0 + */ + + /* check if rssi across bt_rssi_thres boundary */ + for (i = 0; i < BTC_BT_RSSI_THMAX; i++) { + rssi_th = chip->bt_rssi_thres[i]; + rssi_st = &bt->link_info.rssi_state[i]; + + *rssi_st = _update_rssi_state(rtwdev, *rssi_st, rssi, rssi_th); + + if (BTC_RSSI_HIGH(*rssi_st)) { + rssi_level = BTC_BT_RSSI_THMAX - i; + break; + } + } + return rssi_level; +} + #define BT_PROFILE_PROTOCOL_MASK GENMASK(7, 4) static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) @@ -5592,7 +5911,8 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) btinfo.val = bt->raw_info[BTC_BTINFO_H0]; /* raw val is dBm unit, translate from -100~ 0dBm to 0~100%*/ b->rssi = chip->ops->btc_get_bt_rssi(rtwdev, btinfo.hb0.rssi); - btc->dm.trx_info.bt_rssi = b->rssi; + bt->rssi_level = _update_bt_rssi_level(rtwdev, b->rssi); + btc->dm.trx_info.bt_rssi = bt->rssi_level; /* parse raw info high-Byte1 */ btinfo.val = bt->raw_info[BTC_BTINFO_H1]; @@ -5796,22 +6116,22 @@ void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_sta chip->ops->btc_init_cfg(rtwdev); } else { rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, false); - if (rf_state == BTC_RFCTRL_WL_OFF) + if (rf_state == BTC_RFCTRL_FW_CTRL) + _write_scbd(rtwdev, BTC_WSCB_ACTIVE, false); + else if (rf_state == BTC_RFCTRL_WL_OFF) _write_scbd(rtwdev, BTC_WSCB_ALL, false); - else if (rf_state == BTC_RFCTRL_LPS_WL_ON && - wl->status.map.lps_pre != BTC_LPS_OFF) + else + _write_scbd(rtwdev, BTC_WSCB_ACTIVE, false); + + if (rf_state == BTC_RFCTRL_LPS_WL_ON && + wl->status.map.lps_pre != BTC_LPS_OFF) _update_bt_scbd(rtwdev, true); } btc->dm.cnt_dm[BTC_DCNT_BTCNT_HANG] = 0; - if (wl->status.map.lps_pre == BTC_LPS_OFF && - wl->status.map.lps_pre != wl->status.map.lps) - btc->dm.tdma_instant_excute = 1; - else - btc->dm.tdma_instant_excute = 0; + btc->dm.tdma_instant_excute = 1; _run_coex(rtwdev, BTC_RSN_NTFY_RADIO_STATE); - btc->dm.tdma_instant_excute = 0; wl->status.map.rf_off_pre = wl->status.map.rf_off; wl->status.map.lps_pre = wl->status.map.lps; } @@ -6050,6 +6370,13 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) dm->trx_info.tx_tp = link_info_t->tx_throughput; dm->trx_info.rx_tp = link_info_t->rx_throughput; + /* Trigger coex-run if 0x10980 reg-value is diff with coex setup */ + if ((dm->wl_btg_rx_rb != dm->wl_btg_rx && + dm->wl_btg_rx_rb != BTC_BTGCTRL_BB_GNT_NOTFOUND) || + (dm->wl_pre_agc_rb != dm->wl_pre_agc && + dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND)) + iter_data->is_sta_change = true; + if (is_sta_change) iter_data->is_sta_change = true; @@ -6435,8 +6762,9 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) bt_linfo->pan_desc.active ? "Y" : "N"); seq_printf(m, - " %-15s : rssi:%ddBm, tx_rate:%dM, %s%s%s", + " %-15s : rssi:%ddBm(lvl:%d), tx_rate:%dM, %s%s%s", "[link]", bt_linfo->rssi - 100, + bt->rssi_level, bt_linfo->tx_3m ? 3 : 2, bt_linfo->status.map.inq_pag ? " inq-page!!" : "", bt_linfo->status.map.acl_busy ? " acl_busy!!" : "", @@ -6545,6 +6873,8 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e #define CASE_BTC_SLOT_STR(e) case CXST_ ## e: return #e #define CASE_BTC_EVT_STR(e) case CXEVNT_## e: return #e +#define CASE_BTC_INIT(e) case BTC_MODE_## e: return #e +#define CASE_BTC_ANTPATH_STR(e) case BTC_ANT_##e: return #e static const char *steps_to_str(u16 step) { @@ -6625,8 +6955,9 @@ static const char *steps_to_str(u16 step) CASE_BTC_POLICY_STR(FIX_TD3060); CASE_BTC_POLICY_STR(FIX_TD2080); CASE_BTC_POLICY_STR(FIX_TDW1B1); - CASE_BTC_POLICY_STR(FIX_TD4020); CASE_BTC_POLICY_STR(FIX_TD4010ISO); + CASE_BTC_POLICY_STR(FIX_TD4010ISO_DL); + CASE_BTC_POLICY_STR(FIX_TD4010ISO_UL); CASE_BTC_POLICY_STR(PFIX_TD3030); CASE_BTC_POLICY_STR(PFIX_TD5050); CASE_BTC_POLICY_STR(PFIX_TD2030); @@ -6719,6 +7050,37 @@ static const char *id_to_evt(u32 id) } } +static const char *id_to_mode(u8 id) +{ + switch (id) { + CASE_BTC_INIT(NORMAL); + CASE_BTC_INIT(WL); + CASE_BTC_INIT(BT); + CASE_BTC_INIT(WLOFF); + default: + return "unknown"; + } +} + +static const char *id_to_ant(u32 id) +{ + switch (id) { + CASE_BTC_ANTPATH_STR(WPOWERON); + CASE_BTC_ANTPATH_STR(WINIT); + CASE_BTC_ANTPATH_STR(WONLY); + CASE_BTC_ANTPATH_STR(WOFF); + CASE_BTC_ANTPATH_STR(W2G); + CASE_BTC_ANTPATH_STR(W5G); + CASE_BTC_ANTPATH_STR(W25G); + CASE_BTC_ANTPATH_STR(FREERUN); + CASE_BTC_ANTPATH_STR(WRFK); + CASE_BTC_ANTPATH_STR(BRFK); + CASE_BTC_ANTPATH_STR(MAX); + default: + return "unknown"; + } +} + static void seq_print_segment(struct seq_file *m, const char *prefix, u16 *data, u8 len, u8 seg_len, u8 start_idx, u8 ring_len) @@ -6773,12 +7135,13 @@ static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m) (btc->ctrl.manual ? "(Manual)" : "(Auto)")); seq_printf(m, - " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%ld, run_cnt:%d\n", + " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%s, init_mode:%s, run_cnt:%d\n", "[status]", module->ant.type == BTC_ANT_SHARED ? "shared" : "dedicated", steps_to_str(dm->run_reason), steps_to_str(dm->run_action | BTC_ACT_EXT_BIT), - FIELD_GET(GENMASK(7, 0), dm->set_ant_path), + id_to_ant(FIELD_GET(GENMASK(7, 0), dm->set_ant_path)), + id_to_mode(wl->coex_mode), dm->cnt_dm[BTC_DCNT_RUN]); _show_dm_step(rtwdev, m); @@ -7681,7 +8044,8 @@ static void _get_gnt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_coex_gnt *gnt struct rtw89_mac_ax_gnt *gnt; u32 val, status; - if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B) { + if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B || + chip->chip_id == RTL8851B) { rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_1, &val); rtw89_mac_read_lte(rtwdev, R_AX_GNT_VAL, &status); @@ -7743,27 +8107,25 @@ static void _show_mreg_v1(struct rtw89_dev *rtwdev, struct seq_file *m) bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD], cx->cnt_bt[BTC_BCNT_SCBDUPDATE]); - /* To avoid I/O if WL LPS or power-off */ - if (!wl->status.map.lps && !wl->status.map.rf_off) { - btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev); + btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev); + _get_gnt(rtwdev, &gnt_cfg); + + gnt = gnt_cfg.band[0]; + seq_printf(m, + " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ", + "[gnt_status]", + chip->chip_id == RTL8852C ? "HW" : + btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT", + gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl, + gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt); + + gnt = gnt_cfg.band[1]; + seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n", + gnt.gnt_wl_sw_en ? "SW" : "HW", + gnt.gnt_wl, + gnt.gnt_bt_sw_en ? "SW" : "HW", + gnt.gnt_bt); - _get_gnt(rtwdev, &gnt_cfg); - gnt = gnt_cfg.band[0]; - seq_printf(m, - " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ", - "[gnt_status]", - chip->chip_id == RTL8852C ? "HW" : - btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT", - gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl, - gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt); - - gnt = gnt_cfg.band[1]; - seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n", - gnt.gnt_wl_sw_en ? "SW" : "HW", - gnt.gnt_wl, - gnt.gnt_bt_sw_en ? "SW" : "HW", - gnt.gnt_bt); - } pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo; if (!pcinfo->valid) { rtw89_debug(rtwdev, RTW89_DBG_BTC, @@ -7847,27 +8209,25 @@ static void _show_mreg_v2(struct rtw89_dev *rtwdev, struct seq_file *m) bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD], cx->cnt_bt[BTC_BCNT_SCBDUPDATE]); - /* To avoid I/O if WL LPS or power-off */ - if (!wl->status.map.lps && !wl->status.map.rf_off) { - btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev); + btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev); + _get_gnt(rtwdev, &gnt_cfg); + + gnt = gnt_cfg.band[0]; + seq_printf(m, + " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ", + "[gnt_status]", + chip->chip_id == RTL8852C ? "HW" : + btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT", + gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl, + gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt); + + gnt = gnt_cfg.band[1]; + seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n", + gnt.gnt_wl_sw_en ? "SW" : "HW", + gnt.gnt_wl, + gnt.gnt_bt_sw_en ? "SW" : "HW", + gnt.gnt_bt); - _get_gnt(rtwdev, &gnt_cfg); - gnt = gnt_cfg.band[0]; - seq_printf(m, - " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ", - "[gnt_status]", - chip->chip_id == RTL8852C ? "HW" : - btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT", - gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl, - gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt); - - gnt = gnt_cfg.band[1]; - seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n", - gnt.gnt_wl_sw_en ? "SW" : "HW", - gnt.gnt_wl, - gnt.gnt_bt_sw_en ? "SW" : "HW", - gnt.gnt_bt); - } pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo; if (!pcinfo->valid) { rtw89_debug(rtwdev, RTW89_DBG_BTC, diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index e761537097..46e25c6f88 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -142,6 +142,44 @@ enum btc_lps_state { BTC_LPS_RF_ON = 2 }; +#define R_BTC_BB_BTG_RX 0x980 +#define R_BTC_BB_PRE_AGC_S1 0x476C +#define R_BTC_BB_PRE_AGC_S0 0x4688 + +#define B_BTC_BB_GNT_MUX GENMASK(20, 17) +#define B_BTC_BB_PRE_AGC_MASK GENMASK(31, 24) +#define B_BTC_BB_PRE_AGC_VAL BIT(31) + +#define BTC_REG_NOTFOUND 0xff + +enum btc_ant_div_pos { + BTC_ANT_DIV_MAIN = 0, + BTC_ANT_DIV_AUX = 1, +}; + +enum btc_get_reg_status { + BTC_CSTATUS_TXDIV_POS = 0, + BTC_CSTATUS_RXDIV_POS = 1, + BTC_CSTATUS_BB_GNT_MUX = 2, + BTC_CSTATUS_BB_GNT_MUX_MON = 3, + BTC_CSTATUS_BB_PRE_AGC = 4, + BTC_CSTATUS_BB_PRE_AGC_MON = 5, +}; + +enum btc_preagc_type { + BTC_PREAGC_DISABLE, + BTC_PREAGC_ENABLE, + BTC_PREAGC_BB_FWCTRL, + BTC_PREAGC_NOTFOUND, +}; + +enum btc_btgctrl_type { + BTC_BTGCTRL_DISABLE, + BTC_BTGCTRL_ENABLE, + BTC_BTGCTRL_BB_GNT_FWCTRL, + BTC_BTGCTRL_BB_GNT_NOTFOUND, +}; + void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev); void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev); void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode); diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index a3624ebf01..fd527a2499 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1407,29 +1407,65 @@ static int rtw89_core_rx_process_mac_ppdu(struct rtw89_dev *rtwdev, struct sk_buff *skb, struct rtw89_rx_phy_ppdu *phy_ppdu) { + const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_rxinfo *rxinfo = (const struct rtw89_rxinfo *)skb->data; + const struct rtw89_rxinfo_user *user; + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + int rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE; bool rx_cnt_valid = false; + bool invalid = false; u8 plcp_size = 0; - u8 usr_num = 0; u8 *phy_sts; + u8 usr_num; + int i; + + if (chip_gen == RTW89_CHIP_BE) { + invalid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_INVALID_V1); + rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE_V1; + } + + if (invalid) + return -EINVAL; rx_cnt_valid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_RX_CNT_VLD); - plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3; - usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM); - if (usr_num > RTW89_PPDU_MAX_USR) { - rtw89_warn(rtwdev, "Invalid user number in mac info\n"); + if (chip_gen == RTW89_CHIP_BE) { + plcp_size = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_PLCP_LEN_V1) << 3; + usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM_V1); + } else { + plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3; + usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM); + } + if (usr_num > chip->ppdu_max_usr) { + rtw89_warn(rtwdev, "Invalid user number (%d) in mac info\n", + usr_num); return -EINVAL; } + /* For WiFi 7 chips, RXWD.mac_id of PPDU status is not set by hardware, + * so update mac_id by rxinfo_user[].mac_id. + */ + for (i = 0; i < usr_num && chip_gen == RTW89_CHIP_BE; i++) { + user = &rxinfo->user[i]; + if (!le32_get_bits(user->w0, RTW89_RXINFO_USER_MAC_ID_VALID)) + continue; + + phy_ppdu->mac_id = + le32_get_bits(user->w0, RTW89_RXINFO_USER_MACID); + break; + } + phy_sts = skb->data + RTW89_PPDU_MAC_INFO_SIZE; phy_sts += usr_num * RTW89_PPDU_MAC_INFO_USR_SIZE; /* 8-byte alignment */ if (usr_num & BIT(0)) phy_sts += RTW89_PPDU_MAC_INFO_USR_SIZE; if (rx_cnt_valid) - phy_sts += RTW89_PPDU_MAC_RX_CNT_SIZE; + phy_sts += rx_cnt_size; phy_sts += plcp_size; + if (phy_sts > skb->data + skb->len) + return -EINVAL; + phy_ppdu->buf = phy_sts; phy_ppdu->len = skb->data + skb->len - phy_sts; @@ -1477,14 +1513,24 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data, static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev, const struct rtw89_phy_sts_iehdr *iehdr) { - static const u8 physts_ie_len_tab[32] = { - 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, - VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, - VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 + static const u8 physts_ie_len_tabs[RTW89_CHIP_GEN_NUM][32] = { + [RTW89_CHIP_AX] = { + 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, + VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, + VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 + }, + [RTW89_CHIP_BE] = { + 32, 40, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, + VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, + VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 + }, }; + const u8 *physts_ie_len_tab; u16 ie_len; u8 ie; + physts_ie_len_tab = physts_ie_len_tabs[rtwdev->chip->chip_gen]; + ie = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_TYPE); if (physts_ie_len_tab[ie] != VAR_LEN) ie_len = physts_ie_len_tab[ie]; @@ -1563,9 +1609,17 @@ static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev, { const struct rtw89_phy_sts_hdr *hdr = phy_ppdu->buf; u32 len_from_header; + bool physts_valid; + + physts_valid = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_VALID); + if (!physts_valid) + return -EINVAL; len_from_header = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_LEN) << 3; + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) + len_from_header += PHY_STS_HDR_LEN; + if (len_from_header != phy_ppdu->len) { rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "phy ppdu len mismatch\n"); return -EINVAL; @@ -2052,13 +2106,19 @@ static void rtw89_core_rx_process_ppdu_sts(struct rtw89_dev *rtwdev, .mac_id = desc_info->mac_id}; int ret; - if (desc_info->mac_info_valid) - rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu); + if (desc_info->mac_info_valid) { + ret = rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu); + if (ret) + goto out; + } + ret = rtw89_core_rx_process_phy_ppdu(rtwdev, &phy_ppdu); if (ret) - rtw89_debug(rtwdev, RTW89_DBG_TXRX, "process ppdu failed\n"); + goto out; rtw89_core_rx_process_phy_sts(rtwdev, &phy_ppdu); + +out: rtw89_core_rx_pending_skb(rtwdev, &phy_ppdu, desc_info, skb); dev_kfree_skb_any(skb); } @@ -2823,9 +2883,6 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) lockdep_assert_held(&rtwdev->mutex); - ieee80211_queue_delayed_work(hw, &rtwvif->roc.roc_work, - msecs_to_jiffies(rtwvif->roc.duration)); - rtw89_leave_ips_by_hwflags(rtwdev); rtw89_leave_lps(rtwdev); rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_ROC); @@ -2847,6 +2904,9 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH); ieee80211_ready_on_channel(hw); + cancel_delayed_work(&rtwvif->roc.roc_work); + ieee80211_queue_delayed_work(hw, &rtwvif->roc.roc_work, + msecs_to_jiffies(rtwvif->roc.duration)); } void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) @@ -3069,6 +3129,7 @@ static void rtw89_track_work(struct work_struct *work) rtw89_phy_tx_path_div_track(rtwdev); rtw89_phy_antdiv_track(rtwdev); rtw89_phy_ul_tb_ctrl_track(rtwdev); + rtw89_phy_edcca_track(rtwdev); rtw89_tas_track(rtwdev); rtw89_chanctx_track(rtwdev); @@ -3895,10 +3956,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) /* efuse process */ /* pre-config BB/RF, BB reset/RFC reset */ - ret = rtw89_chip_disable_bb_rf(rtwdev); - if (ret) - return ret; - ret = rtw89_chip_enable_bb_rf(rtwdev); + ret = rtw89_chip_reset_bb_rf(rtwdev); if (ret) return ret; @@ -4156,17 +4214,18 @@ out: static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; int ret; ret = rtw89_mac_partial_init(rtwdev, false); if (ret) return ret; - ret = rtw89_parse_efuse_map(rtwdev); + ret = mac->parse_efuse_map(rtwdev); if (ret) return ret; - ret = rtw89_parse_phycap_map(rtwdev); + ret = mac->parse_phycap_map(rtwdev); if (ret) return ret; @@ -4176,6 +4235,8 @@ static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev) rtw89_core_setup_phycap(rtwdev); + rtw89_hci_mac_pre_deinit(rtwdev); + rtw89_mac_pwr_off(rtwdev); return 0; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 8f59461e58..ea6df859ba 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -16,6 +16,9 @@ struct rtw89_dev; struct rtw89_pci_info; struct rtw89_mac_gen_def; struct rtw89_phy_gen_def; +struct rtw89_efuse_block_cfg; +struct rtw89_fw_txpwr_track_cfg; +struct rtw89_phy_rfk_log_fmt; extern const struct ieee80211_ops rtw89_ops; @@ -37,6 +40,8 @@ extern const struct ieee80211_ops rtw89_ops; #define RSSI_FACTOR 1 #define RTW89_RSSI_RAW_TO_DBM(rssi) ((s8)((rssi) >> RSSI_FACTOR) - MAX_RSSI) #define RTW89_TX_DIV_RSSI_RAW_TH (2 << RSSI_FACTOR) +#define DELTA_SWINGIDX_SIZE 30 + #define RTW89_RADIOTAP_ROOM_HE sizeof(struct ieee80211_radiotap_he) #define RTW89_RADIOTAP_ROOM_EHT \ (sizeof(struct ieee80211_radiotap_tlv) + \ @@ -103,6 +108,14 @@ enum rtw89_gain_offset { RTW89_GAIN_OFFSET_5G_LOW, RTW89_GAIN_OFFSET_5G_MID, RTW89_GAIN_OFFSET_5G_HIGH, + RTW89_GAIN_OFFSET_6G_L0, + RTW89_GAIN_OFFSET_6G_L1, + RTW89_GAIN_OFFSET_6G_M0, + RTW89_GAIN_OFFSET_6G_M1, + RTW89_GAIN_OFFSET_6G_H0, + RTW89_GAIN_OFFSET_6G_H1, + RTW89_GAIN_OFFSET_6G_UH0, + RTW89_GAIN_OFFSET_6G_UH1, RTW89_GAIN_OFFSET_NR, }; @@ -1693,6 +1706,7 @@ struct rtw89_btc_wl_info { u8 port_id[RTW89_WIFI_ROLE_MLME_MAX]; u8 rssi_level; u8 cn_report; + u8 coex_mode; bool scbd_change; u32 scbd; @@ -1800,6 +1814,7 @@ struct rtw89_btc_bt_info { union rtw89_btc_bt_rfk_info_map rfk_info; u8 raw_info[BTC_BTINFO_MAX]; /* raw bt info from mailbox */ + u8 rssi_level; u32 scbd; u32 feature; @@ -1816,7 +1831,8 @@ struct rtw89_btc_bt_info { u32 hi_lna_rx: 1; u32 scan_rx_low_pri: 1; u32 scan_info_update: 1; - u32 rsvd: 20; + u32 lna_constrain: 3; + u32 rsvd: 17; }; struct rtw89_btc_cx { @@ -2492,18 +2508,22 @@ struct rtw89_btc_dm { u32 noisy_level: 3; u32 coex_info_map: 8; u32 bt_only: 1; - u32 wl_btg_rx: 1; + u32 wl_btg_rx: 2; u32 trx_para_level: 8; u32 wl_stb_chg: 1; u32 pta_owner: 1; + u32 tdma_instant_excute: 1; + u32 wl_btg_rx_rb: 2; u16 slot_dur[CXST_MAX]; u8 run_reason; u8 run_action; + u8 wl_pre_agc: 2; u8 wl_lna2: 1; + u8 wl_pre_agc_rb: 2; }; struct rtw89_btc_ctrl { @@ -2771,6 +2791,20 @@ enum rtw89_rx_frame_type { RTW89_RX_TYPE_RSVD = 3, }; +enum rtw89_efuse_block { + RTW89_EFUSE_BLOCK_SYS = 0, + RTW89_EFUSE_BLOCK_RF = 1, + RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO = 2, + RTW89_EFUSE_BLOCK_HCI_DIG_USB = 3, + RTW89_EFUSE_BLOCK_HCI_PHY_PCIE = 4, + RTW89_EFUSE_BLOCK_HCI_PHY_USB3 = 5, + RTW89_EFUSE_BLOCK_HCI_PHY_USB2 = 6, + RTW89_EFUSE_BLOCK_ADIE = 7, + + RTW89_EFUSE_BLOCK_NUM, + RTW89_EFUSE_BLOCK_IGNORE, +}; + struct rtw89_ra_info { u8 is_dis_ra:1; /* Bit0 : CCK @@ -2809,10 +2843,10 @@ struct rtw89_ra_info { u8 csi_bw:3; }; -#define RTW89_PPDU_MAX_USR 4 #define RTW89_PPDU_MAC_INFO_USR_SIZE 4 #define RTW89_PPDU_MAC_INFO_SIZE 8 #define RTW89_PPDU_MAC_RX_CNT_SIZE 96 +#define RTW89_PPDU_MAC_RX_CNT_SIZE_V1 128 #define RTW89_MAX_RX_AGG_NUM 64 #define RTW89_MAX_TX_AGG_NUM 128 @@ -3058,6 +3092,7 @@ struct rtw89_hci_ops { void (*write32)(struct rtw89_dev *rtwdev, u32 addr, u32 data); int (*mac_pre_init)(struct rtw89_dev *rtwdev); + int (*mac_pre_deinit)(struct rtw89_dev *rtwdev); int (*mac_post_init)(struct rtw89_dev *rtwdev); int (*deinit)(struct rtw89_dev *rtwdev); @@ -3112,7 +3147,8 @@ struct rtw89_chip_ops { const struct rtw89_chan *chan, enum rtw89_mac_idx mac_idx, enum rtw89_phy_idx phy_idx); - int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map); + int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block); int (*read_phycap)(struct rtw89_dev *rtwdev, u8 *phycap_map); void (*fem_setup)(struct rtw89_dev *rtwdev); void (*rfe_gpio)(struct rtw89_dev *rtwdev); @@ -3261,6 +3297,8 @@ struct rtw89_dle_size { u16 pge_size; u16 lnk_pge_num; u16 unlnk_pge_num; + /* for WiFi 7 chips below */ + u32 srt_ofst; }; struct rtw89_wde_quota { @@ -3283,6 +3321,26 @@ struct rtw89_ple_quota { u16 wd_rel; u16 cpu_io; u16 tx_rpt; + /* for WiFi 7 chips below */ + u16 h2d; +}; + +struct rtw89_rsvd_quota { + u16 mpdu_info_tbl; + u16 b0_csi; + u16 b1_csi; + u16 b0_lmr; + u16 b1_lmr; + u16 b0_ftm; + u16 b1_ftm; + u16 b0_smr; + u16 b1_smr; + u16 others; +}; + +struct rtw89_dle_rsvd_size { + u32 srt_ofst; + u32 size; }; struct rtw89_dle_mem { @@ -3293,6 +3351,10 @@ struct rtw89_dle_mem { const struct rtw89_wde_quota *wde_max_qt; const struct rtw89_ple_quota *ple_min_qt; const struct rtw89_ple_quota *ple_max_qt; + /* for WiFi 7 chips below */ + const struct rtw89_rsvd_quota *rsvd_qt; + const struct rtw89_dle_rsvd_size *rsvd0_size; + const struct rtw89_dle_rsvd_size *rsvd1_size; }; struct rtw89_reg_def { @@ -3319,6 +3381,12 @@ struct rtw89_reg5_def { u32 data; }; +struct rtw89_reg_imr { + u32 addr; + u32 clr; + u32 set; +}; + struct rtw89_phy_table { const struct rtw89_reg2_def *regs; u32 n_regs; @@ -3528,6 +3596,11 @@ struct rtw89_imr_info { u32 tmac_imr_set; }; +struct rtw89_imr_table { + const struct rtw89_reg_imr *regs; + u32 n_regs; +}; + struct rtw89_xtal_info { u32 xcap_reg; u32 sc_xo_mask; @@ -3559,6 +3632,22 @@ struct rtw89_dig_regs { struct rtw89_reg_def p1_s20_pagcugc_en; }; +struct rtw89_edcca_regs { + u32 edcca_level; + u32 edcca_mask; + u32 edcca_p_mask; + u32 ppdu_level; + u32 ppdu_mask; + u32 rpt_a; + u32 rpt_b; + u32 rpt_sel; + u32 rpt_sel_mask; + u32 rpt_sel_be; + u32 rpt_sel_be_mask; + u32 tx_collision_t2r_st; + u32 tx_collision_t2r_st_mask; +}; + struct rtw89_phy_ul_tb_info { bool dyn_tb_tri_en; u8 def_if_bandedge; @@ -3619,8 +3708,8 @@ struct rtw89_chip_info { u32 rsvd_ple_ofst; const struct rtw89_hfc_param_ini *hfc_param_ini; const struct rtw89_dle_mem *dle_mem; - u8 wde_qempty_acq_num; - u8 wde_qempty_mgq_sel; + u8 wde_qempty_acq_grpnum; + u8 wde_qempty_mgq_grpsel; u32 rf_base_addr[2]; u8 support_chanctx_num; u8 support_bands; @@ -3638,6 +3727,7 @@ struct rtw89_chip_info { u8 bacam_num; u8 bacam_dynamic_num; enum rtw89_bacam_ver bacam_ver; + u8 ppdu_max_usr; u8 sec_ctrl_efuse_size; u32 physical_efuse_size; @@ -3647,6 +3737,7 @@ struct rtw89_chip_info { u32 dav_log_efuse_size; u32 phycap_addr; u32 phycap_size; + const struct rtw89_efuse_block_cfg *efuse_blocks; const struct rtw89_pwr_cfg * const *pwr_on_seq; const struct rtw89_pwr_cfg * const *pwr_off_seq; @@ -3704,11 +3795,13 @@ struct rtw89_chip_info { const struct rtw89_reg_def *dcfo_comp; u8 dcfo_comp_sft; const struct rtw89_imr_info *imr_info; + const struct rtw89_imr_table *imr_dmac_table; + const struct rtw89_imr_table *imr_cmac_table; const struct rtw89_rrsr_cfgs *rrsr_cfgs; struct rtw89_reg_def bss_clr_vld; u32 bss_clr_map_reg; u32 dma_ch_mask; - u32 edcca_lvl_reg; + const struct rtw89_edcca_regs *edcca_regs; const struct wiphy_wowlan_support *wowlan_stub; const struct rtw89_xtal_info *xtal_info; }; @@ -3732,8 +3825,10 @@ enum rtw89_hcifc_mode { }; struct rtw89_dle_info { + const struct rtw89_rsvd_quota *rsvd_qt; enum rtw89_qta_mode qta_mode; u16 ple_pg_size; + u16 ple_free_pg; u16 c0_rx_qta; u16 c1_rx_qta; }; @@ -3858,6 +3953,8 @@ struct rtw89_fw_elm_info { struct rtw89_phy_table *bb_gain; struct rtw89_phy_table *rf_radio[RF_PATH_MAX]; struct rtw89_phy_table *rf_nctl; + struct rtw89_fw_txpwr_track_cfg *txpwr_trk; + struct rtw89_phy_rfk_log_fmt *rfk_log_fmt; }; struct rtw89_fw_info { @@ -3977,6 +4074,17 @@ struct rtw89_sub_entity { struct rtw89_chanctx_cfg *cfg; }; +struct rtw89_edcca_bak { + u8 a; + u8 p; + u8 ppdu; + u8 th_old; +}; + +enum rtw89_dm_type { + RTW89_DM_DYNAMIC_EDCCA, +}; + struct rtw89_hal { u32 rx_fltr; u8 cv; @@ -4001,7 +4109,8 @@ struct rtw89_hal { bool entity_pause; enum rtw89_entity_mode entity_mode; - u32 edcca_bak; + struct rtw89_edcca_bak edcca_bak; + u32 disabled_dm_bitmap; /* bitmap of enum rtw89_dm_type */ }; #define RTW89_MAX_MAC_ID_NUM 128 @@ -4009,6 +4118,9 @@ struct rtw89_hal { enum rtw89_flags { RTW89_FLAG_POWERON, + RTW89_FLAG_DMAC_FUNC, + RTW89_FLAG_CMAC0_FUNC, + RTW89_FLAG_CMAC1_FUNC, RTW89_FLAG_FW_RDY, RTW89_FLAG_RUNNING, RTW89_FLAG_BFEE_MON, @@ -4312,6 +4424,7 @@ struct rtw89_power_trim_info { bool pg_pa_bias_trim; u8 thermal_trim[RF_PATH_MAX]; u8 pa_bias_trim[RF_PATH_MAX]; + u8 pad_bias_trim[RF_PATH_MAX]; }; struct rtw89_regd { @@ -4319,9 +4432,12 @@ struct rtw89_regd { u8 txpwr_regd[RTW89_BAND_NUM]; }; +#define RTW89_REGD_MAX_COUNTRY_NUM U8_MAX + struct rtw89_regulatory_info { const struct rtw89_regd *regd; enum rtw89_reg_6ghz_power reg_6ghz_power; + DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM); }; enum rtw89_ifs_clm_application { @@ -4796,6 +4912,11 @@ static inline void rtw89_hci_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch) return rtwdev->hci.ops->tx_kick_off(rtwdev, txch); } +static inline int rtw89_hci_mac_pre_deinit(struct rtw89_dev *rtwdev) +{ + return rtwdev->hci.ops->mac_pre_deinit(rtwdev); +} + static inline void rtw89_hci_flush_queues(struct rtw89_dev *rtwdev, u32 queues, bool drop) { diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index a3f795d240..44829a1481 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3330,13 +3330,14 @@ out: static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_cpuio_ctrl ctrl_para = {0}; u16 pkt_id; int ret; rtw89_leave_ps_mode(rtwdev); - ret = rtw89_mac_dle_buf_req(rtwdev, 0x20, true, &pkt_id); + ret = mac->dle_buf_req(rtwdev, 0x20, true, &pkt_id); if (ret) return ret; @@ -3348,7 +3349,7 @@ static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev) ctrl_para.dst_pid = WDE_DLE_PORT_ID_WDRLS; ctrl_para.dst_qid = WDE_DLE_QUEID_NO_REPORT; - if (rtw89_mac_set_cpuio(rtwdev, &ctrl_para, true)) + if (mac->set_cpuio(rtwdev, &ctrl_para, true)) return -EFAULT; return 0; @@ -3770,6 +3771,58 @@ static int rtw89_debug_priv_stations_get(struct seq_file *m, void *v) return 0; } +#define DM_INFO(type) {RTW89_DM_ ## type, #type} + +static const struct rtw89_disabled_dm_info { + enum rtw89_dm_type type; + const char *name; +} rtw89_disabled_dm_infos[] = { + DM_INFO(DYNAMIC_EDCCA), +}; + +static int +rtw89_debug_priv_disable_dm_get(struct seq_file *m, void *v) +{ + struct rtw89_debugfs_priv *debugfs_priv = m->private; + struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; + const struct rtw89_disabled_dm_info *info; + struct rtw89_hal *hal = &rtwdev->hal; + u32 disabled; + int i; + + seq_printf(m, "Disabled DM: 0x%x\n", hal->disabled_dm_bitmap); + + for (i = 0; i < ARRAY_SIZE(rtw89_disabled_dm_infos); i++) { + info = &rtw89_disabled_dm_infos[i]; + disabled = BIT(info->type) & hal->disabled_dm_bitmap; + + seq_printf(m, "[%d] %s: %c\n", info->type, info->name, + disabled ? 'X' : 'O'); + } + + return 0; +} + +static ssize_t +rtw89_debug_priv_disable_dm_set(struct file *filp, const char __user *user_buf, + size_t count, loff_t *loff) +{ + struct seq_file *m = (struct seq_file *)filp->private_data; + struct rtw89_debugfs_priv *debugfs_priv = m->private; + struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; + struct rtw89_hal *hal = &rtwdev->hal; + u32 conf; + int ret; + + ret = kstrtou32_from_user(user_buf, count, 0, &conf); + if (ret) + return -EINVAL; + + hal->disabled_dm_bitmap = conf; + + return count; +} + static struct rtw89_debugfs_priv rtw89_debug_priv_read_reg = { .cb_read = rtw89_debug_priv_read_reg_get, .cb_write = rtw89_debug_priv_read_reg_select, @@ -3845,6 +3898,11 @@ static struct rtw89_debugfs_priv rtw89_debug_priv_stations = { .cb_read = rtw89_debug_priv_stations_get, }; +static struct rtw89_debugfs_priv rtw89_debug_priv_disable_dm = { + .cb_read = rtw89_debug_priv_disable_dm_get, + .cb_write = rtw89_debug_priv_disable_dm_set, +}; + #define rtw89_debugfs_add(name, mode, fopname, parent) \ do { \ rtw89_debug_priv_ ##name.rtwdev = rtwdev; \ @@ -3885,13 +3943,13 @@ void rtw89_debugfs_init(struct rtw89_dev *rtwdev) rtw89_debugfs_add_w(fw_log_manual); rtw89_debugfs_add_r(phy_info); rtw89_debugfs_add_r(stations); + rtw89_debugfs_add_rw(disable_dm); } #endif #ifdef CONFIG_RTW89_DEBUGMSG -void __rtw89_debug(struct rtw89_dev *rtwdev, - enum rtw89_debug_mask mask, - const char *fmt, ...) +void rtw89_debug(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask, + const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, @@ -3907,5 +3965,5 @@ void __rtw89_debug(struct rtw89_dev *rtwdev, va_end(args); } -EXPORT_SYMBOL(__rtw89_debug); +EXPORT_SYMBOL(rtw89_debug); #endif diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h index 079269bb52..800ea59873 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.h +++ b/drivers/net/wireless/realtek/rtw89/debug.h @@ -29,6 +29,8 @@ enum rtw89_debug_mask { RTW89_DBG_WOW = BIT(18), RTW89_DBG_UL_TB = BIT(19), RTW89_DBG_CHAN = BIT(20), + RTW89_DBG_ACPI = BIT(21), + RTW89_DBG_EDCCA = BIT(22), RTW89_DBG_UNEXP = BIT(31), }; @@ -57,12 +59,10 @@ static inline void rtw89_debugfs_init(struct rtw89_dev *rtwdev) {} #ifdef CONFIG_RTW89_DEBUGMSG extern unsigned int rtw89_debug_mask; -#define rtw89_debug(rtwdev, a...) __rtw89_debug(rtwdev, ##a) __printf(3, 4) -void __rtw89_debug(struct rtw89_dev *rtwdev, - enum rtw89_debug_mask mask, - const char *fmt, ...); +void rtw89_debug(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask, + const char *fmt, ...); static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask, const char *prefix_str, @@ -73,6 +73,12 @@ static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev, print_hex_dump_bytes(prefix_str, DUMP_PREFIX_OFFSET, buf, len); } + +static inline bool rtw89_debug_is_enabled(struct rtw89_dev *rtwdev, + enum rtw89_debug_mask mask) +{ + return !!(rtw89_debug_mask & mask); +} #else static inline void rtw89_debug(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask, @@ -81,6 +87,11 @@ static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask, const char *prefix_str, const void *buf, size_t len) {} +static inline bool rtw89_debug_is_enabled(struct rtw89_dev *rtwdev, + enum rtw89_debug_mask mask) +{ + return false; +} #endif #endif diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c index 2aaf4d013e..e1236079a8 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.c +++ b/drivers/net/wireless/realtek/rtw89/efuse.c @@ -114,6 +114,11 @@ static int rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev *rtwdev, u8 *map, return 0; } +int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle) +{ + return 0; +} + static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map, u32 dump_addr, u32 dump_size) { @@ -231,7 +236,7 @@ static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map, return 0; } -int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev) +int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev) { u32 phy_size = rtwdev->chip->physical_efuse_size; u32 log_size = rtwdev->chip->logical_efuse_size; @@ -286,7 +291,7 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev) rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, full_log_size); - ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map); + ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, RTW89_EFUSE_BLOCK_IGNORE); if (ret) { rtw89_warn(rtwdev, "failed to read efuse map\n"); goto out_free; @@ -300,7 +305,7 @@ out_free: return ret; } -int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev) +int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev) { u32 phycap_addr = rtwdev->chip->phycap_addr; u32 phycap_size = rtwdev->chip->phycap_size; diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h index 79071aff28..5c6787179b 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.h +++ b/drivers/net/wireless/realtek/rtw89/efuse.h @@ -7,8 +7,21 @@ #include "core.h" -int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev); -int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev); +#define RTW89_EFUSE_BLOCK_ID_MASK GENMASK(31, 16) +#define RTW89_EFUSE_BLOCK_SIZE_MASK GENMASK(15, 0) +#define RTW89_EFUSE_MAX_BLOCK_SIZE 0x10000 + +struct rtw89_efuse_block_cfg { + u32 offset; + u32 size; +}; + +int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev); +int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev); +int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle); +int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev); +int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev); +int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle); int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv); #endif diff --git a/drivers/net/wireless/realtek/rtw89/efuse_be.c b/drivers/net/wireless/realtek/rtw89/efuse_be.c new file mode 100644 index 0000000000..8e8b7cd315 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/efuse_be.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include "debug.h" +#include "efuse.h" +#include "mac.h" +#include "reg.h" + +static void rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; + bool aphy_patch = true; + + if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) + aphy_patch = false; + + rtw89_write8_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK); + + if (aphy_patch) { + rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S); + mdelay(1); + rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B); + rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE); + } + + rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST); +} + +static void rtw89_disable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; + bool aphy_patch = true; + + if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) + aphy_patch = false; + + if (aphy_patch) { + rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE); + rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B); + mdelay(1); + rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S); + } + + rtw89_write8_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK); + rtw89_write32_clr(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST); +} + +static int rtw89_dump_physical_efuse_map_ddv_be(struct rtw89_dev *rtwdev, u8 *map, + u32 dump_addr, u32 dump_size) +{ + u32 efuse_ctl; + u32 addr; + u32 data; + int ret; + + if (!IS_ALIGNED(dump_addr, 4) || !IS_ALIGNED(dump_size, 4)) { + rtw89_err(rtwdev, "Efuse addr 0x%x or size 0x%x not aligned\n", + dump_addr, dump_size); + return -EINVAL; + } + + rtw89_enable_efuse_pwr_cut_ddv_be(rtwdev); + + for (addr = dump_addr; addr < dump_addr + dump_size; addr += 4, map += 4) { + efuse_ctl = u32_encode_bits(addr, B_BE_EF_ADDR_MASK); + rtw89_write32(rtwdev, R_BE_EFUSE_CTRL, efuse_ctl & ~B_BE_EF_RDY); + + ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl, + efuse_ctl & B_BE_EF_RDY, 1, 1000000, + true, rtwdev, R_BE_EFUSE_CTRL); + if (ret) + return -EBUSY; + + data = rtw89_read32(rtwdev, R_BE_EFUSE_CTRL_1_V1); + *((__le32 *)map) = cpu_to_le32(data); + } + + rtw89_disable_efuse_pwr_cut_ddv_be(rtwdev); + + return 0; +} + +static int rtw89_dump_physical_efuse_map_dav_be(struct rtw89_dev *rtwdev, u8 *map, + u32 dump_addr, u32 dump_size) +{ + u32 addr; + u8 val8; + int err; + int ret; + + for (addr = dump_addr; addr < dump_addr + dump_size; addr++) { + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40, + FULL_BIT_MASK); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR, addr & 0xff, + XTAL_SI_LOW_ADDR_MASK); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8, + XTAL_SI_HIGH_ADDR_MASK); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0, + XTAL_SI_MODE_SEL_MASK); + if (ret) + return ret; + + ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err, + !err && (val8 & XTAL_SI_RDY), + 1, 10000, false, + rtwdev, XTAL_SI_CTRL, &val8); + if (ret) { + rtw89_warn(rtwdev, "failed to read dav efuse\n"); + return ret; + } + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8); + if (ret) + return ret; + *map++ = val8; + } + + return 0; +} + +int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle) +{ + u32 val; + int ret = 0; + + if (idle) { + rtw89_write32_set(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN); + } else { + rtw89_write32_clr(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val, + val == MAC_AX_SYS_ACT, 50, 5000, + false, rtwdev, R_BE_IC_PWR_STATE, + B_BE_WHOLE_SYS_PWR_STE_MASK); + if (ret) + rtw89_warn(rtwdev, "failed to convert efuse state\n"); + } + + return ret; +} + +static int rtw89_dump_physical_efuse_map_be(struct rtw89_dev *rtwdev, u8 *map, + u32 dump_addr, u32 dump_size, bool dav) +{ + int ret; + + if (!map || dump_size == 0) + return 0; + + rtw89_cnv_efuse_state_be(rtwdev, false); + + if (dav) { + ret = rtw89_dump_physical_efuse_map_dav_be(rtwdev, map, + dump_addr, dump_size); + if (ret) + return ret; + + rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map dav: ", map, dump_size); + } else { + ret = rtw89_dump_physical_efuse_map_ddv_be(rtwdev, map, + dump_addr, dump_size); + if (ret) + return ret; + + rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map ddv: ", map, dump_size); + } + + rtw89_cnv_efuse_state_be(rtwdev, true); + + return 0; +} + +#define EFUSE_HDR_CONST_MASK GENMASK(23, 20) +#define EFUSE_HDR_PAGE_MASK GENMASK(19, 17) +#define EFUSE_HDR_OFFSET_MASK GENMASK(16, 4) +#define EFUSE_HDR_OFFSET_DAV_MASK GENMASK(11, 4) +#define EFUSE_HDR_WORD_EN_MASK GENMASK(3, 0) + +#define invalid_efuse_header_be(hdr1, hdr2, hdr3) \ + ((hdr1) == 0xff || (hdr2) == 0xff || (hdr3) == 0xff) +#define invalid_efuse_content_be(word_en, i) \ + (((word_en) & BIT(i)) != 0x0) +#define get_efuse_blk_idx_be(hdr1, hdr2, hdr3) \ + (((hdr1) << 16) | ((hdr2) << 8) | (hdr3)) +#define block_idx_to_logical_idx_be(blk_idx, i) \ + (((blk_idx) << 3) + ((i) << 1)) + +#define invalid_efuse_header_dav_be(hdr1, hdr2) \ + ((hdr1) == 0xff || (hdr2) == 0xff) +#define get_efuse_blk_idx_dav_be(hdr1, hdr2) \ + (((hdr1) << 8) | (hdr2)) + +static int rtw89_eeprom_parser_be(struct rtw89_dev *rtwdev, + const u8 *phy_map, u32 phy_size, u8 *log_map, + const struct rtw89_efuse_block_cfg *efuse_block) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + enum rtw89_efuse_block blk_page, page; + u32 size = efuse_block->size; + u32 phy_idx, log_idx; + u32 hdr, page_offset; + u8 hdr1, hdr2, hdr3; + u8 i, val0, val1; + u32 min, max; + u16 blk_idx; + u8 word_en; + + page = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_ID_MASK); + page_offset = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_SIZE_MASK); + + min = ALIGN_DOWN(page_offset, 2); + max = ALIGN(page_offset + size, 2); + + memset(log_map, 0xff, size); + + phy_idx = chip->sec_ctrl_efuse_size; + + do { + if (page == RTW89_EFUSE_BLOCK_ADIE) { + hdr1 = phy_map[phy_idx]; + hdr2 = phy_map[phy_idx + 1]; + if (invalid_efuse_header_dav_be(hdr1, hdr2)) + break; + + phy_idx += 2; + + hdr = get_efuse_blk_idx_dav_be(hdr1, hdr2); + + blk_page = RTW89_EFUSE_BLOCK_ADIE; + blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_DAV_MASK); + word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK); + } else { + hdr1 = phy_map[phy_idx]; + hdr2 = phy_map[phy_idx + 1]; + hdr3 = phy_map[phy_idx + 2]; + if (invalid_efuse_header_be(hdr1, hdr2, hdr3)) + break; + + phy_idx += 3; + + hdr = get_efuse_blk_idx_be(hdr1, hdr2, hdr3); + + blk_page = u32_get_bits(hdr, EFUSE_HDR_PAGE_MASK); + blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_MASK); + word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK); + } + + if (blk_idx >= RTW89_EFUSE_MAX_BLOCK_SIZE >> 3) { + rtw89_err(rtwdev, "[ERR]efuse idx:0x%X\n", phy_idx - 3); + rtw89_err(rtwdev, "[ERR]read hdr:0x%X\n", hdr); + return -EINVAL; + } + + for (i = 0; i < 4; i++) { + if (invalid_efuse_content_be(word_en, i)) + continue; + + if (phy_idx >= phy_size - 1) + return -EINVAL; + + log_idx = block_idx_to_logical_idx_be(blk_idx, i); + + if (blk_page == page && log_idx >= min && log_idx < max) { + val0 = phy_map[phy_idx]; + val1 = phy_map[phy_idx + 1]; + + if (log_idx == min && page_offset > min) { + log_map[log_idx - page_offset + 1] = val1; + } else if (log_idx + 2 == max && + page_offset + size < max) { + log_map[log_idx - page_offset] = val0; + } else { + log_map[log_idx - page_offset] = val0; + log_map[log_idx - page_offset + 1] = val1; + } + } + phy_idx += 2; + } + } while (phy_idx < phy_size); + + return 0; +} + +static int rtw89_parse_logical_efuse_block_be(struct rtw89_dev *rtwdev, + const u8 *phy_map, u32 phy_size, + enum rtw89_efuse_block block) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_efuse_block_cfg *efuse_block; + u8 *log_map; + int ret; + + efuse_block = &chip->efuse_blocks[block]; + + log_map = kmalloc(efuse_block->size, GFP_KERNEL); + if (!log_map) + return -ENOMEM; + + ret = rtw89_eeprom_parser_be(rtwdev, phy_map, phy_size, log_map, efuse_block); + if (ret) { + rtw89_warn(rtwdev, "failed to dump efuse logical block %d\n", block); + goto out_free; + } + + rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, efuse_block->size); + + ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, block); + if (ret) { + rtw89_warn(rtwdev, "failed to read efuse map\n"); + goto out_free; + } + +out_free: + kfree(log_map); + + return ret; +} + +int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev) +{ + u32 phy_size = rtwdev->chip->physical_efuse_size; + u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size; + enum rtw89_efuse_block block; + u8 *phy_map = NULL; + u8 *dav_phy_map = NULL; + int ret; + + if (rtw89_read16(rtwdev, R_BE_SYS_WL_EFUSE_CTRL) & B_BE_AUTOLOAD_SUS) + rtwdev->efuse.valid = true; + else + rtw89_warn(rtwdev, "failed to check efuse autoload\n"); + + phy_map = kmalloc(phy_size, GFP_KERNEL); + if (dav_phy_size) + dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL); + + if (!phy_map || (dav_phy_size && !dav_phy_map)) { + ret = -ENOMEM; + goto out_free; + } + + ret = rtw89_dump_physical_efuse_map_be(rtwdev, phy_map, 0, phy_size, false); + if (ret) { + rtw89_warn(rtwdev, "failed to dump efuse physical map\n"); + goto out_free; + } + ret = rtw89_dump_physical_efuse_map_be(rtwdev, dav_phy_map, 0, dav_phy_size, true); + if (ret) { + rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n"); + goto out_free; + } + + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + block = RTW89_EFUSE_BLOCK_HCI_DIG_USB; + else + block = RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO; + + ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, block); + if (ret) { + rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n", + RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO); + goto out_free; + } + + ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, + RTW89_EFUSE_BLOCK_RF); + if (ret) { + rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n", + RTW89_EFUSE_BLOCK_RF); + goto out_free; + } + +out_free: + kfree(dav_phy_map); + kfree(phy_map); + + return ret; +} + +int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev) +{ + u32 phycap_addr = rtwdev->chip->phycap_addr; + u32 phycap_size = rtwdev->chip->phycap_size; + u8 *phycap_map = NULL; + int ret = 0; + + if (!phycap_size) + return 0; + + phycap_map = kmalloc(phycap_size, GFP_KERNEL); + if (!phycap_map) + return -ENOMEM; + + ret = rtw89_dump_physical_efuse_map_be(rtwdev, phycap_map, + phycap_addr, phycap_size, false); + if (ret) { + rtw89_warn(rtwdev, "failed to dump phycap map\n"); + goto out_free; + } + + ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map); + if (ret) { + rtw89_warn(rtwdev, "failed to read phycap map\n"); + goto out_free; + } + +out_free: + kfree(phycap_map); + + return ret; +} diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 313ed4c454..09684cea97 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -401,10 +401,14 @@ int __rtw89_fw_recognize_from_elm(struct rtw89_dev *rtwdev, const union rtw89_fw_element_arg arg) { enum rtw89_fw_type type = arg.fw_type; + struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_fw_suit *fw_suit; + if (hal->cv != elm->u.bbmcu.cv) + return 1; /* ignore this element */ + fw_suit = rtw89_fw_suit_get(rtwdev, type); - fw_suit->data = elm->u.common.contents; + fw_suit->data = elm->u.bbmcu.contents; fw_suit->size = le32_to_cpu(elm->size); return rtw89_fw_update_ver(rtwdev, type, fw_suit); @@ -453,6 +457,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -658,6 +663,97 @@ setup: return 0; } +static +int rtw89_build_txpwr_trk_tbl_from_elm(struct rtw89_dev *rtwdev, + const struct rtw89_fw_element_hdr *elm, + const union rtw89_fw_element_arg arg) +{ + struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 needed_bitmap = 0; + u32 offset = 0; + int subband; + u32 bitmap; + int type; + + if (chip->support_bands & BIT(NL80211_BAND_6GHZ)) + needed_bitmap |= RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_6GHZ; + if (chip->support_bands & BIT(NL80211_BAND_5GHZ)) + needed_bitmap |= RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_5GHZ; + if (chip->support_bands & BIT(NL80211_BAND_2GHZ)) + needed_bitmap |= RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_2GHZ; + + bitmap = le32_to_cpu(elm->u.txpwr_trk.bitmap); + + if ((bitmap & needed_bitmap) != needed_bitmap) { + rtw89_warn(rtwdev, "needed txpwr trk bitmap %08x but %0x8x\n", + needed_bitmap, bitmap); + return -ENOENT; + } + + elm_info->txpwr_trk = kzalloc(sizeof(*elm_info->txpwr_trk), GFP_KERNEL); + if (!elm_info->txpwr_trk) + return -ENOMEM; + + for (type = 0; bitmap; type++, bitmap >>= 1) { + if (!(bitmap & BIT(0))) + continue; + + if (type >= __RTW89_FW_TXPWR_TRK_TYPE_6GHZ_START && + type <= __RTW89_FW_TXPWR_TRK_TYPE_6GHZ_MAX) + subband = 4; + else if (type >= __RTW89_FW_TXPWR_TRK_TYPE_5GHZ_START && + type <= __RTW89_FW_TXPWR_TRK_TYPE_5GHZ_MAX) + subband = 3; + else if (type >= __RTW89_FW_TXPWR_TRK_TYPE_2GHZ_START && + type <= __RTW89_FW_TXPWR_TRK_TYPE_2GHZ_MAX) + subband = 1; + else + break; + + elm_info->txpwr_trk->delta[type] = &elm->u.txpwr_trk.contents[offset]; + + offset += subband; + if (offset * DELTA_SWINGIDX_SIZE > le32_to_cpu(elm->size)) + goto err; + } + + return 0; + +err: + rtw89_warn(rtwdev, "unexpected txpwr trk offset %d over size %d\n", + offset, le32_to_cpu(elm->size)); + kfree(elm_info->txpwr_trk); + elm_info->txpwr_trk = NULL; + + return -EFAULT; +} + +static +int rtw89_build_rfk_log_fmt_from_elm(struct rtw89_dev *rtwdev, + const struct rtw89_fw_element_hdr *elm, + const union rtw89_fw_element_arg arg) +{ + struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; + u8 rfk_id; + + if (elm_info->rfk_log_fmt) + goto allocated; + + elm_info->rfk_log_fmt = kzalloc(sizeof(*elm_info->rfk_log_fmt), GFP_KERNEL); + if (!elm_info->rfk_log_fmt) + return 1; /* this is an optional element, so just ignore this */ + +allocated: + rfk_id = elm->u.rfk_log_fmt.rfk_id; + if (rfk_id >= RTW89_PHY_C2H_RFK_LOG_FUNC_NUM) + return 1; + + elm_info->rfk_log_fmt->elm[rfk_id] = elm; + + return 0; +} + static const struct rtw89_fw_element_handler __fw_element_handlers[] = { [RTW89_FW_ELEMENT_ID_BBMCU0] = {__rtw89_fw_recognize_from_elm, { .fw_type = RTW89_FW_BBMCU0 }, NULL}, @@ -710,6 +806,12 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = { rtw89_fw_recognize_txpwr_from_elm, { .offset = offsetof(struct rtw89_rfe_data, tx_shape_lmt_ru.conf) }, NULL, }, + [RTW89_FW_ELEMENT_ID_TXPWR_TRK] = { + rtw89_build_txpwr_trk_tbl_from_elm, {}, "PWR_TRK", + }, + [RTW89_FW_ELEMENT_ID_RFKLOG_FMT] = { + rtw89_build_rfk_log_fmt_from_elm, {}, NULL, + }, }; int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev) @@ -750,6 +852,8 @@ int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev) goto next; ret = handler->fn(rtwdev, hdr, handler->arg); + if (ret == 1) /* ignore this element */ + goto next; if (ret) return ret; @@ -956,16 +1060,24 @@ static int rtw89_fw_download_main(struct rtw89_dev *rtwdev, static void rtw89_fw_prog_cnt_dump(struct rtw89_dev *rtwdev) { + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + u32 addr = R_AX_DBG_PORT_SEL; u32 val32; u16 index; + if (chip_gen == RTW89_CHIP_BE) { + addr = R_BE_WLCPU_PORT_PC; + goto dump; + } + rtw89_write32(rtwdev, R_AX_DBG_CTRL, FIELD_PREP(B_AX_DBG_SEL0, FW_PROG_CNTR_DBG_SEL) | FIELD_PREP(B_AX_DBG_SEL1, FW_PROG_CNTR_DBG_SEL)); rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, B_AX_SEL_0XC0_MASK, MAC_DBG_SEL); +dump: for (index = 0; index < 15; index++) { - val32 = rtw89_read32(rtwdev, R_AX_DBG_PORT_SEL); + val32 = rtw89_read32(rtwdev, addr); rtw89_err(rtwdev, "[ERR]fw PC = 0x%x\n", val32); fsleep(10); } @@ -1135,6 +1247,9 @@ static void rtw89_unload_firmware_elements(struct rtw89_dev *rtwdev) for (i = 0; i < ARRAY_SIZE(elm_info->rf_radio); i++) rtw89_free_phy_tbl_from_elm(elm_info->rf_radio[i]); rtw89_free_phy_tbl_from_elm(elm_info->rf_nctl); + + kfree(elm_info->txpwr_trk); + kfree(elm_info->rfk_log_fmt); } void rtw89_unload_firmware(struct rtw89_dev *rtwdev) @@ -2215,6 +2330,41 @@ fail: return ret; } +int rtw89_fw_h2c_notify_dbcc(struct rtw89_dev *rtwdev, bool en) +{ + struct rtw89_h2c_notify_dbcc *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c notify dbcc\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_notify_dbcc *)skb->data; + + h2c->w0 = le32_encode_bits(en, RTW89_H2C_NOTIFY_DBCC_EN); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT, + H2C_FUNC_NOTIFY_DBCC, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp, bool pause) { @@ -3451,6 +3601,8 @@ static bool rtw89_fw_c2h_chk_atomic(struct rtw89_dev *rtwdev, return false; case RTW89_C2H_CAT_MAC: return rtw89_mac_c2h_chk_atomic(rtwdev, class, func); + case RTW89_C2H_CAT_OUTSRC: + return rtw89_phy_c2h_chk_atomic(rtwdev, class, func); } } @@ -3867,6 +4019,8 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, if (info->channel_6ghz && ch_info->pri_ch != info->channel_6ghz) continue; + else if (info->channel_6ghz && probe_count != 0) + ch_info->period += RTW89_CHANNEL_TIME_6G; ch_info->pkt_id[probe_count++] = info->id; if (probe_count >= RTW89_SCANOFLD_MAX_SSID) break; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index d4db9ab0b5..01016588b1 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1685,6 +1685,12 @@ static inline void SET_JOININFO_SELF_ROLE(void *h2c, u32 val) le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 30)); } +struct rtw89_h2c_notify_dbcc { + __le32 w0; +} __packed; + +#define RTW89_H2C_NOTIFY_DBCC_EN BIT(0) + static inline void SET_GENERAL_PKT_MACID(void *h2c, u32 val) { le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); @@ -3426,6 +3432,8 @@ enum rtw89_fw_element_id { RTW89_FW_ELEMENT_ID_TXPWR_LMT_RU_6GHZ = 15, RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT = 16, RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT_RU = 17, + RTW89_FW_ELEMENT_ID_TXPWR_TRK = 18, + RTW89_FW_ELEMENT_ID_RFKLOG_FMT = 19, RTW89_FW_ELEMENT_ID_NUM, }; @@ -3446,6 +3454,7 @@ enum rtw89_fw_element_id { BIT(RTW89_FW_ELEMENT_ID_RADIO_A) | \ BIT(RTW89_FW_ELEMENT_ID_RADIO_B) | \ BIT(RTW89_FW_ELEMENT_ID_RF_NCTL) | \ + BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \ BITS_OF_RTW89_TXPWR_FW_ELEMENTS) struct __rtw89_fw_txpwr_element { @@ -3457,6 +3466,59 @@ struct __rtw89_fw_txpwr_element { u8 content[]; } __packed; +enum rtw89_fw_txpwr_trk_type { + __RTW89_FW_TXPWR_TRK_TYPE_6GHZ_START = 0, + RTW89_FW_TXPWR_TRK_TYPE_6GB_N = 0, + RTW89_FW_TXPWR_TRK_TYPE_6GB_P = 1, + RTW89_FW_TXPWR_TRK_TYPE_6GA_N = 2, + RTW89_FW_TXPWR_TRK_TYPE_6GA_P = 3, + __RTW89_FW_TXPWR_TRK_TYPE_6GHZ_MAX = 3, + + __RTW89_FW_TXPWR_TRK_TYPE_5GHZ_START = 4, + RTW89_FW_TXPWR_TRK_TYPE_5GB_N = 4, + RTW89_FW_TXPWR_TRK_TYPE_5GB_P = 5, + RTW89_FW_TXPWR_TRK_TYPE_5GA_N = 6, + RTW89_FW_TXPWR_TRK_TYPE_5GA_P = 7, + __RTW89_FW_TXPWR_TRK_TYPE_5GHZ_MAX = 7, + + __RTW89_FW_TXPWR_TRK_TYPE_2GHZ_START = 8, + RTW89_FW_TXPWR_TRK_TYPE_2GB_N = 8, + RTW89_FW_TXPWR_TRK_TYPE_2GB_P = 9, + RTW89_FW_TXPWR_TRK_TYPE_2GA_N = 10, + RTW89_FW_TXPWR_TRK_TYPE_2GA_P = 11, + RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_B_N = 12, + RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_B_P = 13, + RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_N = 14, + RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_P = 15, + __RTW89_FW_TXPWR_TRK_TYPE_2GHZ_MAX = 15, + + RTW89_FW_TXPWR_TRK_TYPE_NR, +}; + +struct rtw89_fw_txpwr_track_cfg { + const s8 (*delta[RTW89_FW_TXPWR_TRK_TYPE_NR])[DELTA_SWINGIDX_SIZE]; +}; + +#define RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_6GHZ \ + (BIT(RTW89_FW_TXPWR_TRK_TYPE_6GB_N) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_6GB_P) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_6GA_N) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_6GA_P)) +#define RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_5GHZ \ + (BIT(RTW89_FW_TXPWR_TRK_TYPE_5GB_N) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_5GB_P) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_5GA_N) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_5GA_P)) +#define RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_2GHZ \ + (BIT(RTW89_FW_TXPWR_TRK_TYPE_2GB_N) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_2GB_P) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_2GA_N) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_2GA_P) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_B_N) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_B_P) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_N) | \ + BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_P)) + struct rtw89_fw_element_hdr { __le32 id; /* enum rtw89_fw_element_id */ __le32 size; /* exclude header size */ @@ -3477,6 +3539,23 @@ struct rtw89_fw_element_hdr { __le32 data; } __packed regs[]; } __packed reg2; + struct { + u8 cv; + u8 priv[7]; + u8 contents[]; + } __packed bbmcu; + struct { + __le32 bitmap; /* bitmap of enum rtw89_fw_txpwr_trk_type */ + __le32 rsvd; + s8 contents[][DELTA_SWINGIDX_SIZE]; + } __packed txpwr_trk; + struct { + u8 nr; + u8 rsvd[3]; + u8 rfk_id; /* enum rtw89_phy_c2h_rfk_log_func */ + u8 rsvd1[3]; + __le16 offset[]; + } __packed rfk_log_fmt; struct __rtw89_fw_txpwr_element txpwr; } __packed u; } __packed; @@ -3577,6 +3656,7 @@ struct rtw89_fw_h2c_rf_reg_info { #define H2C_CL_MAC_MEDIA_RPT 0x8 #define H2C_FUNC_MAC_JOININFO 0x0 #define H2C_FUNC_MAC_FWROLE_MAINTAIN 0x4 +#define H2C_FUNC_NOTIFY_DBCC 0x5 /* CLASS 9 - FW offload */ #define H2C_CL_MAC_FW_OFLD 0x9 @@ -3649,9 +3729,78 @@ struct rtw89_fw_h2c_rf_get_mccch { __le32 current_band_type; } __packed; -#define RTW89_FW_RSVD_PLE_SIZE 0x800 +enum rtw89_rf_log_type { + RTW89_RF_RUN_LOG = 0, + RTW89_RF_RPT_LOG = 1, +}; -#define RTW89_WCPU_BASE_MASK GENMASK(27, 0) +struct rtw89_c2h_rf_log_hdr { + u8 type; /* enum rtw89_rf_log_type */ + __le16 len; + u8 content[]; +} __packed; + +struct rtw89_c2h_rf_run_log { + __le32 fmt_idx; + __le32 arg[4]; +} __packed; + +struct rtw89_c2h_rf_dpk_rpt_log { + u8 ver; + u8 idx[2]; + u8 band[2]; + u8 bw[2]; + u8 ch[2]; + u8 path_ok[2]; + u8 txagc[2]; + u8 ther[2]; + u8 gs[2]; + u8 dc_i[4]; + u8 dc_q[4]; + u8 corr_val[2]; + u8 corr_idx[2]; + u8 is_timeout[2]; + u8 rxbb_ov[2]; + u8 rsvd; +} __packed; + +struct rtw89_c2h_rf_dack_rpt_log { + u8 fwdack_ver; + u8 fwdack_rpt_ver; + u8 msbk_d[2][2][16]; + u8 dadck_d[2][2]; + u8 cdack_d[2][2][2]; + __le16 addck2_d[2][2][2]; + u8 adgaink_d[2][2]; + __le16 biask_d[2][2]; + u8 addck_timeout; + u8 cdack_timeout; + u8 dadck_timeout; + u8 msbk_timeout; + u8 adgaink_timeout; + u8 dack_fail; +} __packed; + +struct rtw89_c2h_rf_rxdck_rpt_log { + u8 ver; + u8 band[2]; + u8 bw[2]; + u8 ch[2]; + u8 timeout[2]; +} __packed; + +struct rtw89_c2h_rf_txgapk_rpt_log { + __le32 r0x8010[2]; + __le32 chk_cnt; + u8 track_d[2][17]; + u8 power_d[2][17]; + u8 is_txgapk_ok; + u8 chk_id; + u8 ver; + u8 rsv1; +} __packed; + +#define RTW89_FW_RSVD_PLE_SIZE 0x800 #define RTW89_FW_BACKTRACE_INFO_SIZE 8 #define RTW89_VALID_FW_BACKTRACE_SIZE(_size) \ @@ -3704,6 +3853,7 @@ int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, enum rtw89_upd_mode upd_mode); int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta, bool dis_conn); +int rtw89_fw_h2c_notify_dbcc(struct rtw89_dev *rtwdev, bool en); int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp, bool pause); int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index d0c7de4e80..c485ef2cc3 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5,6 +5,7 @@ #include "cam.h" #include "chan.h" #include "debug.h" +#include "efuse.h" #include "fw.h" #include "mac.h" #include "pci.h" @@ -56,8 +57,8 @@ static u32 rtw89_mac_mem_read(struct rtw89_dev *rtwdev, u32 offset, return rtw89_read32(rtwdev, mac->indir_access_addr); } -int rtw89_mac_check_mac_en(struct rtw89_dev *rtwdev, u8 mac_idx, - enum rtw89_mac_hwmod_sel sel) +static int rtw89_mac_check_mac_en_ax(struct rtw89_dev *rtwdev, u8 mac_idx, + enum rtw89_mac_hwmod_sel sel) { u32 val, r_val; @@ -112,8 +113,7 @@ int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val) return ret; } -static -int dle_dfi_ctrl(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl) +int rtw89_mac_dle_dfi_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl) { u32 ctrl_reg, data_reg, ctrl_data; u32 val; @@ -153,8 +153,8 @@ int dle_dfi_ctrl(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl) return 0; } -static int dle_dfi_quota(struct rtw89_dev *rtwdev, - struct rtw89_mac_dle_dfi_quota *quota) +int rtw89_mac_dle_dfi_quota_cfg(struct rtw89_dev *rtwdev, + struct rtw89_mac_dle_dfi_quota *quota) { struct rtw89_mac_dle_dfi_ctrl ctrl; int ret; @@ -162,9 +162,9 @@ static int dle_dfi_quota(struct rtw89_dev *rtwdev, ctrl.type = quota->dle_type; ctrl.target = DLE_DFI_TYPE_QUOTA; ctrl.addr = quota->qtaid; - ret = dle_dfi_ctrl(rtwdev, &ctrl); + ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl); if (ret) { - rtw89_warn(rtwdev, "[ERR]dle_dfi_ctrl %d\n", ret); + rtw89_warn(rtwdev, "[ERR] dle dfi quota %d\n", ret); return ret; } @@ -173,8 +173,8 @@ static int dle_dfi_quota(struct rtw89_dev *rtwdev, return 0; } -static int dle_dfi_qempty(struct rtw89_dev *rtwdev, - struct rtw89_mac_dle_dfi_qempty *qempty) +int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev, + struct rtw89_mac_dle_dfi_qempty *qempty) { struct rtw89_mac_dle_dfi_ctrl ctrl; u32 ret; @@ -182,9 +182,9 @@ static int dle_dfi_qempty(struct rtw89_dev *rtwdev, ctrl.type = qempty->dle_type; ctrl.target = DLE_DFI_TYPE_QEMPTY; ctrl.addr = qempty->grpsel; - ret = dle_dfi_ctrl(rtwdev, &ctrl); + ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl); if (ret) { - rtw89_warn(rtwdev, "[ERR]dle_dfi_ctrl %d\n", ret); + rtw89_warn(rtwdev, "[ERR] dle dfi qempty %d\n", ret); return ret; } @@ -192,7 +192,7 @@ static int dle_dfi_qempty(struct rtw89_dev *rtwdev, return 0; } -static void dump_err_status_dispatcher(struct rtw89_dev *rtwdev) +static void dump_err_status_dispatcher_ax(struct rtw89_dev *rtwdev) { rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ALWAYS_IMR=0x%08x ", rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); @@ -208,7 +208,7 @@ static void dump_err_status_dispatcher(struct rtw89_dev *rtwdev) rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); } -static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev) +static void rtw89_mac_dump_qta_lost_ax(struct rtw89_dev *rtwdev) { struct rtw89_mac_dle_dfi_qempty qempty; struct rtw89_mac_dle_dfi_quota quota; @@ -219,7 +219,7 @@ static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev) qempty.dle_type = DLE_CTRL_TYPE_PLE; qempty.grpsel = 0; qempty.qempty = ~(u32)0; - ret = dle_dfi_qempty(rtwdev, &qempty); + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); if (ret) rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); else @@ -231,19 +231,19 @@ static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev) ctrl.type = DLE_CTRL_TYPE_PLE; ctrl.target = DLE_DFI_TYPE_QLNKTBL; ctrl.addr = (QLNKTBL_ADDR_INFO_SEL_0 ? QLNKTBL_ADDR_INFO_SEL : 0) | - FIELD_PREP(QLNKTBL_ADDR_TBL_IDX_MASK, i); - ret = dle_dfi_ctrl(rtwdev, &ctrl); + u32_encode_bits(i, QLNKTBL_ADDR_TBL_IDX_MASK); + ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl); if (ret) rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); else - rtw89_info(rtwdev, "qidx%d pktcnt = %ld\n", i, - FIELD_GET(QLNKTBL_DATA_SEL1_PKT_CNT_MASK, - ctrl.out_data)); + rtw89_info(rtwdev, "qidx%d pktcnt = %d\n", i, + u32_get_bits(ctrl.out_data, + QLNKTBL_DATA_SEL1_PKT_CNT_MASK)); } quota.dle_type = DLE_CTRL_TYPE_PLE; quota.qtaid = 6; - ret = dle_dfi_quota(rtwdev, "a); + ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, "a); if (ret) rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); else @@ -251,33 +251,74 @@ static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev) quota.rsv_pgnum, quota.use_pgnum); val = rtw89_read32(rtwdev, R_AX_PLE_QTA6_CFG); - rtw89_info(rtwdev, "[PLE][CMAC0_RX]min_pgnum=0x%lx\n", - FIELD_GET(B_AX_PLE_Q6_MIN_SIZE_MASK, val)); - rtw89_info(rtwdev, "[PLE][CMAC0_RX]max_pgnum=0x%lx\n", - FIELD_GET(B_AX_PLE_Q6_MAX_SIZE_MASK, val)); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]min_pgnum=0x%x\n", + u32_get_bits(val, B_AX_PLE_Q6_MIN_SIZE_MASK)); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]max_pgnum=0x%x\n", + u32_get_bits(val, B_AX_PLE_Q6_MAX_SIZE_MASK)); + val = rtw89_read32(rtwdev, R_AX_RX_FLTR_OPT); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]B_AX_RX_MPDU_MAX_LEN=0x%x\n", + u32_get_bits(val, B_AX_RX_MPDU_MAX_LEN_MASK)); + rtw89_info(rtwdev, "R_AX_RSP_CHK_SIG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RSP_CHK_SIG)); + rtw89_info(rtwdev, "R_AX_TRXPTCL_RESP_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TRXPTCL_RESP_0)); + rtw89_info(rtwdev, "R_AX_CCA_CONTROL=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CCA_CONTROL)); + + if (!rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL)) { + quota.dle_type = DLE_CTRL_TYPE_PLE; + quota.qtaid = 7; + ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, "a); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "quota7 rsv/use: 0x%x/0x%x\n", + quota.rsv_pgnum, quota.use_pgnum); - dump_err_status_dispatcher(rtwdev); + val = rtw89_read32(rtwdev, R_AX_PLE_QTA7_CFG); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]min_pgnum=0x%x\n", + u32_get_bits(val, B_AX_PLE_Q7_MIN_SIZE_MASK)); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]max_pgnum=0x%x\n", + u32_get_bits(val, B_AX_PLE_Q7_MAX_SIZE_MASK)); + val = rtw89_read32(rtwdev, R_AX_RX_FLTR_OPT_C1); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]B_AX_RX_MPDU_MAX_LEN=0x%x\n", + u32_get_bits(val, B_AX_RX_MPDU_MAX_LEN_MASK)); + rtw89_info(rtwdev, "R_AX_RSP_CHK_SIG_C1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RSP_CHK_SIG_C1)); + rtw89_info(rtwdev, "R_AX_TRXPTCL_RESP_0_C1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TRXPTCL_RESP_0_C1)); + rtw89_info(rtwdev, "R_AX_CCA_CONTROL_C1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CCA_CONTROL_C1)); + } + + rtw89_info(rtwdev, "R_AX_DLE_EMPTY0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DLE_EMPTY0)); + rtw89_info(rtwdev, "R_AX_DLE_EMPTY1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DLE_EMPTY1)); + + dump_err_status_dispatcher_ax(rtwdev); } -static void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev, - enum mac_ax_err_info err) +void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 dbg, event; dbg = rtw89_read32(rtwdev, R_AX_SER_DBG_INFO); - event = FIELD_GET(B_AX_L0_TO_L1_EVENT_MASK, dbg); + event = u32_get_bits(dbg, B_AX_L0_TO_L1_EVENT_MASK); switch (event) { case MAC_AX_L0_TO_L1_RX_QTA_LOST: rtw89_info(rtwdev, "quota lost!\n"); - rtw89_mac_dump_qta_lost(rtwdev); + mac->dump_qta_lost(rtwdev); break; default: break; } } -static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) +void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; u32 dmac_err; @@ -357,6 +398,21 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) rtw89_info(rtwdev, "sel=%x,R_AX_SEC_DEBUG2=0x%08x\n", i, rtw89_read32(rtwdev, R_AX_SEC_DEBUG2)); } + } else if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_SEC_ERROR_FLAG=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_ERROR_FLAG)); + rtw89_info(rtwdev, "R_BE_SEC_ERROR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_ERROR_IMR)); + rtw89_info(rtwdev, "R_BE_SEC_ENG_CTRL=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_ENG_CTRL)); + rtw89_info(rtwdev, "R_BE_SEC_MPDU_PROC=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_MPDU_PROC)); + rtw89_info(rtwdev, "R_BE_SEC_CAM_ACCESS=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_CAM_ACCESS)); + rtw89_info(rtwdev, "R_BE_SEC_CAM_RDATA=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_CAM_RDATA)); + rtw89_info(rtwdev, "R_BE_SEC_DEBUG2=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SEC_DEBUG2)); } else { rtw89_info(rtwdev, "R_AX_SEC_ERR_IMR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_SEC_DEBUG)); @@ -393,10 +449,17 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) } if (dmac_err & B_AX_STA_SCHEDULER_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); + if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_INTERRUPT_MASK_REG=0x%08x\n", + rtw89_read32(rtwdev, R_BE_INTERRUPT_MASK_REG)); + rtw89_info(rtwdev, "R_BE_INTERRUPT_STS_REG=0x%08x\n", + rtw89_read32(rtwdev, R_BE_INTERRUPT_STS_REG)); + } else { + rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); + } } if (dmac_err & B_AX_WDE_DLE_ERR_FLAG) { @@ -411,7 +474,7 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) } if (dmac_err & B_AX_TXPKTCTRL_ERR_FLAG) { - if (chip->chip_id == RTL8852C) { + if (chip->chip_id == RTL8852C || chip->chip_id == RTL8922A) { rtw89_info(rtwdev, "R_AX_TXPKTCTL_B0_ERRFLAG_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_IMR)); rtw89_info(rtwdev, "R_AX_TXPKTCTL_B0_ERRFLAG_ISR=0x%08x\n", @@ -443,30 +506,41 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_1)); rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_2=0x%08x\n", rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_2)); - rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_STATUS=0x%08x\n", - rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_STATUS)); rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_0=0x%08x\n", rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_0)); rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_1=0x%08x\n", rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_1)); rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_2=0x%08x\n", rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_2)); - rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n", - rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS)); - if (chip->chip_id == RTL8852C) { - rtw89_info(rtwdev, "R_AX_RX_CTRL0=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RX_CTRL0)); - rtw89_info(rtwdev, "R_AX_RX_CTRL1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RX_CTRL1)); - rtw89_info(rtwdev, "R_AX_RX_CTRL2=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RX_CTRL2)); + if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_WD_CPUQ_OP_3=0x%08x\n", + rtw89_read32(rtwdev, R_BE_WD_CPUQ_OP_3)); + rtw89_info(rtwdev, "R_BE_WD_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_BE_WD_CPUQ_OP_STATUS)); + rtw89_info(rtwdev, "R_BE_PLE_CPUQ_OP_3=0x%08x\n", + rtw89_read32(rtwdev, R_BE_PL_CPUQ_OP_3)); + rtw89_info(rtwdev, "R_BE_PL_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_BE_PL_CPUQ_OP_STATUS)); } else { - rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); - rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); - rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); + rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_STATUS)); + rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS)); + if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_RX_CTRL0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL0)); + rtw89_info(rtwdev, "R_AX_RX_CTRL1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL1)); + rtw89_info(rtwdev, "R_AX_RX_CTRL2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL2)); + } else { + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); + } } } @@ -478,22 +552,37 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) } if (dmac_err & B_AX_DISPATCH_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); - rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); - rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); + if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_DISP_HOST_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_HOST_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR1)); + rtw89_info(rtwdev, "R_BE_DISP_CPU_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_CPU_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR2=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR2)); + rtw89_info(rtwdev, "R_BE_DISP_OTHER_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_OTHER_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR0=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR0)); + } else { + rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); + } } if (dmac_err & B_AX_BBRPT_ERR_FLAG) { - if (chip->chip_id == RTL8852C) { + if (chip->chip_id == RTL8852C || chip->chip_id == RTL8922A) { rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR)); rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_ISR=0x%08x\n", @@ -518,18 +607,54 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR)); } + if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_LA_ERRFLAG_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_LA_ERRFLAG_IMR)); + rtw89_info(rtwdev, "R_BE_LA_ERRFLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_LA_ERRFLAG_ISR)); + } + } + + if (dmac_err & B_AX_HAXIDMA_ERR_FLAG) { + if (chip->chip_id == RTL8922A) { + rtw89_info(rtwdev, "R_BE_HAXI_IDCT_MSK=0x%08x\n", + rtw89_read32(rtwdev, R_BE_HAXI_IDCT_MSK)); + rtw89_info(rtwdev, "R_BE_HAXI_IDCT=0x%08x\n", + rtw89_read32(rtwdev, R_BE_HAXI_IDCT)); + } else if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HAXI_IDCT_MSK)); + rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HAXI_IDCT)); + } + } + + if (dmac_err & B_BE_P_AXIDMA_ERR_INT) { + rtw89_info(rtwdev, "R_BE_PL_AXIDMA_IDCT_MSK=0x%08x\n", + rtw89_mac_mem_read(rtwdev, R_BE_PL_AXIDMA_IDCT_MSK, + RTW89_MAC_MEM_AXIDMA)); + rtw89_info(rtwdev, "R_BE_PL_AXIDMA_IDCT=0x%08x\n", + rtw89_mac_mem_read(rtwdev, R_BE_PL_AXIDMA_IDCT, + RTW89_MAC_MEM_AXIDMA)); } - if (dmac_err & B_AX_HAXIDMA_ERR_FLAG && chip->chip_id == RTL8852C) { - rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_HAXI_IDCT_MSK)); - rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_HAXI_IDCT)); + if (dmac_err & B_BE_MLO_ERR_INT) { + rtw89_info(rtwdev, "R_BE_MLO_ERR_IDCT_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_MLO_ERR_IDCT_IMR)); + rtw89_info(rtwdev, "R_BE_PKTIN_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_MLO_ERR_IDCT_ISR)); + } + + if (dmac_err & B_BE_PLRLS_ERR_INT) { + rtw89_info(rtwdev, "R_BE_PLRLS_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_PLRLS_ERR_IMR)); + rtw89_info(rtwdev, "R_BE_PLRLS_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_BE_PLRLS_ERR_ISR)); } } -static void rtw89_mac_dump_cmac_err_status(struct rtw89_dev *rtwdev, - u8 band) +static void rtw89_mac_dump_cmac_err_status_ax(struct rtw89_dev *rtwdev, + u8 band) { const struct rtw89_chip_info *chip = rtwdev->chip; u32 offset = 0; @@ -619,8 +744,8 @@ static void rtw89_mac_dump_cmac_err_status(struct rtw89_dev *rtwdev, rtw89_read32(rtwdev, R_AX_CMAC_ERR_IMR + offset)); } -static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, - enum mac_ax_err_info err) +static void rtw89_mac_dump_err_status_ax(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err) { if (err != MAC_AX_ERR_L1_ERR_DMAC && err != MAC_AX_ERR_L0_PROMOTE_TO_L1 && @@ -632,11 +757,16 @@ static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, rtw89_info(rtwdev, "--->\nerr=0x%x\n", err); rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n", rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); + rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); + rtw89_info(rtwdev, "DBG Counter 1 (R_AX_DRV_FW_HSK_4)=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DRV_FW_HSK_4)); + rtw89_info(rtwdev, "DBG Counter 2 (R_AX_DRV_FW_HSK_5)=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DRV_FW_HSK_5)); rtw89_mac_dump_dmac_err_status(rtwdev); - rtw89_mac_dump_cmac_err_status(rtwdev, RTW89_MAC_0); - if (rtwdev->dbcc_en) - rtw89_mac_dump_cmac_err_status(rtwdev, RTW89_MAC_1); + rtw89_mac_dump_cmac_err_status_ax(rtwdev, RTW89_MAC_0); + rtw89_mac_dump_cmac_err_status_ax(rtwdev, RTW89_MAC_1); rtwdev->hci.ops->dump_err_status(rtwdev); @@ -681,6 +811,7 @@ static bool rtw89_mac_suppress_log(struct rtw89_dev *rtwdev, u32 err) u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 err, err_scnr; int ret; @@ -706,7 +837,7 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) return err; rtw89_fw_st_dbg_dump(rtwdev); - rtw89_mac_dump_err_status(rtwdev, err); + mac->dump_err_status(rtwdev, err); return err; } @@ -900,7 +1031,7 @@ static int hfc_pub_ctrl(struct rtw89_dev *rtwdev) return 0; } -static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) +static void hfc_get_mix_info_ax(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_page_regs *regs = chip->page_regs; @@ -909,11 +1040,6 @@ static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; struct rtw89_hfc_pub_info *info = ¶m->pub_info; u32 val; - int ret; - - ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); - if (ret) - return ret; val = rtw89_read32(rtwdev, regs->pub_page_info1); info->g0_used = u32_get_bits(val, B_AX_G0_USE_PG_MASK); @@ -958,6 +1084,19 @@ static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) val = rtw89_read32(rtwdev, regs->pub_page_ctrl1); pub_cfg->grp0 = u32_get_bits(val, B_AX_PUBPG_G0_MASK); pub_cfg->grp1 = u32_get_bits(val, B_AX_PUBPG_G1_MASK); +} + +static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); + if (ret) + return ret; + + mac->hfc_get_mix_info(rtwdev); ret = hfc_pub_info_chk(rtwdev); if (param->en && ret) @@ -966,7 +1105,7 @@ static int hfc_upd_mix_info(struct rtw89_dev *rtwdev) return 0; } -static void hfc_h2c_cfg(struct rtw89_dev *rtwdev) +static void hfc_h2c_cfg_ax(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_page_regs *regs = chip->page_regs; @@ -982,7 +1121,7 @@ static void hfc_h2c_cfg(struct rtw89_dev *rtwdev) prec_cfg->h2c_full_cond); } -static void hfc_mix_cfg(struct rtw89_dev *rtwdev) +static void hfc_mix_cfg_ax(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_page_regs *regs = chip->page_regs; @@ -1017,7 +1156,7 @@ static void hfc_mix_cfg(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, regs->hci_fc_ctrl, val); } -static void hfc_func_en(struct rtw89_dev *rtwdev, bool en, bool h2c_en) +static void hfc_func_en_ax(struct rtw89_dev *rtwdev, bool en, bool h2c_en) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_page_regs *regs = chip->page_regs; @@ -1033,8 +1172,9 @@ static void hfc_func_en(struct rtw89_dev *rtwdev, bool en, bool h2c_en) rtw89_write32(rtwdev, regs->hci_fc_ctrl, val); } -static int hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en) +int rtw89_mac_hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_chip_info *chip = rtwdev->chip; u32 dma_ch_mask = chip->dma_ch_mask; u8 ch; @@ -1049,11 +1189,11 @@ static int hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en) if (ret) return ret; - hfc_func_en(rtwdev, false, false); + mac->hfc_func_en(rtwdev, false, false); if (!en && h2c_en) { - hfc_h2c_cfg(rtwdev); - hfc_func_en(rtwdev, en, h2c_en); + mac->hfc_h2c_cfg(rtwdev); + mac->hfc_func_en(rtwdev, en, h2c_en); return ret; } @@ -1069,9 +1209,9 @@ static int hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en) if (ret) return ret; - hfc_mix_cfg(rtwdev); + mac->hfc_mix_cfg(rtwdev); if (en || h2c_en) { - hfc_func_en(rtwdev, en, h2c_en); + mac->hfc_func_en(rtwdev, en, h2c_en); udelay(10); } for (ch = RTW89_DMA_ACH0; ch < RTW89_DMA_H2C; ch++) { @@ -1333,9 +1473,14 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) if (on) { set_bit(RTW89_FLAG_POWERON, rtwdev->flags); + set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); + set_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); rtw89_write8(rtwdev, R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_TP_MAJOR); } else { clear_bit(RTW89_FLAG_POWERON, rtwdev->flags); + clear_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); + clear_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); + clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags); rtw89_write8(rtwdev, R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_PWR_MAJOR); rtw89_set_entity_state(rtwdev, false); @@ -1350,7 +1495,7 @@ void rtw89_mac_pwr_off(struct rtw89_dev *rtwdev) rtw89_mac_power_switch(rtwdev, false); } -static int cmac_func_en(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) +static int cmac_func_en_ax(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) { u32 func_en = 0; u32 ck_en = 0; @@ -1396,7 +1541,7 @@ static int cmac_func_en(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) return 0; } -static int dmac_func_en(struct rtw89_dev *rtwdev) +static int dmac_func_en_ax(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 val32; @@ -1428,7 +1573,7 @@ static int dmac_func_en(struct rtw89_dev *rtwdev) return 0; } -static int chip_func_en(struct rtw89_dev *rtwdev) +static int chip_func_en_ax(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; @@ -1439,19 +1584,19 @@ static int chip_func_en(struct rtw89_dev *rtwdev) return 0; } -static int rtw89_mac_sys_init(struct rtw89_dev *rtwdev) +static int sys_init_ax(struct rtw89_dev *rtwdev) { int ret; - ret = dmac_func_en(rtwdev); + ret = dmac_func_en_ax(rtwdev); if (ret) return ret; - ret = cmac_func_en(rtwdev, 0, true); + ret = cmac_func_en_ax(rtwdev, 0, true); if (ret) return ret; - ret = chip_func_en(rtwdev); + ret = chip_func_en_ax(rtwdev); if (ret) return ret; @@ -1460,10 +1605,14 @@ static int rtw89_mac_sys_init(struct rtw89_dev *rtwdev) const struct rtw89_mac_size_set rtw89_mac_size = { .hfc_preccfg_pcie = {2, 40, 0, 0, 1, 0, 0, 0}, + .hfc_prec_cfg_c0 = {2, 32, 0, 0, 0, 0, 0, 0}, + .hfc_prec_cfg_c2 = {0, 256, 0, 0, 0, 0, 0, 0}, /* PCIE 64 */ .wde_size0 = {RTW89_WDE_PG_64, 4095, 1,}, + .wde_size0_v1 = {RTW89_WDE_PG_64, 3328, 0, 0,}, /* DLFW */ .wde_size4 = {RTW89_WDE_PG_64, 0, 4096,}, + .wde_size4_v1 = {RTW89_WDE_PG_64, 0, 3328, 0,}, /* PCIE 64 */ .wde_size6 = {RTW89_WDE_PG_64, 512, 0,}, /* 8852B PCIE SCC */ @@ -1476,6 +1625,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_size19 = {RTW89_WDE_PG_64, 3328, 0,}, /* PCIE */ .ple_size0 = {RTW89_PLE_PG_128, 1520, 16,}, + .ple_size0_v1 = {RTW89_PLE_PG_128, 2672, 256, 212992,}, + .ple_size3_v1 = {RTW89_PLE_PG_128, 2928, 0, 212992,}, /* DLFW */ .ple_size4 = {RTW89_PLE_PG_128, 64, 1472,}, /* PCIE 64 */ @@ -1488,6 +1639,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_size19 = {RTW89_PLE_PG_128, 1904, 16,}, /* PCIE 64 */ .wde_qt0 = {3792, 196, 0, 107,}, + .wde_qt0_v1 = {3302, 6, 0, 20,}, /* DLFW */ .wde_qt4 = {0, 0, 0, 0,}, /* PCIE 64 */ @@ -1498,10 +1650,13 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_qt17 = {0, 0, 0, 0,}, /* 8852C PCIE SCC */ .wde_qt18 = {3228, 60, 0, 40,}, + .ple_qt0 = {320, 0, 32, 16, 13, 13, 292, 0, 32, 18, 1, 4, 0,}, + .ple_qt1 = {320, 0, 32, 16, 1944, 1944, 2223, 0, 1963, 1949, 1, 1935, 0,}, /* PCIE SCC */ .ple_qt4 = {264, 0, 16, 20, 26, 13, 356, 0, 32, 40, 8,}, /* PCIE SCC */ .ple_qt5 = {264, 0, 32, 20, 64, 13, 1101, 0, 64, 128, 120,}, + .ple_qt9 = {0, 0, 32, 256, 0, 0, 0, 0, 0, 0, 1, 0, 0,}, /* DLFW */ .ple_qt13 = {0, 0, 16, 48, 0, 0, 0, 0, 0, 0, 0,}, /* PCIE 64 */ @@ -1522,6 +1677,10 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt_52b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,}, /* 8851B PCIE WOW */ .ple_qt_51b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,}, + .ple_rsvd_qt0 = {2, 112, 56, 6, 6, 6, 6, 0, 0, 62,}, + .ple_rsvd_qt1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .rsvd0_size0 = {212992, 0,}, + .rsvd1_size0 = {587776, 2048,}, }; EXPORT_SYMBOL(rtw89_mac_size); @@ -1540,7 +1699,9 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, return NULL; } + mac->dle_info.rsvd_qt = cfg->rsvd_qt; mac->dle_info.ple_pg_size = cfg->ple_size->pge_size; + mac->dle_info.ple_free_pg = cfg->ple_size->lnk_pge_num; mac->dle_info.qta_mode = mode; mac->dle_info.c0_rx_qta = cfg->ple_min_qt->cma0_dma; mac->dle_info.c1_rx_qta = cfg->ple_min_qt->cma1_dma; @@ -1548,33 +1709,86 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, return cfg; } -static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) +int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, + enum rtw89_mac_dle_rsvd_qt_type type, + struct rtw89_mac_dle_rsvd_qt_cfg *cfg) +{ + struct rtw89_dle_info *dle_info = &rtwdev->mac.dle_info; + const struct rtw89_rsvd_quota *rsvd_qt = dle_info->rsvd_qt; + + switch (type) { + case DLE_RSVD_QT_MPDU_INFO: + cfg->pktid = dle_info->ple_free_pg; + cfg->pg_num = rsvd_qt->mpdu_info_tbl; + break; + case DLE_RSVD_QT_B0_CSI: + cfg->pktid = dle_info->ple_free_pg + rsvd_qt->mpdu_info_tbl; + cfg->pg_num = rsvd_qt->b0_csi; + break; + case DLE_RSVD_QT_B1_CSI: + cfg->pktid = dle_info->ple_free_pg + + rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi; + cfg->pg_num = rsvd_qt->b1_csi; + break; + case DLE_RSVD_QT_B0_LMR: + cfg->pktid = dle_info->ple_free_pg + + rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi; + cfg->pg_num = rsvd_qt->b0_lmr; + break; + case DLE_RSVD_QT_B1_LMR: + cfg->pktid = dle_info->ple_free_pg + + rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi + + rsvd_qt->b0_lmr; + cfg->pg_num = rsvd_qt->b1_lmr; + break; + case DLE_RSVD_QT_B0_FTM: + cfg->pktid = dle_info->ple_free_pg + + rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi + + rsvd_qt->b0_lmr + rsvd_qt->b1_lmr; + cfg->pg_num = rsvd_qt->b0_ftm; + break; + case DLE_RSVD_QT_B1_FTM: + cfg->pktid = dle_info->ple_free_pg + + rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi + + rsvd_qt->b0_lmr + rsvd_qt->b1_lmr + rsvd_qt->b0_ftm; + cfg->pg_num = rsvd_qt->b1_ftm; + break; + default: + return -EINVAL; + } + + cfg->size = (u32)cfg->pg_num * dle_info->ple_pg_size; + + return 0; +} + +static bool mac_is_txq_empty_ax(struct rtw89_dev *rtwdev) { struct rtw89_mac_dle_dfi_qempty qempty; - u32 qnum, qtmp, val32, msk32; + u32 grpnum, qtmp, val32, msk32; int i, j, ret; - qnum = rtwdev->chip->wde_qempty_acq_num; + grpnum = rtwdev->chip->wde_qempty_acq_grpnum; qempty.dle_type = DLE_CTRL_TYPE_WDE; - for (i = 0; i < qnum; i++) { + for (i = 0; i < grpnum; i++) { qempty.grpsel = i; - ret = dle_dfi_qempty(rtwdev, &qempty); + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); if (ret) { rtw89_warn(rtwdev, "dle dfi acq empty %d\n", ret); return false; } qtmp = qempty.qempty; for (j = 0 ; j < QEMP_ACQ_GRP_MACID_NUM; j++) { - val32 = FIELD_GET(QEMP_ACQ_GRP_QSEL_MASK, qtmp); + val32 = u32_get_bits(qtmp, QEMP_ACQ_GRP_QSEL_MASK); if (val32 != QEMP_ACQ_GRP_QSEL_MASK) return false; qtmp >>= QEMP_ACQ_GRP_QSEL_SH; } } - qempty.grpsel = rtwdev->chip->wde_qempty_mgq_sel; - ret = dle_dfi_qempty(rtwdev, &qempty); + qempty.grpsel = rtwdev->chip->wde_qempty_mgq_grpsel; + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); if (ret) { rtw89_warn(rtwdev, "dle dfi mgq empty %d\n", ret); return false; @@ -1602,11 +1816,21 @@ static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) return (val32 & msk32) == msk32; } -static inline u32 dle_used_size(const struct rtw89_dle_size *wde, - const struct rtw89_dle_size *ple) +static inline u32 dle_used_size(const struct rtw89_dle_mem *cfg) { - return wde->pge_size * (wde->lnk_pge_num + wde->unlnk_pge_num) + + const struct rtw89_dle_size *wde = cfg->wde_size; + const struct rtw89_dle_size *ple = cfg->ple_size; + u32 used; + + used = wde->pge_size * (wde->lnk_pge_num + wde->unlnk_pge_num) + ple->pge_size * (ple->lnk_pge_num + ple->unlnk_pge_num); + + if (cfg->rsvd0_size && cfg->rsvd1_size) { + used += cfg->rsvd0_size->size; + used += cfg->rsvd1_size->size; + } + + return used; } static u32 dle_expected_used_size(struct rtw89_dev *rtwdev, @@ -1620,7 +1844,7 @@ static u32 dle_expected_used_size(struct rtw89_dev *rtwdev, return size; } -static void dle_func_en(struct rtw89_dev *rtwdev, bool enable) +static void dle_func_en_ax(struct rtw89_dev *rtwdev, bool enable) { if (enable) rtw89_write32_set(rtwdev, R_AX_DMAC_FUNC_EN, @@ -1630,7 +1854,7 @@ static void dle_func_en(struct rtw89_dev *rtwdev, bool enable) B_AX_DLE_WDE_EN | B_AX_DLE_PLE_EN); } -static void dle_clk_en(struct rtw89_dev *rtwdev, bool enable) +static void dle_clk_en_ax(struct rtw89_dev *rtwdev, bool enable) { u32 val = B_AX_DLE_WDE_CLK_EN | B_AX_DLE_PLE_CLK_EN; @@ -1643,7 +1867,7 @@ static void dle_clk_en(struct rtw89_dev *rtwdev, bool enable) } } -static int dle_mix_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg) +static int dle_mix_cfg_ax(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg) { const struct rtw89_dle_size *size_cfg; u32 val; @@ -1700,6 +1924,23 @@ static int dle_mix_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg return 0; } +static int chk_dle_rdy_ax(struct rtw89_dev *rtwdev, bool wde_or_ple) +{ + u32 reg, mask; + u32 ini; + + if (wde_or_ple) { + reg = R_AX_WDE_INI_STATUS; + mask = WDE_MGN_INI_RDY; + } else { + reg = R_AX_PLE_INI_STATUS; + mask = PLE_MGN_INI_RDY; + } + + return read_poll_timeout(rtw89_read32, ini, (ini & mask) == mask, 1, + 2000, false, rtwdev, reg); +} + #define INVALID_QT_WCPU U16_MAX #define SET_QUOTA_VAL(_min_x, _max_x, _module, _idx) \ do { \ @@ -1712,10 +1953,10 @@ static int dle_mix_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg #define SET_QUOTA(_x, _module, _idx) \ SET_QUOTA_VAL(min_cfg->_x, max_cfg->_x, _module, _idx) -static void wde_quota_cfg(struct rtw89_dev *rtwdev, - const struct rtw89_wde_quota *min_cfg, - const struct rtw89_wde_quota *max_cfg, - u16 ext_wde_min_qt_wcpu) +static void wde_quota_cfg_ax(struct rtw89_dev *rtwdev, + const struct rtw89_wde_quota *min_cfg, + const struct rtw89_wde_quota *max_cfg, + u16 ext_wde_min_qt_wcpu) { u16 min_qt_wcpu = ext_wde_min_qt_wcpu != INVALID_QT_WCPU ? ext_wde_min_qt_wcpu : min_cfg->wcpu; @@ -1727,9 +1968,9 @@ static void wde_quota_cfg(struct rtw89_dev *rtwdev, SET_QUOTA(cpu_io, WDE, 4); } -static void ple_quota_cfg(struct rtw89_dev *rtwdev, - const struct rtw89_ple_quota *min_cfg, - const struct rtw89_ple_quota *max_cfg) +static void ple_quota_cfg_ax(struct rtw89_dev *rtwdev, + const struct rtw89_ple_quota *min_cfg, + const struct rtw89_ple_quota *max_cfg) { u32 val; @@ -1794,17 +2035,19 @@ static void dle_quota_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg, u16 ext_wde_min_qt_wcpu) { - wde_quota_cfg(rtwdev, cfg->wde_min_qt, cfg->wde_max_qt, ext_wde_min_qt_wcpu); - ple_quota_cfg(rtwdev, cfg->ple_min_qt, cfg->ple_max_qt); + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + mac->wde_quota_cfg(rtwdev, cfg->wde_min_qt, cfg->wde_max_qt, ext_wde_min_qt_wcpu); + mac->ple_quota_cfg(rtwdev, cfg->ple_min_qt, cfg->ple_max_qt); } -static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, - enum rtw89_qta_mode ext_mode) +int rtw89_mac_dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, + enum rtw89_qta_mode ext_mode) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_dle_mem *cfg, *ext_cfg; u16 ext_wde_min_qt_wcpu = INVALID_QT_WCPU; - int ret = 0; - u32 ini; + int ret; ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); if (ret) @@ -1828,36 +2071,31 @@ static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, ext_wde_min_qt_wcpu = ext_cfg->wde_min_qt->wcpu; } - if (dle_used_size(cfg->wde_size, cfg->ple_size) != - dle_expected_used_size(rtwdev, mode)) { + if (dle_used_size(cfg) != dle_expected_used_size(rtwdev, mode)) { rtw89_err(rtwdev, "[ERR]wd/dle mem cfg\n"); ret = -EINVAL; goto error; } - dle_func_en(rtwdev, false); - dle_clk_en(rtwdev, true); + mac->dle_func_en(rtwdev, false); + mac->dle_clk_en(rtwdev, true); - ret = dle_mix_cfg(rtwdev, cfg); + ret = mac->dle_mix_cfg(rtwdev, cfg); if (ret) { rtw89_err(rtwdev, "[ERR] dle mix cfg\n"); goto error; } dle_quota_cfg(rtwdev, cfg, ext_wde_min_qt_wcpu); - dle_func_en(rtwdev, true); + mac->dle_func_en(rtwdev, true); - ret = read_poll_timeout(rtw89_read32, ini, - (ini & WDE_MGN_INI_RDY) == WDE_MGN_INI_RDY, 1, - 2000, false, rtwdev, R_AX_WDE_INI_STATUS); + ret = mac->chk_dle_rdy(rtwdev, true); if (ret) { rtw89_err(rtwdev, "[ERR]WDE cfg ready\n"); return ret; } - ret = read_poll_timeout(rtw89_read32, ini, - (ini & WDE_MGN_INI_RDY) == WDE_MGN_INI_RDY, 1, - 2000, false, rtwdev, R_AX_PLE_INI_STATUS); + ret = mac->chk_dle_rdy(rtwdev, false); if (ret) { rtw89_err(rtwdev, "[ERR]PLE cfg ready\n"); return ret; @@ -1865,7 +2103,7 @@ static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, return 0; error: - dle_func_en(rtwdev, false); + mac->dle_func_en(rtwdev, false); rtw89_err(rtwdev, "[ERR]trxcfg wde 0x8900 = %x\n", rtw89_read32(rtwdev, R_AX_WDE_INI_STATUS)); rtw89_err(rtwdev, "[ERR]trxcfg ple 0x8D00 = %x\n", @@ -1900,8 +2138,8 @@ static bool is_qta_poh(struct rtw89_dev *rtwdev) return rtwdev->hci.type == RTW89_HCI_TYPE_PCIE; } -static int preload_init(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, - enum rtw89_qta_mode mode) +int rtw89_mac_preload_init(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, + enum rtw89_qta_mode mode) { const struct rtw89_chip_info *chip = rtwdev->chip; @@ -1950,7 +2188,7 @@ static void _patch_ss2f_path(struct rtw89_dev *rtwdev) SS2F_PATH_WLCPU); } -static int sta_sch_init(struct rtw89_dev *rtwdev) +static int sta_sch_init_ax(struct rtw89_dev *rtwdev) { u32 p_val; u8 val; @@ -1979,7 +2217,7 @@ static int sta_sch_init(struct rtw89_dev *rtwdev) return 0; } -static int mpdu_proc_init(struct rtw89_dev *rtwdev) +static int mpdu_proc_init_ax(struct rtw89_dev *rtwdev) { int ret; @@ -1996,7 +2234,7 @@ static int mpdu_proc_init(struct rtw89_dev *rtwdev) return 0; } -static int sec_eng_init(struct rtw89_dev *rtwdev) +static int sec_eng_init_ax(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; u32 val = 0; @@ -2031,41 +2269,41 @@ static int sec_eng_init(struct rtw89_dev *rtwdev) return 0; } -static int dmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int dmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { int ret; - ret = dle_init(rtwdev, rtwdev->mac.qta_mode, RTW89_QTA_INVALID); + ret = rtw89_mac_dle_init(rtwdev, rtwdev->mac.qta_mode, RTW89_QTA_INVALID); if (ret) { rtw89_err(rtwdev, "[ERR]DLE init %d\n", ret); return ret; } - ret = preload_init(rtwdev, RTW89_MAC_0, rtwdev->mac.qta_mode); + ret = rtw89_mac_preload_init(rtwdev, RTW89_MAC_0, rtwdev->mac.qta_mode); if (ret) { rtw89_err(rtwdev, "[ERR]preload init %d\n", ret); return ret; } - ret = hfc_init(rtwdev, true, true, true); + ret = rtw89_mac_hfc_init(rtwdev, true, true, true); if (ret) { rtw89_err(rtwdev, "[ERR]HCI FC init %d\n", ret); return ret; } - ret = sta_sch_init(rtwdev); + ret = sta_sch_init_ax(rtwdev); if (ret) { rtw89_err(rtwdev, "[ERR]STA SCH init %d\n", ret); return ret; } - ret = mpdu_proc_init(rtwdev); + ret = mpdu_proc_init_ax(rtwdev); if (ret) { rtw89_err(rtwdev, "[ERR]MPDU Proc init %d\n", ret); return ret; } - ret = sec_eng_init(rtwdev); + ret = sec_eng_init_ax(rtwdev); if (ret) { rtw89_err(rtwdev, "[ERR]Security Engine init %d\n", ret); return ret; @@ -2074,7 +2312,7 @@ static int dmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) return ret; } -static int addr_cam_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int addr_cam_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { u32 val, reg; u16 p_val; @@ -2101,7 +2339,7 @@ static int addr_cam_init(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } -static int scheduler_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int scheduler_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { u32 ret; u32 reg; @@ -2142,10 +2380,10 @@ static int scheduler_init(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } -int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, - enum rtw89_machdr_frame_type type, - enum rtw89_mac_fwd_target fwd_target, - u8 mac_idx) +static int rtw89_mac_typ_fltr_opt_ax(struct rtw89_dev *rtwdev, + enum rtw89_machdr_frame_type type, + enum rtw89_mac_fwd_target fwd_target, + u8 mac_idx) { u32 reg; u32 val; @@ -2184,7 +2422,7 @@ int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, return 0; } -static int rx_fltr_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int rx_fltr_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { int ret, i; u32 mac_ftlr, plcp_ftlr; @@ -2194,8 +2432,8 @@ static int rx_fltr_init(struct rtw89_dev *rtwdev, u8 mac_idx) return ret; for (i = RTW89_MGNT; i <= RTW89_DATA; i++) { - ret = rtw89_mac_typ_fltr_opt(rtwdev, i, RTW89_FWD_TO_HOST, - mac_idx); + ret = rtw89_mac_typ_fltr_opt_ax(rtwdev, i, RTW89_FWD_TO_HOST, + mac_idx); if (ret) return ret; } @@ -2246,7 +2484,7 @@ static void _patch_dis_resp_chk(struct rtw89_dev *rtwdev, u8 mac_idx) } } -static int cca_ctrl_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int cca_ctrl_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { u32 val, reg; int ret; @@ -2278,7 +2516,7 @@ static int cca_ctrl_init(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } -static int nav_ctrl_init(struct rtw89_dev *rtwdev) +static int nav_ctrl_init_ax(struct rtw89_dev *rtwdev) { rtw89_write32_set(rtwdev, R_AX_WMAC_NAV_CTL, B_AX_WMAC_PLCP_UP_NAV_EN | B_AX_WMAC_TF_UP_NAV_EN | @@ -2288,7 +2526,7 @@ static int nav_ctrl_init(struct rtw89_dev *rtwdev) return 0; } -static int spatial_reuse_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int spatial_reuse_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { u32 reg; int ret; @@ -2302,7 +2540,7 @@ static int spatial_reuse_init(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } -static int tmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int tmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { u32 reg; int ret; @@ -2324,7 +2562,7 @@ static int tmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } -static int trxptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int trxptcl_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_rrsr_cfgs *rrsr = chip->rrsr_cfgs; @@ -2381,7 +2619,7 @@ static void rst_bacam(struct rtw89_dev *rtwdev) rtw89_warn(rtwdev, "failed to reset BA CAM\n"); } -static int rmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int rmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { #define TRXCFG_RMAC_CCA_TO 32 #define TRXCFG_RMAC_DATA_TO 15 @@ -2439,7 +2677,7 @@ static int rmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) return ret; } -static int cmac_com_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int cmac_com_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 val, reg; @@ -2464,7 +2702,7 @@ static int cmac_com_init(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } -static bool is_qta_dbcc(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) +bool rtw89_mac_is_qta_dbcc(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) { const struct rtw89_dle_mem *cfg; @@ -2477,7 +2715,7 @@ static bool is_qta_dbcc(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) return (cfg->ple_min_qt->cma1_dma && cfg->ple_max_qt->cma1_dma); } -static int ptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int ptcl_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { u32 val, reg; int ret; @@ -2520,7 +2758,7 @@ static int ptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } -static int cmac_dma_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int cmac_dma_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 reg; @@ -2539,82 +2777,82 @@ static int cmac_dma_init(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } -static int cmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) +static int cmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { int ret; - ret = scheduler_init(rtwdev, mac_idx); + ret = scheduler_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d SCH init %d\n", mac_idx, ret); return ret; } - ret = addr_cam_init(rtwdev, mac_idx); + ret = addr_cam_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d ADDR_CAM reset %d\n", mac_idx, ret); return ret; } - ret = rx_fltr_init(rtwdev, mac_idx); + ret = rx_fltr_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d RX filter init %d\n", mac_idx, ret); return ret; } - ret = cca_ctrl_init(rtwdev, mac_idx); + ret = cca_ctrl_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d CCA CTRL init %d\n", mac_idx, ret); return ret; } - ret = nav_ctrl_init(rtwdev); + ret = nav_ctrl_init_ax(rtwdev); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d NAV CTRL init %d\n", mac_idx, ret); return ret; } - ret = spatial_reuse_init(rtwdev, mac_idx); + ret = spatial_reuse_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d Spatial Reuse init %d\n", mac_idx, ret); return ret; } - ret = tmac_init(rtwdev, mac_idx); + ret = tmac_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d TMAC init %d\n", mac_idx, ret); return ret; } - ret = trxptcl_init(rtwdev, mac_idx); + ret = trxptcl_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d TRXPTCL init %d\n", mac_idx, ret); return ret; } - ret = rmac_init(rtwdev, mac_idx); + ret = rmac_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d RMAC init %d\n", mac_idx, ret); return ret; } - ret = cmac_com_init(rtwdev, mac_idx); + ret = cmac_com_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d Com init %d\n", mac_idx, ret); return ret; } - ret = ptcl_init(rtwdev, mac_idx); + ret = ptcl_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d PTCL init %d\n", mac_idx, ret); return ret; } - ret = cmac_dma_init(rtwdev, mac_idx); + ret = cmac_dma_init_ax(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d DMA init %d\n", mac_idx, ret); return ret; @@ -2626,20 +2864,26 @@ static int cmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) static int rtw89_mac_read_phycap(struct rtw89_dev *rtwdev, struct rtw89_mac_c2h_info *c2h_info) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_mac_h2c_info h2c_info = {0}; u32 ret; + mac->cnv_efuse_state(rtwdev, false); + h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_GET_FEATURE; h2c_info.content_len = 0; ret = rtw89_fw_msg_reg(rtwdev, &h2c_info, c2h_info); if (ret) - return ret; + goto out; if (c2h_info->id != RTW89_FWCMD_C2HREG_FUNC_PHY_CAP) - return -EINVAL; + ret = -EINVAL; - return 0; +out: + mac->cnv_efuse_state(rtwdev, true); + + return ret; } int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev) @@ -2871,7 +3115,7 @@ int rtw89_mac_resume_sch_tx_v1(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en) } EXPORT_SYMBOL(rtw89_mac_resume_sch_tx_v1); -int rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id) +static int dle_buf_req_ax(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id) { u32 val, reg; int ret; @@ -2895,7 +3139,7 @@ int rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *p return 0; } -int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev, +static int set_cpuio_ax(struct rtw89_dev *rtwdev, struct rtw89_cpuio_ctrl *ctrl_para, bool wd) { u32 val, cmd_type, reg; @@ -2948,8 +3192,9 @@ int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev, return 0; } -static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) +int rtw89_mac_dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_dle_mem *cfg; struct rtw89_cpuio_ctrl ctrl_para = {0}; u16 pkt_id; @@ -2961,15 +3206,14 @@ static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) return -EINVAL; } - if (dle_used_size(cfg->wde_size, cfg->ple_size) != - dle_expected_used_size(rtwdev, mode)) { + if (dle_used_size(cfg) != dle_expected_used_size(rtwdev, mode)) { rtw89_err(rtwdev, "[ERR]wd/dle mem cfg\n"); return -EINVAL; } dle_quota_cfg(rtwdev, cfg, INVALID_QT_WCPU); - ret = rtw89_mac_dle_buf_req(rtwdev, 0x20, true, &pkt_id); + ret = mac->dle_buf_req(rtwdev, 0x20, true, &pkt_id); if (ret) { rtw89_err(rtwdev, "[ERR]WDE DLE buf req\n"); return ret; @@ -2981,13 +3225,13 @@ static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) ctrl_para.pkt_num = 0; ctrl_para.dst_pid = WDE_DLE_PORT_ID_WDRLS; ctrl_para.dst_qid = WDE_DLE_QUEID_NO_REPORT; - ret = rtw89_mac_set_cpuio(rtwdev, &ctrl_para, true); + ret = mac->set_cpuio(rtwdev, &ctrl_para, true); if (ret) { rtw89_err(rtwdev, "[ERR]WDE DLE enqueue to head\n"); return -EFAULT; } - ret = rtw89_mac_dle_buf_req(rtwdev, 0x20, false, &pkt_id); + ret = mac->dle_buf_req(rtwdev, 0x20, false, &pkt_id); if (ret) { rtw89_err(rtwdev, "[ERR]PLE DLE buf req\n"); return ret; @@ -2999,7 +3243,7 @@ static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) ctrl_para.pkt_num = 0; ctrl_para.dst_pid = PLE_DLE_PORT_ID_PLRLS; ctrl_para.dst_qid = PLE_DLE_QUEID_NO_REPORT; - ret = rtw89_mac_set_cpuio(rtwdev, &ctrl_para, false); + ret = mac->set_cpuio(rtwdev, &ctrl_para, false); if (ret) { rtw89_err(rtwdev, "[ERR]PLE DLE enqueue to head\n"); return -EFAULT; @@ -3031,7 +3275,7 @@ static int band_idle_ck_b(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } -static int band1_enable(struct rtw89_dev *rtwdev) +static int band1_enable_ax(struct rtw89_dev *rtwdev) { int ret, i; u32 sleep_bak[4] = {0}; @@ -3057,7 +3301,7 @@ static int band1_enable(struct rtw89_dev *rtwdev) return ret; } - ret = dle_quota_change(rtwdev, rtwdev->mac.qta_mode); + ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode); if (ret) { rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret); return ret; @@ -3074,13 +3318,13 @@ static int band1_enable(struct rtw89_dev *rtwdev) return ret; } - ret = cmac_func_en(rtwdev, 1, true); + ret = cmac_func_en_ax(rtwdev, 1, true); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC1 func en %d\n", ret); return ret; } - ret = cmac_init(rtwdev, 1); + ret = cmac_init_ax(rtwdev, 1); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC1 init %d\n", ret); return ret; @@ -3289,8 +3533,8 @@ static void rtw89_tmac_imr_enable(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write32_set(rtwdev, reg, imr->tmac_imr_set); } -static int rtw89_mac_enable_imr(struct rtw89_dev *rtwdev, u8 mac_idx, - enum rtw89_mac_hwmod_sel sel) +static int enable_imr_ax(struct rtw89_dev *rtwdev, u8 mac_idx, + enum rtw89_mac_hwmod_sel sel) { int ret; @@ -3327,7 +3571,7 @@ static int rtw89_mac_enable_imr(struct rtw89_dev *rtwdev, u8 mac_idx, return 0; } -static void rtw89_mac_err_imr_ctrl(struct rtw89_dev *rtwdev, bool en) +static void err_imr_ctrl_ax(struct rtw89_dev *rtwdev, bool en) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; @@ -3340,18 +3584,18 @@ static void rtw89_mac_err_imr_ctrl(struct rtw89_dev *rtwdev, bool en) en ? CMAC1_ERR_IMR_EN : CMAC1_ERR_IMR_DIS); } -static int rtw89_mac_dbcc_enable(struct rtw89_dev *rtwdev, bool enable) +static int dbcc_enable_ax(struct rtw89_dev *rtwdev, bool enable) { int ret = 0; if (enable) { - ret = band1_enable(rtwdev); + ret = band1_enable_ax(rtwdev); if (ret) { rtw89_err(rtwdev, "[ERR] band1_enable %d\n", ret); return ret; } - ret = rtw89_mac_enable_imr(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL); + ret = enable_imr_ax(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL); if (ret) { rtw89_err(rtwdev, "[ERR] enable CMAC1 IMR %d\n", ret); return ret; @@ -3364,7 +3608,7 @@ static int rtw89_mac_dbcc_enable(struct rtw89_dev *rtwdev, bool enable) return 0; } -static int set_host_rpr(struct rtw89_dev *rtwdev) +static int set_host_rpr_ax(struct rtw89_dev *rtwdev) { if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) { rtw89_write32_mask(rtwdev, R_AX_WDRLS_CFG, @@ -3384,46 +3628,46 @@ static int set_host_rpr(struct rtw89_dev *rtwdev) return 0; } -static int rtw89_mac_trx_init(struct rtw89_dev *rtwdev) +static int trx_init_ax(struct rtw89_dev *rtwdev) { enum rtw89_qta_mode qta_mode = rtwdev->mac.qta_mode; int ret; - ret = dmac_init(rtwdev, 0); + ret = dmac_init_ax(rtwdev, 0); if (ret) { rtw89_err(rtwdev, "[ERR]DMAC init %d\n", ret); return ret; } - ret = cmac_init(rtwdev, 0); + ret = cmac_init_ax(rtwdev, 0); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d init %d\n", 0, ret); return ret; } - if (is_qta_dbcc(rtwdev, qta_mode)) { - ret = rtw89_mac_dbcc_enable(rtwdev, true); + if (rtw89_mac_is_qta_dbcc(rtwdev, qta_mode)) { + ret = dbcc_enable_ax(rtwdev, true); if (ret) { rtw89_err(rtwdev, "[ERR]dbcc_enable init %d\n", ret); return ret; } } - ret = rtw89_mac_enable_imr(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); + ret = enable_imr_ax(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); if (ret) { rtw89_err(rtwdev, "[ERR] enable DMAC IMR %d\n", ret); return ret; } - ret = rtw89_mac_enable_imr(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL); + ret = enable_imr_ax(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL); if (ret) { rtw89_err(rtwdev, "[ERR] to enable CMAC0 IMR %d\n", ret); return ret; } - rtw89_mac_err_imr_ctrl(rtwdev, true); + err_imr_ctrl_ax(rtwdev, true); - ret = set_host_rpr(rtwdev); + ret = set_host_rpr_ax(rtwdev); if (ret) { rtw89_err(rtwdev, "[ERR] set host rpr %d\n", ret); return ret; @@ -3514,11 +3758,10 @@ static int rtw89_mac_enable_cpu_ax(struct rtw89_dev *rtwdev, u8 boot_reason, return 0; } -static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) +static void rtw89_mac_hci_func_en_ax(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 val; - int ret; if (chip_id == RTL8852C) val = B_AX_MAC_FUNC_EN | B_AX_DMAC_FUNC_EN | B_AX_DISPATCHER_EN | @@ -3527,6 +3770,12 @@ static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) val = B_AX_MAC_FUNC_EN | B_AX_DMAC_FUNC_EN | B_AX_DISPATCHER_EN | B_AX_PKT_BUF_EN; rtw89_write32(rtwdev, R_AX_DMAC_FUNC_EN, val); +} + +static void rtw89_mac_dmac_func_pre_en_ax(struct rtw89_dev *rtwdev) +{ + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + u32 val; if (chip_id == RTL8851B) val = B_AX_DISPATCHER_CLK_EN | B_AX_AXIDMA_CLK_EN; @@ -3535,7 +3784,7 @@ static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, R_AX_DMAC_CLK_EN, val); if (chip_id != RTL8852C) - goto dle; + return; val = rtw89_read32(rtwdev, R_AX_HAXI_INIT_CFG1); val &= ~(B_AX_DMA_MODE_MASK | B_AX_STOP_AXI_MST); @@ -3550,15 +3799,23 @@ static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) B_AX_STOP_CH12 | B_AX_STOP_ACH2); rtw89_write32_clr(rtwdev, R_AX_HAXI_DMA_STOP2, B_AX_STOP_CH10 | B_AX_STOP_CH11); rtw89_write32_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_AXIDMA_EN); +} -dle: - ret = dle_init(rtwdev, RTW89_QTA_DLFW, rtwdev->mac.qta_mode); +static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + int ret; + + mac->hci_func_en(rtwdev); + mac->dmac_func_pre_en(rtwdev); + + ret = rtw89_mac_dle_init(rtwdev, RTW89_QTA_DLFW, rtwdev->mac.qta_mode); if (ret) { rtw89_err(rtwdev, "[ERR]DLE pre init %d\n", ret); return ret; } - ret = hfc_init(rtwdev, true, false, true); + ret = rtw89_mac_hfc_init(rtwdev, true, false, true); if (ret) { rtw89_err(rtwdev, "[ERR]HCI FC pre init %d\n", ret); return ret; @@ -3632,6 +3889,7 @@ int rtw89_mac_partial_init(struct rtw89_dev *rtwdev, bool include_bb) int rtw89_mac_init(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_chip_info *chip = rtwdev->chip; bool include_bb = !!chip->bbmcu_nr; int ret; @@ -3644,11 +3902,11 @@ int rtw89_mac_init(struct rtw89_dev *rtwdev) if (ret) goto fail; - ret = rtw89_mac_sys_init(rtwdev); + ret = mac->sys_init(rtwdev); if (ret) goto fail; - ret = rtw89_mac_trx_init(rtwdev); + ret = mac->trx_init(rtwdev); if (ret) goto fail; @@ -5249,7 +5507,8 @@ bool rtw89_mac_get_ctrl_path(struct rtw89_dev *rtwdev) if (chip->chip_id == RTL8852C) return false; - else if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B) + else if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B || + chip->chip_id == RTL8851B) val = rtw89_read8_mask(rtwdev, R_AX_SYS_SDIO_CTRL + 3, B_AX_LTE_MUX_CTRL_PATH >> 24); @@ -5694,7 +5953,8 @@ int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev, return 0; } -int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask) +static +int rtw89_mac_write_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask) { u32 val32; int ret; @@ -5716,9 +5976,9 @@ int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask return 0; } -EXPORT_SYMBOL(rtw89_mac_write_xtal_si); -int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val) +static +int rtw89_mac_read_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 *val) { u32 val32; int ret; @@ -5741,7 +6001,6 @@ int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val) return 0; } -EXPORT_SYMBOL(rtw89_mac_read_xtal_si); static void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) @@ -5791,6 +6050,7 @@ void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, enum rtw89_mac_idx band) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_pkt_drop_params params = {0}; bool empty; int i, ret = 0, try_cnt = 3; @@ -5799,7 +6059,7 @@ int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, params.sel = RTW89_PKT_DROP_SEL_BAND_ONCE; for (i = 0; i < try_cnt; i++) { - ret = read_poll_timeout(mac_is_txq_empty, empty, empty, 50, + ret = read_poll_timeout(mac->is_txq_empty, empty, empty, 50, 50000, false, rtwdev); if (ret && !RTW89_CHK_FW_FEATURE(NO_PACKET_DROP, &rtwdev->fw)) rtw89_fw_h2c_pkt_drop(rtwdev, ¶ms); @@ -5847,13 +6107,44 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { B_AX_BFMEE_HE_NDPA_EN, }, + .check_mac_en = rtw89_mac_check_mac_en_ax, + .sys_init = sys_init_ax, + .trx_init = trx_init_ax, + .hci_func_en = rtw89_mac_hci_func_en_ax, + .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_ax, + .dle_func_en = dle_func_en_ax, + .dle_clk_en = dle_clk_en_ax, .bf_assoc = rtw89_mac_bf_assoc_ax, + .typ_fltr_opt = rtw89_mac_typ_fltr_opt_ax, + + .dle_mix_cfg = dle_mix_cfg_ax, + .chk_dle_rdy = chk_dle_rdy_ax, + .dle_buf_req = dle_buf_req_ax, + .hfc_func_en = hfc_func_en_ax, + .hfc_h2c_cfg = hfc_h2c_cfg_ax, + .hfc_mix_cfg = hfc_mix_cfg_ax, + .hfc_get_mix_info = hfc_get_mix_info_ax, + .wde_quota_cfg = wde_quota_cfg_ax, + .ple_quota_cfg = ple_quota_cfg_ax, + .set_cpuio = set_cpuio_ax, + .disable_cpu = rtw89_mac_disable_cpu_ax, .fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax, .fwdl_get_status = rtw89_fw_get_rdy_ax, .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_ax, + .parse_efuse_map = rtw89_parse_efuse_map_ax, + .parse_phycap_map = rtw89_parse_phycap_map_ax, + .cnv_efuse_state = rtw89_cnv_efuse_state_ax, .get_txpwr_cr = rtw89_mac_get_txpwr_cr_ax, + + .write_xtal_si = rtw89_mac_write_xtal_si_ax, + .read_xtal_si = rtw89_mac_read_xtal_si_ax, + + .dump_qta_lost = rtw89_mac_dump_qta_lost_ax, + .dump_err_status = rtw89_mac_dump_err_status_ax, + + .is_txq_empty = mac_is_txq_empty_ax, }; EXPORT_SYMBOL(rtw89_mac_gen_ax); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index f9fef678f3..ed98b49809 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -10,6 +10,7 @@ #define MAC_MEM_DUMP_PAGE_SIZE 0x40000 #define ADDR_CAM_ENT_SIZE 0x40 +#define ADDR_CAM_ENT_SHORT_SIZE 0x20 #define BSSID_CAM_ENT_SIZE 0x08 #define HFC_PAGE_UNIT 64 #define RPWM_TRY_CNT 3 @@ -536,6 +537,9 @@ enum rtw89_mac_bf_rrsc_rate { #define B_CMAC1_MGQ_NO_PWRSAV BIT(11) #define B_CMAC1_CPUMGQ BIT(12) +#define B_CMAC0_MGQ_NORMAL_BE BIT(2) +#define B_CMAC1_MGQ_NORMAL_BE BIT(30) + #define QEMP_ACQ_GRP_MACID_NUM 8 #define QEMP_ACQ_GRP_QSEL_SH 4 #define QEMP_ACQ_GRP_QSEL_MASK 0xF @@ -649,6 +653,22 @@ struct rtw89_mac_dle_dfi_qempty { u32 qempty; }; +enum rtw89_mac_dle_rsvd_qt_type { + DLE_RSVD_QT_MPDU_INFO, + DLE_RSVD_QT_B0_CSI, + DLE_RSVD_QT_B1_CSI, + DLE_RSVD_QT_B0_LMR, + DLE_RSVD_QT_B1_LMR, + DLE_RSVD_QT_B0_FTM, + DLE_RSVD_QT_B1_FTM, +}; + +struct rtw89_mac_dle_rsvd_qt_cfg { + u16 pktid; + u16 pg_num; + u32 size; +}; + enum rtw89_mac_error_scenario { RTW89_RXI300_ERROR = 1, RTW89_WCPU_CPU_EXCEPTION = 2, @@ -817,27 +837,37 @@ enum mac_ax_err_info { struct rtw89_mac_size_set { const struct rtw89_hfc_prec_cfg hfc_preccfg_pcie; + const struct rtw89_hfc_prec_cfg hfc_prec_cfg_c0; + const struct rtw89_hfc_prec_cfg hfc_prec_cfg_c2; const struct rtw89_dle_size wde_size0; + const struct rtw89_dle_size wde_size0_v1; const struct rtw89_dle_size wde_size4; + const struct rtw89_dle_size wde_size4_v1; const struct rtw89_dle_size wde_size6; const struct rtw89_dle_size wde_size7; const struct rtw89_dle_size wde_size9; const struct rtw89_dle_size wde_size18; const struct rtw89_dle_size wde_size19; const struct rtw89_dle_size ple_size0; + const struct rtw89_dle_size ple_size0_v1; + const struct rtw89_dle_size ple_size3_v1; const struct rtw89_dle_size ple_size4; const struct rtw89_dle_size ple_size6; const struct rtw89_dle_size ple_size8; const struct rtw89_dle_size ple_size18; const struct rtw89_dle_size ple_size19; const struct rtw89_wde_quota wde_qt0; + const struct rtw89_wde_quota wde_qt0_v1; const struct rtw89_wde_quota wde_qt4; const struct rtw89_wde_quota wde_qt6; const struct rtw89_wde_quota wde_qt7; const struct rtw89_wde_quota wde_qt17; const struct rtw89_wde_quota wde_qt18; + const struct rtw89_ple_quota ple_qt0; + const struct rtw89_ple_quota ple_qt1; const struct rtw89_ple_quota ple_qt4; const struct rtw89_ple_quota ple_qt5; + const struct rtw89_ple_quota ple_qt9; const struct rtw89_ple_quota ple_qt13; const struct rtw89_ple_quota ple_qt18; const struct rtw89_ple_quota ple_qt44; @@ -848,6 +878,10 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt_52a_wow; const struct rtw89_ple_quota ple_qt_52b_wow; const struct rtw89_ple_quota ple_qt_51b_wow; + const struct rtw89_rsvd_quota ple_rsvd_qt0; + const struct rtw89_rsvd_quota ple_rsvd_qt1; + const struct rtw89_dle_rsvd_size rsvd0_size0; + const struct rtw89_dle_rsvd_size rsvd1_size0; }; extern const struct rtw89_mac_size_set rtw89_mac_size; @@ -864,18 +898,60 @@ struct rtw89_mac_gen_def { struct rtw89_reg_def muedca_ctrl; struct rtw89_reg_def bfee_ctrl; + int (*check_mac_en)(struct rtw89_dev *rtwdev, u8 band, + enum rtw89_mac_hwmod_sel sel); + int (*sys_init)(struct rtw89_dev *rtwdev); + int (*trx_init)(struct rtw89_dev *rtwdev); + void (*hci_func_en)(struct rtw89_dev *rtwdev); + void (*dmac_func_pre_en)(struct rtw89_dev *rtwdev); + void (*dle_func_en)(struct rtw89_dev *rtwdev, bool enable); + void (*dle_clk_en)(struct rtw89_dev *rtwdev, bool enable); void (*bf_assoc)(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); + int (*typ_fltr_opt)(struct rtw89_dev *rtwdev, + enum rtw89_machdr_frame_type type, + enum rtw89_mac_fwd_target fwd_target, + u8 mac_idx); + + int (*dle_mix_cfg)(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg); + int (*chk_dle_rdy)(struct rtw89_dev *rtwdev, bool wde_or_ple); + int (*dle_buf_req)(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id); + void (*hfc_func_en)(struct rtw89_dev *rtwdev, bool en, bool h2c_en); + void (*hfc_h2c_cfg)(struct rtw89_dev *rtwdev); + void (*hfc_mix_cfg)(struct rtw89_dev *rtwdev); + void (*hfc_get_mix_info)(struct rtw89_dev *rtwdev); + void (*wde_quota_cfg)(struct rtw89_dev *rtwdev, + const struct rtw89_wde_quota *min_cfg, + const struct rtw89_wde_quota *max_cfg, + u16 ext_wde_min_qt_wcpu); + void (*ple_quota_cfg)(struct rtw89_dev *rtwdev, + const struct rtw89_ple_quota *min_cfg, + const struct rtw89_ple_quota *max_cfg); + int (*set_cpuio)(struct rtw89_dev *rtwdev, + struct rtw89_cpuio_ctrl *ctrl_para, bool wd); + void (*disable_cpu)(struct rtw89_dev *rtwdev); int (*fwdl_enable_wcpu)(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw, bool include_bb); u8 (*fwdl_get_status)(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type); int (*fwdl_check_path_ready)(struct rtw89_dev *rtwdev, bool h2c_or_fwdl); + int (*parse_efuse_map)(struct rtw89_dev *rtwdev); + int (*parse_phycap_map)(struct rtw89_dev *rtwdev); + int (*cnv_efuse_state)(struct rtw89_dev *rtwdev, bool idle); bool (*get_txpwr_cr)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 reg_base, u32 *cr); + + int (*write_xtal_si)(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask); + int (*read_xtal_si)(struct rtw89_dev *rtwdev, u8 offset, u8 *val); + + void (*dump_qta_lost)(struct rtw89_dev *rtwdev); + void (*dump_err_status)(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err); + + bool (*is_txq_empty)(struct rtw89_dev *rtwdev); }; extern const struct rtw89_mac_gen_def rtw89_mac_gen_ax; @@ -977,10 +1053,31 @@ rtw89_write32_port_set(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, void rtw89_mac_pwr_off(struct rtw89_dev *rtwdev); int rtw89_mac_partial_init(struct rtw89_dev *rtwdev, bool include_bb); int rtw89_mac_init(struct rtw89_dev *rtwdev); +int rtw89_mac_dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, + enum rtw89_qta_mode ext_mode); +int rtw89_mac_hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en); +int rtw89_mac_preload_init(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, + enum rtw89_qta_mode mode); +bool rtw89_mac_is_qta_dbcc(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode); +static inline int rtw89_mac_check_mac_en(struct rtw89_dev *rtwdev, u8 band, - enum rtw89_mac_hwmod_sel sel); + enum rtw89_mac_hwmod_sel sel) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + return mac->check_mac_en(rtwdev, band, sel); +} + int rtw89_mac_write_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 val); int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val); +int rtw89_mac_dle_dfi_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl); +int rtw89_mac_dle_dfi_quota_cfg(struct rtw89_dev *rtwdev, + struct rtw89_mac_dle_dfi_quota *quota); +void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev); +int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev, + struct rtw89_mac_dle_dfi_qempty *qempty); +void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err); int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, @@ -1011,6 +1108,23 @@ static inline int rtw89_chip_disable_bb_rf(struct rtw89_dev *rtwdev) return chip->ops->disable_bb_rf(rtwdev); } +static inline int rtw89_chip_reset_bb_rf(struct rtw89_dev *rtwdev) +{ + int ret; + + if (rtwdev->chip->chip_gen != RTW89_CHIP_AX) + return 0; + + ret = rtw89_chip_disable_bb_rf(rtwdev); + if (ret) + return ret; + ret = rtw89_chip_enable_bb_rf(rtwdev); + if (ret) + return ret; + + return 0; +} + u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev); int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err); bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func); @@ -1186,6 +1300,7 @@ enum rtw89_mac_xtal_si_offset { #define XTAL_SC_XI_MASK GENMASK(7, 0) XTAL_SI_XTAL_SC_XO = 0x05, #define XTAL_SC_XO_MASK GENMASK(7, 0) + XTAL_SI_XREF_MODE = 0x0B, XTAL_SI_PWR_CUT = 0x10, #define XTAL_SI_SMALL_PWR_CUT BIT(0) #define XTAL_SI_BIG_PWR_CUT BIT(1) @@ -1195,6 +1310,8 @@ enum rtw89_mac_xtal_si_offset { #define XTAL_SI_LDO_LPS GENMASK(6, 4) XTAL_SI_XTAL_XMD_4 = 0x26, #define XTAL_SI_LPS_CAP GENMASK(3, 0) + XTAL_SI_XREF_RF1 = 0x2D, + XTAL_SI_XREF_RF2 = 0x2E, XTAL_SI_CV = 0x41, #define XTAL_SI_ACV_MASK GENMASK(3, 0) XTAL_SI_LOW_ADDR = 0x62, @@ -1222,20 +1339,34 @@ enum rtw89_mac_xtal_si_offset { XTAL_SI_SRAM_CTRL = 0xA1, #define XTAL_SI_SRAM_DIS BIT(1) #define FULL_BIT_MASK GENMASK(7, 0) + XTAL_SI_PLL = 0xE0, + XTAL_SI_PLL_1 = 0xE1, }; -int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask); -int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val); +static inline +int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + return mac->write_xtal_si(rtwdev, offset, val, mask); +} + +static inline +int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + return mac->read_xtal_si(rtwdev, offset, val); +} + void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); -int rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id); -int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev, - struct rtw89_cpuio_ctrl *ctrl_para, bool wd); -int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, - enum rtw89_machdr_frame_type type, - enum rtw89_mac_fwd_target fwd_target, u8 mac_idx); int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow); int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, enum rtw89_mac_idx band); void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool wow); +int rtw89_mac_dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode); +int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, + enum rtw89_mac_dle_rsvd_qt_type type, + struct rtw89_mac_dle_rsvd_qt_cfg *cfg); #endif diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index b7ceaf5595..956a06c8cd 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -226,6 +226,7 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, { struct rtw89_dev *rtwdev = hw->priv; const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + u32 rx_fltr; mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); @@ -272,16 +273,29 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, } } + rx_fltr = rtwdev->hal.rx_fltr; + + /* mac80211 doesn't configure filter when HW scan, driver need to + * set by itself. However, during P2P scan might have configure + * filter to overwrite filter that HW scan needed, so we need to + * check scan and append related filter + */ + if (rtwdev->scanning) { + rx_fltr &= ~B_AX_A_BCN_CHK_EN; + rx_fltr &= ~B_AX_A_BC; + rx_fltr &= ~B_AX_A_A1_MATCH; + } + rtw89_write32_mask(rtwdev, rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), B_AX_RX_FLTR_CFG_MASK, - rtwdev->hal.rx_fltr); + rx_fltr); if (!rtwdev->dbcc_en) goto out; rtw89_write32_mask(rtwdev, rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_1), B_AX_RX_FLTR_CFG_MASK, - rtwdev->hal.rx_fltr); + rx_fltr); out: mutex_unlock(&rtwdev->mutex); @@ -427,7 +441,7 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, * when disconnected by peer */ if (rtwdev->scanning) - rtw89_hw_scan_abort(rtwdev, vif); + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); } } @@ -976,7 +990,7 @@ static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, } if (rtwdev->scanning) - rtw89_hw_scan_abort(rtwdev, vif); + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); if (type == IEEE80211_ROC_TYPE_MGMT_TX) roc->state = RTW89_ROC_MGMT; diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 3278f241db..be30c93462 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -3,6 +3,7 @@ */ #include "debug.h" +#include "efuse.h" #include "fw.h" #include "mac.h" #include "reg.h" @@ -56,6 +57,369 @@ static const struct rtw89_port_reg rtw89_port_base_be = { R_BE_PORT_HGQ_WINDOW_CFG + 3}, }; +static int rtw89_mac_check_mac_en_be(struct rtw89_dev *rtwdev, u8 mac_idx, + enum rtw89_mac_hwmod_sel sel) +{ + if (sel == RTW89_DMAC_SEL && + test_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags)) + return 0; + if (sel == RTW89_CMAC_SEL && mac_idx == RTW89_MAC_0 && + test_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags)) + return 0; + if (sel == RTW89_CMAC_SEL && mac_idx == RTW89_MAC_1 && + test_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags)) + return 0; + + return -EFAULT; +} + +static bool is_qta_poh(struct rtw89_dev *rtwdev) +{ + return rtwdev->hci.type == RTW89_HCI_TYPE_PCIE; +} + +static void hfc_get_mix_info_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; + struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; + struct rtw89_hfc_pub_cfg *pub_cfg = ¶m->pub_cfg; + struct rtw89_hfc_pub_info *info = ¶m->pub_info; + u32 val; + + val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO1); + info->g0_used = u32_get_bits(val, B_BE_G0_USE_PG_MASK); + info->g1_used = u32_get_bits(val, B_BE_G1_USE_PG_MASK); + + val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO3); + info->g0_aval = u32_get_bits(val, B_BE_G0_AVAL_PG_MASK); + info->g1_aval = u32_get_bits(val, B_BE_G1_AVAL_PG_MASK); + info->pub_aval = u32_get_bits(rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO2), + B_BE_PUB_AVAL_PG_MASK); + info->wp_aval = u32_get_bits(rtw89_read32(rtwdev, R_BE_WP_PAGE_INFO1), + B_BE_WP_AVAL_PG_MASK); + + val = rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL); + param->en = !!(val & B_BE_HCI_FC_EN); + param->h2c_en = !!(val & B_BE_HCI_FC_CH12_EN); + param->mode = u32_get_bits(val, B_BE_HCI_FC_MODE_MASK); + prec_cfg->ch011_full_cond = u32_get_bits(val, B_BE_HCI_FC_WD_FULL_COND_MASK); + prec_cfg->h2c_full_cond = u32_get_bits(val, B_BE_HCI_FC_CH12_FULL_COND_MASK); + prec_cfg->wp_ch07_full_cond = + u32_get_bits(val, B_BE_HCI_FC_WP_CH07_FULL_COND_MASK); + prec_cfg->wp_ch811_full_cond = + u32_get_bits(val, B_BE_HCI_FC_WP_CH811_FULL_COND_MASK); + + val = rtw89_read32(rtwdev, R_BE_CH_PAGE_CTRL); + prec_cfg->ch011_prec = u32_get_bits(val, B_BE_PREC_PAGE_CH011_V1_MASK); + prec_cfg->h2c_prec = u32_get_bits(val, B_BE_PREC_PAGE_CH12_V1_MASK); + + val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_CTRL2); + pub_cfg->pub_max = u32_get_bits(val, B_BE_PUBPG_ALL_MASK); + + val = rtw89_read32(rtwdev, R_BE_WP_PAGE_CTRL1); + prec_cfg->wp_ch07_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH07_MASK); + prec_cfg->wp_ch811_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH811_MASK); + + val = rtw89_read32(rtwdev, R_BE_WP_PAGE_CTRL2); + pub_cfg->wp_thrd = u32_get_bits(val, B_BE_WP_THRD_MASK); + + val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_CTRL1); + pub_cfg->grp0 = u32_get_bits(val, B_BE_PUBPG_G0_MASK); + pub_cfg->grp1 = u32_get_bits(val, B_BE_PUBPG_G1_MASK); +} + +static void hfc_h2c_cfg_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; + const struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; + u32 val; + + val = u32_encode_bits(prec_cfg->h2c_prec, B_BE_PREC_PAGE_CH12_V1_MASK); + rtw89_write32(rtwdev, R_BE_CH_PAGE_CTRL, val); +} + +static void hfc_mix_cfg_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; + const struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; + const struct rtw89_hfc_pub_cfg *pub_cfg = ¶m->pub_cfg; + u32 val; + + val = u32_encode_bits(prec_cfg->ch011_prec, B_BE_PREC_PAGE_CH011_V1_MASK) | + u32_encode_bits(prec_cfg->h2c_prec, B_BE_PREC_PAGE_CH12_V1_MASK); + rtw89_write32(rtwdev, R_BE_CH_PAGE_CTRL, val); + + val = u32_encode_bits(pub_cfg->pub_max, B_BE_PUBPG_ALL_MASK); + rtw89_write32(rtwdev, R_BE_PUB_PAGE_CTRL2, val); + + val = u32_encode_bits(prec_cfg->wp_ch07_prec, B_BE_PREC_PAGE_WP_CH07_MASK) | + u32_encode_bits(prec_cfg->wp_ch811_prec, B_BE_PREC_PAGE_WP_CH811_MASK); + rtw89_write32(rtwdev, R_BE_WP_PAGE_CTRL1, val); + + val = u32_replace_bits(rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL), + param->mode, B_BE_HCI_FC_MODE_MASK); + val = u32_replace_bits(val, prec_cfg->ch011_full_cond, + B_BE_HCI_FC_WD_FULL_COND_MASK); + val = u32_replace_bits(val, prec_cfg->h2c_full_cond, + B_BE_HCI_FC_CH12_FULL_COND_MASK); + val = u32_replace_bits(val, prec_cfg->wp_ch07_full_cond, + B_BE_HCI_FC_WP_CH07_FULL_COND_MASK); + val = u32_replace_bits(val, prec_cfg->wp_ch811_full_cond, + B_BE_HCI_FC_WP_CH811_FULL_COND_MASK); + rtw89_write32(rtwdev, R_BE_HCI_FC_CTRL, val); +} + +static void hfc_func_en_be(struct rtw89_dev *rtwdev, bool en, bool h2c_en) +{ + struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; + u32 val; + + val = rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL); + param->en = en; + param->h2c_en = h2c_en; + val = en ? (val | B_BE_HCI_FC_EN) : (val & ~B_BE_HCI_FC_EN); + val = h2c_en ? (val | B_BE_HCI_FC_CH12_EN) : + (val & ~B_BE_HCI_FC_CH12_EN); + rtw89_write32(rtwdev, R_BE_HCI_FC_CTRL, val); +} + +static void dle_func_en_be(struct rtw89_dev *rtwdev, bool enable) +{ + if (enable) + rtw89_write32_set(rtwdev, R_BE_DMAC_FUNC_EN, + B_BE_DLE_WDE_EN | B_BE_DLE_PLE_EN); + else + rtw89_write32_clr(rtwdev, R_BE_DMAC_FUNC_EN, + B_BE_DLE_WDE_EN | B_BE_DLE_PLE_EN); +} + +static void dle_clk_en_be(struct rtw89_dev *rtwdev, bool enable) +{ + if (enable) + rtw89_write32_set(rtwdev, R_BE_DMAC_CLK_EN, + B_BE_DLE_WDE_CLK_EN | B_BE_DLE_PLE_CLK_EN); + else + rtw89_write32_clr(rtwdev, R_BE_DMAC_CLK_EN, + B_BE_DLE_WDE_CLK_EN | B_BE_DLE_PLE_CLK_EN); +} + +static int dle_mix_cfg_be(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg) +{ + const struct rtw89_dle_size *wde_size_cfg, *ple_size_cfg; + u32 bound; + u32 val; + + wde_size_cfg = cfg->wde_size; + ple_size_cfg = cfg->ple_size; + + val = rtw89_read32(rtwdev, R_BE_WDE_PKTBUF_CFG); + + switch (wde_size_cfg->pge_size) { + default: + case RTW89_WDE_PG_64: + val = u32_replace_bits(val, S_AX_WDE_PAGE_SEL_64, + B_BE_WDE_PAGE_SEL_MASK); + break; + case RTW89_WDE_PG_128: + val = u32_replace_bits(val, S_AX_WDE_PAGE_SEL_128, + B_BE_WDE_PAGE_SEL_MASK); + break; + case RTW89_WDE_PG_256: + rtw89_err(rtwdev, "[ERR]WDE DLE doesn't support 256 byte!\n"); + return -EINVAL; + } + + bound = wde_size_cfg->srt_ofst / DLE_BOUND_UNIT; + val = u32_replace_bits(val, bound, B_BE_WDE_START_BOUND_MASK); + val = u32_replace_bits(val, wde_size_cfg->lnk_pge_num, + B_BE_WDE_FREE_PAGE_NUM_MASK); + rtw89_write32(rtwdev, R_BE_WDE_PKTBUF_CFG, val); + + val = rtw89_read32(rtwdev, R_BE_PLE_PKTBUF_CFG); + + switch (ple_size_cfg->pge_size) { + default: + case RTW89_PLE_PG_64: + rtw89_err(rtwdev, "[ERR]PLE DLE doesn't support 64 byte!\n"); + return -EINVAL; + case RTW89_PLE_PG_128: + val = u32_replace_bits(val, S_AX_PLE_PAGE_SEL_128, + B_BE_PLE_PAGE_SEL_MASK); + break; + case RTW89_PLE_PG_256: + val = u32_replace_bits(val, S_AX_PLE_PAGE_SEL_256, + B_BE_PLE_PAGE_SEL_MASK); + break; + } + + bound = ple_size_cfg->srt_ofst / DLE_BOUND_UNIT; + val = u32_replace_bits(val, bound, B_BE_PLE_START_BOUND_MASK); + val = u32_replace_bits(val, ple_size_cfg->lnk_pge_num, + B_BE_PLE_FREE_PAGE_NUM_MASK); + rtw89_write32(rtwdev, R_BE_PLE_PKTBUF_CFG, val); + + return 0; +} + +static int chk_dle_rdy_be(struct rtw89_dev *rtwdev, bool wde_or_ple) +{ + u32 reg, mask; + u32 ini; + + if (wde_or_ple) { + reg = R_AX_WDE_INI_STATUS; + mask = WDE_MGN_INI_RDY; + } else { + reg = R_AX_PLE_INI_STATUS; + mask = PLE_MGN_INI_RDY; + } + + return read_poll_timeout(rtw89_read32, ini, (ini & mask) == mask, 1, + 2000, false, rtwdev, reg); +} + +#define INVALID_QT_WCPU U16_MAX +#define SET_QUOTA_VAL(_min_x, _max_x, _module, _idx) \ + do { \ + val = u32_encode_bits(_min_x, B_BE_ ## _module ## _Q ## _idx ## _MIN_SIZE_MASK) | \ + u32_encode_bits(_max_x, B_BE_ ## _module ## _Q ## _idx ## _MAX_SIZE_MASK); \ + rtw89_write32(rtwdev, \ + R_BE_ ## _module ## _QTA ## _idx ## _CFG, \ + val); \ + } while (0) +#define SET_QUOTA(_x, _module, _idx) \ + SET_QUOTA_VAL(min_cfg->_x, max_cfg->_x, _module, _idx) + +static void wde_quota_cfg_be(struct rtw89_dev *rtwdev, + const struct rtw89_wde_quota *min_cfg, + const struct rtw89_wde_quota *max_cfg, + u16 ext_wde_min_qt_wcpu) +{ + u16 min_qt_wcpu = ext_wde_min_qt_wcpu != INVALID_QT_WCPU ? + ext_wde_min_qt_wcpu : min_cfg->wcpu; + u16 max_qt_wcpu = max(max_cfg->wcpu, min_qt_wcpu); + u32 val; + + SET_QUOTA(hif, WDE, 0); + SET_QUOTA_VAL(min_qt_wcpu, max_qt_wcpu, WDE, 1); + SET_QUOTA_VAL(0, 0, WDE, 2); + SET_QUOTA(pkt_in, WDE, 3); + SET_QUOTA(cpu_io, WDE, 4); +} + +static void ple_quota_cfg_be(struct rtw89_dev *rtwdev, + const struct rtw89_ple_quota *min_cfg, + const struct rtw89_ple_quota *max_cfg) +{ + u32 val; + + SET_QUOTA(cma0_tx, PLE, 0); + SET_QUOTA(cma1_tx, PLE, 1); + SET_QUOTA(c2h, PLE, 2); + SET_QUOTA(h2c, PLE, 3); + SET_QUOTA(wcpu, PLE, 4); + SET_QUOTA(mpdu_proc, PLE, 5); + SET_QUOTA(cma0_dma, PLE, 6); + SET_QUOTA(cma1_dma, PLE, 7); + SET_QUOTA(bb_rpt, PLE, 8); + SET_QUOTA(wd_rel, PLE, 9); + SET_QUOTA(cpu_io, PLE, 10); + SET_QUOTA(tx_rpt, PLE, 11); + SET_QUOTA(h2d, PLE, 12); +} + +static void rtw89_mac_hci_func_en_be(struct rtw89_dev *rtwdev) +{ + rtw89_write32_set(rtwdev, R_BE_HCI_FUNC_EN, B_BE_HCI_TXDMA_EN | + B_BE_HCI_RXDMA_EN); +} + +static void rtw89_mac_dmac_func_pre_en_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + val = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); + + switch (rtwdev->hci.type) { + case RTW89_HCI_TYPE_PCIE: + val = u32_replace_bits(val, S_BE_DMA_MOD_PCIE_NO_DATA_CPU, + B_BE_DMA_MODE_MASK); + break; + case RTW89_HCI_TYPE_USB: + val = u32_replace_bits(val, S_BE_DMA_MOD_USB, B_BE_DMA_MODE_MASK); + val = (val & ~B_BE_STOP_AXI_MST) | B_BE_TXDMA_EN | B_BE_RXDMA_EN; + break; + case RTW89_HCI_TYPE_SDIO: + val = u32_replace_bits(val, S_BE_DMA_MOD_SDIO, B_BE_DMA_MODE_MASK); + val = (val & ~B_BE_STOP_AXI_MST) | B_BE_TXDMA_EN | B_BE_RXDMA_EN; + break; + default: + return; + } + + rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val); + + rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1, + B_BE_STOP_CH0 | B_BE_STOP_CH1 | B_BE_STOP_CH2 | + B_BE_STOP_CH3 | B_BE_STOP_CH4 | B_BE_STOP_CH5 | + B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 | + B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11 | + B_BE_STOP_CH12 | B_BE_STOP_CH13 | B_BE_STOP_CH14); + + rtw89_write32_set(rtwdev, R_BE_DMAC_TABLE_CTRL, B_BE_DMAC_ADDR_MODE); +} + +static +int rtw89_mac_write_xtal_si_be(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask) +{ + u32 val32; + int ret; + + val32 = u32_encode_bits(offset, B_BE_WL_XTAL_SI_ADDR_MASK) | + u32_encode_bits(val, B_BE_WL_XTAL_SI_DATA_MASK) | + u32_encode_bits(mask, B_BE_WL_XTAL_SI_BITMASK_MASK) | + u32_encode_bits(XTAL_SI_NORMAL_WRITE, B_BE_WL_XTAL_SI_MODE_MASK) | + u32_encode_bits(0, B_BE_WL_XTAL_SI_CHIPID_MASK) | + B_BE_WL_XTAL_SI_CMD_POLL; + rtw89_write32(rtwdev, R_BE_WLAN_XTAL_SI_CTRL, val32); + + ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_WL_XTAL_SI_CMD_POLL), + 50, 50000, false, rtwdev, R_BE_WLAN_XTAL_SI_CTRL); + if (ret) { + rtw89_warn(rtwdev, "xtal si not ready(W): offset=%x val=%x mask=%x\n", + offset, val, mask); + return ret; + } + + return 0; +} + +static +int rtw89_mac_read_xtal_si_be(struct rtw89_dev *rtwdev, u8 offset, u8 *val) +{ + u32 val32; + int ret; + + val32 = u32_encode_bits(offset, B_BE_WL_XTAL_SI_ADDR_MASK) | + u32_encode_bits(0x0, B_BE_WL_XTAL_SI_DATA_MASK) | + u32_encode_bits(0x0, B_BE_WL_XTAL_SI_BITMASK_MASK) | + u32_encode_bits(XTAL_SI_NORMAL_READ, B_BE_WL_XTAL_SI_MODE_MASK) | + u32_encode_bits(0, B_BE_WL_XTAL_SI_CHIPID_MASK) | + B_BE_WL_XTAL_SI_CMD_POLL; + rtw89_write32(rtwdev, R_BE_WLAN_XTAL_SI_CTRL, val32); + + ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_WL_XTAL_SI_CMD_POLL), + 50, 50000, false, rtwdev, R_BE_WLAN_XTAL_SI_CTRL); + if (ret) { + rtw89_warn(rtwdev, "xtal si not ready(R): offset=%x\n", offset); + return ret; + } + + *val = rtw89_read8(rtwdev, R_BE_WLAN_XTAL_SI_CTRL + 1); + + return 0; +} + static void rtw89_mac_disable_cpu_be(struct rtw89_dev *rtwdev) { u32 val32; @@ -92,8 +456,6 @@ static int wcpu_on(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw) u32 val32; int ret; - rtw89_write32_set(rtwdev, R_BE_UDM0, B_BE_UDM0_DBG_MODE_CTRL); - val32 = rtw89_read32(rtwdev, R_BE_HALT_C2H); if (val32) { rtw89_warn(rtwdev, "[SER] AON L2 Debug register not empty before Boot.\n"); @@ -117,6 +479,10 @@ static int wcpu_on(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw) rtw89_write32(rtwdev, R_BE_HALT_H2C_CTRL, 0); rtw89_write32(rtwdev, R_BE_HALT_C2H_CTRL, 0); + val32 = rtw89_read32(rtwdev, R_BE_HISR0); + rtw89_write32(rtwdev, R_BE_HISR0, B_BE_HALT_C2H_INT); + rtw89_debug(rtwdev, RTW89_DBG_SER, "HISR0=0x%x\n", val32); + rtw89_write32_set(rtwdev, R_BE_SYS_CLK_CTRL, B_BE_CPU_CLK_EN); rtw89_write32_clr(rtwdev, R_BE_SYS_CFG5, B_BE_WDT_WAKE_PCIE_EN | B_BE_WDT_WAKE_USB_EN); @@ -205,6 +571,1153 @@ static int rtw89_fwdl_check_path_ready_be(struct rtw89_dev *rtwdev, rtwdev, R_BE_WCPU_FW_CTRL); } +static int dmac_func_en_be(struct rtw89_dev *rtwdev) +{ + return 0; +} + +static int cmac_func_en_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) +{ + u32 reg; + + if (mac_idx > RTW89_MAC_1) + return -EINVAL; + + if (mac_idx == RTW89_MAC_0) + return 0; + + if (en) { + rtw89_write32_set(rtwdev, R_BE_AFE_CTRL1, B_BE_AFE_CTRL1_SET); + rtw89_write32_clr(rtwdev, R_BE_SYS_ISO_CTRL_EXTEND, B_BE_R_SYM_ISO_CMAC12PP); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_CMAC1_FEN); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CK_EN, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_CK_EN_SET); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CMAC_FUNC_EN, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_CMAC_FUNC_EN_SET); + + set_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); + } else { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CMAC_FUNC_EN, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_CMAC_FUNC_EN_SET); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CK_EN, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_CK_EN_SET); + + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_CMAC1_FEN); + rtw89_write32_set(rtwdev, R_BE_SYS_ISO_CTRL_EXTEND, B_BE_R_SYM_ISO_CMAC12PP); + rtw89_write32_clr(rtwdev, R_BE_AFE_CTRL1, B_BE_AFE_CTRL1_SET); + + clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); + } + + return 0; +} + +static int chip_func_en_be(struct rtw89_dev *rtwdev) +{ + return 0; +} + +static int sys_init_be(struct rtw89_dev *rtwdev) +{ + int ret; + + ret = dmac_func_en_be(rtwdev); + if (ret) + return ret; + + ret = cmac_func_en_be(rtwdev, RTW89_MAC_0, true); + if (ret) + return ret; + + ret = chip_func_en_be(rtwdev); + if (ret) + return ret; + + return ret; +} + +static int sta_sch_init_be(struct rtw89_dev *rtwdev) +{ + u32 p_val; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); + if (ret) + return ret; + + rtw89_write8_set(rtwdev, R_BE_SS_CTRL, B_BE_SS_EN); + + ret = read_poll_timeout(rtw89_read32, p_val, p_val & B_BE_SS_INIT_DONE, + 1, TRXCFG_WAIT_CNT, false, rtwdev, R_BE_SS_CTRL); + if (ret) { + rtw89_err(rtwdev, "[ERR]STA scheduler init\n"); + return ret; + } + + rtw89_write32_set(rtwdev, R_BE_SS_CTRL, B_BE_WARM_INIT); + rtw89_write32_clr(rtwdev, R_BE_SS_CTRL, B_BE_BAND_TRIG_EN | B_BE_BAND1_TRIG_EN); + + return 0; +} + +static int mpdu_proc_init_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_BE_MPDU_PROC, B_BE_APPEND_FCS); + rtw89_write32(rtwdev, R_BE_CUT_AMSDU_CTRL, TRXCFG_MPDU_PROC_CUT_CTRL); + + val32 = rtw89_read32(rtwdev, R_BE_HDR_SHCUT_SETTING); + val32 |= (B_BE_TX_HW_SEQ_EN | B_BE_TX_HW_ACK_POLICY_EN | B_BE_TX_MAC_MPDU_PROC_EN); + val32 &= ~B_BE_TX_ADDR_MLD_TO_LIK; + rtw89_write32_set(rtwdev, R_BE_HDR_SHCUT_SETTING, val32); + + rtw89_write32(rtwdev, R_BE_RX_HDRTRNS, TRXCFG_MPDU_PROC_RX_HDR_CONV); + + val32 = rtw89_read32(rtwdev, R_BE_DISP_FWD_WLAN_0); + val32 = u32_replace_bits(val32, 1, B_BE_FWD_WLAN_CPU_TYPE_0_DATA_MASK); + val32 = u32_replace_bits(val32, 1, B_BE_FWD_WLAN_CPU_TYPE_0_MNG_MASK); + val32 = u32_replace_bits(val32, 1, B_BE_FWD_WLAN_CPU_TYPE_0_CTL_MASK); + val32 = u32_replace_bits(val32, 1, B_BE_FWD_WLAN_CPU_TYPE_1_MASK); + rtw89_write32(rtwdev, R_BE_DISP_FWD_WLAN_0, val32); + + return 0; +} + +static int sec_eng_init_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); + if (ret) + return ret; + + val32 = rtw89_read32(rtwdev, R_BE_SEC_ENG_CTRL); + val32 |= B_BE_CLK_EN_CGCMP | B_BE_CLK_EN_WAPI | B_BE_CLK_EN_WEP_TKIP | + B_BE_SEC_TX_ENC | B_BE_SEC_RX_DEC | + B_BE_MC_DEC | B_BE_BC_DEC | + B_BE_BMC_MGNT_DEC | B_BE_UC_MGNT_DEC; + val32 &= ~B_BE_SEC_PRE_ENQUE_TX; + rtw89_write32(rtwdev, R_BE_SEC_ENG_CTRL, val32); + + rtw89_write32_set(rtwdev, R_BE_SEC_MPDU_PROC, B_BE_APPEND_ICV | B_BE_APPEND_MIC); + + return 0; +} + +static int txpktctrl_init_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_mac_dle_rsvd_qt_cfg qt_cfg; + u32 val32; + int ret; + + ret = rtw89_mac_get_dle_rsvd_qt_cfg(rtwdev, DLE_RSVD_QT_MPDU_INFO, &qt_cfg); + if (ret) { + rtw89_err(rtwdev, "get dle rsvd qt %d cfg fail %d\n", + DLE_RSVD_QT_MPDU_INFO, ret); + return ret; + } + + val32 = rtw89_read32(rtwdev, R_BE_TXPKTCTL_MPDUINFO_CFG); + val32 = u32_replace_bits(val32, qt_cfg.pktid, B_BE_MPDUINFO_PKTID_MASK); + val32 = u32_replace_bits(val32, MPDU_INFO_B1_OFST, B_BE_MPDUINFO_B1_BADDR_MASK); + val32 |= B_BE_MPDUINFO_FEN; + rtw89_write32(rtwdev, R_BE_TXPKTCTL_MPDUINFO_CFG, val32); + + return 0; +} + +static int mlo_init_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + int ret; + + val32 = rtw89_read32(rtwdev, R_BE_MLO_INIT_CTL); + + val32 |= B_BE_MLO_TABLE_REINIT; + rtw89_write32(rtwdev, R_BE_MLO_INIT_CTL, val32); + val32 &= ~B_BE_MLO_TABLE_REINIT; + rtw89_write32(rtwdev, R_BE_MLO_INIT_CTL, val32); + + ret = read_poll_timeout_atomic(rtw89_read32, val32, + val32 & B_BE_MLO_TABLE_INIT_DONE, + 1, 1000, false, rtwdev, R_BE_MLO_INIT_CTL); + if (ret) + rtw89_err(rtwdev, "[MLO]%s: MLO init polling timeout\n", __func__); + + rtw89_write32_set(rtwdev, R_BE_SS_CTRL, B_BE_MLO_HW_CHGLINK_EN); + rtw89_write32_set(rtwdev, R_BE_CMAC_SHARE_ACQCHK_CFG_0, B_BE_R_MACID_ACQ_CHK_EN); + + return ret; +} + +static int dmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + int ret; + + ret = rtw89_mac_dle_init(rtwdev, rtwdev->mac.qta_mode, RTW89_QTA_INVALID); + if (ret) { + rtw89_err(rtwdev, "[ERR]DLE init %d\n", ret); + return ret; + } + + ret = rtw89_mac_preload_init(rtwdev, RTW89_MAC_0, rtwdev->mac.qta_mode); + if (ret) { + rtw89_err(rtwdev, "[ERR]preload init %d\n", ret); + return ret; + } + + ret = rtw89_mac_hfc_init(rtwdev, true, true, true); + if (ret) { + rtw89_err(rtwdev, "[ERR]HCI FC init %d\n", ret); + return ret; + } + + ret = sta_sch_init_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR]STA SCH init %d\n", ret); + return ret; + } + + ret = mpdu_proc_init_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR]MPDU Proc init %d\n", ret); + return ret; + } + + ret = sec_eng_init_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR]Security Engine init %d\n", ret); + return ret; + } + + ret = txpktctrl_init_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR]TX pkt ctrl init %d\n", ret); + return ret; + } + + ret = mlo_init_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR]MLO init %d\n", ret); + return ret; + } + + return ret; +} + +static int scheduler_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 val32; + u32 reg; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_HE_CTN_CHK_CCA_NAV, mac_idx); + val32 = B_BE_HE_CTN_CHK_CCA_P20 | B_BE_HE_CTN_CHK_EDCCA_P20 | + B_BE_HE_CTN_CHK_CCA_BITMAP | B_BE_HE_CTN_CHK_EDCCA_BITMAP | + B_BE_HE_CTN_CHK_NO_GNT_WL | B_BE_HE_CTN_CHK_BASIC_NAV | + B_BE_HE_CTN_CHK_INTRA_NAV | B_BE_HE_CTN_CHK_TX_NAV; + rtw89_write32(rtwdev, reg, val32); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_HE_SIFS_CHK_CCA_NAV, mac_idx); + val32 = B_BE_HE_SIFS_CHK_EDCCA_P20 | B_BE_HE_SIFS_CHK_EDCCA_BITMAP | + B_BE_HE_SIFS_CHK_NO_GNT_WL; + rtw89_write32(rtwdev, reg, val32); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TB_CHK_CCA_NAV, mac_idx); + val32 = B_BE_TB_CHK_EDCCA_BITMAP | B_BE_TB_CHK_NO_GNT_WL | B_BE_TB_CHK_BASIC_NAV; + rtw89_write32(rtwdev, reg, val32); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CCA_CFG_0, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_NO_GNT_WL_EN); + + if (is_qta_poh(rtwdev)) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PREBKF_CFG_0, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_PREBKF_TIME_MASK, + SCH_PREBKF_24US); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CTN_CFG_0, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_PREBKF_TIME_NONAC_MASK, + SCH_PREBKF_24US); + } + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_EDCA_BCNQ_PARAM, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_BCNQ_CW_MASK, 0x32); + rtw89_write32_mask(rtwdev, reg, B_BE_BCNQ_AIFS_MASK, BCN_IFS_25US); + + return 0; +} + +static int addr_cam_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 val32; + u16 val16; + u32 reg; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_ADDR_CAM_CTRL, mac_idx); + val32 = rtw89_read32(rtwdev, reg); + val32 = u32_replace_bits(val32, ADDR_CAM_SERCH_RANGE, B_BE_ADDR_CAM_RANGE_MASK); + val32 |= B_BE_ADDR_CAM_EN; + if (mac_idx == RTW89_MAC_0) + val32 |= B_BE_ADDR_CAM_CLR; + rtw89_write32(rtwdev, reg, val32); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_ADDR_CAM_CTRL, mac_idx); + ret = read_poll_timeout_atomic(rtw89_read16, val16, !(val16 & B_BE_ADDR_CAM_CLR), + 1, TRXCFG_WAIT_CNT, false, rtwdev, reg); + if (ret) + rtw89_err(rtwdev, "[ERR]ADDR_CAM reset\n"); + + return ret; +} + +static int rtw89_mac_typ_fltr_opt_be(struct rtw89_dev *rtwdev, + enum rtw89_machdr_frame_type type, + enum rtw89_mac_fwd_target fwd_target, + u8 mac_idx) +{ + u32 reg; + u32 val; + + switch (fwd_target) { + case RTW89_FWD_DONT_CARE: + val = RX_FLTR_FRAME_DROP_BE; + break; + case RTW89_FWD_TO_HOST: + case RTW89_FWD_TO_WLAN_CPU: + val = RX_FLTR_FRAME_ACCEPT_BE; + break; + default: + rtw89_err(rtwdev, "[ERR]set rx filter fwd target err\n"); + return -EINVAL; + } + + switch (type) { + case RTW89_MGNT: + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_MGNT_FLTR, mac_idx); + break; + case RTW89_CTRL: + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CTRL_FLTR, mac_idx); + break; + case RTW89_DATA: + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_DATA_FLTR, mac_idx); + break; + default: + rtw89_err(rtwdev, "[ERR]set rx filter type err\n"); + return -EINVAL; + } + rtw89_write32(rtwdev, reg, val); + + return 0; +} + +static int rx_fltr_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 reg; + u32 val; + + rtw89_mac_typ_fltr_opt_be(rtwdev, RTW89_MGNT, RTW89_FWD_TO_HOST, mac_idx); + rtw89_mac_typ_fltr_opt_be(rtwdev, RTW89_CTRL, RTW89_FWD_TO_HOST, mac_idx); + rtw89_mac_typ_fltr_opt_be(rtwdev, RTW89_DATA, RTW89_FWD_TO_HOST, mac_idx); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_FLTR_OPT, mac_idx); + val = B_BE_A_BC_CAM_MATCH | B_BE_A_UC_CAM_MATCH | B_BE_A_MC | + B_BE_A_BC | B_BE_A_A1_MATCH | B_BE_SNIFFER_MODE | + u32_encode_bits(15, B_BE_UID_FILTER_MASK); + rtw89_write32(rtwdev, reg, val); + u32p_replace_bits(&rtwdev->hal.rx_fltr, 15, B_BE_UID_FILTER_MASK); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PLCP_HDR_FLTR, mac_idx); + val = B_BE_HE_SIGB_CRC_CHK | B_BE_VHT_MU_SIGB_CRC_CHK | + B_BE_VHT_SU_SIGB_CRC_CHK | B_BE_SIGA_CRC_CHK | + B_BE_LSIG_PARITY_CHK_EN | B_BE_CCK_SIG_CHK | B_BE_CCK_CRC_CHK; + rtw89_write16(rtwdev, reg, val); + + return 0; +} + +static int cca_ctrl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + return 0; +} + +static int nav_ctrl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 val32; + u32 reg; + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMAC_NAV_CTL, mac_idx); + + val32 = rtw89_read32(rtwdev, reg); + val32 &= ~B_BE_WMAC_PLCP_UP_NAV_EN; + val32 |= B_BE_WMAC_TF_UP_NAV_EN | B_BE_WMAC_NAV_UPPER_EN; + val32 = u32_replace_bits(val32, NAV_25MS, B_BE_WMAC_NAV_UPPER_MASK); + + rtw89_write32(rtwdev, reg, val32); + + return 0; +} + +static int spatial_reuse_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 reg; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_SR_CTRL, mac_idx); + rtw89_write8_clr(rtwdev, reg, B_BE_SR_EN | B_BE_SR_CTRL_PLCP_EN); + + return 0; +} + +static int tmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 reg; + + rtw89_write32_clr(rtwdev, R_BE_TB_PPDU_CTRL, B_BE_QOSNULL_UPD_MUEDCA_EN); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMTX_TCR_BE_4, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_4XLTF_ZLD_USTIMER_MASK, 0x12); + rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_2XLTF_ZLD_USTIMER_MASK, 0xe); + + return 0; +} + +static int trxptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_rrsr_cfgs *rrsr = chip->rrsr_cfgs; + struct rtw89_hal *hal = &rtwdev->hal; + u32 val32; + u32 reg; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_MAC_LOOPBACK, mac_idx); + val32 = rtw89_read32(rtwdev, reg); + val32 = u32_replace_bits(val32, S_BE_MACLBK_PLCP_DLY_DEF, + B_BE_MACLBK_PLCP_DLY_MASK); + val32 &= ~B_BE_MACLBK_EN; + rtw89_write32(rtwdev, reg, val32); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_0, mac_idx); + val32 = rtw89_read32(rtwdev, reg); + val32 = u32_replace_bits(val32, WMAC_SPEC_SIFS_CCK, + B_BE_WMAC_SPEC_SIFS_CCK_MASK); + val32 = u32_replace_bits(val32, WMAC_SPEC_SIFS_OFDM_1115E, + B_BE_WMAC_SPEC_SIFS_OFDM_MASK); + rtw89_write32(rtwdev, reg, val32); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_LEGACY, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_ACK_BA_RESP_LEGACY_CHK_EDCCA); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_HE, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_ACK_BA_RESP_HE_CHK_EDCCA); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_EHT_LEG_PUNC, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_ACK_BA_EHT_LEG_PUNC_CHK_EDCCA); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RXTRIG_TEST_USER_2, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_RXTRIG_FCSCHK_EN); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_1, mac_idx); + val32 = rtw89_read32(rtwdev, reg); + val32 &= B_BE_FTM_RRSR_RATE_EN_MASK | B_BE_WMAC_RESP_DOPPLEB_BE_EN | + B_BE_WMAC_RESP_DCM_EN | B_BE_WMAC_RESP_REF_RATE_MASK; + rtw89_write32(rtwdev, reg, val32); + rtw89_write32_mask(rtwdev, reg, rrsr->ref_rate.mask, rrsr->ref_rate.data); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_RRSR1, mac_idx); + val32 = rtw89_read32(rtwdev, reg); + val32 &= B_BE_RRSR_RATE_EN_MASK | B_BE_RRSR_CCK_MASK | B_BE_RSC_MASK; + rtw89_write32(rtwdev, reg, val32); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_RRSR0, mac_idx); + val32 = rtw89_read32(rtwdev, reg); + val32 &= B_BE_RRSR_OFDM_MASK | B_BE_RRSR_HT_MASK | B_BE_RRSR_VHT_MASK | + B_BE_RRSR_HE_MASK; + rtw89_write32(rtwdev, reg, val32); + + if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_RRSR1, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_RSC_MASK, 1); + } + + return 0; +} + +static int rst_bacam_be(struct rtw89_dev *rtwdev) +{ + u32 val; + int ret; + + rtw89_write32_mask(rtwdev, R_BE_RESPBA_CAM_CTRL, B_BE_BACAM_RST_MASK, + S_BE_BACAM_RST_ALL); + + ret = read_poll_timeout_atomic(rtw89_read32_mask, val, val == S_BE_BACAM_RST_DONE, + 1, 1000, false, + rtwdev, R_BE_RESPBA_CAM_CTRL, B_BE_BACAM_RST_MASK); + if (ret) + rtw89_err(rtwdev, "[ERR]bacam rst timeout\n"); + + return ret; +} + +#define PLD_RLS_MAX_PG 127 +#define RX_MAX_LEN_UNIT 512 +#define RX_SPEC_MAX_LEN (11454 + RX_MAX_LEN_UNIT) + +static int rmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 rx_min_qta, rx_max_len, rx_max_pg; + u16 val16; + u32 reg; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + if (mac_idx == RTW89_MAC_0) { + ret = rst_bacam_be(rtwdev); + if (ret) + return ret; + } + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_DLK_PROTECT_CTL, mac_idx); + val16 = rtw89_read16(rtwdev, reg); + val16 = u16_replace_bits(val16, TRXCFG_RMAC_DATA_TO, B_BE_RX_DLK_DATA_TIME_MASK); + val16 = u16_replace_bits(val16, TRXCFG_RMAC_CCA_TO, B_BE_RX_DLK_CCA_TIME_MASK); + val16 |= B_BE_RX_DLK_RST_EN; + rtw89_write16(rtwdev, reg, val16); + + if (mac_idx == RTW89_MAC_0) + rx_min_qta = rtwdev->mac.dle_info.c0_rx_qta; + else + rx_min_qta = rtwdev->mac.dle_info.c1_rx_qta; + rx_max_pg = min_t(u32, rx_min_qta, PLD_RLS_MAX_PG); + rx_max_len = rx_max_pg * rtwdev->mac.dle_info.ple_pg_size; + rx_max_len = min_t(u32, rx_max_len, RX_SPEC_MAX_LEN); + rx_max_len /= RX_MAX_LEN_UNIT; + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_FLTR_OPT, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_RX_MPDU_MAX_LEN_MASK, rx_max_len); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PLCP_HDR_FLTR, mac_idx); + rtw89_write8_clr(rtwdev, reg, B_BE_VHT_SU_SIGB_CRC_CHK); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RCR, mac_idx); + rtw89_write16_set(rtwdev, reg, B_BE_BUSY_CHKSN); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_PLCP_EXT_OPTION_1, mac_idx); + rtw89_write16_set(rtwdev, reg, B_BE_PLCP_SU_PSDU_LEN_SRC); + + return 0; +} + +static int resp_pktctl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + struct rtw89_mac_dle_rsvd_qt_cfg qt_cfg; + enum rtw89_mac_dle_rsvd_qt_type type; + u32 reg; + int ret; + + if (mac_idx == RTW89_MAC_1) + type = DLE_RSVD_QT_B1_CSI; + else + type = DLE_RSVD_QT_B0_CSI; + + ret = rtw89_mac_get_dle_rsvd_qt_cfg(rtwdev, type, &qt_cfg); + if (ret) { + rtw89_err(rtwdev, "get dle rsvd qt %d cfg fail %d\n", type, ret); + return ret; + } + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RESP_CSI_RESERVED_PAGE, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_CSI_RESERVED_START_PAGE_MASK, qt_cfg.pktid); + rtw89_write32_mask(rtwdev, reg, B_BE_CSI_RESERVED_PAGE_NUM_MASK, qt_cfg.pg_num); + + return 0; +} + +static int cmac_com_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 val32; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + if (mac_idx == RTW89_MAC_0) { + val32 = rtw89_read32(rtwdev, R_BE_TX_SUB_BAND_VALUE); + val32 = u32_replace_bits(val32, S_BE_TXSB_20M_8, B_BE_TXSB_20M_MASK); + val32 = u32_replace_bits(val32, S_BE_TXSB_40M_4, B_BE_TXSB_40M_MASK); + val32 = u32_replace_bits(val32, S_BE_TXSB_80M_2, B_BE_TXSB_80M_MASK); + val32 = u32_replace_bits(val32, S_BE_TXSB_160M_1, B_BE_TXSB_160M_MASK); + rtw89_write32(rtwdev, R_BE_TX_SUB_BAND_VALUE, val32); + } else { + val32 = rtw89_read32(rtwdev, R_BE_TX_SUB_BAND_VALUE_C1); + val32 = u32_replace_bits(val32, S_BE_TXSB_20M_2, B_BE_TXSB_20M_MASK); + val32 = u32_replace_bits(val32, S_BE_TXSB_40M_1, B_BE_TXSB_40M_MASK); + val32 = u32_replace_bits(val32, S_BE_TXSB_80M_0, B_BE_TXSB_80M_MASK); + val32 = u32_replace_bits(val32, S_BE_TXSB_160M_0, B_BE_TXSB_160M_MASK); + rtw89_write32(rtwdev, R_BE_TX_SUB_BAND_VALUE_C1, val32); + } + + return 0; +} + +static int ptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 val32; + u8 val8; + u32 reg; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + if (is_qta_poh(rtwdev)) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_SIFS_SETTING, mac_idx); + val32 = rtw89_read32(rtwdev, reg); + val32 = u32_replace_bits(val32, S_AX_CTS2S_TH_1K, + B_BE_HW_CTS2SELF_PKT_LEN_TH_MASK); + val32 = u32_replace_bits(val32, S_AX_CTS2S_TH_SEC_256B, + B_BE_HW_CTS2SELF_PKT_LEN_TH_TWW_MASK); + val32 |= B_BE_HW_CTS2SELF_EN; + rtw89_write32(rtwdev, reg, val32); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_FSM_MON, mac_idx); + val32 = rtw89_read32(rtwdev, reg); + val32 = u32_replace_bits(val32, S_AX_PTCL_TO_2MS, + B_BE_PTCL_TX_ARB_TO_THR_MASK); + val32 &= ~B_BE_PTCL_TX_ARB_TO_MODE; + rtw89_write32(rtwdev, reg, val32); + } + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_COMMON_SETTING_0, mac_idx); + val8 = rtw89_read8(rtwdev, reg); + val8 |= B_BE_CMAC_TX_MODE_0 | B_BE_CMAC_TX_MODE_1; + val8 &= ~(B_BE_PTCL_TRIGGER_SS_EN_0 | + B_BE_PTCL_TRIGGER_SS_EN_1 | + B_BE_PTCL_TRIGGER_SS_EN_UL); + rtw89_write8(rtwdev, reg, val8); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_AMPDU_AGG_LIMIT, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_AMPDU_MAX_TIME_MASK, AMPDU_MAX_TIME); + + return 0; +} + +static int cmac_dma_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 val32; + u32 reg; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_CTRL_1, mac_idx); + + val32 = rtw89_read32(rtwdev, reg); + val32 = u32_replace_bits(val32, WLCPU_RXCH2_QID, + B_BE_RXDMA_TXRPT_QUEUE_ID_SW_MASK); + val32 = u32_replace_bits(val32, WLCPU_RXCH2_QID, + B_BE_RXDMA_F2PCMDRPT_QUEUE_ID_SW_MASK); + rtw89_write32(rtwdev, reg, val32); + + return 0; +} + +static int cmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + int ret; + + ret = scheduler_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d SCH init %d\n", mac_idx, ret); + return ret; + } + + ret = addr_cam_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d ADDR_CAM reset %d\n", mac_idx, + ret); + return ret; + } + + ret = rx_fltr_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d RX filter init %d\n", mac_idx, + ret); + return ret; + } + + ret = cca_ctrl_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d CCA CTRL init %d\n", mac_idx, + ret); + return ret; + } + + ret = nav_ctrl_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d NAV CTRL init %d\n", mac_idx, + ret); + return ret; + } + + ret = spatial_reuse_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d Spatial Reuse init %d\n", + mac_idx, ret); + return ret; + } + + ret = tmac_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d TMAC init %d\n", mac_idx, ret); + return ret; + } + + ret = trxptcl_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d TRXPTCL init %d\n", mac_idx, ret); + return ret; + } + + ret = rmac_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d RMAC init %d\n", mac_idx, ret); + return ret; + } + + ret = resp_pktctl_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d resp pktctl init %d\n", mac_idx, ret); + return ret; + } + + ret = cmac_com_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d Com init %d\n", mac_idx, ret); + return ret; + } + + ret = ptcl_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d PTCL init %d\n", mac_idx, ret); + return ret; + } + + ret = cmac_dma_init_be(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d DMA init %d\n", mac_idx, ret); + return ret; + } + + return ret; +} + +static int tx_idle_poll_band_be(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 reg; + u8 val8; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_TX_CTN_SEL, mac_idx); + + ret = read_poll_timeout_atomic(rtw89_read8, val8, !(val8 & B_BE_PTCL_BUSY), + 30, 66000, false, rtwdev, reg); + + return ret; +} + +static int dle_buf_req_be(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id) +{ + u32 val, reg; + int ret; + + reg = wd ? R_BE_WD_BUF_REQ : R_BE_PL_BUF_REQ; + val = buf_len; + val |= B_BE_WD_BUF_REQ_EXEC; + rtw89_write32(rtwdev, reg, val); + + reg = wd ? R_BE_WD_BUF_STATUS : R_BE_PL_BUF_STATUS; + + ret = read_poll_timeout(rtw89_read32, val, val & B_BE_WD_BUF_STAT_DONE, + 1, 2000, false, rtwdev, reg); + if (ret) + return ret; + + *pkt_id = u32_get_bits(val, B_BE_WD_BUF_STAT_PKTID_MASK); + if (*pkt_id == S_WD_BUF_STAT_PKTID_INVALID) + return -ENOENT; + + return 0; +} + +static int set_cpuio_be(struct rtw89_dev *rtwdev, + struct rtw89_cpuio_ctrl *ctrl_para, bool wd) +{ + u32 val_op0, val_op1, val_op2, val_op3; + u32 val, cmd_type, reg; + int ret; + + cmd_type = ctrl_para->cmd_type; + + reg = wd ? R_BE_WD_CPUQ_OP_3 : R_BE_PL_CPUQ_OP_3; + val_op3 = u32_replace_bits(0, ctrl_para->start_pktid, + B_BE_WD_CPUQ_OP_STRT_PKTID_MASK); + val_op3 = u32_replace_bits(val_op3, ctrl_para->end_pktid, + B_BE_WD_CPUQ_OP_END_PKTID_MASK); + rtw89_write32(rtwdev, reg, val_op3); + + reg = wd ? R_BE_WD_CPUQ_OP_1 : R_BE_PL_CPUQ_OP_1; + val_op1 = u32_replace_bits(0, ctrl_para->src_pid, + B_BE_WD_CPUQ_OP_SRC_PID_MASK); + val_op1 = u32_replace_bits(val_op1, ctrl_para->src_qid, + B_BE_WD_CPUQ_OP_SRC_QID_MASK); + val_op1 = u32_replace_bits(val_op1, ctrl_para->macid, + B_BE_WD_CPUQ_OP_SRC_MACID_MASK); + rtw89_write32(rtwdev, reg, val_op1); + + reg = wd ? R_BE_WD_CPUQ_OP_2 : R_BE_PL_CPUQ_OP_2; + val_op2 = u32_replace_bits(0, ctrl_para->dst_pid, + B_BE_WD_CPUQ_OP_DST_PID_MASK); + val_op2 = u32_replace_bits(val_op2, ctrl_para->dst_qid, + B_BE_WD_CPUQ_OP_DST_QID_MASK); + val_op2 = u32_replace_bits(val_op2, ctrl_para->macid, + B_BE_WD_CPUQ_OP_DST_MACID_MASK); + rtw89_write32(rtwdev, reg, val_op2); + + reg = wd ? R_BE_WD_CPUQ_OP_0 : R_BE_PL_CPUQ_OP_0; + val_op0 = u32_replace_bits(0, cmd_type, + B_BE_WD_CPUQ_OP_CMD_TYPE_MASK); + val_op0 = u32_replace_bits(val_op0, ctrl_para->pkt_num, + B_BE_WD_CPUQ_OP_PKTNUM_MASK); + val_op0 |= B_BE_WD_CPUQ_OP_EXEC; + rtw89_write32(rtwdev, reg, val_op0); + + reg = wd ? R_BE_WD_CPUQ_OP_STATUS : R_BE_PL_CPUQ_OP_STATUS; + + ret = read_poll_timeout(rtw89_read32, val, val & B_BE_WD_CPUQ_OP_STAT_DONE, + 1, 2000, false, rtwdev, reg); + if (ret) { + rtw89_err(rtwdev, "[ERR]set cpuio wd timeout\n"); + rtw89_err(rtwdev, "[ERR]op_0=0x%X, op_1=0x%X, op_2=0x%X\n", + val_op0, val_op1, val_op2); + return ret; + } + + if (cmd_type == CPUIO_OP_CMD_GET_NEXT_PID || + cmd_type == CPUIO_OP_CMD_GET_1ST_PID) + ctrl_para->pktid = u32_get_bits(val, B_BE_WD_CPUQ_OP_PKTID_MASK); + + return 0; +} + +static int preload_init_be(struct rtw89_dev *rtwdev, u8 mac_idx, + enum rtw89_qta_mode mode) +{ + u32 max_preld_size, min_rsvd_size; + u32 val32; + u32 reg; + + max_preld_size = mac_idx == RTW89_MAC_0 ? + PRELD_B0_ENT_NUM : PRELD_B1_ENT_NUM; + max_preld_size *= PRELD_AMSDU_SIZE; + + reg = mac_idx == RTW89_MAC_0 ? R_BE_TXPKTCTL_B0_PRELD_CFG0 : + R_BE_TXPKTCTL_B1_PRELD_CFG0; + val32 = rtw89_read32(rtwdev, reg); + val32 = u32_replace_bits(val32, max_preld_size, B_BE_B0_PRELD_USEMAXSZ_MASK); + val32 |= B_BE_B0_PRELD_FEN; + rtw89_write32(rtwdev, reg, val32); + + min_rsvd_size = PRELD_AMSDU_SIZE; + reg = mac_idx == RTW89_MAC_0 ? R_BE_TXPKTCTL_B0_PRELD_CFG1 : + R_BE_TXPKTCTL_B1_PRELD_CFG1; + val32 = rtw89_read32(rtwdev, reg); + val32 = u32_replace_bits(val32, PRELD_NEXT_WND, B_BE_B0_PRELD_NXT_TXENDWIN_MASK); + val32 = u32_replace_bits(val32, min_rsvd_size, B_BE_B0_PRELD_NXT_RSVMINSZ_MASK); + rtw89_write32(rtwdev, reg, val32); + + return 0; +} + +static int dbcc_bb_ctrl_be(struct rtw89_dev *rtwdev, bool bb1_en) +{ + return 0; +} + +static int enable_imr_be(struct rtw89_dev *rtwdev, u8 mac_idx, + enum rtw89_mac_hwmod_sel sel) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_imr_table *table; + const struct rtw89_reg_imr *reg; + u32 addr; + u32 val; + int i; + + if (sel == RTW89_DMAC_SEL) + table = chip->imr_dmac_table; + else if (sel == RTW89_CMAC_SEL) + table = chip->imr_cmac_table; + else + return -EINVAL; + + for (i = 0; i < table->n_regs; i++) { + reg = &table->regs[i]; + addr = rtw89_mac_reg_by_idx(rtwdev, reg->addr, mac_idx); + + val = rtw89_read32(rtwdev, addr); + val &= ~reg->clr; + val |= reg->set; + rtw89_write32(rtwdev, addr, val); + } + + return 0; +} + +static void err_imr_ctrl_be(struct rtw89_dev *rtwdev, bool en) +{ + u32 v32_dmac = en ? DMAC_ERR_IMR_EN : DMAC_ERR_IMR_DIS; + u32 v32_cmac0 = en ? CMAC0_ERR_IMR_EN : CMAC0_ERR_IMR_DIS; + u32 v32_cmac1 = en ? CMAC1_ERR_IMR_EN : CMAC1_ERR_IMR_DIS; + + v32_dmac &= ~B_BE_DMAC_NOTX_ERR_INT_EN; + + rtw89_write32(rtwdev, R_BE_DMAC_ERR_IMR, v32_dmac); + rtw89_write32(rtwdev, R_BE_CMAC_ERR_IMR, v32_cmac0); + + if (rtwdev->dbcc_en) + rtw89_write32(rtwdev, R_BE_CMAC_ERR_IMR_C1, v32_cmac1); +} + +static int band1_enable_be(struct rtw89_dev *rtwdev) +{ + int ret; + + ret = tx_idle_poll_band_be(rtwdev, RTW89_MAC_0); + if (ret) { + rtw89_err(rtwdev, "[ERR]tx idle poll %d\n", ret); + return ret; + } + + ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode); + if (ret) { + rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret); + return ret; + } + + ret = preload_init_be(rtwdev, RTW89_MAC_1, rtwdev->mac.qta_mode); + if (ret) { + rtw89_err(rtwdev, "[ERR]preload init B1 %d\n", ret); + return ret; + } + + ret = cmac_func_en_be(rtwdev, RTW89_MAC_1, true); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d func en %d\n", RTW89_MAC_1, ret); + return ret; + } + + ret = cmac_init_be(rtwdev, RTW89_MAC_1); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d init %d\n", RTW89_MAC_1, ret); + return ret; + } + + ret = dbcc_bb_ctrl_be(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "[ERR]enable bb 1 %d\n", ret); + return ret; + } + + ret = enable_imr_be(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL); + if (ret) { + rtw89_err(rtwdev, "[ERR] enable CMAC1 IMR %d\n", ret); + return ret; + } + + return 0; +} + +static int band1_disable_be(struct rtw89_dev *rtwdev) +{ + int ret; + + ret = dbcc_bb_ctrl_be(rtwdev, false); + if (ret) { + rtw89_err(rtwdev, "[ERR]disable bb 1 %d\n", ret); + return ret; + } + + ret = cmac_func_en_be(rtwdev, RTW89_MAC_1, false); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d func dis %d\n", RTW89_MAC_1, ret); + return ret; + } + + ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode); + if (ret) { + rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret); + return ret; + } + + return 0; +} + +static int dbcc_enable_be(struct rtw89_dev *rtwdev, bool enable) +{ + int ret; + + if (enable) { + ret = band1_enable_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR] band1_enable %d\n", ret); + return ret; + } + + if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) { + ret = rtw89_fw_h2c_notify_dbcc(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "%s:[ERR]notfify dbcc1 fail %d\n", + __func__, ret); + return ret; + } + } + } else { + if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) { + ret = rtw89_fw_h2c_notify_dbcc(rtwdev, false); + if (ret) { + rtw89_err(rtwdev, "%s:[ERR]notfify dbcc1 fail %d\n", + __func__, ret); + return ret; + } + } + + ret = band1_disable_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR] band1_disable %d\n", ret); + return ret; + } + } + + return 0; +} + +static int set_host_rpr_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + u32 mode; + u32 fltr; + bool poh; + + poh = is_qta_poh(rtwdev); + + if (poh) { + mode = RTW89_RPR_MODE_POH; + fltr = S_BE_WDRLS_FLTR_TXOK | S_BE_WDRLS_FLTR_RTYLMT | + S_BE_WDRLS_FLTR_LIFTIM | S_BE_WDRLS_FLTR_MACID; + } else { + mode = RTW89_RPR_MODE_STF; + fltr = 0; + } + + rtw89_write32_mask(rtwdev, R_BE_WDRLS_CFG, B_BE_WDRLS_MODE_MASK, mode); + + val32 = rtw89_read32(rtwdev, R_BE_RLSRPT0_CFG1); + val32 = u32_replace_bits(val32, fltr, B_BE_RLSRPT0_FLTR_MAP_MASK); + val32 = u32_replace_bits(val32, 30, B_BE_RLSRPT0_AGGNUM_MASK); + val32 = u32_replace_bits(val32, 255, B_BE_RLSRPT0_TO_MASK); + rtw89_write32(rtwdev, R_BE_RLSRPT0_CFG1, val32); + + return 0; +} + +static int trx_init_be(struct rtw89_dev *rtwdev) +{ + enum rtw89_qta_mode qta_mode = rtwdev->mac.qta_mode; + int ret; + + ret = dmac_init_be(rtwdev, 0); + if (ret) { + rtw89_err(rtwdev, "[ERR]DMAC init %d\n", ret); + return ret; + } + + ret = cmac_init_be(rtwdev, 0); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d init %d\n", 0, ret); + return ret; + } + + if (rtw89_mac_is_qta_dbcc(rtwdev, qta_mode)) { + ret = dbcc_enable_be(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "[ERR]dbcc_enable init %d\n", ret); + return ret; + } + } + + ret = enable_imr_be(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); + if (ret) { + rtw89_err(rtwdev, "[ERR] enable DMAC IMR %d\n", ret); + return ret; + } + + ret = enable_imr_be(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL); + if (ret) { + rtw89_err(rtwdev, "[ERR] to enable CMAC0 IMR %d\n", ret); + return ret; + } + + err_imr_ctrl_be(rtwdev, true); + + ret = set_host_rpr_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR] set host rpr %d\n", ret); + return ret; + } + + return 0; +} + static bool rtw89_mac_get_txpwr_cr_be(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 reg_base, u32 *cr) @@ -404,6 +1917,299 @@ static void rtw89_mac_bf_assoc_be(struct rtw89_dev *rtwdev, } } +static void dump_err_status_dispatcher_be(struct rtw89_dev *rtwdev) +{ + rtw89_info(rtwdev, "R_BE_DISP_HOST_IMR=0x%08x ", + rtw89_read32(rtwdev, R_BE_DISP_HOST_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR1)); + rtw89_info(rtwdev, "R_BE_DISP_CPU_IMR=0x%08x ", + rtw89_read32(rtwdev, R_BE_DISP_CPU_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR2=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR2)); + rtw89_info(rtwdev, "R_BE_DISP_OTHER_IMR=0x%08x ", + rtw89_read32(rtwdev, R_BE_DISP_OTHER_IMR)); + rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR0=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR0)); +} + +static void rtw89_mac_dump_qta_lost_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_mac_dle_dfi_qempty qempty; + struct rtw89_mac_dle_dfi_quota quota; + struct rtw89_mac_dle_dfi_ctrl ctrl; + u32 val, not_empty, i; + int ret; + + qempty.dle_type = DLE_CTRL_TYPE_PLE; + qempty.grpsel = 0; + qempty.qempty = ~(u32)0; + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "DLE group0 empty: 0x%x\n", qempty.qempty); + + for (not_empty = ~qempty.qempty, i = 0; not_empty != 0; not_empty >>= 1, i++) { + if (!(not_empty & BIT(0))) + continue; + ctrl.type = DLE_CTRL_TYPE_PLE; + ctrl.target = DLE_DFI_TYPE_QLNKTBL; + ctrl.addr = (QLNKTBL_ADDR_INFO_SEL_0 ? QLNKTBL_ADDR_INFO_SEL : 0) | + u32_encode_bits(i, QLNKTBL_ADDR_TBL_IDX_MASK); + ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "qidx%d pktcnt = %d\n", i, + u32_get_bits(ctrl.out_data, + QLNKTBL_DATA_SEL1_PKT_CNT_MASK)); + } + + quota.dle_type = DLE_CTRL_TYPE_PLE; + quota.qtaid = 6; + ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, "a); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "quota6 rsv/use: 0x%x/0x%x\n", + quota.rsv_pgnum, quota.use_pgnum); + + val = rtw89_read32(rtwdev, R_BE_PLE_QTA6_CFG); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]min_pgnum=0x%x\n", + u32_get_bits(val, B_BE_PLE_Q6_MIN_SIZE_MASK)); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]max_pgnum=0x%x\n", + u32_get_bits(val, B_BE_PLE_Q6_MAX_SIZE_MASK)); + val = rtw89_read32(rtwdev, R_BE_RX_FLTR_OPT); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]B_BE_RX_MPDU_MAX_LEN=0x%x\n", + u32_get_bits(val, B_BE_RX_MPDU_MAX_LEN_MASK)); + rtw89_info(rtwdev, "R_BE_RSP_CHK_SIG=0x%08x\n", + rtw89_read32(rtwdev, R_BE_RSP_CHK_SIG)); + rtw89_info(rtwdev, "R_BE_TRXPTCL_RESP_0=0x%08x\n", + rtw89_read32(rtwdev, R_BE_TRXPTCL_RESP_0)); + + if (!rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL)) { + quota.dle_type = DLE_CTRL_TYPE_PLE; + quota.qtaid = 7; + ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, "a); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "quota7 rsv/use: 0x%x/0x%x\n", + quota.rsv_pgnum, quota.use_pgnum); + + val = rtw89_read32(rtwdev, R_BE_PLE_QTA7_CFG); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]min_pgnum=0x%x\n", + u32_get_bits(val, B_BE_PLE_Q7_MIN_SIZE_MASK)); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]max_pgnum=0x%x\n", + u32_get_bits(val, B_BE_PLE_Q7_MAX_SIZE_MASK)); + val = rtw89_read32(rtwdev, R_BE_RX_FLTR_OPT_C1); + rtw89_info(rtwdev, "[PLE][CMAC1_RX]B_BE_RX_MPDU_MAX_LEN=0x%x\n", + u32_get_bits(val, B_BE_RX_MPDU_MAX_LEN_MASK)); + rtw89_info(rtwdev, "R_BE_RSP_CHK_SIG_C1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_RSP_CHK_SIG_C1)); + rtw89_info(rtwdev, "R_BE_TRXPTCL_RESP_0_C1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_TRXPTCL_RESP_0_C1)); + } + + rtw89_info(rtwdev, "R_BE_DLE_EMPTY0=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DLE_EMPTY0)); + rtw89_info(rtwdev, "R_BE_DLE_EMPTY1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_DLE_EMPTY1)); + + dump_err_status_dispatcher_be(rtwdev); +} + +static void rtw89_mac_dump_cmac_err_status_be(struct rtw89_dev *rtwdev, + u8 band) +{ + u32 offset = 0; + u32 cmac_err; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, band, RTW89_CMAC_SEL); + if (ret) { + rtw89_info(rtwdev, "[CMAC] : CMAC%d not enabled\n", band); + return; + } + + if (band) + offset = RTW89_MAC_BE_BAND_REG_OFFSET; + + cmac_err = rtw89_read32(rtwdev, R_BE_CMAC_ERR_ISR + offset); + rtw89_info(rtwdev, "R_BE_CMAC_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_CMAC_ERR_ISR + offset)); + rtw89_info(rtwdev, "R_BE_CMAC_FUNC_EN [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_CMAC_FUNC_EN + offset)); + rtw89_info(rtwdev, "R_BE_CK_EN [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_CK_EN + offset)); + + if (cmac_err & B_BE_SCHEDULE_TOP_ERR_IND) { + rtw89_info(rtwdev, "R_BE_SCHEDULE_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_SCHEDULE_ERR_IMR + offset)); + rtw89_info(rtwdev, "R_BE_SCHEDULE_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_SCHEDULE_ERR_ISR + offset)); + } + + if (cmac_err & B_BE_PTCL_TOP_ERR_IND) { + rtw89_info(rtwdev, "R_BE_PTCL_IMR0 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PTCL_IMR0 + offset)); + rtw89_info(rtwdev, "R_BE_PTCL_ISR0 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PTCL_ISR0 + offset)); + rtw89_info(rtwdev, "R_BE_PTCL_IMR1 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PTCL_IMR1 + offset)); + rtw89_info(rtwdev, "R_BE_PTCL_ISR1 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PTCL_ISR1 + offset)); + } + + if (cmac_err & B_BE_DMA_TOP_ERR_IND) { + rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG_IMR + offset)); + rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG + offset)); + rtw89_info(rtwdev, "R_BE_TX_ERROR_FLAG_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TX_ERROR_FLAG_IMR + offset)); + rtw89_info(rtwdev, "R_BE_TX_ERROR_FLAG [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TX_ERROR_FLAG + offset)); + rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG_IMR_1 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG_IMR_1 + offset)); + rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG_1 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG_1 + offset)); + } + + if (cmac_err & B_BE_PHYINTF_ERR_IND) { + rtw89_info(rtwdev, "R_BE_PHYINFO_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PHYINFO_ERR_IMR_V1 + offset)); + rtw89_info(rtwdev, "R_BE_PHYINFO_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_PHYINFO_ERR_ISR + offset)); + } + + if (cmac_err & B_AX_TXPWR_CTRL_ERR_IND) { + rtw89_info(rtwdev, "R_BE_TXPWR_ERR_FLAG [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TXPWR_ERR_FLAG + offset)); + rtw89_info(rtwdev, "R_BE_TXPWR_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TXPWR_ERR_IMR + offset)); + } + + if (cmac_err & (B_BE_WMAC_RX_ERR_IND | B_BE_WMAC_TX_ERR_IND | + B_BE_WMAC_RX_IDLETO_IDCT | B_BE_PTCL_TX_IDLETO_IDCT)) { + rtw89_info(rtwdev, "R_BE_DBGSEL_TRXPTCL [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_DBGSEL_TRXPTCL + offset)); + rtw89_info(rtwdev, "R_BE_TRXPTCL_ERROR_INDICA_MASK [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TRXPTCL_ERROR_INDICA_MASK + offset)); + rtw89_info(rtwdev, "R_BE_TRXPTCL_ERROR_INDICA [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_TRXPTCL_ERROR_INDICA + offset)); + rtw89_info(rtwdev, "R_BE_RX_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERR_IMR + offset)); + rtw89_info(rtwdev, "R_BE_RX_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_RX_ERR_ISR + offset)); + } + + rtw89_info(rtwdev, "R_BE_CMAC_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_BE_CMAC_ERR_IMR + offset)); +} + +static void rtw89_mac_dump_err_status_be(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err) +{ + if (err != MAC_AX_ERR_L1_ERR_DMAC && + err != MAC_AX_ERR_L0_PROMOTE_TO_L1 && + err != MAC_AX_ERR_L0_ERR_CMAC0 && + err != MAC_AX_ERR_L0_ERR_CMAC1 && + err != MAC_AX_ERR_RXI300) + return; + + rtw89_info(rtwdev, "--->\nerr=0x%x\n", err); + rtw89_info(rtwdev, "R_BE_SER_DBG_INFO=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_DBG_INFO)); + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT)); + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT1)); + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT2=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT2)); + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT3=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT3)); + if (!rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL)) { + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT_C1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT_C1)); + rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT1_C1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT1_C1)); + } + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_0=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_0)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_1=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_1)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_2=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_2)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_3=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_3)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_4=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_4)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_5=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_5)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_6=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_6)); + rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_7=0x%08x\n", + rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_7)); + + rtw89_mac_dump_dmac_err_status(rtwdev); + rtw89_mac_dump_cmac_err_status_be(rtwdev, RTW89_MAC_0); + rtw89_mac_dump_cmac_err_status_be(rtwdev, RTW89_MAC_1); + + rtwdev->hci.ops->dump_err_status(rtwdev); + + if (err == MAC_AX_ERR_L0_PROMOTE_TO_L1) + rtw89_mac_dump_l0_to_l1(rtwdev, err); + + rtw89_info(rtwdev, "<---\n"); +} + +static bool mac_is_txq_empty_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_mac_dle_dfi_qempty qempty; + u32 val32, msk32; + u32 grpnum; + int ret; + int i; + + grpnum = rtwdev->chip->wde_qempty_acq_grpnum; + qempty.dle_type = DLE_CTRL_TYPE_WDE; + + for (i = 0; i < grpnum; i++) { + qempty.grpsel = i; + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); + if (ret) { + rtw89_warn(rtwdev, + "%s: failed to dle dfi acq empty: %d\n", + __func__, ret); + return false; + } + + /* Each acq group contains 32 queues (8 macid * 4 acq), + * but here, we can simply check if all bits are set. + */ + if (qempty.qempty != MASKDWORD) + return false; + } + + qempty.grpsel = rtwdev->chip->wde_qempty_mgq_grpsel; + ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty); + if (ret) { + rtw89_warn(rtwdev, "%s: failed to dle dfi mgq empty: %d\n", + __func__, ret); + return false; + } + + msk32 = B_CMAC0_MGQ_NORMAL_BE | B_CMAC1_MGQ_NORMAL_BE; + if ((qempty.qempty & msk32) != msk32) + return false; + + msk32 = B_BE_WDE_EMPTY_QUE_OTHERS; + val32 = rtw89_read32(rtwdev, R_BE_DLE_EMPTY0); + return (val32 & msk32) == msk32; +} + const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .band1_offset = RTW89_MAC_BE_BAND_REG_OFFSET, .filter_model_addr = R_BE_FILTER_MODEL_ADDR, @@ -423,13 +2229,44 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { B_BE_BFMEE_HE_NDPA_EN | B_BE_BFMEE_EHT_NDPA_EN, }, + .check_mac_en = rtw89_mac_check_mac_en_be, + .sys_init = sys_init_be, + .trx_init = trx_init_be, + .hci_func_en = rtw89_mac_hci_func_en_be, + .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_be, + .dle_func_en = dle_func_en_be, + .dle_clk_en = dle_clk_en_be, .bf_assoc = rtw89_mac_bf_assoc_be, + .typ_fltr_opt = rtw89_mac_typ_fltr_opt_be, + + .dle_mix_cfg = dle_mix_cfg_be, + .chk_dle_rdy = chk_dle_rdy_be, + .dle_buf_req = dle_buf_req_be, + .hfc_func_en = hfc_func_en_be, + .hfc_h2c_cfg = hfc_h2c_cfg_be, + .hfc_mix_cfg = hfc_mix_cfg_be, + .hfc_get_mix_info = hfc_get_mix_info_be, + .wde_quota_cfg = wde_quota_cfg_be, + .ple_quota_cfg = ple_quota_cfg_be, + .set_cpuio = set_cpuio_be, + .disable_cpu = rtw89_mac_disable_cpu_be, .fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be, .fwdl_get_status = fwdl_get_status_be, .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_be, + .parse_efuse_map = rtw89_parse_efuse_map_be, + .parse_phycap_map = rtw89_parse_phycap_map_be, + .cnv_efuse_state = rtw89_cnv_efuse_state_be, .get_txpwr_cr = rtw89_mac_get_txpwr_cr_be, + + .write_xtal_si = rtw89_mac_write_xtal_si_be, + .read_xtal_si = rtw89_mac_read_xtal_si_be, + + .dump_qta_lost = rtw89_mac_dump_qta_lost_be, + .dump_err_status = rtw89_mac_dump_err_status_be, + + .is_txq_empty = mac_is_txq_empty_be, }; EXPORT_SYMBOL(rtw89_mac_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 14ddb0d39e..cb03474f81 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -19,28 +19,25 @@ MODULE_PARM_DESC(disable_clkreq, "Set Y to disable PCI clkreq support"); MODULE_PARM_DESC(disable_aspm_l1, "Set Y to disable PCI ASPM L1 support"); MODULE_PARM_DESC(disable_aspm_l1ss, "Set Y to disable PCI L1SS support"); -static int rtw89_pci_rst_bdram_pcie(struct rtw89_dev *rtwdev) +static int rtw89_pci_rst_bdram_ax(struct rtw89_dev *rtwdev) { u32 val; int ret; - rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1, - rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) | B_AX_RST_BDRAM); + rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RST_BDRAM); ret = read_poll_timeout_atomic(rtw89_read32, val, !(val & B_AX_RST_BDRAM), 1, RTW89_PCI_POLL_BDRAM_RST_CNT, false, rtwdev, R_AX_PCIE_INIT_CFG1); - if (ret) - return -EBUSY; - - return 0; + return ret; } static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev, struct rtw89_pci_dma_ring *bd_ring, u32 cur_idx, bool tx) { + const struct rtw89_pci_info *info = rtwdev->pci_info; u32 cnt, cur_rp, wp, rp, len; rp = bd_ring->rp; @@ -48,10 +45,14 @@ static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev, len = bd_ring->len; cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx); - if (tx) + if (tx) { cnt = cur_rp >= rp ? cur_rp - rp : len - (rp - cur_rp); - else + } else { + if (info->rx_ring_eq_is_full) + wp += 1; + cnt = cur_rp >= wp ? cur_rp - wp : len - (wp - cur_rp); + } bd_ring->rp = cur_rp; @@ -154,8 +155,8 @@ static void rtw89_pci_sync_skb_for_device(struct rtw89_dev *rtwdev, DMA_FROM_DEVICE); } -static int rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev, - struct sk_buff *skb) +static void rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev, + struct sk_buff *skb) { struct rtw89_pci_rxbd_info *rxbd_info; struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb); @@ -165,10 +166,58 @@ static int rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev, rx_info->ls = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_LS); rx_info->len = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_WRITE_SIZE); rx_info->tag = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_TAG); +} + +static int rtw89_pci_validate_rx_tag(struct rtw89_dev *rtwdev, + struct rtw89_pci_rx_ring *rx_ring, + struct sk_buff *skb) +{ + struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb); + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 target_rx_tag; + + if (!info->check_rx_tag) + return 0; + + /* valid range is 1 ~ 0x1FFF */ + if (rx_ring->target_rx_tag == 0) + target_rx_tag = 1; + else + target_rx_tag = rx_ring->target_rx_tag; + + if (rx_info->tag != target_rx_tag) { + rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "mismatch RX tag 0x%x 0x%x\n", + rx_info->tag, target_rx_tag); + return -EAGAIN; + } return 0; } +static +int rtw89_pci_sync_skb_for_device_and_validate_rx_info(struct rtw89_dev *rtwdev, + struct rtw89_pci_rx_ring *rx_ring, + struct sk_buff *skb) +{ + struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb); + int rx_tag_retry = 100; + int ret; + + do { + rtw89_pci_sync_skb_for_cpu(rtwdev, skb); + rtw89_pci_rxbd_info_update(rtwdev, skb); + + ret = rtw89_pci_validate_rx_tag(rtwdev, rx_ring, skb); + if (ret != -EAGAIN) + break; + } while (rx_tag_retry--); + + /* update target rx_tag for next RX */ + rx_ring->target_rx_tag = rx_info->tag + 1; + + return ret; +} + static void rtw89_pci_ctrl_txdma_ch_pcie(struct rtw89_dev *rtwdev, bool enable) { const struct rtw89_pci_info *info = rtwdev->pci_info; @@ -226,6 +275,21 @@ rtw89_skb_put_rx_data(struct rtw89_dev *rtwdev, bool fs, bool ls, return true; } +static u32 rtw89_pci_get_rx_skb_idx(struct rtw89_dev *rtwdev, + struct rtw89_pci_dma_ring *bd_ring) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 wp = bd_ring->wp; + + if (!info->rx_ring_eq_is_full) + return wp; + + if (++wp >= bd_ring->len) + wp = 0; + + return wp; +} + static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev, struct rtw89_pci_rx_ring *rx_ring) { @@ -235,15 +299,16 @@ static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev, struct sk_buff *new = rx_ring->diliver_skb; struct sk_buff *skb; u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info); + u32 skb_idx; u32 offset; u32 cnt = 1; bool fs, ls; int ret; - skb = rx_ring->buf[bd_ring->wp]; - rtw89_pci_sync_skb_for_cpu(rtwdev, skb); + skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring); + skb = rx_ring->buf[skb_idx]; - ret = rtw89_pci_rxbd_info_update(rtwdev, skb); + ret = rtw89_pci_sync_skb_for_device_and_validate_rx_info(rtwdev, rx_ring, skb); if (ret) { rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n", bd_ring->wp, ret); @@ -525,13 +590,14 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev, u32 cnt = 0; u32 rpp_size = sizeof(struct rtw89_pci_rpp_fmt); u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info); + u32 skb_idx; u32 offset; int ret; - skb = rx_ring->buf[bd_ring->wp]; - rtw89_pci_sync_skb_for_cpu(rtwdev, skb); + skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring); + skb = rx_ring->buf[skb_idx]; - ret = rtw89_pci_rxbd_info_update(rtwdev, skb); + ret = rtw89_pci_sync_skb_for_device_and_validate_rx_info(rtwdev, rx_ring, skb); if (ret) { rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n", bd_ring->wp, ret); @@ -676,11 +742,26 @@ void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v1); -static void rtw89_pci_clear_isr0(struct rtw89_dev *rtwdev, u32 isr00) +void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev, + struct rtw89_pci *rtwpci, + struct rtw89_pci_isrs *isrs) { - /* write 1 clear */ - rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isr00); + isrs->ind_isrs = rtw89_read32(rtwdev, R_BE_PCIE_HISR) & rtwpci->ind_intrs; + isrs->halt_c2h_isrs = isrs->ind_isrs & B_BE_HS0ISR_IND_INT ? + rtw89_read32(rtwdev, R_BE_HISR0) & rtwpci->halt_c2h_intrs : 0; + isrs->isrs[0] = isrs->ind_isrs & B_BE_HCI_AXIDMA_INT ? + rtw89_read32(rtwdev, R_BE_HAXI_HISR00) & rtwpci->intrs[0] : 0; + isrs->isrs[1] = rtw89_read32(rtwdev, R_BE_PCIE_DMA_ISR); + + if (isrs->halt_c2h_isrs) + rtw89_write32(rtwdev, R_BE_HISR0, isrs->halt_c2h_isrs); + if (isrs->isrs[0]) + rtw89_write32(rtwdev, R_BE_HAXI_HISR00, isrs->isrs[0]); + if (isrs->isrs[1]) + rtw89_write32(rtwdev, R_BE_PCIE_DMA_ISR, isrs->isrs[1]); + rtw89_write32(rtwdev, R_BE_PCIE_HISR, isrs->ind_isrs); } +EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v2); void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) { @@ -713,6 +794,22 @@ void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpc } EXPORT_SYMBOL(rtw89_pci_disable_intr_v1); +void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) +{ + rtw89_write32(rtwdev, R_BE_HIMR0, rtwpci->halt_c2h_intrs); + rtw89_write32(rtwdev, R_BE_HAXI_HIMR00, rtwpci->intrs[0]); + rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, rtwpci->intrs[1]); + rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, rtwpci->ind_intrs); +} +EXPORT_SYMBOL(rtw89_pci_enable_intr_v2); + +void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) +{ + rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, 0); + rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, 0); +} +EXPORT_SYMBOL(rtw89_pci_disable_intr_v2); + static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; @@ -753,6 +850,8 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) { struct rtw89_dev *rtwdev = dev; struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; struct rtw89_pci_isrs isrs; unsigned long flags; @@ -760,13 +859,13 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) rtw89_chip_recognize_intrs(rtwdev, rtwpci, &isrs); spin_unlock_irqrestore(&rtwpci->irq_lock, flags); - if (unlikely(isrs.isrs[0] & B_AX_RDU_INT)) + if (unlikely(isrs.isrs[0] & gen_def->isr_rdu)) rtw89_pci_isr_rxd_unavail(rtwdev, rtwpci); - if (unlikely(isrs.halt_c2h_isrs & B_AX_HALT_C2H_INT_EN)) + if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_halt_c2h)) rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev)); - if (unlikely(isrs.halt_c2h_isrs & B_AX_WDT_TIMEOUT_INT_EN)) + if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_wdt_timeout)) rtw89_ser_notify(rtwdev, MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT); if (unlikely(rtwpci->under_recovery)) @@ -817,6 +916,15 @@ exit: return irqret; } +#define DEF_TXCHADDRS_TYPE2(gen, ch_idx, txch, v...) \ + [RTW89_TXCH_##ch_idx] = { \ + .num = R_##gen##_##txch##_TXBD_NUM ##v, \ + .idx = R_##gen##_##txch##_TXBD_IDX ##v, \ + .bdram = 0, \ + .desa_l = R_##gen##_##txch##_TXBD_DESA_L ##v, \ + .desa_h = R_##gen##_##txch##_TXBD_DESA_H ##v, \ + } + #define DEF_TXCHADDRS_TYPE1(info, txch, v...) \ [RTW89_TXCH_##txch] = { \ .num = R_AX_##txch##_TXBD_NUM ##v, \ @@ -835,12 +943,12 @@ exit: .desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \ } -#define DEF_RXCHADDRS(info, rxch, v...) \ - [RTW89_RXCH_##rxch] = { \ - .num = R_AX_##rxch##_RXBD_NUM ##v, \ - .idx = R_AX_##rxch##_RXBD_IDX ##v, \ - .desa_l = R_AX_##rxch##_RXBD_DESA_L ##v, \ - .desa_h = R_AX_##rxch##_RXBD_DESA_H ##v, \ +#define DEF_RXCHADDRS(gen, ch_idx, rxch, v...) \ + [RTW89_RXCH_##ch_idx] = { \ + .num = R_##gen##_##rxch##_RXBD_NUM ##v, \ + .idx = R_##gen##_##rxch##_RXBD_IDX ##v, \ + .desa_l = R_##gen##_##rxch##_RXBD_DESA_L ##v, \ + .desa_h = R_##gen##_##rxch##_RXBD_DESA_H ##v, \ } const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = { @@ -860,8 +968,8 @@ const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = { DEF_TXCHADDRS(info, CH12), }, .rx = { - DEF_RXCHADDRS(info, RXQ), - DEF_RXCHADDRS(info, RPQ), + DEF_RXCHADDRS(AX, RXQ, RXQ), + DEF_RXCHADDRS(AX, RPQ, RPQ), }, }; EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set); @@ -883,12 +991,35 @@ const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1 = { DEF_TXCHADDRS(info, CH12, _V1), }, .rx = { - DEF_RXCHADDRS(info, RXQ, _V1), - DEF_RXCHADDRS(info, RPQ, _V1), + DEF_RXCHADDRS(AX, RXQ, RXQ, _V1), + DEF_RXCHADDRS(AX, RPQ, RPQ, _V1), }, }; EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_v1); +const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be = { + .tx = { + DEF_TXCHADDRS_TYPE2(BE, ACH0, CH0, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH1, CH1, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH2, CH2, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH3, CH3, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH4, CH4, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH5, CH5, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH6, CH6, _V1), + DEF_TXCHADDRS_TYPE2(BE, ACH7, CH7, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH8, CH8, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH9, CH9, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH10, CH10, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH11, CH11, _V1), + DEF_TXCHADDRS_TYPE2(BE, CH12, CH12, _V1), + }, + .rx = { + DEF_RXCHADDRS(BE, RXQ, RXQ0, _V1), + DEF_RXCHADDRS(BE, RPQ, RPQ0, _V1), + }, +}; +EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_be); + #undef DEF_TXCHADDRS_TYPE1 #undef DEF_TXCHADDRS #undef DEF_RXCHADDRS @@ -1422,6 +1553,7 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) struct rtw89_pci_dma_ring *bd_ring; const struct rtw89_pci_bd_ram *bd_ram; u32 addr_num; + u32 addr_idx; u32 addr_bdram; u32 addr_desa_l; u32 val32; @@ -1433,19 +1565,21 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) tx_ring = &rtwpci->tx_rings[i]; bd_ring = &tx_ring->bd_ring; - bd_ram = &bd_ram_table[i]; + bd_ram = bd_ram_table ? &bd_ram_table[i] : NULL; addr_num = bd_ring->addr.num; addr_bdram = bd_ring->addr.bdram; addr_desa_l = bd_ring->addr.desa_l; bd_ring->wp = 0; bd_ring->rp = 0; - val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) | - FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) | - FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num); - rtw89_write16(rtwdev, addr_num, bd_ring->len); - rtw89_write32(rtwdev, addr_bdram, val32); + if (addr_bdram && bd_ram) { + val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) | + FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) | + FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num); + + rtw89_write32(rtwdev, addr_bdram, val32); + } rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); } @@ -1453,14 +1587,22 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) rx_ring = &rtwpci->rx_rings[i]; bd_ring = &rx_ring->bd_ring; addr_num = bd_ring->addr.num; + addr_idx = bd_ring->addr.idx; addr_desa_l = bd_ring->addr.desa_l; - bd_ring->wp = 0; + if (info->rx_ring_eq_is_full) + bd_ring->wp = bd_ring->len - 1; + else + bd_ring->wp = 0; bd_ring->rp = 0; rx_ring->diliver_skb = NULL; rx_ring->diliver_desc.ready = false; + rx_ring->target_rx_tag = 0; rtw89_write16(rtwdev, addr_num, bd_ring->len); rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); + + if (info->rx_ring_eq_is_full) + rtw89_write16(rtwdev, addr_idx, bd_ring->wp); } } @@ -1471,7 +1613,7 @@ static void rtw89_pci_release_tx_ring(struct rtw89_dev *rtwdev, rtw89_pci_release_pending_txwd_skb(rtwdev, tx_ring); } -static void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev) +void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; const struct rtw89_pci_info *info = rtwdev->pci_info; @@ -1684,24 +1826,16 @@ static void rtw89_pci_ctrl_dma_trx(struct rtw89_dev *rtwdev, bool enable) static void rtw89_pci_ctrl_dma_io(struct rtw89_dev *rtwdev, bool enable) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - u32 reg, mask; - - if (chip_id == RTL8852C) { - reg = R_AX_HAXI_INIT_CFG1; - mask = B_AX_STOP_AXI_MST; - } else { - reg = R_AX_PCIE_DMA_STOP1; - mask = B_AX_STOP_PCIEIO; - } + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_reg_def *reg = &info->dma_io_stop; if (enable) - rtw89_write32_clr(rtwdev, reg, mask); + rtw89_write32_clr(rtwdev, reg->addr, reg->mask); else - rtw89_write32_set(rtwdev, reg, mask); + rtw89_write32_set(rtwdev, reg->addr, reg->mask); } -static void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable) +void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable) { rtw89_pci_ctrl_dma_io(rtwdev, enable); rtw89_pci_ctrl_dma_trx(rtwdev, enable); @@ -2303,7 +2437,7 @@ static void rtw89_pci_set_keep_reg(struct rtw89_dev *rtwdev) B_AX_PCIE_TXRST_KEEP_REG | B_AX_PCIE_RXRST_KEEP_REG); } -static void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev) +static void rtw89_pci_clr_idx_all_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; @@ -2491,7 +2625,7 @@ static int rtw89_pci_ops_deinit(struct rtw89_dev *rtwdev) return 0; } -static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) +static int rtw89_pci_ops_mac_pre_init_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; int ret; @@ -2550,7 +2684,7 @@ static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) /* fill TRX BD indexes */ rtw89_pci_ops_reset(rtwdev); - ret = rtw89_pci_rst_bdram_pcie(rtwdev); + ret = rtw89_pci_rst_bdram_ax(rtwdev); if (ret) { rtw89_warn(rtwdev, "reset bdram busy\n"); return ret; @@ -2648,7 +2782,7 @@ int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en) } EXPORT_SYMBOL(rtw89_pci_ltr_set_v1); -static int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev) +static int rtw89_pci_ops_mac_post_init_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; @@ -3026,6 +3160,7 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev, struct rtw89_pci_rx_ring *rx_ring, u32 desc_size, u32 len, u32 rxch) { + const struct rtw89_pci_info *info = rtwdev->pci_info; const struct rtw89_pci_ch_dma_addr *rxch_addr; struct sk_buff *skb; u8 *head; @@ -3052,11 +3187,15 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev, rx_ring->bd_ring.len = len; rx_ring->bd_ring.desc_size = desc_size; rx_ring->bd_ring.addr = *rxch_addr; - rx_ring->bd_ring.wp = 0; + if (info->rx_ring_eq_is_full) + rx_ring->bd_ring.wp = len - 1; + else + rx_ring->bd_ring.wp = 0; rx_ring->bd_ring.rp = 0; rx_ring->buf_sz = buf_sz; rx_ring->diliver_skb = NULL; rx_ring->diliver_desc.ready = false; + rx_ring->target_rx_tag = 0; for (i = 0; i < len; i++) { skb = dev_alloc_skb(buf_sz); @@ -3289,6 +3428,55 @@ void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev) } EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v1); +static void rtw89_pci_recovery_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = 0; + rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 | + B_BE_PCIE_RX_RPQ0_IMR0_V1; +} + +static void rtw89_pci_default_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HCI_AXIDMA_INT_EN0 | + B_BE_HS0_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = B_BE_RDU_CH1_INT_IMR_V1 | + B_BE_RDU_CH0_INT_IMR_V1; + rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 | + B_BE_PCIE_RX_RPQ0_IMR0_V1; +} + +static void rtw89_pci_low_power_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0 | + B_BE_HS1_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = 0; + rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 | + B_BE_PCIE_RX_RPQ0_IMR0_V1; +} + +void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + if (rtwpci->under_recovery) + rtw89_pci_recovery_intr_mask_v2(rtwdev); + else if (rtwpci->low_power) + rtw89_pci_low_power_intr_mask_v2(rtwdev); + else + rtw89_pci_default_intr_mask_v2(rtwdev); +} +EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v2); + static int rtw89_pci_request_irq(struct rtw89_dev *rtwdev, struct pci_dev *pdev) { @@ -3480,19 +3668,27 @@ static void rtw89_pci_aspm_set(struct rtw89_dev *rtwdev, bool enable) static void rtw89_pci_recalc_int_mit(struct rtw89_dev *rtwdev) { + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + const struct rtw89_pci_info *info = rtwdev->pci_info; struct rtw89_traffic_stats *stats = &rtwdev->stats; enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv; enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv; u32 val = 0; - if (!rtwdev->scanning && - (tx_tfc_lv >= RTW89_TFC_HIGH || rx_tfc_lv >= RTW89_TFC_HIGH)) + if (rtwdev->scanning || + (tx_tfc_lv < RTW89_TFC_HIGH && rx_tfc_lv < RTW89_TFC_HIGH)) + goto out; + + if (chip_gen == RTW89_CHIP_BE) + val = B_BE_PCIE_MIT_RX0P2_EN | B_BE_PCIE_MIT_RX0P1_EN; + else val = B_AX_RXMIT_RXP2_SEL | B_AX_RXMIT_RXP1_SEL | FIELD_PREP(B_AX_RXCOUNTER_MATCH_MASK, RTW89_PCI_RXBD_NUM_MAX / 2) | FIELD_PREP(B_AX_RXTIMER_UNIT_MASK, AX_RXTIMER_UNIT_64US) | FIELD_PREP(B_AX_RXTIMER_MATCH_MASK, 2048 / 64); - rtw89_write32(rtwdev, R_AX_INT_MIT_RX, val); +out: + rtw89_write32(rtwdev, info->mit_addr, val); } static void rtw89_pci_link_cfg(struct rtw89_dev *rtwdev) @@ -3582,7 +3778,7 @@ static void rtw89_pci_l1ss_cfg(struct rtw89_dev *rtwdev) rtw89_pci_l1ss_set(rtwdev, true); } -static int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev) +static int rtw89_pci_poll_io_idle_ax(struct rtw89_dev *rtwdev) { int ret = 0; u32 sts; @@ -3599,7 +3795,7 @@ static int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev) return ret; } -static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) +static int rtw89_pci_lv1rst_stop_dma_ax(struct rtw89_dev *rtwdev) { u32 val; int ret; @@ -3608,7 +3804,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) return 0; rtw89_pci_ctrl_dma_all(rtwdev, false); - ret = rtw89_pci_poll_io_idle(rtwdev); + ret = rtw89_pci_poll_io_idle_ax(rtwdev); if (ret) { val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG); rtw89_debug(rtwdev, RTW89_DBG_HCI, @@ -3619,7 +3815,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) if (val & B_AX_RX_STUCK) rtw89_mac_ctrl_hci_dma_rx(rtwdev, false); rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); - ret = rtw89_pci_poll_io_idle(rtwdev); + ret = rtw89_pci_poll_io_idle_ax(rtwdev); val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG); rtw89_debug(rtwdev, RTW89_DBG_HCI, "[PCIe] poll_io_idle fail, after 0x%08x: 0x%08x\n", @@ -3629,23 +3825,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) return ret; } - - -static int rtw89_pci_rst_bdram(struct rtw89_dev *rtwdev) -{ - int ret = 0; - u32 val32, sts; - - val32 = B_AX_RST_BDRAM; - rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, val32); - - ret = read_poll_timeout_atomic(rtw89_read32, sts, - (sts & B_AX_RST_BDRAM) == 0x0, 1, 100, - true, rtwdev, R_AX_PCIE_INIT_CFG1); - return ret; -} - -static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) +static int rtw89_pci_lv1rst_start_dma_ax(struct rtw89_dev *rtwdev) { u32 ret; @@ -3656,7 +3836,7 @@ static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); rtw89_pci_clr_idx_all(rtwdev); - ret = rtw89_pci_rst_bdram(rtwdev); + ret = rtw89_pci_rst_bdram_ax(rtwdev); if (ret) return ret; @@ -3667,18 +3847,20 @@ static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev, enum rtw89_lv1_rcvy_step step) { + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; int ret; switch (step) { case RTW89_LV1_RCVY_STEP_1: - ret = rtw89_pci_lv1rst_stop_dma(rtwdev); + ret = gen_def->lv1rst_stop_dma(rtwdev); if (ret) rtw89_err(rtwdev, "lv1 rcvy pci stop dma fail\n"); break; case RTW89_LV1_RCVY_STEP_2: - ret = rtw89_pci_lv1rst_start_dma(rtwdev); + ret = gen_def->lv1rst_start_dma(rtwdev); if (ret) rtw89_err(rtwdev, "lv1 rcvy pci start dma fail\n"); break; @@ -3692,29 +3874,41 @@ static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev, static void rtw89_pci_ops_dump_err_status(struct rtw89_dev *rtwdev) { - rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX =0x%08x\n", - rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX)); - rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n", - rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG)); - rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n", - rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG)); + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) + return; + + if (rtwdev->chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG_V1)); + rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG_V1)); + } else { + rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX =0x%08x\n", + rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX)); + rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG)); + rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG)); + } } static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) { struct rtw89_dev *rtwdev = container_of(napi, struct rtw89_dev, napi); struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; unsigned long flags; int work_done; rtwdev->napi_budget_countdown = budget; - rtw89_pci_clear_isr0(rtwdev, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT); + rtw89_write32(rtwdev, gen_def->isr_clear_rpq.addr, gen_def->isr_clear_rpq.data); work_done = rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown); if (work_done == budget) return budget; - rtw89_pci_clear_isr0(rtwdev, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT | B_AX_RDU_INT); + rtw89_write32(rtwdev, gen_def->isr_clear_rxq.addr, gen_def->isr_clear_rxq.data); work_done += rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown); if (work_done < budget && napi_complete_done(napi, work_done)) { spin_lock_irqsave(&rtwpci->irq_lock, flags); @@ -3791,6 +3985,26 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev) SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume); EXPORT_SYMBOL(rtw89_pm_ops); +const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { + .isr_rdu = B_AX_RDU_INT, + .isr_halt_c2h = B_AX_HALT_C2H_INT_EN, + .isr_wdt_timeout = B_AX_WDT_TIMEOUT_INT_EN, + .isr_clear_rpq = {R_AX_PCIE_HISR00, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT}, + .isr_clear_rxq = {R_AX_PCIE_HISR00, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT | + B_AX_RDU_INT}, + + .mac_pre_init = rtw89_pci_ops_mac_pre_init_ax, + .mac_pre_deinit = NULL, + .mac_post_init = rtw89_pci_ops_mac_post_init_ax, + + .clr_idx_all = rtw89_pci_clr_idx_all_ax, + .rst_bdram = rtw89_pci_rst_bdram_ax, + + .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_ax, + .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_ax, +}; +EXPORT_SYMBOL(rtw89_pci_gen_ax); + static const struct rtw89_hci_ops rtw89_pci_ops = { .tx_write = rtw89_pci_ops_tx_write, .tx_kick_off = rtw89_pci_ops_tx_kick_off, @@ -3810,6 +4024,7 @@ static const struct rtw89_hci_ops rtw89_pci_ops = { .write32 = rtw89_pci_ops_write32, .mac_pre_init = rtw89_pci_ops_mac_pre_init, + .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit, .mac_post_init = rtw89_pci_ops_mac_post_init, .deinit = rtw89_pci_ops_deinit, @@ -3829,7 +4044,7 @@ static const struct rtw89_hci_ops rtw89_pci_ops = { .clear = rtw89_pci_clear_resource, .disable_intr = rtw89_pci_disable_intr_lock, .enable_intr = rtw89_pci_enable_intr_lock, - .rst_bdram = rtw89_pci_rst_bdram_pcie, + .rst_bdram = rtw89_pci_reset_bdram, }; int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 2f3d1ad3b0..772a84bd8d 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -245,6 +245,203 @@ #define B_AX_HS1ISR_IND_INT BIT(25) #define B_AX_PCIE_DBG_STE_INT BIT(13) +#define R_BE_PCIE_FRZ_CLK 0x3004 +#define B_BE_PCIE_FRZ_MAC_HW_RST BIT(31) +#define B_BE_PCIE_FRZ_CFG_SPC_RST BIT(30) +#define B_BE_PCIE_FRZ_ELBI_RST BIT(29) +#define B_BE_PCIE_MAC_IS_ACTIVE BIT(28) +#define B_BE_PCIE_FRZ_RTK_HW_RST BIT(27) +#define B_BE_PCIE_FRZ_REG_RST BIT(26) +#define B_BE_PCIE_FRZ_ANA_RST BIT(25) +#define B_BE_PCIE_FRZ_WLAN_RST BIT(24) +#define B_BE_PCIE_FRZ_FLR_RST BIT(23) +#define B_BE_PCIE_FRZ_RET_NON_STKY_RST BIT(22) +#define B_BE_PCIE_FRZ_RET_STKY_RST BIT(21) +#define B_BE_PCIE_FRZ_NON_STKY_RST BIT(20) +#define B_BE_PCIE_FRZ_STKY_RST BIT(19) +#define B_BE_PCIE_FRZ_RET_CORE_RST BIT(18) +#define B_BE_PCIE_FRZ_PWR_RST BIT(17) +#define B_BE_PCIE_FRZ_PERST_RST BIT(16) +#define B_BE_PCIE_FRZ_PHY_ALOAD BIT(15) +#define B_BE_PCIE_FRZ_PHY_HW_RST BIT(14) +#define B_BE_PCIE_DBG_CLK BIT(4) +#define B_BE_PCIE_EN_CLK BIT(3) +#define B_BE_PCIE_DBI_ACLK_ACT BIT(2) +#define B_BE_PCIE_S1_ACLK_ACT BIT(1) +#define B_BE_PCIE_EN_AUX_CLK BIT(0) + +#define R_BE_PCIE_PS_CTRL 0x3008 +#define B_BE_RSM_L0S_EN BIT(8) +#define B_BE_CMAC_EXIT_L1_EN BIT(7) +#define B_BE_DMAC0_EXIT_L1_EN BIT(6) +#define B_BE_FORCE_L0 BIT(5) +#define B_BE_DBI_RO_WR_DISABLE BIT(4) +#define B_BE_SEL_XFER_PENDING BIT(3) +#define B_BE_SEL_REQ_ENTR_L1 BIT(2) +#define B_BE_PCIE_EN_SWENT_L23 BIT(1) +#define B_BE_SEL_REQ_EXIT_L1 BIT(0) + +#define R_BE_PCIE_LAT_CTRL 0x3044 +#define B_BE_ELBI_PHY_REMAP_MASK GENMASK(29, 24) +#define B_BE_SYS_SUS_L12_EN BIT(17) +#define B_BE_MDIO_S_EN BIT(16) +#define B_BE_SYM_AUX_CLK_SEL BIT(15) +#define B_BE_RTK_LDO_POWER_LATENCY_MASK GENMASK(11, 10) +#define B_BE_RTK_LDO_BIAS_LATENCY_MASK GENMASK(9, 8) +#define B_BE_CLK_REQ_LAT_MASK GENMASK(7, 4) + +#define R_BE_PCIE_HIMR0 0x30B0 +#define B_BE_PCIE_HB1_IND_INTA_IMR BIT(31) +#define B_BE_PCIE_HB0_IND_INTA_IMR BIT(30) +#define B_BE_HCI_AXIDMA_INTA_IMR BIT(29) +#define B_BE_HC0_IND_INTA_IMR BIT(28) +#define B_BE_HD1_IND_INTA_IMR BIT(27) +#define B_BE_HD0_IND_INTA_IMR BIT(26) +#define B_BE_HS1_IND_INTA_IMR BIT(25) +#define B_BE_HS0_IND_INTA_IMR BIT(24) +#define B_BE_PCIE_HOTRST_INT_EN BIT(16) +#define B_BE_PCIE_FLR_INT_EN BIT(15) +#define B_BE_PCIE_PERST_INT_EN BIT(14) +#define B_BE_PCIE_DBG_STE_INT_EN BIT(13) +#define B_BE_HB1_IND_INT_EN0 BIT(9) +#define B_BE_HB0_IND_INT_EN0 BIT(8) +#define B_BE_HC1_IND_INT_EN0 BIT(7) +#define B_BE_HCI_AXIDMA_INT_EN0 BIT(5) +#define B_BE_HC0_IND_INT_EN0 BIT(4) +#define B_BE_HD1_IND_INT_EN0 BIT(3) +#define B_BE_HD0_IND_INT_EN0 BIT(2) +#define B_BE_HS1_IND_INT_EN0 BIT(1) +#define B_BE_HS0_IND_INT_EN0 BIT(0) + +#define R_BE_PCIE_HISR 0x30B4 +#define B_BE_PCIE_HOTRST_INT BIT(16) +#define B_BE_PCIE_FLR_INT BIT(15) +#define B_BE_PCIE_PERST_INT BIT(14) +#define B_BE_PCIE_DBG_STE_INT BIT(13) +#define B_BE_HB1IMR_IND BIT(9) +#define B_BE_HB0IMR_IND BIT(8) +#define B_BE_HC1ISR_IND_INT BIT(7) +#define B_BE_HCI_AXIDMA_INT BIT(5) +#define B_BE_HC0ISR_IND_INT BIT(4) +#define B_BE_HD1ISR_IND_INT BIT(3) +#define B_BE_HD0ISR_IND_INT BIT(2) +#define B_BE_HS1ISR_IND_INT BIT(1) +#define B_BE_HS0ISR_IND_INT BIT(0) + +#define R_BE_PCIE_DMA_IMR_0_V1 0x30B8 +#define B_BE_PCIE_RX_RX1P1_IMR0_V1 BIT(23) +#define B_BE_PCIE_RX_RX0P1_IMR0_V1 BIT(22) +#define B_BE_PCIE_RX_ROQ1_IMR0_V1 BIT(21) +#define B_BE_PCIE_RX_RPQ1_IMR0_V1 BIT(20) +#define B_BE_PCIE_RX_RX1P2_IMR0_V1 BIT(19) +#define B_BE_PCIE_RX_ROQ0_IMR0_V1 BIT(18) +#define B_BE_PCIE_RX_RPQ0_IMR0_V1 BIT(17) +#define B_BE_PCIE_RX_RX0P2_IMR0_V1 BIT(16) +#define B_BE_PCIE_TX_CH14_IMR0 BIT(14) +#define B_BE_PCIE_TX_CH13_IMR0 BIT(13) +#define B_BE_PCIE_TX_CH12_IMR0 BIT(12) +#define B_BE_PCIE_TX_CH11_IMR0 BIT(11) +#define B_BE_PCIE_TX_CH10_IMR0 BIT(10) +#define B_BE_PCIE_TX_CH9_IMR0 BIT(9) +#define B_BE_PCIE_TX_CH8_IMR0 BIT(8) +#define B_BE_PCIE_TX_CH7_IMR0 BIT(7) +#define B_BE_PCIE_TX_CH6_IMR0 BIT(6) +#define B_BE_PCIE_TX_CH5_IMR0 BIT(5) +#define B_BE_PCIE_TX_CH4_IMR0 BIT(4) +#define B_BE_PCIE_TX_CH3_IMR0 BIT(3) +#define B_BE_PCIE_TX_CH2_IMR0 BIT(2) +#define B_BE_PCIE_TX_CH1_IMR0 BIT(1) +#define B_BE_PCIE_TX_CH0_IMR0 BIT(0) + +#define R_BE_PCIE_DMA_ISR 0x30BC +#define B_BE_PCIE_RX_RX1P1_ISR_V1 BIT(23) +#define B_BE_PCIE_RX_RX0P1_ISR_V1 BIT(22) +#define B_BE_PCIE_RX_ROQ1_ISR_V1 BIT(21) +#define B_BE_PCIE_RX_RPQ1_ISR_V1 BIT(20) +#define B_BE_PCIE_RX_RX1P2_ISR_V1 BIT(19) +#define B_BE_PCIE_RX_ROQ0_ISR_V1 BIT(18) +#define B_BE_PCIE_RX_RPQ0_ISR_V1 BIT(17) +#define B_BE_PCIE_RX_RX0P2_ISR_V1 BIT(16) +#define B_BE_PCIE_TX_CH14_ISR BIT(14) +#define B_BE_PCIE_TX_CH13_ISR BIT(13) +#define B_BE_PCIE_TX_CH12_ISR BIT(12) +#define B_BE_PCIE_TX_CH11_ISR BIT(11) +#define B_BE_PCIE_TX_CH10_ISR BIT(10) +#define B_BE_PCIE_TX_CH9_ISR BIT(9) +#define B_BE_PCIE_TX_CH8_ISR BIT(8) +#define B_BE_PCIE_TX_CH7_ISR BIT(7) +#define B_BE_PCIE_TX_CH6_ISR BIT(6) +#define B_BE_PCIE_TX_CH5_ISR BIT(5) +#define B_BE_PCIE_TX_CH4_ISR BIT(4) +#define B_BE_PCIE_TX_CH3_ISR BIT(3) +#define B_BE_PCIE_TX_CH2_ISR BIT(2) +#define B_BE_PCIE_TX_CH1_ISR BIT(1) +#define B_BE_PCIE_TX_CH0_ISR BIT(0) + +#define R_BE_HAXI_HIMR00 0xB0B0 +#define B_BE_RDU_CH5_INT_IMR_V1 BIT(30) +#define B_BE_RDU_CH4_INT_IMR_V1 BIT(29) +#define B_BE_RDU_CH3_INT_IMR_V1 BIT(28) +#define B_BE_RDU_CH2_INT_IMR_V1 BIT(27) +#define B_BE_RDU_CH1_INT_IMR_V1 BIT(26) +#define B_BE_RDU_CH0_INT_IMR_V1 BIT(25) +#define B_BE_RXDMA_STUCK_INT_EN_V1 BIT(24) +#define B_BE_TXDMA_STUCK_INT_EN_V1 BIT(23) +#define B_BE_TXDMA_CH14_INT_EN_V1 BIT(22) +#define B_BE_TXDMA_CH13_INT_EN_V1 BIT(21) +#define B_BE_TXDMA_CH12_INT_EN_V1 BIT(20) +#define B_BE_TXDMA_CH11_INT_EN_V1 BIT(19) +#define B_BE_TXDMA_CH10_INT_EN_V1 BIT(18) +#define B_BE_TXDMA_CH9_INT_EN_V1 BIT(17) +#define B_BE_TXDMA_CH8_INT_EN_V1 BIT(16) +#define B_BE_TXDMA_CH7_INT_EN_V1 BIT(15) +#define B_BE_TXDMA_CH6_INT_EN_V1 BIT(14) +#define B_BE_TXDMA_CH5_INT_EN_V1 BIT(13) +#define B_BE_TXDMA_CH4_INT_EN_V1 BIT(12) +#define B_BE_TXDMA_CH3_INT_EN_V1 BIT(11) +#define B_BE_TXDMA_CH2_INT_EN_V1 BIT(10) +#define B_BE_TXDMA_CH1_INT_EN_V1 BIT(9) +#define B_BE_TXDMA_CH0_INT_EN_V1 BIT(8) +#define B_BE_RX1P1DMA_INT_EN_V1 BIT(7) +#define B_BE_RX0P1DMA_INT_EN_V1 BIT(6) +#define B_BE_RO1DMA_INT_EN BIT(5) +#define B_BE_RP1DMA_INT_EN BIT(4) +#define B_BE_RX1DMA_INT_EN BIT(3) +#define B_BE_RO0DMA_INT_EN BIT(2) +#define B_BE_RP0DMA_INT_EN BIT(1) +#define B_BE_RX0DMA_INT_EN BIT(0) + +#define R_BE_HAXI_HISR00 0xB0B4 +#define B_BE_RDU_CH6_INT BIT(28) +#define B_BE_RDU_CH5_INT BIT(27) +#define B_BE_RDU_CH4_INT BIT(26) +#define B_BE_RDU_CH2_INT BIT(25) +#define B_BE_RDU_CH1_INT BIT(24) +#define B_BE_RDU_CH0_INT BIT(23) +#define B_BE_RXDMA_STUCK_INT BIT(22) +#define B_BE_TXDMA_STUCK_INT BIT(21) +#define B_BE_TXDMA_CH14_INT BIT(20) +#define B_BE_TXDMA_CH13_INT BIT(19) +#define B_BE_TXDMA_CH12_INT BIT(18) +#define B_BE_TXDMA_CH11_INT BIT(17) +#define B_BE_TXDMA_CH10_INT BIT(16) +#define B_BE_TXDMA_CH9_INT BIT(15) +#define B_BE_TXDMA_CH8_INT BIT(14) +#define B_BE_TXDMA_CH7_INT BIT(13) +#define B_BE_TXDMA_CH6_INT BIT(12) +#define B_BE_TXDMA_CH5_INT BIT(11) +#define B_BE_TXDMA_CH4_INT BIT(10) +#define B_BE_TXDMA_CH3_INT BIT(9) +#define B_BE_TXDMA_CH2_INT BIT(8) +#define B_BE_TXDMA_CH1_INT BIT(7) +#define B_BE_TXDMA_CH0_INT BIT(6) +#define B_BE_RPQ1DMA_INT BIT(5) +#define B_BE_RX1P1DMA_INT BIT(4) +#define B_BE_RX1DMA_INT BIT(3) +#define B_BE_RPQ0DMA_INT BIT(2) +#define B_BE_RX0P1DMA_INT BIT(1) +#define B_BE_RX0DMA_INT BIT(0) + /* TX/RX */ #define R_AX_DRV_FW_HSK_0 0x01B0 #define R_AX_DRV_FW_HSK_1 0x01B4 @@ -496,6 +693,105 @@ #define B_AX_CH11_BUSY BIT(1) #define B_AX_CH10_BUSY BIT(0) +#define R_BE_HAXI_DMA_STOP1 0xB010 +#define B_BE_STOP_WPDMA BIT(31) +#define B_BE_STOP_CH14 BIT(14) +#define B_BE_STOP_CH13 BIT(13) +#define B_BE_STOP_CH12 BIT(12) +#define B_BE_STOP_CH11 BIT(11) +#define B_BE_STOP_CH10 BIT(10) +#define B_BE_STOP_CH9 BIT(9) +#define B_BE_STOP_CH8 BIT(8) +#define B_BE_STOP_CH7 BIT(7) +#define B_BE_STOP_CH6 BIT(6) +#define B_BE_STOP_CH5 BIT(5) +#define B_BE_STOP_CH4 BIT(4) +#define B_BE_STOP_CH3 BIT(3) +#define B_BE_STOP_CH2 BIT(2) +#define B_BE_STOP_CH1 BIT(1) +#define B_BE_STOP_CH0 BIT(0) +#define B_BE_TX_STOP1_MASK (B_BE_STOP_CH0 | B_BE_STOP_CH1 | \ + B_BE_STOP_CH2 | B_BE_STOP_CH3 | \ + B_BE_STOP_CH4 | B_BE_STOP_CH5 | \ + B_BE_STOP_CH6 | B_BE_STOP_CH7 | \ + B_BE_STOP_CH8 | B_BE_STOP_CH9 | \ + B_BE_STOP_CH10 | B_BE_STOP_CH11 | \ + B_BE_STOP_CH12) + +#define R_BE_CH0_TXBD_NUM_V1 0xB030 +#define R_BE_CH1_TXBD_NUM_V1 0xB032 +#define R_BE_CH2_TXBD_NUM_V1 0xB034 +#define R_BE_CH3_TXBD_NUM_V1 0xB036 +#define R_BE_CH4_TXBD_NUM_V1 0xB038 +#define R_BE_CH5_TXBD_NUM_V1 0xB03A +#define R_BE_CH6_TXBD_NUM_V1 0xB03C +#define R_BE_CH7_TXBD_NUM_V1 0xB03E +#define R_BE_CH8_TXBD_NUM_V1 0xB040 +#define R_BE_CH9_TXBD_NUM_V1 0xB042 +#define R_BE_CH10_TXBD_NUM_V1 0xB044 +#define R_BE_CH11_TXBD_NUM_V1 0xB046 +#define R_BE_CH12_TXBD_NUM_V1 0xB048 +#define R_BE_CH13_TXBD_NUM_V1 0xB04C +#define R_BE_CH14_TXBD_NUM_V1 0xB04E + +#define R_BE_RXQ0_RXBD_NUM_V1 0xB050 +#define R_BE_RPQ0_RXBD_NUM_V1 0xB052 + +#define R_BE_CH0_TXBD_IDX_V1 0xB100 +#define R_BE_CH1_TXBD_IDX_V1 0xB104 +#define R_BE_CH2_TXBD_IDX_V1 0xB108 +#define R_BE_CH3_TXBD_IDX_V1 0xB10C +#define R_BE_CH4_TXBD_IDX_V1 0xB110 +#define R_BE_CH5_TXBD_IDX_V1 0xB114 +#define R_BE_CH6_TXBD_IDX_V1 0xB118 +#define R_BE_CH7_TXBD_IDX_V1 0xB11C +#define R_BE_CH8_TXBD_IDX_V1 0xB120 +#define R_BE_CH9_TXBD_IDX_V1 0xB124 +#define R_BE_CH10_TXBD_IDX_V1 0xB128 +#define R_BE_CH11_TXBD_IDX_V1 0xB12C +#define R_BE_CH12_TXBD_IDX_V1 0xB130 +#define R_BE_CH13_TXBD_IDX_V1 0xB134 +#define R_BE_CH14_TXBD_IDX_V1 0xB138 + +#define R_BE_RXQ0_RXBD_IDX_V1 0xB160 +#define R_BE_RPQ0_RXBD_IDX_V1 0xB164 + +#define R_BE_CH0_TXBD_DESA_L_V1 0xB200 +#define R_BE_CH0_TXBD_DESA_H_V1 0xB204 +#define R_BE_CH1_TXBD_DESA_L_V1 0xB208 +#define R_BE_CH1_TXBD_DESA_H_V1 0xB20C +#define R_BE_CH2_TXBD_DESA_L_V1 0xB210 +#define R_BE_CH2_TXBD_DESA_H_V1 0xB214 +#define R_BE_CH3_TXBD_DESA_L_V1 0xB218 +#define R_BE_CH3_TXBD_DESA_H_V1 0xB21C +#define R_BE_CH4_TXBD_DESA_L_V1 0xB220 +#define R_BE_CH4_TXBD_DESA_H_V1 0xB224 +#define R_BE_CH5_TXBD_DESA_L_V1 0xB228 +#define R_BE_CH5_TXBD_DESA_H_V1 0xB22C +#define R_BE_CH6_TXBD_DESA_L_V1 0xB230 +#define R_BE_CH6_TXBD_DESA_H_V1 0xB234 +#define R_BE_CH7_TXBD_DESA_L_V1 0xB238 +#define R_BE_CH7_TXBD_DESA_H_V1 0xB23C +#define R_BE_CH8_TXBD_DESA_L_V1 0xB240 +#define R_BE_CH8_TXBD_DESA_H_V1 0xB244 +#define R_BE_CH9_TXBD_DESA_L_V1 0xB248 +#define R_BE_CH9_TXBD_DESA_H_V1 0xB24C +#define R_BE_CH10_TXBD_DESA_L_V1 0xB250 +#define R_BE_CH10_TXBD_DESA_H_V1 0xB254 +#define R_BE_CH11_TXBD_DESA_L_V1 0xB258 +#define R_BE_CH11_TXBD_DESA_H_V1 0xB25C +#define R_BE_CH12_TXBD_DESA_L_V1 0xB260 +#define R_BE_CH12_TXBD_DESA_H_V1 0xB264 +#define R_BE_CH13_TXBD_DESA_L_V1 0xB268 +#define R_BE_CH13_TXBD_DESA_H_V1 0xB26C +#define R_BE_CH14_TXBD_DESA_L_V1 0xB270 +#define R_BE_CH14_TXBD_DESA_H_V1 0xB274 + +#define R_BE_RXQ0_RXBD_DESA_L_V1 0xB300 +#define R_BE_RXQ0_RXBD_DESA_H_V1 0xB304 +#define R_BE_RPQ0_RXBD_DESA_L_V1 0xB308 +#define R_BE_RPQ0_RXBD_DESA_H_V1 0xB30C + /* Configure */ #define R_AX_PCIE_INIT_CFG2 0x1004 #define B_AX_WD_ITVL_IDLE GENMASK(27, 24) @@ -516,6 +812,15 @@ #define B_AX_RXCOUNTER_MATCH_MASK GENMASK(15, 8) #define B_AX_RXTIMER_MATCH_MASK GENMASK(7, 0) +#define R_AX_DBG_ERR_FLAG_V1 0x1104 + +#define R_AX_INT_MIT_RX_V1 0x1184 +#define B_AX_RXMIT_RXP2_SEL_V1 BIT(19) +#define B_AX_RXMIT_RXP1_SEL_V1 BIT(18) +#define B_AX_MIT_RXTIMER_UNIT_MASK GENMASK(17, 16) +#define B_AX_MIT_RXCOUNTER_MATCH_MASK GENMASK(15, 8) +#define B_AX_MIT_RXTIMER_MATCH_MASK GENMASK(7, 0) + #define R_AX_DBG_ERR_FLAG 0x11C4 #define B_AX_PCIE_RPQ_FULL BIT(29) #define B_AX_PCIE_RXQ_FULL BIT(28) @@ -554,23 +859,158 @@ #define R_AX_PCIE_HRPWM_V1 0x30C0 #define R_AX_PCIE_CRPWM 0x30C4 +#define R_AX_LBC_WATCHDOG_V1 0x30D8 + +#define R_BE_PCIE_HRPWM 0x30C0 +#define R_BE_PCIE_CRPWM 0x30C4 + +#define R_BE_L1_2_CTRL_HCILDO 0x3110 +#define B_BE_PCIE_DIS_L1_2_CTRL_HCILDO BIT(0) + +#define R_BE_PL1_DBG_INFO 0x3120 +#define B_BE_END_PL1_CNT_MASK GENMASK(23, 16) +#define B_BE_START_PL1_CNT_MASK GENMASK(7, 0) + +#define R_BE_PCIE_MIT0_TMR 0x3330 +#define B_BE_PCIE_MIT0_RX_TMR_MASK GENMASK(5, 4) +#define BE_MIT0_TMR_UNIT_1MS 0 +#define BE_MIT0_TMR_UNIT_2MS 1 +#define BE_MIT0_TMR_UNIT_4MS 2 +#define BE_MIT0_TMR_UNIT_8MS 3 +#define B_BE_PCIE_MIT0_TX_TMR_MASK GENMASK(1, 0) + +#define R_BE_PCIE_MIT0_CNT 0x3334 +#define B_BE_PCIE_RX_MIT0_CNT_MASK GENMASK(31, 24) +#define B_BE_PCIE_TX_MIT0_CNT_MASK GENMASK(23, 16) +#define B_BE_PCIE_RX_MIT0_TMR_CNT_MASK GENMASK(15, 8) +#define B_BE_PCIE_TX_MIT0_TMR_CNT_MASK GENMASK(7, 0) + +#define R_BE_PCIE_MIT_CH_EN 0x3338 +#define B_BE_PCIE_MIT_RX1P1_EN BIT(23) +#define B_BE_PCIE_MIT_RX0P1_EN BIT(22) +#define B_BE_PCIE_MIT_ROQ1_EN BIT(21) +#define B_BE_PCIE_MIT_RPQ1_EN BIT(20) +#define B_BE_PCIE_MIT_RX1P2_EN BIT(19) +#define B_BE_PCIE_MIT_ROQ0_EN BIT(18) +#define B_BE_PCIE_MIT_RPQ0_EN BIT(17) +#define B_BE_PCIE_MIT_RX0P2_EN BIT(16) +#define B_BE_PCIE_MIT_TXCH14_EN BIT(14) +#define B_BE_PCIE_MIT_TXCH13_EN BIT(13) +#define B_BE_PCIE_MIT_TXCH12_EN BIT(12) +#define B_BE_PCIE_MIT_TXCH11_EN BIT(11) +#define B_BE_PCIE_MIT_TXCH10_EN BIT(10) +#define B_BE_PCIE_MIT_TXCH9_EN BIT(9) +#define B_BE_PCIE_MIT_TXCH8_EN BIT(8) +#define B_BE_PCIE_MIT_TXCH7_EN BIT(7) +#define B_BE_PCIE_MIT_TXCH6_EN BIT(6) +#define B_BE_PCIE_MIT_TXCH5_EN BIT(5) +#define B_BE_PCIE_MIT_TXCH4_EN BIT(4) +#define B_BE_PCIE_MIT_TXCH3_EN BIT(3) +#define B_BE_PCIE_MIT_TXCH2_EN BIT(2) +#define B_BE_PCIE_MIT_TXCH1_EN BIT(1) +#define B_BE_PCIE_MIT_TXCH0_EN BIT(0) + +#define R_BE_SER_PL1_CTRL 0x34A8 +#define B_BE_PL1_SER_PL1_EN BIT(31) +#define B_BE_PL1_IGNORE_HOT_RST BIT(30) +#define B_BE_PL1_TIMER_UNIT_MASK GENMASK(19, 17) +#define B_BE_PL1_TIMER_CLEAR BIT(0) + +#define R_BE_REG_PL1_MASK 0x34B0 +#define B_BE_SER_PCLKREQ_ACK_MASK BIT(5) +#define B_BE_SER_PM_CLK_MASK BIT(4) +#define B_BE_SER_LTSSM_IMR BIT(3) +#define B_BE_SER_PM_MASTER_IMR BIT(2) +#define B_BE_SER_L1SUB_IMR BIT(1) +#define B_BE_SER_PMU_IMR BIT(0) + +#define R_BE_RX_APPEND_MODE 0x8920 +#define B_BE_APPEND_OFFSET_MASK GENMASK(23, 16) +#define B_BE_APPEND_LEN_MASK GENMASK(15, 0) + +#define R_BE_TXBD_RWPTR_CLR1 0xB014 +#define B_BE_CLR_CH14_IDX BIT(14) +#define B_BE_CLR_CH13_IDX BIT(13) +#define B_BE_CLR_CH12_IDX BIT(12) +#define B_BE_CLR_CH11_IDX BIT(11) +#define B_BE_CLR_CH10_IDX BIT(10) +#define B_BE_CLR_CH9_IDX BIT(9) +#define B_BE_CLR_CH8_IDX BIT(8) +#define B_BE_CLR_CH7_IDX BIT(7) +#define B_BE_CLR_CH6_IDX BIT(6) +#define B_BE_CLR_CH5_IDX BIT(5) +#define B_BE_CLR_CH4_IDX BIT(4) +#define B_BE_CLR_CH3_IDX BIT(3) +#define B_BE_CLR_CH2_IDX BIT(2) +#define B_BE_CLR_CH1_IDX BIT(1) +#define B_BE_CLR_CH0_IDX BIT(0) + +#define R_BE_RXBD_RWPTR_CLR1_V1 0xB018 +#define B_BE_CLR_ROQ1_IDX_V1 BIT(5) +#define B_BE_CLR_RPQ1_IDX_V1 BIT(4) +#define B_BE_CLR_RXQ1_IDX_V1 BIT(3) +#define B_BE_CLR_ROQ0_IDX BIT(2) +#define B_BE_CLR_RPQ0_IDX BIT(1) +#define B_BE_CLR_RXQ0_IDX BIT(0) + +#define R_BE_HAXI_DMA_BUSY1 0xB01C +#define B_BE_HAXI_MST_BUSY BIT(31) +#define B_BE_HAXI_RX_IDLE BIT(25) +#define B_BE_HAXI_TX_IDLE BIT(24) +#define B_BE_ROQ1_BUSY_V1 BIT(21) +#define B_BE_RPQ1_BUSY_V1 BIT(20) +#define B_BE_RXQ1_BUSY_V1 BIT(19) +#define B_BE_ROQ0_BUSY_V1 BIT(18) +#define B_BE_RPQ0_BUSY_V1 BIT(17) +#define B_BE_RXQ0_BUSY_V1 BIT(16) +#define B_BE_WPDMA_BUSY BIT(15) +#define B_BE_CH14_BUSY BIT(14) +#define B_BE_CH13_BUSY BIT(13) +#define B_BE_CH12_BUSY BIT(12) +#define B_BE_CH11_BUSY BIT(11) +#define B_BE_CH10_BUSY BIT(10) +#define B_BE_CH9_BUSY BIT(9) +#define B_BE_CH8_BUSY BIT(8) +#define B_BE_CH7_BUSY BIT(7) +#define B_BE_CH6_BUSY BIT(6) +#define B_BE_CH5_BUSY BIT(5) +#define B_BE_CH4_BUSY BIT(4) +#define B_BE_CH3_BUSY BIT(3) +#define B_BE_CH2_BUSY BIT(2) +#define B_BE_CH1_BUSY BIT(1) +#define B_BE_CH0_BUSY BIT(0) +#define DMA_BUSY1_CHECK_BE (B_BE_CH0_BUSY | B_BE_CH1_BUSY | B_BE_CH2_BUSY | \ + B_BE_CH3_BUSY | B_BE_CH4_BUSY | B_BE_CH5_BUSY | \ + B_BE_CH6_BUSY | B_BE_CH7_BUSY | B_BE_CH8_BUSY | \ + B_BE_CH9_BUSY | B_BE_CH10_BUSY | B_BE_CH11_BUSY | \ + B_BE_CH12_BUSY | B_BE_CH13_BUSY | B_BE_CH14_BUSY) + +#define R_BE_HAXI_EXP_CTRL_V1 0xB020 +#define B_BE_R_NO_SEC_ACCESS BIT(31) +#define B_BE_FORCE_EN_DMA_RX_GCLK BIT(5) +#define B_BE_FORCE_EN_DMA_TX_GCLK BIT(4) +#define B_BE_MAX_TAG_NUM_MASK GENMASK(3, 0) + #define RTW89_PCI_TXBD_NUM_MAX 256 #define RTW89_PCI_RXBD_NUM_MAX 256 #define RTW89_PCI_TXWD_NUM_MAX 512 #define RTW89_PCI_TXWD_PAGE_SIZE 128 #define RTW89_PCI_ADDRINFO_MAX 4 -#define RTW89_PCI_RX_BUF_SIZE 11460 +#define RTW89_PCI_RX_BUF_SIZE (11454 + 40) /* +40 for rtw89_rxdesc_long_v2 */ #define RTW89_PCI_POLL_BDRAM_RST_CNT 100 #define RTW89_PCI_MULTITAG 8 /* PCIE CFG register */ +#define RTW89_PCIE_CAPABILITY_SPEED 0x7C +#define RTW89_PCIE_SUPPORT_GEN_MASK GENMASK(3, 0) #define RTW89_PCIE_L1_STS_V1 0x80 #define RTW89_BCFG_LINK_SPEED_MASK GENMASK(19, 16) #define RTW89_PCIE_GEN1_SPEED 0x01 #define RTW89_PCIE_GEN2_SPEED 0x02 #define RTW89_PCIE_PHY_RATE 0x82 #define RTW89_PCIE_PHY_RATE_MASK GENMASK(1, 0) +#define RTW89_PCIE_LINK_CHANGE_SPEED 0xA0 #define RTW89_PCIE_L1SS_STS_V1 0x0168 #define RTW89_PCIE_BIT_ASPM_L11 BIT(3) #define RTW89_PCIE_BIT_ASPM_L12 BIT(2) @@ -585,6 +1025,8 @@ #define RTW89_PCIE_BIT_CLK BIT(4) #define RTW89_PCIE_BIT_L1 BIT(3) #define RTW89_PCIE_CLK_CTRL 0x0725 +#define RTW89_PCIE_FTS 0x080C +#define RTW89_PCIE_POLLING_BIT BIT(17) #define RTW89_PCIE_RST_MSTATE 0x0B48 #define RTW89_PCIE_BIT_CFG_RST_MSTATE BIT(0) @@ -757,7 +1199,26 @@ struct rtw89_pci_bd_ram { u8 min_num; }; +struct rtw89_pci_gen_def { + u32 isr_rdu; + u32 isr_halt_c2h; + u32 isr_wdt_timeout; + struct rtw89_reg2_def isr_clear_rpq; + struct rtw89_reg2_def isr_clear_rxq; + + int (*mac_pre_init)(struct rtw89_dev *rtwdev); + int (*mac_pre_deinit)(struct rtw89_dev *rtwdev); + int (*mac_post_init)(struct rtw89_dev *rtwdev); + + void (*clr_idx_all)(struct rtw89_dev *rtwdev); + int (*rst_bdram)(struct rtw89_dev *rtwdev); + + int (*lv1rst_stop_dma)(struct rtw89_dev *rtwdev); + int (*lv1rst_start_dma)(struct rtw89_dev *rtwdev); +}; + struct rtw89_pci_info { + const struct rtw89_pci_gen_def *gen_def; enum mac_ax_bd_trunc_mode txbd_trunc_mode; enum mac_ax_bd_trunc_mode rxbd_trunc_mode; enum mac_ax_rxbd_mode rxbd_mode; @@ -772,6 +1233,8 @@ struct rtw89_pci_info { enum mac_ax_pcie_func_ctrl autok_en; enum mac_ax_pcie_func_ctrl io_rcy_en; enum mac_ax_io_rcy_tmr io_rcy_tmr; + bool rx_ring_eq_is_full; + bool check_rx_tag; u32 init_cfg_reg; u32 txhci_en_bit; @@ -781,6 +1244,7 @@ struct rtw89_pci_info { u32 max_tag_num_mask; u32 rxbd_rwptr_clr_reg; u32 txbd_rwptr_clr2_reg; + struct rtw89_reg_def dma_io_stop; struct rtw89_reg_def dma_stop1; struct rtw89_reg_def dma_stop2; struct rtw89_reg_def dma_busy1; @@ -789,6 +1253,7 @@ struct rtw89_pci_info { u32 rpwm_addr; u32 cpwm_addr; + u32 mit_addr; u32 tx_dma_ch_mask; const struct rtw89_pci_bd_idx_addr *bd_idx_addr_low_power; const struct rtw89_pci_ch_dma_addr_set *dma_addr_set; @@ -812,7 +1277,7 @@ struct rtw89_pci_tx_data { struct rtw89_pci_rx_info { dma_addr_t dma; - u32 fs:1, ls:1, tag:11, len:14; + u32 fs:1, ls:1, tag:13, len:14; }; #define RTW89_PCI_TXBD_OPTION_LS BIT(14) @@ -941,6 +1406,7 @@ struct rtw89_pci_rx_ring { u32 buf_sz; struct sk_buff *diliver_skb; struct rtw89_rx_desc_info diliver_desc; + u32 target_rx_tag:13; }; struct rtw89_pci_isrs { @@ -1059,33 +1525,45 @@ static inline bool rtw89_pci_ltr_is_err_reg_val(u32 val) extern const struct dev_pm_ops rtw89_pm_ops; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1; +extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be; extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM]; extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM]; +extern const struct rtw89_pci_gen_def rtw89_pci_gen_ax; +extern const struct rtw89_pci_gen_def rtw89_pci_gen_be; struct pci_device_id; int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtw89_pci_remove(struct pci_dev *pdev); +void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev); int rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en); int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en); +int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en); u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev, void *txaddr_info_addr, u32 total_len, dma_addr_t dma, u8 *add_info_nr); u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev, void *txaddr_info_addr, u32 total_len, dma_addr_t dma, u8 *add_info_nr); +void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable); void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev); void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev); +void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev); void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); +void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); +void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci, struct rtw89_pci_isrs *isrs); void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci, struct rtw89_pci_isrs *isrs); +void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev, + struct rtw89_pci *rtwpci, + struct rtw89_pci_isrs *isrs); static inline u32 rtw89_chip_fill_txaddr_info(struct rtw89_dev *rtwdev, @@ -1157,4 +1635,47 @@ void rtw89_chip_recognize_intrs(struct rtw89_dev *rtwdev, info->recognize_intrs(rtwdev, rtwpci, isrs); } +static inline int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->mac_pre_init(rtwdev); +} + +static inline int rtw89_pci_ops_mac_pre_deinit(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + if (!gen_def->mac_pre_deinit) + return 0; + + return gen_def->mac_pre_deinit(rtwdev); +} + +static inline int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->mac_post_init(rtwdev); +} + +static inline void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + gen_def->clr_idx_all(rtwdev); +} + +static inline int rtw89_pci_reset_bdram(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->rst_bdram(rtwdev); +} + #endif diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c new file mode 100644 index 0000000000..629ffa4bee --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include <linux/pci.h> + +#include "mac.h" +#include "pci.h" +#include "reg.h" + +enum pcie_rxbd_mode { + PCIE_RXBD_NORM = 0, + PCIE_RXBD_SEP, + PCIE_RXBD_EXT, +}; + +#define PL0_TMR_SCALE_ASIC 1 +#define PL0_TMR_ANA_172US 0x800 +#define PL0_TMR_MAC_1MS 0x27100 +#define PL0_TMR_AUX_1MS 0x1E848 + +static void _patch_pcie_power_wake_be(struct rtw89_dev *rtwdev, bool power_up) +{ + if (power_up) + rtw89_write32_set(rtwdev, R_BE_HCI_OPT_CTRL, BIT_WAKE_CTRL_V1); + else + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, BIT_WAKE_CTRL_V1); +} + +static void rtw89_pci_set_io_rcy_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 scale = PL0_TMR_SCALE_ASIC; + u32 val32; + + if (info->io_rcy_en == MAC_AX_PCIE_ENABLE) { + val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ? + PL0_TMR_ANA_172US : info->io_rcy_tmr; + val32 /= scale; + + rtw89_write32(rtwdev, R_BE_AON_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_MDIO_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_LA_MODE_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_AR_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_AW_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_W_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_B_TMR, val32); + rtw89_write32(rtwdev, R_BE_WDT_R_TMR, val32); + + val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ? + PL0_TMR_MAC_1MS : info->io_rcy_tmr; + val32 /= scale; + rtw89_write32(rtwdev, R_BE_WLAN_WDT_TMR, val32); + rtw89_write32(rtwdev, R_BE_AXIDMA_WDT_TMR, val32); + + val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ? + PL0_TMR_AUX_1MS : info->io_rcy_tmr; + val32 /= scale; + rtw89_write32(rtwdev, R_BE_LOCAL_WDT_TMR, val32); + } else { + rtw89_write32_clr(rtwdev, R_BE_WLAN_WDT, B_BE_WLAN_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_AXIDMA_WDT, B_BE_AXIDMA_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_AON_WDT, B_BE_AON_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_LOCAL_WDT, B_BE_LOCAL_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_MDIO_WDT, B_BE_MDIO_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_LA_MODE_WDT, B_BE_LA_MODE_WDT_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_AR, B_BE_WDT_AR_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_AW, B_BE_WDT_AW_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_W, B_BE_WDT_W_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_B, B_BE_WDT_B_ENABLE); + rtw89_write32_clr(rtwdev, R_BE_WDT_R, B_BE_WDT_R_ENABLE); + } +} + +static void rtw89_pci_ctrl_wpdma_pcie_be(struct rtw89_dev *rtwdev, bool en) +{ + if (en) + rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1, B_BE_STOP_WPDMA); + else + rtw89_write32_set(rtwdev, R_BE_HAXI_DMA_STOP1, B_BE_STOP_WPDMA); +} + +static void rtw89_pci_ctrl_trxdma_pcie_be(struct rtw89_dev *rtwdev, + enum mac_ax_pcie_func_ctrl tx_en, + enum mac_ax_pcie_func_ctrl rx_en, + enum mac_ax_pcie_func_ctrl io_en) +{ + u32 val; + + val = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); + + if (tx_en == MAC_AX_PCIE_ENABLE) + val |= B_BE_TXDMA_EN; + else if (tx_en == MAC_AX_PCIE_DISABLE) + val &= ~B_BE_TXDMA_EN; + + if (rx_en == MAC_AX_PCIE_ENABLE) + val |= B_BE_RXDMA_EN; + else if (rx_en == MAC_AX_PCIE_DISABLE) + val &= ~B_BE_RXDMA_EN; + + if (io_en == MAC_AX_PCIE_ENABLE) + val &= ~B_BE_STOP_AXI_MST; + else if (io_en == MAC_AX_PCIE_DISABLE) + val |= B_BE_STOP_AXI_MST; + + rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val); +} + +static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + struct rtw89_pci_rx_ring *rx_ring; + u32 val; + + val = B_BE_CLR_CH0_IDX | B_BE_CLR_CH1_IDX | B_BE_CLR_CH2_IDX | + B_BE_CLR_CH3_IDX | B_BE_CLR_CH4_IDX | B_BE_CLR_CH5_IDX | + B_BE_CLR_CH6_IDX | B_BE_CLR_CH7_IDX | B_BE_CLR_CH8_IDX | + B_BE_CLR_CH9_IDX | B_BE_CLR_CH10_IDX | B_BE_CLR_CH11_IDX | + B_BE_CLR_CH12_IDX | B_BE_CLR_CH13_IDX | B_BE_CLR_CH14_IDX; + rtw89_write32(rtwdev, R_BE_TXBD_RWPTR_CLR1, val); + + rtw89_write32(rtwdev, R_BE_RXBD_RWPTR_CLR1_V1, + B_BE_CLR_RXQ0_IDX | B_BE_CLR_RPQ0_IDX); + + rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ]; + rtw89_write16(rtwdev, R_BE_RXQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1); + + rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ]; + rtw89_write16(rtwdev, R_BE_RPQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1); +} + +static int rtw89_pci_poll_txdma_ch_idle_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + return read_poll_timeout(rtw89_read32, val, (val & DMA_BUSY1_CHECK_BE) == 0, + 10, 1000, false, rtwdev, R_BE_HAXI_DMA_BUSY1); +} + +static int rtw89_pci_poll_rxdma_ch_idle_be(struct rtw89_dev *rtwdev) +{ + u32 check; + u32 val; + + check = B_BE_RXQ0_BUSY_V1 | B_BE_RPQ0_BUSY_V1; + + return read_poll_timeout(rtw89_read32, val, (val & check) == 0, + 10, 1000, false, rtwdev, R_BE_HAXI_DMA_BUSY1); +} + +static int rtw89_pci_poll_dma_all_idle_be(struct rtw89_dev *rtwdev) +{ + int ret; + + ret = rtw89_pci_poll_txdma_ch_idle_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "txdma ch busy\n"); + return ret; + } + + ret = rtw89_pci_poll_rxdma_ch_idle_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "rxdma ch busy\n"); + return ret; + } + + return 0; +} + +static void rtw89_pci_mode_op_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 val32_init1, val32_rxapp, val32_exp; + + val32_init1 = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); + val32_rxapp = rtw89_read32(rtwdev, R_BE_RX_APPEND_MODE); + val32_exp = rtw89_read32(rtwdev, R_BE_HAXI_EXP_CTRL_V1); + + if (info->rxbd_mode == MAC_AX_RXBD_PKT) { + val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_NORM, + B_BE_RXQ_RXBD_MODE_MASK); + } else if (info->rxbd_mode == MAC_AX_RXBD_SEP) { + val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_SEP, + B_BE_RXQ_RXBD_MODE_MASK); + val32_rxapp = u32_replace_bits(val32_rxapp, 0, + B_BE_APPEND_LEN_MASK); + } + + val32_init1 = u32_replace_bits(val32_init1, info->tx_burst, + B_BE_MAX_TXDMA_MASK); + val32_init1 = u32_replace_bits(val32_init1, info->rx_burst, + B_BE_MAX_RXDMA_MASK); + val32_exp = u32_replace_bits(val32_exp, info->multi_tag_num, + B_BE_MAX_TAG_NUM_MASK); + val32_init1 = u32_replace_bits(val32_init1, info->wd_dma_idle_intvl, + B_BE_CFG_WD_PERIOD_IDLE_MASK); + val32_init1 = u32_replace_bits(val32_init1, info->wd_dma_act_intvl, + B_BE_CFG_WD_PERIOD_ACTIVE_MASK); + + rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val32_init1); + rtw89_write32(rtwdev, R_BE_RX_APPEND_MODE, val32_rxapp); + rtw89_write32(rtwdev, R_BE_HAXI_EXP_CTRL_V1, val32_exp); +} + +static int rtw89_pci_rst_bdram_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + rtw89_write32_set(rtwdev, R_BE_HAXI_INIT_CFG1, B_BE_SET_BDRAM_BOUND); + + return read_poll_timeout(rtw89_read32, val, !(val & B_BE_SET_BDRAM_BOUND), + 50, 500000, false, rtwdev, R_BE_HAXI_INIT_CFG1); +} + +static void rtw89_pci_debounce_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + + val32 = rtw89_read32(rtwdev, R_BE_SYS_PAGE_CLK_GATED); + val32 = u32_replace_bits(val32, 0, B_BE_PCIE_PRST_DEBUNC_PERIOD_MASK); + val32 |= B_BE_SYM_PRST_DEBUNC_SEL; + rtw89_write32(rtwdev, R_BE_SYS_PAGE_CLK_GATED, val32); +} + +static void rtw89_pci_ldo_low_pwr_be(struct rtw89_dev *rtwdev) +{ + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_PSUS_OFF_CAPC_EN); + rtw89_write32_set(rtwdev, R_BE_SYS_PAGE_CLK_GATED, + B_BE_SOP_OFFPOOBS_PC | B_BE_CPHY_AUXCLK_OP | + B_BE_CPHY_POWER_READY_CHK); + rtw89_write32_clr(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_PCIE_FORCE_IBX_EN | + B_BE_PCIE_DIS_L2_RTK_PERST | + B_BE_PCIE_DIS_L2__CTRL_LDO_HCI); + rtw89_write32_clr(rtwdev, R_BE_L1_2_CTRL_HCILDO, B_BE_PCIE_DIS_L1_2_CTRL_HCILDO); +} + +static void rtw89_pci_pcie_setting_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; + + rtw89_write32_set(rtwdev, R_BE_PCIE_FRZ_CLK, B_BE_PCIE_EN_AUX_CLK); + rtw89_write32_clr(rtwdev, R_BE_PCIE_PS_CTRL, B_BE_CMAC_EXIT_L1_EN); + + if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) + return; + + rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_R_SYM_AUTOLOAD_WITH_PMC_SEL); + rtw89_write32_set(rtwdev, R_BE_PCIE_LAT_CTRL, B_BE_SYM_AUX_CLK_SEL); +} + +static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + + rtw89_write32(rtwdev, R_BE_PL1_DBG_INFO, 0x0); + rtw89_write32_set(rtwdev, R_BE_FWS1IMR, B_BE_PCIE_SER_TIMEOUT_INDIC_EN); + rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN); + + val32 = rtw89_read32(rtwdev, R_BE_REG_PL1_MASK); + val32 |= B_BE_SER_PMU_IMR | B_BE_SER_L1SUB_IMR | B_BE_SER_PM_MASTER_IMR | + B_BE_SER_LTSSM_IMR | B_BE_SER_PM_CLK_MASK | B_BE_SER_PCLKREQ_ACK_MASK; + rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32); +} + +static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool all_en, + bool h2c_en) +{ + u32 mask_all; + u32 val; + + mask_all = B_BE_STOP_CH0 | B_BE_STOP_CH1 | B_BE_STOP_CH2 | + B_BE_STOP_CH3 | B_BE_STOP_CH4 | B_BE_STOP_CH5 | + B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 | + B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11; + + val = rtw89_read32(rtwdev, R_BE_HAXI_DMA_STOP1); + val |= B_BE_STOP_CH13 | B_BE_STOP_CH14; + + if (all_en) + val &= ~mask_all; + else + val |= mask_all; + + if (h2c_en) + val &= ~B_BE_STOP_CH12; + else + val |= B_BE_STOP_CH12; + + rtw89_write32(rtwdev, R_BE_HAXI_DMA_STOP1, val); +} + +static int rtw89_pci_ops_mac_pre_init_be(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_pci_set_io_rcy_be(rtwdev); + _patch_pcie_power_wake_be(rtwdev, true); + rtw89_pci_ctrl_wpdma_pcie_be(rtwdev, false); + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_DISABLE, + MAC_AX_PCIE_DISABLE, MAC_AX_PCIE_DISABLE); + rtw89_pci_clr_idx_all_be(rtwdev); + + ret = rtw89_pci_poll_dma_all_idle_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR] poll pcie dma all idle\n"); + return ret; + } + + rtw89_pci_mode_op_be(rtwdev); + rtw89_pci_ops_reset(rtwdev); + + ret = rtw89_pci_rst_bdram_be(rtwdev); + if (ret) { + rtw89_err(rtwdev, "[ERR]pcie rst bdram\n"); + return ret; + } + + rtw89_pci_debounce_be(rtwdev); + rtw89_pci_ldo_low_pwr_be(rtwdev); + rtw89_pci_pcie_setting_be(rtwdev); + rtw89_pci_ser_setting_be(rtwdev); + + rtw89_pci_ctrl_txdma_ch_be(rtwdev, false, true); + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_ENABLE, + MAC_AX_PCIE_ENABLE, MAC_AX_PCIE_ENABLE); + + return 0; +} + +static int rtw89_pci_ops_mac_pre_deinit_be(struct rtw89_dev *rtwdev) +{ + u32 val; + + _patch_pcie_power_wake_be(rtwdev, false); + + val = rtw89_read32_mask(rtwdev, R_BE_IC_PWR_STATE, B_BE_WLMAC_PWR_STE_MASK); + if (val == 0) + return 0; + + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_DISABLE, + MAC_AX_PCIE_DISABLE, MAC_AX_PCIE_DISABLE); + rtw89_pci_clr_idx_all_be(rtwdev); + + return 0; +} + +int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en) +{ + u32 ctrl0, cfg0, cfg1, dec_ctrl, idle_ltcy, act_ltcy, dis_ltcy; + + ctrl0 = rtw89_read32(rtwdev, R_BE_LTR_CTRL_0); + if (rtw89_pci_ltr_is_err_reg_val(ctrl0)) + return -EINVAL; + cfg0 = rtw89_read32(rtwdev, R_BE_LTR_CFG_0); + if (rtw89_pci_ltr_is_err_reg_val(cfg0)) + return -EINVAL; + cfg1 = rtw89_read32(rtwdev, R_BE_LTR_CFG_1); + if (rtw89_pci_ltr_is_err_reg_val(cfg1)) + return -EINVAL; + dec_ctrl = rtw89_read32(rtwdev, R_BE_LTR_DECISION_CTRL_V1); + if (rtw89_pci_ltr_is_err_reg_val(dec_ctrl)) + return -EINVAL; + idle_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1); + if (rtw89_pci_ltr_is_err_reg_val(idle_ltcy)) + return -EINVAL; + act_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1); + if (rtw89_pci_ltr_is_err_reg_val(act_ltcy)) + return -EINVAL; + dis_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX0_V1); + if (rtw89_pci_ltr_is_err_reg_val(dis_ltcy)) + return -EINVAL; + + if (en) { + dec_ctrl |= B_BE_ENABLE_LTR_CTL_DECISION | B_BE_LTR_HW_DEC_EN_V1; + ctrl0 |= B_BE_LTR_HW_EN; + } else { + dec_ctrl &= ~(B_BE_ENABLE_LTR_CTL_DECISION | B_BE_LTR_HW_DEC_EN_V1 | + B_BE_LTR_EN_PORT_V1_MASK); + ctrl0 &= ~B_BE_LTR_HW_EN; + } + + dec_ctrl = u32_replace_bits(dec_ctrl, PCI_LTR_SPC_500US, + B_BE_LTR_SPACE_IDX_MASK); + cfg0 = u32_replace_bits(cfg0, PCI_LTR_IDLE_TIMER_3_2MS, + B_BE_LTR_IDLE_TIMER_IDX_MASK); + cfg1 = u32_replace_bits(cfg1, 0xC0, B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK); + cfg1 = u32_replace_bits(cfg1, 0xC0, B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK); + cfg0 = u32_replace_bits(cfg0, 1, B_BE_LTR_IDX_ACTIVE_MASK); + cfg0 = u32_replace_bits(cfg0, 3, B_BE_LTR_IDX_IDLE_MASK); + dec_ctrl = u32_replace_bits(dec_ctrl, 0, B_BE_LTR_IDX_DISABLE_V1_MASK); + + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1, 0x90039003); + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1, 0x880b880b); + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX0_V1, 0); + rtw89_write32(rtwdev, R_BE_LTR_DECISION_CTRL_V1, dec_ctrl); + rtw89_write32(rtwdev, R_BE_LTR_CFG_0, cfg0); + rtw89_write32(rtwdev, R_BE_LTR_CFG_1, cfg1); + rtw89_write32(rtwdev, R_BE_LTR_CTRL_0, ctrl0); + + return 0; +} +EXPORT_SYMBOL(rtw89_pci_ltr_set_v2); + +static void rtw89_pci_configure_mit_be(struct rtw89_dev *rtwdev) +{ + u32 cnt; + u32 val; + + rtw89_write32_mask(rtwdev, R_BE_PCIE_MIT0_TMR, + B_BE_PCIE_MIT0_RX_TMR_MASK, BE_MIT0_TMR_UNIT_1MS); + + val = rtw89_read32(rtwdev, R_BE_PCIE_MIT0_CNT); + cnt = min_t(u32, U8_MAX, RTW89_PCI_RXBD_NUM_MAX / 2); + val = u32_replace_bits(val, cnt, B_BE_PCIE_RX_MIT0_CNT_MASK); + val = u32_replace_bits(val, 2, B_BE_PCIE_RX_MIT0_TMR_CNT_MASK); + rtw89_write32(rtwdev, R_BE_PCIE_MIT0_CNT, val); +} + +static int rtw89_pci_ops_mac_post_init_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + int ret; + + ret = info->ltr_set(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "pci ltr set fail\n"); + return ret; + } + + rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_IGNORE, + MAC_AX_PCIE_IGNORE, MAC_AX_PCIE_ENABLE); + rtw89_pci_ctrl_wpdma_pcie_be(rtwdev, true); + rtw89_pci_ctrl_txdma_ch_be(rtwdev, true, true); + rtw89_pci_configure_mit_be(rtwdev); + + return 0; +} + +static int rtw89_pci_poll_io_idle_be(struct rtw89_dev *rtwdev) +{ + u32 sts; + int ret; + + ret = read_poll_timeout_atomic(rtw89_read32, sts, + !(sts & B_BE_HAXI_MST_BUSY), + 10, 1000, false, rtwdev, + R_BE_HAXI_DMA_BUSY1); + if (ret) { + rtw89_err(rtwdev, "pci dmach busy1 0x%X\n", sts); + return ret; + } + + return 0; +} + +static int rtw89_pci_lv1rst_stop_dma_be(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_pci_ctrl_dma_all(rtwdev, false); + ret = rtw89_pci_poll_io_idle_be(rtwdev); + if (!ret) + return 0; + + rtw89_debug(rtwdev, RTW89_DBG_HCI, + "[PCIe] poll_io_idle fail; reset hci dma trx\n"); + + rtw89_mac_ctrl_hci_dma_trx(rtwdev, false); + rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); + + return rtw89_pci_poll_io_idle_be(rtwdev); +} + +static int rtw89_pci_lv1rst_start_dma_be(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_mac_ctrl_hci_dma_trx(rtwdev, false); + rtw89_mac_ctrl_hci_dma_trx(rtwdev, true); + rtw89_pci_clr_idx_all(rtwdev); + + ret = rtw89_pci_rst_bdram_be(rtwdev); + if (ret) + return ret; + + rtw89_pci_ctrl_dma_all(rtwdev, true); + return 0; +} + +const struct rtw89_pci_gen_def rtw89_pci_gen_be = { + .isr_rdu = B_BE_RDU_CH1_INT | B_BE_RDU_CH0_INT, + .isr_halt_c2h = B_BE_HALT_C2H_INT, + .isr_wdt_timeout = B_BE_WDT_TIMEOUT_INT, + .isr_clear_rpq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RPQ0_ISR_V1}, + .isr_clear_rxq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RX0P2_ISR_V1}, + + .mac_pre_init = rtw89_pci_ops_mac_pre_init_be, + .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit_be, + .mac_post_init = rtw89_pci_ops_mac_post_init_be, + + .clr_idx_all = rtw89_pci_clr_idx_all_be, + .rst_bdram = rtw89_pci_rst_bdram_be, + + .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_be, + .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_be, +}; +EXPORT_SYMBOL(rtw89_pci_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 17ccc9efed..bafc7b1cc1 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2445,6 +2445,298 @@ void (* const rtw89_phy_c2h_ra_handler[])(struct rtw89_dev *rtwdev, [RTW89_PHY_C2H_FUNC_TXSTS] = NULL, }; +static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, + enum rtw89_phy_c2h_rfk_log_func func, + void *content, u16 len) +{ + struct rtw89_c2h_rf_txgapk_rpt_log *txgapk; + struct rtw89_c2h_rf_rxdck_rpt_log *rxdck; + struct rtw89_c2h_rf_dack_rpt_log *dack; + struct rtw89_c2h_rf_dpk_rpt_log *dpk; + + switch (func) { + case RTW89_PHY_C2H_RFK_LOG_FUNC_DPK: + if (len != sizeof(*dpk)) + goto out; + + dpk = content; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "DPK ver:%d idx:%2ph band:%2ph bw:%2ph ch:%2ph path:%2ph\n", + dpk->ver, dpk->idx, dpk->band, dpk->bw, dpk->ch, dpk->path_ok); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "DPK txagc:%2ph ther:%2ph gs:%2ph dc_i:%4ph dc_q:%4ph\n", + dpk->txagc, dpk->ther, dpk->gs, dpk->dc_i, dpk->dc_q); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "DPK corr_v:%2ph corr_i:%2ph to:%2ph ov:%2ph\n", + dpk->corr_val, dpk->corr_idx, dpk->is_timeout, dpk->rxbb_ov); + return; + case RTW89_PHY_C2H_RFK_LOG_FUNC_DACK: + if (len != sizeof(*dack)) + goto out; + + dack = content; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]ver=0x%x 0x%x\n", + dack->fwdack_ver, dack->fwdack_rpt_ver); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 CDACK ic = [0x%x, 0x%x]\n", + dack->cdack_d[0][0][0], dack->cdack_d[0][0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 CDACK qc = [0x%x, 0x%x]\n", + dack->cdack_d[0][1][0], dack->cdack_d[0][1][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 CDACK ic = [0x%x, 0x%x]\n", + dack->cdack_d[1][0][0], dack->cdack_d[1][0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 CDACK qc = [0x%x, 0x%x]\n", + dack->cdack_d[1][1][0], dack->cdack_d[1][1][1]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK ic = [0x%x, 0x%x]\n", + dack->addck2_d[0][0][0], dack->addck2_d[0][0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK qc = [0x%x, 0x%x]\n", + dack->addck2_d[0][1][0], dack->addck2_d[0][1][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_DCK ic = [0x%x, 0x%x]\n", + dack->addck2_d[1][0][0], dack->addck2_d[1][0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_DCK qc = [0x%x, 0x%x]\n", + dack->addck2_d[1][1][0], dack->addck2_d[1][1][1]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_GAINK ic = 0x%x, qc = 0x%x\n", + dack->adgaink_d[0][0], dack->adgaink_d[0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_GAINK ic = 0x%x, qc = 0x%x\n", + dack->adgaink_d[1][0], dack->adgaink_d[1][1]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 DAC_DCK ic = 0x%x, qc = 0x%x\n", + dack->dadck_d[0][0], dack->dadck_d[0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 DAC_DCK ic = 0x%x, qc = 0x%x\n", + dack->dadck_d[1][0], dack->dadck_d[1][1]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 biask iqc = 0x%x\n", + dack->biask_d[0][0]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 biask iqc = 0x%x\n", + dack->biask_d[1][0]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic: %*ph\n", + (int)sizeof(dack->msbk_d[0][0]), dack->msbk_d[0][0]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc: %*ph\n", + (int)sizeof(dack->msbk_d[0][1]), dack->msbk_d[0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK ic: %*ph\n", + (int)sizeof(dack->msbk_d[1][0]), dack->msbk_d[1][0]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK qc: %*ph\n", + (int)sizeof(dack->msbk_d[1][1]), dack->msbk_d[1][1]); + return; + case RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK: + if (len != sizeof(*rxdck)) + goto out; + + rxdck = content; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "RXDCK ver:%d band:%2ph bw:%2ph ch:%2ph to:%2ph\n", + rxdck->ver, rxdck->band, rxdck->bw, rxdck->ch, + rxdck->timeout); + return; + case RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK: + if (len != sizeof(*txgapk)) + goto out; + + txgapk = content; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TXGAPK]rpt r0x8010[0]=0x%x, r0x8010[1]=0x%x\n", + le32_to_cpu(txgapk->r0x8010[0]), + le32_to_cpu(txgapk->r0x8010[1])); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt chk_id = %d\n", + txgapk->chk_id); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt chk_cnt = %d\n", + le32_to_cpu(txgapk->chk_cnt)); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt ver = 0x%x\n", + txgapk->ver); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt rsv1 = %d\n", + txgapk->rsv1); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt track_d[0] = %*ph\n", + (int)sizeof(txgapk->track_d[0]), txgapk->track_d[0]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt power_d[0] = %*ph\n", + (int)sizeof(txgapk->power_d[0]), txgapk->power_d[0]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt track_d[1] = %*ph\n", + (int)sizeof(txgapk->track_d[1]), txgapk->track_d[1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt power_d[1] = %*ph\n", + (int)sizeof(txgapk->power_d[1]), txgapk->power_d[1]); + return; + default: + break; + } + +out: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "unexpected RFK func %d report log with length %d\n", func, len); +} + +static bool rtw89_phy_c2h_rfk_run_log(struct rtw89_dev *rtwdev, + enum rtw89_phy_c2h_rfk_log_func func, + void *content, u16 len) +{ + struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; + const struct rtw89_c2h_rf_run_log *log = content; + const struct rtw89_fw_element_hdr *elm; + u32 fmt_idx; + u16 offset; + + if (sizeof(*log) != len) + return false; + + if (!elm_info->rfk_log_fmt) + return false; + + elm = elm_info->rfk_log_fmt->elm[func]; + fmt_idx = le32_to_cpu(log->fmt_idx); + if (!elm || fmt_idx >= elm->u.rfk_log_fmt.nr) + return false; + + offset = le16_to_cpu(elm->u.rfk_log_fmt.offset[fmt_idx]); + if (offset == 0) + return false; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, &elm->u.common.contents[offset], + le32_to_cpu(log->arg[0]), le32_to_cpu(log->arg[1]), + le32_to_cpu(log->arg[2]), le32_to_cpu(log->arg[3])); + + return true; +} + +static void rtw89_phy_c2h_rfk_log(struct rtw89_dev *rtwdev, struct sk_buff *c2h, + u32 len, enum rtw89_phy_c2h_rfk_log_func func, + const char *rfk_name) +{ + struct rtw89_c2h_hdr *c2h_hdr = (struct rtw89_c2h_hdr *)c2h->data; + struct rtw89_c2h_rf_log_hdr *log_hdr; + void *log_ptr = c2h_hdr; + u16 content_len; + u16 chunk_len; + bool handled; + + if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK)) + return; + + log_ptr += sizeof(*c2h_hdr); + len -= sizeof(*c2h_hdr); + + while (len > sizeof(*log_hdr)) { + log_hdr = log_ptr; + content_len = le16_to_cpu(log_hdr->len); + chunk_len = content_len + sizeof(*log_hdr); + + if (chunk_len > len) + break; + + switch (log_hdr->type) { + case RTW89_RF_RUN_LOG: + handled = rtw89_phy_c2h_rfk_run_log(rtwdev, func, + log_hdr->content, content_len); + if (handled) + break; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "%s run: %*ph\n", + rfk_name, content_len, log_hdr->content); + break; + case RTW89_RF_RPT_LOG: + rtw89_phy_c2h_rfk_rpt_log(rtwdev, func, + log_hdr->content, content_len); + break; + default: + return; + } + + log_ptr += chunk_len; + len -= chunk_len; + } +} + +static void +rtw89_phy_c2h_rfk_log_iqk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ + rtw89_phy_c2h_rfk_log(rtwdev, c2h, len, + RTW89_PHY_C2H_RFK_LOG_FUNC_IQK, "IQK"); +} + +static void +rtw89_phy_c2h_rfk_log_dpk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ + rtw89_phy_c2h_rfk_log(rtwdev, c2h, len, + RTW89_PHY_C2H_RFK_LOG_FUNC_DPK, "DPK"); +} + +static void +rtw89_phy_c2h_rfk_log_dack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ + rtw89_phy_c2h_rfk_log(rtwdev, c2h, len, + RTW89_PHY_C2H_RFK_LOG_FUNC_DACK, "DACK"); +} + +static void +rtw89_phy_c2h_rfk_log_rxdck(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ + rtw89_phy_c2h_rfk_log(rtwdev, c2h, len, + RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK, "RX_DCK"); +} + +static void +rtw89_phy_c2h_rfk_log_tssi(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ + rtw89_phy_c2h_rfk_log(rtwdev, c2h, len, + RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI, "TSSI"); +} + +static void +rtw89_phy_c2h_rfk_log_txgapk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ + rtw89_phy_c2h_rfk_log(rtwdev, c2h, len, + RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK, "TXGAPK"); +} + +static +void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev, + struct sk_buff *c2h, u32 len) = { + [RTW89_PHY_C2H_RFK_LOG_FUNC_IQK] = rtw89_phy_c2h_rfk_log_iqk, + [RTW89_PHY_C2H_RFK_LOG_FUNC_DPK] = rtw89_phy_c2h_rfk_log_dpk, + [RTW89_PHY_C2H_RFK_LOG_FUNC_DACK] = rtw89_phy_c2h_rfk_log_dack, + [RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK] = rtw89_phy_c2h_rfk_log_rxdck, + [RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI] = rtw89_phy_c2h_rfk_log_tssi, + [RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK] = rtw89_phy_c2h_rfk_log_txgapk, +}; + +static void +rtw89_phy_c2h_rfk_report_state(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ +} + +static +void (* const rtw89_phy_c2h_rfk_report_handler[])(struct rtw89_dev *rtwdev, + struct sk_buff *c2h, u32 len) = { + [RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE] = rtw89_phy_c2h_rfk_report_state, +}; + +bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func) +{ + switch (class) { + case RTW89_PHY_C2H_RFK_LOG: + switch (func) { + case RTW89_PHY_C2H_RFK_LOG_FUNC_IQK: + case RTW89_PHY_C2H_RFK_LOG_FUNC_DPK: + case RTW89_PHY_C2H_RFK_LOG_FUNC_DACK: + case RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK: + case RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI: + case RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK: + return true; + default: + return false; + } + case RTW89_PHY_C2H_RFK_REPORT: + switch (func) { + case RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE: + return true; + default: + return false; + } + default: + return false; + } +} + void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len, u8 class, u8 func) { @@ -2456,6 +2748,14 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, if (func < RTW89_PHY_C2H_FUNC_RA_MAX) handler = rtw89_phy_c2h_ra_handler[func]; break; + case RTW89_PHY_C2H_RFK_LOG: + if (func < ARRAY_SIZE(rtw89_phy_c2h_rfk_log_handler)) + handler = rtw89_phy_c2h_rfk_log_handler[func]; + break; + case RTW89_PHY_C2H_RFK_REPORT: + if (func < ARRAY_SIZE(rtw89_phy_c2h_rfk_report_handler)) + handler = rtw89_phy_c2h_rfk_report_handler[func]; + break; case RTW89_PHY_C2H_CLASS_DM: if (func == RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY) return; @@ -4620,6 +4920,29 @@ static void rtw89_phy_env_monitor_init(struct rtw89_dev *rtwdev) rtw89_phy_ifs_clm_setting_init(rtwdev); } +static void rtw89_phy_edcca_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs; + struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak; + + memset(edcca_bak, 0, sizeof(*edcca_bak)); + + if (rtwdev->chip->chip_id == RTL8922A && rtwdev->hal.cv == CHIP_CAV) { + rtw89_phy_set_phy_regs(rtwdev, R_TXGATING, B_TXGATING_EN, 0); + rtw89_phy_set_phy_regs(rtwdev, R_CTLTOP, B_CTLTOP_VAL, 2); + rtw89_phy_set_phy_regs(rtwdev, R_CTLTOP, B_CTLTOP_ON, 1); + rtw89_phy_set_phy_regs(rtwdev, R_SPOOF_CG, B_SPOOF_CG_EN, 0); + rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_CG_EN, 0); + rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_FFT_EN, 0); + rtw89_phy_set_phy_regs(rtwdev, R_SEGSND, B_SEGSND_EN, 0); + rtw89_phy_set_phy_regs(rtwdev, R_SEGSND, B_SEGSND_EN, 1); + rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_FFT_EN, 1); + } + + rtw89_phy_write32_mask(rtwdev, edcca_regs->tx_collision_t2r_st, + edcca_regs->tx_collision_t2r_st_mask, 0x29); +} + void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) { rtw89_phy_stat_init(rtwdev); @@ -4630,6 +4953,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_physts_parsing_init(rtwdev); rtw89_phy_dig_init(rtwdev); rtw89_phy_cfo_init(rtwdev); + rtw89_phy_edcca_init(rtwdev); rtw89_phy_ul_tb_info_init(rtwdev); rtw89_phy_antdiv_init(rtwdev); rtw89_chip_rfe_gpio(rtwdev); @@ -4892,23 +5216,188 @@ void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx, } EXPORT_SYMBOL(rtw89_decode_chan_idx); -#define EDCCA_DEFAULT 249 void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan) { - u32 reg = rtwdev->chip->edcca_lvl_reg; - struct rtw89_hal *hal = &rtwdev->hal; - u32 val; + const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs; + struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak; if (scan) { - hal->edcca_bak = rtw89_phy_read32(rtwdev, reg); - val = hal->edcca_bak; - u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_A_MSK); - u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_P_MSK); - u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_PPDU_LVL_MSK); - rtw89_phy_write32(rtwdev, reg, val); + edcca_bak->a = + rtw89_phy_read32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_mask); + edcca_bak->p = + rtw89_phy_read32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_p_mask); + edcca_bak->ppdu = + rtw89_phy_read32_mask(rtwdev, edcca_regs->ppdu_level, + edcca_regs->ppdu_mask); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_mask, EDCCA_MAX); + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_p_mask, EDCCA_MAX); + rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level, + edcca_regs->ppdu_mask, EDCCA_MAX); + } else { + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_mask, + edcca_bak->a); + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_p_mask, + edcca_bak->p); + rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level, + edcca_regs->ppdu_mask, + edcca_bak->ppdu); + } +} + +static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev) +{ + const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs; + bool flag_fb, flag_p20, flag_s20, flag_s40, flag_s80; + s8 pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80; + u8 path, per20_bitmap; + u8 pwdb[8]; + u32 tmp; + + if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_EDCCA)) + return; + + if (rtwdev->chip->chip_id == RTL8922A) + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be, + edcca_regs->rpt_sel_be_mask, 0); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 0); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b); + path = u32_get_bits(tmp, B_EDCCA_RPT_B_PATH_MASK); + flag_s80 = u32_get_bits(tmp, B_EDCCA_RPT_B_S80); + flag_s40 = u32_get_bits(tmp, B_EDCCA_RPT_B_S40); + flag_s20 = u32_get_bits(tmp, B_EDCCA_RPT_B_S20); + flag_p20 = u32_get_bits(tmp, B_EDCCA_RPT_B_P20); + flag_fb = u32_get_bits(tmp, B_EDCCA_RPT_B_FB); + pwdb_s20 = u32_get_bits(tmp, MASKBYTE1); + pwdb_p20 = u32_get_bits(tmp, MASKBYTE2); + pwdb_fb = u32_get_bits(tmp, MASKBYTE3); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 4); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b); + pwdb_s80 = u32_get_bits(tmp, MASKBYTE1); + pwdb_s40 = u32_get_bits(tmp, MASKBYTE2); + + per20_bitmap = rtw89_phy_read32_mask(rtwdev, edcca_regs->rpt_a, + MASKBYTE0); + + if (rtwdev->chip->chip_id == RTL8922A) { + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be, + edcca_regs->rpt_sel_be_mask, 4); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b); + pwdb[0] = u32_get_bits(tmp, MASKBYTE3); + pwdb[1] = u32_get_bits(tmp, MASKBYTE2); + pwdb[2] = u32_get_bits(tmp, MASKBYTE1); + pwdb[3] = u32_get_bits(tmp, MASKBYTE0); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be, + edcca_regs->rpt_sel_be_mask, 5); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b); + pwdb[4] = u32_get_bits(tmp, MASKBYTE3); + pwdb[5] = u32_get_bits(tmp, MASKBYTE2); + pwdb[6] = u32_get_bits(tmp, MASKBYTE1); + pwdb[7] = u32_get_bits(tmp, MASKBYTE0); } else { - rtw89_phy_write32(rtwdev, reg, hal->edcca_bak); + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 0); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a); + pwdb[0] = u32_get_bits(tmp, MASKBYTE3); + pwdb[1] = u32_get_bits(tmp, MASKBYTE2); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 1); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a); + pwdb[2] = u32_get_bits(tmp, MASKBYTE3); + pwdb[3] = u32_get_bits(tmp, MASKBYTE2); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 2); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a); + pwdb[4] = u32_get_bits(tmp, MASKBYTE3); + pwdb[5] = u32_get_bits(tmp, MASKBYTE2); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel, + edcca_regs->rpt_sel_mask, 3); + tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a); + pwdb[6] = u32_get_bits(tmp, MASKBYTE3); + pwdb[7] = u32_get_bits(tmp, MASKBYTE2); } + + rtw89_debug(rtwdev, RTW89_DBG_EDCCA, + "[EDCCA]: edcca_bitmap = %04x\n", per20_bitmap); + + rtw89_debug(rtwdev, RTW89_DBG_EDCCA, + "[EDCCA]: pwdb per20{0,1,2,3,4,5,6,7} = {%d,%d,%d,%d,%d,%d,%d,%d}(dBm)\n", + pwdb[0], pwdb[1], pwdb[2], pwdb[3], pwdb[4], pwdb[5], + pwdb[6], pwdb[7]); + + rtw89_debug(rtwdev, RTW89_DBG_EDCCA, + "[EDCCA]: path=%d, flag {FB,p20,s20,s40,s80} = {%d,%d,%d,%d,%d}\n", + path, flag_fb, flag_p20, flag_s20, flag_s40, flag_s80); + + rtw89_debug(rtwdev, RTW89_DBG_EDCCA, + "[EDCCA]: pwdb {FB,p20,s20,s40,s80} = {%d,%d,%d,%d,%d}(dBm)\n", + pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80); +} + +static u8 rtw89_phy_edcca_get_thre_by_rssi(struct rtw89_dev *rtwdev) +{ + struct rtw89_phy_ch_info *ch_info = &rtwdev->ch_info; + bool is_linked = rtwdev->total_sta_assoc > 0; + u8 rssi_min = ch_info->rssi_min >> 1; + u8 edcca_thre; + + if (!is_linked) { + edcca_thre = EDCCA_MAX; + } else { + edcca_thre = rssi_min - RSSI_UNIT_CONVER + EDCCA_UNIT_CONVER - + EDCCA_TH_REF; + edcca_thre = max_t(u8, edcca_thre, EDCCA_TH_L2H_LB); + } + + return edcca_thre; +} + +void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev) +{ + const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs; + struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak; + u8 th; + + th = rtw89_phy_edcca_get_thre_by_rssi(rtwdev); + if (th == edcca_bak->th_old) + return; + + edcca_bak->th_old = th; + + rtw89_debug(rtwdev, RTW89_DBG_EDCCA, + "[EDCCA]: Normal Mode, EDCCA_th = %d\n", th); + + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_mask, th); + rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level, + edcca_regs->edcca_p_mask, th); + rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level, + edcca_regs->ppdu_mask, th); +} + +void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + + if (hal->disabled_dm_bitmap & BIT(RTW89_DM_DYNAMIC_EDCCA)) + return; + + rtw89_phy_edcca_thre_calc(rtwdev); + rtw89_phy_edcca_log(rtwdev); } static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = { diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 5c85122e7b..3e379077c6 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -122,6 +122,13 @@ #define PHYSTS_RSVD BIT(RTW89_RX_TYPE_RSVD) #define PPDU_FILTER_BITMAP (PHYSTS_MGNT | PHYSTS_DATA) +#define EDCCA_MAX 249 +#define EDCCA_TH_L2H_LB 66 +#define EDCCA_TH_REF 3 +#define EDCCA_HL_DIFF_NORMAL 8 +#define RSSI_UNIT_CONVER 110 +#define EDCCA_UNIT_CONVER 128 + enum rtw89_phy_c2h_ra_func { RTW89_PHY_C2H_FUNC_STS_RPT, RTW89_PHY_C2H_FUNC_MU_GPTBL_RPT, @@ -129,6 +136,21 @@ enum rtw89_phy_c2h_ra_func { RTW89_PHY_C2H_FUNC_RA_MAX, }; +enum rtw89_phy_c2h_rfk_log_func { + RTW89_PHY_C2H_RFK_LOG_FUNC_IQK = 0, + RTW89_PHY_C2H_RFK_LOG_FUNC_DPK = 1, + RTW89_PHY_C2H_RFK_LOG_FUNC_DACK = 2, + RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK = 3, + RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI = 4, + RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK = 5, + + RTW89_PHY_C2H_RFK_LOG_FUNC_NUM, +}; + +enum rtw89_phy_c2h_rfk_report_func { + RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE = 0, +}; + enum rtw89_phy_c2h_dm_func { RTW89_PHY_C2H_DM_FUNC_FW_TEST, RTW89_PHY_C2H_DM_FUNC_FW_TRIG_TX_RPT, @@ -142,6 +164,8 @@ enum rtw89_phy_c2h_class { RTW89_PHY_C2H_CLASS_RUA, RTW89_PHY_C2H_CLASS_RA, RTW89_PHY_C2H_CLASS_DM, + RTW89_PHY_C2H_RFK_LOG = 0x8, + RTW89_PHY_C2H_RFK_REPORT = 0x9, RTW89_PHY_C2H_CLASS_BTC_MIN = 0x10, RTW89_PHY_C2H_CLASS_BTC_MAX = 0x17, RTW89_PHY_C2H_CLASS_MAX, @@ -284,8 +308,6 @@ struct rtw89_txpwr_byrate_cfg { u32 data; }; -#define DELTA_SWINGIDX_SIZE 30 - struct rtw89_txpwr_track_cfg { const s8 (*delta_swingidx_6gb_n)[DELTA_SWINGIDX_SIZE]; const s8 (*delta_swingidx_6gb_p)[DELTA_SWINGIDX_SIZE]; @@ -478,6 +500,10 @@ struct rtw89_txpwr_limit_ru_be { s8 ru106_26[RTW89_RU_SEC_NUM_BE]; }; +struct rtw89_phy_rfk_log_fmt { + const struct rtw89_fw_element_hdr *elm[RTW89_PHY_C2H_RFK_LOG_FUNC_NUM]; +}; + struct rtw89_phy_gen_def { u32 cr_base; const struct rtw89_ccx_regs *ccx; @@ -591,6 +617,22 @@ enum rtw89_gain_offset rtw89_subband_to_gain_offset_band_of_ofdm(enum rtw89_subb return RTW89_GAIN_OFFSET_5G_MID; case RTW89_CH_5G_BAND_4: return RTW89_GAIN_OFFSET_5G_HIGH; + case RTW89_CH_6G_BAND_IDX0: + return RTW89_GAIN_OFFSET_6G_L0; + case RTW89_CH_6G_BAND_IDX1: + return RTW89_GAIN_OFFSET_6G_L1; + case RTW89_CH_6G_BAND_IDX2: + return RTW89_GAIN_OFFSET_6G_M0; + case RTW89_CH_6G_BAND_IDX3: + return RTW89_GAIN_OFFSET_6G_M1; + case RTW89_CH_6G_BAND_IDX4: + return RTW89_GAIN_OFFSET_6G_H0; + case RTW89_CH_6G_BAND_IDX5: + return RTW89_GAIN_OFFSET_6G_H1; + case RTW89_CH_6G_BAND_IDX6: + return RTW89_GAIN_OFFSET_6G_UH0; + case RTW89_CH_6G_BAND_IDX7: + return RTW89_GAIN_OFFSET_6G_UH1; } } @@ -764,6 +806,7 @@ void rtw89_phy_ra_updata_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, const struct cfg80211_bitrate_mask *mask); +bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func); void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len, u8 class, u8 func); void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev); @@ -791,5 +834,7 @@ u8 rtw89_encode_chan_idx(struct rtw89_dev *rtwdev, u8 central_ch, u8 band); void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx, u8 *ch, enum nl80211_band *band); void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan); +void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev); +void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw89/ps.h b/drivers/net/wireless/realtek/rtw89/ps.h index aff0fba71c..54486e4550 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.h +++ b/drivers/net/wireless/realtek/rtw89/ps.h @@ -33,6 +33,10 @@ static inline void rtw89_enter_ips_by_hwflags(struct rtw89_dev *rtwdev) { struct ieee80211_hw *hw = rtwdev->hw; + /* prevent entering IPS after ROC, but it is scanning */ + if (rtwdev->scanning) + return; + if (hw->conf.flags & IEEE80211_CONF_IDLE) rtw89_enter_ips(rtwdev); } diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 672010b9e0..8456e2b0c1 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -116,6 +116,7 @@ #define B_AX_LTE_MUX_CTRL_PATH BIT(26) #define R_AX_HCI_OPT_CTRL 0x0074 +#define BIT_WAKE_CTRL_V1 BIT(23) #define BIT_WAKE_CTRL BIT(5) #define R_AX_HCI_BG_CTRL 0x0078 @@ -1456,6 +1457,8 @@ #define B_AX_PLE_Q6_MAX_SIZE_MASK GENMASK(27, 16) #define B_AX_PLE_Q6_MIN_SIZE_MASK GENMASK(11, 0) #define R_AX_PLE_QTA7_CFG 0x905C +#define B_AX_PLE_Q7_MAX_SIZE_MASK GENMASK(27, 16) +#define B_AX_PLE_Q7_MIN_SIZE_MASK GENMASK(11, 0) #define R_AX_PLE_QTA8_CFG 0x9060 #define R_AX_PLE_QTA9_CFG 0x9064 #define R_AX_PLE_QTA10_CFG 0x9068 @@ -3646,6 +3649,50 @@ #define B_AX_GNT_BT_TX_SW_VAL BIT(1) #define B_AX_GNT_BT_TX_SW_CTRL BIT(0) +#define R_BE_SYS_ISO_CTRL 0x0000 +#define B_BE_PWC_EV2EF_B BIT(15) +#define B_BE_PWC_EV2EF_S BIT(14) +#define B_BE_PA33V_EN BIT(13) +#define B_BE_PA12V_EN BIT(12) +#define B_BE_PAOOBS33V_EN BIT(11) +#define B_BE_PAOOBS12V_EN BIT(10) +#define B_BE_ISO_RFDIO BIT(9) +#define B_BE_ISO_EB2CORE BIT(8) +#define B_BE_ISO_DIOE BIT(7) +#define B_BE_ISO_WLPON2PP BIT(6) +#define B_BE_ISO_IP2MAC_WA02PP BIT(5) +#define B_BE_ISO_PD2CORE BIT(4) +#define B_BE_ISO_PA2PCIE BIT(3) +#define B_BE_ISO_PAOOBS2PCIE BIT(1) +#define B_BE_ISO_WD2PP BIT(0) + +#define R_BE_SYS_PW_CTRL 0x0004 +#define B_BE_SOP_ASWRM BIT(31) +#define B_BE_SOP_EASWR BIT(30) +#define B_BE_SOP_PWMM_DSWR BIT(29) +#define B_BE_SOP_EDSWR BIT(28) +#define B_BE_SOP_ACKF BIT(27) +#define B_BE_SOP_ERCK BIT(26) +#define B_BE_SOP_ANA_CLK_DIVISION_2 BIT(25) +#define B_BE_SOP_EXTL BIT(24) +#define B_BE_SOP_OFF_CAPC_EN BIT(23) +#define B_BE_XTAL_OFF_A_DIE BIT(22) +#define B_BE_ROP_SWPR BIT(21) +#define B_BE_DIS_HW_LPLDM BIT(20) +#define B_BE_DIS_HW_LPURLDO BIT(19) +#define B_BE_DIS_WLBT_PDNSUSEN_SOPC BIT(18) +#define B_BE_RDY_SYSPWR BIT(17) +#define B_BE_EN_WLON BIT(16) +#define B_BE_APDM_HPDN BIT(15) +#define B_BE_PSUS_OFF_CAPC_EN BIT(14) +#define B_BE_AFSM_PCIE_SUS_EN BIT(12) +#define B_BE_AFSM_WLSUS_EN BIT(11) +#define B_BE_APFM_SWLPS BIT(10) +#define B_BE_APFM_OFFMAC BIT(9) +#define B_BE_APFN_ONMAC BIT(8) +#define B_BE_CHIP_PDN_EN BIT(7) +#define B_BE_RDY_MACDIS BIT(6) + #define R_BE_SYS_CLK_CTRL 0x0008 #define B_BE_CPU_CLK_EN BIT(14) #define B_BE_SYMR_BE_CLK_EN BIT(13) @@ -3656,6 +3703,249 @@ #define B_BE_ANA_CLK_DIVISION_2 BIT(1) #define B_BE_CNTD16V_EN BIT(0) +#define R_BE_SYS_WL_EFUSE_CTRL 0x000A +#define B_BE_OTP_B_PWC_RPT BIT(15) +#define B_BE_OTP_S_PWC_RPT BIT(14) +#define B_BE_OTP_ISO_RPT BIT(13) +#define B_BE_OTP_BURST_RPT BIT(12) +#define B_BE_OTP_AUTOLOAD_RPT BIT(11) +#define B_BE_AUTOLOAD_DIS_A_DIE BIT(6) +#define B_BE_AUTOLOAD_SUS BIT(5) +#define B_BE_AUTOLOAD_DIS BIT(4) + +#define R_BE_SYS_PAGE_CLK_GATED 0x000C +#define B_BE_USB_APHY_PC_DLP_OP BIT(27) +#define B_BE_PCIE_APHY_PC_DLP_OP BIT(26) +#define B_BE_UPHY_POWER_READY_CHK BIT(25) +#define B_BE_CPHY_POWER_READY_CHK BIT(24) +#define B_BE_PCIE_PRST_DEBUNC_PERIOD_MASK GENMASK(23, 22) +#define B_BE_SYM_PRST_DEBUNC_SEL BIT(21) +#define B_BE_CPHY_AUXCLK_OP BIT(20) +#define B_BE_SOP_OFFUA_PC BIT(19) +#define B_BE_SOP_OFFPOOBS_PC BIT(18) +#define B_BE_PCIE_LAN1_MASK BIT(17) +#define B_BE_PCIE_LAN0_MASK BIT(16) +#define B_BE_DIS_CLK_REGF_GATE BIT(15) +#define B_BE_DIS_CLK_REGE_GATE BIT(14) +#define B_BE_DIS_CLK_REGD_GATE BIT(13) +#define B_BE_DIS_CLK_REGC_GATE BIT(12) +#define B_BE_DIS_CLK_REGB_GATE BIT(11) +#define B_BE_DIS_CLK_REGA_GATE BIT(10) +#define B_BE_DIS_CLK_REG9_GATE BIT(9) +#define B_BE_DIS_CLK_REG8_GATE BIT(8) +#define B_BE_DIS_CLK_REG7_GATE BIT(7) +#define B_BE_DIS_CLK_REG6_GATE BIT(6) +#define B_BE_DIS_CLK_REG5_GATE BIT(5) +#define B_BE_DIS_CLK_REG4_GATE BIT(4) +#define B_BE_DIS_CLK_REG3_GATE BIT(3) +#define B_BE_DIS_CLK_REG2_GATE BIT(2) +#define B_BE_DIS_CLK_REG1_GATE BIT(1) +#define B_BE_DIS_CLK_REG0_GATE BIT(0) + +#define R_BE_ANAPAR_POW_MAC 0x0016 +#define B_BE_POW_PC_LDO_PORT1 BIT(3) +#define B_BE_POW_PC_LDO_PORT0 BIT(2) +#define B_BE_POW_PLL_V1 BIT(1) +#define B_BE_POW_POWER_CUT_POW_LDO BIT(0) + +#define R_BE_SYS_ADIE_PAD_PWR_CTRL 0x0018 +#define B_BE_SYM_PADPDN_WL_RFC1_1P3 BIT(6) +#define B_BE_SYM_PADPDN_WL_RFC0_1P3 BIT(5) + +#define R_BE_AFE_LDO_CTRL 0x0020 +#define B_BE_FORCE_MACBBBT_PWR_ON BIT(31) +#define B_BE_R_SYM_WLPOFF_P4_PC_EN BIT(28) +#define B_BE_R_SYM_WLPOFF_P3_PC_EN BIT(27) +#define B_BE_R_SYM_WLPOFF_P2_PC_EN BIT(26) +#define B_BE_R_SYM_WLPOFF_P1_PC_EN BIT(25) +#define B_BE_R_SYM_WLPOFF_PC_EN BIT(24) +#define B_BE_AON_OFF_PC_EN BIT(23) +#define B_BE_R_SYM_WLPON_P3_PC_EN BIT(21) +#define B_BE_R_SYM_WLPON_P2_PC_EN BIT(20) +#define B_BE_R_SYM_WLPON_P1_PC_EN BIT(19) +#define B_BE_R_SYM_WLPON_PC_EN BIT(18) +#define B_BE_R_SYM_WLBBPON1_P1_PC_EN BIT(15) +#define B_BE_R_SYM_WLBBPON1_PC_EN BIT(14) +#define B_BE_R_SYM_WLBBPON_P1_PC_EN BIT(13) +#define B_BE_R_SYM_WLBBPON_PC_EN BIT(12) +#define B_BE_R_SYM_DIS_WPHYBBOFF_PC BIT(10) +#define B_BE_R_SYM_WLBBOFF1_P4_PC_EN BIT(9) +#define B_BE_R_SYM_WLBBOFF1_P3_PC_EN BIT(8) +#define B_BE_R_SYM_WLBBOFF1_P2_PC_EN BIT(7) +#define B_BE_R_SYM_WLBBOFF1_P1_PC_EN BIT(6) +#define B_BE_R_SYM_WLBBOFF1_PC_EN BIT(5) +#define B_BE_R_SYM_WLBBOFF_P4_PC_EN BIT(4) +#define B_BE_R_SYM_WLBBOFF_P3_PC_EN BIT(3) +#define B_BE_R_SYM_WLBBOFF_P2_PC_EN BIT(2) +#define B_BE_R_SYM_WLBBOFF_P1_PC_EN BIT(1) +#define B_BE_R_SYM_WLBBOFF_PC_EN BIT(0) + +#define R_BE_AFE_CTRL1 0x0024 +#define B_BE_R_SYM_WLCMAC0_P4_PC_EN BIT(28) +#define B_BE_R_SYM_WLCMAC0_P3_PC_EN BIT(27) +#define B_BE_R_SYM_WLCMAC0_P2_PC_EN BIT(26) +#define B_BE_R_SYM_WLCMAC0_P1_PC_EN BIT(25) +#define B_BE_R_SYM_WLCMAC0_PC_EN BIT(24) +#define B_BE_DATAMEM_PC3_EN BIT(23) +#define B_BE_DATAMEM_PC2_EN BIT(22) +#define B_BE_DATAMEM_PC1_EN BIT(21) +#define B_BE_DATAMEM_PC_EN BIT(20) +#define B_BE_DMEM7_PC_EN BIT(19) +#define B_BE_DMEM6_PC_EN BIT(18) +#define B_BE_DMEM5_PC_EN BIT(17) +#define B_BE_DMEM4_PC_EN BIT(16) +#define B_BE_DMEM3_PC_EN BIT(15) +#define B_BE_DMEM2_PC_EN BIT(14) +#define B_BE_DMEM1_PC_EN BIT(13) +#define B_BE_IMEM4_PC_EN BIT(12) +#define B_BE_IMEM3_PC_EN BIT(11) +#define B_BE_IMEM2_PC_EN BIT(10) +#define B_BE_IMEM1_PC_EN BIT(9) +#define B_BE_IMEM0_PC_EN BIT(8) +#define B_BE_R_SYM_WLCMAC1_P4_PC_EN BIT(4) +#define B_BE_R_SYM_WLCMAC1_P3_PC_EN BIT(3) +#define B_BE_R_SYM_WLCMAC1_P2_PC_EN BIT(2) +#define B_BE_R_SYM_WLCMAC1_P1_PC_EN BIT(1) +#define B_BE_R_SYM_WLCMAC1_PC_EN BIT(0) +#define B_BE_AFE_CTRL1_SET (B_BE_R_SYM_WLCMAC1_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P1_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P2_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P3_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P4_PC_EN) + +#define R_BE_EFUSE_CTRL 0x0030 +#define B_BE_EF_MODE_SEL_MASK GENMASK(31, 30) +#define B_BE_EF_RDY BIT(29) +#define B_BE_EF_COMP_RESULT BIT(28) +#define B_BE_EF_ADDR_MASK GENMASK(15, 0) + +#define R_BE_EFUSE_CTRL_1_V1 0x0034 +#define B_BE_EF_DATA_MASK GENMASK(31, 0) + +#define R_BE_WL_BT_PWR_CTRL 0x0068 +#define B_BE_ISO_BD2PP BIT(31) +#define B_BE_LDOV12B_EN BIT(30) +#define B_BE_CKEN_BT BIT(29) +#define B_BE_FEN_BT BIT(28) +#define B_BE_BTCPU_BOOTSEL BIT(27) +#define B_BE_SPI_SPEEDUP BIT(26) +#define B_BE_BT_LDO_MODE BIT(25) +#define B_BE_ISO_BTPON2PP BIT(22) +#define B_BE_BT_FUNC_EN BIT(18) +#define B_BE_BT_HWPDN_SL BIT(17) +#define B_BE_BT_DISN_EN BIT(16) +#define B_BE_SDM_SRC_SEL BIT(12) +#define B_BE_ISO_BA2PP BIT(11) +#define B_BE_BT_AFE_LDO_EN BIT(10) +#define B_BE_BT_AFE_PLL_EN BIT(9) +#define B_BE_WLAN_32K_SEL BIT(6) +#define B_BE_WL_DRV_EXIST_IDX BIT(5) +#define B_BE_DOP_EHPAD BIT(4) +#define B_BE_WL_FUNC_EN BIT(2) +#define B_BE_WL_HWPDN_SL BIT(1) +#define B_BE_WL_HWPDN_EN BIT(0) + +#define R_BE_SYS_SDIO_CTRL 0x0070 +#define B_BE_MCM_FLASH_EN BIT(28) +#define B_BE_PCIE_SEC_LOAD BIT(26) +#define B_BE_PCIE_SER_RSTB BIT(25) +#define B_BE_PCIE_SEC_LOAD_CLR BIT(24) +#define B_BE_SDIO_CMD_SW_RST BIT(20) +#define B_BE_SDIO_INT_POLARITY BIT(19) +#define B_BE_SDIO_OFF_EN BIT(17) +#define B_BE_SDIO_ON_EN BIT(16) +#define B_BE_PCIE_DIS_L2__CTRL_LDO_HCI BIT(15) +#define B_BE_PCIE_DIS_L2_RTK_PERST BIT(14) +#define B_BE_PCIE_FORCE_PWR_NGAT BIT(13) +#define B_BE_PCIE_FORCE_IBX_EN BIT(12) +#define B_BE_PCIE_AUXCLK_GATE BIT(11) +#define B_BE_PCIE_WAIT_TIMEOUT_EVENT BIT(10) +#define B_BE_PCIE_WAIT_TIME BIT(9) +#define B_BE_L1OFF_TO_L0_RESUME_EVT BIT(8) +#define B_BE_USBA_FORCE_PWR_NGAT BIT(7) +#define B_BE_USBD_FORCE_PWR_NGAT BIT(6) +#define B_BE_BT_CTRL_USB_PWR BIT(5) +#define B_BE_USB_D_STATE_HOLD BIT(4) +#define B_BE_R_BE_FORCE_DP BIT(3) +#define B_BE_R_BE_DP_MODE BIT(2) +#define B_BE_RES_USB_MASS_STORAGE_DESC BIT(1) +#define B_BE_USB_WAIT_TIME BIT(0) + +#define R_BE_HCI_OPT_CTRL 0x0074 +#define B_BE_HCI_WLAN_IO_ST BIT(31) +#define B_BE_HCI_WLAN_IO_EN BIT(28) +#define B_BE_HAXIDMA_IO_ST BIT(27) +#define B_BE_HAXIDMA_BACKUP_RESTORE_ST BIT(26) +#define B_BE_HAXIDMA_IO_EN BIT(24) +#define B_BE_EN_PCIE_WAKE BIT(23) +#define B_BE_SDIO_PAD_H3L1 BIT(22) +#define B_BE_USBMAC_ANACLK_SW BIT(21) +#define B_BE_PCIE_CPHY_CCK_XTAL_SEL BIT(20) +#define B_BE_SDIO_DATA_PAD_SMT BIT(19) +#define B_BE_SDIO_PAD_E5 BIT(18) +#define B_BE_FORCE_PCIE_AUXCLK BIT(17) +#define B_BE_HCI_LA_ADDR_MAP BIT(16) +#define B_BE_HCI_LA_GLO_RST BIT(15) +#define B_BE_USB3_SUS_DIS BIT(14) +#define B_BE_NOPWR_CTRL_SEL BIT(13) +#define B_BE_USB_HOST_PWR_OFF_EN BIT(12) +#define B_BE_SYM_LPS_BLOCK_EN BIT(11) +#define B_BE_USB_LPM_ACT_EN BIT(10) +#define B_BE_USB_LPM_NY BIT(9) +#define B_BE_USB2_SUS_DIS BIT(8) +#define B_BE_SDIO_PAD_E_MASK GENMASK(7, 5) +#define B_BE_USB_LPPLL_EN BIT(4) +#define B_BE_USB1_1_USB2_0_DECISION BIT(3) +#define B_BE_ROP_SW15 BIT(2) +#define B_BE_PCI_CKRDY_OPT BIT(1) +#define B_BE_PCI_VAUX_EN BIT(0) + +#define R_BE_SYS_ISO_CTRL_EXTEND 0x0080 +#define B_BE_R_SYM_ISO_DMEM62PP BIT(29) +#define B_BE_R_SYM_ISO_DMEM52PP BIT(28) +#define B_BE_R_SYM_ISO_DMEM42PP BIT(27) +#define B_BE_R_SYM_ISO_DMEM32PP BIT(26) +#define B_BE_R_SYM_ISO_DMEM22PP BIT(25) +#define B_BE_R_SYM_ISO_DMEM12PP BIT(24) +#define B_BE_R_SYM_ISO_IMEM42PP BIT(22) +#define B_BE_R_SYM_ISO_IMEM32PP BIT(21) +#define B_BE_R_SYM_ISO_IMEM22PP BIT(20) +#define B_BE_R_SYM_ISO_IMEM12PP BIT(19) +#define B_BE_R_SYM_ISO_IMEM02PP BIT(18) +#define B_BE_R_SYM_ISO_AON_OFF2PP BIT(15) +#define B_BE_R_SYM_PWC_HCILA BIT(13) +#define B_BE_R_SYM_PWC_PD12V BIT(12) +#define B_BE_R_SYM_PWC_UD12V BIT(11) +#define B_BE_R_SYM_PWC_BTBRG BIT(10) +#define B_BE_R_SYM_LDOBTSDIO_EN BIT(9) +#define B_BE_R_SYM_LDOSPDIO_EN BIT(8) +#define B_BE_R_SYM_ISO_HCILA BIT(4) +#define B_BE_R_SYM_ISO_BTBRG2PP BIT(2) +#define B_BE_R_SYM_ISO_BTSDIO2PP BIT(1) +#define B_BE_R_SYM_ISO_SPDIO2PP BIT(0) + +#define R_BE_FEN_RST_ENABLE 0x0084 +#define B_BE_R_SYM_FEN_WLMACOFF BIT(31) +#define B_BE_R_SYM_ISO_WA12PP BIT(28) +#define B_BE_R_SYM_ISO_CMAC12PP BIT(25) +#define B_BE_R_SYM_ISO_CMAC02PP BIT(24) +#define B_BE_R_SYM_ISO_ADDA_P32PP BIT(23) +#define B_BE_R_SYM_ISO_ADDA_P22PP BIT(22) +#define B_BE_R_SYM_ISO_ADDA_P12PP BIT(21) +#define B_BE_R_SYM_ISO_ADDA_P02PP BIT(20) +#define B_BE_CMAC1_FEN BIT(17) +#define B_BE_CMAC0_FEN BIT(16) +#define B_BE_SYM_ISO_BBPON12PP BIT(13) +#define B_BE_SYM_ISO_BB12PP BIT(12) +#define B_BE_BOOT_RDY1 BIT(10) +#define B_BE_FEN_BB1_IP_RSTN BIT(9) +#define B_BE_FEN_BB1PLAT_RSTB BIT(8) +#define B_BE_SYM_ISO_BBPON02PP BIT(5) +#define B_BE_SYM_ISO_BB02PP BIT(4) +#define B_BE_BOOT_RDY0 BIT(2) +#define B_BE_FEN_BB_IP_RSTN BIT(1) +#define B_BE_FEN_BBPLAT_RSTB BIT(0) + #define R_BE_PLATFORM_ENABLE 0x0088 #define B_BE_HOLD_AFTER_RESET BIT(11) #define B_BE_SYM_WLPLT_MEM_MUX_EN BIT(10) @@ -3669,6 +3959,92 @@ #define B_BE_WCPU_EN BIT(1) #define B_BE_PLATFORM_EN BIT(0) +#define R_BE_WLLPS_CTRL 0x0090 +#define B_BE_LPSOP_BBMEMDS BIT(30) +#define B_BE_LPSOP_BBOFF BIT(29) +#define B_BE_LPSOP_MACOFF BIT(28) +#define B_BE_LPSOP_OFF_CAPC_EN BIT(27) +#define B_BE_LPSOP_MEM_DS BIT(26) +#define B_BE_LPSOP_XTALM_LPS BIT(23) +#define B_BE_LPSOP_XTAL BIT(22) +#define B_BE_LPSOP_ACLK_DIV_2 BIT(21) +#define B_BE_LPSOP_ACLK_SEL BIT(20) +#define B_BE_LPSOP_ASWRM BIT(17) +#define B_BE_LPSOP_ASWR BIT(16) +#define B_BE_LPSOP_DSWR_ADJ_MASK GENMASK(15, 12) +#define B_BE_LPSOP_DSWRSD BIT(10) +#define B_BE_LPSOP_DSWRM BIT(9) +#define B_BE_LPSOP_DSWR BIT(8) +#define B_BE_LPSOP_OLD_ADJ_MASK GENMASK(7, 4) +#define B_BE_FORCE_LEAVE_LPS BIT(3) +#define B_BE_LPSOP_OLDSD BIT(2) +#define B_BE_DIS_WLBT_LPSEN_LOPC BIT(1) +#define B_BE_WL_LPS_EN BIT(0) + +#define R_BE_WLRESUME_CTRL 0x0094 +#define B_BE_LPSROP_DMEM5_RSU_EN BIT(31) +#define B_BE_LPSROP_DMEM4_RSU_EN BIT(30) +#define B_BE_LPSROP_DMEM3_RSU_EN BIT(29) +#define B_BE_LPSROP_DMEM2_RSU_EN BIT(28) +#define B_BE_LPSROP_DMEM1_RSU_EN BIT(27) +#define B_BE_LPSROP_DMEM0_RSU_EN BIT(26) +#define B_BE_LPSROP_IMEM5_RSU_EN BIT(25) +#define B_BE_LPSROP_IMEM4_RSU_EN BIT(24) +#define B_BE_LPSROP_IMEM3_RSU_EN BIT(23) +#define B_BE_LPSROP_IMEM2_RSU_EN BIT(22) +#define B_BE_LPSROP_IMEM1_RSU_EN BIT(21) +#define B_BE_LPSROP_IMEM0_RSU_EN BIT(20) +#define B_BE_LPSROP_BB1_W_BB0 BIT(14) +#define B_BE_LPSROP_CMAC1 BIT(13) +#define B_BE_LPSROP_CMAC0 BIT(12) +#define B_BE_LPSROP_XTALM BIT(11) +#define B_BE_LPSROP_PLLM BIT(10) +#define B_BE_LPSROP_HIOE BIT(9) +#define B_BE_LPSROP_CPU BIT(8) +#define B_BE_LPSROP_LOWPWRPLL BIT(7) +#define B_BE_LPSROP_DSWRSD_SEL_MASK GENMASK(5, 4) + +#define R_BE_EFUSE_CTRL_2_V1 0x00A4 +#define B_BE_EF_ENT BIT(31) +#define B_BE_EF_TCOLUMN_EN BIT(29) +#define B_BE_BT_OTP_PWC_DIS BIT(28) +#define B_BE_EF_RDT BIT(27) +#define B_BE_R_SYM_AUTOLOAD_WITH_PMC_SEL BIT(24) +#define B_BE_EF_PGTS_MASK GENMASK(23, 20) +#define B_BE_EF_BURST BIT(19) +#define B_BE_EF_TEST_SEL_MASK GENMASK(18, 16) +#define B_BE_EF_TROW_EN BIT(15) +#define B_BE_EF_ERR_FLAG BIT(14) +#define B_BE_EF_FBURST_DIS BIT(13) +#define B_BE_EF_HT_SEL BIT(12) +#define B_BE_EF_DSB_EN BIT(11) +#define B_BE_EF_DLY_SEL_MASK GENMASK(3, 0) + +#define R_BE_PMC_DBG_CTRL2 0x00CC +#define B_BE_EFUSE_BURN_GNT_MASK GENMASK(31, 24) +#define B_BE_DIS_IOWRAP_TIMEOUT BIT(16) +#define B_BE_STOP_WL_PMC BIT(9) +#define B_BE_STOP_SYM_PMC BIT(8) +#define B_BE_SYM_REG_PCIE_WRMSK BIT(7) +#define B_BE_BT_ACCESS_WL_PAGE0 BIT(6) +#define B_BE_R_BE_RST_WLPMC BIT(5) +#define B_BE_R_BE_RST_PD12N BIT(4) +#define B_BE_SYSON_DIS_WLR_BE_WRMSK BIT(3) +#define B_BE_SYSON_DIS_PMCR_BE_WRMSK BIT(2) +#define B_BE_SYSON_R_BE_ARB_MASK GENMASK(1, 0) + +#define R_BE_PCIE_MIO_INTF 0x00E4 +#define B_BE_AON_MIO_EPHY_1K_SEL_MASK GENMASK(29, 24) +#define B_BE_PCIE_MIO_ADDR_PAGE_V1_MASK GENMASK(20, 16) +#define B_BE_PCIE_MIO_ASIF BIT(15) +#define B_BE_PCIE_MIO_BYIOREG BIT(13) +#define B_BE_PCIE_MIO_RE BIT(12) +#define B_BE_PCIE_MIO_WE_MASK GENMASK(11, 8) +#define B_BE_PCIE_MIO_ADDR_MASK GENMASK(7, 0) + +#define R_BE_PCIE_MIO_INTD 0x00E8 +#define B_BE_PCIE_MIO_DATA_MASK GENMASK(31, 0) + #define R_BE_HALT_H2C_CTRL 0x0160 #define B_BE_HALT_H2C_TRIGGER BIT(0) @@ -3693,6 +4069,82 @@ #define R_BE_SECURE_BOOT_MALLOC_INFO 0x0184 +#define R_BE_FWS1IMR 0x0198 +#define B_BE_FS_RPWM_INT_EN_V1 BIT(24) +#define B_BE_PCIE_HOTRST_EN BIT(22) +#define B_BE_PCIE_SER_TIMEOUT_INDIC_EN BIT(21) +#define B_BE_PCIE_RXI300_SLVTOUT_INDIC_EN BIT(20) +#define B_BE_AON_PCIE_FLR_INT_EN BIT(19) +#define B_BE_PCIE_ERR_INDIC_INT_EN BIT(18) +#define B_BE_SDIO_ERR_INDIC_INT_EN BIT(17) +#define B_BE_USB_ERR_INDIC_INT_EN BIT(16) +#define B_BE_FS_GPIO27_INT_EN BIT(11) +#define B_BE_FS_GPIO26_INT_EN BIT(10) +#define B_BE_FS_GPIO25_INT_EN BIT(9) +#define B_BE_FS_GPIO24_INT_EN BIT(8) +#define B_BE_FS_GPIO23_INT_EN BIT(7) +#define B_BE_FS_GPIO22_INT_EN BIT(6) +#define B_BE_FS_GPIO21_INT_EN BIT(5) +#define B_BE_FS_GPIO20_INT_EN BIT(4) +#define B_BE_FS_GPIO19_INT_EN BIT(3) +#define B_BE_FS_GPIO18_INT_EN BIT(2) +#define B_BE_FS_GPIO17_INT_EN BIT(1) +#define B_BE_FS_GPIO16_INT_EN BIT(0) + +#define R_BE_HIMR0 0x01A0 +#define B_BE_WDT_DATACPU_TIMEOUT_INT_EN BIT(25) +#define B_BE_HALT_D2H_INT_EN BIT(24) +#define B_BE_WDT_TIMEOUT_INT_EN BIT(22) +#define B_BE_HALT_C2H_INT_EN BIT(21) +#define B_BE_RON_INT_EN BIT(20) +#define B_BE_PDNINT_EN BIT(19) +#define B_BE_SPSANA_OCP_INT_EN BIT(18) +#define B_BE_SPS_OCP_INT_EN BIT(17) +#define B_BE_BTON_STS_UPDATE_INT_EN BIT(16) +#define B_BE_GPIOF_INT_EN BIT(15) +#define B_BE_GPIOE_INT_EN BIT(14) +#define B_BE_GPIOD_INT_EN BIT(13) +#define B_BE_GPIOC_INT_EN BIT(12) +#define B_BE_GPIOB_INT_EN BIT(11) +#define B_BE_GPIOA_INT_EN BIT(10) +#define B_BE_GPIO9_INT_EN BIT(9) +#define B_BE_GPIO8_INT_EN BIT(8) +#define B_BE_GPIO7_INT_EN BIT(7) +#define B_BE_GPIO6_INT_EN BIT(6) +#define B_BE_GPIO5_INT_EN BIT(5) +#define B_BE_GPIO4_INT_EN BIT(4) +#define B_BE_GPIO3_INT_EN BIT(3) +#define B_BE_GPIO2_INT_EN BIT(2) +#define B_BE_GPIO1_INT_EN BIT(1) +#define B_BE_GPIO0_INT_EN BIT(0) + +#define R_BE_HISR0 0x01A4 +#define B_BE_WDT_DATACPU_TIMEOUT_INT BIT(25) +#define B_BE_HALT_D2H_INT BIT(24) +#define B_BE_WDT_TIMEOUT_INT BIT(22) +#define B_BE_HALT_C2H_INT BIT(21) +#define B_BE_RON_INT BIT(20) +#define B_BE_PDNINT BIT(19) +#define B_BE_SPSANA_OCP_INT BIT(18) +#define B_BE_SPS_OCP_INT BIT(17) +#define B_BE_BTON_STS_UPDATE_INT BIT(16) +#define B_BE_GPIOF_INT BIT(15) +#define B_BE_GPIOE_INT BIT(14) +#define B_BE_GPIOD_INT BIT(13) +#define B_BE_GPIOC_INT BIT(12) +#define B_BE_GPIOB_INT BIT(11) +#define B_BE_GPIOA_INT BIT(10) +#define B_BE_GPIO9_INT BIT(9) +#define B_BE_GPIO8_INT BIT(8) +#define B_BE_GPIO7_INT BIT(7) +#define B_BE_GPIO6_INT BIT(6) +#define B_BE_GPIO5_INT BIT(5) +#define B_BE_GPIO4_INT BIT(4) +#define B_BE_GPIO3_INT BIT(3) +#define B_BE_GPIO2_INT BIT(2) +#define B_BE_GPIO1_INT BIT(1) +#define B_BE_GPIO0_INT BIT(0) + #define R_BE_WCPU_FW_CTRL 0x01E0 #define B_BE_RUN_ENV_MASK GENMASK(31, 30) #define B_BE_WCPU_FWDL_STATUS_MASK GENMASK(29, 26) @@ -3738,6 +4190,78 @@ #define R_BE_UDM2 0x01F8 #define B_BE_UDM2_EPC_RA_MASK GENMASK(31, 0) +#define R_BE_AFE_ON_CTRL0 0x0240 +#define B_BE_REG_LPF_R3_3_0_MASK GENMASK(31, 29) +#define B_BE_REG_LPF_R2_MASK GENMASK(28, 24) +#define B_BE_REG_LPF_C3_MASK GENMASK(23, 21) +#define B_BE_REG_LPF_C2_MASK GENMASK(20, 18) +#define B_BE_REG_LPF_C1_MASK GENMASK(17, 15) +#define B_BE_REG_CP_ICPX2 BIT(14) +#define B_BE_REG_CP_ICP_SEL_FAST_MASK GENMASK(13, 10) +#define B_BE_REG_CP_ICP_SEL_MASK GENMASK(9, 6) +#define B_BE_REG_IB_PI_MASK GENMASK(5, 4) +#define B_BE_REG_CK_DEBUG_BT BIT(3) +#define B_BE_EN_PC_LDO BIT(2) +#define B_BE_LDO_VSEL_MASK GENMASK(1, 0) + +#define R_BE_AFE_ON_CTRL1 0x0244 +#define B_BE_REG_CK_MON_SEL_MASK GENMASK(31, 29) +#define B_BE_REG_CK_MON_CK960M_EN BIT(28) +#define B_BE_REG_XTAL_FREQ_SEL BIT(27) +#define B_BE_REG_XTAL_EDGE_SEL BIT(26) +#define B_BE_REG_VCO_KVCO BIT(25) +#define B_BE_REG_SDM_EDGE_SEL BIT(24) +#define B_BE_REG_SDM_CK_SEL BIT(23) +#define B_BE_REG_SDM_CK_GATED BIT(22) +#define B_BE_REG_PFD_RESET_GATED BIT(21) +#define B_BE_REG_LPF_R3_FAST_MASK GENMASK(20, 16) +#define B_BE_REG_LPF_R2_FAST_MASK GENMASK(15, 11) +#define B_BE_REG_LPF_C3_FAST_MASK GENMASK(10, 8) +#define B_BE_REG_LPF_C2_FAST_MASK GENMASK(7, 5) +#define B_BE_REG_LPF_C1_FAST_MASK GENMASK(4, 2) +#define B_BE_REG_LPF_R3_4_MASK GENMASK(1, 0) + +#define R_BE_AFE_ON_CTRL3 0x024C +#define B_BE_LDO_VSEL_DA_1_MASK GENMASK(31, 30) +#define B_BE_LDO_VSEL_DA_0_MASK GENMASK(29, 28) +#define B_BE_LDO_VSEL_D2S_1_MASK GENMASK(27, 26) +#define B_BE_LDO_VSEL_D2S_0_MASK GENMASK(25, 24) +#define B_BE_LDO_VSEL_BUF_MASK GENMASK(23, 22) +#define B_BE_REG_R2_L_MASK GENMASK(21, 19) +#define B_BE_REG_R1_L_MASK GENMASK(18, 16) +#define B_BE_REG_CK_DEBUG_BT_MON BIT(15) +#define B_BE_REG_BT_CLK_BUF_POWER BIT(14) +#define B_BE_REG_BG_OUT_BTADC_V1 BIT(13) +#define B_BE_REG_SEL_V18 BIT(11) +#define B_BE_REG_FRAC_EN BIT(10) +#define B_BE_REG_CK1920M_EN BIT(9) +#define B_BE_REG_CK1280M_EN BIT(8) +#define B_BE_REG_12LDO_SEL_MASK GENMASK(7, 6) +#define B_BE_REG_09LDO_SEL_MASK GENMASK(5, 4) +#define B_BE_REG_VC_TH BIT(3) +#define B_BE_REG_VC_TL BIT(2) +#define B_BE_REG_CK40M_EN BIT(1) +#define B_BE_REG_CK640M_EN BIT(0) + +#define R_BE_WLAN_XTAL_SI_CTRL 0x0270 +#define B_BE_WL_XTAL_SI_CMD_POLL BIT(31) +#define B_BE_WL_XTAL_SI_CHIPID_MASK GENMASK(30, 28) +#define B_BE_WL_XTAL_SI_MODE_MASK GENMASK(25, 24) +#define B_BE_WL_XTAL_SI_BITMASK_MASK GENMASK(23, 16) +#define B_BE_WL_XTAL_SI_DATA_MASK GENMASK(15, 8) +#define B_BE_WL_XTAL_SI_ADDR_MASK GENMASK(7, 0) + +#define R_BE_IC_PWR_STATE 0x03F0 +#define B_BE_WHOLE_SYS_PWR_STE_MASK GENMASK(25, 16) +#define MAC_AX_SYS_ACT 0x220 +#define B_BE_WLMAC_PWR_STE_MASK GENMASK(9, 8) +#define B_BE_UART_HCISYS_PWR_STE_MASK GENMASK(7, 6) +#define B_BE_SDIO_HCISYS_PWR_STE_MASK GENMASK(5, 4) +#define B_BE_USB_HCISYS_PWR_STE_MASK GENMASK(3, 2) +#define B_BE_PCIE_HCISYS_PWR_STE_MASK GENMASK(1, 0) + +#define R_BE_WLCPU_PORT_PC 0x03FC + #define R_BE_DCPU_PLATFORM_ENABLE 0x0888 #define B_BE_DCPU_SYM_DPLT_MEM_MUX_EN BIT(10) #define B_BE_DCPU_WARM_EN BIT(9) @@ -3747,8 +4271,947 @@ #define B_BE_DCPU_EN BIT(1) #define B_BE_DCPU_PLATFORM_EN BIT(0) +#define R_BE_PL_AXIDMA_IDCT_MSK 0x0910 +#define B_BE_PL_AXIDMA_RRESP_ERR_MASK BIT(6) +#define B_BE_PL_AXIDMA_BRESP_ERR_MASK BIT(5) +#define B_BE_PL_AXIDMA_FC_ERR_MASK BIT(4) +#define B_BE_PL_AXIDMA_TXBD_LEN0_MASK BIT(3) +#define B_BE_PL_AXIDMA_TXBD_4KBOUD_LENERR_MASK BIT(2) +#define B_BE_PL_AXIDMA_TXBD_RX_STUCK_MASK BIT(1) +#define B_BE_PL_AXIDMA_TXBD_TX_STUCK_MASK BIT(0) +#define B_BE_PL_AXIDMA_IDCT_MSK_CLR (B_BE_PL_AXIDMA_TXBD_TX_STUCK_MASK | \ + B_BE_PL_AXIDMA_TXBD_RX_STUCK_MASK | \ + B_BE_PL_AXIDMA_TXBD_LEN0_MASK | \ + B_BE_PL_AXIDMA_FC_ERR_MASK | \ + B_BE_PL_AXIDMA_BRESP_ERR_MASK | \ + B_BE_PL_AXIDMA_RRESP_ERR_MASK) +#define B_BE_PL_AXIDMA_IDCT_MSK_SET (B_BE_PL_AXIDMA_TXBD_TX_STUCK_MASK | \ + B_BE_PL_AXIDMA_TXBD_RX_STUCK_MASK | \ + B_BE_PL_AXIDMA_TXBD_LEN0_MASK | \ + B_BE_PL_AXIDMA_FC_ERR_MASK) + +#define R_BE_PL_AXIDMA_IDCT 0x0914 +#define B_BE_PL_AXIDMA_RRESP_ERR BIT(6) +#define B_BE_PL_AXIDMA_BRESP_ERR BIT(5) +#define B_BE_PL_AXIDMA_FC_ERR BIT(4) +#define B_BE_PL_AXIDMA_TXBD_LEN0 BIT(3) +#define B_BE_PL_AXIDMA_TXBD_4KBOUD_LENERR BIT(2) +#define B_BE_PL_AXIDMA_TXBD_RX_STUCK BIT(1) +#define B_BE_PL_AXIDMA_TXBD_TX_STUCK BIT(0) + #define R_BE_FILTER_MODEL_ADDR 0x0C04 +#define R_BE_WLAN_WDT 0x3050 +#define B_BE_WLAN_WDT_TIMEOUT BIT(31) +#define B_BE_WLAN_WDT_TIMER_CLEAR BIT(4) +#define B_BE_WLAN_WDT_BYPASS BIT(1) +#define B_BE_WLAN_WDT_ENABLE BIT(0) + +#define R_BE_AXIDMA_WDT 0x305C +#define B_BE_AXIDMA_WDT_TIMEOUT BIT(31) +#define B_BE_AXIDMA_WDT_TIMER_CLEAR BIT(4) +#define B_BE_AXIDMA_WDT_BYPASS BIT(1) +#define B_BE_AXIDMA_WDT_ENABLE BIT(0) + +#define R_BE_AON_WDT 0x3068 +#define B_BE_AON_WDT_TIMEOUT BIT(31) +#define B_BE_AON_WDT_TIMER_CLEAR BIT(4) +#define B_BE_AON_WDT_BYPASS BIT(1) +#define B_BE_AON_WDT_ENABLE BIT(0) + +#define R_BE_AON_WDT_TMR 0x306C +#define R_BE_MDIO_WDT_TMR 0x3090 +#define R_BE_LA_MODE_WDT_TMR 0x309C +#define R_BE_WDT_AR_TMR 0x3144 +#define R_BE_WDT_AW_TMR 0x3150 +#define R_BE_WLAN_WDT_TMR 0x3054 +#define R_BE_WDT_W_TMR 0x315C +#define R_BE_AXIDMA_WDT_TMR 0x3060 +#define R_BE_WDT_B_TMR 0x3164 +#define R_BE_WDT_R_TMR 0x316C +#define R_BE_LOCAL_WDT_TMR 0x3084 + +#define R_BE_LOCAL_WDT 0x3080 +#define B_BE_LOCAL_WDT_TIMEOUT BIT(31) +#define B_BE_LOCAL_WDT_TIMER_CLEAR BIT(4) +#define B_BE_LOCAL_WDT_BYPASS BIT(1) +#define B_BE_LOCAL_WDT_ENABLE BIT(0) + +#define R_BE_MDIO_WDT 0x308C +#define B_BE_MDIO_WDT_TIMEOUT BIT(31) +#define B_BE_MDIO_WDT_TIMER_CLEAR BIT(4) +#define B_BE_MDIO_WDT_BYPASS BIT(1) +#define B_BE_MDIO_WDT_ENABLE BIT(0) + +#define R_BE_LA_MODE_WDT 0x3098 +#define B_BE_LA_MODE_WDT_TIMEOUT BIT(31) +#define B_BE_LA_MODE_WDT_TIMER_CLEAR BIT(4) +#define B_BE_LA_MODE_WDT_BYPASS BIT(1) +#define B_BE_LA_MODE_WDT_ENABLE BIT(0) + +#define R_BE_WDT_AR 0x3140 +#define B_BE_WDT_AR_TIMEOUT BIT(31) +#define B_BE_WDT_AR_TIMER_CLEAR BIT(4) +#define B_BE_WDT_AR_BYPASS BIT(1) +#define B_BE_WDT_AR_ENABLE BIT(0) + +#define R_BE_WDT_AW 0x314C +#define B_BE_WDT_AW_TIMEOUT BIT(31) +#define B_BE_WDT_AW_TIMER_CLEAR BIT(4) +#define B_BE_WDT_AW_BYPASS BIT(1) +#define B_BE_WDT_AW_ENABLE BIT(0) + +#define R_BE_WDT_W 0x3158 +#define B_BE_WDT_W_TIMEOUT BIT(31) +#define B_BE_WDT_W_TIMER_CLEAR BIT(4) +#define B_BE_WDT_W_BYPASS BIT(1) +#define B_BE_WDT_W_ENABLE BIT(0) + +#define R_BE_WDT_B 0x3160 +#define B_BE_WDT_B_TIMEOUT BIT(31) +#define B_BE_WDT_B_TIMER_CLEAR BIT(4) +#define B_BE_WDT_B_BYPASS BIT(1) +#define B_BE_WDT_B_ENABLE BIT(0) + +#define R_BE_WDT_R 0x3168 +#define B_BE_WDT_R_TIMEOUT BIT(31) +#define B_BE_WDT_R_TIMER_CLEAR BIT(4) +#define B_BE_WDT_R_BYPASS BIT(1) +#define B_BE_WDT_R_ENABLE BIT(0) + +#define R_BE_LTR_DECISION_CTRL_V1 0x3610 +#define B_BE_ENABLE_LTR_CTL_DECISION BIT(31) +#define B_BE_LAT_LTR_IDX_DRV_VLD_V1 BIT(24) +#define B_BE_LAT_LTR_IDX_DRV_V1_MASK GENMASK(23, 22) +#define B_BE_LAT_LTR_IDX_FW_VLD_V1 BIT(21) +#define B_BE_LAT_LTR_IDX_FW_V1_MASK GENMASK(20, 19) +#define B_BE_LAT_LTR_IDX_HW_VLD_V1 BIT(18) +#define B_BE_LAT_LTR_IDX_HW_V1_MASK GENMASK(17, 16) +#define B_BE_LTR_IDX_DRV_V1_MASK GENMASK(15, 14) +#define B_BE_LTR_REQ_DRV_V1 BIT(13) +#define B_BE_LTR_IDX_DISABLE_V1_MASK GENMASK(9, 8) +#define B_BE_LTR_EN_PORT_V1_MASK GENMASK(6, 4) +#define B_BE_LTR_DRV_DEC_EN_V1 BIT(6) +#define B_BE_LTR_FW_DEC_EN_V1 BIT(5) +#define B_BE_LTR_HW_DEC_EN_V1 BIT(4) +#define B_BE_LTR_SPACE_IDX_MASK GENMASK(1, 0) + +#define R_BE_LTR_LATENCY_IDX0_V1 0x3614 +#define R_BE_LTR_LATENCY_IDX1_V1 0x3618 +#define R_BE_LTR_LATENCY_IDX2_V1 0x361C +#define R_BE_LTR_LATENCY_IDX3_V1 0x3620 + +#define R_BE_HCI_FUNC_EN 0x7880 +#define B_BE_HCI_CR_PROTECT BIT(31) +#define B_BE_HCI_TRXBUF_EN BIT(2) +#define B_BE_HCI_RXDMA_EN BIT(1) +#define B_BE_HCI_TXDMA_EN BIT(0) + +#define R_BE_DMAC_FUNC_EN 0x8400 +#define B_BE_DMAC_CRPRT BIT(31) +#define B_BE_MAC_FUNC_EN BIT(30) +#define B_BE_DMAC_FUNC_EN BIT(29) +#define B_BE_MPDU_PROC_EN BIT(28) +#define B_BE_WD_RLS_EN BIT(27) +#define B_BE_DLE_WDE_EN BIT(26) +#define B_BE_TXPKT_CTRL_EN BIT(25) +#define B_BE_STA_SCH_EN BIT(24) +#define B_BE_DLE_PLE_EN BIT(23) +#define B_BE_PKT_BUF_EN BIT(22) +#define B_BE_DMAC_TBL_EN BIT(21) +#define B_BE_PKT_IN_EN BIT(20) +#define B_BE_DLE_CPUIO_EN BIT(19) +#define B_BE_DISPATCHER_EN BIT(18) +#define B_BE_BBRPT_EN BIT(17) +#define B_BE_MAC_SEC_EN BIT(16) +#define B_BE_DMACREG_GCKEN BIT(15) +#define B_BE_H_AXIDMA_EN BIT(14) +#define B_BE_DMAC_MLO_EN BIT(11) +#define B_BE_PLRLS_EN BIT(10) +#define B_BE_P_AXIDMA_EN BIT(9) +#define B_BE_DLE_DATACPUIO_EN BIT(8) +#define B_BE_LTR_CTL_EN BIT(7) + +#define R_BE_DMAC_CLK_EN 0x8404 +#define B_BE_MAC_CKEN BIT(30) +#define B_BE_DMAC_CKEN BIT(29) +#define B_BE_MPDU_CKEN BIT(28) +#define B_BE_WD_RLS_CLK_EN BIT(27) +#define B_BE_DLE_WDE_CLK_EN BIT(26) +#define B_BE_TXPKT_CTRL_CLK_EN BIT(25) +#define B_BE_STA_SCH_CLK_EN BIT(24) +#define B_BE_DLE_PLE_CLK_EN BIT(23) +#define B_BE_PKTBUF_CKEN BIT(22) +#define B_BE_DMAC_TABLE_CLK_EN BIT(21) +#define B_BE_PKT_IN_CLK_EN BIT(20) +#define B_BE_DLE_CPUIO_CLK_EN BIT(19) +#define B_BE_DISPATCHER_CLK_EN BIT(18) +#define B_BE_BBRPT_CLK_EN BIT(17) +#define B_BE_MAC_SEC_CLK_EN BIT(16) +#define B_BE_H_AXIDMA_CKEN BIT(14) +#define B_BE_DMAC_MLO_CKEN BIT(11) +#define B_BE_PLRLS_CKEN BIT(10) +#define B_BE_P_AXIDMA_CKEN BIT(9) +#define B_BE_DLE_DATACPUIO_CKEN BIT(8) + +#define R_BE_LTR_CTRL_0 0x8410 +#define B_BE_LTR_REQ_FW BIT(18) +#define B_BE_LTR_IDX_FW_MASK GENMASK(17, 16) +#define B_BE_LTR_IDLE_TIMER_IDX_MASK GENMASK(10, 8) +#define B_BE_LTR_WD_NOEMP_CHK BIT(1) +#define B_BE_LTR_HW_EN BIT(0) + +#define R_BE_LTR_CFG_0 0x8414 +#define B_BE_LTR_IDX_DISABLE_MASK GENMASK(17, 16) +#define B_BE_LTR_IDX_IDLE_MASK GENMASK(15, 14) +#define B_BE_LTR_IDX_ACTIVE_MASK GENMASK(13, 12) +#define B_BE_LTR_IDLE_TIMER_IDX_MASK GENMASK(10, 8) +#define B_BE_EN_LTR_CMAC_RX_USE_PG_CHK BIT(3) +#define B_BE_EN_LTR_WD_NON_EMPTY_CHK BIT(2) +#define B_BE_EN_LTR_HAXIDMA_TX_IDLE_CHK BIT(1) +#define B_BE_EN_LTR_HAXIDMA_RX_IDLE_CHK BIT(0) + +#define R_BE_LTR_CFG_1 0x8418 +#define B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK GENMASK(27, 16) +#define B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK GENMASK(11, 0) + +#define R_BE_DMAC_TABLE_CTRL 0x8420 +#define B_BE_HWAMSDU_PADDING_MODE BIT(31) +#define B_BE_MACID_MPDU_PROCESSOR_OFFSET_MASK GENMASK(26, 16) +#define B_BE_DMAC_ADDR_MODE BIT(12) +#define B_BE_DMAC_CTRL_INFO_SER_IO BIT(11) +#define B_BE_DMAC_CTRL_INFO_OFFSET_MASK GENMASK(10, 0) + +#define R_BE_SER_DBG_INFO 0x8424 +#define B_BE_SER_L0_PROMOTE_L1_EVENT_MASK GENMASK(31, 28) +#define B_BE_SER_L1_COUNTER_MASK GENMASK(27, 24) +#define B_BE_RMAC_PPDU_HANG_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L0_COUNTER_MASK GENMASK(8, 0) + +#define R_BE_DLE_EMPTY0 0x8430 +#define B_BE_PLE_EMPTY_QTA_DMAC_H2D BIT(27) +#define B_BE_PLE_EMPTY_QTA_DMAC_CPUIO BIT(26) +#define B_BE_PLE_EMPTY_QTA_DMAC_MPDU_TX BIT(25) +#define B_BE_PLE_EMPTY_QTA_DMAC_WLAN_CPU BIT(24) +#define B_BE_PLE_EMPTY_QTA_DMAC_H2C BIT(23) +#define B_BE_PLE_EMPTY_QTA_DMAC_B1_TXPL BIT(22) +#define B_BE_PLE_EMPTY_QTA_DMAC_B0_TXPL BIT(21) +#define B_BE_WDE_EMPTY_QTA_DMAC_CPUIO BIT(20) +#define B_BE_WDE_EMPTY_QTA_DMAC_PKTIN BIT(19) +#define B_BE_WDE_EMPTY_QTA_DMAC_DATA_CPU BIT(18) +#define B_BE_WDE_EMPTY_QTA_DMAC_WLAN_CPU BIT(17) +#define B_BE_WDE_EMPTY_QTA_DMAC_HIF BIT(16) +#define B_BE_WDE_EMPTY_QUE_CMAC_B1_HIQ BIT(15) +#define B_BE_WDE_EMPTY_QUE_CMAC_B1_MBH BIT(14) +#define B_BE_WDE_EMPTY_QUE_CMAC_B0_OTHERS BIT(13) +#define B_BE_WDE_EMPTY_QUE_DMAC_MLO_ACQ BIT(12) +#define B_BE_WDE_EMPTY_QUE_DMAC_MLO_MISC BIT(11) +#define B_BE_WDE_EMPTY_QUE_DMAC_PKTIN BIT(10) +#define B_BE_PLE_EMPTY_QUE_DMAC_SEC_TX BIT(9) +#define B_BE_PLE_EMPTY_QUE_DMAC_MPDU_TX BIT(8) +#define B_BE_WDE_EMPTY_QUE_OTHERS BIT(7) +#define B_BE_WDE_EMPTY_QUE_CMAC_WMM3 BIT(6) +#define B_BE_WDE_EMPTY_QUE_CMAC_WMM2 BIT(5) +#define B_BE_WDE_EMPTY_QUE_CMAC0_WMM1 BIT(4) +#define B_BE_WDE_EMPTY_QUE_CMAC0_WMM0 BIT(3) +#define B_BE_WDE_EMPTY_QUE_CMAC1_MBH BIT(2) +#define B_BE_WDE_EMPTY_QUE_CMAC0_MBH BIT(1) +#define B_BE_WDE_EMPTY_QUE_CMAC0_ALL_AC BIT(0) + +#define R_BE_DLE_EMPTY1 0x8434 +#define B_BE_PLE_EMPTY_QTA_CMAC_DMA_TXRPT BIT(21) +#define B_BE_PLE_EMPTY_QTA_DMAC_WDRLS BIT(20) +#define B_BE_PLE_EMPTY_QTA_CMAC1_DMA_BBRPT BIT(19) +#define B_BE_PLE_EMPTY_QTA_CMAC1_DMA_RX BIT(18) +#define B_BE_PLE_EMPTY_QTA_CMAC0_DMA_RX BIT(17) +#define B_BE_PLE_EMPTY_QTA_DMAC_C2H BIT(16) +#define B_BE_PLE_EMPTY_QUE_DMAC_PLRLS BIT(5) +#define B_BE_PLE_EMPTY_QUE_DMAC_CPUIO BIT(4) +#define B_BE_PLE_EMPTY_QUE_DMAC_SEC_RX BIT(3) +#define B_BE_PLE_EMPTY_QUE_DMAC_MPDU_RX BIT(2) +#define B_BE_PLE_EMPTY_QUE_DMAC_HDP BIT(1) +#define B_BE_WDE_EMPTY_QUE_DMAC_WDRLS BIT(0) + +#define R_BE_SER_L1_DBG_CNT_0 0x8440 +#define B_BE_SER_L1_WDRLS_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L1_SEC_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L1_MPDU_CNT_MASK GENMASK(15, 8) +#define B_BE_SER_L1_STA_SCH_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_L1_DBG_CNT_1 0x8444 +#define B_BE_SER_L1_WDE_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L1_TXPKTCTRL_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L1_PLE_CNT_MASK GENMASK(15, 8) +#define B_BE_SER_L1_PKTIN_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_L1_DBG_CNT_2 0x8448 +#define B_BE_SER_L1_DISP_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L1_APB_BRIDGE_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L1_DLE_W_CPUIO_CNT_MASK GENMASK(15, 8) +#define B_BE_SER_L1_BBRPT_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_L1_DBG_CNT_3 0x844C +#define B_BE_SER_L1_HCI_BUF_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L1_P_AXIDMA_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L1_H_AXIDMA_CNT_MASK GENMASK(15, 8) +#define B_BE_SER_L1_MLO_ERR_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_L1_DBG_CNT_4 0x8450 +#define B_BE_SER_L1_PLDRLS_ERR_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L1_DLE_D_CPUIO_CNT_MASK GENMASK(23, 16) + +#define R_BE_SER_L1_DBG_CNT_5 0x8454 +#define B_BE_SER_L1_DBG_0_MASK GENMASK(31, 0) + +#define R_BE_SER_L1_DBG_CNT_6 0x8458 +#define B_BE_SER_L1_DBG_1_MASK GENMASK(31, 0) + +#define R_BE_SER_L1_DBG_CNT_7 0x845C +#define B_BE_SER_L1_DBG_2_MASK GENMASK(31, 0) + +#define R_BE_DMAC_ERR_IMR 0x8520 +#define B_BE_DMAC_NOTX_ERR_INT_EN BIT(21) +#define B_BE_DMAC_NORX_ERR_INT_EN BIT(20) +#define B_BE_DLE_DATACPUIO_ERR_INT_EN BIT(19) +#define B_BE_PLRSL_ERR_INT_EN BIT(18) +#define B_BE_MLO_ERR_INT_EN BIT(17) +#define B_BE_DMAC_FW_ERR_INT_EN BIT(16) +#define B_BE_H_AXIDMA_ERR_INT_EN BIT(14) +#define B_BE_P_AXIDMA_ERR_INT_EN BIT(13) +#define B_BE_HCI_BUF_ERR_INT_EN BIT(12) +#define B_BE_BBRPT_ERR_INT_EN BIT(11) +#define B_BE_DLE_CPUIO_ERR_INT_EN BIT(10) +#define B_BE_APB_BRIDGE_ERR_INT_EN BIT(9) +#define B_BE_DISPATCH_ERR_INT_EN BIT(8) +#define B_BE_PKTIN_ERR_INT_EN BIT(7) +#define B_BE_PLE_DLE_ERR_INT_EN BIT(6) +#define B_BE_TXPKTCTRL_ERR_INT_EN BIT(5) +#define B_BE_WDE_DLE_ERR_INT_EN BIT(4) +#define B_BE_STA_SCHEDULER_ERR_INT_EN BIT(3) +#define B_BE_MPDU_ERR_INT_EN BIT(2) +#define B_BE_WSEC_ERR_INT_EN BIT(1) +#define B_BE_WDRLS_ERR_INT_EN BIT(0) + +#define R_BE_DMAC_ERR_ISR 0x8524 +#define B_BE_DLE_DATACPUIO_ERR_INT BIT(19) +#define B_BE_PLRLS_ERR_INT BIT(18) +#define B_BE_MLO_ERR_INT BIT(17) +#define B_BE_DMAC_FW_ERR_IDCT BIT(16) +#define B_BE_H_AXIDMA_ERR_INT BIT(14) +#define B_BE_P_AXIDMA_ERR_INT BIT(13) +#define B_BE_HCI_BUF_ERR_FLAG BIT(12) +#define B_BE_BBRPT_ERR_FLAG BIT(11) +#define B_BE_DLE_CPUIO_ERR_FLAG BIT(10) +#define B_BE_APB_BRIDGE_ERR_FLAG BIT(9) +#define B_BE_DISPATCH_ERR_FLAG BIT(8) +#define B_BE_PKTIN_ERR_FLAG BIT(7) +#define B_BE_PLE_DLE_ERR_FLAG BIT(6) +#define B_BE_TXPKTCTRL_ERR_FLAG BIT(5) +#define B_BE_WDE_DLE_ERR_FLAG BIT(4) +#define B_BE_STA_SCHEDULER_ERR_FLAG BIT(3) +#define B_BE_MPDU_ERR_FLAG BIT(2) +#define B_BE_WSEC_ERR_FLAG BIT(1) +#define B_BE_WDRLS_ERR_FLAG BIT(0) + +#define R_BE_DISP_ERROR_ISR0 0x8804 +#define B_BE_REUSE_SIZE_ERR BIT(31) +#define B_BE_REUSE_EN_ERR BIT(30) +#define B_BE_STF_OQT_UNDERFLOW_ERR BIT(29) +#define B_BE_STF_OQT_OVERFLOW_ERR BIT(28) +#define B_BE_STF_WRFF_UNDERFLOW_ERR BIT(27) +#define B_BE_STF_WRFF_OVERFLOW_ERR BIT(26) +#define B_BE_STF_CMD_UNDERFLOW_ERR BIT(25) +#define B_BE_STF_CMD_OVERFLOW_ERR BIT(24) +#define B_BE_REUSE_SIZE_ZERO_ERR BIT(23) +#define B_BE_REUSE_PKT_CNT_ERR BIT(22) +#define B_BE_CDT_PTR_TIMEOUT_ERR BIT(21) +#define B_BE_CDT_HCI_TIMEOUT_ERR BIT(20) +#define B_BE_HDT_PTR_TIMEOUT_ERR BIT(19) +#define B_BE_HDT_HCI_TIMEOUT_ERR BIT(18) +#define B_BE_CDT_ADDR_INFO_LEN_ERR BIT(17) +#define B_BE_HDT_ADDR_INFO_LEN_ERR BIT(16) +#define B_BE_CDR_DMA_TIMEOUT_ERR BIT(15) +#define B_BE_CDR_RX_TIMEOUT_ERR BIT(14) +#define B_BE_PLE_OUTPUT_ERR BIT(12) +#define B_BE_PLE_RESPOSE_ERR BIT(11) +#define B_BE_PLE_BURST_NUM_ERR BIT(10) +#define B_BE_PLE_NULL_PKT_ERR BIT(9) +#define B_BE_PLE_FLOW_CTRL_ERR BIT(8) +#define B_BE_HDR_DMA_TIMEOUT_ERR BIT(7) +#define B_BE_HDR_RX_TIMEOUT_ERR BIT(6) +#define B_BE_WDE_OUTPUT_ERR BIT(4) +#define B_BE_WDE_RESPONSE_ERR BIT(3) +#define B_BE_WDE_BURST_NUM_ERR BIT(2) +#define B_BE_WDE_NULL_PKT_ERR BIT(1) +#define B_BE_WDE_FLOW_CTRL_ERR BIT(0) + +#define R_BE_DISP_ERROR_ISR1 0x8808 +#define B_BE_HR_WRFF_UNDERFLOW_ERR BIT(31) +#define B_BE_HR_WRFF_OVERFLOW_ERR BIT(30) +#define B_BE_HR_CHKSUM_FSM_ERR BIT(29) +#define B_BE_HR_SHIFT_DMA_CFG_ERR BIT(28) +#define B_BE_HR_DMA_PROCESS_ERR BIT(27) +#define B_BE_HR_TOTAL_LEN_UNDER_ERR BIT(26) +#define B_BE_HR_SHIFT_EN_ERR BIT(25) +#define B_BE_HR_AGG_CFG_ERR BIT(24) +#define B_BE_HR_PLD_LEN_ZERO_ERR BIT(22) +#define B_BE_HT_ILL_CH_ERR BIT(20) +#define B_BE_HT_ADDR_INFO_LEN_ERR BIT(18) +#define B_BE_HT_WD_LEN_OVER_ERR BIT(17) +#define B_BE_HT_PLD_CMD_UNDERFLOW_ERR BIT(16) +#define B_BE_HT_PLD_CMD_OVERFLOW_ERR BIT(15) +#define B_BE_HT_WRFF_UNDERFLOW_ERR BIT(14) +#define B_BE_HT_WRFF_OVERFLOW_ERR BIT(13) +#define B_BE_HT_CHKSUM_FSM_ERR BIT(12) +#define B_BE_HT_NON_IDLE_PKT_STR_ERR BIT(11) +#define B_BE_HT_PRE_SUB_BE_ERR BIT(10) +#define B_BE_HT_WD_CHKSUM_ERR BIT(9) +#define B_BE_HT_CHANNEL_DMA_ERR BIT(8) +#define B_BE_HT_OFFSET_UNMATCH_ERR BIT(7) +#define B_BE_HT_PAYLOAD_UNDER_ERR BIT(6) +#define B_BE_HT_PAYLOAD_OVER_ERR BIT(5) +#define B_BE_HT_PERMU_FF_UNDERFLOW_ERR BIT(4) +#define B_BE_HT_PERMU_FF_OVERFLOW_ERR BIT(3) +#define B_BE_HT_PKT_FAIL_ERR BIT(2) +#define B_BE_HT_CH_ID_ERR BIT(1) +#define B_BE_HT_EP_CH_DIFF_ERR BIT(0) + +#define R_BE_DISP_ERROR_ISR2 0x880C +#define B_BE_CR_PLD_LEN_ERR BIT(30) +#define B_BE_CR_WRFF_UNDERFLOW_ERR BIT(29) +#define B_BE_CR_WRFF_OVERFLOW_ERR BIT(28) +#define B_BE_CR_SHIFT_DMA_CFG_ERR BIT(27) +#define B_BE_CR_DMA_PROCESS_ERR BIT(26) +#define B_BE_CR_SHIFT_EN_ERR BIT(24) +#define B_BE_REUSE_FIFO_B_UNDER_ERR BIT(22) +#define B_BE_REUSE_FIFO_B_OVER_ERR BIT(21) +#define B_BE_REUSE_FIFO_A_UNDER_ERR BIT(20) +#define B_BE_REUSE_FIFO_A_OVER_ERR BIT(19) +#define B_BE_CT_ADDR_INFO_LEN_MISS_ERR BIT(17) +#define B_BE_CT_WD_LEN_OVER_ERR BIT(16) +#define B_BE_CT_F2P_SEQ_ERR BIT(15) +#define B_BE_CT_F2P_QSEL_ERR BIT(14) +#define B_BE_CT_PLD_CMD_UNDERFLOW_ERR BIT(13) +#define B_BE_CT_PLD_CMD_OVERFLOW_ERR BIT(12) +#define B_BE_CT_PRE_SUB_ERR BIT(11) +#define B_BE_CT_WD_CHKSUM_ERR BIT(10) +#define B_BE_CT_CHANNEL_DMA_ERR BIT(9) +#define B_BE_CT_OFFSET_UNMATCH_ERR BIT(8) +#define B_BE_F2P_TOTAL_NUM_ERR BIT(7) +#define B_BE_CT_PAYLOAD_UNDER_ERR BIT(6) +#define B_BE_CT_PAYLOAD_OVER_ERR BIT(5) +#define B_BE_CT_PERMU_FF_UNDERFLOW_ERR BIT(4) +#define B_BE_CT_PERMU_FF_OVERFLOW_ERR BIT(3) +#define B_BE_CT_CH_ID_ERR BIT(2) +#define B_BE_CT_EP_CH_DIFF_ERR BIT(0) + +#define R_BE_DISP_OTHER_IMR 0x8870 +#define B_BE_REUSE_SIZE_ERR_INT_EN BIT(31) +#define B_BE_REUSE_EN_ERR_INT_EN BIT(30) +#define B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN BIT(29) +#define B_BE_STF_OQT_OVERFLOW_ERR_INT_EN BIT(28) +#define B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN BIT(27) +#define B_BE_STF_WRFF_OVERFLOW_ERR_INT_EN BIT(26) +#define B_BE_STF_CMD_UNDERFLOW_ERR_INT_EN BIT(25) +#define B_BE_STF_CMD_OVERFLOW_ERR_INT_EN BIT(24) +#define B_BE_REUSE_SIZE_ZERO_ERR_INT_EN BIT(23) +#define B_BE_REUSE_PKT_CNT_ERR_INT_EN BIT(22) +#define B_BE_CDT_PTR_TIMEOUT_ERR_INT_EN BIT(21) +#define B_BE_CDT_HCI_TIMEOUT_ERR_INT_EN BIT(20) +#define B_BE_HDT_PTR_TIMEOUT_ERR_INT_EN BIT(19) +#define B_BE_HDT_HCI_TIMEOUT_ERR_INT_EN BIT(18) +#define B_BE_CDT_ADDR_INFO_LEN_ERR_INT_EN BIT(17) +#define B_BE_HDT_ADDR_INFO_LEN_ERR_INT_EN BIT(16) +#define B_BE_CDR_DMA_TIMEOUT_ERR_INT_EN BIT(15) +#define B_BE_CDR_RX_TIMEOUT_ERR_INT_EN BIT(14) +#define B_BE_PLE_OUTPUT_ERR_INT_EN BIT(12) +#define B_BE_PLE_RESPOSE_ERR_INT_EN BIT(11) +#define B_BE_PLE_BURST_NUM_ERR_INT_EN BIT(10) +#define B_BE_PLE_NULL_PKT_ERR_INT_EN BIT(9) +#define B_BE_PLE_FLOW_CTRL_ERR_INT_EN BIT(8) +#define B_BE_HDR_DMA_TIMEOUT_ERR_INT_EN BIT(7) +#define B_BE_HDR_RX_TIMEOUT_ERR_INT_EN BIT(6) +#define B_BE_WDE_OUTPUT_ERR_INT_EN BIT(4) +#define B_BE_WDE_RESPONSE_ERR_INT_EN BIT(3) +#define B_BE_WDE_BURST_NUM_ERR_INT_EN BIT(2) +#define B_BE_WDE_NULL_PKT_ERR_INT_EN BIT(1) +#define B_BE_WDE_FLOW_CTRL_ERR_INT_EN BIT(0) +#define B_BE_DISP_OTHER_IMR_CLR (B_BE_WDE_FLOW_CTRL_ERR_INT_EN | \ + B_BE_WDE_NULL_PKT_ERR_INT_EN | \ + B_BE_WDE_BURST_NUM_ERR_INT_EN | \ + B_BE_WDE_RESPONSE_ERR_INT_EN | \ + B_BE_WDE_OUTPUT_ERR_INT_EN | \ + B_BE_HDR_RX_TIMEOUT_ERR_INT_EN | \ + B_BE_HDR_DMA_TIMEOUT_ERR_INT_EN | \ + B_BE_PLE_FLOW_CTRL_ERR_INT_EN | \ + B_BE_PLE_NULL_PKT_ERR_INT_EN | \ + B_BE_PLE_BURST_NUM_ERR_INT_EN | \ + B_BE_PLE_RESPOSE_ERR_INT_EN | \ + B_BE_PLE_OUTPUT_ERR_INT_EN | \ + B_BE_CDR_RX_TIMEOUT_ERR_INT_EN | \ + B_BE_CDR_DMA_TIMEOUT_ERR_INT_EN | \ + B_BE_HDT_ADDR_INFO_LEN_ERR_INT_EN | \ + B_BE_CDT_ADDR_INFO_LEN_ERR_INT_EN | \ + B_BE_HDT_HCI_TIMEOUT_ERR_INT_EN | \ + B_BE_HDT_PTR_TIMEOUT_ERR_INT_EN | \ + B_BE_CDT_HCI_TIMEOUT_ERR_INT_EN | \ + B_BE_CDT_PTR_TIMEOUT_ERR_INT_EN | \ + B_BE_REUSE_PKT_CNT_ERR_INT_EN | \ + B_BE_REUSE_SIZE_ZERO_ERR_INT_EN | \ + B_BE_STF_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_STF_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN | \ + B_BE_STF_OQT_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN | \ + B_BE_REUSE_EN_ERR_INT_EN | \ + B_BE_REUSE_SIZE_ERR_INT_EN) +#define B_BE_DISP_OTHER_IMR_SET (B_BE_STF_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_STF_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN | \ + B_BE_STF_OQT_OVERFLOW_ERR_INT_EN | \ + B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN) + +#define R_BE_DISP_HOST_IMR 0x8874 +#define B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN BIT(31) +#define B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN BIT(30) +#define B_BE_HR_CHKSUM_FSM_ERR_INT_EN BIT(29) +#define B_BE_HR_SHIFT_DMA_CFG_ERR_INT_EN BIT(28) +#define B_BE_HR_DMA_PROCESS_ERR_INT_EN BIT(27) +#define B_BE_HR_TOTAL_LEN_UNDER_ERR_INT_EN BIT(26) +#define B_BE_HR_SHIFT_EN_ERR_INT_EN BIT(25) +#define B_BE_HR_AGG_CFG_ERR_INT_EN BIT(24) +#define B_BE_HR_PLD_LEN_ZERO_ERR_INT_EN BIT(22) +#define B_BE_HT_ILL_CH_ERR_INT_EN BIT(20) +#define B_BE_HT_ADDR_INFO_LEN_ERR_INT_EN BIT(18) +#define B_BE_HT_WD_LEN_OVER_ERR_INT_EN BIT(17) +#define B_BE_HT_PLD_CMD_UNDERFLOW_ERR_INT_EN BIT(16) +#define B_BE_HT_PLD_CMD_OVERFLOW_ERR_INT_EN BIT(15) +#define B_BE_HT_WRFF_UNDERFLOW_ERR_INT_EN BIT(14) +#define B_BE_HT_WRFF_OVERFLOW_ERR_INT_EN BIT(13) +#define B_BE_HT_CHKSUM_FSM_ERR_INT_EN BIT(12) +#define B_BE_HT_NON_IDLE_PKT_STR_ERR_EN BIT(11) +#define B_BE_HT_PRE_SUB_ERR_INT_EN BIT(10) +#define B_BE_HT_WD_CHKSUM_ERR_INT_EN BIT(9) +#define B_BE_HT_CHANNEL_DMA_ERR_INT_EN BIT(8) +#define B_BE_HT_OFFSET_UNMATCH_ERR_INT_EN BIT(7) +#define B_BE_HT_PAYLOAD_UNDER_ERR_INT_EN BIT(6) +#define B_BE_HT_PAYLOAD_OVER_ERR_INT_EN BIT(5) +#define B_BE_HT_PERMU_FF_UNDERFLOW_ERR_INT_EN BIT(4) +#define B_BE_HT_PERMU_FF_OVERFLOW_ERR_INT_EN BIT(3) +#define B_BE_HT_PKT_FAIL_ERR_INT_EN BIT(2) +#define B_BE_HT_CH_ID_ERR_INT_EN BIT(1) +#define B_BE_HT_EP_CH_DIFF_ERR_INT_EN BIT(0) +#define B_BE_DISP_HOST_IMR_CLR (B_BE_HT_EP_CH_DIFF_ERR_INT_EN | \ + B_BE_HT_CH_ID_ERR_INT_EN | \ + B_BE_HT_PKT_FAIL_ERR_INT_EN | \ + B_BE_HT_PERMU_FF_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_PAYLOAD_OVER_ERR_INT_EN | \ + B_BE_HT_PAYLOAD_UNDER_ERR_INT_EN | \ + B_BE_HT_OFFSET_UNMATCH_ERR_INT_EN | \ + B_BE_HT_CHANNEL_DMA_ERR_INT_EN | \ + B_BE_HT_WD_CHKSUM_ERR_INT_EN | \ + B_BE_HT_PRE_SUB_ERR_INT_EN | \ + B_BE_HT_NON_IDLE_PKT_STR_ERR_EN | \ + B_BE_HT_CHKSUM_FSM_ERR_INT_EN | \ + B_BE_HT_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_WRFF_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_PLD_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_WD_LEN_OVER_ERR_INT_EN | \ + B_BE_HT_ADDR_INFO_LEN_ERR_INT_EN | \ + B_BE_HT_ILL_CH_ERR_INT_EN | \ + B_BE_HR_PLD_LEN_ZERO_ERR_INT_EN | \ + B_BE_HR_AGG_CFG_ERR_INT_EN | \ + B_BE_HR_SHIFT_EN_ERR_INT_EN | \ + B_BE_HR_TOTAL_LEN_UNDER_ERR_INT_EN | \ + B_BE_HR_DMA_PROCESS_ERR_INT_EN | \ + B_BE_HR_SHIFT_DMA_CFG_ERR_INT_EN | \ + B_BE_HR_CHKSUM_FSM_ERR_INT_EN | \ + B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN) +#define B_BE_DISP_HOST_IMR_SET (B_BE_HT_EP_CH_DIFF_ERR_INT_EN | \ + B_BE_HT_PERMU_FF_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_PAYLOAD_OVER_ERR_INT_EN | \ + B_BE_HT_PAYLOAD_UNDER_ERR_INT_EN | \ + B_BE_HT_CHANNEL_DMA_ERR_INT_EN | \ + B_BE_HT_PRE_SUB_ERR_INT_EN | \ + B_BE_HT_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_WRFF_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_PLD_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_HT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_HT_WD_LEN_OVER_ERR_INT_EN | \ + B_BE_HT_ILL_CH_ERR_INT_EN | \ + B_BE_HR_TOTAL_LEN_UNDER_ERR_INT_EN | \ + B_BE_HR_DMA_PROCESS_ERR_INT_EN | \ + B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN) + +#define R_BE_DISP_CPU_IMR 0x8878 +#define B_BE_CR_PLD_LEN_ERR_INT_EN BIT(30) +#define B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN BIT(29) +#define B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN BIT(28) +#define B_BE_CR_SHIFT_DMA_CFG_ERR_INT_EN BIT(27) +#define B_BE_CR_DMA_PROCESS_ERR_INT_EN BIT(26) +#define B_BE_CR_TOTAL_LEN_UNDER_ERR_INT_EN BIT(25) +#define B_BE_CR_SHIFT_EN_ERR_INT_EN BIT(24) +#define B_BE_REUSE_FIFO_B_UNDER_ERR_INT_EN BIT(22) +#define B_BE_REUSE_FIFO_B_OVER_ERR_INT_EN BIT(21) +#define B_BE_REUSE_FIFO_A_UNDER_ERR_INT_EN BIT(20) +#define B_BE_REUSE_FIFO_A_OVER_ERR_INT_EN BIT(19) +#define B_BE_CT_ADDR_INFO_LEN_MISS_ERR_INT_EN BIT(17) +#define B_BE_CT_WD_LEN_OVER_ERR_INT_EN BIT(16) +#define B_BE_CT_F2P_SEQ_ERR_INT_EN BIT(15) +#define B_BE_CT_F2P_QSEL_ERR_INT_EN BIT(14) +#define B_BE_CT_PLD_CMD_UNDERFLOW_ERR_INT_EN BIT(13) +#define B_BE_CT_PLD_CMD_OVERFLOW_ERR_INT_EN BIT(12) +#define B_BE_CT_PRE_SUB_ERR_INT_EN BIT(11) +#define B_BE_CT_WD_CHKSUM_ERR_INT_EN BIT(10) +#define B_BE_CT_CHANNEL_DMA_ERR_INT_EN BIT(9) +#define B_BE_CT_OFFSET_UNMATCH_ERR_INT_EN BIT(8) +#define B_BE_CT_PAYLOAD_CHKSUM_ERR_INT_EN BIT(7) +#define B_BE_CT_PAYLOAD_UNDER_ERR_INT_EN BIT(6) +#define B_BE_CT_PAYLOAD_OVER_ERR_INT_EN BIT(5) +#define B_BE_CT_PERMU_FF_UNDERFLOW_ERR_INT_EN BIT(4) +#define B_BE_CT_PERMU_FF_OVERFLOW_ERR_INT_EN BIT(3) +#define B_BE_CT_CH_ID_ERR_INT_EN BIT(2) +#define B_BE_CT_PKT_FAIL_ERR_INT_EN BIT(1) +#define B_BE_CT_EP_CH_DIFF_ERR_INT_EN BIT(0) +#define B_BE_DISP_CPU_IMR_CLR (B_BE_CT_EP_CH_DIFF_ERR_INT_EN | \ + B_BE_CT_CH_ID_ERR_INT_EN | \ + B_BE_CT_PERMU_FF_OVERFLOW_ERR_INT_EN | \ + B_BE_CT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \ + B_BE_CT_PAYLOAD_OVER_ERR_INT_EN | \ + B_BE_CT_PAYLOAD_UNDER_ERR_INT_EN | \ + B_BE_CT_OFFSET_UNMATCH_ERR_INT_EN | \ + B_BE_CT_CHANNEL_DMA_ERR_INT_EN | \ + B_BE_CT_WD_CHKSUM_ERR_INT_EN | \ + B_BE_CT_PRE_SUB_ERR_INT_EN | \ + B_BE_CT_PLD_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_CT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_CT_F2P_QSEL_ERR_INT_EN | \ + B_BE_CT_F2P_SEQ_ERR_INT_EN | \ + B_BE_CT_WD_LEN_OVER_ERR_INT_EN | \ + B_BE_CT_ADDR_INFO_LEN_MISS_ERR_INT_EN | \ + B_BE_REUSE_FIFO_A_OVER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_A_UNDER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_B_OVER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_B_UNDER_ERR_INT_EN | \ + B_BE_CR_SHIFT_EN_ERR_INT_EN | \ + B_BE_CR_DMA_PROCESS_ERR_INT_EN | \ + B_BE_CR_SHIFT_DMA_CFG_ERR_INT_EN | \ + B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN | \ + B_BE_CR_PLD_LEN_ERR_INT_EN) +#define B_BE_DISP_CPU_IMR_SET (B_BE_CT_EP_CH_DIFF_ERR_INT_EN | \ + B_BE_CT_CH_ID_ERR_INT_EN | \ + B_BE_CT_PERMU_FF_OVERFLOW_ERR_INT_EN | \ + B_BE_CT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \ + B_BE_CT_PAYLOAD_OVER_ERR_INT_EN | \ + B_BE_CT_PAYLOAD_UNDER_ERR_INT_EN | \ + B_BE_CT_PRE_SUB_ERR_INT_EN | \ + B_BE_CT_PLD_CMD_OVERFLOW_ERR_INT_EN | \ + B_BE_CT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \ + B_BE_CT_WD_LEN_OVER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_A_OVER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_A_UNDER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_B_OVER_ERR_INT_EN | \ + B_BE_REUSE_FIFO_B_UNDER_ERR_INT_EN | \ + B_BE_CR_DMA_PROCESS_ERR_INT_EN | \ + B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN | \ + B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN) + +#define R_BE_DISP_FWD_WLAN_0 0x8938 +#define B_BE_FWD_WLAN_CPU_TYPE_13_MASK GENMASK(31, 30) +#define B_BE_FWD_WLAN_CPU_TYPE_12_MASK GENMASK(29, 28) +#define B_BE_FWD_WLAN_CPU_TYPE_11_MASK GENMASK(27, 26) +#define B_BE_FWD_WLAN_CPU_TYPE_10_MASK GENMASK(25, 24) +#define B_BE_FWD_WLAN_CPU_TYPE_9_MASK GENMASK(23, 22) +#define B_BE_FWD_WLAN_CPU_TYPE_8_MASK GENMASK(21, 20) +#define B_BE_FWD_WLAN_CPU_TYPE_7_MASK GENMASK(19, 18) +#define B_BE_FWD_WLAN_CPU_TYPE_6_MASK GENMASK(17, 16) +#define B_BE_FWD_WLAN_CPU_TYPE_5_MASK GENMASK(15, 14) +#define B_BE_FWD_WLAN_CPU_TYPE_4_MASK GENMASK(13, 12) +#define B_BE_FWD_WLAN_CPU_TYPE_3_MASK GENMASK(11, 10) +#define B_BE_FWD_WLAN_CPU_TYPE_2_MASK GENMASK(9, 8) +#define B_BE_FWD_WLAN_CPU_TYPE_1_MASK GENMASK(7, 6) +#define B_BE_FWD_WLAN_CPU_TYPE_0_CTL_MASK GENMASK(5, 4) +#define B_BE_FWD_WLAN_CPU_TYPE_0_MNG_MASK GENMASK(3, 2) +#define B_BE_FWD_WLAN_CPU_TYPE_0_DATA_MASK GENMASK(1, 0) + +#define R_BE_WDE_PKTBUF_CFG 0x8C08 +#define B_BE_WDE_FREE_PAGE_NUM_MASK GENMASK(28, 16) +#define B_BE_WDE_START_BOUND_MASK GENMASK(14, 8) +#define B_BE_WDE_PAGE_SEL_MASK GENMASK(1, 0) + +#define R_BE_WDE_ERR_IMR 0x8C38 +#define B_BE_WDE_DATCHN_CAMREQ_ERR_INT_EN BIT(29) +#define B_BE_WDE_DATCHN_ADRERR_ERR_INT_EN BIT(28) +#define B_BE_WDE_DATCHN_RRDY_ERR_INT_EN BIT(27) +#define B_BE_WDE_DATCHN_FRZTO_ERR_INT_EN BIT(26) +#define B_BE_WDE_DATCHN_NULLPG_ERR_INT_EN BIT(25) +#define B_BE_WDE_DATCHN_ARBT_ERR_INT_EN BIT(24) +#define B_BE_WDE_QUEMGN_FRZTO_ERR_INT_EN BIT(23) +#define B_BE_WDE_NXTPKTLL_AD_ERR_INT_EN BIT(22) +#define B_BE_WDE_PREPKTLLT_AD_ERR_INT_EN BIT(21) +#define B_BE_WDE_ENQ_PKTCNT_NVAL_ERR_INT_EN BIT(20) +#define B_BE_WDE_ENQ_PKTCNT_OVRF_ERR_INT_EN BIT(19) +#define B_BE_WDE_QUE_SRCQUEID_ERR_INT_EN BIT(18) +#define B_BE_WDE_QUE_DSTQUEID_ERR_INT_EN BIT(17) +#define B_BE_WDE_QUE_CMDTYPE_ERR_INT_EN BIT(16) +#define B_BE_WDE_BUFMGN_MRG_SZLMT_ERR_INT_EN BIT(13) +#define B_BE_WDE_BUFMGN_MRG_QTAID_ERR_INT_EN BIT(12) +#define B_BE_WDE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN BIT(11) +#define B_BE_WDE_ERR_BUFMGN_MRG_STRPKTID_ERR_INT_EN BIT(10) +#define B_BE_WDE_BUFMGN_FRZTO_ERR_INT_EN BIT(9) +#define B_BE_WDE_GETNPG_PGOFST_ERR_INT_EN BIT(8) +#define B_BE_WDE_GETNPG_STRPG_ERR_INT_EN BIT(7) +#define B_BE_WDE_BUFREQ_SRCHTAILPG_ERR_INT_EN BIT(6) +#define B_BE_WDE_BUFRTN_SIZE_ERR_INT_EN BIT(5) +#define B_BE_WDE_BUFRTN_INVLD_PKTID_ERR_INT_EN BIT(4) +#define B_BE_WDE_BUFREQ_UNAVAL_ERR_INT_EN BIT(3) +#define B_BE_WDE_BUFREQ_SIZELMT_INT_EN BIT(2) +#define B_BE_WDE_BUFREQ_SIZE0_INT_EN BIT(1) +#define B_BE_WDE_BUFREQ_QTAID_ERR_INT_EN BIT(0) +#define B_BE_WDE_ERR_IMR_CLR (B_BE_WDE_BUFREQ_QTAID_ERR_INT_EN | \ + B_BE_WDE_BUFREQ_SIZE0_INT_EN | \ + B_BE_WDE_BUFREQ_SIZELMT_INT_EN | \ + B_BE_WDE_BUFREQ_UNAVAL_ERR_INT_EN | \ + B_BE_WDE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \ + B_BE_WDE_BUFRTN_SIZE_ERR_INT_EN | \ + B_BE_WDE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \ + B_BE_WDE_GETNPG_STRPG_ERR_INT_EN | \ + B_BE_WDE_GETNPG_PGOFST_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_ERR_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_QTAID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \ + B_BE_WDE_QUE_CMDTYPE_ERR_INT_EN | \ + B_BE_WDE_QUE_DSTQUEID_ERR_INT_EN | \ + B_BE_WDE_QUE_SRCQUEID_ERR_INT_EN | \ + B_BE_WDE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \ + B_BE_WDE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \ + B_BE_WDE_PREPKTLLT_AD_ERR_INT_EN | \ + B_BE_WDE_NXTPKTLL_AD_ERR_INT_EN | \ + B_BE_WDE_QUEMGN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_DATCHN_ARBT_ERR_INT_EN | \ + B_BE_WDE_DATCHN_NULLPG_ERR_INT_EN | \ + B_BE_WDE_DATCHN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_DATCHN_RRDY_ERR_INT_EN | \ + B_BE_WDE_DATCHN_ADRERR_ERR_INT_EN | \ + B_BE_WDE_DATCHN_CAMREQ_ERR_INT_EN) +#define B_BE_WDE_ERR_IMR_SET (B_BE_WDE_BUFREQ_QTAID_ERR_INT_EN | \ + B_BE_WDE_BUFREQ_SIZE0_INT_EN | \ + B_BE_WDE_BUFREQ_SIZELMT_INT_EN | \ + B_BE_WDE_BUFREQ_UNAVAL_ERR_INT_EN | \ + B_BE_WDE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \ + B_BE_WDE_BUFRTN_SIZE_ERR_INT_EN | \ + B_BE_WDE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \ + B_BE_WDE_GETNPG_STRPG_ERR_INT_EN | \ + B_BE_WDE_GETNPG_PGOFST_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_ERR_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_QTAID_ERR_INT_EN | \ + B_BE_WDE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \ + B_BE_WDE_QUE_CMDTYPE_ERR_INT_EN | \ + B_BE_WDE_QUE_DSTQUEID_ERR_INT_EN | \ + B_BE_WDE_QUE_SRCQUEID_ERR_INT_EN | \ + B_BE_WDE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \ + B_BE_WDE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \ + B_BE_WDE_PREPKTLLT_AD_ERR_INT_EN | \ + B_BE_WDE_NXTPKTLL_AD_ERR_INT_EN | \ + B_BE_WDE_QUEMGN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_DATCHN_ARBT_ERR_INT_EN | \ + B_BE_WDE_DATCHN_NULLPG_ERR_INT_EN | \ + B_BE_WDE_DATCHN_FRZTO_ERR_INT_EN | \ + B_BE_WDE_DATCHN_RRDY_ERR_INT_EN | \ + B_BE_WDE_DATCHN_ADRERR_ERR_INT_EN | \ + B_BE_WDE_DATCHN_CAMREQ_ERR_INT_EN) + +#define R_BE_WDE_QTA0_CFG 0x8C40 +#define B_BE_WDE_Q0_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_WDE_Q0_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_WDE_QTA1_CFG 0x8C44 +#define B_BE_WDE_Q1_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_WDE_Q1_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_WDE_QTA2_CFG 0x8C48 +#define B_BE_WDE_Q2_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_WDE_Q2_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_WDE_QTA3_CFG 0x8C4C +#define B_BE_WDE_Q3_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_WDE_Q3_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_WDE_QTA4_CFG 0x8C50 +#define B_BE_WDE_Q4_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_WDE_Q4_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_WDE_ERR1_IMR 0x8CC0 +#define B_BE_WDE_QUEMGN_CMACACQ_DEQNTFY_INT_EN BIT(8) +#define B_BE_WDE_ERR1_IMR_CLR B_BE_WDE_QUEMGN_CMACACQ_DEQNTFY_INT_EN +#define B_BE_WDE_ERR1_IMR_SET B_BE_WDE_QUEMGN_CMACACQ_DEQNTFY_INT_EN + +#define R_BE_PLE_PKTBUF_CFG 0x9008 +#define B_BE_PLE_FREE_PAGE_NUM_MASK GENMASK(28, 16) +#define B_BE_PLE_START_BOUND_MASK GENMASK(14, 8) +#define B_BE_PLE_PAGE_SEL_MASK GENMASK(1, 0) + +#define R_BE_PLE_ERR_IMR 0x9038 +#define B_BE_PLE_DATCHN_CAMREQ_ERR_INT_EN BIT(29) +#define B_BE_PLE_DATCHN_ADRERR_ERR_INT_EN BIT(28) +#define B_BE_PLE_DATCHN_RRDY_ERR_INT_EN BIT(27) +#define B_BE_PLE_DATCHN_FRZTO_ERR_INT_EN BIT(26) +#define B_BE_PLE_DATCHN_NULLPG_ERR_INT_EN BIT(25) +#define B_BE_PLE_DATCHN_ARBT_ERR_INT_EN BIT(24) +#define B_BE_PLE_QUEMGN_FRZTO_ERR_INT_EN BIT(23) +#define B_BE_PLE_NXTPKTLL_AD_ERR_INT_EN BIT(22) +#define B_BE_PLE_PREPKTLLT_AD_ERR_INT_EN BIT(21) +#define B_BE_PLE_ENQ_PKTCNT_NVAL_ERR_INT_EN BIT(20) +#define B_BE_PLE_ENQ_PKTCNT_OVRF_ERR_INT_EN BIT(19) +#define B_BE_PLE_QUE_SRCQUEID_ERR_INT_EN BIT(18) +#define B_BE_PLE_QUE_DSTQUEID_ERR_INT_EN BIT(17) +#define B_BE_PLE_QUE_CMDTYPE_ERR_INT_EN BIT(16) +#define B_BE_PLE_BUFMGN_MRG_SZLMT_ERR_INT_EN BIT(13) +#define B_BE_PLE_BUFMGN_MRG_QTAID_ERR_INT_EN BIT(12) +#define B_BE_PLE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN BIT(11) +#define B_BE_PLE_BUFMGN_MRG_STRPKTID_ERR_INT_EN BIT(10) +#define B_BE_PLE_BUFMGN_FRZTO_ERR_INT_EN BIT(9) +#define B_BE_PLE_GETNPG_PGOFST_ERR_INT_EN BIT(8) +#define B_BE_PLE_GETNPG_STRPG_ERR_INT_EN BIT(7) +#define B_BE_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN BIT(6) +#define B_BE_PLE_BUFRTN_SIZE_ERR_INT_EN BIT(5) +#define B_BE_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN BIT(4) +#define B_BE_PLE_BUFREQ_UNAVAL_ERR_INT_EN BIT(3) +#define B_BE_PLE_BUFREQ_SIZELMT_INT_EN BIT(2) +#define B_BE_PLE_BUFREQ_SIZE0_INT_EN BIT(1) +#define B_BE_PLE_BUFREQ_QTAID_ERR_INT_EN BIT(0) +#define B_BE_PLE_ERR_IMR_CLR (B_BE_PLE_BUFREQ_QTAID_ERR_INT_EN | \ + B_BE_PLE_BUFREQ_SIZE0_INT_EN | \ + B_BE_PLE_BUFREQ_SIZELMT_INT_EN | \ + B_BE_PLE_BUFREQ_UNAVAL_ERR_INT_EN | \ + B_BE_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \ + B_BE_PLE_BUFRTN_SIZE_ERR_INT_EN | \ + B_BE_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \ + B_BE_PLE_GETNPG_STRPG_ERR_INT_EN | \ + B_BE_PLE_GETNPG_PGOFST_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_QTAID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \ + B_BE_PLE_QUE_CMDTYPE_ERR_INT_EN | \ + B_BE_PLE_QUE_DSTQUEID_ERR_INT_EN | \ + B_BE_PLE_QUE_SRCQUEID_ERR_INT_EN | \ + B_BE_PLE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \ + B_BE_PLE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \ + B_BE_PLE_PREPKTLLT_AD_ERR_INT_EN | \ + B_BE_PLE_NXTPKTLL_AD_ERR_INT_EN | \ + B_BE_PLE_QUEMGN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_DATCHN_ARBT_ERR_INT_EN | \ + B_BE_PLE_DATCHN_NULLPG_ERR_INT_EN | \ + B_BE_PLE_DATCHN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_DATCHN_RRDY_ERR_INT_EN | \ + B_BE_PLE_DATCHN_ADRERR_ERR_INT_EN | \ + B_BE_PLE_DATCHN_CAMREQ_ERR_INT_EN) +#define B_BE_PLE_ERR_IMR_SET (B_BE_PLE_BUFREQ_QTAID_ERR_INT_EN | \ + B_BE_PLE_BUFREQ_SIZE0_INT_EN | \ + B_BE_PLE_BUFREQ_SIZELMT_INT_EN | \ + B_BE_PLE_BUFREQ_UNAVAL_ERR_INT_EN | \ + B_BE_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \ + B_BE_PLE_BUFRTN_SIZE_ERR_INT_EN | \ + B_BE_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \ + B_BE_PLE_GETNPG_STRPG_ERR_INT_EN | \ + B_BE_PLE_GETNPG_PGOFST_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_QTAID_ERR_INT_EN | \ + B_BE_PLE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \ + B_BE_PLE_QUE_CMDTYPE_ERR_INT_EN | \ + B_BE_PLE_QUE_DSTQUEID_ERR_INT_EN | \ + B_BE_PLE_QUE_SRCQUEID_ERR_INT_EN | \ + B_BE_PLE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \ + B_BE_PLE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \ + B_BE_PLE_PREPKTLLT_AD_ERR_INT_EN | \ + B_BE_PLE_NXTPKTLL_AD_ERR_INT_EN | \ + B_BE_PLE_QUEMGN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_DATCHN_ARBT_ERR_INT_EN | \ + B_BE_PLE_DATCHN_NULLPG_ERR_INT_EN | \ + B_BE_PLE_DATCHN_FRZTO_ERR_INT_EN | \ + B_BE_PLE_DATCHN_RRDY_ERR_INT_EN | \ + B_BE_PLE_DATCHN_ADRERR_ERR_INT_EN | \ + B_BE_PLE_DATCHN_CAMREQ_ERR_INT_EN) + +#define R_BE_PLE_QTA0_CFG 0x9040 +#define B_BE_PLE_Q0_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q0_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA1_CFG 0x9044 +#define B_BE_PLE_Q1_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q1_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA2_CFG 0x9048 +#define B_BE_PLE_Q2_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q2_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA3_CFG 0x904C +#define B_BE_PLE_Q3_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q3_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA4_CFG 0x9050 +#define B_BE_PLE_Q4_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q4_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA5_CFG 0x9054 +#define B_BE_PLE_Q5_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q5_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA6_CFG 0x9058 +#define B_BE_PLE_Q6_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q6_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA7_CFG 0x905C +#define B_BE_PLE_Q7_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q7_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA8_CFG 0x9060 +#define B_BE_PLE_Q8_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q8_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA9_CFG 0x9064 +#define B_BE_PLE_Q9_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q9_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA10_CFG 0x9068 +#define B_BE_PLE_Q10_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q10_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA11_CFG 0x906C +#define B_BE_PLE_Q11_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q11_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_QTA12_CFG 0x9070 +#define B_BE_PLE_Q12_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q12_MIN_SIZE_MASK GENMASK(11, 0) + +#define R_BE_PLE_ERRFLAG1_IMR 0x90C0 +#define B_BE_PLE_SRCHPG_PGOFST_IMR BIT(26) +#define B_BE_PLE_SRCHPG_STRPG_IMR BIT(25) +#define B_BE_PLE_SRCHPG_FRZTO_IMR BIT(24) +#define B_BE_PLE_ERRFLAG1_IMR_CLR (B_BE_PLE_SRCHPG_FRZTO_IMR | \ + B_BE_PLE_SRCHPG_STRPG_IMR | \ + B_BE_PLE_SRCHPG_PGOFST_IMR) +#define B_BE_PLE_ERRFLAG1_IMR_SET (B_BE_PLE_SRCHPG_FRZTO_IMR | \ + B_BE_PLE_SRCHPG_STRPG_IMR | \ + B_BE_PLE_SRCHPG_PGOFST_IMR) + #define R_BE_PLE_DBG_FUN_INTF_CTL 0x9110 #define B_BE_PLE_DFI_ACTIVE BIT(31) #define B_BE_PLE_DFI_TRGSEL_MASK GENMASK(19, 16) @@ -3757,6 +5220,608 @@ #define R_BE_PLE_DBG_FUN_INTF_DATA 0x9114 #define B_BE_PLE_DFI_DATA_MASK GENMASK(31, 0) +#define R_BE_WDRLS_CFG 0x9408 +#define B_BE_WDRLS_DIS_AGAC BIT(31) +#define B_BE_RLSRPT_BUFREQ_TO_MASK GENMASK(15, 8) +#define B_BE_RLSRPT_BUFREQ_TO_SEL_MASK GENMASK(7, 6) +#define B_BE_WDRLS_MODE_MASK GENMASK(1, 0) + +#define R_BE_WDRLS_ERR_IMR 0x9430 +#define B_BE_WDRLS_RPT3_FRZTO_ERR_INT_EN BIT(21) +#define B_BE_WDRLS_RPT3_AGGNUM0_ERR_INT_EN BIT(20) +#define B_BE_WDRLS_RPT2_FRZTO_ERR_INT_EN BIT(17) +#define B_BE_WDRLS_RPT2_AGGNUM0_ERR_INT_EN BIT(16) +#define B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN BIT(13) +#define B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN BIT(12) +#define B_BE_WDRLS_RPT0_FRZTO_ERR_INT_EN BIT(9) +#define B_BE_WDRLS_RPT0_AGGNUM0_ERR_INT_EN BIT(8) +#define B_BE_WDRLS_PLEBREQ_PKTID_ISNULL_ERR_INT_EN BIT(5) +#define B_BE_WDRLS_PLEBREQ_TO_ERR_INT_EN BIT(4) +#define B_BE_WDRLS_CTL_FRZTO_ERR_INT_EN BIT(2) +#define B_BE_WDRLS_CTL_PLPKTID_ISNULL_ERR_INT_EN BIT(1) +#define B_BE_WDRLS_CTL_WDPKTID_ISNULL_ERR_INT_EN BIT(0) +#define B_BE_WDRLS_ERR_IMR_CLR (B_BE_WDRLS_CTL_WDPKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_CTL_PLPKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_CTL_FRZTO_ERR_INT_EN | \ + B_BE_WDRLS_PLEBREQ_TO_ERR_INT_EN | \ + B_BE_WDRLS_PLEBREQ_PKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_RPT0_AGGNUM0_ERR_INT_EN | \ + B_BE_WDRLS_RPT0_FRZTO_ERR_INT_EN | \ + B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN | \ + B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN) +#define B_BE_WDRLS_ERR_IMR_SET (B_BE_WDRLS_CTL_WDPKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_CTL_PLPKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_CTL_FRZTO_ERR_INT_EN | \ + B_BE_WDRLS_PLEBREQ_PKTID_ISNULL_ERR_INT_EN | \ + B_BE_WDRLS_RPT0_AGGNUM0_ERR_INT_EN | \ + B_BE_WDRLS_RPT0_FRZTO_ERR_INT_EN | \ + B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN | \ + B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN) + +#define R_BE_RLSRPT0_CFG1 0x9444 +#define B_BE_RLSRPT0_FLTR_MAP_MASK GENMASK(27, 24) +#define S_BE_WDRLS_FLTR_TXOK 1 +#define S_BE_WDRLS_FLTR_RTYLMT 2 +#define S_BE_WDRLS_FLTR_LIFTIM 4 +#define S_BE_WDRLS_FLTR_MACID 8 +#define B_BE_RLSRPT0_TO_MASK GENMASK(23, 16) +#define B_BE_RLSRPT0_AGGNUM_MASK GENMASK(7, 0) + +#define R_BE_BBRPT_COM_ERR_IMR 0x9608 +#define B_BE_BBRPT_COM_EVT01_ISR_EN BIT(1) +#define B_BE_BBRPT_COM_NULL_PLPKTID_ISR_EN BIT(0) +#define B_BE_BBRPT_COM_ERR_IMR_CLR (B_BE_BBRPT_COM_NULL_PLPKTID_ISR_EN | \ + B_BE_BBRPT_COM_EVT01_ISR_EN) +#define B_BE_BBRPT_COM_ERR_IMR_SET B_BE_BBRPT_COM_NULL_PLPKTID_ISR_EN + +#define R_BE_BBRPT_CHINFO_ERR_IMR 0x9628 +#define B_BE_ERR_BB_ONETEN_INT_EN BIT(1) +#define B_BE_ERR_GEN_FRZTO_INT_EN BIT(0) +#define B_BE_BBRPT_CHINFO_ERR_IMR_CLR (B_BE_ERR_GEN_FRZTO_INT_EN | \ + B_BE_ERR_BB_ONETEN_INT_EN) +#define B_BE_BBRPT_CHINFO_ERR_IMR_SET (B_BE_ERR_GEN_FRZTO_INT_EN | \ + B_BE_ERR_BB_ONETEN_INT_EN) + +#define R_BE_BBRPT_DFS_ERR_IMR 0x9638 +#define B_BE_BBRPT_DFS_TO_ERR_INT_EN BIT(0) +#define B_BE_BBRPT_DFS_ERR_IMR_CLR B_BE_BBRPT_DFS_TO_ERR_INT_EN +#define B_BE_BBRPT_DFS_ERR_IMR_SET B_BE_BBRPT_DFS_TO_ERR_INT_EN + +#define R_BE_LA_ERRFLAG_IMR 0x9668 +#define B_BE_LA_IMR_DATA_LOSS BIT(0) +#define B_BE_LA_ERRFLAG_IMR_CLR B_BE_LA_IMR_DATA_LOSS +#define B_BE_LA_ERRFLAG_IMR_SET B_BE_LA_IMR_DATA_LOSS + +#define R_BE_LA_ERRFLAG_ISR 0x966C +#define B_BE_LA_ISR_DATA_LOSS BIT(0) + +#define R_BE_CH_INFO_DBGFLAG_IMR 0x9688 +#define B_BE_BCHN_EVT01_ISR_EN BIT(29) +#define B_BE_BCHN_REQTO_ISR_EN BIT(28) +#define B_BE_CHIF_RXDATA_AFACT_ISR_EN BIT(11) +#define B_BE_CHIF_RXDATA_BFACT_ISR_EN BIT(10) +#define B_BE_CHIF_HDR_SEGLEN_ISR_EN BIT(9) +#define B_BE_CHIF_HDR_INVLD_ISR_EN BIT(8) +#define B_BE_CHIF_BBONL_BFACT_ISR_EN BIT(4) +#define B_BE_CHIF_RPT_OVF_ISR_EN BIT(3) +#define B_BE_DBG_CHIF_DATA_LOSS_ISR_EN BIT(2) +#define B_BE_CHIF_DATA_WTOUT_ISR_EN BIT(1) +#define B_BE_CHIF_RPT_WTOUT_ISR_EN BIT(0) +#define B_BE_CH_INFO_DBGFLAG_IMR_CLR (B_BE_CHIF_RPT_WTOUT_ISR_EN | \ + B_BE_CHIF_DATA_WTOUT_ISR_EN | \ + B_BE_DBG_CHIF_DATA_LOSS_ISR_EN | \ + B_BE_CHIF_RPT_OVF_ISR_EN | \ + B_BE_CHIF_HDR_INVLD_ISR_EN | \ + B_BE_CHIF_HDR_SEGLEN_ISR_EN | \ + B_BE_CHIF_RXDATA_BFACT_ISR_EN | \ + B_BE_CHIF_RXDATA_AFACT_ISR_EN) +#define B_BE_CH_INFO_DBGFLAG_IMR_SET 0 + +#define R_BE_WD_BUF_REQ 0x9800 +#define B_BE_WD_BUF_REQ_EXEC BIT(31) +#define B_BE_WD_BUF_REQ_QUOTA_ID_MASK GENMASK(23, 16) +#define B_BE_WD_BUF_REQ_LEN_MASK GENMASK(15, 0) + +#define R_BE_WD_BUF_STATUS 0x9804 +#define B_BE_WD_BUF_STAT_DONE BIT(31) +#define B_BE_WD_BUF_STAT_PKTID_MASK GENMASK(11, 0) + +#define R_BE_WD_CPUQ_OP_0 0x9810 +#define B_BE_WD_CPUQ_OP_EXEC BIT(31) +#define B_BE_WD_CPUQ_OP_CMD_TYPE_MASK GENMASK(27, 24) +#define B_BE_WD_CPUQ_OP_PKTNUM_MASK GENMASK(7, 0) + +#define R_BE_WD_CPUQ_OP_1 0x9814 +#define B_BE_WD_CPUQ_OP_SRC_MACID_MASK GENMASK(19, 12) +#define B_BE_WD_CPUQ_OP_SRC_QID_MASK GENMASK(9, 4) +#define B_BE_WD_CPUQ_OP_SRC_PID_MASK GENMASK(2, 0) + +#define R_BE_WD_CPUQ_OP_2 0x9818 +#define B_BE_WD_CPUQ_OP_DST_MACID_MASK GENMASK(19, 12) +#define B_BE_WD_CPUQ_OP_DST_QID_MASK GENMASK(9, 4) +#define B_BE_WD_CPUQ_OP_DST_PID_MASK GENMASK(2, 0) + +#define R_BE_WD_CPUQ_OP_3 0x981C +#define B_BE_WD_CPUQ_OP_STRT_PKTID_MASK GENMASK(27, 16) +#define B_BE_WD_CPUQ_OP_END_PKTID_MASK GENMASK(11, 0) + +#define R_BE_WD_CPUQ_OP_STATUS 0x9820 +#define B_BE_WD_CPUQ_OP_STAT_DONE BIT(31) +#define B_BE_WD_CPUQ_OP_PKTCNT_MASK GENMASK(27, 16) +#define B_BE_WD_CPUQ_OP_PKTID_MASK GENMASK(11, 0) + +#define R_BE_PL_BUF_REQ 0x9840 +#define B_BE_PL_BUF_REQ_EXEC BIT(31) +#define B_BE_PL_BUF_REQ_QUOTA_ID_MASK GENMASK(19, 16) +#define B_BE_PL_BUF_REQ_LEN_MASK GENMASK(15, 0) + +#define R_BE_PL_BUF_STATUS 0x9844 +#define B_BE_PL_BUF_STAT_DONE BIT(31) +#define B_BE_PL_BUF_STAT_PKTID_MASK GENMASK(11, 0) + +#define R_BE_PL_CPUQ_OP_0 0x9850 +#define B_BE_PL_CPUQ_OP_EXEC BIT(31) +#define B_BE_PL_CPUQ_OP_CMD_TYPE_MASK GENMASK(27, 24) +#define B_BE_PL_CPUQ_OP_PKTNUM_MASK GENMASK(7, 0) + +#define R_BE_PL_CPUQ_OP_1 0x9854 +#define B_BE_PL_CPUQ_OP_SRC_MACID_MASK GENMASK(19, 12) +#define B_BE_PL_CPUQ_OP_SRC_QID_MASK GENMASK(9, 4) +#define B_BE_PL_CPUQ_OP_SRC_PID_MASK GENMASK(2, 0) + +#define R_BE_PL_CPUQ_OP_2 0x9858 +#define B_BE_PL_CPUQ_OP_DST_MACID_MASK GENMASK(19, 12) +#define B_BE_PL_CPUQ_OP_DST_QID_MASK GENMASK(9, 4) +#define B_BE_PL_CPUQ_OP_DST_PID_MASK GENMASK(2, 0) + +#define R_BE_PL_CPUQ_OP_3 0x985C +#define B_BE_PL_CPUQ_OP_STRT_PKTID_MASK GENMASK(27, 16) +#define B_BE_PL_CPUQ_OP_END_PKTID_MASK GENMASK(11, 0) + +#define R_BE_PL_CPUQ_OP_STATUS 0x9860 +#define B_BE_PL_CPUQ_OP_STAT_DONE BIT(31) +#define B_BE_PL_CPUQ_OP_PKTCNT_MASK GENMASK(27, 16) +#define B_BE_PL_CPUQ_OP_PKTID_MASK GENMASK(11, 0) + +#define R_BE_CPUIO_ERR_IMR 0x9888 +#define B_BE_PLEQUE_OP_ERR_INT_EN BIT(12) +#define B_BE_PLEBUF_OP_ERR_INT_EN BIT(8) +#define B_BE_WDEQUE_OP_ERR_INT_EN BIT(4) +#define B_BE_WDEBUF_OP_ERR_INT_EN BIT(0) +#define B_BE_CPUIO_ERR_IMR_CLR (B_BE_WDEBUF_OP_ERR_INT_EN | \ + B_BE_WDEQUE_OP_ERR_INT_EN | \ + B_BE_PLEBUF_OP_ERR_INT_EN | \ + B_BE_PLEQUE_OP_ERR_INT_EN) +#define B_BE_CPUIO_ERR_IMR_SET (B_BE_WDEBUF_OP_ERR_INT_EN | \ + B_BE_WDEQUE_OP_ERR_INT_EN | \ + B_BE_PLEBUF_OP_ERR_INT_EN | \ + B_BE_PLEQUE_OP_ERR_INT_EN) + +#define R_BE_PKTIN_ERR_IMR 0x9A20 +#define B_BE_SW_MERGE_ERR_INT_EN BIT(1) +#define B_BE_GET_NULL_PKTID_ERR_INT_EN BIT(0) +#define B_BE_PKTIN_ERR_IMR_CLR (B_BE_SW_MERGE_ERR_INT_EN | \ + B_BE_GET_NULL_PKTID_ERR_INT_EN) +#define B_BE_PKTIN_ERR_IMR_SET (B_BE_SW_MERGE_ERR_INT_EN | \ + B_BE_GET_NULL_PKTID_ERR_INT_EN) + +#define R_BE_HDR_SHCUT_SETTING 0x9B00 +#define B_BE_TX_ADDR_MLD_TO_LIK BIT(4) +#define B_BE_TX_HW_SEC_HDR_EN BIT(3) +#define B_BE_TX_MAC_MPDU_PROC_EN BIT(2) +#define B_BE_TX_HW_ACK_POLICY_EN BIT(1) +#define B_BE_TX_HW_SEQ_EN BIT(0) + +#define R_BE_MPDU_TX_ERR_IMR 0x9BF4 +#define B_BE_TX_TIMEOUT_ERR_EN BIT(0) +#define B_BE_MPDU_TX_ERR_IMR_CLR B_BE_TX_TIMEOUT_ERR_EN +#define B_BE_MPDU_TX_ERR_IMR_SET 0 + +#define R_BE_MPDU_PROC 0x9C00 +#define B_BE_PORT_SEL BIT(29) +#define B_BE_WPKT_WLANCPU_QSEL_MASK GENMASK(28, 27) +#define B_BE_WPKT_DATACPU_QSEL_MASK GENMASK(26, 25) +#define B_BE_WPKT_FW_RLS BIT(24) +#define B_BE_FWD_RPKT_MASK GENMASK(23, 16) +#define B_BE_FWD_WPKT_MASK GENMASK(15, 8) +#define B_BE_RXFWD_PRIO_MASK GENMASK(5, 4) +#define B_BE_RXFWD_EN BIT(3) +#define B_BE_DROP_NONDMA_PPDU BIT(2) +#define B_BE_APPEND_FCS BIT(0) + +#define R_BE_CUT_AMSDU_CTRL 0x9C94 +#define B_BE_EN_CUT_AMSDU BIT(31) +#define B_BE_CUT_AMSDU_CHKLEN_EN BIT(30) +#define B_BE_CA_CHK_ADDRCAM_EN BIT(29) +#define B_BE_MPDU_CUT_CTRL_EN BIT(24) +#define B_BE_CUT_AMSDU_CHKLEN_L_TH_MASK GENMASK(23, 16) +#define B_BE_CUT_AMSDU_CHKLEN_H_TH_MASK GENMASK(15, 0) + +#define R_BE_RX_HDRTRNS 0x9CC0 +#define B_BE_RX_MGN_MLD_ADDR_EN BIT(6) +#define B_BE_HDR_INFO_MASK GENMASK(5, 4) +#define B_BE_HC_ADDR_HIT_EN BIT(3) +#define B_BE_RX_ADDR_LINK_TO_MLO BIT(2) +#define B_BE_HDR_CNV BIT(1) +#define B_BE_RX_HDR_CNV_EN BIT(0) +#define TRXCFG_MPDU_PROC_RX_HDR_CONV 0x00000000 + +#define R_BE_MPDU_RX_ERR_IMR 0x9CF4 +#define B_BE_LEN_ERR_IMR BIT(3) +#define B_BE_TIMEOUT_ERR_IMR BIT(1) +#define B_BE_MPDU_RX_ERR_IMR_CLR B_BE_TIMEOUT_ERR_IMR +#define B_BE_MPDU_RX_ERR_IMR_SET 0 + +#define R_BE_SEC_ENG_CTRL 0x9D00 +#define B_BE_SEC_ENG_EN BIT(31) +#define B_BE_CCMP_SPP_MIC BIT(30) +#define B_BE_CCMP_SPP_CTR BIT(29) +#define B_BE_SEC_CAM_ACC BIT(28) +#define B_BE_WMAC_SEC_PN_SEL_MASK GENMASK(27, 26) +#define B_BE_WMAC_SEC_MASKIV BIT(25) +#define B_BE_WAPI_SPEC BIT(24) +#define B_BE_REVERT_TA_RA_MLD_EN BIT(23) +#define B_BE_SEC_DBG_SEL_MASK GENMASK(19, 16) +#define B_BE_CAM_FORCE_CLK BIT(15) +#define B_BE_SEC_FORCE_CLK BIT(14) +#define B_BE_SEC_RX_SHORT_ADD_ICVERR BIT(13) +#define B_BE_SRAM_IO_PROT BIT(12) +#define B_BE_SEC_PRE_ENQUE_TX BIT(11) +#define B_BE_CLK_EN_CGCMP BIT(10) +#define B_BE_CLK_EN_WAPI BIT(9) +#define B_BE_CLK_EN_WEP_TKIP BIT(8) +#define B_BE_BMC_MGNT_DEC BIT(5) +#define B_BE_UC_MGNT_DEC BIT(4) +#define B_BE_MC_DEC BIT(3) +#define B_BE_BC_DEC BIT(2) +#define B_BE_SEC_RX_DEC BIT(1) +#define B_BE_SEC_TX_ENC BIT(0) + +#define R_BE_SEC_MPDU_PROC 0x9D04 +#define B_BE_DBG_ENGINE_SEL BIT(8) +#define B_BE_STOP_RX_PKT_HANDLE BIT(7) +#define B_BE_STOP_TX_PKT_HANDLE BIT(6) +#define B_BE_QUEUE_FOWARD_SEL BIT(5) +#define B_BE_RESP1_PROTECT BIT(4) +#define B_BE_RESP0_PROTECT BIT(3) +#define B_BE_TX_ACTIVE_PROTECT BIT(2) +#define B_BE_APPEND_ICV BIT(1) +#define B_BE_APPEND_MIC BIT(0) + +#define R_BE_SEC_CAM_ACCESS 0x9D10 +#define B_BE_SEC_TIME_OUT_MASK GENMASK(31, 16) +#define B_BE_SEC_CAM_POLL BIT(15) +#define B_BE_SEC_CAM_RW BIT(14) +#define B_BE_SEC_CAM_ACC_FAIL BIT(13) +#define B_BE_SEC_CAM_OFFSET_MASK GENMASK(10, 0) + +#define R_BE_SEC_CAM_RDATA 0x9D14 +#define B_BE_SEC_CAM_RDATA_MASK GENMASK(31, 0) + +#define R_BE_SEC_DEBUG2 0x9D28 +#define B_BE_DBG_READ_MASK GENMASK(31, 0) + +#define R_BE_SEC_ERROR_IMR 0x9D2C +#define B_BE_QUEUE_OPERATION_HANG_IMR BIT(4) +#define B_BE_SEC1_RX_HANG_IMR BIT(3) +#define B_BE_SEC1_TX_HANG_IMR BIT(2) +#define B_BE_RX_HANG_IMR BIT(1) +#define B_BE_TX_HANG_IMR BIT(0) +#define B_BE_SEC_ERROR_IMR_CLR (B_BE_TX_HANG_IMR | \ + B_BE_RX_HANG_IMR | \ + B_BE_SEC1_TX_HANG_IMR | \ + B_BE_SEC1_RX_HANG_IMR | \ + B_BE_QUEUE_OPERATION_HANG_IMR) +#define B_BE_SEC_ERROR_IMR_SET (B_BE_TX_HANG_IMR | \ + B_BE_RX_HANG_IMR | \ + B_BE_SEC1_TX_HANG_IMR | \ + B_BE_SEC1_RX_HANG_IMR | \ + B_BE_QUEUE_OPERATION_HANG_IMR) + +#define R_BE_SEC_ERROR_FLAG 0x9D30 +#define B_BE_TXD_DIFF_KEYCAM_TYPE_ERROR BIT(5) +#define B_BE_QUEUE_OPERATION_HANG_ERROR BIT(4) +#define B_BE_SEC1_RX_HANG_ERROR BIT(3) +#define B_BE_SEC1_TX_HANG_ERROR BIT(2) +#define B_BE_RX_HANG_ERROR BIT(1) +#define B_BE_TX_HANG_ERROR BIT(0) + +#define R_BE_TXPKTCTL_MPDUINFO_CFG 0x9F10 +#define B_BE_MPDUINFO_FEN BIT(31) +#define B_BE_MPDUINFO_PKTID_MASK GENMASK(27, 16) +#define B_BE_MPDUINFO_B1_BADDR_MASK GENMASK(5, 0) +#define MPDU_INFO_B1_OFST 18 + +#define R_BE_TXPKTCTL_B0_PRELD_CFG0 0x9F48 +#define B_BE_B0_PRELD_FEN BIT(31) +#define B_BE_B0_PRELD_USEMAXSZ_MASK GENMASK(25, 16) +#define B_BE_B0_PRELD_CAM_G1ENTNUM_MASK GENMASK(12, 8) +#define B_BE_B0_PRELD_CAM_G0ENTNUM_MASK GENMASK(4, 0) + +#define R_BE_TXPKTCTL_B0_PRELD_CFG1 0x9F4C +#define B_BE_B0_PRELD_NXT_TXENDWIN_MASK GENMASK(11, 8) +#define B_BE_B0_PRELD_NXT_RSVMINSZ_MASK GENMASK(7, 0) + +#define R_BE_TXPKTCTL_B0_ERRFLAG_IMR 0x9F78 +#define B_BE_B0_IMR_DBG_USRCTL_RLSBMPLEN BIT(25) +#define B_BE_B0_IMR_DBG_USRCTL_RDNRLSCMD BIT(24) +#define B_BE_B0_IMR_ERR_PRELD_ENTNUMCFG BIT(17) +#define B_BE_B0_IMR_ERR_PRELD_RLSPKTSZERR BIT(16) +#define B_BE_B0_IMR_ERR_CMDPSR_TBLSZ BIT(11) +#define B_BE_B0_IMR_ERR_CMDPSR_FRZTO BIT(10) +#define B_BE_B0_IMR_ERR_CMDPSR_CMDTYPE BIT(9) +#define B_BE_B0_IMR_ERR_CMDPSR_1STCMDERR BIT(8) +#define B_BE_B0_IMR_ERR_USRCTL_NOINIT BIT(1) +#define B_BE_B0_IMR_ERR_USRCTL_REINIT BIT(0) +#define B_BE_TXPKTCTL_B0_ERRFLAG_IMR_CLR (B_BE_B0_IMR_ERR_USRCTL_REINIT | \ + B_BE_B0_IMR_ERR_USRCTL_NOINIT | \ + B_BE_B0_IMR_DBG_USRCTL_RDNRLSCMD | \ + B_BE_B0_IMR_DBG_USRCTL_RLSBMPLEN | \ + B_BE_B0_IMR_ERR_CMDPSR_1STCMDERR | \ + B_BE_B0_IMR_ERR_CMDPSR_CMDTYPE | \ + B_BE_B0_IMR_ERR_CMDPSR_FRZTO | \ + B_BE_B0_IMR_ERR_CMDPSR_TBLSZ | \ + B_BE_B0_IMR_ERR_PRELD_RLSPKTSZERR | \ + B_BE_B0_IMR_ERR_PRELD_ENTNUMCFG) +#define B_BE_TXPKTCTL_B0_ERRFLAG_IMR_SET (B_BE_B0_IMR_ERR_USRCTL_REINIT | \ + B_BE_B0_IMR_ERR_USRCTL_NOINIT | \ + B_BE_B0_IMR_ERR_CMDPSR_1STCMDERR | \ + B_BE_B0_IMR_ERR_CMDPSR_CMDTYPE | \ + B_BE_B0_IMR_ERR_CMDPSR_FRZTO | \ + B_BE_B0_IMR_ERR_CMDPSR_TBLSZ | \ + B_BE_B0_IMR_ERR_PRELD_RLSPKTSZERR | \ + B_BE_B0_IMR_ERR_PRELD_ENTNUMCFG) + +#define R_BE_TXPKTCTL_B1_PRELD_CFG0 0x9F88 +#define B_BE_B1_PRELD_FEN BIT(31) +#define B_BE_B1_PRELD_USEMAXSZ_MASK GENMASK(25, 16) +#define B_BE_B1_PRELD_CAM_G1ENTNUM_MASK GENMASK(12, 8) +#define B_BE_B1_PRELD_CAM_G0ENTNUM_MASK GENMASK(4, 0) + +#define R_BE_TXPKTCTL_B1_PRELD_CFG1 0x9F8C +#define B_BE_B1_PRELD_NXT_TXENDWIN_MASK GENMASK(11, 8) +#define B_BE_B1_PRELD_NXT_RSVMINSZ_MASK GENMASK(7, 0) + +#define R_BE_TXPKTCTL_B1_ERRFLAG_IMR 0x9FB8 +#define B_BE_B1_IMR_DBG_USRCTL_RLSBMPLEN BIT(25) +#define B_BE_B1_IMR_DBG_USRCTL_RDNRLSCMD BIT(24) +#define B_BE_B1_IMR_ERR_PRELD_ENTNUMCFG BIT(17) +#define B_BE_B1_IMR_ERR_PRELD_RLSPKTSZERR BIT(16) +#define B_BE_B1_IMR_ERR_CMDPSR_TBLSZ BIT(11) +#define B_BE_B1_IMR_ERR_CMDPSR_FRZTO BIT(10) +#define B_BE_B1_IMR_ERR_CMDPSR_CMDTYPE BIT(9) +#define B_BE_B1_IMR_ERR_CMDPSR_1STCMDERR BIT(8) +#define B_BE_B1_IMR_ERR_USRCTL_NOINIT BIT(1) +#define B_BE_B1_IMR_ERR_USRCTL_REINIT BIT(0) +#define B_BE_TXPKTCTL_B1_ERRFLAG_IMR_CLR (B_BE_B1_IMR_ERR_USRCTL_REINIT | \ + B_BE_B1_IMR_ERR_USRCTL_NOINIT | \ + B_BE_B1_IMR_DBG_USRCTL_RDNRLSCMD | \ + B_BE_B1_IMR_DBG_USRCTL_RLSBMPLEN | \ + B_BE_B1_IMR_ERR_CMDPSR_1STCMDERR | \ + B_BE_B1_IMR_ERR_CMDPSR_CMDTYPE | \ + B_BE_B1_IMR_ERR_CMDPSR_FRZTO | \ + B_BE_B1_IMR_ERR_CMDPSR_TBLSZ | \ + B_BE_B1_IMR_ERR_PRELD_RLSPKTSZERR | \ + B_BE_B1_IMR_ERR_PRELD_ENTNUMCFG) +#define B_BE_TXPKTCTL_B1_ERRFLAG_IMR_SET (B_BE_B1_IMR_ERR_USRCTL_REINIT | \ + B_BE_B1_IMR_ERR_USRCTL_NOINIT | \ + B_BE_B1_IMR_ERR_CMDPSR_1STCMDERR | \ + B_BE_B1_IMR_ERR_CMDPSR_CMDTYPE | \ + B_BE_B1_IMR_ERR_CMDPSR_FRZTO | \ + B_BE_B1_IMR_ERR_CMDPSR_TBLSZ | \ + B_BE_B1_IMR_ERR_PRELD_RLSPKTSZERR | \ + B_BE_B1_IMR_ERR_PRELD_ENTNUMCFG) + +#define R_BE_MLO_INIT_CTL 0xA114 +#define B_BE_MLO_TABLE_INIT_DONE BIT(31) +#define B_BE_MLO_TABLE_CLR_DONE BIT(30) +#define B_BE_MLO_TABLE_REINIT BIT(23) +#define B_BE_MLO_TABLE_HW_FLAG_CLR BIT(22) + +#define R_BE_MLO_ERR_IDCT_IMR 0xA128 +#define B_BE_MLO_ERR_IDCT_IMR_0 BIT(31) +#define B_BE_MLO_ERR_IDCT_IMR_1 BIT(30) +#define B_BE_MLO_ERR_IDCT_IMR_2 BIT(29) +#define B_BE_MLO_ERR_IDCT_IMR_3 BIT(28) +#define B_BE_MLO_ERR_IDCT_IMR_CLR (B_BE_MLO_ERR_IDCT_IMR_2 | \ + B_BE_MLO_ERR_IDCT_IMR_1 | \ + B_BE_MLO_ERR_IDCT_IMR_0) +#define B_BE_MLO_ERR_IDCT_IMR_SET (B_BE_MLO_ERR_IDCT_IMR_2 | \ + B_BE_MLO_ERR_IDCT_IMR_1 | \ + B_BE_MLO_ERR_IDCT_IMR_0) + +#define R_BE_MLO_ERR_IDCT_ISR 0xA12C +#define B_BE_MLO_ISR_IDCT_0 BIT(31) +#define B_BE_MLO_ISR_IDCT_1 BIT(30) +#define B_BE_MLO_ISR_IDCT_2 BIT(29) +#define B_BE_MLO_ISR_IDCT_3 BIT(28) + +#define R_BE_PLRLS_ERR_IMR 0xA218 +#define B_BE_PLRLS_CTL_FRZTO_IMR BIT(0) +#define B_BE_PLRLS_ERR_IMR_CLR B_BE_PLRLS_CTL_FRZTO_IMR +#define B_BE_PLRLS_ERR_IMR_SET B_BE_PLRLS_CTL_FRZTO_IMR + +#define R_BE_PLRLS_ERR_ISR 0xA21C +#define B_BE_PLRLS_CTL_EVT03_ISR BIT(3) +#define B_BE_PLRLS_CTL_EVT02_ISR BIT(2) +#define B_BE_PLRLS_CTL_EVT01_ISR BIT(1) +#define B_BE_PLRLS_CTL_FRZTO_ISR BIT(0) + +#define R_BE_SS_CTRL 0xA310 +#define B_BE_SS_INIT_DONE BIT(31) +#define B_BE_WDE_STA_DIS BIT(30) +#define B_BE_WARM_INIT BIT(29) +#define B_BE_BAND_TRIG_EN BIT(28) +#define B_BE_RMAC_REQ_DIS BIT(27) +#define B_BE_DLYTX_SEL_MASK GENMASK(25, 24) +#define B_BE_WMM3_SWITCH_MASK GENMASK(23, 22) +#define B_BE_WMM2_SWITCH_MASK GENMASK(21, 20) +#define B_BE_WMM1_SWITCH_MASK GENMASK(19, 18) +#define B_BE_WMM0_SWITCH_MASK GENMASK(17, 16) +#define B_BE_STA_OPTION_CR BIT(15) +#define B_BE_EMLSR_STA_EMPTY_EN BIT(11) +#define B_BE_MLO_HW_CHGLINK_EN BIT(10) +#define B_BE_BAND1_TRIG_EN BIT(9) +#define B_BE_RMAC1_REQ_DIS BIT(8) +#define B_BE_MRT_SRAM_EN BIT(7) +#define B_BE_MRT_INIT_EN BIT(6) +#define B_BE_AVG_LENG_EN BIT(5) +#define B_BE_AVG_INIT_EN BIT(4) +#define B_BE_LENG_INIT_EN BIT(2) +#define B_BE_PMPA_INIT_EN BIT(1) +#define B_BE_SS_EN BIT(0) + +#define R_BE_INTERRUPT_MASK_REG 0xA3F0 +#define B_BE_PLE_B_PKTID_ERR_IMR BIT(2) +#define B_BE_RPT_TIMEOUT_IMR BIT(1) +#define B_BE_SEARCH_TIMEOUT_IMR BIT(0) +#define B_BE_INTERRUPT_MASK_REG_CLR (B_BE_SEARCH_TIMEOUT_IMR | \ + B_BE_RPT_TIMEOUT_IMR | \ + B_BE_PLE_B_PKTID_ERR_IMR) +#define B_BE_INTERRUPT_MASK_REG_SET (B_BE_SEARCH_TIMEOUT_IMR | \ + B_BE_RPT_TIMEOUT_IMR | \ + B_BE_PLE_B_PKTID_ERR_IMR) + +#define R_BE_INTERRUPT_STS_REG 0xA3F4 +#define B_BE_PLE_B_PKTID_ERR_ISR BIT(2) +#define B_BE_RPT_TIMEOUT_ISR BIT(1) +#define B_BE_SEARCH_TIMEOUT_ISR BIT(0) + +#define R_BE_HAXI_INIT_CFG1 0xB000 +#define B_BE_CFG_WD_PERIOD_IDLE_MASK GENMASK(31, 28) +#define B_BE_CFG_WD_PERIOD_ACTIVE_MASK GENMASK(27, 24) +#define B_BE_EN_RO_IDX_UPD_BY_IO BIT(19) +#define B_BE_RST_KEEP_REG BIT(18) +#define B_BE_FLUSH_HAXI_MST BIT(17) +#define B_BE_SET_BDRAM_BOUND BIT(16) +#define B_BE_ADDRINFO_ALIGN4B_EN BIT(15) +#define B_BE_RXBD_DONE_MODE_MASK GENMASK(14, 13) +#define B_BE_RXQ_RXBD_MODE_MASK GENMASK(12, 11) +#define B_BE_DMA_MODE_MASK GENMASK(10, 8) +#define S_BE_DMA_MOD_PCIE_NO_DATA_CPU 0x0 +#define S_BE_DMA_MOD_PCIE_DATA_CPU 0x1 +#define S_BE_DMA_MOD_USB 0x4 +#define S_BE_DMA_MOD_SDIO 0x6 +#define B_BE_STOP_AXI_MST BIT(7) +#define B_BE_RXDMA_ALIGN64B_EN BIT(6) +#define B_BE_RXDMA_EN BIT(5) +#define B_BE_TXDMA_EN BIT(4) +#define B_BE_MAX_RXDMA_MASK GENMASK(3, 2) +#define B_BE_MAX_TXDMA_MASK GENMASK(1, 0) + +#define R_BE_HAXI_DMA_STOP1 0xB010 +#define B_BE_STOP_WPDMA BIT(31) +#define B_BE_STOP_CH14 BIT(14) +#define B_BE_STOP_CH13 BIT(13) +#define B_BE_STOP_CH12 BIT(12) +#define B_BE_STOP_CH11 BIT(11) +#define B_BE_STOP_CH10 BIT(10) +#define B_BE_STOP_CH9 BIT(9) +#define B_BE_STOP_CH8 BIT(8) +#define B_BE_STOP_CH7 BIT(7) +#define B_BE_STOP_CH6 BIT(6) +#define B_BE_STOP_CH5 BIT(5) +#define B_BE_STOP_CH4 BIT(4) +#define B_BE_STOP_CH3 BIT(3) +#define B_BE_STOP_CH2 BIT(2) +#define B_BE_STOP_CH1 BIT(1) +#define B_BE_STOP_CH0 BIT(0) + +#define R_BE_HAXI_IDCT_MSK 0xB0B8 +#define B_BE_HAXI_RRESP_ERR_IDCT_MSK BIT(7) +#define B_BE_HAXI_BRESP_ERR_IDCT_MSK BIT(6) +#define B_BE_RXDMA_ERR_FLAG_IDCT_MSK BIT(5) +#define B_BE_SET_FC_ERROR_FLAG_IDCT_MSK BIT(4) +#define B_BE_TXBD_LEN0_ERR_IDCT_MSK BIT(3) +#define B_BE_TXBD_4KBOUND_ERR_IDCT_MSK BIT(2) +#define B_BE_RXMDA_STUCK_IDCT_MSK BIT(1) +#define B_BE_TXMDA_STUCK_IDCT_MSK BIT(0) +#define B_BE_HAXI_IDCT_MSK_CLR (B_BE_TXMDA_STUCK_IDCT_MSK | \ + B_BE_RXMDA_STUCK_IDCT_MSK | \ + B_BE_TXBD_LEN0_ERR_IDCT_MSK | \ + B_BE_SET_FC_ERROR_FLAG_IDCT_MSK | \ + B_BE_RXDMA_ERR_FLAG_IDCT_MSK | \ + B_BE_HAXI_BRESP_ERR_IDCT_MSK | \ + B_BE_HAXI_RRESP_ERR_IDCT_MSK) +#define B_BE_HAXI_IDCT_MSK_SET (B_BE_TXMDA_STUCK_IDCT_MSK | \ + B_BE_RXMDA_STUCK_IDCT_MSK | \ + B_BE_TXBD_LEN0_ERR_IDCT_MSK | \ + B_BE_SET_FC_ERROR_FLAG_IDCT_MSK | \ + B_BE_RXDMA_ERR_FLAG_IDCT_MSK | \ + B_BE_HAXI_BRESP_ERR_IDCT_MSK | \ + B_BE_HAXI_RRESP_ERR_IDCT_MSK) + +#define R_BE_HAXI_IDCT 0xB0BC +#define B_BE_HAXI_RRESP_ERR_IDCT BIT(7) +#define B_BE_HAXI_BRESP_ERR_IDCT BIT(6) +#define B_BE_RXDMA_ERR_FLAG_IDCT BIT(5) +#define B_BE_SET_FC_ERROR_FLAG_IDCT BIT(4) +#define B_BE__TXBD_LEN0_ERR_IDCT BIT(3) +#define B_BE__TXBD_4KBOUND_ERR_IDCT BIT(2) +#define B_BE_RXMDA_STUCK_IDCT BIT(1) +#define B_BE_TXMDA_STUCK_IDCT BIT(0) + +#define R_BE_HCI_FC_CTRL 0xB700 +#define B_BE_WD_PAGE_MODE_MASK GENMASK(17, 16) +#define B_BE_HCI_FC_CH14_FULL_COND_MASK GENMASK(15, 14) +#define B_BE_HCI_FC_TWD_FULL_COND_MASK GENMASK(13, 12) +#define B_BE_HCI_FC_CH12_FULL_COND_MASK GENMASK(11, 10) +#define B_BE_HCI_FC_WP_CH811_FULL_COND_MASK GENMASK(9, 8) +#define B_BE_HCI_FC_WP_CH07_FULL_COND_MASK GENMASK(7, 6) +#define B_BE_HCI_FC_WD_FULL_COND_MASK GENMASK(5, 4) +#define B_BE_HCI_FC_CH12_EN BIT(3) +#define B_BE_HCI_FC_MODE_MASK GENMASK(2, 1) +#define B_BE_HCI_FC_EN BIT(0) + +#define R_BE_CH_PAGE_CTRL 0xB704 +#define B_BE_PREC_PAGE_CH12_V1_MASK GENMASK(21, 16) +#define B_BE_PREC_PAGE_CH011_V1_MASK GENMASK(5, 0) + +#define R_BE_PUB_PAGE_INFO3 0xB78C +#define B_BE_G1_AVAL_PG_MASK GENMASK(28, 16) +#define B_BE_G0_AVAL_PG_MASK GENMASK(12, 0) + +#define R_BE_PUB_PAGE_CTRL1 0xB790 +#define B_BE_PUBPG_G1_MASK GENMASK(28, 16) +#define B_BE_PUBPG_G0_MASK GENMASK(12, 0) + +#define R_BE_PUB_PAGE_CTRL2 0xB794 +#define B_BE_PUBPG_ALL_MASK GENMASK(12, 0) + +#define R_BE_PUB_PAGE_INFO1 0xB79C +#define B_BE_G1_USE_PG_MASK GENMASK(28, 16) +#define B_BE_G0_USE_PG_MASK GENMASK(12, 0) + +#define R_BE_PUB_PAGE_INFO2 0xB7A0 +#define B_BE_PUB_AVAL_PG_MASK GENMASK(12, 0) + +#define R_BE_WP_PAGE_CTRL1 0xB7A4 +#define B_BE_PREC_PAGE_WP_CH811_MASK GENMASK(24, 16) +#define B_BE_PREC_PAGE_WP_CH07_MASK GENMASK(8, 0) + +#define R_BE_WP_PAGE_CTRL2 0xB7A8 +#define B_BE_WP_THRD_MASK GENMASK(12, 0) + +#define R_BE_WP_PAGE_INFO1 0xB7AC +#define B_BE_WP_AVAL_PG_MASK GENMASK(28, 16) + +#define R_BE_CMAC_SHARE_FUNC_EN 0x0E000 +#define B_BE_CMAC_SHARE_CRPRT BIT(31) +#define B_BE_CMAC_SHARE_EN BIT(30) +#define B_BE_FORCE_BTCOEX_REG_GCKEN BIT(24) +#define B_BE_FORCE_CMAC_SHARE_COMMON_REG_GCKEN BIT(16) +#define B_BE_FORCE_CMAC_SHARE_REG_GCKEN BIT(15) +#define B_BE_RESPBA_EN BIT(2) +#define B_BE_ADDRSRCH_EN BIT(1) +#define B_BE_BTCOEX_EN BIT(0) + +#define R_BE_CMAC_SHARE_ACQCHK_CFG_0 0x0E010 +#define B_BE_ACQCHK_ERR_FLAG_MASK GENMASK(31, 24) +#define B_BE_R_ACQCHK_ENTRY_IDX_SEL_MASK GENMASK(7, 4) +#define B_BE_MACID_ACQ_GRP1_CLR_P BIT(3) +#define B_BE_MACID_ACQ_GRP0_CLR_P BIT(2) +#define B_BE_R_MACID_ACQ_CHK_EN BIT(0) + #define R_BE_CMAC_FUNC_EN 0x10000 #define R_BE_CMAC_FUNC_EN_C1 0x14000 #define B_BE_CMAC_CRPRT BIT(31) @@ -3789,6 +5854,138 @@ B_BE_CMAC_CRPRT | B_BE_TXTIME_EN | B_BE_RESP_PKTCTL_EN | \ B_BE_SIGB_EN) +#define R_BE_CK_EN 0x10004 +#define R_BE_CK_EN_C1 0x14004 +#define B_BE_CMAC_CKEN BIT(30) +#define B_BE_BCN_P1_P4_CKEN BIT(15) +#define B_BE_BCN_P0MB1_15_CKEN BIT(14) +#define B_BE_TXTIME_CKEN BIT(8) +#define B_BE_RESP_PKTCTL_CKEN BIT(7) +#define B_BE_SIGB_CKEN BIT(6) +#define B_BE_PHYINTF_CKEN BIT(5) +#define B_BE_CMAC_DMA_CKEN BIT(4) +#define B_BE_PTCLTOP_CKEN BIT(3) +#define B_BE_SCHEDULER_CKEN BIT(2) +#define B_BE_TMAC_CKEN BIT(1) +#define B_BE_RMAC_CKEN BIT(0) +#define B_BE_CK_EN_SET (B_BE_CMAC_CKEN | B_BE_PHYINTF_CKEN | B_BE_CMAC_DMA_CKEN | \ + B_BE_PTCLTOP_CKEN | B_BE_SCHEDULER_CKEN | B_BE_TMAC_CKEN | \ + B_BE_RMAC_CKEN | B_BE_TXTIME_CKEN | B_BE_RESP_PKTCTL_CKEN | \ + B_BE_SIGB_CKEN) + +#define R_BE_TX_SUB_BAND_VALUE 0x10088 +#define R_BE_TX_SUB_BAND_VALUE_C1 0x14088 +#define B_BE_PRI20_BITMAP_MASK GENMASK(31, 16) +#define BE_PRI20_BITMAP_MAX 15 +#define B_BE_TXSB_160M_MASK GENMASK(15, 12) +#define S_BE_TXSB_160M_0 0 +#define S_BE_TXSB_160M_1 1 +#define B_BE_TXSB_80M_MASK GENMASK(11, 8) +#define S_BE_TXSB_80M_0 0 +#define S_BE_TXSB_80M_2 2 +#define S_BE_TXSB_80M_4 4 +#define B_BE_TXSB_40M_MASK GENMASK(7, 4) +#define S_BE_TXSB_40M_0 0 +#define S_BE_TXSB_40M_1 1 +#define S_BE_TXSB_40M_4 4 +#define B_BE_TXSB_20M_MASK GENMASK(3, 0) +#define S_BE_TXSB_20M_8 8 +#define S_BE_TXSB_20M_4 4 +#define S_BE_TXSB_20M_2 2 + +#define R_BE_PTCL_RRSR0 0x1008C +#define R_BE_PTCL_RRSR0_C1 0x1408C +#define B_BE_RRSR_HE_MASK GENMASK(31, 24) +#define B_BE_RRSR_VHT_MASK GENMASK(23, 16) +#define B_BE_RRSR_HT_MASK GENMASK(15, 8) +#define B_BE_RRSR_OFDM_MASK GENMASK(7, 0) + +#define R_BE_PTCL_RRSR1 0x10090 +#define R_BE_PTCL_RRSR1_C1 0x14090 +#define B_BE_RRSR_EHT_MASK GENMASK(23, 16) +#define B_BE_RRSR_RATE_EN_MASK GENMASK(12, 8) +#define B_BE_RSC_MASK GENMASK(7, 6) +#define B_BE_RRSR_CCK_MASK GENMASK(3, 0) + +#define R_BE_CMAC_ERR_IMR 0x10160 +#define R_BE_CMAC_ERR_IMR_C1 0x14160 +#define B_BE_CMAC_FW_ERR_IDCT_EN BIT(16) +#define B_BE_PTCL_TX_IDLETO_IDCT_EN BIT(9) +#define B_BE_WMAC_RX_IDLETO_IDCT_EN BIT(8) +#define B_BE_WMAC_TX_ERR_IND_EN BIT(7) +#define B_BE_WMAC_RX_ERR_IND_EN BIT(6) +#define B_BE_TXPWR_CTRL_ERR_IND_EN BIT(5) +#define B_BE_PHYINTF_ERR_IND_EN BIT(4) +#define B_BE_DMA_TOP_ERR_IND_EN BIT(3) +#define B_BE_RESP_PKTCTL_ERR_IND_EN BIT(2) +#define B_BE_PTCL_TOP_ERR_IND_EN BIT(1) +#define B_BE_SCHEDULE_TOP_ERR_IND_EN BIT(0) + +#define R_BE_CMAC_ERR_ISR 0x10164 +#define R_BE_CMAC_ERR_ISR_C1 0x14164 +#define B_BE_CMAC_FW_ERR_IDCT BIT(16) +#define B_BE_PTCL_TX_IDLETO_IDCT BIT(9) +#define B_BE_WMAC_RX_IDLETO_IDCT BIT(8) +#define B_BE_WMAC_TX_ERR_IND BIT(7) +#define B_BE_WMAC_RX_ERR_IND BIT(6) +#define B_BE_TXPWR_CTRL_ERR_IND BIT(5) +#define B_BE_PHYINTF_ERR_IND BIT(4) +#define B_BE_DMA_TOP_ERR_IND BIT(3) +#define B_BE_RESP_PKTCTL_ERR_IDCT BIT(2) +#define B_BE_PTCL_TOP_ERR_IND BIT(1) +#define B_BE_SCHEDULE_TOP_ERR_IND BIT(0) + +#define R_BE_SER_L0_DBG_CNT 0x10170 +#define R_BE_SER_L0_DBG_CNT_C1 0x14170 +#define B_BE_SER_L0_PHYINTF_CNT_MASK GENMASK(31, 24) +#define B_BE_SER_L0_DMA_CNT_MASK GENMASK(23, 16) +#define B_BE_SER_L0_PTCL_CNT_MASK GENMASK(15, 8) +#define B_BE_SER_L0_SCH_CNT_MASK GENMASK(7, 0) + +#define R_BE_SER_L0_DBG_CNT1 0x10174 +#define R_BE_SER_L0_DBG_CNT1_C1 0x14174 +#define B_BE_SER_L0_TMAC_COUNTER_MASK GENMASK(23, 16) +#define B_BE_SER_L0_RMAC_COUNTER_MASK GENMASK(15, 8) +#define B_BE_SER_L0_TXPWR_COUNTER_MASK GENMASK(7, 0) + +#define R_BE_SER_L0_DBG_CNT2 0x10178 +#define R_BE_SER_L0_DBG_CNT2_C1 0x14178 + +#define R_BE_SER_L0_DBG_CNT3 0x1017C +#define R_BE_SER_L0_DBG_CNT3_C1 0x1417C +#define B_BE_SER_L0_SUBMODULE_BIT31_CNT BIT(31) +#define B_BE_SER_L0_SUBMODULE_BIT30_CNT BIT(30) +#define B_BE_SER_L0_SUBMODULE_BIT29_CNT BIT(29) +#define B_BE_SER_L0_SUBMODULE_BIT28_CNT BIT(28) +#define B_BE_SER_L0_SUBMODULE_BIT27_CNT BIT(27) +#define B_BE_SER_L0_SUBMODULE_BIT26_CNT BIT(26) +#define B_BE_SER_L0_SUBMODULE_BIT25_CNT BIT(25) +#define B_BE_SER_L0_SUBMODULE_BIT24_CNT BIT(24) +#define B_BE_SER_L0_SUBMODULE_BIT23_CNT BIT(23) +#define B_BE_SER_L0_SUBMODULE_BIT22_CNT BIT(22) +#define B_BE_SER_L0_SUBMODULE_BIT21_CNT BIT(21) +#define B_BE_SER_L0_SUBMODULE_BIT20_CNT BIT(20) +#define B_BE_SER_L0_SUBMODULE_BIT19_CNT BIT(19) +#define B_BE_SER_L0_SUBMODULE_BIT18_CNT BIT(18) +#define B_BE_SER_L0_SUBMODULE_BIT17_CNT BIT(17) +#define B_BE_SER_L0_SUBMODULE_BIT16_CNT BIT(16) +#define B_BE_SER_L0_SUBMODULE_BIT15_CNT BIT(15) +#define B_BE_SER_L0_SUBMODULE_BIT14_CNT BIT(14) +#define B_BE_SER_L0_SUBMODULE_BIT13_CNT BIT(13) +#define B_BE_SER_L0_SUBMODULE_BIT12_CNT BIT(12) +#define B_BE_SER_L0_SUBMODULE_BIT11_CNT BIT(11) +#define B_BE_SER_L0_SUBMODULE_BIT10_CNT BIT(10) +#define B_BE_SER_L0_SUBMODULE_BIT9_CNT BIT(9) +#define B_BE_SER_L0_SUBMODULE_BIT8_CNT BIT(8) +#define B_BE_SER_L0_SUBMODULE_BIT7_CNT BIT(7) +#define B_BE_SER_L0_SUBMODULE_BIT6_CNT BIT(6) +#define B_BE_SER_L0_SUBMODULE_BIT5_CNT BIT(5) +#define B_BE_SER_L0_SUBMODULE_BIT4_CNT BIT(4) +#define B_BE_SER_L0_SUBMODULE_BIT3_CNT BIT(3) +#define B_BE_SER_L0_SUBMODULE_BIT2_CNT BIT(2) +#define B_BE_SER_L0_SUBMODULE_BIT1_CNT BIT(1) +#define B_BE_SER_L0_SUBMODULE_BIT0_CNT BIT(0) + #define R_BE_PORT_0_TSF_SYNC 0x102A0 #define R_BE_PORT_0_TSF_SYNC_C1 0x142A0 #define B_BE_P0_SYNC_NOW_P BIT(30) @@ -3797,6 +5994,55 @@ #define B_BE_P0_SYNC_PORT_SRC_SEL_MASK GENMASK(26, 24) #define B_BE_P0_TSFTR_SYNC_OFFSET_MASK GENMASK(18, 0) +#define R_BE_EDCA_BCNQ_PARAM 0x10324 +#define R_BE_EDCA_BCNQ_PARAM_C1 0x14324 +#define B_BE_BCNQ_CW_MASK GENMASK(31, 24) +#define B_BE_BCNQ_AIFS_MASK GENMASK(23, 16) +#define BCN_IFS_25US 0x19 +#define B_BE_PIFS_MASK GENMASK(15, 8) +#define B_BE_FORCE_BCN_IFS_MASK GENMASK(7, 0) + +#define R_BE_PREBKF_CFG_0 0x10338 +#define R_BE_PREBKF_CFG_0_C1 0x14338 +#define B_BE_100NS_TIME_MASK GENMASK(28, 24) +#define B_BE_RX_AIR_END_TIME_MASK GENMASK(22, 16) +#define B_BE_MACTX_LATENCY_MASK GENMASK(10, 8) +#define B_BE_PREBKF_TIME_MASK GENMASK(4, 0) + +#define R_BE_CCA_CFG_0 0x10340 +#define R_BE_CCA_CFG_0_C1 0x14340 +#define B_BE_R_SIFS_AGGR_TIME_V1_MASK GENMASK(31, 24) +#define B_BE_EDCCA_SEC160_EN BIT(23) +#define B_BE_EDCCA_SEC80_EN BIT(22) +#define B_BE_EDCCA_SEC40_EN BIT(21) +#define B_BE_EDCCA_SEC20_EN BIT(20) +#define B_BE_SEC160_EN BIT(19) +#define B_BE_CCA_BITMAP_EN BIT(18) +#define B_BE_TXPKTCTL_RST_EDCA_EN BIT(17) +#define B_BE_WMAC_RST_EDCA_EN BIT(16) +#define B_BE_TXFAIL_BRK_TXOP_EN BIT(11) +#define B_BE_EDCCA_PER20_BITMAP_SIFS_EN BIT(10) +#define B_BE_NO_GNT_WL_BRK_TXOP_EN BIT(9) +#define B_BE_NAV_BRK_TXOP_EN BIT(8) +#define B_BE_TX_NAV_EN BIT(7) +#define B_BE_BCN_IGNORE_EDCCA BIT(6) +#define B_BE_NO_GNT_WL_EN BIT(5) +#define B_BE_EDCCA_EN BIT(4) +#define B_BE_SEC80_EN BIT(3) +#define B_BE_SEC40_EN BIT(2) +#define B_BE_SEC20_EN BIT(1) +#define B_BE_CCA_EN BIT(0) + +#define R_BE_CTN_CFG_0 0x1034C +#define R_BE_CTN_CFG_0_C1 0x1434C +#define B_BE_OTHER_LINK_BKF_BLK_TX_THD_MASK GENMASK(30, 24) +#define B_BE_CCK_SIFS_COMP_MASK GENMASK(22, 16) +#define B_BE_PIFS_TIMEUNIT_MASK GENMASK(15, 14) +#define B_BE_PREBKF_TIME_NONAC_MASK GENMASK(12, 8) +#define B_BE_SR_TX_EN BIT(2) +#define B_BE_NAV_BLK_MGQ BIT(1) +#define B_BE_NAV_BLK_HGQ BIT(0) + #define R_BE_MUEDCA_BE_PARAM_0 0x10350 #define R_BE_MUEDCA_BK_PARAM_0 0x10354 #define R_BE_MUEDCA_VI_PARAM_0 0x10358 @@ -3809,6 +6055,74 @@ #define B_BE_SET_MUEDCATIMER_TF_0 BIT(4) #define B_BE_MUEDCA_EN_0 BIT(0) +#define R_BE_TB_CHK_CCA_NAV 0x103AC +#define R_BE_TB_CHK_CCA_NAV_C1 0x143AC +#define B_BE_TB_CHK_TX_NAV BIT(15) +#define B_BE_TB_CHK_INTRA_NAV BIT(14) +#define B_BE_TB_CHK_BASIC_NAV BIT(13) +#define B_BE_TB_CHK_NO_GNT_WL BIT(12) +#define B_BE_TB_CHK_EDCCA_S160 BIT(11) +#define B_BE_TB_CHK_EDCCA_S80 BIT(10) +#define B_BE_TB_CHK_EDCCA_S40 BIT(9) +#define B_BE_TB_CHK_EDCCA_S20 BIT(8) +#define B_BE_TB_CHK_CCA_S160 BIT(7) +#define B_BE_TB_CHK_CCA_S80 BIT(6) +#define B_BE_TB_CHK_CCA_S40 BIT(5) +#define B_BE_TB_CHK_CCA_S20 BIT(4) +#define B_BE_TB_CHK_EDCCA_BITMAP BIT(3) +#define B_BE_TB_CHK_CCA_BITMAP BIT(2) +#define B_BE_TB_CHK_EDCCA_P20 BIT(1) +#define B_BE_TB_CHK_CCA_P20 BIT(0) + +#define R_BE_HE_SIFS_CHK_CCA_NAV 0x103B4 +#define R_BE_HE_SIFS_CHK_CCA_NAV_C1 0x143B4 +#define B_BE_HE_SIFS_CHK_TX_NAV BIT(15) +#define B_BE_HE_SIFS_CHK_INTRA_NAV BIT(14) +#define B_BE_HE_SIFS_CHK_BASIC_NAV BIT(13) +#define B_BE_HE_SIFS_CHK_NO_GNT_WL BIT(12) +#define B_BE_HE_SIFS_CHK_EDCCA_S160 BIT(11) +#define B_BE_HE_SIFS_CHK_EDCCA_S80 BIT(10) +#define B_BE_HE_SIFS_CHK_EDCCA_S40 BIT(9) +#define B_BE_HE_SIFS_CHK_EDCCA_S20 BIT(8) +#define B_BE_HE_SIFS_CHK_CCA_S160 BIT(7) +#define B_BE_HE_SIFS_CHK_CCA_S80 BIT(6) +#define B_BE_HE_SIFS_CHK_CCA_S40 BIT(5) +#define B_BE_HE_SIFS_CHK_CCA_S20 BIT(4) +#define B_BE_HE_SIFS_CHK_EDCCA_BITMAP BIT(3) +#define B_BE_HE_SIFS_CHK_CCA_BITMAP BIT(2) +#define B_BE_HE_SIFS_CHK_EDCCA_P20 BIT(1) +#define B_BE_HE_SIFS_CHK_CCA_P20 BIT(0) + +#define R_BE_HE_CTN_CHK_CCA_NAV 0x103C4 +#define R_BE_HE_CTN_CHK_CCA_NAV_C1 0x143C4 +#define B_BE_HE_CTN_CHK_TX_NAV BIT(15) +#define B_BE_HE_CTN_CHK_INTRA_NAV BIT(14) +#define B_BE_HE_CTN_CHK_BASIC_NAV BIT(13) +#define B_BE_HE_CTN_CHK_NO_GNT_WL BIT(12) +#define B_BE_HE_CTN_CHK_EDCCA_S160 BIT(11) +#define B_BE_HE_CTN_CHK_EDCCA_S80 BIT(10) +#define B_BE_HE_CTN_CHK_EDCCA_S40 BIT(9) +#define B_BE_HE_CTN_CHK_EDCCA_S20 BIT(8) +#define B_BE_HE_CTN_CHK_CCA_S160 BIT(7) +#define B_BE_HE_CTN_CHK_CCA_S80 BIT(6) +#define B_BE_HE_CTN_CHK_CCA_S40 BIT(5) +#define B_BE_HE_CTN_CHK_CCA_S20 BIT(4) +#define B_BE_HE_CTN_CHK_EDCCA_BITMAP BIT(3) +#define B_BE_HE_CTN_CHK_CCA_BITMAP BIT(2) +#define B_BE_HE_CTN_CHK_EDCCA_P20 BIT(1) +#define B_BE_HE_CTN_CHK_CCA_P20 BIT(0) + +#define R_BE_SCHEDULE_ERR_IMR 0x103E8 +#define R_BE_SCHEDULE_ERR_IMR_C1 0x143E8 +#define B_BE_FSM_TIMEOUT_ERR_INT_EN BIT(0) +#define B_BE_SCHEDULE_ERR_IMR_CLR B_BE_FSM_TIMEOUT_ERR_INT_EN +#define B_BE_SCHEDULE_ERR_IMR_SET B_BE_FSM_TIMEOUT_ERR_INT_EN + +#define R_BE_SCHEDULE_ERR_ISR 0x103EC +#define R_BE_SCHEDULE_ERR_ISR_C1 0x143EC +#define B_BE_SORT_NON_IDLE_ERR_INT BIT(1) +#define B_BE_FSM_TIMEOUT_ERR_INT BIT(0) + #define R_BE_PORT_CFG_P0 0x10400 #define R_BE_PORT_CFG_P0_C1 0x14400 #define B_BE_BCN_ERLY_SORT_EN_P0 BIT(18) @@ -3923,12 +6237,51 @@ #define R_BE_PORT_HGQ_WINDOW_CFG 0x105A0 #define R_BE_PORT_HGQ_WINDOW_CFG_C1 0x145A0 +#define R_BE_PTCL_COMMON_SETTING_0 0x10800 +#define R_BE_PTCL_COMMON_SETTING_0_C1 0x14800 +#define B_BE_PCIE_MODE_MASK GENMASK(15, 14) +#define B_BE_CPUMGQ_LIFETIME_EN BIT(8) +#define B_BE_MGQ_LIFETIME_EN BIT(7) +#define B_BE_LIFETIME_EN BIT(6) +#define B_BE_DIS_PTCL_CLK_GATING BIT(5) +#define B_BE_PTCL_TRIGGER_SS_EN_UL BIT(4) +#define B_BE_PTCL_TRIGGER_SS_EN_1 BIT(3) +#define B_BE_PTCL_TRIGGER_SS_EN_0 BIT(2) +#define B_BE_CMAC_TX_MODE_1 BIT(1) +#define B_BE_CMAC_TX_MODE_0 BIT(0) + +#define R_BE_TB_PPDU_CTRL 0x1080C +#define R_BE_TB_PPDU_CTRL_C1 0x1480C +#define B_BE_TB_PPDU_BK_DIS BIT(15) +#define B_BE_TB_PPDU_BE_DIS BIT(14) +#define B_BE_TB_PPDU_VI_DIS BIT(13) +#define B_BE_TB_PPDU_VO_DIS BIT(12) +#define B_BE_QOSNULL_UPD_MUEDCA_EN BIT(3) +#define B_BE_TB_BYPASS_TXPWR BIT(2) +#define B_BE_SW_PREFER_AC_MASK GENMASK(1, 0) + +#define R_BE_AMPDU_AGG_LIMIT 0x10810 +#define R_BE_AMPDU_AGG_LIMIT_C1 0x14810 +#define B_BE_AMPDU_MAX_TIME_MASK GENMASK(31, 24) +#define AMPDU_MAX_TIME 0x9E +#define B_BE_RA_TRY_RATE_AGG_LMT_MASK GENMASK(23, 16) +#define B_BE_RTS_MAX_AGG_NUM_MASK GENMASK(15, 8) +#define B_BE_MAX_AGG_NUM_MASK GENMASK(7, 0) + #define R_BE_AGG_LEN_HT_0 0x10814 #define R_BE_AGG_LEN_HT_0_C1 0x14814 #define B_BE_AMPDU_MAX_LEN_HT_MASK GENMASK(31, 16) #define B_BE_RTS_TXTIME_TH_MASK GENMASK(15, 8) #define B_BE_RTS_LEN_TH_MASK GENMASK(7, 0) +#define R_BE_SIFS_SETTING 0x10824 +#define R_BE_SIFS_SETTING_C1 0x14824 +#define B_BE_HW_CTS2SELF_PKT_LEN_TH_MASK GENMASK(31, 24) +#define B_BE_HW_CTS2SELF_PKT_LEN_TH_TWW_MASK GENMASK(23, 18) +#define B_BE_HW_CTS2SELF_EN BIT(16) +#define B_BE_SPEC_SIFS_OFDM_PTCL_MASK GENMASK(15, 8) +#define B_BE_SPEC_SIFS_CCK_PTCL_MASK GENMASK(7, 0) + #define R_BE_MBSSID_DROP_0 0x1083C #define R_BE_MBSSID_DROP_0_C1 0x1483C #define B_BE_GI_LTF_FB_SEL BIT(30) @@ -3947,6 +6300,375 @@ #define R_BE_PTCL_BSS_COLOR_1_C1 0x148A4 #define B_BE_BSS_COLOB_BE_PORT_4_MASK GENMASK(5, 0) +#define R_BE_PTCL_IMR_2 0x108B8 +#define R_BE_PTCL_IMR_2_C1 0x148B8 +#define B_BE_NO_TRX_TIMEOUT_IMR BIT(1) +#define B_BE_TX_IDLE_TIMEOUT_IMR BIT(0) +#define B_BE_PTCL_IMR_2_CLR B_BE_TX_IDLE_TIMEOUT_IMR +#define B_BE_PTCL_IMR_2_SET 0 + +#define R_BE_PTCL_IMR0 0x108C0 +#define R_BE_PTCL_IMR0_C1 0x148C0 +#define B_BE_PTCL_ERROR_FLAG_IMR BIT(31) +#define B_BE_FSM1_TIMEOUT_ERR_INT_EN BIT(1) +#define B_BE_FSM_TIMEOUT_ERR_INT_EN BIT(0) +#define B_BE_PTCL_IMR0_CLR (B_BE_FSM_TIMEOUT_ERR_INT_EN | \ + B_BE_FSM1_TIMEOUT_ERR_INT_EN | \ + B_BE_PTCL_ERROR_FLAG_IMR) +#define B_BE_PTCL_IMR0_SET (B_BE_FSM_TIMEOUT_ERR_INT_EN | \ + B_BE_FSM1_TIMEOUT_ERR_INT_EN | \ + B_BE_PTCL_ERROR_FLAG_IMR) + +#define R_BE_PTCL_ISR0 0x108C4 +#define R_BE_PTCL_ISR0_C1 0x148C4 +#define B_BE_PTCL_ERROR_FLAG_ISR BIT(31) +#define B_BE_FSM1_TIMEOUT_ERR BIT(1) +#define B_BE_FSM_TIMEOUT_ERR BIT(0) + +#define R_BE_PTCL_IMR1 0x108C8 +#define R_BE_PTCL_IMR1_C1 0x148C8 +#define B_BE_F2PCMD_PKTID_IMR BIT(30) +#define B_BE_F2PCMD_RD_PKTID_IMR BIT(29) +#define B_BE_F2PCMD_ASSIGN_PKTID_IMR BIT(28) +#define B_BE_F2PCMD_USER_ALLC_IMR BIT(27) +#define B_BE_RX_SPF_U0_PKTID_IMR BIT(26) +#define B_BE_TX_SPF_U1_PKTID_IMR BIT(25) +#define B_BE_TX_SPF_U2_PKTID_IMR BIT(24) +#define B_BE_TX_SPF_U3_PKTID_IMR BIT(23) +#define B_BE_TX_RECORD_PKTID_IMR BIT(22) +#define B_BE_TWTSP_QSEL_IMR BIT(14) +#define B_BE_F2P_RLS_CTN_SEL_IMR BIT(13) +#define B_BE_BCNQ_ORDER_IMR BIT(12) +#define B_BE_Q_PKTID_IMR BIT(11) +#define B_BE_D_PKTID_IMR BIT(10) +#define B_BE_TXPRT_FULL_DROP_IMR BIT(9) +#define B_BE_F2PCMDRPT_FULL_DROP_IMR BIT(8) +#define B_BE_PTCL_IMR1_CLR (B_BE_F2PCMDRPT_FULL_DROP_IMR | \ + B_BE_TXPRT_FULL_DROP_IMR | \ + B_BE_D_PKTID_IMR | \ + B_BE_Q_PKTID_IMR | \ + B_BE_BCNQ_ORDER_IMR | \ + B_BE_F2P_RLS_CTN_SEL_IMR | \ + B_BE_TWTSP_QSEL_IMR | \ + B_BE_TX_RECORD_PKTID_IMR | \ + B_BE_TX_SPF_U3_PKTID_IMR | \ + B_BE_TX_SPF_U2_PKTID_IMR | \ + B_BE_TX_SPF_U1_PKTID_IMR | \ + B_BE_RX_SPF_U0_PKTID_IMR | \ + B_BE_F2PCMD_USER_ALLC_IMR | \ + B_BE_F2PCMD_ASSIGN_PKTID_IMR | \ + B_BE_F2PCMD_RD_PKTID_IMR | \ + B_BE_F2PCMD_PKTID_IMR) +#define B_BE_PTCL_IMR1_SET B_BE_F2PCMD_USER_ALLC_IMR + +#define R_BE_PTCL_ISR1 0x108CC +#define R_BE_PTCL_ISR1_C1 0x148CC +#define B_BE_F2PCMD_PKTID_ERR BIT(30) +#define B_BE_F2PCMD_RD_PKTID_ERR BIT(29) +#define B_BE_F2PCMD_ASSIGN_PKTID_ERR BIT(28) +#define B_BE_F2PCMD_USER_ALLC_ERR BIT(27) +#define B_BE_RX_SPF_U0_PKTID_ERR BIT(26) +#define B_BE_TX_SPF_U1_PKTID_ERR BIT(25) +#define B_BE_TX_SPF_U2_PKTID_ERR BIT(24) +#define B_BE_TX_SPF_U3_PKTID_ERR BIT(23) +#define B_BE_TX_RECORD_PKTID_ERR BIT(22) +#define B_BE_TWTSP_QSEL_ERR BIT(14) +#define B_BE_F2P_RLS_CTN_SEL_ERR BIT(13) +#define B_BE_BCNQ_ORDER_ERR BIT(12) +#define B_BE_Q_PKTID_ERR BIT(11) +#define B_BE_D_PKTID_ERR BIT(10) +#define B_BE_TXPRT_FULL_DROP_ERR BIT(9) +#define B_BE_F2PCMDRPT_FULL_DROP_ERR BIT(8) + +#define R_BE_PTCL_FSM_MON 0x108E8 +#define R_BE_PTCL_FSM_MON_C1 0x148E8 +#define B_BE_PTCL_FSM2_TO_MODE BIT(30) +#define B_BE_PTCL_FSM2_TO_THR_MASK GENMASK(29, 24) +#define B_BE_PTCL_FSM1_TO_MODE BIT(22) +#define B_BE_PTCL_FSM1_TO_THR_MASK GENMASK(21, 16) +#define B_BE_PTCL_FSM0_TO_MODE BIT(14) +#define B_BE_PTCL_FSM0_TO_THR_MASK GENMASK(13, 8) +#define B_BE_PTCL_TX_ARB_TO_MODE BIT(6) +#define B_BE_PTCL_TX_ARB_TO_THR_MASK GENMASK(5, 0) + +#define R_BE_PTCL_TX_CTN_SEL 0x108EC +#define R_BE_PTCL_TX_CTN_SEL_C1 0x148EC +#define B_BE_PTCL_TXOP_STAT BIT(8) +#define B_BE_PTCL_BUSY BIT(7) +#define B_BE_PTCL_DROP BIT(5) +#define B_BE_PTCL_TX_QUEUE_IDX_MASK GENMASK(4, 0) + +#define R_BE_RX_ERROR_FLAG 0x10C00 +#define R_BE_RX_ERROR_FLAG_C1 0x14C00 +#define B_BE_RX_CSI_NOT_RELEASE_ERROR BIT(31) +#define B_BE_RX_GET_NULL_PKT_ERROR BIT(30) +#define B_BE_RX_RU0_FSM_HANG_ERROR BIT(29) +#define B_BE_RX_RU1_FSM_HANG_ERROR BIT(28) +#define B_BE_RX_RU2_FSM_HANG_ERROR BIT(27) +#define B_BE_RX_RU3_FSM_HANG_ERROR BIT(26) +#define B_BE_RX_RU4_FSM_HANG_ERROR BIT(25) +#define B_BE_RX_RU5_FSM_HANG_ERROR BIT(24) +#define B_BE_RX_RU6_FSM_HANG_ERROR BIT(23) +#define B_BE_RX_RU7_FSM_HANG_ERROR BIT(22) +#define B_BE_RX_RXSTS_FSM_HANG_ERROR BIT(21) +#define B_BE_RX_CSI_FSM_HANG_ERROR BIT(20) +#define B_BE_RX_TXRPT_FSM_HANG_ERROR BIT(19) +#define B_BE_RX_F2PCMD_FSM_HANG_ERROR BIT(18) +#define B_BE_RX_RU0_ZERO_LENGTH_ERROR BIT(17) +#define B_BE_RX_RU1_ZERO_LENGTH_ERROR BIT(16) +#define B_BE_RX_RU2_ZERO_LENGTH_ERROR BIT(15) +#define B_BE_RX_RU3_ZERO_LENGTH_ERROR BIT(14) +#define B_BE_RX_RU4_ZERO_LENGTH_ERROR BIT(13) +#define B_BE_RX_RU5_ZERO_LENGTH_ERROR BIT(12) +#define B_BE_RX_RU6_ZERO_LENGTH_ERROR BIT(11) +#define B_BE_RX_RU7_ZERO_LENGTH_ERROR BIT(10) +#define B_BE_RX_RXSTS_ZERO_LENGTH_ERROR BIT(9) +#define B_BE_RX_CSI_ZERO_LENGTH_ERROR BIT(8) +#define B_BE_PLE_DATA_OPT_FSM_HANG BIT(7) +#define B_BE_PLE_RXDATA_REQUEST_BUFFER_FSM_HANG BIT(6) +#define B_BE_PLE_TXRPT_REQUEST_BUFFER_FSM_HANG BIT(5) +#define B_BE_PLE_WD_OPT_FSM_HANG BIT(4) +#define B_BE_PLE_ENQ_FSM_HANG BIT(3) +#define B_BE_RXDATA_ENQUE_ORDER_ERROR BIT(2) +#define B_BE_RXSTS_ENQUE_ORDER_ERROR BIT(1) +#define B_BE_RX_CSI_PKT_NUM_ERROR BIT(0) + +#define R_BE_RX_ERROR_FLAG_IMR 0x10C04 +#define R_BE_RX_ERROR_FLAG_IMR_C1 0x14C04 +#define B_BE_RX_CSI_NOT_RELEASE_ERROR_IMR BIT(31) +#define B_BE_RX_GET_NULL_PKT_ERROR_IMR BIT(30) +#define B_BE_RX_RU0_FSM_HANG_ERROR_IMR BIT(29) +#define B_BE_RX_RU1_FSM_HANG_ERROR_IMR BIT(28) +#define B_BE_RX_RU2_FSM_HANG_ERROR_IMR BIT(27) +#define B_BE_RX_RU3_FSM_HANG_ERROR_IMR BIT(26) +#define B_BE_RX_RU4_FSM_HANG_ERROR_IMR BIT(25) +#define B_BE_RX_RU5_FSM_HANG_ERROR_IMR BIT(24) +#define B_BE_RX_RU6_FSM_HANG_ERROR_IMR BIT(23) +#define B_BE_RX_RU7_FSM_HANG_ERROR_IMR BIT(22) +#define B_BE_RX_RXSTS_FSM_HANG_ERROR_IMR BIT(21) +#define B_BE_RX_CSI_FSM_HANG_ERROR_IMR BIT(20) +#define B_BE_RX_TXRPT_FSM_HANG_ERROR_IMR BIT(19) +#define B_BE_RX_F2PCMD_FSM_HANG_ERROR_IMR BIT(18) +#define B_BE_RX_RU0_ZERO_LENGTH_ERROR_IMR BIT(17) +#define B_BE_RX_RU1_ZERO_LENGTH_ERROR_IMR BIT(16) +#define B_BE_RX_RU2_ZERO_LENGTH_ERROR_IMR BIT(15) +#define B_BE_RX_RU3_ZERO_LENGTH_ERROR_IMR BIT(14) +#define B_BE_RX_RU4_ZERO_LENGTH_ERROR_IMR BIT(13) +#define B_BE_RX_RU5_ZERO_LENGTH_ERROR_IMR BIT(12) +#define B_BE_RX_RU6_ZERO_LENGTH_ERROR_IMR BIT(11) +#define B_BE_RX_RU7_ZERO_LENGTH_ERROR_IMR BIT(10) +#define B_BE_RX_RXSTS_ZERO_LENGTH_ERROR_IMR BIT(9) +#define B_BE_RX_CSI_ZERO_LENGTH_ERROR_IMR BIT(8) +#define B_BE_PLE_DATA_OPT_FSM_HANG_IMR BIT(7) +#define B_BE_PLE_RXDATA_REQUEST_BUFFER_FSM_HANG_IMR BIT(6) +#define B_BE_PLE_TXRPT_REQUEST_BUFFER_FSM_HANG_IMR BIT(5) +#define B_BE_PLE_WD_OPT_FSM_HANG_IMR BIT(4) +#define B_BE_PLE_ENQ_FSM_HANG_IMR BIT(3) +#define B_BE_RXDATA_ENQUE_ORDER_ERROR_IMR BIT(2) +#define B_BE_RXSTS_ENQUE_ORDER_ERROR_IMR BIT(1) +#define B_BE_RX_CSI_PKT_NUM_ERROR_IMR BIT(0) +#define B_BE_RX_ERROR_FLAG_IMR_CLR (B_BE_RX_RXSTS_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU7_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU6_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU5_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU4_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU3_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU2_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU1_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU0_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_F2PCMD_FSM_HANG_ERROR_IMR | \ + B_BE_RX_TXRPT_FSM_HANG_ERROR_IMR | \ + B_BE_RX_CSI_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RXSTS_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU7_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU6_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU5_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU4_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU3_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU2_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU1_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU0_FSM_HANG_ERROR_IMR | \ + B_BE_RX_GET_NULL_PKT_ERROR_IMR) +#define B_BE_RX_ERROR_FLAG_IMR_SET (B_BE_RX_RXSTS_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU7_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU6_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU5_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU4_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU3_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU2_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU1_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU0_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_F2PCMD_FSM_HANG_ERROR_IMR | \ + B_BE_RX_TXRPT_FSM_HANG_ERROR_IMR | \ + B_BE_RX_CSI_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RXSTS_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU7_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU6_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU5_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU4_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU3_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU2_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU1_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU0_FSM_HANG_ERROR_IMR | \ + B_BE_RX_GET_NULL_PKT_ERROR_IMR) + +#define R_BE_RX_CTRL_1 0x10C0C +#define R_BE_RX_CTRL_1_C1 0x14C0C +#define B_BE_RXDMA_TXRPT_QUEUE_ID_SW_MASK GENMASK(30, 25) +#define B_BE_RXDMA_F2PCMDRPT_QUEUE_ID_SW_MASK GENMASK(23, 18) +#define B_BE_RXDMA_TXRPT_PORT_ID_SW_MASK GENMASK(17, 14) +#define B_BE_RXDMA_F2PCMDRPT_PORT_ID_SW_MASK GENMASK(13, 10) +#define B_BE_DBG_SEL_MASK GENMASK(1, 0) +#define WLCPU_RXCH2_QID 0xA + +#define R_BE_TX_ERROR_FLAG 0x10C6C +#define R_BE_TX_ERROR_FLAG_C1 0x14C6C +#define B_BE_TX_RU0_FSM_HANG_ERROR BIT(31) +#define B_BE_TX_RU1_FSM_HANG_ERROR BIT(30) +#define B_BE_TX_RU2_FSM_HANG_ERROR BIT(29) +#define B_BE_TX_RU3_FSM_HANG_ERROR BIT(28) +#define B_BE_TX_RU4_FSM_HANG_ERROR BIT(27) +#define B_BE_TX_RU5_FSM_HANG_ERROR BIT(26) +#define B_BE_TX_RU6_FSM_HANG_ERROR BIT(25) +#define B_BE_TX_RU7_FSM_HANG_ERROR BIT(24) +#define B_BE_TX_RU8_FSM_HANG_ERROR BIT(23) +#define B_BE_TX_RU9_FSM_HANG_ERROR BIT(22) +#define B_BE_TX_RU10_FSM_HANG_ERROR BIT(21) +#define B_BE_TX_RU11_FSM_HANG_ERROR BIT(20) +#define B_BE_TX_RU12_FSM_HANG_ERROR BIT(19) +#define B_BE_TX_RU13_FSM_HANG_ERROR BIT(18) +#define B_BE_TX_RU14_FSM_HANG_ERROR BIT(17) +#define B_BE_TX_RU15_FSM_HANG_ERROR BIT(16) +#define B_BE_TX_CSI_FSM_HANG_ERROR BIT(15) +#define B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR BIT(14) + +#define R_BE_TX_ERROR_FLAG_IMR 0x10C70 +#define R_BE_TX_ERROR_FLAG_IMR_C1 0x14C70 +#define B_BE_TX_RU0_FSM_HANG_ERROR_IMR BIT(31) +#define B_BE_TX_RU1_FSM_HANG_ERROR_IMR BIT(30) +#define B_BE_TX_RU2_FSM_HANG_ERROR_IMR BIT(29) +#define B_BE_TX_RU3_FSM_HANG_ERROR_IMR BIT(28) +#define B_BE_TX_RU4_FSM_HANG_ERROR_IMR BIT(27) +#define B_BE_TX_RU5_FSM_HANG_ERROR_IMR BIT(26) +#define B_BE_TX_RU6_FSM_HANG_ERROR_IMR BIT(25) +#define B_BE_TX_RU7_FSM_HANG_ERROR_IMR BIT(24) +#define B_BE_TX_RU8_FSM_HANG_ERROR_IMR BIT(23) +#define B_BE_TX_RU9_FSM_HANG_ERROR_IMR BIT(22) +#define B_BE_TX_RU10_FSM_HANG_ERROR_IMR BIT(21) +#define B_BE_TX_RU11_FSM_HANG_ERROR_IMR BIT(20) +#define B_BE_TX_RU12_FSM_HANG_ERROR_IMR BIT(19) +#define B_BE_TX_RU13_FSM_HANG_ERROR_IMR BIT(18) +#define B_BE_TX_RU14_FSM_HANG_ERROR_IMR BIT(17) +#define B_BE_TX_RU15_FSM_HANG_ERROR_IMR BIT(16) +#define B_BE_TX_CSI_FSM_HANG_ERROR_IMR BIT(15) +#define B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR_IMR BIT(14) +#define B_BE_TX_ERROR_FLAG_IMR_CLR (B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR_IMR | \ + B_BE_TX_CSI_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU15_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU14_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU13_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU12_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU11_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU10_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU9_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU8_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU7_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU6_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU5_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU4_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU3_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU2_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU1_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU0_FSM_HANG_ERROR_IMR) +#define B_BE_TX_ERROR_FLAG_IMR_SET (B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR_IMR | \ + B_BE_TX_CSI_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU15_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU14_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU13_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU12_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU11_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU10_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU9_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU8_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU7_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU6_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU5_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU4_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU3_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU2_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU1_FSM_HANG_ERROR_IMR | \ + B_BE_TX_RU0_FSM_HANG_ERROR_IMR) + +#define R_BE_RX_ERROR_FLAG_1 0x10C84 +#define R_BE_RX_ERROR_FLAG_1_C1 0x14C84 +#define B_BE_RX_RU8_FSM_HANG_ERROR BIT(29) +#define B_BE_RX_RU9_FSM_HANG_ERROR BIT(28) +#define B_BE_RX_RU10_FSM_HANG_ERROR BIT(27) +#define B_BE_RX_RU11_FSM_HANG_ERROR BIT(26) +#define B_BE_RX_RU12_FSM_HANG_ERROR BIT(25) +#define B_BE_RX_RU13_FSM_HANG_ERROR BIT(24) +#define B_BE_RX_RU14_FSM_HANG_ERROR BIT(23) +#define B_BE_RX_RU15_FSM_HANG_ERROR BIT(22) +#define B_BE_RX_RU8_ZERO_LENGTH_ERROR BIT(17) +#define B_BE_RX_RU9_ZERO_LENGTH_ERROR BIT(16) +#define B_BE_RX_RU10_ZERO_LENGTH_ERROR BIT(15) +#define B_BE_RX_RU11_ZERO_LENGTH_ERROR BIT(14) +#define B_BE_RX_RU12_ZERO_LENGTH_ERROR BIT(13) +#define B_BE_RX_RU13_ZERO_LENGTH_ERROR BIT(12) +#define B_BE_RX_RU14_ZERO_LENGTH_ERROR BIT(11) +#define B_BE_RX_RU15_ZERO_LENGTH_ERROR BIT(10) + +#define R_BE_RX_ERROR_FLAG_IMR_1 0x10C88 +#define R_BE_RX_ERROR_FLAG_IMR_1_C1 0x14C88 +#define B_BE_RX_RU8_FSM_HANG_ERROR_IMR BIT(29) +#define B_BE_RX_RU9_FSM_HANG_ERROR_IMR BIT(28) +#define B_BE_RX_RU10_FSM_HANG_ERROR_IMR BIT(27) +#define B_BE_RX_RU11_FSM_HANG_ERROR_IMR BIT(26) +#define B_BE_RX_RU12_FSM_HANG_ERROR_IMR BIT(25) +#define B_BE_RX_RU13_FSM_HANG_ERROR_IMR BIT(24) +#define B_BE_RX_RU14_FSM_HANG_ERROR_IMR BIT(23) +#define B_BE_RX_RU15_FSM_HANG_ERROR_IMR BIT(22) +#define B_BE_RX_RU8_ZERO_LENGTH_ERROR_IMR BIT(17) +#define B_BE_RX_RU9_ZERO_LENGTH_ERROR_IMR BIT(16) +#define B_BE_RX_RU10_ZERO_LENGTH_ERROR_IMR BIT(15) +#define B_BE_RX_RU11_ZERO_LENGTH_ERROR_IMR BIT(14) +#define B_BE_RX_RU12_ZERO_LENGTH_ERROR_IMR BIT(13) +#define B_BE_RX_RU13_ZERO_LENGTH_ERROR_IMR BIT(12) +#define B_BE_RX_RU14_ZERO_LENGTH_ERROR_IMR BIT(11) +#define B_BE_RX_RU15_ZERO_LENGTH_ERROR_IMR BIT(10) +#define B_BE_TX_ERROR_FLAG_IMR_1_CLR (B_BE_RX_RU8_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU9_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU10_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU11_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU12_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU13_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU14_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU15_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU8_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU9_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU10_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU11_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU12_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU13_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU14_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU15_ZERO_LENGTH_ERROR_IMR) +#define B_BE_TX_ERROR_FLAG_IMR_1_SET (B_BE_RX_RU8_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU9_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU10_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU11_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU12_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU13_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU14_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU15_FSM_HANG_ERROR_IMR | \ + B_BE_RX_RU8_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU9_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU10_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU11_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU12_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU13_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU14_ZERO_LENGTH_ERROR_IMR | \ + B_BE_RX_RU15_ZERO_LENGTH_ERROR_IMR) + #define R_BE_WMTX_MOREDATA_TSFT_STMP_CTL 0x10E08 #define R_BE_WMTX_MOREDATA_TSFT_STMP_CTL_C1 0x14E08 #define B_BE_TSFT_OFS_MASK GENMASK(31, 16) @@ -3954,6 +6676,173 @@ #define B_BE_UPD_HGQMD BIT(1) #define B_BE_UPD_TIMIE BIT(0) +#define R_BE_WMTX_TCR_BE_4 0x10E2C +#define R_BE_WMTX_TCR_BE_4_C1 0x14E2C +#define B_BE_UL_EHT_MUMIMO_LTF_MODE BIT(30) +#define B_BE_UL_HE_MUMIMO_LTF_MODE BIT(29) +#define B_BE_EHT_HE_PPDU_4XLTF_ZLD_USTIMER_MASK GENMASK(28, 24) +#define B_BE_EHT_HE_PPDU_2XLTF_ZLD_USTIMER_MASK GENMASK(20, 16) +#define B_BE_NON_LEGACY_PPDU_ZLD_USTIMER_MASK GENMASK(12, 8) +#define B_BE_LEGACY_PPDU_ZLD_USTIMER_MASK GENMASK(4, 0) + +#define R_BE_RSP_CHK_SIG 0x11000 +#define R_BE_RSP_CHK_SIG_C1 0x15000 +#define B_BE_RSP_STATIC_RTS_CHK_SERV_BW_EN BIT(30) +#define B_BE_RSP_TBPPDU_CHK_PWR BIT(29) +#define B_BE_RESP_PAIR_MACID_LEN_EN BIT(25) +#define B_BE_RESP_TX_ABORT_TEST_EN BIT(24) +#define B_BE_RESP_ER_SU_RU106_EN BIT(23) +#define B_BE_RESP_ER_SU_EN BIT(22) +#define B_BE_TXDATA_END_PS_OPT BIT(18) +#define B_BE_CHECK_SOUNDING_SEQ BIT(17) +#define B_BE_RXBA_IGNOREA2 BIT(16) +#define B_BE_ACKTO_CCK_MASK GENMASK(15, 8) +#define B_BE_ACKTO_MASK GENMASK(8, 0) + +#define R_BE_TRXPTCL_RESP_0 0x11004 +#define R_BE_TRXPTCL_RESP_0_C1 0x15004 +#define B_BE_WMAC_RESP_STBC_EN BIT(31) +#define B_BE_WMAC_RXFTM_TXACK_SB BIT(30) +#define B_BE_WMAC_RXFTM_TXACKBWEQ BIT(29) +#define B_BE_RESP_TB_CHK_TXTIME BIT(24) +#define B_BE_RSP_CHK_CCA BIT(23) +#define B_BE_WMAC_LDPC_EN BIT(22) +#define B_BE_WMAC_SGIEN BIT(21) +#define B_BE_WMAC_SPLCPEN BIT(20) +#define B_BE_RESP_EHT_MCS15_REF BIT(19) +#define B_BE_RESP_EHT_MCS14_REF BIT(18) +#define B_BE_WMAC_BESP_EARLY_TXBA BIT(17) +#define B_BE_WMAC_MBA_DUR_FORCE BIT(16) +#define B_BE_WMAC_SPEC_SIFS_OFDM_MASK GENMASK(15, 8) +#define WMAC_SPEC_SIFS_OFDM_1115E 0x11 +#define B_BE_WMAC_SPEC_SIFS_CCK_MASK GENMASK(7, 0) + +#define R_BE_TRXPTCL_RESP_1 0x11008 +#define R_BE_TRXPTCL_RESP_1_C1 0x15008 +#define B_BE_WMAC_RESP_SR_MODE_EN BIT(31) +#define B_BE_FTM_RRSR_RATE_EN_MASK GENMASK(28, 24) +#define B_BE_NESS_MASK GENMASK(23, 22) +#define B_BE_WMAC_RESP_DOPPLEB_BE_EN BIT(21) +#define B_BE_WMAC_RESP_DCM_EN BIT(20) +#define B_BE_WMAC_CLR_ABORT_RESP_TX_CNT BIT(15) +#define B_BE_WMAC_RESP_REF_RATE_SEL BIT(12) +#define B_BE_WMAC_RESP_REF_RATE_MASK GENMASK(11, 0) + +#define R_BE_MAC_LOOPBACK 0x11020 +#define R_BE_MAC_LOOPBACK_C1 0x15020 +#define B_BE_MACLBK_DIS_GCLK BIT(30) +#define B_BE_MACLBK_STS_EN BIT(29) +#define B_BE_MACLBK_RDY_PERIOD_MASK GENMASK(28, 17) +#define B_BE_MACLBK_PLCP_DLY_MASK GENMASK(16, 8) +#define S_BE_MACLBK_PLCP_DLY_DEF 0x28 +#define B_BE_MACLBK_RDY_NUM_MASK GENMASK(7, 3) +#define B_BE_MACLBK_EN BIT(0) + +#define R_BE_WMAC_NAV_CTL 0x11080 +#define R_BE_WMAC_NAV_CTL_C1 0x15080 +#define B_BE_WMAC_NAV_UPPER_EN BIT(26) +#define B_BE_WMAC_0P125US_TIMER_MASK GENMASK(25, 18) +#define B_BE_WMAC_PLCP_UP_NAV_EN BIT(17) +#define B_BE_WMAC_TF_UP_NAV_EN BIT(16) +#define B_BE_WMAC_NAV_UPPER_MASK GENMASK(15, 8) +#define NAV_25MS 0xC4 +#define B_BE_WMAC_RTS_RST_DUR_MASK GENMASK(7, 0) + +#define R_BE_RXTRIG_TEST_USER_2 0x110B0 +#define R_BE_RXTRIG_TEST_USER_2_C1 0x150B0 +#define B_BE_RXTRIG_MACID_MASK GENMASK(31, 24) +#define B_BE_RXTRIG_RU26_DIS BIT(21) +#define B_BE_RXTRIG_FCSCHK_EN BIT(20) +#define B_BE_RXTRIG_PORT_SEL_MASK GENMASK(19, 17) +#define B_BE_RXTRIG_EN BIT(16) +#define B_BE_RXTRIG_USERINFO_2_MASK GENMASK(15, 0) + +#define R_BE_TRXPTCL_ERROR_INDICA_MASK 0x110BC +#define R_BE_TRXPTCL_ERROR_INDICA_MASK_C1 0x150BC +#define B_BE_WMAC_FTM_TIMEOUT_MODE BIT(30) +#define B_BE_WMAC_FTM_TIMEOUT_THR_MASK GENMASK(29, 24) +#define B_BE_WMAC_MODE BIT(22) +#define B_BE_WMAC_TIMETOUT_THR_MASK GENMASK(21, 16) +#define B_BE_RMAC_BFMER BIT(9) +#define B_BE_RMAC_FTM BIT(8) +#define B_BE_RMAC_CSI BIT(7) +#define B_BE_TMAC_MIMO_CTRL BIT(6) +#define B_BE_TMAC_RXTB BIT(5) +#define B_BE_TMAC_HWSIGB_GEN BIT(4) +#define B_BE_TMAC_TXPLCP BIT(3) +#define B_BE_TMAC_RESP BIT(2) +#define B_BE_TMAC_TXCTL BIT(1) +#define B_BE_TMAC_MACTX BIT(0) +#define B_BE_TRXPTCL_ERROR_INDICA_MASK_CLR (B_BE_TMAC_MACTX | \ + B_BE_TMAC_TXCTL | \ + B_BE_TMAC_RESP | \ + B_BE_TMAC_TXPLCP | \ + B_BE_TMAC_HWSIGB_GEN | \ + B_BE_TMAC_RXTB | \ + B_BE_TMAC_MIMO_CTRL | \ + B_BE_RMAC_CSI | \ + B_BE_RMAC_FTM | \ + B_BE_RMAC_BFMER) +#define B_BE_TRXPTCL_ERROR_INDICA_MASK_SET (B_BE_TMAC_MACTX | \ + B_BE_TMAC_TXCTL | \ + B_BE_TMAC_RESP | \ + B_BE_TMAC_TXPLCP | \ + B_BE_TMAC_HWSIGB_GEN | \ + B_BE_TMAC_RXTB | \ + B_BE_TMAC_MIMO_CTRL | \ + B_BE_RMAC_CSI | \ + B_BE_RMAC_FTM | \ + B_BE_RMAC_BFMER) + +#define R_BE_TRXPTCL_ERROR_INDICA 0x110C0 +#define R_BE_TRXPTCL_ERROR_INDICA_C1 0x150C0 +#define B_BE_BFMER_ERR_FLAG BIT(9) +#define B_BE_FTM_ERROR_FLAG_CLR BIT(8) +#define B_BE_CSI_ERROR_FLAG_CLR BIT(7) +#define B_BE_MIMOCTRL_ERROR_FLAG_CLR BIT(6) +#define B_BE_RXTB_ERROR_FLAG_CLR BIT(5) +#define B_BE_HWSIGB_GEN_ERROR_FLAG_CLR BIT(4) +#define B_BE_TXPLCP_ERROR_FLAG_CLR BIT(3) +#define B_BE_RESP_ERROR_FLAG_CLR BIT(2) +#define B_BE_TXCTL_ERROR_FLAG_CLR BIT(1) +#define B_BE_MACTX_ERROR_FLAG_CLR BIT(0) + +#define R_BE_DBGSEL_TRXPTCL 0x110F4 +#define R_BE_DBGSEL_TRXPTCL_C1 0x150F4 +#define B_BE_WMAC_CHNSTS_STATE_MASK GENMASK(19, 16) +#define B_BE_DBGSEL_TRIGCMD_SEL_MASK GENMASK(11, 8) +#define B_BE_DBGSEL_TRXPTCL_MASK GENMASK(7, 0) + +#define R_BE_PHYINFO_ERR_IMR_V1 0x110F8 +#define R_BE_PHYINFO_ERR_IMR_V1_C1 0x150F8 +#define B_BE_PHYINTF_RXTB_WIDTH_MASK GENMASK(31, 30) +#define B_BE_PHYINTF_RXTB_EN_PHASE_MASK GENMASK(29, 28) +#define B_BE_PHYINTF_MIMO_WIDTH_MASK GENMASK(27, 26) +#define B_BE_PHYINTF_MIMO_EN_PHASE_MASK GENMASK(25, 24) +#define B_BE_PHYINTF_TIMEOUT_THR_V1_MASK GENMASK(21, 16) +#define B_BE_CSI_ON_TIMEOUT_EN BIT(5) +#define B_BE_STS_ON_TIMEOUT_EN BIT(4) +#define B_BE_DATA_ON_TIMEOUT_EN BIT(3) +#define B_BE_OFDM_CCA_TIMEOUT_EN BIT(2) +#define B_BE_CCK_CCA_TIMEOUT_EN BIT(1) +#define B_BE_PHY_TXON_TIMEOUT_EN BIT(0) +#define B_BE_PHYINFO_ERR_IMR_V1_CLR (B_BE_PHY_TXON_TIMEOUT_EN | \ + B_BE_CCK_CCA_TIMEOUT_EN | \ + B_BE_OFDM_CCA_TIMEOUT_EN | \ + B_BE_DATA_ON_TIMEOUT_EN | \ + B_BE_STS_ON_TIMEOUT_EN | \ + B_BE_CSI_ON_TIMEOUT_EN) +#define B_BE_PHYINFO_ERR_IMR_V1_SET 0 + +#define R_BE_PHYINFO_ERR_ISR 0x110FC +#define R_BE_PHYINFO_ERR_ISR_C1 0x150FC +#define B_BE_CSI_ON_TIMEOUT_ERR BIT(5) +#define B_BE_STS_ON_TIMEOUT_ERR BIT(4) +#define B_BE_DATA_ON_TIMEOUT_ERR BIT(3) +#define B_BE_OFDM_CCA_TIMEOUT_ERR BIT(2) +#define B_BE_CCK_CCA_TIMEOUT_ERR BIT(1) +#define B_BE_PHY_TXON_TIMEOUT_ERR BIT(0) + #define R_BE_BFMEE_RESP_OPTION 0x11180 #define R_BE_BFMEE_RESP_OPTION_C1 0x15180 #define B_BE_BFMEE_CSI_SEC_TYPE_SH 20 @@ -4009,6 +6898,103 @@ #define B_BE_BFMEE_HT_CSI_RATE_MASK GENMASK(7, 0) #define CSI_INIT_RATE_EHT 0x3 +#define R_BE_WMAC_ACK_BA_RESP_LEGACY 0x11200 +#define R_BE_WMAC_ACK_BA_RESP_LEGACY_C1 0x15200 +#define B_BE_ACK_BA_RESP_LEGACY_CHK_NSTR BIT(16) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_TX_NAV BIT(15) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_INTRA_NAV BIT(14) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_BASIC_NAV BIT(13) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_BTCCA BIT(12) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_CCA160 BIT(5) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_CCA80 BIT(4) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_CCA40 BIT(3) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_CCA20 BIT(2) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_EDCCA BIT(1) +#define B_BE_ACK_BA_RESP_LEGACY_CHK_CCA BIT(0) + +#define R_BE_WMAC_ACK_BA_RESP_HE 0x11204 +#define R_BE_WMAC_ACK_BA_RESP_HE_C1 0x15204 +#define B_BE_ACK_BA_RESP_HE_CHK_NSTR BIT(16) +#define B_BE_ACK_BA_RESP_HE_CHK_TX_NAV BIT(15) +#define B_BE_ACK_BA_RESP_HE_CHK_INTRA_NAV BIT(14) +#define B_BE_ACK_BA_RESP_HE_CHK_BASIC_NAV BIT(13) +#define B_BE_ACK_BA_RESP_HE_CHK_BTCCA BIT(12) +#define B_BE_ACK_BA_RESP_HE_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_ACK_BA_RESP_HE_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_ACK_BA_RESP_HE_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_ACK_BA_RESP_HE_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_ACK_BA_RESP_HE_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_ACK_BA_RESP_HE_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_ACK_BA_RESP_HE_CHK_SEC_CCA160 BIT(5) +#define B_BE_ACK_BA_RESP_HE_CHK_SEC_CCA80 BIT(4) +#define B_BE_ACK_BA_RESP_HE_CHK_SEC_CCA40 BIT(3) +#define B_BE_ACK_BA_RESP_HE_CHK_SEC_CCA20 BIT(2) +#define B_BE_ACK_BA_RESP_HE_CHK_EDCCA BIT(1) +#define B_BE_ACK_BA_RESP_HE_CHK_CCA BIT(0) + +#define R_BE_WMAC_ACK_BA_RESP_EHT_LEG_PUNC 0x11208 +#define R_BE_WMAC_ACK_BA_RESP_EHT_LEG_PUNC_C1 0x15208 +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_NSTR BIT(16) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_TX_NAV BIT(15) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_INTRA_NAV BIT(14) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_BASIC_NAV BIT(13) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_BTCCA BIT(12) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_CCA160 BIT(5) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_CCA80 BIT(4) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_CCA40 BIT(3) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_CCA20 BIT(2) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_EDCCA BIT(1) +#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_CCA BIT(0) + +#define R_BE_RCR 0x11400 +#define R_BE_RCR_C1 0x15400 +#define B_BE_BUSY_CHKSN BIT(15) +#define B_BE_DYN_CHEN BIT(14) +#define B_BE_AUTO_RST BIT(13) +#define B_BE_TIMER_SEL BIT(12) +#define B_BE_STOP_RX_IN BIT(11) +#define B_BE_PSR_RDY_CHKDIS BIT(10) +#define B_BE_DRV_INFO_SZ_MASK GENMASK(9, 8) +#define B_BE_HDR_CNV_SZ_MASK GENMASK(7, 6) +#define B_BE_PHY_RPT_SZ_MASK GENMASK(5, 4) +#define B_BE_CH_EN BIT(0) + +#define R_BE_DLK_PROTECT_CTL 0x11402 +#define R_BE_DLK_PROTECT_CTL_C1 0x15402 +#define B_BE_RX_DLK_CCA_TIME_MASK GENMASK(15, 8) +#define TRXCFG_RMAC_CCA_TO 32 +#define B_BE_RX_DLK_DATA_TIME_MASK GENMASK(7, 4) +#define TRXCFG_RMAC_DATA_TO 15 +#define B_BE_RX_DLK_RST_FSM BIT(3) +#define B_BE_RX_DLK_RST_SKIPDMA BIT(2) +#define B_BE_RX_DLK_RST_EN BIT(1) +#define B_BE_RX_DLK_INT_EN BIT(0) + +#define R_BE_PLCP_HDR_FLTR 0x11404 +#define R_BE_PLCP_HDR_FLTR_C1 0x15404 +#define B_BE_PLCP_RXFA_RESET_TYPE_MASK GENMASK(15, 12) +#define B_BE_PLCP_RXFA_RESET_EN BIT(11) +#define B_BE_DIS_CHK_MIN_LEN BIT(8) +#define B_BE_HE_SIGB_CRC_CHK BIT(6) +#define B_BE_VHT_MU_SIGB_CRC_CHK BIT(5) +#define B_BE_VHT_SU_SIGB_CRC_CHK BIT(4) +#define B_BE_SIGA_CRC_CHK BIT(3) +#define B_BE_LSIG_PARITY_CHK_EN BIT(2) +#define B_BE_CCK_SIG_CHK BIT(1) +#define B_BE_CCK_CRC_CHK BIT(0) + #define R_BE_RX_FLTR_OPT 0x11420 #define R_BE_RX_FLTR_OPT_C1 0x15420 #define B_BE_UID_FILTER_MASK GENMASK(31, 24) @@ -4028,12 +7014,168 @@ #define B_BE_A_A1_MATCH BIT(1) #define B_BE_SNIFFER_MODE BIT(0) +#define R_BE_CTRL_FLTR 0x11424 +#define R_BE_CTRL_FLTR_C1 0x15424 +#define B_BE_CTRL_STYPE_MASK GENMASK(15, 0) +#define RX_FLTR_FRAME_DROP_BE 0x0000 +#define RX_FLTR_FRAME_ACCEPT_BE 0xFFFF + +#define R_BE_MGNT_FLTR 0x11428 +#define R_BE_MGNT_FLTR_C1 0x15428 +#define B_BE_MGNT_STYPE_MASK GENMASK(15, 0) + +#define R_BE_DATA_FLTR 0x1142C +#define R_BE_DATA_FLTR_C1 0x1542C +#define B_BE_DATA_STYPE_MASK GENMASK(15, 0) + +#define R_BE_ADDR_CAM_CTRL 0x11434 +#define R_BE_ADDR_CAM_CTRL_C1 0x15434 +#define B_BE_ADDR_CAM_RANGE_MASK GENMASK(23, 16) +#define ADDR_CAM_SERCH_RANGE 0x7f +#define B_BE_ADDR_CAM_CMPLIMT_MASK GENMASK(15, 12) +#define B_BE_ADDR_CAM_IORST BIT(10) +#define B_BE_DIS_ADDR_CLK_GATED BIT(9) +#define B_BE_ADDR_CAM_CLR BIT(8) +#define B_BE_ADDR_CAM_A2_B0_CHK BIT(2) +#define B_BE_ADDR_CAM_SRCH_PERPKT BIT(1) +#define B_BE_ADDR_CAM_EN BIT(0) + +#define R_BE_RESPBA_CAM_CTRL 0x1143C +#define R_BE_RESPBA_CAM_CTRL_C1 0x1543C +#define B_BE_BACAM_SKIP_ALL_QOSNULL BIT(24) +#define B_BE_BACAM_STD_SSN_SEL BIT(20) +#define B_BE_BACAM_TEMP_SZ_MASK GENMASK(17, 16) +#define B_BE_BACAM_RST_IDX_MASK GENMASK(15, 8) +#define B_BE_BACAM_SHIFT_POLL BIT(7) +#define B_BE_BACAM_IORST BIT(6) +#define B_BE_BACAM_GCK_DIS BIT(5) +#define B_BE_COMPL_VAL BIT(3) +#define B_BE_SSN_SEL BIT(2) +#define B_BE_BACAM_RST_MASK GENMASK(1, 0) +#define S_BE_BACAM_RST_DONE 0 +#define S_BE_BACAM_RST_ENT 1 +#define S_BE_BACAM_RST_ALL 2 + +#define R_BE_RX_SR_CTRL 0x1144A +#define R_BE_RX_SR_CTRL_C1 0x1544A +#define B_BE_SR_OP_MODE_MASK GENMASK(5, 4) +#define B_BE_SRG_CHK_EN BIT(2) +#define B_BE_SR_CTRL_PLCP_EN BIT(1) +#define B_BE_SR_EN BIT(0) + #define R_BE_CSIRPT_OPTION 0x11464 #define R_BE_CSIRPT_OPTION_C1 0x15464 #define B_BE_CSIPRT_EHTSU_AID_EN BIT(26) #define B_BE_CSIPRT_HESU_AID_EN BIT(25) #define B_BE_CSIPRT_VHTSU_AID_EN BIT(24) +#define R_BE_RX_ERR_ISR 0x114F4 +#define R_BE_RX_ERR_ISR_C1 0x154F4 +#define B_BE_RX_ERR_TRIG_ACT_TO BIT(9) +#define B_BE_RX_ERR_STS_ACT_TO BIT(8) +#define B_BE_RX_ERR_CSI_ACT_TO BIT(7) +#define B_BE_RX_ERR_ACT_TO BIT(6) +#define B_BE_CSI_DATAON_ASSERT_TO BIT(5) +#define B_BE_DATAON_ASSERT_TO BIT(4) +#define B_BE_CCA_ASSERT_TO BIT(3) +#define B_BE_RX_ERR_DMA_TO BIT(2) +#define B_BE_RX_ERR_DATA_TO BIT(1) +#define B_BE_RX_ERR_CCA_TO BIT(0) + +#define R_BE_RX_ERR_IMR 0x114F8 +#define R_BE_RX_ERR_IMR_C1 0x154F8 +#define B_BE_RX_ERR_TRIG_ACT_TO_MSK BIT(9) +#define B_BE_RX_ERR_STS_ACT_TO_MSK BIT(8) +#define B_BE_RX_ERR_CSI_ACT_TO_MSK BIT(7) +#define B_BE_RX_ERR_ACT_TO_MSK BIT(6) +#define B_BE_CSI_DATAON_ASSERT_TO_MSK BIT(5) +#define B_BE_DATAON_ASSERT_TO_MSK BIT(4) +#define B_BE_CCA_ASSERT_TO_MSK BIT(3) +#define B_BE_RX_ERR_DMA_TO_MSK BIT(2) +#define B_BE_RX_ERR_DATA_TO_MSK BIT(1) +#define B_BE_RX_ERR_CCA_TO_MSK BIT(0) +#define B_BE_RX_ERR_IMR_CLR (B_BE_RX_ERR_CCA_TO_MSK | \ + B_BE_RX_ERR_DATA_TO_MSK | \ + B_BE_RX_ERR_DMA_TO_MSK | \ + B_BE_CCA_ASSERT_TO_MSK | \ + B_BE_DATAON_ASSERT_TO_MSK | \ + B_BE_CSI_DATAON_ASSERT_TO_MSK | \ + B_BE_RX_ERR_ACT_TO_MSK | \ + B_BE_RX_ERR_CSI_ACT_TO_MSK | \ + B_BE_RX_ERR_STS_ACT_TO_MSK | \ + B_BE_RX_ERR_TRIG_ACT_TO_MSK) +#define B_BE_RX_ERR_IMR_SET (B_BE_RX_ERR_ACT_TO_MSK | \ + B_BE_RX_ERR_STS_ACT_TO_MSK | \ + B_BE_RX_ERR_TRIG_ACT_TO_MSK) + +#define R_BE_RX_PLCP_EXT_OPTION_1 0x11514 +#define R_BE_RX_PLCP_EXT_OPTION_1_C1 0x15514 +#define B_BE_PLCP_CLOSE_RX_UNSPUUORT BIT(19) +#define B_BE_PLCP_CLOSE_RX_BB_BRK BIT(18) +#define B_BE_PLCP_CLOSE_RX_PSDU_PRES BIT(17) +#define B_BE_PLCP_CLOSE_RX_NDP BIT(16) +#define B_BE_PLCP_NSS_SRC BIT(11) +#define B_BE_PLCP_DOPPLEB_BE_SRC BIT(10) +#define B_BE_PLCP_STBC_SRC BIT(9) +#define B_BE_PLCP_SU_PSDU_LEN_SRC BIT(8) +#define B_BE_PLCP_RXSB_SRC BIT(7) +#define B_BE_PLCP_BW_SRC_MASK GENMASK(6, 5) +#define B_BE_PLCP_GILTF_SRC BIT(4) +#define B_BE_PLCP_NSTS_SRC BIT(3) +#define B_BE_PLCP_MCS_SRC BIT(2) +#define B_BE_PLCP_CH20_WIDATA_SRC BIT(1) +#define B_BE_PLCP_PPDU_TYPE_SRC BIT(0) + +#define R_BE_RESP_CSI_RESERVED_PAGE 0x11810 +#define R_BE_RESP_CSI_RESERVED_PAGE_C1 0x15810 +#define B_BE_CSI_RESERVED_PAGE_NUM_MASK GENMASK(27, 16) +#define B_BE_CSI_RESERVED_START_PAGE_MASK GENMASK(11, 0) + +#define R_BE_RESP_IMR 0x11884 +#define R_BE_RESP_IMR_C1 0x15884 +#define B_BE_RESP_TBL_FLAG_ERR_ISR_EN BIT(17) +#define B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN BIT(16) +#define B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN BIT(15) +#define B_BE_RESP_TOO_MANY_PLD_ERR_ISR_EN BIT(14) +#define B_BE_RESP_TXDMA_READ_DATA_ERR_ISR_EN BIT(13) +#define B_BE_RESP_PLDID_RDY_ERR_ISR_EN BIT(12) +#define B_BE_RESP_RX_OVERWRITE_ERR_ISR_EN BIT(11) +#define B_BE_RESP_RXDMA_WRPTR_INVLD_ERR_ISR_EN BIT(10) +#define B_BE_RESP_RXDMA_REQ_INVLD_ERR_ISR_EN BIT(9) +#define B_BE_RESP_RXDMA_REQ_MACID_ERR_ISR_EN BIT(8) +#define B_BE_RESP_TXCMD_TX_ST_ABORT_ERR_ISR_EN BIT(6) +#define B_BE_RESP_TXCMD_DMAC_PROC_ERR_ISR_EN BIT(5) +#define B_BE_RESP_TXCMD_TBL_ERR_ISR_EN BIT(4) +#define B_BE_RESP_INITCMD_RX_ST_ABORT_ERR_ISR_EN BIT(3) +#define B_BE_RESP_INITCMD_RESERVD_PAGE_ABORT_ERR_ISR_EN BIT(2) +#define B_BE_RESP_INITCMD_TX_ST_ABORT_ERR_ISR_EN BIT(1) +#define B_BE_RESP_DMAC_PROC_ERR_ISR_EN BIT(0) +#define B_BE_RESP_IMR_CLR (B_BE_RESP_DMAC_PROC_ERR_ISR_EN | \ + B_BE_RESP_INITCMD_TX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_INITCMD_RX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_TBL_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_DMAC_PROC_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_TX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_RXDMA_REQ_MACID_ERR_ISR_EN | \ + B_BE_RESP_RXDMA_REQ_INVLD_ERR_ISR_EN | \ + B_BE_RESP_RXDMA_WRPTR_INVLD_ERR_ISR_EN | \ + B_BE_RESP_RX_OVERWRITE_ERR_ISR_EN | \ + B_BE_RESP_PLDID_RDY_ERR_ISR_EN | \ + B_BE_RESP_TXDMA_READ_DATA_ERR_ISR_EN | \ + B_BE_RESP_TOO_MANY_PLD_ERR_ISR_EN | \ + B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN | \ + B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN) +#define B_BE_RESP_IMR_SET (B_BE_RESP_DMAC_PROC_ERR_ISR_EN | \ + B_BE_RESP_INITCMD_TX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_INITCMD_RX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_TBL_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_DMAC_PROC_ERR_ISR_EN | \ + B_BE_RESP_TXCMD_TX_ST_ABORT_ERR_ISR_EN | \ + B_BE_RESP_RX_OVERWRITE_ERR_ISR_EN | \ + B_BE_RESP_PLDID_RDY_ERR_ISR_EN | \ + B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN | \ + B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN) + #define R_BE_PWR_MODULE 0x11900 #define R_BE_PWR_MODULE_C1 0x15900 @@ -4045,6 +7187,17 @@ #define R_BE_PWR_RU_LMT 0x12048 #define R_BE_PWR_RU_LMT_MAX 0x120E4 +#define R_BE_C0_TXPWR_IMR 0x128E0 +#define R_BE_C0_TXPWR_IMR_C1 0x168E0 +#define B_BE_FSM_TIMEOUT_ERR_INT_EN BIT(0) +#define B_BE_C0_TXPWR_IMR_CLR B_BE_FSM_TIMEOUT_ERR_INT_EN +#define B_BE_C0_TXPWR_IMR_SET B_BE_FSM_TIMEOUT_ERR_INT_EN + +#define R_BE_TXPWR_ERR_FLAG 0x128E4 +#define R_BE_TXPWR_ERR_IMR 0x128E0 +#define R_BE_TXPWR_ERR_FLAG_C1 0x158E4 +#define R_BE_TXPWR_ERR_IMR_C1 0x158E0 + #define CMAC1_START_ADDR_BE 0x14000 #define CMAC1_END_ADDR_BE 0x17FFF @@ -4310,6 +7463,11 @@ #define B_P0_RSTB_WATCH_DOG BIT(0) #define B_P1_RSTB_WATCH_DOG BIT(1) #define B_UPD_P0_EN BIT(31) +#define R_SPOOF_CG 0x00B4 +#define B_SPOOF_CG_EN BIT(17) +#define R_DFS_FFT_CG 0x00B8 +#define B_DFS_CG_EN BIT(1) +#define B_DFS_FFT_EN BIT(0) #define R_ANAPAR_PW15 0x030C #define B_ANAPAR_PW15 GENMASK(31, 24) #define B_ANAPAR_PW15_H GENMASK(27, 24) @@ -4372,6 +7530,8 @@ #define R_PHY_STS_BITMAP_HT 0x076C #define R_PHY_STS_BITMAP_VHT 0x0770 #define R_PHY_STS_BITMAP_HE 0x0774 +#define R_EDCCA_RPTREG_SEL_BE 0x078C +#define B_EDCCA_RPTREG_SEL_BE_MSK GENMASK(22, 20) #define R_PMAC_GNT 0x0980 #define B_PMAC_GNT_TXEN BIT(0) #define B_PMAC_GNT_RXEN BIT(16) @@ -4431,12 +7591,18 @@ #define B_IOQ_IQK_DPK_EN BIT(1) #define R_GNT_BT_WGT_EN 0x0C6C #define B_GNT_BT_WGT_EN BIT(21) +#define R_TX_COLLISION_T2R_ST 0x0C70 +#define B_TX_COLLISION_T2R_ST_M GENMASK(25, 20) +#define R_TXGATING 0x0C74 +#define B_TXGATING_EN BIT(4) #define R_PD_ARBITER_OFF 0x0C80 #define B_PD_ARBITER_OFF BIT(31) #define R_SNDCCA_A1 0x0C9C #define B_SNDCCA_A1_EN GENMASK(19, 12) #define R_SNDCCA_A2 0x0CA0 #define B_SNDCCA_A2_VAL GENMASK(19, 12) +#define R_TX_COLLISION_T2R_ST_BE 0x0CC8 +#define B_TX_COLLISION_T2R_ST_BE_M GENMASK(13, 8) #define R_RXHT_MCS_LIMIT 0x0D18 #define B_RXHT_MCS_LIMIT GENMASK(9, 8) #define R_RXVHT_MCS_LIMIT 0x0D18 @@ -4455,6 +7621,10 @@ #define R_BRK_ASYNC_RST_EN_1 0x0DC0 #define R_BRK_ASYNC_RST_EN_2 0x0DC4 #define R_BRK_ASYNC_RST_EN_3 0x0DC8 +#define R_CTLTOP 0x1008 +#define B_CTLTOP_ON BIT(23) +#define B_CTLTOP_VAL GENMASK(15, 12) +#define R_EDCCA_RPT_SEL_BE 0x10CC #define R_S0_HW_SI_DIS 0x1200 #define B_S0_HW_SI_DIS_W_R_TRIG GENMASK(30, 28) #define R_P0_RXCK 0x12A0 @@ -4486,6 +7656,14 @@ #define R_CFO_COMP_SEG0_H 0x1388 #define R_CFO_COMP_SEG0_CTRL 0x138C #define R_DBG32_D 0x1730 +#define R_EDCCA_RPT_A 0x1738 +#define R_EDCCA_RPT_B 0x173c +#define B_EDCCA_RPT_B_FB BIT(7) +#define B_EDCCA_RPT_B_P20 BIT(6) +#define B_EDCCA_RPT_B_S20 BIT(5) +#define B_EDCCA_RPT_B_S40 BIT(4) +#define B_EDCCA_RPT_B_S80 BIT(3) +#define B_EDCCA_RPT_B_PATH_MASK GENMASK(2, 1) #define R_SWSI_V1 0x174C #define B_SWSI_W_BUSY_V1 BIT(24) #define B_SWSI_R_BUSY_V1 BIT(25) @@ -4547,6 +7725,8 @@ #define R_S0_ADDCK 0x1E00 #define B_S0_ADDCK_I GENMASK(9, 0) #define B_S0_ADDCK_Q GENMASK(19, 10) +#define R_EDCCA_RPT_SEL 0x20CC +#define B_EDCCA_RPT_SEL_MSK GENMASK(2, 0) #define R_ADC_FIFO 0x20fc #define B_ADC_FIFO_RST GENMASK(31, 24) #define B_ADC_FIFO_RXK GENMASK(31, 16) @@ -4593,6 +7773,8 @@ #define B_DBCC_80P80_SEL_EVM_RPT2_EN BIT(0) #define R_P1_EN_SOUND_WO_NDP 0x2D7C #define B_P1_EN_SOUND_WO_NDP BIT(1) +#define R_EDCCA_RPT_A_BE 0x2E38 +#define R_EDCCA_RPT_B_BE 0x2E3C #define R_S1_HW_SI_DIS 0x3200 #define B_S1_HW_SI_DIS_W_R_TRIG GENMASK(30, 28) #define R_P1_RXCK 0x32A0 @@ -4636,6 +7818,7 @@ #define B_SEG0CSI_EN BIT(23) #define R_BSS_CLR_MAP 0x43ac #define R_BSS_CLR_MAP_V1 0x43B0 +#define R_BSS_CLR_MAP_V2 0x4EB0 #define B_BSS_CLR_MAP_VLD0 BIT(28) #define B_BSS_CLR_MAP_TGT GENMASK(27, 22) #define B_BSS_CLR_MAP_STAID GENMASK(21, 11) @@ -4800,9 +7983,9 @@ #define R_SEG0R_PD_V2 0x6A74 #define R_SEG0R_EDCCA_LVL 0x4840 #define R_SEG0R_EDCCA_LVL_V1 0x4884 -#define B_SEG0R_PPDU_LVL_MSK GENMASK(31, 24) -#define B_SEG0R_EDCCA_LVL_P_MSK GENMASK(15, 8) -#define B_SEG0R_EDCCA_LVL_A_MSK GENMASK(7, 0) +#define B_EDCCA_LVL_MSK3 GENMASK(31, 24) +#define B_EDCCA_LVL_MSK1 GENMASK(15, 8) +#define B_EDCCA_LVL_MSK0 GENMASK(7, 0) #define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1 BIT(30) #define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK BIT(29) #define B_SEG0R_PD_LOWER_BOUND_MSK GENMASK(10, 6) @@ -4929,6 +8112,8 @@ #define R_BMODE_PDTH_EN_V1 0x4B74 #define R_BMODE_PDTH_EN_V2 0x6718 #define B_BMODE_PDTH_LIMIT_EN_MSK_V1 BIT(30) +#define R_BSS_CLR_VLD_V2 0x4EBC +#define B_BSS_CLR_VLD0_V2 BIT(2) #define R_CFO_COMP_SEG1_L 0x5384 #define R_CFO_COMP_SEG1_H 0x5388 #define R_CFO_COMP_SEG1_CTRL 0x538C @@ -5056,6 +8241,10 @@ #define B_DCFO_WEIGHT_MSK_V1 GENMASK(31, 28) #define R_DCFO_OPT_V1 0x6260 #define B_DCFO_OPT_EN_V1 BIT(17) +#define R_SEG0R_EDCCA_LVL_BE 0x69EC +#define R_SEG0R_PPDU_LVL_BE 0x69F0 +#define R_SEGSND 0x6A14 +#define B_SEGSND_EN BIT(31) #define R_RPL_BIAS_COMP1 0x6DF0 #define B_RPL_BIAS_COMP1_MASK GENMASK(7, 0) #define R_P1_TSSI_ALIM1 0x7630 diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index ca99422e60..d0857ef60e 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -112,9 +112,9 @@ static const struct rtw89_regd rtw89_regd_map[] = { COUNTRY_REGD("MY", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("PK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("PH", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("LK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_ETSI), COUNTRY_REGD("TH", RTW89_ETSI, RTW89_ETSI, RTW89_THAILAND), COUNTRY_REGD("VN", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("AU", RTW89_ACMA, RTW89_ACMA, RTW89_ACMA), @@ -179,7 +179,7 @@ static const struct rtw89_regd rtw89_regd_map[] = { COUNTRY_REGD("GE", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GI", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GL", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("GP", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GU", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("GG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), @@ -257,7 +257,42 @@ static const struct rtw89_regd rtw89_regd_map[] = { COUNTRY_REGD("PS", RTW89_ETSI, RTW89_ETSI, RTW89_NA), }; -static const struct rtw89_regd *rtw89_regd_find_reg_by_name(char *alpha2) +static const char rtw89_alpha2_list_eu[][3] = { + "AT", + "BE", + "CY", + "CZ", + "DK", + "EE", + "FI", + "FR", + "DE", + "GR", + "HU", + "IS", + "IE", + "IT", + "LV", + "LI", + "LT", + "LU", + "MT", + "MC", + "NL", + "NO", + "PL", + "PT", + "SK", + "SI", + "ES", + "SE", + "CH", + "BG", + "HR", + "RO", +}; + +static const struct rtw89_regd *rtw89_regd_find_reg_by_name(const char *alpha2) { u32 i; @@ -274,6 +309,24 @@ static bool rtw89_regd_is_ww(const struct rtw89_regd *regd) return regd == &rtw89_ww_regd; } +static u8 rtw89_regd_get_index(const struct rtw89_regd *regd) +{ + BUILD_BUG_ON(ARRAY_SIZE(rtw89_regd_map) > RTW89_REGD_MAX_COUNTRY_NUM); + + if (rtw89_regd_is_ww(regd)) + return RTW89_REGD_MAX_COUNTRY_NUM; + + return regd - rtw89_regd_map; +} + +static u8 rtw89_regd_get_index_by_name(const char *alpha2) +{ + const struct rtw89_regd *regd; + + regd = rtw89_regd_find_reg_by_name(alpha2); + return rtw89_regd_get_index(regd); +} + #define rtw89_debug_regd(_dev, _regd, _desc, _argv...) \ do { \ typeof(_regd) __r = _regd; \ @@ -291,19 +344,22 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, const struct rtw89_chip_info *chip = rtwdev->chip; bool regd_allow_unii_4 = chip->support_unii4; struct ieee80211_supported_band *sband; + struct rtw89_acpi_dsm_result res = {}; int ret; u8 val; if (!chip->support_unii4) goto bottom; - ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &val); + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &res); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: cannot eval unii 4: %d\n", ret); goto bottom; } + val = res.u.value; + rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: eval if allow unii 4: %d\n", val); @@ -332,25 +388,99 @@ bottom: sband->n_channels -= 3; } +static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block, + const char *alpha2) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + u8 index; + + index = rtw89_regd_get_index_by_name(alpha2); + if (index == RTW89_REGD_MAX_COUNTRY_NUM) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, "%s: unknown alpha2 %c%c\n", + __func__, alpha2[0], alpha2[1]); + return; + } + + if (block) + set_bit(index, regulatory->block_6ghz); + else + clear_bit(index, regulatory->block_6ghz); +} + +static void rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_acpi_country_code *country; + const struct rtw89_acpi_policy_6ghz *ptr; + struct rtw89_acpi_dsm_result res = {}; + bool to_block; + int i, j; + int ret; + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_BP, &res); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval policy 6ghz: %d\n", ret); + return; + } + + ptr = res.u.policy_6ghz; + + switch (ptr->policy_mode) { + case RTW89_ACPI_POLICY_BLOCK: + to_block = true; + break; + case RTW89_ACPI_POLICY_ALLOW: + to_block = false; + /* only below list is allowed; block all first */ + bitmap_fill(regulatory->block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM); + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "%s: unknown policy mode: %d\n", __func__, + ptr->policy_mode); + goto out; + } + + for (i = 0; i < ptr->country_count; i++) { + country = &ptr->country_list[i]; + if (memcmp("EU", country->alpha2, 2) != 0) { + __rtw89_regd_setup_policy_6ghz(rtwdev, to_block, + country->alpha2); + continue; + } + + for (j = 0; j < ARRAY_SIZE(rtw89_alpha2_list_eu); j++) + __rtw89_regd_setup_policy_6ghz(rtwdev, to_block, + rtw89_alpha2_list_eu[j]); + } + +out: + kfree(ptr); +} + static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy) { const struct rtw89_chip_info *chip = rtwdev->chip; bool chip_support_6ghz = chip->support_bands & BIT(NL80211_BAND_6GHZ); bool regd_allow_6ghz = chip_support_6ghz; struct ieee80211_supported_band *sband; + struct rtw89_acpi_dsm_result res = {}; int ret; u8 val; if (!chip_support_6ghz) goto bottom; - ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &val); + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &res); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: cannot eval 6ghz: %d\n", ret); goto bottom; } + val = res.u.value; + rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: eval if disallow 6ghz: %d\n", val); @@ -369,8 +499,10 @@ bottom: rtw89_debug(rtwdev, RTW89_DBG_REGD, "regd: allow 6ghz: %d\n", regd_allow_6ghz); - if (regd_allow_6ghz) + if (regd_allow_6ghz) { + rtw89_regd_setup_policy_6ghz(rtwdev); return; + } sband = wiphy->bands[NL80211_BAND_6GHZ]; if (!sband) @@ -430,6 +562,33 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev, return 0; } +static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev, + struct wiphy *wiphy) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_regd *regd = regulatory->regd; + struct ieee80211_supported_band *sband; + u8 index; + int i; + + index = rtw89_regd_get_index(regd); + if (index == RTW89_REGD_MAX_COUNTRY_NUM) + return; + + if (!test_bit(index, regulatory->block_6ghz)) + return; + + rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is blocked by policy\n", + regd->alpha2[0], regd->alpha2[1]); + + sband = wiphy->bands[NL80211_BAND_6GHZ]; + if (!sband) + return; + + for (i = 0; i < sband->n_channels; i++) + sband->channels[i].flags |= IEEE80211_CHAN_DISABLED; +} + static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev, struct wiphy *wiphy, struct regulatory_request *request) @@ -444,6 +603,8 @@ static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev, wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; else wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE; + + rtw89_regd_apply_policy_6ghz(rtwdev, wiphy); } void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 50522ff850..5c167a9278 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -205,6 +205,20 @@ static const struct rtw89_dig_regs rtw8851b_dig_regs = { B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, }; +static const struct rtw89_edcca_regs rtw8851b_edcca_regs = { + .edcca_level = R_SEG0R_EDCCA_LVL_V1, + .edcca_mask = B_EDCCA_LVL_MSK0, + .edcca_p_mask = B_EDCCA_LVL_MSK1, + .ppdu_level = R_SEG0R_EDCCA_LVL_V1, + .ppdu_mask = B_EDCCA_LVL_MSK3, + .rpt_a = R_EDCCA_RPT_A, + .rpt_b = R_EDCCA_RPT_B, + .rpt_sel = R_EDCCA_RPT_SEL, + .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK, + .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST, + .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M, +}; + static const struct rtw89_btc_rf_trx_para rtw89_btc_8851b_rf_ul[] = { {255, 0, 0, 7}, /* 0 -> original */ {255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */ @@ -500,7 +514,8 @@ static void rtw8851b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, gain->offset_valid = valid; } -static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8851b_efuse *map; @@ -2359,8 +2374,8 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8851b_hfc_param_ini_pcie, .dle_mem = rtw8851b_dle_mem_pcie, - .wde_qempty_acq_num = 4, - .wde_qempty_mgq_sel = 4, + .wde_qempty_acq_grpnum = 4, + .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, @@ -2393,12 +2408,14 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .bacam_num = 2, .bacam_dynamic_num = 4, .bacam_ver = RTW89_BACAM_V0, + .ppdu_max_usr = 4, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, .limit_efuse_size = 1280, .dav_phy_efuse_size = 0, .dav_log_efuse_size = 0, + .efuse_blocks = NULL, .phycap_addr = 0x580, .phycap_size = 128, .para_ver = 0, @@ -2437,13 +2454,15 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .dcfo_comp = &rtw8851b_dcfo_comp, .dcfo_comp_sft = 12, .imr_info = &rtw8851b_imr_info, + .imr_dmac_table = NULL, + .imr_cmac_table = NULL, .rrsr_cfgs = &rtw8851b_rrsr_cfgs, .bss_clr_vld = {R_BSS_CLR_MAP_V1, B_BSS_CLR_MAP_VLD0}, .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), - .edcca_lvl_reg = R_SEG0R_EDCCA_LVL_V1, + .edcca_regs = &rtw8851b_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8851b, #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index 0f7711c50b..ca1374a717 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -10,6 +10,7 @@ #include "rtw8851b.h" static const struct rtw89_pci_info rtw8851b_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -24,6 +25,8 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_DISABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, + .check_rx_tag = false, .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, @@ -33,6 +36,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, .txbd_rwptr_clr2_reg = 0, + .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO}, .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK_V1}, .dma_stop2 = {0}, .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK_V1}, @@ -41,6 +45,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, + .mit_addr = R_AX_INT_MIT_RX, .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) | BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 0c36e6180e..0c76c52ce2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -498,6 +498,20 @@ static const struct rtw89_dig_regs rtw8852a_dig_regs = { B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, }; +static const struct rtw89_edcca_regs rtw8852a_edcca_regs = { + .edcca_level = R_SEG0R_EDCCA_LVL, + .edcca_mask = B_EDCCA_LVL_MSK0, + .edcca_p_mask = B_EDCCA_LVL_MSK1, + .ppdu_level = R_SEG0R_EDCCA_LVL, + .ppdu_mask = B_EDCCA_LVL_MSK3, + .rpt_a = R_EDCCA_RPT_A, + .rpt_b = R_EDCCA_RPT_B, + .rpt_sel = R_EDCCA_RPT_SEL, + .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK, + .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST, + .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M, +}; + static void rtw8852ae_efuse_parsing(struct rtw89_efuse *efuse, struct rtw8852a_efuse *map) { @@ -537,7 +551,8 @@ static void rtw8852a_efuse_parsing_tssi(struct rtw89_dev *rtwdev, } } -static int rtw8852a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8852a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8852a_efuse *map; @@ -2094,8 +2109,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852a_hfc_param_ini_pcie, .dle_mem = rtw8852a_dle_mem_pcie, - .wde_qempty_acq_num = 16, - .wde_qempty_mgq_sel = 16, + .wde_qempty_acq_grpnum = 16, + .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xc000, 0xd000}, .pwr_on_seq = pwr_on_seq_8852a, .pwr_off_seq = pwr_off_seq_8852a, @@ -2129,12 +2144,14 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .bacam_num = 2, .bacam_dynamic_num = 4, .bacam_ver = RTW89_BACAM_V0, + .ppdu_max_usr = 4, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 1536, .limit_efuse_size = 1152, .dav_phy_efuse_size = 0, .dav_log_efuse_size = 0, + .efuse_blocks = NULL, .phycap_addr = 0x580, .phycap_size = 128, .para_ver = 0x0, @@ -2174,11 +2191,13 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .dcfo_comp = &rtw8852a_dcfo_comp, .dcfo_comp_sft = 10, .imr_info = &rtw8852a_imr_info, + .imr_dmac_table = NULL, + .imr_cmac_table = NULL, .rrsr_cfgs = &rtw8852a_rrsr_cfgs, .bss_clr_vld = {R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0}, .bss_clr_map_reg = R_BSS_CLR_MAP, .dma_ch_mask = 0, - .edcca_lvl_reg = R_SEG0R_EDCCA_LVL, + .edcca_regs = &rtw8852a_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852a, #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index d835a44a1d..7c6ffedb77 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -10,6 +10,7 @@ #include "rtw8852a.h" static const struct rtw89_pci_info rtw8852a_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -24,6 +25,8 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_DISABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, + .check_rx_tag = false, .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, @@ -33,6 +36,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, .txbd_rwptr_clr2_reg = R_AX_TXBD_RWPTR_CLR2, + .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO}, .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK}, .dma_stop2 = {R_AX_PCIE_DMA_STOP2, B_AX_TX_STOP2_ALL}, .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK}, @@ -41,6 +45,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, + .mit_addr = R_AX_INT_MIT_RX, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = NULL, .dma_addr_set = &rtw89_pci_ch_dma_addr_set, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 9d4e6f0821..de887a35f3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -330,6 +330,20 @@ static const struct rtw89_dig_regs rtw8852b_dig_regs = { B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, }; +static const struct rtw89_edcca_regs rtw8852b_edcca_regs = { + .edcca_level = R_SEG0R_EDCCA_LVL_V1, + .edcca_mask = B_EDCCA_LVL_MSK0, + .edcca_p_mask = B_EDCCA_LVL_MSK1, + .ppdu_level = R_SEG0R_EDCCA_LVL_V1, + .ppdu_mask = B_EDCCA_LVL_MSK3, + .rpt_a = R_EDCCA_RPT_A, + .rpt_b = R_EDCCA_RPT_B, + .rpt_sel = R_EDCCA_RPT_SEL, + .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK, + .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST, + .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M, +}; + static const struct rtw89_btc_rf_trx_para rtw89_btc_8852b_rf_ul[] = { {255, 0, 0, 7}, /* 0 -> original */ {255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */ @@ -638,7 +652,8 @@ static void rtw8852b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, gain->offset_valid = valid; } -static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8852b_efuse *map; @@ -2528,8 +2543,8 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, .dle_mem = rtw8852b_dle_mem_pcie, - .wde_qempty_acq_num = 4, - .wde_qempty_mgq_sel = 4, + .wde_qempty_acq_grpnum = 4, + .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, @@ -2563,12 +2578,14 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .bacam_num = 2, .bacam_dynamic_num = 4, .bacam_ver = RTW89_BACAM_V0, + .ppdu_max_usr = 4, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, .limit_efuse_size = 1280, .dav_phy_efuse_size = 96, .dav_log_efuse_size = 16, + .efuse_blocks = NULL, .phycap_addr = 0x580, .phycap_size = 128, .para_ver = 0, @@ -2608,13 +2625,15 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .dcfo_comp = &rtw8852b_dcfo_comp, .dcfo_comp_sft = 10, .imr_info = &rtw8852b_imr_info, + .imr_dmac_table = NULL, + .imr_cmac_table = NULL, .rrsr_cfgs = &rtw8852b_rrsr_cfgs, .bss_clr_vld = {R_BSS_CLR_MAP_V1, B_BSS_CLR_MAP_VLD0}, .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), - .edcca_lvl_reg = R_SEG0R_EDCCA_LVL_V1, + .edcca_regs = &rtw8852b_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852b, #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index ecf39d2d9f..ed71364e64 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -10,6 +10,7 @@ #include "rtw8852b.h" static const struct rtw89_pci_info rtw8852b_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -24,6 +25,8 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_DISABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, + .check_rx_tag = false, .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, @@ -33,6 +36,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, .txbd_rwptr_clr2_reg = 0, + .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO}, .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK_V1}, .dma_stop2 = {0}, .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK_V1}, @@ -41,6 +45,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM, .cpwm_addr = R_AX_CPWM, + .mit_addr = R_AX_INT_MIT_RX, .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) | BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 3b7d8ab39b..8618d0204f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -167,6 +167,20 @@ static const struct rtw89_dig_regs rtw8852c_dig_regs = { B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, }; +static const struct rtw89_edcca_regs rtw8852c_edcca_regs = { + .edcca_level = R_SEG0R_EDCCA_LVL, + .edcca_mask = B_EDCCA_LVL_MSK0, + .edcca_p_mask = B_EDCCA_LVL_MSK1, + .ppdu_level = R_SEG0R_EDCCA_LVL, + .ppdu_mask = B_EDCCA_LVL_MSK3, + .rpt_a = R_EDCCA_RPT_A, + .rpt_b = R_EDCCA_RPT_B, + .rpt_sel = R_EDCCA_RPT_SEL, + .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK, + .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST, + .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M, +}; + static void rtw8852c_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en, enum rtw89_phy_idx phy_idx); @@ -426,11 +440,36 @@ static void rtw8852c_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, valid |= _decode_efuse_gain(map->rx_gain_5g_high, &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH], &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH]); + valid |= _decode_efuse_gain(map->rx_gain_6g_l0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_l1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L1]); + valid |= _decode_efuse_gain(map->rx_gain_6g_m0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_m1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M1]); + valid |= _decode_efuse_gain(map->rx_gain_6g_h0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_h1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H1]); + valid |= _decode_efuse_gain(map->rx_gain_6g_uh0, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH0], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH0]); + valid |= _decode_efuse_gain(map->rx_gain_6g_uh1, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH1], + &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH1]); gain->offset_valid = valid; } -static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) { struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw8852c_efuse *map; @@ -2840,8 +2879,8 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852c_hfc_param_ini_pcie, .dle_mem = rtw8852c_dle_mem_pcie, - .wde_qempty_acq_num = 16, - .wde_qempty_mgq_sel = 16, + .wde_qempty_acq_grpnum = 16, + .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xe000, 0xf000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, @@ -2877,12 +2916,14 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .bacam_num = 8, .bacam_dynamic_num = 8, .bacam_ver = RTW89_BACAM_V0_EXT, + .ppdu_max_usr = 8, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, .limit_efuse_size = 1280, .dav_phy_efuse_size = 96, .dav_log_efuse_size = 16, + .efuse_blocks = NULL, .phycap_addr = 0x590, .phycap_size = 0x60, .para_ver = 0x1, @@ -2923,11 +2964,13 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .dcfo_comp = &rtw8852c_dcfo_comp, .dcfo_comp_sft = 12, .imr_info = &rtw8852c_imr_info, + .imr_dmac_table = NULL, + .imr_cmac_table = NULL, .rrsr_cfgs = &rtw8852c_rrsr_cfgs, .bss_clr_vld = {R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0}, .bss_clr_map_reg = R_BSS_CLR_MAP, .dma_ch_mask = 0, - .edcca_lvl_reg = R_SEG0R_EDCCA_LVL, + .edcca_regs = &rtw8852c_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852c, #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.h b/drivers/net/wireless/realtek/rtw89/rtw8852c.h index ac642808a8..77b05daedd 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.h @@ -73,9 +73,25 @@ struct rtw8852c_efuse { u8 bw40_1s_tssi_6g_a[TSSI_MCS_6G_CH_GROUP_NUM]; u8 rsvd14[10]; u8 bw40_1s_tssi_6g_b[TSSI_MCS_6G_CH_GROUP_NUM]; - u8 rsvd15[110]; + u8 rsvd15[94]; + u8 rx_gain_6g_l0; + u8 rsvd16; + u8 rx_gain_6g_l1; + u8 rsvd17; + u8 rx_gain_6g_m0; + u8 rsvd18; + u8 rx_gain_6g_m1; + u8 rsvd19; + u8 rx_gain_6g_h0; + u8 rsvd20; + u8 rx_gain_6g_h1; + u8 rsvd21; + u8 rx_gain_6g_uh0; + u8 rsvd22; + u8 rx_gain_6g_uh1; + u8 rsvd23; u8 channel_plan_6g; - u8 rsvd16[71]; + u8 rsvd24[71]; union { struct rtw8852c_u_efuse u; struct rtw8852c_e_efuse e; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 80490a5437..583ea673a4 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -19,6 +19,7 @@ static const struct rtw89_pci_bd_idx_addr rtw8852c_bd_idx_addr_low_power = { }; static const struct rtw89_pci_info rtw8852c_pci_info = { + .gen_def = &rtw89_pci_gen_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -33,6 +34,8 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_ENABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, + .check_rx_tag = false, .init_cfg_reg = R_AX_HAXI_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN_V1, @@ -42,6 +45,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .max_tag_num_mask = B_AX_MAX_TAG_NUM_V1_MASK, .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR_V1, .txbd_rwptr_clr2_reg = R_AX_TXBD_RWPTR_CLR2_V1, + .dma_io_stop = {R_AX_HAXI_INIT_CFG1, B_AX_STOP_AXI_MST}, .dma_stop1 = {R_AX_HAXI_DMA_STOP1, B_AX_TX_STOP1_MASK}, .dma_stop2 = {R_AX_HAXI_DMA_STOP2, B_AX_TX_STOP2_ALL}, .dma_busy1 = {R_AX_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK}, @@ -50,6 +54,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .rpwm_addr = R_AX_PCIE_HRPWM_V1, .cpwm_addr = R_AX_PCIE_CRPWM, + .mit_addr = R_AX_INT_MIT_RX_V1, .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = &rtw8852c_bd_idx_addr_low_power, .dma_addr_set = &rtw89_pci_ch_dma_addr_set_v1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c new file mode 100644 index 0000000000..0e7300cc6d --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -0,0 +1,710 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include "debug.h" +#include "efuse.h" +#include "fw.h" +#include "mac.h" +#include "phy.h" +#include "reg.h" +#include "rtw8922a.h" + +#define RTW8922A_FW_FORMAT_MAX 0 +#define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw" +#define RTW8922A_MODULE_FIRMWARE \ + RTW8922A_FW_BASENAME ".bin" + +static const struct rtw89_hfc_ch_cfg rtw8922a_hfc_chcfg_pcie[] = { + {2, 1641, grp_0}, /* ACH 0 */ + {2, 1641, grp_0}, /* ACH 1 */ + {2, 1641, grp_0}, /* ACH 2 */ + {2, 1641, grp_0}, /* ACH 3 */ + {2, 1641, grp_1}, /* ACH 4 */ + {2, 1641, grp_1}, /* ACH 5 */ + {2, 1641, grp_1}, /* ACH 6 */ + {2, 1641, grp_1}, /* ACH 7 */ + {2, 1641, grp_0}, /* B0MGQ */ + {2, 1641, grp_0}, /* B0HIQ */ + {2, 1641, grp_1}, /* B1MGQ */ + {2, 1641, grp_1}, /* B1HIQ */ + {0, 0, 0}, /* FWCMDQ */ + {0, 0, 0}, /* BMC */ + {0, 0, 0}, /* H2D */ +}; + +static const struct rtw89_hfc_pub_cfg rtw8922a_hfc_pubcfg_pcie = { + 1651, /* Group 0 */ + 1651, /* Group 1 */ + 3302, /* Public Max */ + 0, /* WP threshold */ +}; + +static const struct rtw89_hfc_param_ini rtw8922a_hfc_param_ini_pcie[] = { + [RTW89_QTA_SCC] = {rtw8922a_hfc_chcfg_pcie, &rtw8922a_hfc_pubcfg_pcie, + &rtw89_mac_size.hfc_prec_cfg_c0, RTW89_HCIFC_POH}, + [RTW89_QTA_DLFW] = {NULL, NULL, &rtw89_mac_size.hfc_prec_cfg_c2, + RTW89_HCIFC_POH}, + [RTW89_QTA_INVALID] = {NULL}, +}; + +static const struct rtw89_dle_mem rtw8922a_dle_mem_pcie[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size0_v1, + &rtw89_mac_size.ple_size0_v1, &rtw89_mac_size.wde_qt0_v1, + &rtw89_mac_size.wde_qt0_v1, &rtw89_mac_size.ple_qt0, + &rtw89_mac_size.ple_qt1, &rtw89_mac_size.ple_rsvd_qt0, + &rtw89_mac_size.rsvd0_size0, &rtw89_mac_size.rsvd1_size0}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size4_v1, + &rtw89_mac_size.ple_size3_v1, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt9, + &rtw89_mac_size.ple_qt9, &rtw89_mac_size.ple_rsvd_qt1, + &rtw89_mac_size.rsvd0_size0, &rtw89_mac_size.rsvd1_size0}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + +static const struct rtw89_reg_imr rtw8922a_imr_dmac_regs[] = { + {R_BE_DISP_HOST_IMR, B_BE_DISP_HOST_IMR_CLR, B_BE_DISP_HOST_IMR_SET}, + {R_BE_DISP_CPU_IMR, B_BE_DISP_CPU_IMR_CLR, B_BE_DISP_CPU_IMR_SET}, + {R_BE_DISP_OTHER_IMR, B_BE_DISP_OTHER_IMR_CLR, B_BE_DISP_OTHER_IMR_SET}, + {R_BE_PKTIN_ERR_IMR, B_BE_PKTIN_ERR_IMR_CLR, B_BE_PKTIN_ERR_IMR_SET}, + {R_BE_INTERRUPT_MASK_REG, B_BE_INTERRUPT_MASK_REG_CLR, B_BE_INTERRUPT_MASK_REG_SET}, + {R_BE_MLO_ERR_IDCT_IMR, B_BE_MLO_ERR_IDCT_IMR_CLR, B_BE_MLO_ERR_IDCT_IMR_SET}, + {R_BE_MPDU_TX_ERR_IMR, B_BE_MPDU_TX_ERR_IMR_CLR, B_BE_MPDU_TX_ERR_IMR_SET}, + {R_BE_MPDU_RX_ERR_IMR, B_BE_MPDU_RX_ERR_IMR_CLR, B_BE_MPDU_RX_ERR_IMR_SET}, + {R_BE_SEC_ERROR_IMR, B_BE_SEC_ERROR_IMR_CLR, B_BE_SEC_ERROR_IMR_SET}, + {R_BE_CPUIO_ERR_IMR, B_BE_CPUIO_ERR_IMR_CLR, B_BE_CPUIO_ERR_IMR_SET}, + {R_BE_WDE_ERR_IMR, B_BE_WDE_ERR_IMR_CLR, B_BE_WDE_ERR_IMR_SET}, + {R_BE_WDE_ERR1_IMR, B_BE_WDE_ERR1_IMR_CLR, B_BE_WDE_ERR1_IMR_SET}, + {R_BE_PLE_ERR_IMR, B_BE_PLE_ERR_IMR_CLR, B_BE_PLE_ERR_IMR_SET}, + {R_BE_PLE_ERRFLAG1_IMR, B_BE_PLE_ERRFLAG1_IMR_CLR, B_BE_PLE_ERRFLAG1_IMR_SET}, + {R_BE_WDRLS_ERR_IMR, B_BE_WDRLS_ERR_IMR_CLR, B_BE_WDRLS_ERR_IMR_SET}, + {R_BE_TXPKTCTL_B0_ERRFLAG_IMR, B_BE_TXPKTCTL_B0_ERRFLAG_IMR_CLR, + B_BE_TXPKTCTL_B0_ERRFLAG_IMR_SET}, + {R_BE_TXPKTCTL_B1_ERRFLAG_IMR, B_BE_TXPKTCTL_B1_ERRFLAG_IMR_CLR, + B_BE_TXPKTCTL_B1_ERRFLAG_IMR_SET}, + {R_BE_BBRPT_COM_ERR_IMR, B_BE_BBRPT_COM_ERR_IMR_CLR, B_BE_BBRPT_COM_ERR_IMR_SET}, + {R_BE_BBRPT_CHINFO_ERR_IMR, B_BE_BBRPT_CHINFO_ERR_IMR_CLR, + B_BE_BBRPT_CHINFO_ERR_IMR_SET}, + {R_BE_BBRPT_DFS_ERR_IMR, B_BE_BBRPT_DFS_ERR_IMR_CLR, B_BE_BBRPT_DFS_ERR_IMR_SET}, + {R_BE_LA_ERRFLAG_IMR, B_BE_LA_ERRFLAG_IMR_CLR, B_BE_LA_ERRFLAG_IMR_SET}, + {R_BE_CH_INFO_DBGFLAG_IMR, B_BE_CH_INFO_DBGFLAG_IMR_CLR, B_BE_CH_INFO_DBGFLAG_IMR_SET}, + {R_BE_PLRLS_ERR_IMR, B_BE_PLRLS_ERR_IMR_CLR, B_BE_PLRLS_ERR_IMR_SET}, + {R_BE_HAXI_IDCT_MSK, B_BE_HAXI_IDCT_MSK_CLR, B_BE_HAXI_IDCT_MSK_SET}, +}; + +static const struct rtw89_imr_table rtw8922a_imr_dmac_table = { + .regs = rtw8922a_imr_dmac_regs, + .n_regs = ARRAY_SIZE(rtw8922a_imr_dmac_regs), +}; + +static const struct rtw89_reg_imr rtw8922a_imr_cmac_regs[] = { + {R_BE_RESP_IMR, B_BE_RESP_IMR_CLR, B_BE_RESP_IMR_SET}, + {R_BE_RX_ERROR_FLAG_IMR, B_BE_RX_ERROR_FLAG_IMR_CLR, B_BE_RX_ERROR_FLAG_IMR_SET}, + {R_BE_TX_ERROR_FLAG_IMR, B_BE_TX_ERROR_FLAG_IMR_CLR, B_BE_TX_ERROR_FLAG_IMR_SET}, + {R_BE_RX_ERROR_FLAG_IMR_1, B_BE_TX_ERROR_FLAG_IMR_1_CLR, B_BE_TX_ERROR_FLAG_IMR_1_SET}, + {R_BE_PTCL_IMR1, B_BE_PTCL_IMR1_CLR, B_BE_PTCL_IMR1_SET}, + {R_BE_PTCL_IMR0, B_BE_PTCL_IMR0_CLR, B_BE_PTCL_IMR0_SET}, + {R_BE_PTCL_IMR_2, B_BE_PTCL_IMR_2_CLR, B_BE_PTCL_IMR_2_SET}, + {R_BE_SCHEDULE_ERR_IMR, B_BE_SCHEDULE_ERR_IMR_CLR, B_BE_SCHEDULE_ERR_IMR_SET}, + {R_BE_C0_TXPWR_IMR, B_BE_C0_TXPWR_IMR_CLR, B_BE_C0_TXPWR_IMR_SET}, + {R_BE_TRXPTCL_ERROR_INDICA_MASK, B_BE_TRXPTCL_ERROR_INDICA_MASK_CLR, + B_BE_TRXPTCL_ERROR_INDICA_MASK_SET}, + {R_BE_RX_ERR_IMR, B_BE_RX_ERR_IMR_CLR, B_BE_RX_ERR_IMR_SET}, + {R_BE_PHYINFO_ERR_IMR_V1, B_BE_PHYINFO_ERR_IMR_V1_CLR, B_BE_PHYINFO_ERR_IMR_V1_SET}, +}; + +static const struct rtw89_imr_table rtw8922a_imr_cmac_table = { + .regs = rtw8922a_imr_cmac_regs, + .n_regs = ARRAY_SIZE(rtw8922a_imr_cmac_regs), +}; + +static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { + [RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310}, + [RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240}, + [RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO] = {.offset = 0x20000, .size = 0x4800}, + [RTW89_EFUSE_BLOCK_HCI_DIG_USB] = {.offset = 0x30000, .size = 0x890}, + [RTW89_EFUSE_BLOCK_HCI_PHY_PCIE] = {.offset = 0x40000, .size = 0x200}, + [RTW89_EFUSE_BLOCK_HCI_PHY_USB3] = {.offset = 0x50000, .size = 0x80}, + [RTW89_EFUSE_BLOCK_HCI_PHY_USB2] = {.offset = 0x60000, .size = 0x0}, + [RTW89_EFUSE_BLOCK_ADIE] = {.offset = 0x70000, .size = 0x10}, +}; + +static int rtw8922a_pwr_on_func(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + u32 val32; + int ret; + + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_AFSM_WLSUS_EN | + B_BE_AFSM_PCIE_SUS_EN); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_DIS_WLBT_PDNSUSEN_SOPC); + rtw89_write32_set(rtwdev, R_BE_WLLPS_CTRL, B_BE_DIS_WLBT_LPSEN_LOPC); + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APDM_HPDN); + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS); + + ret = read_poll_timeout(rtw89_read32, val32, val32 & B_BE_RDY_SYSPWR, + 1000, 3000000, false, rtwdev, R_BE_SYS_PW_CTRL); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_set(rtwdev, R_BE_WLRESUME_CTRL, B_BE_LPSROP_CMAC0 | + B_BE_LPSROP_CMAC1); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFN_ONMAC); + + ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_APFN_ONMAC), + 1000, 3000000, false, rtwdev, R_BE_SYS_PW_CTRL); + if (ret) + return ret; + + rtw89_write32_clr(rtwdev, R_BE_AFE_ON_CTRL1, B_BE_REG_CK_MON_CK960M_EN); + rtw89_write8_set(rtwdev, R_BE_ANAPAR_POW_MAC, B_BE_POW_PC_LDO_PORT0 | + B_BE_POW_PC_LDO_PORT1); + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_R_SYM_ISO_ADDA_P02PP | + B_BE_R_SYM_ISO_ADDA_P12PP); + rtw89_write8_set(rtwdev, R_BE_PLATFORM_ENABLE, B_BE_PLATFORM_EN); + rtw89_write32_set(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN); + + ret = read_poll_timeout(rtw89_read32, val32, val32 & B_BE_HAXIDMA_IO_ST, + 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL); + if (ret) + return ret; + + ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HAXIDMA_BACKUP_RESTORE_ST), + 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN); + + ret = read_poll_timeout(rtw89_read32, val32, val32 & B_BE_HCI_WLAN_IO_ST, + 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL); + if (ret) + return ret; + + rtw89_write32_clr(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_PCIE_FORCE_IBX_EN); + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL, 0x02, 0x02); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL, 0x01, 0x01); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC1_1P3); + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x40, 0x40); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC0_1P3); + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x20, 0x20); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x04, 0x04); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x08, 0x08); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x10); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0xEB, 0xFF); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0xEB, 0xFF); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x01, 0x01); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x02, 0x02); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x80); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XREF_RF1, 0, 0x40); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XREF_RF2, 0, 0x40); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL_1, 0x40, 0x60); + if (ret) + return ret; + + if (hal->cv != CHIP_CAV) { + rtw89_write32_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK); + rtw89_write32_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE); + rtw89_write32_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B); + + mdelay(1); + + rtw89_write32_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S); + rtw89_write32_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK); + } + + rtw89_write32_set(rtwdev, R_BE_DMAC_FUNC_EN, + B_BE_MAC_FUNC_EN | B_BE_DMAC_FUNC_EN | B_BE_MPDU_PROC_EN | + B_BE_WD_RLS_EN | B_BE_DLE_WDE_EN | B_BE_TXPKT_CTRL_EN | + B_BE_STA_SCH_EN | B_BE_DLE_PLE_EN | B_BE_PKT_BUF_EN | + B_BE_DMAC_TBL_EN | B_BE_PKT_IN_EN | B_BE_DLE_CPUIO_EN | + B_BE_DISPATCHER_EN | B_BE_BBRPT_EN | B_BE_MAC_SEC_EN | + B_BE_H_AXIDMA_EN | B_BE_DMAC_MLO_EN | B_BE_PLRLS_EN | + B_BE_P_AXIDMA_EN | B_BE_DLE_DATACPUIO_EN | B_BE_LTR_CTL_EN); + + set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); + + rtw89_write32_set(rtwdev, R_BE_CMAC_SHARE_FUNC_EN, + B_BE_CMAC_SHARE_EN | B_BE_RESPBA_EN | B_BE_ADDRSRCH_EN | + B_BE_BTCOEX_EN); + rtw89_write32_set(rtwdev, R_BE_CMAC_FUNC_EN, + B_BE_CMAC_EN | B_BE_CMAC_TXEN | B_BE_CMAC_RXEN | + B_BE_SIGB_EN | B_BE_PHYINTF_EN | B_BE_CMAC_DMA_EN | + B_BE_PTCLTOP_EN | B_BE_SCHEDULER_EN | B_BE_TMAC_EN | + B_BE_RMAC_EN | B_BE_TXTIME_EN | B_BE_RESP_PKTCTL_EN); + + set_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); + + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_FEN_BB_IP_RSTN | + B_BE_FEN_BBPLAT_RSTB); + + return 0; +} + +static int rtw8922a_pwr_off_func(struct rtw89_dev *rtwdev) +{ + u32 val32; + int ret; + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x10, 0x10); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x08); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x04); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0xC6, 0xFF); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0xC6, 0xFF); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x80, 0x80); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x02); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x01); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL, 0x02, 0xFF); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL, 0x00, 0xFF); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_R_SYM_ISO_ADDA_P02PP | + B_BE_R_SYM_ISO_ADDA_P12PP); + rtw89_write8_clr(rtwdev, R_BE_ANAPAR_POW_MAC, B_BE_POW_PC_LDO_PORT0 | + B_BE_POW_PC_LDO_PORT1); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write8_clr(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_FEN_BB_IP_RSTN | + B_BE_FEN_BBPLAT_RSTB); + rtw89_write32_clr(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC0_1P3); + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x20); + if (ret) + return ret; + + rtw89_write32_clr(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC1_1P3); + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x40); + if (ret) + return ret; + + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN); + + ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HAXIDMA_IO_ST), + 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL); + if (ret) + return ret; + + ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HAXIDMA_BACKUP_RESTORE_ST), + 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL); + if (ret) + return ret; + + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN); + + ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HCI_WLAN_IO_ST), + 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC); + + ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_APFM_OFFMAC), + 1000, 3000000, false, rtwdev, R_BE_SYS_PW_CTRL); + if (ret) + return ret; + + rtw89_write32(rtwdev, R_BE_WLLPS_CTRL, 0x0000A1B2); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_XTAL_OFF_A_DIE); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS); + rtw89_write32(rtwdev, R_BE_UDM1, 0); + + return 0; +} + +static void rtw8922a_efuse_parsing_tssi(struct rtw89_dev *rtwdev, + struct rtw8922a_efuse *map) +{ + struct rtw8922a_tssi_offset *ofst[] = {&map->path_a_tssi, &map->path_b_tssi}; + u8 *bw40_1s_tssi_6g_ofst[] = {map->bw40_1s_tssi_6g_a, map->bw40_1s_tssi_6g_b}; + struct rtw89_tssi_info *tssi = &rtwdev->tssi; + u8 i, j; + + tssi->thermal[RF_PATH_A] = map->path_a_therm; + tssi->thermal[RF_PATH_B] = map->path_b_therm; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + memcpy(tssi->tssi_cck[i], ofst[i]->cck_tssi, + sizeof(ofst[i]->cck_tssi)); + + for (j = 0; j < TSSI_CCK_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][EFUSE] path=%d cck[%d]=0x%x\n", + i, j, tssi->tssi_cck[i][j]); + + memcpy(tssi->tssi_mcs[i], ofst[i]->bw40_tssi, + sizeof(ofst[i]->bw40_tssi)); + memcpy(tssi->tssi_mcs[i] + TSSI_MCS_2G_CH_GROUP_NUM, + ofst[i]->bw40_1s_tssi_5g, sizeof(ofst[i]->bw40_1s_tssi_5g)); + memcpy(tssi->tssi_6g_mcs[i], bw40_1s_tssi_6g_ofst[i], + sizeof(tssi->tssi_6g_mcs[i])); + + for (j = 0; j < TSSI_MCS_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][EFUSE] path=%d mcs[%d]=0x%x\n", + i, j, tssi->tssi_mcs[i][j]); + } +} + +static void rtw8922a_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, + struct rtw8922a_efuse *map) +{ + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + bool all_0xff = true, all_0x00 = true; + int i, j; + u8 t; + + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_CCK] = map->rx_gain_a._2g_cck; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_CCK] = map->rx_gain_b._2g_cck; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_OFDM] = map->rx_gain_a._2g_ofdm; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_OFDM] = map->rx_gain_b._2g_ofdm; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_LOW] = map->rx_gain_a._5g_low; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_LOW] = map->rx_gain_b._5g_low; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_MID] = map->rx_gain_a._5g_mid; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_MID] = map->rx_gain_b._5g_mid; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH] = map->rx_gain_a._5g_high; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH] = map->rx_gain_b._5g_high; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L0] = map->rx_gain_6g_a._6g_l0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L0] = map->rx_gain_6g_b._6g_l0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L1] = map->rx_gain_6g_a._6g_l1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L1] = map->rx_gain_6g_b._6g_l1; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M0] = map->rx_gain_6g_a._6g_m0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M0] = map->rx_gain_6g_b._6g_m0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M1] = map->rx_gain_6g_a._6g_m1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M1] = map->rx_gain_6g_b._6g_m1; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H0] = map->rx_gain_6g_a._6g_h0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H0] = map->rx_gain_6g_b._6g_h0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H1] = map->rx_gain_6g_a._6g_h1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H1] = map->rx_gain_6g_b._6g_h1; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH0] = map->rx_gain_6g_a._6g_uh0; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH0] = map->rx_gain_6g_b._6g_uh0; + gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH1] = map->rx_gain_6g_a._6g_uh1; + gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH1] = map->rx_gain_6g_b._6g_uh1; + + for (i = RF_PATH_A; i <= RF_PATH_B; i++) + for (j = 0; j < RTW89_GAIN_OFFSET_NR; j++) { + t = gain->offset[i][j]; + if (t != 0xff) + all_0xff = false; + if (t != 0x0) + all_0x00 = false; + + /* transform: sign-bit + U(7,2) to S(8,2) */ + if (t & 0x80) + gain->offset[i][j] = (t ^ 0x7f) + 1; + } + + gain->offset_valid = !all_0xff && !all_0x00; +} + +static void rtw8922a_read_efuse_mac_addr(struct rtw89_dev *rtwdev, u32 addr) +{ + struct rtw89_efuse *efuse = &rtwdev->efuse; + u16 val; + int i; + + for (i = 0; i < ETH_ALEN; i += 2, addr += 2) { + val = rtw89_read16(rtwdev, addr); + efuse->addr[i] = val & 0xff; + efuse->addr[i + 1] = val >> 8; + } +} + +static int rtw8922a_read_efuse_pci_sdio(struct rtw89_dev *rtwdev, u8 *log_map) +{ + struct rtw89_efuse *efuse = &rtwdev->efuse; + + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw8922a_read_efuse_mac_addr(rtwdev, 0x3104); + else + ether_addr_copy(efuse->addr, log_map + 0x001A); + + return 0; +} + +static int rtw8922a_read_efuse_usb(struct rtw89_dev *rtwdev, u8 *log_map) +{ + rtw8922a_read_efuse_mac_addr(rtwdev, 0x4078); + + return 0; +} + +static int rtw8922a_read_efuse_rf(struct rtw89_dev *rtwdev, u8 *log_map) +{ + struct rtw8922a_efuse *map = (struct rtw8922a_efuse *)log_map; + struct rtw89_efuse *efuse = &rtwdev->efuse; + + efuse->rfe_type = map->rfe_type; + efuse->xtal_cap = map->xtal_k; + efuse->country_code[0] = map->country_code[0]; + efuse->country_code[1] = map->country_code[1]; + rtw8922a_efuse_parsing_tssi(rtwdev, map); + rtw8922a_efuse_parsing_gain_offset(rtwdev, map); + + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); + + return 0; +} + +static int rtw8922a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, + enum rtw89_efuse_block block) +{ + switch (block) { + case RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO: + return rtw8922a_read_efuse_pci_sdio(rtwdev, log_map); + case RTW89_EFUSE_BLOCK_HCI_DIG_USB: + return rtw8922a_read_efuse_usb(rtwdev, log_map); + case RTW89_EFUSE_BLOCK_RF: + return rtw8922a_read_efuse_rf(rtwdev, log_map); + default: + return 0; + } +} + +#define THM_TRIM_POSITIVE_MASK BIT(6) +#define THM_TRIM_MAGNITUDE_MASK GENMASK(5, 0) + +static void rtw8922a_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + static const u32 thm_trim_addr[RF_PATH_NUM_8922A] = {0x1706, 0x1733}; + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u32 addr = rtwdev->chip->phycap_addr; + bool pg = true; + u8 pg_th; + s8 val; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + pg_th = phycap_map[thm_trim_addr[i] - addr]; + if (pg_th == 0xff) { + info->thermal_trim[i] = 0; + pg = false; + break; + } + + val = u8_get_bits(pg_th, THM_TRIM_MAGNITUDE_MASK); + + if (!(pg_th & THM_TRIM_POSITIVE_MASK)) + val *= -1; + + info->thermal_trim[i] = val; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[THERMAL][TRIM] path=%d thermal_trim=0x%x (%d)\n", + i, pg_th, val); + } + + info->pg_thermal_trim = pg; +} + +static void rtw8922a_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + static const u32 pabias_trim_addr[RF_PATH_NUM_8922A] = {0x1707, 0x1734}; + static const u32 check_pa_pad_trim_addr = 0x1700; + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u32 addr = rtwdev->chip->phycap_addr; + u8 val; + u8 i; + + val = phycap_map[check_pa_pad_trim_addr - addr]; + if (val != 0xff) + info->pg_pa_bias_trim = true; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n", + i, info->pa_bias_trim[i]); + } +} + +static void rtw8922a_phycap_parsing_pad_bias_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + static const u32 pad_bias_trim_addr[RF_PATH_NUM_8922A] = {0x1708, 0x1735}; + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u32 addr = rtwdev->chip->phycap_addr; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + info->pad_bias_trim[i] = phycap_map[pad_bias_trim_addr[i] - addr]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PAD_BIAS][TRIM] path=%d pad_bias_trim=0x%x\n", + i, info->pad_bias_trim[i]); + } +} + +static int rtw8922a_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + rtw8922a_phycap_parsing_thermal_trim(rtwdev, phycap_map); + rtw8922a_phycap_parsing_pa_bias_trim(rtwdev, phycap_map); + rtw8922a_phycap_parsing_pad_bias_trim(rtwdev, phycap_map); + + return 0; +} + +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = RTW89_MAX_PATTERN_NUM, + .pattern_max_len = RTW89_MAX_PATTERN_SIZE, + .pattern_min_len = 1, +}; +#endif + +static const struct rtw89_chip_ops rtw8922a_chip_ops = { + .read_efuse = rtw8922a_read_efuse, + .read_phycap = rtw8922a_read_phycap, + .pwr_on_func = rtw8922a_pwr_on_func, + .pwr_off_func = rtw8922a_pwr_off_func, +}; + +const struct rtw89_chip_info rtw8922a_chip_info = { + .chip_id = RTL8922A, + .chip_gen = RTW89_CHIP_BE, + .ops = &rtw8922a_chip_ops, + .mac_def = &rtw89_mac_gen_be, + .phy_def = &rtw89_phy_gen_be, + .fw_basename = RTW8922A_FW_BASENAME, + .fw_format_max = RTW8922A_FW_FORMAT_MAX, + .try_ce_fw = false, + .bbmcu_nr = 1, + .needed_fw_elms = RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS, + .fifo_size = 589824, + .small_fifo_size = false, + .dle_scc_rsvd_size = 0, + .max_amsdu_limit = 8000, + .dis_2g_40m_ul_ofdma = false, + .rsvd_ple_ofst = 0x8f800, + .hfc_param_ini = rtw8922a_hfc_param_ini_pcie, + .dle_mem = rtw8922a_dle_mem_pcie, + .wde_qempty_acq_grpnum = 4, + .wde_qempty_mgq_grpsel = 4, + .rf_base_addr = {0xe000, 0xf000}, + .pwr_on_seq = NULL, + .pwr_off_seq = NULL, + .bb_table = NULL, + .bb_gain_table = NULL, + .rf_table = {}, + .nctl_table = NULL, + .nctl_post_table = NULL, + .dflt_parms = NULL, /* load parm from fw */ + .rfe_parms_conf = NULL, /* load parm from fw */ + .txpwr_factor_rf = 2, + .txpwr_factor_mac = 1, + .dig_table = NULL, + .tssi_dbw_table = NULL, + .support_chanctx_num = 1, + .support_bands = BIT(NL80211_BAND_2GHZ) | + BIT(NL80211_BAND_5GHZ) | + BIT(NL80211_BAND_6GHZ), + .support_unii4 = true, + .ul_tb_waveform_ctrl = false, + .ul_tb_pwr_diff = false, + .hw_sec_hdr = true, + .rf_path_num = 2, + .tx_nss = 2, + .rx_nss = 2, + .acam_num = 128, + .bcam_num = 20, + .scam_num = 32, + .bacam_num = 8, + .bacam_dynamic_num = 8, + .bacam_ver = RTW89_BACAM_V1, + .ppdu_max_usr = 16, + .sec_ctrl_efuse_size = 4, + .physical_efuse_size = 0x1300, + .logical_efuse_size = 0x70000, + .limit_efuse_size = 0x40000, + .dav_phy_efuse_size = 0, + .dav_log_efuse_size = 0, + .efuse_blocks = rtw8922a_efuse_blocks, + .phycap_addr = 0x1700, + .phycap_size = 0x38, + + .ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) | + BIT(RTW89_PS_MODE_CLK_GATED) | + BIT(RTW89_PS_MODE_PWR_GATED), + .low_power_hci_modes = 0, + .hci_func_en_addr = R_BE_HCI_FUNC_EN, + .h2c_desc_size = sizeof(struct rtw89_rxdesc_short_v2), + .txwd_body_size = sizeof(struct rtw89_txwd_body_v2), + .txwd_info_size = sizeof(struct rtw89_txwd_info_v2), + .cfo_src_fd = true, + .cfo_hw_comp = true, + .dcfo_comp = NULL, + .dcfo_comp_sft = 0, + .imr_info = NULL, + .imr_dmac_table = &rtw8922a_imr_dmac_table, + .imr_cmac_table = &rtw8922a_imr_cmac_table, + .bss_clr_vld = {R_BSS_CLR_VLD_V2, B_BSS_CLR_VLD0_V2}, + .bss_clr_map_reg = R_BSS_CLR_MAP_V2, + .dma_ch_mask = 0, +#ifdef CONFIG_PM + .wowlan_stub = &rtw_wowlan_stub_8922a, +#endif + .xtal_info = NULL, +}; +EXPORT_SYMBOL(rtw8922a_chip_info); + +MODULE_FIRMWARE(RTW8922A_MODULE_FIRMWARE); +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11be wireless 8922A driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.h b/drivers/net/wireless/realtek/rtw89/rtw8922a.h new file mode 100644 index 0000000000..597317ab6a --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2023 Realtek Corporation + */ + +#ifndef __RTW89_8922A_H__ +#define __RTW89_8922A_H__ + +#include "core.h" + +#define RF_PATH_NUM_8922A 2 +#define BB_PATH_NUM_8922A 2 + +struct rtw8922a_tssi_offset { + u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM]; + u8 bw40_tssi[TSSI_MCS_2G_CH_GROUP_NUM]; + u8 rsvd[7]; + u8 bw40_1s_tssi_5g[TSSI_MCS_5G_CH_GROUP_NUM]; + u8 bw_diff_5g[10]; +} __packed; + +struct rtw8922a_rx_gain { + u8 _2g_ofdm; + u8 _2g_cck; + u8 _5g_low; + u8 _5g_mid; + u8 _5g_high; +} __packed; + +struct rtw8922a_rx_gain_6g { + u8 _6g_l0; + u8 _6g_l1; + u8 _6g_m0; + u8 _6g_m1; + u8 _6g_h0; + u8 _6g_h1; + u8 _6g_uh0; + u8 _6g_uh1; +} __packed; + +struct rtw8922a_efuse { + u8 country_code[2]; + u8 rsvd[0xe]; + struct rtw8922a_tssi_offset path_a_tssi; + struct rtw8922a_tssi_offset path_b_tssi; + u8 rsvd1[0x54]; + u8 channel_plan; + u8 xtal_k; + u8 rsvd2[0x7]; + u8 board_info; + u8 rsvd3[0x8]; + u8 rfe_type; + u8 rsvd4[0x5]; + u8 path_a_therm; + u8 path_b_therm; + u8 rsvd5[0x2]; + struct rtw8922a_rx_gain rx_gain_a; + struct rtw8922a_rx_gain rx_gain_b; + u8 rsvd6[0x22]; + u8 bw40_1s_tssi_6g_a[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd7[0xa]; + u8 bw40_1s_tssi_6g_b[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd8[0xa]; + u8 bw40_1s_tssi_6g_c[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd9[0xa]; + u8 bw40_1s_tssi_6g_d[TSSI_MCS_6G_CH_GROUP_NUM]; + u8 rsvd10[0xa]; + struct rtw8922a_rx_gain_6g rx_gain_6g_a; + struct rtw8922a_rx_gain_6g rx_gain_6g_b; +} __packed; + +extern const struct rtw89_chip_info rtw8922a_chip_info; + +#endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c new file mode 100644 index 0000000000..9f46fb1661 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include <linux/module.h> +#include <linux/pci.h> + +#include "pci.h" +#include "reg.h" +#include "rtw8922a.h" + +static const struct rtw89_pci_info rtw8922a_pci_info = { + .gen_def = &rtw89_pci_gen_be, + .txbd_trunc_mode = MAC_AX_BD_TRUNC, + .rxbd_trunc_mode = MAC_AX_BD_TRUNC, + .rxbd_mode = MAC_AX_RXBD_PKT, + .tag_mode = MAC_AX_TAG_MULTI, + .tx_burst = MAC_AX_TX_BURST_V1_256B, + .rx_burst = MAC_AX_RX_BURST_V1_128B, + .wd_dma_idle_intvl = MAC_AX_WD_DMA_INTVL_256NS, + .wd_dma_act_intvl = MAC_AX_WD_DMA_INTVL_256NS, + .multi_tag_num = MAC_AX_TAG_NUM_8, + .lbc_en = MAC_AX_PCIE_ENABLE, + .lbc_tmr = MAC_AX_LBC_TMR_2MS, + .autok_en = MAC_AX_PCIE_DISABLE, + .io_rcy_en = MAC_AX_PCIE_ENABLE, + .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF, + .rx_ring_eq_is_full = true, + .check_rx_tag = true, + + .init_cfg_reg = R_BE_HAXI_INIT_CFG1, + .txhci_en_bit = B_BE_TXDMA_EN, + .rxhci_en_bit = B_BE_RXDMA_EN, + .rxbd_mode_bit = B_BE_RXQ_RXBD_MODE_MASK, + .exp_ctrl_reg = R_BE_HAXI_EXP_CTRL_V1, + .max_tag_num_mask = B_BE_MAX_TAG_NUM_MASK, + .rxbd_rwptr_clr_reg = R_BE_RXBD_RWPTR_CLR1_V1, + .txbd_rwptr_clr2_reg = R_BE_TXBD_RWPTR_CLR1, + .dma_io_stop = {R_BE_HAXI_INIT_CFG1, B_BE_STOP_AXI_MST}, + .dma_stop1 = {R_BE_HAXI_DMA_STOP1, B_BE_TX_STOP1_MASK}, + .dma_stop2 = {0}, + .dma_busy1 = {R_BE_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK_BE}, + .dma_busy2_reg = 0, + .dma_busy3_reg = R_BE_HAXI_DMA_BUSY1, + + .rpwm_addr = R_BE_PCIE_HRPWM, + .cpwm_addr = R_BE_PCIE_CRPWM, + .mit_addr = R_BE_PCIE_MIT_CH_EN, + .tx_dma_ch_mask = 0, + .bd_idx_addr_low_power = NULL, + .dma_addr_set = &rtw89_pci_ch_dma_addr_set_be, + .bd_ram_table = NULL, + + .ltr_set = rtw89_pci_ltr_set_v2, + .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1, + .config_intr_mask = rtw89_pci_config_intr_mask_v2, + .enable_intr = rtw89_pci_enable_intr_v2, + .disable_intr = rtw89_pci_disable_intr_v2, + .recognize_intrs = rtw89_pci_recognize_intrs_v2, +}; + +static const struct rtw89_driver_info rtw89_8922ae_info = { + .chip = &rtw8922a_chip_info, + .bus = { + .pci = &rtw8922a_pci_info, + }, +}; + +static const struct pci_device_id rtw89_8922ae_id_table[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8922), + .driver_data = (kernel_ulong_t)&rtw89_8922ae_info, + }, + {}, +}; +MODULE_DEVICE_TABLE(pci, rtw89_8922ae_id_table); + +static struct pci_driver rtw89_8922ae_driver = { + .name = "rtw89_8922ae", + .id_table = rtw89_8922ae_id_table, + .probe = rtw89_pci_probe, + .remove = rtw89_pci_remove, + .driver.pm = &rtw89_pm_ops, +}; +module_pci_driver(rtw89_8922ae_driver); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11be wireless 8922AE driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c index aed05b026c..1b2a400406 100644 --- a/drivers/net/wireless/realtek/rtw89/sar.c +++ b/drivers/net/wireless/realtek/rtw89/sar.c @@ -404,16 +404,18 @@ out: void rtw89_tas_init(struct rtw89_dev *rtwdev) { struct rtw89_tas_info *tas = &rtwdev->tas; + struct rtw89_acpi_dsm_result res = {}; int ret; u8 val; - ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &val); + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &res); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_SAR, "acpi: cannot get TAS: %d\n", ret); return; } + val = res.u.value; switch (val) { case 0: tas->enable = false; diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index c164435305..99896d85d2 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -361,6 +361,9 @@ static int hal_enable_dma(struct rtw89_ser *ser) ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_2); if (!ret) clear_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); + else + rtw89_debug(rtwdev, RTW89_DBG_SER, + "lv1 rcvy fail to start dma: %d\n", ret); return ret; } @@ -376,6 +379,9 @@ static int hal_stop_dma(struct rtw89_ser *ser) ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_1); if (!ret) set_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); + else + rtw89_debug(rtwdev, RTW89_DBG_SER, + "lv1 rcvy fail to stop dma: %d\n", ret); return ret; } @@ -584,6 +590,14 @@ struct __fw_backtrace_info { static_assert(RTW89_FW_BACKTRACE_INFO_SIZE == sizeof(struct __fw_backtrace_info)); +static u32 convert_addr_from_wcpu(u32 wcpu_addr) +{ + if (wcpu_addr < 0x30000000) + return wcpu_addr; + + return wcpu_addr & GENMASK(28, 0); +} + static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf, const struct __fw_backtrace_entry *ent) { @@ -591,7 +605,7 @@ static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf, const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 filter_model_addr = mac->filter_model_addr; u32 indir_access_addr = mac->indir_access_addr; - u32 fwbt_addr = ent->wcpu_addr & RTW89_WCPU_BASE_MASK; + u32 fwbt_addr = convert_addr_from_wcpu(ent->wcpu_addr); u32 fwbt_size = ent->size; u32 fwbt_key = ent->key; u32 i; diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 7142cce167..c467a80ffa 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -416,8 +416,11 @@ struct rtw89_rxinfo { } __packed; #define RTW89_RXINFO_W0_USR_NUM GENMASK(3, 0) +#define RTW89_RXINFO_W0_USR_NUM_V1 GENMASK(4, 0) #define RTW89_RXINFO_W0_FW_DEFINE GENMASK(15, 8) +#define RTW89_RXINFO_W0_PLCP_LEN_V1 GENMASK(23, 16) #define RTW89_RXINFO_W0_LSIG_LEN GENMASK(27, 16) +#define RTW89_RXINFO_W0_INVALID_V1 BIT(27) #define RTW89_RXINFO_W0_IS_TO_SELF BIT(28) #define RTW89_RXINFO_W0_RX_CNT_VLD BIT(29) #define RTW89_RXINFO_W0_LONG_RXD GENMASK(31, 30) @@ -430,6 +433,7 @@ struct rtw89_phy_sts_hdr { } __packed; #define RTW89_PHY_STS_HDR_W0_IE_MAP GENMASK(4, 0) +#define RTW89_PHY_STS_HDR_W0_VALID BIT(7) #define RTW89_PHY_STS_HDR_W0_LEN GENMASK(15, 8) #define RTW89_PHY_STS_HDR_W0_RSSI_AVG GENMASK(31, 24) #define RTW89_PHY_STS_HDR_W1_RSSI_A GENMASK(7, 0) diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 660bf2ece9..5c7ca36c09 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -73,13 +73,14 @@ static int rtw89_wow_config_mac(struct rtw89_dev *rtwdev, bool enable_wow) static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; enum rtw89_mac_fwd_target fwd_target = enable ? RTW89_FWD_DONT_CARE : RTW89_FWD_TO_HOST; - rtw89_mac_typ_fltr_opt(rtwdev, RTW89_MGNT, fwd_target, RTW89_MAC_0); - rtw89_mac_typ_fltr_opt(rtwdev, RTW89_CTRL, fwd_target, RTW89_MAC_0); - rtw89_mac_typ_fltr_opt(rtwdev, RTW89_DATA, fwd_target, RTW89_MAC_0); + mac->typ_fltr_opt(rtwdev, RTW89_MGNT, fwd_target, RTW89_MAC_0); + mac->typ_fltr_opt(rtwdev, RTW89_CTRL, fwd_target, RTW89_MAC_0); + mac->typ_fltr_opt(rtwdev, RTW89_DATA, fwd_target, RTW89_MAC_0); } static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c index 301bd0043a..4e5b351f80 100644 --- a/drivers/net/wireless/ti/wl1251/sdio.c +++ b/drivers/net/wireless/ti/wl1251/sdio.c @@ -343,5 +343,6 @@ static void __exit wl1251_sdio_exit(void) module_init(wl1251_sdio_init); module_exit(wl1251_sdio_exit); +MODULE_DESCRIPTION("TI WL1251 SDIO helpers"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index 29292f06bd..1936bb3af5 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -342,6 +342,7 @@ static struct spi_driver wl1251_spi_driver = { module_spi_driver(wl1251_spi_driver); +MODULE_DESCRIPTION("TI WL1251 SPI helpers"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); MODULE_ALIAS("spi:wl1251"); diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index de045fe4ca..b26d42b4e3 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -1955,6 +1955,7 @@ module_param_named(tcxo, tcxo_param, charp, 0); MODULE_PARM_DESC(tcxo, "TCXO clock: 19.2, 26, 38.4, 52, 16.368, 32.736, 16.8, 33.6"); +MODULE_DESCRIPTION("TI WL12xx wireless driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 20d9181b34..2ccac1cdec 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -2086,6 +2086,7 @@ module_param_named(num_rx_desc, num_rx_desc_param, int, 0400); MODULE_PARM_DESC(num_rx_desc_param, "Number of Rx descriptors: u8 (default is 32)"); +MODULE_DESCRIPTION("TI WiLink 8 wireless driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_FIRMWARE(WL18XX_FW_NAME); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index fb9ed97774..5736acb4d2 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -6793,6 +6793,7 @@ MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); module_param(no_recovery, int, 0600); MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck."); +MODULE_DESCRIPTION("TI WLAN core driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index f0686635db..eb5482ed76 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -447,6 +447,7 @@ module_sdio_driver(wl1271_sdio_driver); module_param(dump, bool, 0600); MODULE_PARM_DESC(dump, "Enable sdio read/write dumps."); +MODULE_DESCRIPTION("TI WLAN SDIO helpers"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 7d9a139db5..0aa2b2f3c5 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -562,6 +562,7 @@ static struct spi_driver wl1271_spi_driver = { }; module_spi_driver(wl1271_spi_driver); +MODULE_DESCRIPTION("TI WLAN SPI helpers"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index c7b4414cc6..a9c3fb2ccd 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -190,10 +190,25 @@ static const struct ieee80211_regdomain hwsim_world_regdom_custom_03 = { } }; +static const struct ieee80211_regdomain hwsim_world_regdom_custom_04 = { + .n_reg_rules = 6, + .alpha2 = "99", + .reg_rules = { + REG_RULE(2412 - 10, 2462 + 10, 40, 0, 20, 0), + REG_RULE(2484 - 10, 2484 + 10, 40, 0, 20, 0), + REG_RULE(5150 - 10, 5240 + 10, 80, 0, 30, 0), + REG_RULE(5260 - 10, 5320 + 10, 80, 0, 30, + NL80211_RRF_DFS_CONCURRENT | NL80211_RRF_DFS), + REG_RULE(5745 - 10, 5825 + 10, 80, 0, 30, 0), + REG_RULE(5855 - 10, 5925 + 10, 80, 0, 33, 0), + } +}; + static const struct ieee80211_regdomain *hwsim_world_regdom_custom[] = { &hwsim_world_regdom_custom_01, &hwsim_world_regdom_custom_02, &hwsim_world_regdom_custom_03, + &hwsim_world_regdom_custom_04, }; struct hwsim_vif_priv { @@ -3803,7 +3818,7 @@ static int hwsim_pmsr_report_nl(struct sk_buff *msg, struct genl_info *info) } nla_for_each_nested(peer, peers, rem) { - struct cfg80211_pmsr_result result; + struct cfg80211_pmsr_result result = {}; err = mac80211_hwsim_parse_pmsr_result(peer, &result, info); if (err) @@ -4029,6 +4044,8 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = { IEEE80211_HE_MAC_CAP3_OMI_CONTROL | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G, .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | @@ -4134,6 +4151,8 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = { IEEE80211_HE_MAC_CAP3_OMI_CONTROL | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G, .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | @@ -4237,6 +4256,8 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = { IEEE80211_HE_MAC_CAP3_OMI_CONTROL | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G, .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | @@ -5288,6 +5309,10 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, schedule_timeout_interruptible(1); } + /* TODO: Add param */ + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_DFS_CONCURRENT); + if (param->no_vif) ieee80211_hw_set(hw, NO_AUTO_VIF); diff --git a/drivers/net/wireless/zydas/Kconfig b/drivers/net/wireless/zydas/Kconfig index 08574433df..839e1217e8 100644 --- a/drivers/net/wireless/zydas/Kconfig +++ b/drivers/net/wireless/zydas/Kconfig @@ -12,25 +12,6 @@ config WLAN_VENDOR_ZYDAS if WLAN_VENDOR_ZYDAS -config USB_ZD1201 - tristate "USB ZD1201 based Wireless device support" - depends on CFG80211 && USB - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - help - Say Y if you want to use wireless LAN adapters based on the ZyDAS - ZD1201 chip. - - This driver makes the adapter appear as a normal Ethernet interface, - typically on wlan0. - - The zd1201 device requires external firmware to be loaded. - This can be found at http://linux-lc100020.sourceforge.net/ - - To compile this driver as a module, choose M here: the - module will be called zd1201. - source "drivers/net/wireless/zydas/zd1211rw/Kconfig" endif # WLAN_VENDOR_ZYDAS diff --git a/drivers/net/wireless/zydas/Makefile b/drivers/net/wireless/zydas/Makefile index c70003d30a..3e0a51db98 100644 --- a/drivers/net/wireless/zydas/Makefile +++ b/drivers/net/wireless/zydas/Makefile @@ -1,4 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_ZD1211RW) += zd1211rw/ - -obj-$(CONFIG_USB_ZD1201) += zd1201.o diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c deleted file mode 100644 index 2814df1ecc..0000000000 --- a/drivers/net/wireless/zydas/zd1201.c +++ /dev/null @@ -1,1909 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for ZyDAS zd1201 based USB wireless devices. - * - * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) - * - * Parts of this driver have been derived from a wlan-ng version - * modified by ZyDAS. They also made documentation available, thanks! - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/wireless.h> -#include <net/cfg80211.h> -#include <net/iw_handler.h> -#include <linux/string.h> -#include <linux/if_arp.h> -#include <linux/firmware.h> -#include "zd1201.h" - -static const struct usb_device_id zd1201_table[] = { - {USB_DEVICE(0x0586, 0x3400)}, /* Peabird USB Wireless Adapter */ - {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 USB Wireless Adapter */ - {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */ - {USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */ - {USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */ - {USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */ - {} -}; - -static int ap; /* Are we an AP or a normal station? */ - -#define ZD1201_VERSION "0.15" - -MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>"); -MODULE_DESCRIPTION("Driver for ZyDAS ZD1201 based USB Wireless adapters"); -MODULE_VERSION(ZD1201_VERSION); -MODULE_LICENSE("GPL"); -module_param(ap, int, 0); -MODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded"); -MODULE_DEVICE_TABLE(usb, zd1201_table); - - -static int zd1201_fw_upload(struct usb_device *dev, int apfw) -{ - const struct firmware *fw_entry; - const char *data; - unsigned long len; - int err; - unsigned char ret; - char *buf; - char *fwfile; - - if (apfw) - fwfile = "zd1201-ap.fw"; - else - fwfile = "zd1201.fw"; - - err = request_firmware(&fw_entry, fwfile, &dev->dev); - if (err) { - dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile); - dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n"); - dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info.\n"); - return err; - } - - data = fw_entry->data; - len = fw_entry->size; - - buf = kmalloc(1024, GFP_ATOMIC); - if (!buf) { - err = -ENOMEM; - goto exit; - } - - while (len > 0) { - int translen = (len > 1024) ? 1024 : len; - memcpy(buf, data, translen); - - err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0, - USB_DIR_OUT | 0x40, 0, 0, buf, translen, - ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - len -= translen; - data += translen; - } - - err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x2, - USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4, - USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - memcpy(&ret, buf, sizeof(ret)); - - if (ret & 0x80) { - err = -EIO; - goto exit; - } - - err = 0; -exit: - kfree(buf); - release_firmware(fw_entry); - return err; -} - -MODULE_FIRMWARE("zd1201-ap.fw"); -MODULE_FIRMWARE("zd1201.fw"); - -static void zd1201_usbfree(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - - switch(urb->status) { - case -EILSEQ: - case -ENODEV: - case -ETIME: - case -ENOENT: - case -EPIPE: - case -EOVERFLOW: - case -ESHUTDOWN: - dev_warn(&zd->usb->dev, "%s: urb failed: %d\n", - zd->dev->name, urb->status); - } - - kfree(urb->transfer_buffer); - usb_free_urb(urb); -} - -/* cmdreq message: - u32 type - u16 cmd - u16 parm0 - u16 parm1 - u16 parm2 - u8 pad[4] - - total: 4 + 2 + 2 + 2 + 2 + 4 = 16 -*/ -static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, - int parm1, int parm2) -{ - unsigned char *command; - int ret; - struct urb *urb; - - command = kmalloc(16, GFP_ATOMIC); - if (!command) - return -ENOMEM; - - *((__le32*)command) = cpu_to_le32(ZD1201_USB_CMDREQ); - *((__le16*)&command[4]) = cpu_to_le16(cmd); - *((__le16*)&command[6]) = cpu_to_le16(parm0); - *((__le16*)&command[8]) = cpu_to_le16(parm1); - *((__le16*)&command[10])= cpu_to_le16(parm2); - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - kfree(command); - return -ENOMEM; - } - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), - command, 16, zd1201_usbfree, zd); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - kfree(command); - usb_free_urb(urb); - } - - return ret; -} - -/* Callback after sending out a packet */ -static void zd1201_usbtx(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - netif_wake_queue(zd->dev); -} - -/* Incoming data */ -static void zd1201_usbrx(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - int free = 0; - unsigned char *data = urb->transfer_buffer; - struct sk_buff *skb; - unsigned char type; - - if (!zd) - return; - - switch(urb->status) { - case -EILSEQ: - case -ENODEV: - case -ETIME: - case -ENOENT: - case -EPIPE: - case -EOVERFLOW: - case -ESHUTDOWN: - dev_warn(&zd->usb->dev, "%s: rx urb failed: %d\n", - zd->dev->name, urb->status); - free = 1; - goto exit; - } - - if (urb->status != 0 || urb->actual_length == 0) - goto resubmit; - - type = data[0]; - if (type == ZD1201_PACKET_EVENTSTAT || type == ZD1201_PACKET_RESOURCE) { - memcpy(zd->rxdata, data, urb->actual_length); - zd->rxlen = urb->actual_length; - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - } - /* Info frame */ - if (type == ZD1201_PACKET_INQUIRE) { - int i = 0; - unsigned short infotype, copylen; - infotype = le16_to_cpu(*(__le16*)&data[6]); - - if (infotype == ZD1201_INF_LINKSTATUS) { - short linkstatus; - - linkstatus = le16_to_cpu(*(__le16*)&data[8]); - switch(linkstatus) { - case 1: - netif_carrier_on(zd->dev); - break; - case 2: - netif_carrier_off(zd->dev); - break; - case 3: - netif_carrier_off(zd->dev); - break; - case 4: - netif_carrier_on(zd->dev); - break; - default: - netif_carrier_off(zd->dev); - } - goto resubmit; - } - if (infotype == ZD1201_INF_ASSOCSTATUS) { - short status = le16_to_cpu(*(__le16*)(data+8)); - int event; - union iwreq_data wrqu; - - switch (status) { - case ZD1201_ASSOCSTATUS_STAASSOC: - case ZD1201_ASSOCSTATUS_REASSOC: - event = IWEVREGISTERED; - break; - case ZD1201_ASSOCSTATUS_DISASSOC: - case ZD1201_ASSOCSTATUS_ASSOCFAIL: - case ZD1201_ASSOCSTATUS_AUTHFAIL: - default: - event = IWEVEXPIRED; - } - memcpy(wrqu.addr.sa_data, data+10, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(zd->dev, event, &wrqu, NULL); - - goto resubmit; - } - if (infotype == ZD1201_INF_AUTHREQ) { - union iwreq_data wrqu; - - memcpy(wrqu.addr.sa_data, data+8, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - /* There isn't a event that trully fits this request. - We assume that userspace will be smart enough to - see a new station being expired and sends back a - authstation ioctl to authorize it. */ - wireless_send_event(zd->dev, IWEVEXPIRED, &wrqu, NULL); - goto resubmit; - } - /* Other infotypes are handled outside this handler */ - zd->rxlen = 0; - while (i < urb->actual_length) { - copylen = le16_to_cpu(*(__le16*)&data[i+2]); - /* Sanity check, sometimes we get junk */ - if (copylen+zd->rxlen > sizeof(zd->rxdata)) - break; - memcpy(zd->rxdata+zd->rxlen, data+i+4, copylen); - zd->rxlen += copylen; - i += 64; - } - if (i >= urb->actual_length) { - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - } - goto resubmit; - } - /* Actual data */ - if (data[urb->actual_length-1] == ZD1201_PACKET_RXDATA) { - int datalen = urb->actual_length-1; - unsigned short len, fc, seq; - - len = ntohs(*(__be16 *)&data[datalen-2]); - if (len>datalen) - len=datalen; - fc = le16_to_cpu(*(__le16 *)&data[datalen-16]); - seq = le16_to_cpu(*(__le16 *)&data[datalen-24]); - - if (zd->monitor) { - if (datalen < 24) - goto resubmit; - if (!(skb = dev_alloc_skb(datalen+24))) - goto resubmit; - - skb_put_data(skb, &data[datalen - 16], 2); - skb_put_data(skb, &data[datalen - 2], 2); - skb_put_data(skb, &data[datalen - 14], 6); - skb_put_data(skb, &data[datalen - 22], 6); - skb_put_data(skb, &data[datalen - 8], 6); - skb_put_data(skb, &data[datalen - 24], 2); - skb_put_data(skb, data, len); - skb->protocol = eth_type_trans(skb, zd->dev); - zd->dev->stats.rx_packets++; - zd->dev->stats.rx_bytes += skb->len; - netif_rx(skb); - goto resubmit; - } - - if ((seq & IEEE80211_SCTL_FRAG) || - (fc & IEEE80211_FCTL_MOREFRAGS)) { - struct zd1201_frag *frag = NULL; - char *ptr; - - if (datalen<14) - goto resubmit; - if ((seq & IEEE80211_SCTL_FRAG) == 0) { - frag = kmalloc(sizeof(*frag), GFP_ATOMIC); - if (!frag) - goto resubmit; - skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2); - if (!skb) { - kfree(frag); - goto resubmit; - } - frag->skb = skb; - frag->seq = seq & IEEE80211_SCTL_SEQ; - skb_reserve(skb, 2); - skb_put_data(skb, &data[datalen - 14], 12); - skb_put_data(skb, &data[6], 2); - skb_put_data(skb, data + 8, len); - hlist_add_head(&frag->fnode, &zd->fraglist); - goto resubmit; - } - hlist_for_each_entry(frag, &zd->fraglist, fnode) - if (frag->seq == (seq&IEEE80211_SCTL_SEQ)) - break; - if (!frag) - goto resubmit; - skb = frag->skb; - ptr = skb_put(skb, len); - if (ptr) - memcpy(ptr, data+8, len); - if (fc & IEEE80211_FCTL_MOREFRAGS) - goto resubmit; - hlist_del_init(&frag->fnode); - kfree(frag); - } else { - if (datalen<14) - goto resubmit; - skb = dev_alloc_skb(len + 14 + 2); - if (!skb) - goto resubmit; - skb_reserve(skb, 2); - skb_put_data(skb, &data[datalen - 14], 12); - skb_put_data(skb, &data[6], 2); - skb_put_data(skb, data + 8, len); - } - skb->protocol = eth_type_trans(skb, zd->dev); - zd->dev->stats.rx_packets++; - zd->dev->stats.rx_bytes += skb->len; - netif_rx(skb); - } -resubmit: - memset(data, 0, ZD1201_RXSIZE); - - urb->status = 0; - urb->dev = zd->usb; - if(usb_submit_urb(urb, GFP_ATOMIC)) - free = 1; - -exit: - if (free) { - zd->rxlen = 0; - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - kfree(urb->transfer_buffer); - } -} - -static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata, - unsigned int riddatalen) -{ - int err; - int i = 0; - int code; - int rid_fid; - int length; - unsigned char *pdata; - - zd->rxdatas = 0; - err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0); - if (err) - return err; - - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - code = le16_to_cpu(*(__le16*)(&zd->rxdata[4])); - rid_fid = le16_to_cpu(*(__le16*)(&zd->rxdata[6])); - length = le16_to_cpu(*(__le16*)(&zd->rxdata[8])); - if (length > zd->rxlen) - length = zd->rxlen-6; - - /* If access bit is not on, then error */ - if ((code & ZD1201_ACCESSBIT) != ZD1201_ACCESSBIT || rid_fid != rid ) - return -EINVAL; - - /* Not enough buffer for allocating data */ - if (riddatalen != (length - 4)) { - dev_dbg(&zd->usb->dev, "riddatalen mismatches, expected=%u, (packet=%u) length=%u, rid=0x%04X, rid_fid=0x%04X\n", - riddatalen, zd->rxlen, length, rid, rid_fid); - return -ENODATA; - } - - zd->rxdatas = 0; - /* Issue SetRxRid commnd */ - err = zd1201_docmd(zd, ZD1201_CMDCODE_SETRXRID, rid, 0, length); - if (err) - return err; - - /* Receive RID record from resource packets */ - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - if (zd->rxdata[zd->rxlen - 1] != ZD1201_PACKET_RESOURCE) { - dev_dbg(&zd->usb->dev, "Packet type mismatch: 0x%x not 0x3\n", - zd->rxdata[zd->rxlen-1]); - return -EINVAL; - } - - /* Set the data pointer and received data length */ - pdata = zd->rxdata; - length = zd->rxlen; - - do { - int actual_length; - - actual_length = (length > 64) ? 64 : length; - - if (pdata[0] != 0x3) { - dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n", - pdata[0]); - return -EINVAL; - } - - if (actual_length != 64) { - /* Trim the last packet type byte */ - actual_length--; - } - - /* Skip the 4 bytes header (RID length and RID) */ - if (i == 0) { - pdata += 8; - actual_length -= 8; - } else { - pdata += 4; - actual_length -= 4; - } - - memcpy(riddata, pdata, actual_length); - riddata += actual_length; - pdata += actual_length; - length -= 64; - i++; - } while (length > 0); - - return 0; -} - -/* - * resreq: - * byte type - * byte sequence - * u16 reserved - * byte data[12] - * total: 16 - */ -static int zd1201_setconfig(struct zd1201 *zd, int rid, const void *buf, int len, int wait) -{ - int err; - unsigned char *request; - int reqlen; - char seq=0; - struct urb *urb; - gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; - - len += 4; /* first 4 are for header */ - - zd->rxdatas = 0; - zd->rxlen = 0; - for (seq=0; len > 0; seq++) { - request = kzalloc(16, gfp_mask); - if (!request) - return -ENOMEM; - urb = usb_alloc_urb(0, gfp_mask); - if (!urb) { - kfree(request); - return -ENOMEM; - } - reqlen = len>12 ? 12 : len; - request[0] = ZD1201_USB_RESREQ; - request[1] = seq; - request[2] = 0; - request[3] = 0; - if (request[1] == 0) { - /* add header */ - *(__le16*)&request[4] = cpu_to_le16((len-2+1)/2); - *(__le16*)&request[6] = cpu_to_le16(rid); - memcpy(request+8, buf, reqlen-4); - buf += reqlen-4; - } else { - memcpy(request+4, buf, reqlen); - buf += reqlen; - } - - len -= reqlen; - - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, - zd->endp_out2), request, 16, zd1201_usbfree, zd); - err = usb_submit_urb(urb, gfp_mask); - if (err) - goto err; - } - - request = kmalloc(16, gfp_mask); - if (!request) - return -ENOMEM; - urb = usb_alloc_urb(0, gfp_mask); - if (!urb) { - kfree(request); - return -ENOMEM; - } - *((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ); - *((__le16*)&request[4]) = - cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT); - *((__le16*)&request[6]) = cpu_to_le16(rid); - *((__le16*)&request[8]) = cpu_to_le16(0); - *((__le16*)&request[10]) = cpu_to_le16(0); - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), - request, 16, zd1201_usbfree, zd); - err = usb_submit_urb(urb, gfp_mask); - if (err) - goto err; - - if (wait) { - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) { - dev_dbg(&zd->usb->dev, "wrong or no RID received\n"); - } - } - - return 0; -err: - kfree(request); - usb_free_urb(urb); - return err; -} - -static inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val) -{ - int err; - __le16 zdval; - - err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16)); - if (err) - return err; - *val = le16_to_cpu(zdval); - return 0; -} - -static inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val) -{ - __le16 zdval = cpu_to_le16(val); - return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1)); -} - -static int zd1201_drvr_start(struct zd1201 *zd) -{ - int err, i; - short max; - __le16 zdmax; - unsigned char *buffer; - - buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - usb_fill_bulk_urb(zd->rx_urb, zd->usb, - usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE, - zd1201_usbrx, zd); - - err = usb_submit_urb(zd->rx_urb, GFP_KERNEL); - if (err) - goto err_buffer; - - err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); - if (err) - goto err_urb; - - err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax, - sizeof(__le16)); - if (err) - goto err_urb; - - max = le16_to_cpu(zdmax); - for (i=0; i<max; i++) { - err = zd1201_docmd(zd, ZD1201_CMDCODE_ALLOC, 1514, 0, 0); - if (err) - goto err_urb; - } - - return 0; - -err_urb: - usb_kill_urb(zd->rx_urb); - return err; -err_buffer: - kfree(buffer); - return err; -} - -/* Magic alert: The firmware doesn't seem to like the MAC state being - * toggled in promisc (aka monitor) mode. - * (It works a number of times, but will halt eventually) - * So we turn it of before disabling and on after enabling if needed. - */ -static int zd1201_enable(struct zd1201 *zd) -{ - int err; - - if (zd->mac_enabled) - return 0; - - err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0); - if (!err) - zd->mac_enabled = 1; - - if (zd->monitor) - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1); - - return err; -} - -static int zd1201_disable(struct zd1201 *zd) -{ - int err; - - if (!zd->mac_enabled) - return 0; - if (zd->monitor) { - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); - if (err) - return err; - } - - err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0); - if (!err) - zd->mac_enabled = 0; - return err; -} - -static int zd1201_mac_reset(struct zd1201 *zd) -{ - if (!zd->mac_enabled) - return 0; - zd1201_disable(zd); - return zd1201_enable(zd); -} - -static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen) -{ - int err, val; - char buf[IW_ESSID_MAX_SIZE+2]; - - err = zd1201_disable(zd); - if (err) - return err; - - val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; - val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val); - if (err) - return err; - - *(__le16 *)buf = cpu_to_le16(essidlen); - memcpy(buf+2, essid, essidlen); - if (!zd->ap) { /* Normal station */ - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } else { /* AP */ - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } - - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, - zd->dev->dev_addr, zd->dev->addr_len, 1); - if (err) - return err; - - err = zd1201_enable(zd); - if (err) - return err; - - msleep(100); - return 0; -} - -static int zd1201_net_open(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - - /* Start MAC with wildcard if no essid set */ - if (!zd->mac_enabled) - zd1201_join(zd, zd->essid, zd->essidlen); - netif_start_queue(dev); - - return 0; -} - -static int zd1201_net_stop(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - -/* - RFC 1042 encapsulates Ethernet frames in 802.11 frames - by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0 - (0x00, 0x00, 0x00). Zd requires an additional padding, copy - of ethernet addresses, length of the standard RFC 1042 packet - and a command byte (which is nul for tx). - - tx frame (from Wlan NG): - RFC 1042: - llc 0xAA 0xAA 0x03 (802.2 LLC) - snap 0x00 0x00 0x00 (Ethernet encapsulated) - type 2 bytes, Ethernet type field - payload (minus eth header) - Zydas specific: - padding 1B if (skb->len+8+1)%64==0 - Eth MAC addr 12 bytes, Ethernet MAC addresses - length 2 bytes, RFC 1042 packet length - (llc+snap+type+payload) - zd 1 null byte, zd1201 packet type - */ -static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - unsigned char *txbuf = zd->txdata; - int txbuflen, pad = 0, err; - struct urb *urb = zd->tx_urb; - - if (!zd->mac_enabled || zd->monitor) { - dev->stats.tx_dropped++; - kfree_skb(skb); - return NETDEV_TX_OK; - } - netif_stop_queue(dev); - - txbuflen = skb->len + 8 + 1; - if (txbuflen%64 == 0) { - pad = 1; - txbuflen++; - } - txbuf[0] = 0xAA; - txbuf[1] = 0xAA; - txbuf[2] = 0x03; - txbuf[3] = 0x00; /* rfc1042 */ - txbuf[4] = 0x00; - txbuf[5] = 0x00; - - skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12); - if (pad) - txbuf[skb->len-12+6]=0; - skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12); - *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6); - txbuf[txbuflen-1] = 0; - - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out), - txbuf, txbuflen, zd1201_usbtx, zd); - - err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC); - if (err) { - dev->stats.tx_errors++; - netif_start_queue(dev); - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - } - kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static void zd1201_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct zd1201 *zd = netdev_priv(dev); - - if (!zd) - return; - dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n", - dev->name); - usb_unlink_urb(zd->tx_urb); - dev->stats.tx_errors++; - /* Restart the timeout to quiet the watchdog: */ - netif_trans_update(dev); /* prevent tx timeout */ -} - -static int zd1201_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - struct zd1201 *zd = netdev_priv(dev); - int err; - - if (!zd) - return -ENODEV; - - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, - addr->sa_data, dev->addr_len, 1); - if (err) - return err; - eth_hw_addr_set(dev, addr->sa_data); - - return zd1201_mac_reset(zd); -} - -static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - - return &zd->iwstats; -} - -static void zd1201_set_multicast(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - struct netdev_hw_addr *ha; - unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; - int i; - - if (netdev_mc_count(dev) > ZD1201_MAXMULTI) - return; - - i = 0; - netdev_for_each_mc_addr(ha, dev) - memcpy(reqbuf + i++ * ETH_ALEN, ha->addr, ETH_ALEN); - zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf, - netdev_mc_count(dev) * ETH_ALEN, 0); -} - -static int zd1201_config_commit(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct zd1201 *zd = netdev_priv(dev); - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_name(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - strcpy(wrqu->name, "IEEE 802.11b"); - return 0; -} - -static int zd1201_set_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct zd1201 *zd = netdev_priv(dev); - short channel = 0; - int err; - - if (freq->e == 0) - channel = freq->m; - else - channel = ieee80211_frequency_to_channel(freq->m); - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel); - if (err) - return err; - - zd1201_mac_reset(zd); - - return 0; -} - -static int zd1201_get_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct zd1201 *zd = netdev_priv(dev); - short channel; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel); - if (err) - return err; - freq->e = 0; - freq->m = channel; - - return 0; -} - -static int zd1201_set_mode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct zd1201 *zd = netdev_priv(dev); - short porttype, monitor = 0; - unsigned char buffer[IW_ESSID_MAX_SIZE+2]; - int err; - - if (zd->ap) { - if (*mode != IW_MODE_MASTER) - return -EINVAL; - return 0; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); - if (err) - return err; - zd->dev->type = ARPHRD_ETHER; - switch(*mode) { - case IW_MODE_MONITOR: - monitor = 1; - zd->dev->type = ARPHRD_IEEE80211; - /* Make sure we are no longer associated with by - setting an 'impossible' essid. - (otherwise we mess up firmware) - */ - zd1201_join(zd, "\0-*#\0", 5); - /* Put port in pIBSS */ - fallthrough; - case 8: /* No pseudo-IBSS in wireless extensions (yet) */ - porttype = ZD1201_PORTTYPE_PSEUDOIBSS; - break; - case IW_MODE_ADHOC: - porttype = ZD1201_PORTTYPE_IBSS; - break; - case IW_MODE_INFRA: - porttype = ZD1201_PORTTYPE_BSS; - break; - default: - return -EINVAL; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); - if (err) - return err; - if (zd->monitor && !monitor) { - zd1201_disable(zd); - *(__le16 *)buffer = cpu_to_le16(zd->essidlen); - memcpy(buffer+2, zd->essid, zd->essidlen); - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, - buffer, IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } - zd->monitor = monitor; - /* If monitor mode is set we don't actually turn it on here since it - * is done during mac reset anyway (see zd1201_mac_enable). - */ - zd1201_mac_reset(zd); - - return 0; -} - -static int zd1201_get_mode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct zd1201 *zd = netdev_priv(dev); - short porttype; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPORTTYPE, &porttype); - if (err) - return err; - switch(porttype) { - case ZD1201_PORTTYPE_IBSS: - *mode = IW_MODE_ADHOC; - break; - case ZD1201_PORTTYPE_BSS: - *mode = IW_MODE_INFRA; - break; - case ZD1201_PORTTYPE_WDS: - *mode = IW_MODE_REPEAT; - break; - case ZD1201_PORTTYPE_PSEUDOIBSS: - *mode = 8;/* No Pseudo-IBSS... */ - break; - case ZD1201_PORTTYPE_AP: - *mode = IW_MODE_MASTER; - break; - default: - dev_dbg(&zd->usb->dev, "Unknown porttype: %d\n", - porttype); - *mode = IW_MODE_AUTO; - } - if (zd->monitor) - *mode = IW_MODE_MONITOR; - - return 0; -} - -static int zd1201_get_range(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_point *wrq = &wrqu->data; - struct iw_range *range = (struct iw_range *)extra; - - wrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = WIRELESS_EXT; - - range->max_qual.qual = 128; - range->max_qual.level = 128; - range->max_qual.noise = 128; - range->max_qual.updated = 7; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = ZD1201_NUMKEYS; - - range->num_bitrates = 4; - range->bitrate[0] = 1000000; - range->bitrate[1] = 2000000; - range->bitrate[2] = 5500000; - range->bitrate[3] = 11000000; - - range->min_rts = 0; - range->min_frag = ZD1201_FRAGMIN; - range->max_rts = ZD1201_RTSMAX; - range->min_frag = ZD1201_FRAGMAX; - - return 0; -} - -/* Little bit of magic here: we only get the quality if we poll - * for it, and we never get an actual request to trigger such - * a poll. Therefore we 'assume' that the user will soon ask for - * the stats after asking the bssid. - */ -static int zd1201_get_wap(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct zd1201 *zd = netdev_priv(dev); - unsigned char buffer[6]; - - if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) { - /* Unfortunately the quality and noise reported is useless. - they seem to be accumulators that increase until you - read them, unless we poll on a fixed interval we can't - use them - */ - /*zd->iwstats.qual.qual = le16_to_cpu(((__le16 *)buffer)[0]);*/ - zd->iwstats.qual.level = le16_to_cpu(((__le16 *)buffer)[1]); - /*zd->iwstats.qual.noise = le16_to_cpu(((__le16 *)buffer)[2]);*/ - zd->iwstats.qual.updated = 2; - } - - return zd1201_getconfig(zd, ZD1201_RID_CURRENTBSSID, ap_addr->sa_data, 6); -} - -static int zd1201_set_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - /* We do everything in get_scan */ - return 0; -} - -static int zd1201_get_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_point *srq = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - int err, i, j, enabled_save; - struct iw_event iwe; - char *cev = extra; - char *end_buf = extra + IW_SCAN_MAX_DATA; - - /* No scanning in AP mode */ - if (zd->ap) - return -EOPNOTSUPP; - - /* Scan doesn't seem to work if disabled */ - enabled_save = zd->mac_enabled; - zd1201_enable(zd); - - zd->rxdatas = 0; - err = zd1201_docmd(zd, ZD1201_CMDCODE_INQUIRE, - ZD1201_INQ_SCANRESULTS, 0, 0); - if (err) - return err; - - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - if (le16_to_cpu(*(__le16*)&zd->rxdata[2]) != ZD1201_INQ_SCANRESULTS) - return -EIO; - - for(i=8; i<zd->rxlen; i+=62) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6); - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = zd->rxdata[i+16]; - iwe.u.data.flags = 1; - cev = iwe_stream_add_point(info, cev, end_buf, - &iwe, zd->rxdata+i+18); - - iwe.cmd = SIOCGIWMODE; - if (zd->rxdata[i+14]&0x01) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_UINT_LEN); - - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = zd->rxdata[i+0]; - iwe.u.freq.e = 0; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - iwe.cmd = SIOCGIWRATE; - iwe.u.bitrate.fixed = 0; - iwe.u.bitrate.disabled = 0; - for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) { - iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_PARAM_LEN); - } - - iwe.cmd = SIOCGIWENCODE; - iwe.u.data.length = 0; - if (zd->rxdata[i+14]&0x10) - iwe.u.data.flags = IW_ENCODE_ENABLED; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL); - - iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = zd->rxdata[i+4]; - iwe.u.qual.noise= zd->rxdata[i+2]/10-100; - iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100; - iwe.u.qual.updated = 7; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_QUAL_LEN); - } - - if (!enabled_save) - zd1201_disable(zd); - - srq->length = cev - extra; - srq->flags = 0; - - return 0; -} - -static int zd1201_set_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - - if (data->length > IW_ESSID_MAX_SIZE) - return -EINVAL; - if (data->length < 1) - data->length = 1; - zd->essidlen = data->length; - memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1); - memcpy(zd->essid, essid, data->length); - return zd1201_join(zd, zd->essid, zd->essidlen); -} - -static int zd1201_get_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - - memcpy(essid, zd->essid, zd->essidlen); - data->flags = 1; - data->length = zd->essidlen; - - return 0; -} - -static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *nick) -{ - struct iw_point *data = &wrqu->data; - strcpy(nick, "zd1201"); - data->flags = 1; - data->length = strlen(nick); - return 0; -} - -static int zd1201_set_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct zd1201 *zd = netdev_priv(dev); - short rate; - int err; - - switch (rrq->value) { - case 1000000: - rate = ZD1201_RATEB1; - break; - case 2000000: - rate = ZD1201_RATEB2; - break; - case 5500000: - rate = ZD1201_RATEB5; - break; - case 11000000: - default: - rate = ZD1201_RATEB11; - break; - } - if (!rrq->fixed) { /* Also enable all lower bitrates */ - rate |= rate-1; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate); - if (err) - return err; - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct zd1201 *zd = netdev_priv(dev); - short rate; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CURRENTTXRATE, &rate); - if (err) - return err; - - switch(rate) { - case 1: - rrq->value = 1000000; - break; - case 2: - rrq->value = 2000000; - break; - case 5: - rrq->value = 5500000; - break; - case 11: - rrq->value = 11000000; - break; - default: - rrq->value = 0; - } - rrq->fixed = 0; - rrq->disabled = 0; - - return 0; -} - -static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct zd1201 *zd = netdev_priv(dev); - int err; - short val = rts->value; - - if (rts->disabled || !rts->fixed) - val = ZD1201_RTSMAX; - if (val > ZD1201_RTSMAX) - return -EINVAL; - if (val < 0) - return -EINVAL; - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, val); - if (err) - return err; - return zd1201_mac_reset(zd); -} - -static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct zd1201 *zd = netdev_priv(dev); - short rtst; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, &rtst); - if (err) - return err; - rts->value = rtst; - rts->disabled = (rts->value == ZD1201_RTSMAX); - rts->fixed = 1; - - return 0; -} - -static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *frag = &wrqu->frag; - struct zd1201 *zd = netdev_priv(dev); - int err; - short val = frag->value; - - if (frag->disabled || !frag->fixed) - val = ZD1201_FRAGMAX; - if (val > ZD1201_FRAGMAX) - return -EINVAL; - if (val < ZD1201_FRAGMIN) - return -EINVAL; - if (val & 1) - return -EINVAL; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, val); - if (err) - return err; - return zd1201_mac_reset(zd); -} - -static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *frag = &wrqu->frag; - struct zd1201 *zd = netdev_priv(dev); - short fragt; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, &fragt); - if (err) - return err; - frag->value = fragt; - frag->disabled = (frag->value == ZD1201_FRAGMAX); - frag->fixed = 1; - - return 0; -} - -static int zd1201_set_retry(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -static int zd1201_get_retry(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -static int zd1201_set_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct zd1201 *zd = netdev_priv(dev); - short i; - int err, rid; - - if (erq->length > ZD1201_MAXKEYLEN) - return -EINVAL; - - i = (erq->flags & IW_ENCODE_INDEX)-1; - if (i == -1) { - err = zd1201_getconfig16(zd,ZD1201_RID_CNFDEFAULTKEYID,&i); - if (err) - return err; - } else { - err = zd1201_setconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, i); - if (err) - return err; - } - - if (i < 0 || i >= ZD1201_NUMKEYS) - return -EINVAL; - - rid = ZD1201_RID_CNFDEFAULTKEY0 + i; - err = zd1201_setconfig(zd, rid, key, erq->length, 1); - if (err) - return err; - zd->encode_keylen[i] = erq->length; - memcpy(zd->encode_keys[i], key, erq->length); - - i=0; - if (!(erq->flags & IW_ENCODE_DISABLED & IW_ENCODE_MODE)) { - i |= 0x01; - zd->encode_enabled = 1; - } else - zd->encode_enabled = 0; - if (erq->flags & IW_ENCODE_RESTRICTED & IW_ENCODE_MODE) { - i |= 0x02; - zd->encode_restricted = 1; - } else - zd->encode_restricted = 0; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFWEBFLAGS, i); - if (err) - return err; - - if (zd->encode_enabled) - i = ZD1201_CNFAUTHENTICATION_SHAREDKEY; - else - i = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, i); - if (err) - return err; - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct zd1201 *zd = netdev_priv(dev); - short i; - int err; - - if (zd->encode_enabled) - erq->flags = IW_ENCODE_ENABLED; - else - erq->flags = IW_ENCODE_DISABLED; - if (zd->encode_restricted) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - i = (erq->flags & IW_ENCODE_INDEX) -1; - if (i == -1) { - err = zd1201_getconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, &i); - if (err) - return err; - } - if (i<0 || i>= ZD1201_NUMKEYS) - return -EINVAL; - - erq->flags |= i+1; - - erq->length = zd->encode_keylen[i]; - memcpy(key, zd->encode_keys[i], erq->length); - - return 0; -} - -static int zd1201_set_power(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct zd1201 *zd = netdev_priv(dev); - short enabled, duration, level; - int err; - - enabled = vwrq->disabled ? 0 : 1; - if (enabled) { - if (vwrq->flags & IW_POWER_PERIOD) { - duration = vwrq->value; - err = zd1201_setconfig16(zd, - ZD1201_RID_CNFMAXSLEEPDURATION, duration); - if (err) - return err; - goto out; - } - if (vwrq->flags & IW_POWER_TIMEOUT) { - err = zd1201_getconfig16(zd, - ZD1201_RID_CNFMAXSLEEPDURATION, &duration); - if (err) - return err; - level = vwrq->value * 4 / duration; - if (level > 4) - level = 4; - if (level < 0) - level = 0; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMEPS, - level); - if (err) - return err; - goto out; - } - return -EINVAL; - } -out: - return zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled); -} - -static int zd1201_get_power(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct zd1201 *zd = netdev_priv(dev); - short enabled, level, duration; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMENABLED, &enabled); - if (err) - return err; - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMEPS, &level); - if (err) - return err; - err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXSLEEPDURATION, &duration); - if (err) - return err; - vwrq->disabled = enabled ? 0 : 1; - if (vwrq->flags & IW_POWER_TYPE) { - if (vwrq->flags & IW_POWER_PERIOD) { - vwrq->value = duration; - vwrq->flags = IW_POWER_PERIOD; - } else { - vwrq->value = duration * level / 4; - vwrq->flags = IW_POWER_TIMEOUT; - } - } - if (vwrq->flags & IW_POWER_MODE) { - if (enabled && level) - vwrq->flags = IW_POWER_UNICAST_R; - else - vwrq->flags = IW_POWER_ALL_R; - } - - return 0; -} - - -static const iw_handler zd1201_iw_handler[] = -{ - IW_HANDLER(SIOCSIWCOMMIT, zd1201_config_commit), - IW_HANDLER(SIOCGIWNAME, zd1201_get_name), - IW_HANDLER(SIOCSIWFREQ, zd1201_set_freq), - IW_HANDLER(SIOCGIWFREQ, zd1201_get_freq), - IW_HANDLER(SIOCSIWMODE, zd1201_set_mode), - IW_HANDLER(SIOCGIWMODE, zd1201_get_mode), - IW_HANDLER(SIOCGIWRANGE, zd1201_get_range), - IW_HANDLER(SIOCGIWAP, zd1201_get_wap), - IW_HANDLER(SIOCSIWSCAN, zd1201_set_scan), - IW_HANDLER(SIOCGIWSCAN, zd1201_get_scan), - IW_HANDLER(SIOCSIWESSID, zd1201_set_essid), - IW_HANDLER(SIOCGIWESSID, zd1201_get_essid), - IW_HANDLER(SIOCGIWNICKN, zd1201_get_nick), - IW_HANDLER(SIOCSIWRATE, zd1201_set_rate), - IW_HANDLER(SIOCGIWRATE, zd1201_get_rate), - IW_HANDLER(SIOCSIWRTS, zd1201_set_rts), - IW_HANDLER(SIOCGIWRTS, zd1201_get_rts), - IW_HANDLER(SIOCSIWFRAG, zd1201_set_frag), - IW_HANDLER(SIOCGIWFRAG, zd1201_get_frag), - IW_HANDLER(SIOCSIWRETRY, zd1201_set_retry), - IW_HANDLER(SIOCGIWRETRY, zd1201_get_retry), - IW_HANDLER(SIOCSIWENCODE, zd1201_set_encode), - IW_HANDLER(SIOCGIWENCODE, zd1201_get_encode), - IW_HANDLER(SIOCSIWPOWER, zd1201_set_power), - IW_HANDLER(SIOCGIWPOWER, zd1201_get_power), -}; - -static int zd1201_set_hostauth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - - if (!zd->ap) - return -EOPNOTSUPP; - - return zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value); -} - -static int zd1201_get_hostauth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - short hostauth; - int err; - - if (!zd->ap) - return -EOPNOTSUPP; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFHOSTAUTH, &hostauth); - if (err) - return err; - rrq->value = hostauth; - rrq->fixed = 1; - - return 0; -} - -static int zd1201_auth_sta(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *sta = &wrqu->ap_addr; - struct zd1201 *zd = netdev_priv(dev); - unsigned char buffer[10]; - - if (!zd->ap) - return -EOPNOTSUPP; - - memcpy(buffer, sta->sa_data, ETH_ALEN); - *(short*)(buffer+6) = 0; /* 0==success, 1==failure */ - *(short*)(buffer+8) = 0; - - return zd1201_setconfig(zd, ZD1201_RID_AUTHENTICATESTA, buffer, 10, 1); -} - -static int zd1201_set_maxassoc(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - - if (!zd->ap) - return -EOPNOTSUPP; - - return zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value); -} - -static int zd1201_get_maxassoc(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - short maxassoc; - int err; - - if (!zd->ap) - return -EOPNOTSUPP; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, &maxassoc); - if (err) - return err; - rrq->value = maxassoc; - rrq->fixed = 1; - - return 0; -} - -static const iw_handler zd1201_private_handler[] = { - zd1201_set_hostauth, /* ZD1201SIWHOSTAUTH */ - zd1201_get_hostauth, /* ZD1201GIWHOSTAUTH */ - zd1201_auth_sta, /* ZD1201SIWAUTHSTA */ - NULL, /* nothing to get */ - zd1201_set_maxassoc, /* ZD1201SIMAXASSOC */ - zd1201_get_maxassoc, /* ZD1201GIMAXASSOC */ -}; - -static const struct iw_priv_args zd1201_private_args[] = { - { ZD1201SIWHOSTAUTH, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "sethostauth" }, - { ZD1201GIWHOSTAUTH, IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostauth" }, - { ZD1201SIWAUTHSTA, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "authstation" }, - { ZD1201SIWMAXASSOC, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "setmaxassoc" }, - { ZD1201GIWMAXASSOC, IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmaxassoc" }, -}; - -static const struct iw_handler_def zd1201_iw_handlers = { - .num_standard = ARRAY_SIZE(zd1201_iw_handler), - .num_private = ARRAY_SIZE(zd1201_private_handler), - .num_private_args = ARRAY_SIZE(zd1201_private_args), - .standard = zd1201_iw_handler, - .private = zd1201_private_handler, - .private_args = (struct iw_priv_args *) zd1201_private_args, - .get_wireless_stats = zd1201_get_wireless_stats, -}; - -static const struct net_device_ops zd1201_netdev_ops = { - .ndo_open = zd1201_net_open, - .ndo_stop = zd1201_net_stop, - .ndo_start_xmit = zd1201_hard_start_xmit, - .ndo_tx_timeout = zd1201_tx_timeout, - .ndo_set_rx_mode = zd1201_set_multicast, - .ndo_set_mac_address = zd1201_set_mac_address, - .ndo_validate_addr = eth_validate_addr, -}; - -static int zd1201_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct zd1201 *zd; - struct net_device *dev; - struct usb_device *usb; - int err; - short porttype; - char buf[IW_ESSID_MAX_SIZE+2]; - u8 addr[ETH_ALEN]; - - usb = interface_to_usbdev(interface); - - dev = alloc_etherdev(sizeof(*zd)); - if (!dev) - return -ENOMEM; - zd = netdev_priv(dev); - zd->dev = dev; - - zd->ap = ap; - zd->usb = usb; - zd->removed = 0; - init_waitqueue_head(&zd->rxdataq); - INIT_HLIST_HEAD(&zd->fraglist); - - err = zd1201_fw_upload(usb, zd->ap); - if (err) { - dev_err(&usb->dev, "zd1201 firmware upload failed: %d\n", err); - goto err_zd; - } - - zd->endp_in = 1; - zd->endp_out = 1; - zd->endp_out2 = 2; - zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!zd->rx_urb || !zd->tx_urb) { - err = -ENOMEM; - goto err_zd; - } - - mdelay(100); - err = zd1201_drvr_start(zd); - if (err) - goto err_zd; - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXDATALEN, 2312); - if (err) - goto err_start; - - err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, - ZD1201_RATEB1 | ZD1201_RATEB2 | ZD1201_RATEB5 | ZD1201_RATEB11); - if (err) - goto err_start; - - dev->netdev_ops = &zd1201_netdev_ops; - dev->wireless_handlers = &zd1201_iw_handlers; - dev->watchdog_timeo = ZD1201_TX_TIMEOUT; - strcpy(dev->name, "wlan%d"); - - err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, addr, ETH_ALEN); - if (err) - goto err_start; - eth_hw_addr_set(dev, addr); - - /* Set wildcard essid to match zd->essid */ - *(__le16 *)buf = cpu_to_le16(0); - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - goto err_start; - - if (zd->ap) - porttype = ZD1201_PORTTYPE_AP; - else - porttype = ZD1201_PORTTYPE_BSS; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); - if (err) - goto err_start; - - SET_NETDEV_DEV(dev, &usb->dev); - - err = register_netdev(dev); - if (err) - goto err_start; - dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n", - dev->name); - - usb_set_intfdata(interface, zd); - zd1201_enable(zd); /* zd1201 likes to startup enabled, */ - zd1201_disable(zd); /* interfering with all the wifis in range */ - return 0; - -err_start: - /* Leave the device in reset state */ - zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); -err_zd: - usb_free_urb(zd->tx_urb); - usb_free_urb(zd->rx_urb); - free_netdev(dev); - return err; -} - -static void zd1201_disconnect(struct usb_interface *interface) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - struct hlist_node *node2; - struct zd1201_frag *frag; - - if (!zd) - return; - usb_set_intfdata(interface, NULL); - - hlist_for_each_entry_safe(frag, node2, &zd->fraglist, fnode) { - hlist_del_init(&frag->fnode); - kfree_skb(frag->skb); - kfree(frag); - } - - if (zd->tx_urb) { - usb_kill_urb(zd->tx_urb); - usb_free_urb(zd->tx_urb); - } - if (zd->rx_urb) { - usb_kill_urb(zd->rx_urb); - usb_free_urb(zd->rx_urb); - } - - if (zd->dev) { - unregister_netdev(zd->dev); - free_netdev(zd->dev); - } -} - -#ifdef CONFIG_PM - -static int zd1201_suspend(struct usb_interface *interface, - pm_message_t message) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - - netif_device_detach(zd->dev); - - zd->was_enabled = zd->mac_enabled; - - if (zd->was_enabled) - return zd1201_disable(zd); - else - return 0; -} - -static int zd1201_resume(struct usb_interface *interface) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - - if (!zd || !zd->dev) - return -ENODEV; - - netif_device_attach(zd->dev); - - if (zd->was_enabled) - return zd1201_enable(zd); - else - return 0; -} - -#else - -#define zd1201_suspend NULL -#define zd1201_resume NULL - -#endif - -static struct usb_driver zd1201_usb = { - .name = "zd1201", - .probe = zd1201_probe, - .disconnect = zd1201_disconnect, - .id_table = zd1201_table, - .suspend = zd1201_suspend, - .resume = zd1201_resume, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(zd1201_usb); diff --git a/drivers/net/wireless/zydas/zd1201.h b/drivers/net/wireless/zydas/zd1201.h deleted file mode 100644 index c46ac87550..0000000000 --- a/drivers/net/wireless/zydas/zd1201.h +++ /dev/null @@ -1,144 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) - * - * Parts of this driver have been derived from a wlan-ng version - * modified by ZyDAS. - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#ifndef _INCLUDE_ZD1201_H_ -#define _INCLUDE_ZD1201_H_ - -#define ZD1201_NUMKEYS 4 -#define ZD1201_MAXKEYLEN 13 -#define ZD1201_MAXMULTI 16 -#define ZD1201_FRAGMAX 2500 -#define ZD1201_FRAGMIN 256 -#define ZD1201_RTSMAX 2500 - -#define ZD1201_RXSIZE 3000 - -struct zd1201 { - struct usb_device *usb; - int removed; - struct net_device *dev; - struct iw_statistics iwstats; - - int endp_in; - int endp_out; - int endp_out2; - struct urb *rx_urb; - struct urb *tx_urb; - - unsigned char rxdata[ZD1201_RXSIZE]; - int rxlen; - wait_queue_head_t rxdataq; - int rxdatas; - struct hlist_head fraglist; - unsigned char txdata[ZD1201_RXSIZE]; - - int ap; - char essid[IW_ESSID_MAX_SIZE+1]; - int essidlen; - int mac_enabled; - int was_enabled; - int monitor; - int encode_enabled; - int encode_restricted; - unsigned char encode_keys[ZD1201_NUMKEYS][ZD1201_MAXKEYLEN]; - int encode_keylen[ZD1201_NUMKEYS]; -}; - -struct zd1201_frag { - struct hlist_node fnode; - int seq; - struct sk_buff *skb; -}; - -#define ZD1201SIWHOSTAUTH SIOCIWFIRSTPRIV -#define ZD1201GIWHOSTAUTH ZD1201SIWHOSTAUTH+1 -#define ZD1201SIWAUTHSTA SIOCIWFIRSTPRIV+2 -#define ZD1201SIWMAXASSOC SIOCIWFIRSTPRIV+4 -#define ZD1201GIWMAXASSOC ZD1201SIWMAXASSOC+1 - -#define ZD1201_FW_TIMEOUT (1000) - -#define ZD1201_TX_TIMEOUT (2000) - -#define ZD1201_USB_CMDREQ 0 -#define ZD1201_USB_RESREQ 1 - -#define ZD1201_CMDCODE_INIT 0x00 -#define ZD1201_CMDCODE_ENABLE 0x01 -#define ZD1201_CMDCODE_DISABLE 0x02 -#define ZD1201_CMDCODE_ALLOC 0x0a -#define ZD1201_CMDCODE_INQUIRE 0x11 -#define ZD1201_CMDCODE_SETRXRID 0x17 -#define ZD1201_CMDCODE_ACCESS 0x21 - -#define ZD1201_PACKET_EVENTSTAT 0x0 -#define ZD1201_PACKET_RXDATA 0x1 -#define ZD1201_PACKET_INQUIRE 0x2 -#define ZD1201_PACKET_RESOURCE 0x3 - -#define ZD1201_ACCESSBIT 0x0100 - -#define ZD1201_RID_CNFPORTTYPE 0xfc00 -#define ZD1201_RID_CNFOWNMACADDR 0xfc01 -#define ZD1201_RID_CNFDESIREDSSID 0xfc02 -#define ZD1201_RID_CNFOWNCHANNEL 0xfc03 -#define ZD1201_RID_CNFOWNSSID 0xfc04 -#define ZD1201_RID_CNFMAXDATALEN 0xfc07 -#define ZD1201_RID_CNFPMENABLED 0xfc09 -#define ZD1201_RID_CNFPMEPS 0xfc0a -#define ZD1201_RID_CNFMAXSLEEPDURATION 0xfc0c -#define ZD1201_RID_CNFDEFAULTKEYID 0xfc23 -#define ZD1201_RID_CNFDEFAULTKEY0 0xfc24 -#define ZD1201_RID_CNFDEFAULTKEY1 0xfc25 -#define ZD1201_RID_CNFDEFAULTKEY2 0xfc26 -#define ZD1201_RID_CNFDEFAULTKEY3 0xfc27 -#define ZD1201_RID_CNFWEBFLAGS 0xfc28 -#define ZD1201_RID_CNFAUTHENTICATION 0xfc2a -#define ZD1201_RID_CNFMAXASSOCSTATIONS 0xfc2b -#define ZD1201_RID_CNFHOSTAUTH 0xfc2e -#define ZD1201_RID_CNFGROUPADDRESS 0xfc80 -#define ZD1201_RID_CNFFRAGTHRESHOLD 0xfc82 -#define ZD1201_RID_CNFRTSTHRESHOLD 0xfc83 -#define ZD1201_RID_TXRATECNTL 0xfc84 -#define ZD1201_RID_PROMISCUOUSMODE 0xfc85 -#define ZD1201_RID_CNFBASICRATES 0xfcb3 -#define ZD1201_RID_AUTHENTICATESTA 0xfce3 -#define ZD1201_RID_CURRENTBSSID 0xfd42 -#define ZD1201_RID_COMMSQUALITY 0xfd43 -#define ZD1201_RID_CURRENTTXRATE 0xfd44 -#define ZD1201_RID_CNFMAXTXBUFFERNUMBER 0xfda0 -#define ZD1201_RID_CURRENTCHANNEL 0xfdc1 - -#define ZD1201_INQ_SCANRESULTS 0xf101 - -#define ZD1201_INF_LINKSTATUS 0xf200 -#define ZD1201_INF_ASSOCSTATUS 0xf201 -#define ZD1201_INF_AUTHREQ 0xf202 - -#define ZD1201_ASSOCSTATUS_STAASSOC 0x1 -#define ZD1201_ASSOCSTATUS_REASSOC 0x2 -#define ZD1201_ASSOCSTATUS_DISASSOC 0x3 -#define ZD1201_ASSOCSTATUS_ASSOCFAIL 0x4 -#define ZD1201_ASSOCSTATUS_AUTHFAIL 0x5 - -#define ZD1201_PORTTYPE_IBSS 0 -#define ZD1201_PORTTYPE_BSS 1 -#define ZD1201_PORTTYPE_WDS 2 -#define ZD1201_PORTTYPE_PSEUDOIBSS 3 -#define ZD1201_PORTTYPE_AP 6 - -#define ZD1201_RATEB1 1 -#define ZD1201_RATEB2 2 -#define ZD1201_RATEB5 4 /* 5.5 really, but 5 is shorter :) */ -#define ZD1201_RATEB11 8 - -#define ZD1201_CNFAUTHENTICATION_OPENSYSTEM 0x0001 -#define ZD1201_CNFAUTHENTICATION_SHAREDKEY 0x0002 - -#endif /* _INCLUDE_ZD1201_H_ */ |