From 5aabff05df8e137c6690437f79b05408294fea57 Mon Sep 17 00:00:00 2001 From: Toshi Kikuchi Date: Tue, 2 Dec 2014 10:55:54 +0200 Subject: ath10k: read calibration data from Device Tree This patch adds support for reading calibration data from Device Tree. It looks for the calibration data in Device Tree if it can't find it in a file. If there's no node in Device Tree, ath10k will try to find the calibration data from OTP. The node for the calibration data should be defined like this: pci { pcie@0 { reg = <0 0 0 0 0>; #interrupt-cells = <1>; #size-cells = <2>; #address-cells = <3>; device_type = "pci"; ath10k@0,0 { reg = <0 0 0 0 0>; device_type = "pci"; qcom,ath10k-calibration-data = [ 01 02 03 ... ]; }; }; }; Signed-off-by: Toshi Kikuchi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 70 +++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/core.h | 3 ++ 2 files changed, 72 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7762061a1944..6165f2735b35 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -17,6 +17,7 @@ #include #include +#include #include "core.h" #include "mac.h" @@ -249,6 +250,63 @@ static int ath10k_download_cal_file(struct ath10k *ar) return 0; } +static int ath10k_download_cal_dt(struct ath10k *ar) +{ + struct device_node *node; + int data_len; + void *data; + int ret; + + node = ar->dev->of_node; + if (!node) + /* Device Tree is optional, don't print any warnings if + * there's no node for ath10k. + */ + return -ENOENT; + + if (!of_get_property(node, "qcom,ath10k-calibration-data", + &data_len)) { + /* The calibration data node is optional */ + return -ENOENT; + } + + if (data_len != QCA988X_CAL_DATA_LEN) { + ath10k_warn(ar, "invalid calibration data length in DT: %d\n", + data_len); + ret = -EMSGSIZE; + goto out; + } + + data = kmalloc(data_len, GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto out; + } + + ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data", + data, data_len); + if (ret) { + ath10k_warn(ar, "failed to read calibration data from DT: %d\n", + ret); + goto out_free; + } + + ret = ath10k_download_board_data(ar, data, data_len); + if (ret) { + ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n", + ret); + goto out_free; + } + + ret = 0; + +out_free: + kfree(data); + +out: + return ret; +} + static int ath10k_download_and_run_otp(struct ath10k *ar) { u32 result, address = ar->hw_params.patch_load_addr; @@ -662,7 +720,17 @@ static int ath10k_download_cal_data(struct ath10k *ar) } ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot did not find a calibration file, try OTP next: %d\n", + "boot did not find a calibration file, try DT next: %d\n", + ret); + + ret = ath10k_download_cal_dt(ar); + if (ret == 0) { + ar->cal_mode = ATH10K_CAL_MODE_DT; + goto done; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot did not find DT entry, try OTP next: %d\n", ret); ret = ath10k_download_and_run_otp(ar); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 514c219263a5..69f78bf88023 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -401,6 +401,7 @@ enum ath10k_dev_flags { enum ath10k_cal_mode { ATH10K_CAL_MODE_FILE, ATH10K_CAL_MODE_OTP, + ATH10K_CAL_MODE_DT, }; static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) @@ -410,6 +411,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) return "file"; case ATH10K_CAL_MODE_OTP: return "otp"; + case ATH10K_CAL_MODE_DT: + return "dt"; } return "unknown"; -- cgit v1.2.1 From 7505f7c3ec1d2f13ed75fef6b2681eb18e7d9147 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 2 Dec 2014 10:55:54 +0200 Subject: ath10k: create a chip revision whitelist This will make it easier to extend and maintain list of supported hardware. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 37 ---------------------------------- drivers/net/wireless/ath/ath10k/pci.c | 31 ++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/pci.h | 5 +++++ 3 files changed, 36 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 6165f2735b35..3a299fc8be88 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1136,34 +1136,6 @@ static int ath10k_core_probe_fw(struct ath10k *ar) return 0; } -static int ath10k_core_check_chip_id(struct ath10k *ar) -{ - u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV); - - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n", - ar->chip_id, hw_revision); - - /* Check that we are not using hw1.0 (some of them have same pci id - * as hw2.0) before doing anything else as ath10k crashes horribly - * due to missing hw1.0 workarounds. */ - switch (hw_revision) { - case QCA988X_HW_1_0_CHIP_ID_REV: - ath10k_err(ar, "ERROR: qca988x hw1.0 is not supported\n"); - return -EOPNOTSUPP; - - case QCA988X_HW_2_0_CHIP_ID_REV: - /* known hardware revision, continue normally */ - return 0; - - default: - ath10k_warn(ar, "Warning: hardware revision unknown (0x%x), expect problems\n", - ar->chip_id); - return 0; - } - - return 0; -} - static void ath10k_core_register_work(struct work_struct *work) { struct ath10k *ar = container_of(work, struct ath10k, register_work); @@ -1211,16 +1183,7 @@ err: int ath10k_core_register(struct ath10k *ar, u32 chip_id) { - int status; - ar->chip_id = chip_id; - - status = ath10k_core_check_chip_id(ar); - if (status) { - ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id); - return status; - } - queue_work(ar->workqueue, &ar->register_work); return 0; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 7abb8367119a..5e50214246f8 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -64,6 +64,14 @@ static const struct pci_device_id ath10k_pci_id_table[] = { {0} }; +static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { + /* QCA988X pre 2.0 chips are not supported because they need some nasty + * hacks. ath10k doesn't have them and these devices crash horribly + * because of that. + */ + { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV }, +}; + static void ath10k_pci_buffer_cleanup(struct ath10k *ar); static int ath10k_pci_cold_reset(struct ath10k *ar); static int ath10k_pci_warm_reset(struct ath10k *ar); @@ -2476,6 +2484,23 @@ static void ath10k_pci_release(struct ath10k *ar) pci_disable_device(pdev); } +static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id) +{ + const struct ath10k_pci_supp_chip *supp_chip; + int i; + u32 rev_id = MS(chip_id, SOC_CHIP_ID_REV); + + for (i = 0; i < ARRAY_SIZE(ath10k_pci_supp_chips); i++) { + supp_chip = &ath10k_pci_supp_chips[i]; + + if (supp_chip->dev_id == dev_id && + supp_chip->rev_id == rev_id) + return true; + } + + return false; +} + static int ath10k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_dev) { @@ -2521,6 +2546,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_sleep; } + if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) { + ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", + pdev->device, chip_id); + goto err_sleep; + } + ret = ath10k_pci_alloc_pipes(ar); if (ret) { ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index cf36511c7f4d..ce4a1ef89961 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -152,6 +152,11 @@ struct ath10k_pci_pipe { struct tasklet_struct intr; }; +struct ath10k_pci_supp_chip { + u32 dev_id; + u32 rev_id; +}; + struct ath10k_pci { struct pci_dev *pdev; struct device *dev; -- cgit v1.2.1 From 9764a2af0d592c6a9b95c913b1d65a2d4a2dc78e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 2 Dec 2014 10:55:54 +0200 Subject: ath10k: put board size into hw_params This makes it easier to extend the list of supported hardware. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 8 +++++--- drivers/net/wireless/ath/ath10k/core.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3a299fc8be88..e038e3e44971 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -54,6 +54,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .fw = QCA988X_HW_2_0_FW_FILE, .otp = QCA988X_HW_2_0_OTP_FILE, .board = QCA988X_HW_2_0_BOARD_DATA_FILE, + .board_size = QCA988X_BOARD_DATA_SZ, + .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ, }, }, }; @@ -147,8 +149,8 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data, size_t data_len) { - u32 board_data_size = QCA988X_BOARD_DATA_SZ; - u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ; + u32 board_data_size = ar->hw_params.fw.board_size; + u32 board_ext_data_size = ar->hw_params.fw.board_ext_size; u32 board_ext_data_addr; int ret; @@ -194,7 +196,7 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data, static int ath10k_download_board_data(struct ath10k *ar, const void *data, size_t data_len) { - u32 board_data_size = QCA988X_BOARD_DATA_SZ; + u32 board_data_size = ar->hw_params.fw.board_size; u32 address; int ret; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 69f78bf88023..2de5a0c6d725 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -489,6 +489,8 @@ struct ath10k { const char *fw; const char *otp; const char *board; + size_t board_size; + size_t board_ext_size; } fw; } hw_params; -- cgit v1.2.1 From 3a8200b226e683097945ae9620b0aef19df86a40 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 2 Dec 2014 10:55:55 +0200 Subject: ath10k: move uart pin config into hw_params This will make it possible to easily support different hardware with different uart pin configuration. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 3 ++- drivers/net/wireless/ath/ath10k/core.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index e038e3e44971..54fdc716597c 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -49,6 +49,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .id = QCA988X_HW_2_0_VERSION, .name = "qca988x hw2.0", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, + .uart_pin = 7, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, .fw = QCA988X_HW_2_0_FW_FILE, @@ -766,7 +767,7 @@ static int ath10k_init_uart(struct ath10k *ar) if (!uart_print) return 0; - ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7); + ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin); if (ret) { ath10k_warn(ar, "could not enable UART prints (%d)\n", ret); return ret; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 2de5a0c6d725..44bee8850586 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -483,6 +483,7 @@ struct ath10k { u32 id; const char *name; u32 patch_load_addr; + int uart_pin; struct ath10k_hw_params_fw { const char *dir; -- cgit v1.2.1 From c6ce492d03e89e1f1a30cbdab777e9367baeae34 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 3 Dec 2014 10:09:31 +0200 Subject: ath10k: clean up error handling in ath10k_core_probe_fw() Use the error handling style preferred in ath10k. Makes it easier to add ath10k_init_firmware_features() function in the next patch. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 54fdc716597c..e5790b84d8ba 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1096,8 +1096,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ret = ath10k_bmi_get_target_info(ar, &target_info); if (ret) { ath10k_err(ar, "could not get target info (%d)\n", ret); - ath10k_hif_power_down(ar); - return ret; + goto err_power_down; } ar->target_version = target_info.version; @@ -1106,15 +1105,13 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ret = ath10k_init_hw_params(ar); if (ret) { ath10k_err(ar, "could not get hw params (%d)\n", ret); - ath10k_hif_power_down(ar); - return ret; + goto err_power_down; } ret = ath10k_core_fetch_firmware_files(ar); if (ret) { ath10k_err(ar, "could not fetch firmware files (%d)\n", ret); - ath10k_hif_power_down(ar); - return ret; + goto err_power_down; } ath10k_core_init_max_sta_count(ar); @@ -1124,10 +1121,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); if (ret) { ath10k_err(ar, "could not init core (%d)\n", ret); - ath10k_core_free_firmware_files(ar); - ath10k_hif_power_down(ar); - mutex_unlock(&ar->conf_mutex); - return ret; + goto err_unlock; } ath10k_print_driver_info(ar); @@ -1137,6 +1131,16 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ath10k_hif_power_down(ar); return 0; + +err_unlock: + mutex_unlock(&ar->conf_mutex); + + ath10k_core_free_firmware_files(ar); + +err_power_down: + ath10k_hif_power_down(ar); + + return ret; } static void ath10k_core_register_work(struct work_struct *work) -- cgit v1.2.1 From 5f2144d9b2ea297aa75f0f952be96af7f02360f1 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 3 Dec 2014 10:09:59 +0200 Subject: ath10k: create ath10k_core_init_features() It's easier to manage firmware version differences when we configure them in one place. Rename ath10k_core_init_max_sta_count() to ath10k_core_init_firmware_features() and start moving most of the firmware version ("features") handling to that function. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index e5790b84d8ba..6c47c1e28292 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -643,13 +643,6 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) goto err; } - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) && - !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); - ret = -EINVAL; - goto err; - } - /* now fetch the board file */ if (ar->hw_params.fw.board == NULL) { ath10k_err(ar, "board data file not defined"); @@ -870,8 +863,14 @@ static void ath10k_core_restart(struct work_struct *work) mutex_unlock(&ar->conf_mutex); } -static void ath10k_core_init_max_sta_count(struct ath10k *ar) +static int ath10k_core_init_firmware_features(struct ath10k *ar) { + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) && + !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); + return -EINVAL; + } + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { ar->max_num_peers = TARGET_10X_NUM_PEERS; ar->max_num_stations = TARGET_10X_NUM_STATIONS; @@ -879,6 +878,8 @@ static void ath10k_core_init_max_sta_count(struct ath10k *ar) ar->max_num_peers = TARGET_NUM_PEERS; ar->max_num_stations = TARGET_NUM_STATIONS; } + + return 0; } int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) @@ -1114,7 +1115,12 @@ static int ath10k_core_probe_fw(struct ath10k *ar) goto err_power_down; } - ath10k_core_init_max_sta_count(ar); + ret = ath10k_core_init_firmware_features(ar); + if (ret) { + ath10k_err(ar, "fatal problem with firmware features: %d\n", + ret); + goto err_free_firmware_files; + } mutex_lock(&ar->conf_mutex); @@ -1135,6 +1141,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) err_unlock: mutex_unlock(&ar->conf_mutex); +err_free_firmware_files: ath10k_core_free_firmware_files(ar); err_power_down: -- cgit v1.2.1 From 202e86e60646d6987e3a3e63871453401e72d451 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 3 Dec 2014 10:10:08 +0200 Subject: ath10k: add ATH10K_FW_IE_WMI_OP_VERSION Instead of using feature flags, add new 32 bit variable for managing different WMI versions. This makes it firmware interface tests a bit less convoluted, especially when we add one more interface. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 49 ++++++++++++++++++++++++++++++---- drivers/net/wireless/ath/ath10k/core.h | 8 +++--- drivers/net/wireless/ath/ath10k/hw.h | 16 +++++++++++ 3 files changed, 65 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 6c47c1e28292..16f210e0b833 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -508,7 +508,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) int ie_id, i, index, bit, ret; struct ath10k_fw_ie *hdr; const u8 *data; - __le32 *timestamp; + __le32 *timestamp, *version; /* first fetch the firmware file (firmware-*.bin) */ ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); @@ -623,6 +623,17 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) ar->otp_len = ie_len; break; + case ATH10K_FW_IE_WMI_OP_VERSION: + if (ie_len != sizeof(u32)) + break; + + version = (__le32 *)data; + + ar->wmi.op_version = le32_to_cpup(version); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n", + ar->wmi.op_version); + break; default: ath10k_warn(ar, "Unknown FW IE: %u\n", le32_to_cpu(hdr->id)); @@ -871,12 +882,40 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) return -EINVAL; } - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - ar->max_num_peers = TARGET_10X_NUM_PEERS; - ar->max_num_stations = TARGET_10X_NUM_STATIONS; - } else { + if (ar->wmi.op_version >= ATH10K_FW_WMI_OP_VERSION_MAX) { + ath10k_err(ar, "unsupported WMI OP version (max %d): %d\n", + ATH10K_FW_WMI_OP_VERSION_MAX, ar->wmi.op_version); + return -EINVAL; + } + + /* Backwards compatibility for firmwares without + * ATH10K_FW_IE_WMI_OP_VERSION. + */ + if (ar->wmi.op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) { + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) + ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_2; + else + ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; + } else { + ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_MAIN; + } + } + + switch (ar->wmi.op_version) { + case ATH10K_FW_WMI_OP_VERSION_MAIN: ar->max_num_peers = TARGET_NUM_PEERS; ar->max_num_stations = TARGET_NUM_STATIONS; + break; + case ATH10K_FW_WMI_OP_VERSION_10_1: + case ATH10K_FW_WMI_OP_VERSION_10_2: + ar->max_num_peers = TARGET_10X_NUM_PEERS; + ar->max_num_stations = TARGET_10X_NUM_STATIONS; + break; + case ATH10K_FW_WMI_OP_VERSION_UNSET: + case ATH10K_FW_WMI_OP_VERSION_MAX: + WARN_ON(1); + return -EINVAL; } return 0; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 44bee8850586..0ae1df65b048 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -120,6 +120,7 @@ struct ath10k_mem_chunk { }; struct ath10k_wmi { + enum ath10k_fw_wmi_op_version op_version; enum ath10k_htc_ep_id eid; struct completion service_ready; struct completion unified_ready; @@ -369,7 +370,7 @@ enum ath10k_fw_features { /* wmi_mgmt_rx_hdr contains extra RSSI information */ ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0, - /* firmware from 10X branch */ + /* Firmware from 10X branch. Deprecated, don't use in new code. */ ATH10K_FW_FEATURE_WMI_10X = 1, /* firmware support tx frame management over WMI, otherwise it's HTT */ @@ -378,8 +379,9 @@ enum ath10k_fw_features { /* Firmware does not support P2P */ ATH10K_FW_FEATURE_NO_P2P = 3, - /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature bit - * is required to be set as well. + /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature + * bit is required to be set as well. Deprecated, don't use in new + * code. */ ATH10K_FW_FEATURE_WMI_10_2 = 4, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index dfedfd0e0f34..5bae90c3db99 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -58,6 +58,22 @@ enum ath10k_fw_ie_type { ATH10K_FW_IE_FEATURES = 2, ATH10K_FW_IE_FW_IMAGE = 3, ATH10K_FW_IE_OTP_IMAGE = 4, + + /* WMI "operations" interface version, 32 bit value. Supported from + * FW API 4 and above. + */ + ATH10K_FW_IE_WMI_OP_VERSION = 5, +}; + +enum ath10k_fw_wmi_op_version { + ATH10K_FW_WMI_OP_VERSION_UNSET = 0, + + ATH10K_FW_WMI_OP_VERSION_MAIN = 1, + ATH10K_FW_WMI_OP_VERSION_10_1 = 2, + ATH10K_FW_WMI_OP_VERSION_10_2 = 3, + + /* keep last */ + ATH10K_FW_WMI_OP_VERSION_MAX, }; /* Known pecularities: -- cgit v1.2.1 From 91ad5f56f62c0a5582f79fa6306ac189f0ef41bd Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 3 Dec 2014 10:10:17 +0200 Subject: ath10k: set max_num_pending_tx in ath10k_core_init_firmware_features() Better to have this in same place as other firmware interface handling. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 ++ drivers/net/wireless/ath/ath10k/htt_tx.c | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 16f210e0b833..54a1257f8535 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -906,11 +906,13 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_MAIN: ar->max_num_peers = TARGET_NUM_PEERS; ar->max_num_stations = TARGET_NUM_STATIONS; + ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC; break; case ATH10K_FW_WMI_OP_VERSION_10_1: case ATH10K_FW_WMI_OP_VERSION_10_2: ar->max_num_peers = TARGET_10X_NUM_PEERS; ar->max_num_stations = TARGET_10X_NUM_STATIONS; + ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 4bc51d8a14a3..a1bda41fb543 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -93,11 +93,6 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) spin_lock_init(&htt->tx_lock); - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features)) - htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; - else - htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC; - ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", htt->max_num_pending_tx); -- cgit v1.2.1 From 32653cf19554ddb77e9528851df3eed3ea35619d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 3 Dec 2014 10:10:26 +0200 Subject: ath10k: implement intermediate event args This splits the actual event parsing into intermediary structures to facilitate future support of vastly different ABI WMI backends. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 383 +++++++++++++++++++++++++--------- drivers/net/wireless/ath/ath10k/wmi.h | 61 +++++- 2 files changed, 348 insertions(+), 96 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c0f3e4d09263..4a9468e1573d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -977,22 +977,48 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, } } +static int ath10k_wmi_pull_scan_ev(struct sk_buff *skb, + struct wmi_scan_ev_arg *arg) +{ + struct wmi_scan_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->event_type = ev->event_type; + arg->reason = ev->reason; + arg->channel_freq = ev->channel_freq; + arg->scan_req_id = ev->scan_req_id; + arg->scan_id = ev->scan_id; + arg->vdev_id = ev->vdev_id; + + return 0; +} + static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) { - struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data; + struct wmi_scan_ev_arg arg = {}; enum wmi_scan_event_type event_type; enum wmi_scan_completion_reason reason; u32 freq; u32 req_id; u32 scan_id; u32 vdev_id; + int ret; - event_type = __le32_to_cpu(event->event_type); - reason = __le32_to_cpu(event->reason); - freq = __le32_to_cpu(event->channel_freq); - req_id = __le32_to_cpu(event->scan_req_id); - scan_id = __le32_to_cpu(event->scan_id); - vdev_id = __le32_to_cpu(event->vdev_id); + ret = ath10k_wmi_pull_scan_ev(skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse scan event: %d\n", ret); + return ret; + } + + event_type = __le32_to_cpu(arg.event_type); + reason = __le32_to_cpu(arg.reason); + freq = __le32_to_cpu(arg.channel_freq); + req_id = __le32_to_cpu(arg.scan_req_id); + scan_id = __le32_to_cpu(arg.scan_id); + vdev_id = __le32_to_cpu(arg.vdev_id); spin_lock_bh(&ar->data_lock); @@ -1147,11 +1173,52 @@ static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar, } } -static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_pull_mgmt_rx_ev(struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg, + struct ath10k *ar) { struct wmi_mgmt_rx_event_v1 *ev_v1; struct wmi_mgmt_rx_event_v2 *ev_v2; struct wmi_mgmt_rx_hdr_v1 *ev_hdr; + size_t pull_len; + u32 msdu_len; + + if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) { + ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data; + ev_hdr = &ev_v2->hdr.v1; + pull_len = sizeof(*ev_v2); + } else { + ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data; + ev_hdr = &ev_v1->hdr; + pull_len = sizeof(*ev_v1); + } + + if (skb->len < pull_len) + return -EPROTO; + + skb_pull(skb, pull_len); + arg->channel = ev_hdr->channel; + arg->buf_len = ev_hdr->buf_len; + arg->status = ev_hdr->status; + arg->snr = ev_hdr->snr; + arg->phy_mode = ev_hdr->phy_mode; + arg->rate = ev_hdr->rate; + + msdu_len = __le32_to_cpu(arg->buf_len); + if (skb->len < msdu_len) + return -EPROTO; + + /* the WMI buffer might've ended up being padded to 4 bytes due to HTC + * trailer with credit update. Trim the excess garbage. + */ + skb_trim(skb, msdu_len); + + return 0; +} + +static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_mgmt_rx_ev_arg arg = {}; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr; u32 rx_status; @@ -1161,24 +1228,20 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) u32 rate; u32 buf_len; u16 fc; - int pull_len; + int ret; - if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) { - ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data; - ev_hdr = &ev_v2->hdr.v1; - pull_len = sizeof(*ev_v2); - } else { - ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data; - ev_hdr = &ev_v1->hdr; - pull_len = sizeof(*ev_v1); + ret = ath10k_wmi_pull_mgmt_rx_ev(skb, &arg, ar); + if (ret) { + ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret); + return ret; } - channel = __le32_to_cpu(ev_hdr->channel); - buf_len = __le32_to_cpu(ev_hdr->buf_len); - rx_status = __le32_to_cpu(ev_hdr->status); - snr = __le32_to_cpu(ev_hdr->snr); - phy_mode = __le32_to_cpu(ev_hdr->phy_mode); - rate = __le32_to_cpu(ev_hdr->rate); + channel = __le32_to_cpu(arg.channel); + buf_len = __le32_to_cpu(arg.buf_len); + rx_status = __le32_to_cpu(arg.status); + snr = __le32_to_cpu(arg.snr); + phy_mode = __le32_to_cpu(arg.phy_mode); + rate = __le32_to_cpu(arg.rate); memset(status, 0, sizeof(*status)); @@ -1232,8 +1295,6 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR; status->rate_idx = get_rate_idx(rate, status->band); - skb_pull(skb, pull_len); - hdr = (struct ieee80211_hdr *)skb->data; fc = le16_to_cpu(hdr->frame_control); @@ -1266,12 +1327,6 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) status->freq, status->band, status->signal, status->rate_idx); - /* - * packets from HTC come aligned to 4byte boundaries - * because they can originally come in along with a trailer - */ - skb_trim(skb, buf_len); - ieee80211_rx(ar->hw, skb); return 0; } @@ -1295,21 +1350,44 @@ exit: return idx; } +static int ath10k_wmi_pull_ch_info_ev(struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg) +{ + struct wmi_chan_info_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->err_code = ev->err_code; + arg->freq = ev->freq; + arg->cmd_flags = ev->cmd_flags; + arg->noise_floor = ev->noise_floor; + arg->rx_clear_count = ev->rx_clear_count; + arg->cycle_count = ev->cycle_count; + + return 0; +} + static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) { - struct wmi_chan_info_event *ev; + struct wmi_ch_info_ev_arg arg = {}; struct survey_info *survey; u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count; - int idx; + int idx, ret; - ev = (struct wmi_chan_info_event *)skb->data; + ret = ath10k_wmi_pull_ch_info_ev(skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse chan info event: %d\n", ret); + return; + } - err_code = __le32_to_cpu(ev->err_code); - freq = __le32_to_cpu(ev->freq); - cmd_flags = __le32_to_cpu(ev->cmd_flags); - noise_floor = __le32_to_cpu(ev->noise_floor); - rx_clear_count = __le32_to_cpu(ev->rx_clear_count); - cycle_count = __le32_to_cpu(ev->cycle_count); + err_code = __le32_to_cpu(arg.err_code); + freq = __le32_to_cpu(arg.freq); + cmd_flags = __le32_to_cpu(arg.cmd_flags); + noise_floor = __le32_to_cpu(arg.noise_floor); + rx_clear_count = __le32_to_cpu(arg.rx_clear_count); + cycle_count = __le32_to_cpu(arg.cycle_count); ath10k_dbg(ar, ATH10K_DBG_WMI, "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n", @@ -1566,16 +1644,38 @@ static void ath10k_wmi_event_update_stats(struct ath10k *ar, ath10k_debug_fw_stats_process(ar, skb); } +static int ath10k_wmi_pull_vdev_start_ev(struct sk_buff *skb, + struct wmi_vdev_start_ev_arg *arg) +{ + struct wmi_vdev_start_response_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->vdev_id = ev->vdev_id; + arg->req_id = ev->req_id; + arg->resp_type = ev->resp_type; + arg->status = ev->status; + + return 0; +} + static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb) { - struct wmi_vdev_start_response_event *ev; + struct wmi_vdev_start_ev_arg arg = {}; + int ret; ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n"); - ev = (struct wmi_vdev_start_response_event *)skb->data; + ret = ath10k_wmi_pull_vdev_start_ev(skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret); + return; + } - if (WARN_ON(__le32_to_cpu(ev->status))) + if (WARN_ON(__le32_to_cpu(arg.status))) return; complete(&ar->vdev_setup_done); @@ -1588,23 +1688,43 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, complete(&ar->vdev_setup_done); } +static int ath10k_wmi_pull_peer_kick_ev(struct sk_buff *skb, + struct wmi_peer_kick_ev_arg *arg) +{ + struct wmi_peer_sta_kickout_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->mac_addr = ev->peer_macaddr.addr; + + return 0; +} + static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb) { - struct wmi_peer_sta_kickout_event *ev; + struct wmi_peer_kick_ev_arg arg = {}; struct ieee80211_sta *sta; + int ret; - ev = (struct wmi_peer_sta_kickout_event *)skb->data; + ret = ath10k_wmi_pull_peer_kick_ev(skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse peer kickout event: %d\n", + ret); + return; + } ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n", - ev->peer_macaddr.addr); + arg.mac_addr); rcu_read_lock(); - sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL); + sta = ieee80211_find_sta_by_ifaddr(ar->hw, arg.mac_addr, NULL); if (!sta) { ath10k_warn(ar, "Spurious quick kickout for STA %pM\n", - ev->peer_macaddr.addr); + arg.mac_addr); goto exit; } @@ -1641,7 +1761,7 @@ exit: static void ath10k_wmi_update_tim(struct ath10k *ar, struct ath10k_vif *arvif, struct sk_buff *bcn, - struct wmi_bcn_info *bcn_info) + const struct wmi_tim_info *tim_info) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data; struct ieee80211_tim_ie *tim; @@ -1652,14 +1772,14 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, /* if next SWBA has no tim_changed the tim_bitmap is garbage. * we must copy the bitmap upon change and reuse it later */ - if (__le32_to_cpu(bcn_info->tim_info.tim_changed)) { + if (__le32_to_cpu(tim_info->tim_changed)) { int i; BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) != - sizeof(bcn_info->tim_info.tim_bitmap)); + sizeof(tim_info->tim_bitmap)); for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) { - t = bcn_info->tim_info.tim_bitmap[i / 4]; + t = tim_info->tim_bitmap[i / 4]; v = __le32_to_cpu(t); arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF; } @@ -1711,13 +1831,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, return; } - tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast); + tim->bitmap_ctrl = !!__le32_to_cpu(tim_info->tim_mcast); memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); if (tim->dtim_count == 0) { ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true; - if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1) + if (__le32_to_cpu(tim_info->tim_mcast) == 1) ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true; } @@ -1727,7 +1847,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, } static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len, - struct wmi_p2p_noa_info *noa) + const struct wmi_p2p_noa_info *noa) { struct ieee80211_p2p_noa_attr *noa_attr; u8 ctwindow_oppps = noa->ctwindow_oppps; @@ -1769,7 +1889,7 @@ static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len, *noa_attr_len = __cpu_to_le16(attr_len); } -static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa) +static u32 ath10k_p2p_calc_noa_ie_len(const struct wmi_p2p_noa_info *noa) { u32 len = 0; u8 noa_descriptors = noa->num_descriptors; @@ -1789,9 +1909,8 @@ static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa) static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif, struct sk_buff *bcn, - struct wmi_bcn_info *bcn_info) + const struct wmi_p2p_noa_info *noa) { - struct wmi_p2p_noa_info *noa = &bcn_info->p2p_noa_info; u8 *new_data, *old_data = arvif->u.ap.noa_data; u32 new_len; @@ -1832,22 +1951,59 @@ cleanup: kfree(old_data); } +static int ath10k_wmi_pull_swba_ev(struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) +{ + struct wmi_host_swba_event *ev = (void *)skb->data; + u32 map; + size_t i; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->vdev_map = ev->vdev_map; + + for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) { + if (!(map & BIT(0))) + continue; + + /* If this happens there were some changes in firmware and + * ath10k should update the max size of tim_info array. + */ + if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) + break; + + arg->tim_info[i] = &ev->bcn_info[i].tim_info; + arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info; + i++; + } + + return 0; +} + static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) { - struct wmi_host_swba_event *ev; + struct wmi_swba_ev_arg arg = {}; u32 map; int i = -1; - struct wmi_bcn_info *bcn_info; + const struct wmi_tim_info *tim_info; + const struct wmi_p2p_noa_info *noa_info; struct ath10k_vif *arvif; struct sk_buff *bcn; dma_addr_t paddr; int ret, vdev_id = 0; - ev = (struct wmi_host_swba_event *)skb->data; - map = __le32_to_cpu(ev->vdev_map); + ret = ath10k_wmi_pull_swba_ev(skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse swba event: %d\n", ret); + return; + } + + map = __le32_to_cpu(arg.vdev_map); ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n", - ev->vdev_map); + map); for (; map; map >>= 1, vdev_id++) { if (!(map & 0x1)) @@ -1860,19 +2016,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) break; } - bcn_info = &ev->bcn_info[i]; + tim_info = arg.tim_info[i]; + noa_info = arg.noa_info[i]; ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n", i, - __le32_to_cpu(bcn_info->tim_info.tim_len), - __le32_to_cpu(bcn_info->tim_info.tim_mcast), - __le32_to_cpu(bcn_info->tim_info.tim_changed), - __le32_to_cpu(bcn_info->tim_info.tim_num_ps_pending), - __le32_to_cpu(bcn_info->tim_info.tim_bitmap[3]), - __le32_to_cpu(bcn_info->tim_info.tim_bitmap[2]), - __le32_to_cpu(bcn_info->tim_info.tim_bitmap[1]), - __le32_to_cpu(bcn_info->tim_info.tim_bitmap[0])); + __le32_to_cpu(tim_info->tim_len), + __le32_to_cpu(tim_info->tim_mcast), + __le32_to_cpu(tim_info->tim_changed), + __le32_to_cpu(tim_info->tim_num_ps_pending), + __le32_to_cpu(tim_info->tim_bitmap[3]), + __le32_to_cpu(tim_info->tim_bitmap[2]), + __le32_to_cpu(tim_info->tim_bitmap[1]), + __le32_to_cpu(tim_info->tim_bitmap[0])); arvif = ath10k_get_arvif(ar, vdev_id); if (arvif == NULL) { @@ -1899,8 +2056,8 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) } ath10k_tx_h_seq_no(arvif->vif, bcn); - ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info); - ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); + ath10k_wmi_update_tim(ar, arvif, bcn, tim_info); + ath10k_wmi_update_noa(ar, arvif, bcn, noa_info); spin_lock_bh(&ar->data_lock); @@ -2188,37 +2345,53 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar, } } +static int ath10k_wmi_pull_phyerr_ev(struct sk_buff *skb, + struct wmi_phyerr_ev_arg *arg) +{ + struct wmi_phyerr_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + arg->num_phyerrs = ev->num_phyerrs; + arg->tsf_l32 = ev->tsf_l32; + arg->tsf_u32 = ev->tsf_u32; + arg->buf_len = __cpu_to_le32(skb->len - sizeof(*ev)); + arg->phyerrs = ev->phyerrs; + + return 0; +} + static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) { - const struct wmi_phyerr_event *ev; + struct wmi_phyerr_ev_arg arg = {}; const struct wmi_phyerr *phyerr; u32 count, i, buf_len, phy_err_code; u64 tsf; - int left_len = skb->len; + int left_len, ret; ATH10K_DFS_STAT_INC(ar, phy_errors); - /* Check if combined event available */ - if (left_len < sizeof(*ev)) { - ath10k_warn(ar, "wmi phyerr combined event wrong len\n"); + ret = ath10k_wmi_pull_phyerr_ev(skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse phyerr event: %d\n", ret); return; } - left_len -= sizeof(*ev); + left_len = __le32_to_cpu(arg.buf_len); /* Check number of included events */ - ev = (const struct wmi_phyerr_event *)skb->data; - count = __le32_to_cpu(ev->num_phyerrs); + count = __le32_to_cpu(arg.num_phyerrs); - tsf = __le32_to_cpu(ev->tsf_u32); + tsf = __le32_to_cpu(arg.tsf_u32); tsf <<= 32; - tsf |= __le32_to_cpu(ev->tsf_l32); + tsf |= __le32_to_cpu(arg.tsf_l32); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event phyerr count %d tsf64 0x%llX\n", count, tsf); - phyerr = ev->phyerrs; + phyerr = arg.phyerrs; for (i = 0; i < count; i++) { /* Check if we can read event header */ if (left_len < sizeof(*phyerr)) { @@ -2622,22 +2795,42 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar, complete(&ar->wmi.service_ready); } -static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_pull_rdy_ev(struct sk_buff *skb, + struct wmi_rdy_ev_arg *arg) { - struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data; + struct wmi_ready_event *ev = (void *)skb->data; - if (WARN_ON(skb->len < sizeof(*ev))) - return -EINVAL; + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->sw_version = ev->sw_version; + arg->abi_version = ev->abi_version; + arg->status = ev->status; + arg->mac_addr = ev->mac_addr.addr; + + return 0; +} - ether_addr_copy(ar->mac_addr, ev->mac_addr.addr); +static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_rdy_ev_arg arg = {}; + int ret; + + ret = ath10k_wmi_pull_rdy_ev(skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse ready event: %d\n", ret); + return ret; + } ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n", - __le32_to_cpu(ev->sw_version), - __le32_to_cpu(ev->abi_version), - ev->mac_addr.addr, - __le32_to_cpu(ev->status), skb->len, sizeof(*ev)); + "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n", + __le32_to_cpu(arg.sw_version), + __le32_to_cpu(arg.abi_version), + arg.mac_addr, + __le32_to_cpu(arg.status)); + ether_addr_copy(ar->mac_addr, arg.mac_addr); complete(&ar->wmi.unified_ready); return 0; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 21391929d318..0a38798224db 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4120,7 +4120,7 @@ struct wmi_bcn_info { struct wmi_host_swba_event { __le32 vdev_map; - struct wmi_bcn_info bcn_info[1]; + struct wmi_bcn_info bcn_info[0]; } __packed; #define WMI_MAX_AP_VDEV 16 @@ -4567,6 +4567,58 @@ struct wmi_dbglog_cfg_cmd { #define WMI_MAX_MEM_REQS 16 +struct wmi_scan_ev_arg { + __le32 event_type; /* %WMI_SCAN_EVENT_ */ + __le32 reason; /* %WMI_SCAN_REASON_ */ + __le32 channel_freq; /* only valid for WMI_SCAN_EVENT_FOREIGN_CHANNEL */ + __le32 scan_req_id; + __le32 scan_id; + __le32 vdev_id; +}; + +struct wmi_mgmt_rx_ev_arg { + __le32 channel; + __le32 snr; + __le32 rate; + __le32 phy_mode; + __le32 buf_len; + __le32 status; /* %WMI_RX_STATUS_ */ +}; + +struct wmi_ch_info_ev_arg { + __le32 err_code; + __le32 freq; + __le32 cmd_flags; + __le32 noise_floor; + __le32 rx_clear_count; + __le32 cycle_count; +}; + +struct wmi_vdev_start_ev_arg { + __le32 vdev_id; + __le32 req_id; + __le32 resp_type; /* %WMI_VDEV_RESP_ */ + __le32 status; +}; + +struct wmi_peer_kick_ev_arg { + const u8 *mac_addr; +}; + +struct wmi_swba_ev_arg { + __le32 vdev_map; + const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV]; + const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV]; +}; + +struct wmi_phyerr_ev_arg { + __le32 num_phyerrs; + __le32 tsf_l32; + __le32 tsf_u32; + __le32 buf_len; + const struct wmi_phyerr *phyerrs; +}; + struct wmi_svc_rdy_ev_arg { __le32 min_tx_power; __le32 max_tx_power; @@ -4583,6 +4635,13 @@ struct wmi_svc_rdy_ev_arg { const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; }; +struct wmi_rdy_ev_arg { + __le32 sw_version; + __le32 abi_version; + __le32 status; + const u8 *mac_addr; +}; + struct ath10k; struct ath10k_vif; struct ath10k_fw_stats; -- cgit v1.2.1 From d7579d12c33f87de9975d17880d708b50e959bbb Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 3 Dec 2014 10:10:54 +0200 Subject: ath10k: introduce wmi ops Since the 10.x fw branch support was introduced it became apparent ath10k will need to be able to deal with different fw ABIs eventually. The patch creates an abstraction for dealing with command and event structures across different ABIs and mostly gets rid of the ATH10K_FW_FEATURE_WMI_10X flag usage. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/core.h | 2 + drivers/net/wireless/ath/ath10k/debug.c | 1 + drivers/net/wireless/ath/ath10k/mac.c | 2 + drivers/net/wireless/ath/ath10k/spectral.c | 1 + drivers/net/wireless/ath/ath10k/testmode.c | 5 +- drivers/net/wireless/ath/ath10k/wmi-ops.h | 821 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 906 +++++++++++++++++------------ drivers/net/wireless/ath/ath10k/wmi.h | 67 +-- 9 files changed, 1364 insertions(+), 442 deletions(-) create mode 100644 drivers/net/wireless/ath/ath10k/wmi-ops.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 54a1257f8535..d83d9a7ddd77 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -28,6 +28,7 @@ #include "debug.h" #include "htt.h" #include "testmode.h" +#include "wmi-ops.h" unsigned int ath10k_debug_mask; static bool uart_print; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 0ae1df65b048..3f15c134b90e 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -129,6 +129,7 @@ struct ath10k_wmi { struct wmi_cmd_map *cmd; struct wmi_vdev_param_map *vdev_param; struct wmi_pdev_param_map *pdev_param; + const struct wmi_ops *ops; u32 num_mem_chunks; struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS]; @@ -618,6 +619,7 @@ struct ath10k { /* protected by conf_mutex */ const struct firmware *utf; DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT); + enum ath10k_fw_wmi_op_version orig_wmi_op_version; /* protected by data_lock */ bool utf_monitor; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index a716758f14b0..c15b5774dd20 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -23,6 +23,7 @@ #include "core.h" #include "debug.h" #include "hif.h" +#include "wmi-ops.h" /* ms */ #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c4005670cba2..5475f0fbbe41 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -27,6 +27,8 @@ #include "htt.h" #include "txrx.h" #include "testmode.h" +#include "wmi.h" +#include "wmi-ops.h" /**********/ /* Crypto */ diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index 63ce61fcdac8..d22addf6118b 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -17,6 +17,7 @@ #include #include "core.h" #include "debug.h" +#include "wmi-ops.h" static void send_fft_sample(struct ath10k *ar, const struct fft_sample_tlv *fft_sample_tlv) diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c index 483db9cb8c96..b084f88da102 100644 --- a/drivers/net/wireless/ath/ath10k/testmode.c +++ b/drivers/net/wireless/ath/ath10k/testmode.c @@ -187,13 +187,14 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) memcpy(ar->testmode.orig_fw_features, ar->fw_features, sizeof(ar->fw_features)); + ar->testmode.orig_wmi_op_version = ar->wmi.op_version; /* utf.bin firmware image does not advertise firmware features. Do * an ugly hack where we force the firmware features so that wmi.c * will use the correct WMI interface. */ memset(ar->fw_features, 0, sizeof(ar->fw_features)); - __set_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features); + ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; ret = ath10k_hif_power_up(ar); if (ret) { @@ -224,6 +225,7 @@ err_fw_features: /* return the original firmware features */ memcpy(ar->fw_features, ar->testmode.orig_fw_features, sizeof(ar->fw_features)); + ar->wmi.op_version = ar->testmode.orig_wmi_op_version; release_firmware(ar->testmode.utf); ar->testmode.utf = NULL; @@ -250,6 +252,7 @@ static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar) /* return the original firmware features */ memcpy(ar->fw_features, ar->testmode.orig_fw_features, sizeof(ar->fw_features)); + ar->wmi.op_version = ar->testmode.orig_wmi_op_version; release_firmware(ar->testmode.utf); ar->testmode.utf = NULL; diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h new file mode 100644 index 000000000000..1fbc5207b870 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -0,0 +1,821 @@ +/* + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WMI_OPS_H_ +#define _WMI_OPS_H_ + +struct ath10k; +struct sk_buff; + +struct wmi_ops { + void (*rx)(struct ath10k *ar, struct sk_buff *skb); + void (*map_svc)(const __le32 *in, unsigned long *out, size_t len); + + int (*pull_scan)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_scan_ev_arg *arg); + int (*pull_mgmt_rx)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg); + int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg); + int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_vdev_start_ev_arg *arg); + int (*pull_peer_kick)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_peer_kick_ev_arg *arg); + int (*pull_swba)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_swba_ev_arg *arg); + int (*pull_phyerr)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_phyerr_ev_arg *arg); + int (*pull_svc_rdy)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg); + int (*pull_rdy)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_rdy_ev_arg *arg); + int (*pull_fw_stats)(struct ath10k *ar, struct sk_buff *skb, + struct ath10k_fw_stats *stats); + + struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt); + struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar); + struct sk_buff *(*gen_pdev_set_rd)(struct ath10k *ar, u16 rd, u16 rd2g, + u16 rd5g, u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg); + struct sk_buff *(*gen_pdev_set_param)(struct ath10k *ar, u32 id, + u32 value); + struct sk_buff *(*gen_init)(struct ath10k *ar); + struct sk_buff *(*gen_start_scan)(struct ath10k *ar, + const struct wmi_start_scan_arg *arg); + struct sk_buff *(*gen_stop_scan)(struct ath10k *ar, + const struct wmi_stop_scan_arg *arg); + struct sk_buff *(*gen_vdev_create)(struct ath10k *ar, u32 vdev_id, + enum wmi_vdev_type type, + enum wmi_vdev_subtype subtype, + const u8 macaddr[ETH_ALEN]); + struct sk_buff *(*gen_vdev_delete)(struct ath10k *ar, u32 vdev_id); + struct sk_buff *(*gen_vdev_start)(struct ath10k *ar, + const struct wmi_vdev_start_request_arg *arg, + bool restart); + struct sk_buff *(*gen_vdev_stop)(struct ath10k *ar, u32 vdev_id); + struct sk_buff *(*gen_vdev_up)(struct ath10k *ar, u32 vdev_id, u32 aid, + const u8 *bssid); + struct sk_buff *(*gen_vdev_down)(struct ath10k *ar, u32 vdev_id); + struct sk_buff *(*gen_vdev_set_param)(struct ath10k *ar, u32 vdev_id, + u32 param_id, u32 param_value); + struct sk_buff *(*gen_vdev_install_key)(struct ath10k *ar, + const struct wmi_vdev_install_key_arg *arg); + struct sk_buff *(*gen_vdev_spectral_conf)(struct ath10k *ar, + const struct wmi_vdev_spectral_conf_arg *arg); + struct sk_buff *(*gen_vdev_spectral_enable)(struct ath10k *ar, u32 vdev_id, + u32 trigger, u32 enable); + struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]); + struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]); + struct sk_buff *(*gen_peer_flush)(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], + u32 tid_bitmap); + struct sk_buff *(*gen_peer_set_param)(struct ath10k *ar, u32 vdev_id, + const u8 *peer_addr, + enum wmi_peer_param param_id, + u32 param_value); + struct sk_buff *(*gen_peer_assoc)(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg); + struct sk_buff *(*gen_set_psmode)(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_ps_mode psmode); + struct sk_buff *(*gen_set_sta_ps)(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_powersave_param param_id, + u32 value); + struct sk_buff *(*gen_set_ap_ps)(struct ath10k *ar, u32 vdev_id, + const u8 *mac, + enum wmi_ap_ps_peer_param param_id, + u32 value); + struct sk_buff *(*gen_scan_chan_list)(struct ath10k *ar, + const struct wmi_scan_chan_list_arg *arg); + struct sk_buff *(*gen_beacon_dma)(struct ath10k_vif *arvif); + struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar, + const struct wmi_pdev_set_wmm_params_arg *arg); + struct sk_buff *(*gen_request_stats)(struct ath10k *ar, + enum wmi_stats_id stats_id); + struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar, + enum wmi_force_fw_hang_type type, + u32 delay_ms); + struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb); + struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u32 module_enable); + struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter); + struct sk_buff *(*gen_pktlog_disable)(struct ath10k *ar); +}; + +int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); + +static inline int +ath10k_wmi_rx(struct ath10k *ar, struct sk_buff *skb) +{ + if (WARN_ON_ONCE(!ar->wmi.ops->rx)) + return -EOPNOTSUPP; + + ar->wmi.ops->rx(ar, skb); + return 0; +} + +static inline int +ath10k_wmi_map_svc(struct ath10k *ar, const __le32 *in, unsigned long *out, + size_t len) +{ + if (!ar->wmi.ops->map_svc) + return -EOPNOTSUPP; + + ar->wmi.ops->map_svc(in, out, len); + return 0; +} + +static inline int +ath10k_wmi_pull_scan(struct ath10k *ar, struct sk_buff *skb, + struct wmi_scan_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_scan) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_scan(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_mgmt_rx) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_mgmt_rx(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_ch_info(struct ath10k *ar, struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_ch_info) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_ch_info(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_vdev_start(struct ath10k *ar, struct sk_buff *skb, + struct wmi_vdev_start_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_vdev_start) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_vdev_start(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_peer_kick(struct ath10k *ar, struct sk_buff *skb, + struct wmi_peer_kick_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_peer_kick) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_peer_kick(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_swba(struct ath10k *ar, struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_swba) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_swba(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_phyerr(struct ath10k *ar, struct sk_buff *skb, + struct wmi_phyerr_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_phyerr) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_phyerr(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_svc_rdy(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_svc_rdy) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_svc_rdy(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_rdy(struct ath10k *ar, struct sk_buff *skb, + struct wmi_rdy_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_rdy) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_rdy(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, + struct ath10k_fw_stats *stats) +{ + if (!ar->wmi.ops->pull_fw_stats) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_fw_stats(ar, skb, stats); +} + +static inline int +ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); + struct sk_buff *skb; + int ret; + + if (!ar->wmi.ops->gen_mgmt_tx) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_mgmt_tx(ar, msdu); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ret = ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->mgmt_tx_cmdid); + if (ret) + return ret; + + /* FIXME There's no ACK event for Management Tx. This probably + * shouldn't be called here either. */ + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(ar->hw, msdu); + + return 0; +} + +static inline int +ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g, + u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_set_rd) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_set_rd(ar, rd, rd2g, rd5g, ctl2g, ctl5g, + dfs_reg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_set_regdomain_cmdid); +} + +static inline int +ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_suspend) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_suspend(ar, suspend_opt); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid); +} + +static inline int +ath10k_wmi_pdev_resume_target(struct ath10k *ar) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_resume) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_resume(ar); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid); +} + +static inline int +ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_set_param) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_set_param(ar, id, value); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid); +} + +static inline int +ath10k_wmi_cmd_init(struct ath10k *ar) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_init) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_init(ar); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->init_cmdid); +} + +static inline int +ath10k_wmi_start_scan(struct ath10k *ar, + const struct wmi_start_scan_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_start_scan) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_start_scan(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid); +} + +static inline int +ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_stop_scan) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_stop_scan(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid); +} + +static inline int +ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, + enum wmi_vdev_type type, + enum wmi_vdev_subtype subtype, + const u8 macaddr[ETH_ALEN]) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_create) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_create(ar, vdev_id, type, subtype, macaddr); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid); +} + +static inline int +ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_delete) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_delete(ar, vdev_id); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid); +} + +static inline int +ath10k_wmi_vdev_start(struct ath10k *ar, + const struct wmi_vdev_start_request_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_start) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_start(ar, arg, false); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->vdev_start_request_cmdid); +} + +static inline int +ath10k_wmi_vdev_restart(struct ath10k *ar, + const struct wmi_vdev_start_request_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_start) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_start(ar, arg, true); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->vdev_restart_request_cmdid); +} + +static inline int +ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_stop) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_stop(ar, vdev_id); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid); +} + +static inline int +ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_up) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_up(ar, vdev_id, aid, bssid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid); +} + +static inline int +ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_down) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_down(ar, vdev_id); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid); +} + +static inline int +ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, u32 param_id, + u32 param_value) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_set_param) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_set_param(ar, vdev_id, param_id, + param_value); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid); +} + +static inline int +ath10k_wmi_vdev_install_key(struct ath10k *ar, + const struct wmi_vdev_install_key_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_install_key) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_install_key(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->vdev_install_key_cmdid); +} + +static inline int +ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, + const struct wmi_vdev_spectral_conf_arg *arg) +{ + struct sk_buff *skb; + u32 cmd_id; + + skb = ar->wmi.ops->gen_vdev_spectral_conf(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + +static inline int +ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, + u32 enable) +{ + struct sk_buff *skb; + u32 cmd_id; + + skb = ar->wmi.ops->gen_vdev_spectral_enable(ar, vdev_id, trigger, + enable); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + +static inline int +ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_peer_create) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid); +} + +static inline int +ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_peer_delete) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_peer_delete(ar, vdev_id, peer_addr); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid); +} + +static inline int +ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_peer_flush) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_peer_flush(ar, vdev_id, peer_addr, tid_bitmap); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid); +} + +static inline int +ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, const u8 *peer_addr, + enum wmi_peer_param param_id, u32 param_value) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_peer_set_param) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_peer_set_param(ar, vdev_id, peer_addr, param_id, + param_value); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid); +} + +static inline int +ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_ps_mode psmode) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_set_psmode) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_set_psmode(ar, vdev_id, psmode); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->sta_powersave_mode_cmdid); +} + +static inline int +ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_powersave_param param_id, u32 value) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_set_sta_ps) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_set_sta_ps(ar, vdev_id, param_id, value); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->sta_powersave_param_cmdid); +} + +static inline int +ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, + enum wmi_ap_ps_peer_param param_id, u32 value) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_set_ap_ps) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_set_ap_ps(ar, vdev_id, mac, param_id, value); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->ap_ps_peer_param_cmdid); +} + +static inline int +ath10k_wmi_scan_chan_list(struct ath10k *ar, + const struct wmi_scan_chan_list_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_scan_chan_list) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_scan_chan_list(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid); +} + +static inline int +ath10k_wmi_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_peer_assoc) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_peer_assoc(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); +} + +static inline int +ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + struct sk_buff *skb; + int ret; + + if (!ar->wmi.ops->gen_beacon_dma) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_beacon_dma(arvif); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ret = ath10k_wmi_cmd_send_nowait(ar, skb, + ar->wmi.cmd->pdev_send_bcn_cmdid); + if (ret) { + dev_kfree_skb(skb); + return ret; + } + + return 0; +} + +static inline int +ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, + const struct wmi_pdev_set_wmm_params_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_set_wmm) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_set_wmm(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_set_wmm_params_cmdid); +} + +static inline int +ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_request_stats) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_request_stats(ar, stats_id); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid); +} + +static inline int +ath10k_wmi_force_fw_hang(struct ath10k *ar, + enum wmi_force_fw_hang_type type, u32 delay_ms) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_force_fw_hang) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_force_fw_hang(ar, type, delay_ms); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); +} + +static inline int +ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_dbglog_cfg) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_dbglog_cfg(ar, module_enable); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid); +} + +static inline int +ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 filter) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pktlog_enable) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pktlog_enable(ar, filter); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_pktlog_enable_cmdid); +} + +static inline int +ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pktlog_disable) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pktlog_disable(ar); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_pktlog_disable_cmdid); +} + +#endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 4a9468e1573d..24bb97face30 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -24,6 +24,7 @@ #include "wmi.h" #include "mac.h" #include "testmode.h" +#include "wmi-ops.h" /* MAIN WMI cmd track */ static struct wmi_cmd_map wmi_cmd_map = { @@ -685,8 +686,8 @@ static void ath10k_wmi_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) dev_kfree_skb(skb); } -static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, - u32 cmd_id) +int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, + u32 cmd_id) { struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); struct wmi_cmd_hdr *cmd_hdr; @@ -792,24 +793,23 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) return ret; } -int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) +static struct sk_buff * +ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) { - int ret = 0; struct wmi_mgmt_tx_cmd *cmd; struct ieee80211_hdr *hdr; - struct sk_buff *wmi_skb; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct sk_buff *skb; int len; - u32 buf_len = skb->len; + u32 buf_len = msdu->len; u16 fc; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr *)msdu->data; fc = le16_to_cpu(hdr->frame_control); if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control))) - return -EINVAL; + return ERR_PTR(-EINVAL); - len = sizeof(cmd->hdr) + skb->len; + len = sizeof(cmd->hdr) + msdu->len; if ((ieee80211_is_action(hdr->frame_control) || ieee80211_is_deauth(hdr->frame_control) || @@ -821,36 +821,27 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) len = round_up(len, 4); - wmi_skb = ath10k_wmi_alloc_skb(ar, len); - if (!wmi_skb) - return -ENOMEM; + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); - cmd = (struct wmi_mgmt_tx_cmd *)wmi_skb->data; + cmd = (struct wmi_mgmt_tx_cmd *)skb->data; - cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id); + cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(msdu)->vdev_id); cmd->hdr.tx_rate = 0; cmd->hdr.tx_power = 0; cmd->hdr.buf_len = __cpu_to_le32(buf_len); ether_addr_copy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr)); - memcpy(cmd->buf, skb->data, skb->len); + memcpy(cmd->buf, msdu->data, msdu->len); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", - wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE, + msdu, skb->len, fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); trace_ath10k_tx_hdr(ar, skb->data, skb->len); trace_ath10k_tx_payload(ar, skb->data, skb->len); - /* Send the management frame buffer to the target */ - ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid); - if (ret) - return ret; - - /* TODO: report tx status to mac80211 - temporary just ACK */ - info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status_irqsafe(ar->hw, skb); - - return ret; + return skb; } static void ath10k_wmi_event_scan_started(struct ath10k *ar) @@ -977,8 +968,8 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, } } -static int ath10k_wmi_pull_scan_ev(struct sk_buff *skb, - struct wmi_scan_ev_arg *arg) +static int ath10k_wmi_op_pull_scan_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_scan_ev_arg *arg) { struct wmi_scan_event *ev = (void *)skb->data; @@ -1007,7 +998,7 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) u32 vdev_id; int ret; - ret = ath10k_wmi_pull_scan_ev(skb, &arg); + ret = ath10k_wmi_pull_scan(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse scan event: %d\n", ret); return ret; @@ -1173,9 +1164,8 @@ static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar, } } -static int ath10k_wmi_pull_mgmt_rx_ev(struct sk_buff *skb, - struct wmi_mgmt_rx_ev_arg *arg, - struct ath10k *ar) +static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg) { struct wmi_mgmt_rx_event_v1 *ev_v1; struct wmi_mgmt_rx_event_v2 *ev_v2; @@ -1230,7 +1220,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) u16 fc; int ret; - ret = ath10k_wmi_pull_mgmt_rx_ev(skb, &arg, ar); + ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret); return ret; @@ -1350,8 +1340,8 @@ exit: return idx; } -static int ath10k_wmi_pull_ch_info_ev(struct sk_buff *skb, - struct wmi_ch_info_ev_arg *arg) +static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg) { struct wmi_chan_info_event *ev = (void *)skb->data; @@ -1376,7 +1366,7 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count; int idx, ret; - ret = ath10k_wmi_pull_ch_info_ev(skb, &arg); + ret = ath10k_wmi_pull_ch_info(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse chan info event: %d\n", ret); return; @@ -1513,9 +1503,9 @@ static void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate); } -static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar, - struct sk_buff *skb, - struct ath10k_fw_stats *stats) +static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) { const struct wmi_stats_event *ev = (void *)skb->data; u32 num_pdev_stats, num_vdev_stats, num_peer_stats; @@ -1565,9 +1555,9 @@ static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar, return 0; } -static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar, - struct sk_buff *skb, - struct ath10k_fw_stats *stats) +static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) { const struct wmi_stats_event *ev = (void *)skb->data; u32 num_pdev_stats, num_vdev_stats, num_peer_stats; @@ -1628,15 +1618,6 @@ static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar, return 0; } -int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, - struct ath10k_fw_stats *stats) -{ - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - return ath10k_wmi_10x_pull_fw_stats(ar, skb, stats); - else - return ath10k_wmi_main_pull_fw_stats(ar, skb, stats); -} - static void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb) { @@ -1644,8 +1625,9 @@ static void ath10k_wmi_event_update_stats(struct ath10k *ar, ath10k_debug_fw_stats_process(ar, skb); } -static int ath10k_wmi_pull_vdev_start_ev(struct sk_buff *skb, - struct wmi_vdev_start_ev_arg *arg) +static int +ath10k_wmi_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_vdev_start_ev_arg *arg) { struct wmi_vdev_start_response_event *ev = (void *)skb->data; @@ -1669,7 +1651,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n"); - ret = ath10k_wmi_pull_vdev_start_ev(skb, &arg); + ret = ath10k_wmi_pull_vdev_start(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret); return; @@ -1688,8 +1670,9 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, complete(&ar->vdev_setup_done); } -static int ath10k_wmi_pull_peer_kick_ev(struct sk_buff *skb, - struct wmi_peer_kick_ev_arg *arg) +static int +ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_peer_kick_ev_arg *arg) { struct wmi_peer_sta_kickout_event *ev = (void *)skb->data; @@ -1709,7 +1692,7 @@ static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct ieee80211_sta *sta; int ret; - ret = ath10k_wmi_pull_peer_kick_ev(skb, &arg); + ret = ath10k_wmi_pull_peer_kick(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse peer kickout event: %d\n", ret); @@ -1951,8 +1934,8 @@ cleanup: kfree(old_data); } -static int ath10k_wmi_pull_swba_ev(struct sk_buff *skb, - struct wmi_swba_ev_arg *arg) +static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) { struct wmi_host_swba_event *ev = (void *)skb->data; u32 map; @@ -1994,7 +1977,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) dma_addr_t paddr; int ret, vdev_id = 0; - ret = ath10k_wmi_pull_swba_ev(skb, &arg); + ret = ath10k_wmi_pull_swba(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse swba event: %d\n", ret); return; @@ -2345,8 +2328,8 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar, } } -static int ath10k_wmi_pull_phyerr_ev(struct sk_buff *skb, - struct wmi_phyerr_ev_arg *arg) +static int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_phyerr_ev_arg *arg) { struct wmi_phyerr_event *ev = (void *)skb->data; @@ -2372,7 +2355,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) ATH10K_DFS_STAT_INC(ar, phy_errors); - ret = ath10k_wmi_pull_phyerr_ev(skb, &arg); + ret = ath10k_wmi_pull_phyerr(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse phyerr event: %d\n", ret); return; @@ -2608,8 +2591,9 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, return 0; } -static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb, - struct wmi_svc_rdy_ev_arg *arg) +static int +ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg) { struct wmi_service_ready_event *ev; size_t i, n; @@ -2644,8 +2628,9 @@ static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb, return 0; } -static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb, - struct wmi_svc_rdy_ev_arg *arg) +static int +ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg) { struct wmi_10x_service_ready_event *ev; int i, n; @@ -2686,23 +2671,16 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar, u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; int ret; - memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); - - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg); - wmi_10x_svc_map(arg.service_map, ar->wmi.svc_map, - arg.service_map_len); - } else { - ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg); - wmi_main_svc_map(arg.service_map, ar->wmi.svc_map, - arg.service_map_len); - } - + ret = ath10k_wmi_pull_svc_rdy(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse service ready: %d\n", ret); return; } + memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); + ath10k_wmi_map_svc(ar, arg.service_map, ar->wmi.svc_map, + arg.service_map_len); + ar->hw_min_tx_power = __le32_to_cpu(arg.min_tx_power); ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power); ar->ht_cap_info = __le32_to_cpu(arg.ht_cap); @@ -2795,8 +2773,8 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar, complete(&ar->wmi.service_ready); } -static int ath10k_wmi_pull_rdy_ev(struct sk_buff *skb, - struct wmi_rdy_ev_arg *arg) +static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_rdy_ev_arg *arg) { struct wmi_ready_event *ev = (void *)skb->data; @@ -2817,7 +2795,7 @@ static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) struct wmi_rdy_ev_arg arg = {}; int ret; - ret = ath10k_wmi_pull_rdy_ev(skb, &arg); + ret = ath10k_wmi_pull_rdy(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse ready event: %d\n", ret); return ret; @@ -2835,7 +2813,7 @@ static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) return 0; } -static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) +static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; enum wmi_event_id id; @@ -2951,7 +2929,7 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) dev_kfree_skb(skb); } -static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb) +static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; enum wmi_10x_event_id id; @@ -3075,7 +3053,7 @@ out: dev_kfree_skb(skb); } -static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb) +static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; enum wmi_10_2_event_id id; @@ -3194,14 +3172,11 @@ static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb) static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - ath10k_wmi_10_2_process_rx(ar, skb); - else - ath10k_wmi_10x_process_rx(ar, skb); - } else { - ath10k_wmi_main_process_rx(ar, skb); - } + int ret; + + ret = ath10k_wmi_rx(ar, skb); + if (ret) + ath10k_warn(ar, "failed to process wmi rx: %d\n", ret); } int ath10k_wmi_connect(struct ath10k *ar) @@ -3232,16 +3207,17 @@ int ath10k_wmi_connect(struct ath10k *ar) return 0; } -static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd, - u16 rd2g, u16 rd5g, u16 ctl2g, - u16 ctl5g) +static struct sk_buff * +ath10k_wmi_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g, + u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) { struct wmi_pdev_set_regdomain_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data; cmd->reg_domain = __cpu_to_le32(rd); @@ -3253,22 +3229,20 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n", rd, rd2g, rd5g, ctl2g, ctl5g); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_set_regdomain_cmdid); + return skb; } -static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd, - u16 rd2g, u16 rd5g, - u16 ctl2g, u16 ctl5g, - enum wmi_dfs_region dfs_reg) +static struct sk_buff * +ath10k_wmi_10x_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16 + rd5g, u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) { struct wmi_pdev_set_regdomain_cmd_10x *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data; cmd->reg_domain = __cpu_to_le32(rd); @@ -3281,50 +3255,39 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n", rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_set_regdomain_cmdid); -} - -int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, - u16 rd5g, u16 ctl2g, u16 ctl5g, - enum wmi_dfs_region dfs_reg) -{ - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g, - ctl2g, ctl5g, dfs_reg); - else - return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g, - ctl2g, ctl5g); + return skb; } -int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt) +static struct sk_buff * +ath10k_wmi_op_gen_pdev_suspend(struct ath10k *ar, u32 suspend_opt) { struct wmi_pdev_suspend_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_suspend_cmd *)skb->data; cmd->suspend_opt = __cpu_to_le32(suspend_opt); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid); + return skb; } -int ath10k_wmi_pdev_resume_target(struct ath10k *ar) +static struct sk_buff * +ath10k_wmi_op_gen_pdev_resume(struct ath10k *ar) { struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, 0); - if (skb == NULL) - return -ENOMEM; + if (!skb) + return ERR_PTR(-ENOMEM); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid); + return skb; } -int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) +static struct sk_buff * +ath10k_wmi_op_gen_pdev_set_param(struct ath10k *ar, u32 id, u32 value) { struct wmi_pdev_set_param_cmd *cmd; struct sk_buff *skb; @@ -3332,12 +3295,12 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) if (id == WMI_PDEV_PARAM_UNSUPPORTED) { ath10k_warn(ar, "pdev param %d not supported by firmware\n", id); - return -EOPNOTSUPP; + return ERR_PTR(-EOPNOTSUPP); } skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_set_param_cmd *)skb->data; cmd->param_id = __cpu_to_le32(id); @@ -3345,7 +3308,7 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n", id, value); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid); + return skb; } static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, @@ -3370,7 +3333,7 @@ static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, } } -static int ath10k_wmi_main_cmd_init(struct ath10k *ar) +static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar) { struct wmi_init_cmd *cmd; struct sk_buff *buf; @@ -3433,7 +3396,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) buf = ath10k_wmi_alloc_skb(ar, len); if (!buf) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_init_cmd *)buf->data; @@ -3441,10 +3404,10 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n"); - return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); + return buf; } -static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) +static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar) { struct wmi_init_cmd_10x *cmd; struct sk_buff *buf; @@ -3499,7 +3462,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) buf = ath10k_wmi_alloc_skb(ar, len); if (!buf) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_init_cmd_10x *)buf->data; @@ -3507,10 +3470,10 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n"); - return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); + return buf; } -static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) +static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) { struct wmi_init_cmd_10_2 *cmd; struct sk_buff *buf; @@ -3565,7 +3528,7 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) buf = ath10k_wmi_alloc_skb(ar, len); if (!buf) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_init_cmd_10_2 *)buf->data; @@ -3573,23 +3536,7 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n"); - return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); -} - -int ath10k_wmi_cmd_init(struct ath10k *ar) -{ - int ret; - - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - ret = ath10k_wmi_10_2_cmd_init(ar); - else - ret = ath10k_wmi_10x_cmd_init(ar); - } else { - ret = ath10k_wmi_main_cmd_init(ar); - } - - return ret; + return buf; } static int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) @@ -3739,46 +3686,60 @@ ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs, } } -int ath10k_wmi_start_scan(struct ath10k *ar, - const struct wmi_start_scan_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_start_scan(struct ath10k *ar, + const struct wmi_start_scan_arg *arg) { + struct wmi_start_scan_cmd *cmd; struct sk_buff *skb; size_t len; int ret; ret = ath10k_wmi_start_scan_verify(arg); if (ret) - return ret; - - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - len = sizeof(struct wmi_10x_start_scan_cmd) + - ath10k_wmi_start_scan_tlvs_len(arg); - else - len = sizeof(struct wmi_start_scan_cmd) + - ath10k_wmi_start_scan_tlvs_len(arg); + return ERR_PTR(ret); + len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg); skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - struct wmi_10x_start_scan_cmd *cmd; - - cmd = (struct wmi_10x_start_scan_cmd *)skb->data; - ath10k_wmi_put_start_scan_common(&cmd->common, arg); - ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); - } else { - struct wmi_start_scan_cmd *cmd; + cmd = (struct wmi_start_scan_cmd *)skb->data; - cmd = (struct wmi_start_scan_cmd *)skb->data; - cmd->burst_duration_ms = __cpu_to_le32(0); + ath10k_wmi_put_start_scan_common(&cmd->common, arg); + ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); - ath10k_wmi_put_start_scan_common(&cmd->common, arg); - ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); - } + cmd->burst_duration_ms = __cpu_to_le32(0); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n"); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid); + return skb; +} + +static struct sk_buff * +ath10k_wmi_10x_op_gen_start_scan(struct ath10k *ar, + const struct wmi_start_scan_arg *arg) +{ + struct wmi_10x_start_scan_cmd *cmd; + struct sk_buff *skb; + size_t len; + int ret; + + ret = ath10k_wmi_start_scan_verify(arg); + if (ret) + return ERR_PTR(ret); + + len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_10x_start_scan_cmd *)skb->data; + + ath10k_wmi_put_start_scan_common(&cmd->common, arg); + ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi 10x start scan\n"); + return skb; } void ath10k_wmi_start_scan_init(struct ath10k *ar, @@ -3807,7 +3768,9 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar, arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF"; } -int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_stop_scan(struct ath10k *ar, + const struct wmi_stop_scan_arg *arg) { struct wmi_stop_scan_cmd *cmd; struct sk_buff *skb; @@ -3815,13 +3778,13 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) u32 req_id; if (arg->req_id > 0xFFF) - return -EINVAL; + return ERR_PTR(-EINVAL); if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF) - return -EINVAL; + return ERR_PTR(-EINVAL); skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); scan_id = arg->u.scan_id; scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX; @@ -3838,20 +3801,21 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi stop scan reqid %d req_type %d vdev/scan_id %d\n", arg->req_id, arg->req_type, arg->u.scan_id); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid); + return skb; } -int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, - enum wmi_vdev_type type, - enum wmi_vdev_subtype subtype, - const u8 macaddr[ETH_ALEN]) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_create(struct ath10k *ar, u32 vdev_id, + enum wmi_vdev_type type, + enum wmi_vdev_subtype subtype, + const u8 macaddr[ETH_ALEN]) { struct wmi_vdev_create_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_create_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -3862,58 +3826,52 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI vdev create: id %d type %d subtype %d macaddr %pM\n", vdev_id, type, subtype, macaddr); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid); + return skb; } -int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id) { struct wmi_vdev_delete_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_delete_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI vdev delete id %d\n", vdev_id); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid); + return skb; } -static int -ath10k_wmi_vdev_start_restart(struct ath10k *ar, - const struct wmi_vdev_start_request_arg *arg, - u32 cmd_id) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_start(struct ath10k *ar, + const struct wmi_vdev_start_request_arg *arg, + bool restart) { struct wmi_vdev_start_request_cmd *cmd; struct sk_buff *skb; const char *cmdname; u32 flags = 0; - if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid && - cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid) - return -EINVAL; if (WARN_ON(arg->ssid && arg->ssid_len == 0)) - return -EINVAL; + return ERR_PTR(-EINVAL); if (WARN_ON(arg->hidden_ssid && !arg->ssid)) - return -EINVAL; + return ERR_PTR(-EINVAL); if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid))) - return -EINVAL; + return ERR_PTR(-EINVAL); - if (cmd_id == ar->wmi.cmd->vdev_start_request_cmdid) - cmdname = "start"; - else if (cmd_id == ar->wmi.cmd->vdev_restart_request_cmdid) + if (restart) cmdname = "restart"; else - return -EINVAL; /* should not happen, we already check cmd_id */ + cmdname = "start"; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); if (arg->hidden_ssid) flags |= WMI_VDEV_START_HIDDEN_SSID; @@ -3942,50 +3900,36 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar, flags, arg->channel.freq, arg->channel.mode, cmd->chan.flags, arg->channel.max_power); - return ath10k_wmi_cmd_send(ar, skb, cmd_id); -} - -int ath10k_wmi_vdev_start(struct ath10k *ar, - const struct wmi_vdev_start_request_arg *arg) -{ - u32 cmd_id = ar->wmi.cmd->vdev_start_request_cmdid; - - return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id); -} - -int ath10k_wmi_vdev_restart(struct ath10k *ar, - const struct wmi_vdev_start_request_arg *arg) -{ - u32 cmd_id = ar->wmi.cmd->vdev_restart_request_cmdid; - - return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id); + return skb; } -int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id) { struct wmi_vdev_stop_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_stop_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid); + return skb; } -int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, + const u8 *bssid) { struct wmi_vdev_up_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_up_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -3995,30 +3939,30 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n", vdev_id, aid, bssid); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid); + return skb; } -int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id) { struct wmi_vdev_down_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_down_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt vdev down id 0x%x\n", vdev_id); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid); + return skb; } -int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, - u32 param_id, u32 param_value) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id, + u32 param_id, u32 param_value) { struct wmi_vdev_set_param_cmd *cmd; struct sk_buff *skb; @@ -4027,12 +3971,12 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "vdev param %d not supported by firmware\n", param_id); - return -EOPNOTSUPP; + return ERR_PTR(-EOPNOTSUPP); } skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_set_param_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4042,24 +3986,24 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev id 0x%x set param %d value %d\n", vdev_id, param_id, param_value); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid); + return skb; } -int ath10k_wmi_vdev_install_key(struct ath10k *ar, - const struct wmi_vdev_install_key_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_install_key(struct ath10k *ar, + const struct wmi_vdev_install_key_arg *arg) { struct wmi_vdev_install_key_cmd *cmd; struct sk_buff *skb; if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL) - return -EINVAL; + return ERR_PTR(-EINVAL); if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL) - return -EINVAL; + return ERR_PTR(-EINVAL); skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_install_key_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(arg->vdev_id); @@ -4078,20 +4022,19 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev install key idx %d cipher %d len %d\n", arg->key_idx, arg->key_cipher, arg->key_len); - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->vdev_install_key_cmdid); + return skb; } -int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, - const struct wmi_vdev_spectral_conf_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_spectral_conf(struct ath10k *ar, + const struct wmi_vdev_spectral_conf_arg *arg) { struct wmi_vdev_spectral_conf_cmd *cmd; struct sk_buff *skb; - u32 cmdid; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(arg->vdev_id); @@ -4114,39 +4057,38 @@ int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj); cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask); - cmdid = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid; - return ath10k_wmi_cmd_send(ar, skb, cmdid); + return skb; } -int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, - u32 enable) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, + u32 trigger, u32 enable) { struct wmi_vdev_spectral_enable_cmd *cmd; struct sk_buff *skb; - u32 cmdid; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); cmd->trigger_cmd = __cpu_to_le32(trigger); cmd->enable_cmd = __cpu_to_le32(enable); - cmdid = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid; - return ath10k_wmi_cmd_send(ar, skb, cmdid); + return skb; } -int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN]) +static struct sk_buff * +ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) { struct wmi_peer_create_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_peer_create_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4155,18 +4097,19 @@ int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer create vdev_id %d peer_addr %pM\n", vdev_id, peer_addr); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid); + return skb; } -int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN]) +static struct sk_buff * +ath10k_wmi_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) { struct wmi_peer_delete_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_peer_delete_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4175,18 +4118,19 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer delete vdev_id %d peer_addr %pM\n", vdev_id, peer_addr); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid); + return skb; } -int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) +static struct sk_buff * +ath10k_wmi_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) { struct wmi_peer_flush_tids_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_peer_flush_tids_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4196,19 +4140,21 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer flush vdev_id %d peer_addr %pM tids %08x\n", vdev_id, peer_addr, tid_bitmap); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid); + return skb; } -int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, - const u8 *peer_addr, enum wmi_peer_param param_id, - u32 param_value) +static struct sk_buff * +ath10k_wmi_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id, + const u8 *peer_addr, + enum wmi_peer_param param_id, + u32 param_value) { struct wmi_peer_set_param_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_peer_set_param_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4219,19 +4165,19 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev %d peer 0x%pM set param %d value %d\n", vdev_id, peer_addr, param_id, param_value); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid); + return skb; } -int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, - enum wmi_sta_ps_mode psmode) +static struct sk_buff * +ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_ps_mode psmode) { struct wmi_sta_powersave_mode_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_sta_powersave_mode_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4240,21 +4186,20 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi set powersave id 0x%x mode %d\n", vdev_id, psmode); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->sta_powersave_mode_cmdid); + return skb; } -int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, - enum wmi_sta_powersave_param param_id, - u32 value) +static struct sk_buff * +ath10k_wmi_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_powersave_param param_id, + u32 value) { struct wmi_sta_powersave_param_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_sta_powersave_param_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4264,22 +4209,22 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sta ps param vdev_id 0x%x param %d value %d\n", vdev_id, param_id, value); - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->sta_powersave_param_cmdid); + return skb; } -int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, - enum wmi_ap_ps_peer_param param_id, u32 value) +static struct sk_buff * +ath10k_wmi_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac, + enum wmi_ap_ps_peer_param param_id, u32 value) { struct wmi_ap_ps_peer_cmd *cmd; struct sk_buff *skb; if (!mac) - return -EINVAL; + return ERR_PTR(-EINVAL); skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_ap_ps_peer_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4290,13 +4235,12 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n", vdev_id, param_id, value, mac); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->ap_ps_peer_param_cmdid); + return skb; } -int ath10k_wmi_scan_chan_list(struct ath10k *ar, - const struct wmi_scan_chan_list_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_scan_chan_list(struct ath10k *ar, + const struct wmi_scan_chan_list_arg *arg) { struct wmi_scan_chan_list_cmd *cmd; struct sk_buff *skb; @@ -4309,7 +4253,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) - return -EINVAL; + return ERR_PTR(-EINVAL); cmd = (struct wmi_scan_chan_list_cmd *)skb->data; cmd->num_scan_chans = __cpu_to_le32(arg->n_channels); @@ -4321,7 +4265,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, ath10k_wmi_put_wmi_channel(ci, ch); } - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid); + return skb; } static void @@ -4402,12 +4346,9 @@ ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf, cmd->info0 = __cpu_to_le32(info0); } -int ath10k_wmi_peer_assoc(struct ath10k *ar, - const struct wmi_peer_assoc_complete_arg *arg) +static int +ath10k_wmi_peer_assoc_check_arg(const struct wmi_peer_assoc_complete_arg *arg) { - struct sk_buff *skb; - int len; - if (arg->peer_mpdu_density > 16) return -EINVAL; if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES) @@ -4415,49 +4356,98 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES) return -EINVAL; - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd); - else - len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd); - } else { - len = sizeof(struct wmi_main_peer_assoc_complete_cmd); - } + return 0; +} + +static struct sk_buff * +ath10k_wmi_op_gen_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + size_t len = sizeof(struct wmi_main_peer_assoc_complete_cmd); + struct sk_buff *skb; + int ret; + + ret = ath10k_wmi_peer_assoc_check_arg(arg); + if (ret) + return ERR_PTR(ret); skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg); - else - ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg); - } else { - ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg); - } + ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi peer assoc vdev %d addr %pM (%s)\n", + arg->vdev_id, arg->addr, + arg->peer_reassoc ? "reassociate" : "new"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_10_1_op_gen_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + size_t len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd); + struct sk_buff *skb; + int ret; + + ret = ath10k_wmi_peer_assoc_check_arg(arg); + if (ret) + return ERR_PTR(ret); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi peer assoc vdev %d addr %pM (%s)\n", + arg->vdev_id, arg->addr, + arg->peer_reassoc ? "reassociate" : "new"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_10_2_op_gen_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + size_t len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd); + struct sk_buff *skb; + int ret; + + ret = ath10k_wmi_peer_assoc_check_arg(arg); + if (ret) + return ERR_PTR(ret); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer assoc vdev %d addr %pM (%s)\n", arg->vdev_id, arg->addr, arg->peer_reassoc ? "reassociate" : "new"); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); + return skb; } /* This function assumes the beacon is already DMA mapped */ -int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) +static struct sk_buff * +ath10k_wmi_op_gen_beacon_dma(struct ath10k_vif *arvif) { + struct ath10k *ar = arvif->ar; struct wmi_bcn_tx_ref_cmd *cmd; struct sk_buff *skb; struct sk_buff *beacon = arvif->beacon; - struct ath10k *ar = arvif->ar; struct ieee80211_hdr *hdr; - int ret; u16 fc; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); hdr = (struct ieee80211_hdr *)beacon->data; fc = le16_to_cpu(hdr->frame_control); @@ -4477,13 +4467,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab) cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); - ret = ath10k_wmi_cmd_send_nowait(ar, skb, - ar->wmi.cmd->pdev_send_bcn_cmdid); - - if (ret) - dev_kfree_skb(skb); - - return ret; + return skb; } static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, @@ -4497,15 +4481,16 @@ static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, params->no_ack = __cpu_to_le32(arg->no_ack); } -int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, - const struct wmi_pdev_set_wmm_params_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar, + const struct wmi_pdev_set_wmm_params_arg *arg) { struct wmi_pdev_set_wmm_params *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_set_wmm_params *)skb->data; ath10k_wmi_pdev_set_wmm_param(&cmd->ac_be, &arg->ac_be); @@ -4514,35 +4499,36 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n"); - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_set_wmm_params_cmdid); + return skb; } -int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) +static struct sk_buff * +ath10k_wmi_op_gen_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) { struct wmi_request_stats_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_request_stats_cmd *)skb->data; cmd->stats_id = __cpu_to_le32(stats_id); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid); + return skb; } -int ath10k_wmi_force_fw_hang(struct ath10k *ar, - enum wmi_force_fw_hang_type type, u32 delay_ms) +static struct sk_buff * +ath10k_wmi_op_gen_force_fw_hang(struct ath10k *ar, + enum wmi_force_fw_hang_type type, u32 delay_ms) { struct wmi_force_fw_hang_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_force_fw_hang_cmd *)skb->data; cmd->type = __cpu_to_le32(type); @@ -4550,10 +4536,11 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n", type, delay_ms); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); + return skb; } -int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) +static struct sk_buff * +ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable) { struct wmi_dbglog_cfg_cmd *cmd; struct sk_buff *skb; @@ -4561,7 +4548,7 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_dbglog_cfg_cmd *)skb->data; @@ -4586,57 +4573,224 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) __le32_to_cpu(cmd->module_valid), __le32_to_cpu(cmd->config_enable), __le32_to_cpu(cmd->config_valid)); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid); + return skb; } -int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_bitmap) +static struct sk_buff * +ath10k_wmi_op_gen_pktlog_enable(struct ath10k *ar, u32 ev_bitmap) { struct wmi_pdev_pktlog_enable_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); ev_bitmap &= ATH10K_PKTLOG_ANY; - ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi enable pktlog filter:%x\n", ev_bitmap); cmd = (struct wmi_pdev_pktlog_enable_cmd *)skb->data; cmd->ev_bitmap = __cpu_to_le32(ev_bitmap); - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_pktlog_enable_cmdid); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi enable pktlog filter 0x%08x\n", + ev_bitmap); + return skb; } -int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar) +static struct sk_buff * +ath10k_wmi_op_gen_pktlog_disable(struct ath10k *ar) { struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, 0); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi disable pktlog\n"); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_pktlog_disable_cmdid); + return skb; } +static const struct wmi_ops wmi_ops = { + .rx = ath10k_wmi_op_rx, + .map_svc = wmi_main_svc_map, + + .pull_scan = ath10k_wmi_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, + .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + .pull_fw_stats = ath10k_wmi_main_op_pull_fw_stats, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_rd = ath10k_wmi_op_gen_pdev_set_rd, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, + .gen_init = ath10k_wmi_op_gen_init, + .gen_start_scan = ath10k_wmi_op_gen_start_scan, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_peer_assoc = ath10k_wmi_op_gen_peer_assoc, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, +}; + +static const struct wmi_ops wmi_10_1_ops = { + .rx = ath10k_wmi_10_1_op_rx, + .map_svc = wmi_10x_svc_map, + .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, + .pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats, + .gen_init = ath10k_wmi_10_1_op_gen_init, + .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, + .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, + .gen_peer_assoc = ath10k_wmi_10_1_op_gen_peer_assoc, + + /* shared with main branch */ + .pull_scan = ath10k_wmi_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, +}; + +static const struct wmi_ops wmi_10_2_ops = { + .rx = ath10k_wmi_10_2_op_rx, + .gen_init = ath10k_wmi_10_2_op_gen_init, + .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, + + /* shared with 10.1 */ + .map_svc = wmi_10x_svc_map, + .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, + .pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats, + .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, + .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, + + .pull_scan = ath10k_wmi_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, +}; + int ath10k_wmi_attach(struct ath10k *ar) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - ar->wmi.cmd = &wmi_10_2_cmd_map; - else - ar->wmi.cmd = &wmi_10x_cmd_map; - + switch (ar->wmi.op_version) { + case ATH10K_FW_WMI_OP_VERSION_10_2: + ar->wmi.cmd = &wmi_10_2_cmd_map; + ar->wmi.ops = &wmi_10_2_ops; ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map; - } else { + break; + case ATH10K_FW_WMI_OP_VERSION_10_1: + ar->wmi.cmd = &wmi_10x_cmd_map; + ar->wmi.ops = &wmi_10_1_ops; + ar->wmi.vdev_param = &wmi_10x_vdev_param_map; + ar->wmi.pdev_param = &wmi_10x_pdev_param_map; + break; + case ATH10K_FW_WMI_OP_VERSION_MAIN: ar->wmi.cmd = &wmi_cmd_map; + ar->wmi.ops = &wmi_ops; ar->wmi.vdev_param = &wmi_vdev_param_map; ar->wmi.pdev_param = &wmi_pdev_param_map; + break; + case ATH10K_FW_WMI_OP_VERSION_UNSET: + case ATH10K_FW_WMI_OP_VERSION_MAX: + ath10k_err(ar, "unsupported WMI op version: %d\n", + ar->wmi.op_version); + return -EINVAL; } init_completion(&ar->wmi.service_ready); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 0a38798224db..7172f3cb772e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4644,7 +4644,6 @@ struct wmi_rdy_ev_arg { struct ath10k; struct ath10k_vif; -struct ath10k_fw_stats; int ath10k_wmi_attach(struct ath10k *ar); void ath10k_wmi_detach(struct ath10k *ar); @@ -4655,70 +4654,8 @@ int ath10k_wmi_connect(struct ath10k *ar); struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len); int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); - -int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt); -int ath10k_wmi_pdev_resume_target(struct ath10k *ar); -int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, - u16 rd5g, u16 ctl2g, u16 ctl5g, - enum wmi_dfs_region dfs_reg); -int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value); -int ath10k_wmi_cmd_init(struct ath10k *ar); -int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *); +int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, + u32 cmd_id); void ath10k_wmi_start_scan_init(struct ath10k *ar, struct wmi_start_scan_arg *); -int ath10k_wmi_stop_scan(struct ath10k *ar, - const struct wmi_stop_scan_arg *arg); -int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, - enum wmi_vdev_type type, - enum wmi_vdev_subtype subtype, - const u8 macaddr[ETH_ALEN]); -int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id); -int ath10k_wmi_vdev_start(struct ath10k *ar, - const struct wmi_vdev_start_request_arg *); -int ath10k_wmi_vdev_restart(struct ath10k *ar, - const struct wmi_vdev_start_request_arg *); -int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id); -int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, - const u8 *bssid); -int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id); -int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, - u32 param_id, u32 param_value); -int ath10k_wmi_vdev_install_key(struct ath10k *ar, - const struct wmi_vdev_install_key_arg *arg); -int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, - const struct wmi_vdev_spectral_conf_arg *arg); -int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, - u32 enable); -int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN]); -int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN]); -int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN], u32 tid_bitmap); -int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, - const u8 *peer_addr, - enum wmi_peer_param param_id, u32 param_value); -int ath10k_wmi_peer_assoc(struct ath10k *ar, - const struct wmi_peer_assoc_complete_arg *arg); -int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, - enum wmi_sta_ps_mode psmode); -int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, - enum wmi_sta_powersave_param param_id, - u32 value); -int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, - enum wmi_ap_ps_peer_param param_id, u32 value); -int ath10k_wmi_scan_chan_list(struct ath10k *ar, - const struct wmi_scan_chan_list_arg *arg); -int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif); -int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, - const struct wmi_pdev_set_wmm_params_arg *arg); -int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); -int ath10k_wmi_force_fw_hang(struct ath10k *ar, - enum wmi_force_fw_hang_type type, u32 delay_ms); -int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb); -int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable); -int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, - struct ath10k_fw_stats *stats); -int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_list); -int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar); #endif /* _WMI_H_ */ -- cgit v1.2.1 From 0226d6025845d0e93a7a37e0c521a33b546018d9 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 3 Dec 2014 10:11:22 +0200 Subject: ath10k: make some wmi functions public Some functions can be shared across different WMI ABIs. Make them public so different WMI backends can use them from different source files in the future. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 136 ++++++++++++++-------------------- drivers/net/wireless/ath/ath10k/wmi.h | 61 +++++++++++++++ 2 files changed, 117 insertions(+), 80 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 24bb97face30..cc0c9e0ff457 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -610,9 +610,8 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, }; -static void -ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, - const struct wmi_channel_arg *arg) +void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, + const struct wmi_channel_arg *arg) { u32 flags = 0; @@ -987,7 +986,7 @@ static int ath10k_wmi_op_pull_scan_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) +int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) { struct wmi_scan_ev_arg arg = {}; enum wmi_scan_event_type event_type; @@ -1206,7 +1205,7 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) +int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_mgmt_rx_ev_arg arg = {}; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); @@ -1359,7 +1358,7 @@ static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) +void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) { struct wmi_ch_info_ev_arg arg = {}; struct survey_info *survey; @@ -1427,12 +1426,12 @@ exit: spin_unlock_bh(&ar->data_lock); } -static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) +void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n"); } -static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) +int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n", skb->len); @@ -1442,8 +1441,8 @@ static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) return 0; } -static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src, - struct ath10k_fw_stats_pdev *dst) +void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src, + struct ath10k_fw_stats_pdev *dst) { const struct wal_dbg_tx_stats *tx = &src->wal.tx; const struct wal_dbg_rx_stats *rx = &src->wal.rx; @@ -1495,8 +1494,8 @@ static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src, dst->mpdu_errs = __le32_to_cpu(rx->mpdu_errs); } -static void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, - struct ath10k_fw_stats_peer *dst) +void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, + struct ath10k_fw_stats_peer *dst) { ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr); dst->peer_rssi = __le32_to_cpu(src->peer_rssi); @@ -1618,8 +1617,7 @@ static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar, return 0; } -static void ath10k_wmi_event_update_stats(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n"); ath10k_debug_fw_stats_process(ar, skb); @@ -1643,8 +1641,7 @@ ath10k_wmi_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb) { struct wmi_vdev_start_ev_arg arg = {}; int ret; @@ -1663,8 +1660,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, complete(&ar->vdev_setup_done); } -static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n"); complete(&ar->vdev_setup_done); @@ -1685,8 +1681,7 @@ ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb) { struct wmi_peer_kick_ev_arg arg = {}; struct ieee80211_sta *sta; @@ -1965,7 +1960,7 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) +void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) { struct wmi_swba_ev_arg arg = {}; u32 map; @@ -2086,8 +2081,7 @@ skip: } } -static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); } @@ -2208,9 +2202,9 @@ static int ath10k_dfs_fft_report(struct ath10k *ar, return 0; } -static void ath10k_wmi_event_dfs(struct ath10k *ar, - const struct wmi_phyerr *phyerr, - u64 tsf) +void ath10k_wmi_event_dfs(struct ath10k *ar, + const struct wmi_phyerr *phyerr, + u64 tsf) { int buf_len, tlv_len, res, i = 0; const struct phyerr_tlv *tlv; @@ -2273,10 +2267,9 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar, } } -static void -ath10k_wmi_event_spectral_scan(struct ath10k *ar, - const struct wmi_phyerr *phyerr, - u64 tsf) +void ath10k_wmi_event_spectral_scan(struct ath10k *ar, + const struct wmi_phyerr *phyerr, + u64 tsf) { int buf_len, tlv_len, res, i = 0; struct phyerr_tlv *tlv; @@ -2345,7 +2338,7 @@ static int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) +void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) { struct wmi_phyerr_ev_arg arg = {}; const struct wmi_phyerr *phyerr; @@ -2414,19 +2407,17 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) } } -static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) +void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n"); } -static void ath10k_wmi_event_profile_match(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n"); } -static void ath10k_wmi_event_debug_print(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb) { char buf[101], c; int i; @@ -2459,103 +2450,90 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf); } -static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) +void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n"); } -static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n"); } -static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, + struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n"); } -static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, + struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n"); } -static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n"); } -static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n"); } -static void ath10k_wmi_event_dcs_interference(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n"); } -static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n"); } -static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n"); } -static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n"); } -static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n"); } -static void ath10k_wmi_event_delba_complete(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n"); } -static void ath10k_wmi_event_addba_complete(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n"); } -static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, + struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n"); } -static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n"); } -static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n"); } -static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n"); } @@ -2664,8 +2642,7 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -static void ath10k_wmi_event_service_ready(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) { struct wmi_svc_rdy_ev_arg arg = {}; u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; @@ -2790,7 +2767,7 @@ static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) +int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) { struct wmi_rdy_ev_arg arg = {}; int ret; @@ -3311,8 +3288,8 @@ ath10k_wmi_op_gen_pdev_set_param(struct ath10k *ar, u32 id, u32 value) return skb; } -static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, - struct wmi_host_mem_chunks *chunks) +void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, + struct wmi_host_mem_chunks *chunks) { struct host_memory_chunk *chunk; int i; @@ -3539,7 +3516,7 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) return buf; } -static int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) +int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) { if (arg->ie_len && !arg->ie) return -EINVAL; @@ -3590,9 +3567,8 @@ ath10k_wmi_start_scan_tlvs_len(const struct wmi_start_scan_arg *arg) return len; } -static void -ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, - const struct wmi_start_scan_arg *arg) +void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, + const struct wmi_start_scan_arg *arg) { u32 scan_id; u32 scan_req_id; @@ -4470,8 +4446,8 @@ ath10k_wmi_op_gen_beacon_dma(struct ath10k_vif *arvif) return skb; } -static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, - const struct wmi_wmm_params_arg *arg) +void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, + const struct wmi_wmm_params_arg *arg) { params->cwmin = __cpu_to_le32(arg->cwmin); params->cwmax = __cpu_to_le32(arg->cwmax); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 7172f3cb772e..032a8bdb0420 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4644,12 +4644,15 @@ struct wmi_rdy_ev_arg { struct ath10k; struct ath10k_vif; +struct ath10k_fw_stats_pdev; +struct ath10k_fw_stats_peer; int ath10k_wmi_attach(struct ath10k *ar); void ath10k_wmi_detach(struct ath10k *ar); int ath10k_wmi_wait_for_service_ready(struct ath10k *ar); int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar); +struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len); int ath10k_wmi_connect(struct ath10k *ar); struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len); @@ -4658,4 +4661,62 @@ int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); void ath10k_wmi_start_scan_init(struct ath10k *ar, struct wmi_start_scan_arg *); +void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src, + struct ath10k_fw_stats_pdev *dst); +void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, + struct ath10k_fw_stats_peer *dst); +void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, + struct wmi_host_mem_chunks *chunks); +void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, + const struct wmi_start_scan_arg *arg); +void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, + const struct wmi_wmm_params_arg *arg); +void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, + const struct wmi_channel_arg *arg); +int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg); + +int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb); +int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb); +int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_dfs(struct ath10k *ar, + const struct wmi_phyerr *phyerr, u64 tsf); +void ath10k_wmi_event_spectral_scan(struct ath10k *ar, + const struct wmi_phyerr *phyerr, + u64 tsf); +void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, + struct sk_buff *skb); +void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, + struct sk_buff *skb); +void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, + struct sk_buff *skb); +void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, + struct sk_buff *skb); +void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb); +int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb); + #endif /* _WMI_H_ */ -- cgit v1.2.1 From ca996ec5660874edaf7fab6939beaaa9e023d347 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 3 Dec 2014 10:11:32 +0200 Subject: ath10k: implement wmi-tlv backend Latest main firmware branch introduced a new WMI ABI called wmi-tlv. It is not a tlv strictly speaking but something that resembles it because it is ordered and may have duplicate id entries. This prepares ath10k to support new hw. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Makefile | 1 + drivers/net/wireless/ath/ath10k/ce.c | 2 + drivers/net/wireless/ath/ath10k/core.c | 5 + drivers/net/wireless/ath/ath10k/hw.h | 10 + drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2218 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 1380 ++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 7 +- drivers/net/wireless/ath/ath10k/wmi.h | 79 + 8 files changed, 3701 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath10k/wmi-tlv.c create mode 100644 drivers/net/wireless/ath/ath10k/wmi-tlv.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 8b1b1adb477a..8abb66ceb99c 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -8,6 +8,7 @@ ath10k_core-y += mac.o \ htt_tx.o \ txrx.o \ wmi.o \ + wmi-tlv.o \ bmi.o ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index a156e6e48708..42ec79327943 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1093,6 +1093,8 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); + BUILD_BUG_ON(2*TARGET_TLV_NUM_MSDU_DESC > + (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); ce_state->ar = ar; ce_state->id = ce_id; diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index d83d9a7ddd77..577a3d76df22 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -915,6 +915,11 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->max_num_stations = TARGET_10X_NUM_STATIONS; ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; break; + case ATH10K_FW_WMI_OP_VERSION_TLV: + ar->max_num_peers = TARGET_TLV_NUM_PEERS; + ar->max_num_stations = TARGET_TLV_NUM_STATIONS; + ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC; + break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 5bae90c3db99..809c2521adb3 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -71,6 +71,7 @@ enum ath10k_fw_wmi_op_version { ATH10K_FW_WMI_OP_VERSION_MAIN = 1, ATH10K_FW_WMI_OP_VERSION_10_1 = 2, ATH10K_FW_WMI_OP_VERSION_10_2 = 3, + ATH10K_FW_WMI_OP_VERSION_TLV = 4, /* keep last */ ATH10K_FW_WMI_OP_VERSION_MAX, @@ -178,6 +179,15 @@ struct ath10k_pktlog_hdr { #define TARGET_10X_NUM_MSDU_DESC (1024 + 400) #define TARGET_10X_MAX_FRAG_ENTRIES 0 +/* Target specific defines for WMI-TLV firmware */ +#define TARGET_TLV_NUM_VDEVS 3 +#define TARGET_TLV_NUM_STATIONS 32 +#define TARGET_TLV_NUM_PEERS ((TARGET_TLV_NUM_STATIONS) + \ + (TARGET_TLV_NUM_VDEVS) + \ + 2) +#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2) +#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) + /* Number of Copy Engines supported */ #define CE_COUNT 8 diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c new file mode 100644 index 000000000000..b21048c2a52e --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -0,0 +1,2218 @@ +/* + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "core.h" +#include "debug.h" +#include "hw.h" +#include "wmi.h" +#include "wmi-ops.h" +#include "wmi-tlv.h" + +/***************/ +/* TLV helpers */ +/**************/ + +struct wmi_tlv_policy { + size_t min_len; +}; + +static const struct wmi_tlv_policy wmi_tlv_policies[] = { + [WMI_TLV_TAG_ARRAY_BYTE] + = { .min_len = sizeof(u8) }, + [WMI_TLV_TAG_ARRAY_UINT32] + = { .min_len = sizeof(u32) }, + [WMI_TLV_TAG_STRUCT_SCAN_EVENT] + = { .min_len = sizeof(struct wmi_scan_event) }, + [WMI_TLV_TAG_STRUCT_MGMT_RX_HDR] + = { .min_len = sizeof(struct wmi_tlv_mgmt_rx_ev) }, + [WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT] + = { .min_len = sizeof(struct wmi_chan_info_event) }, + [WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT] + = { .min_len = sizeof(struct wmi_vdev_start_response_event) }, + [WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT] + = { .min_len = sizeof(struct wmi_peer_sta_kickout_event) }, + [WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT] + = { .min_len = sizeof(struct wmi_host_swba_event) }, + [WMI_TLV_TAG_STRUCT_TIM_INFO] + = { .min_len = sizeof(struct wmi_tim_info) }, + [WMI_TLV_TAG_STRUCT_P2P_NOA_INFO] + = { .min_len = sizeof(struct wmi_p2p_noa_info) }, + [WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT] + = { .min_len = sizeof(struct wmi_tlv_svc_rdy_ev) }, + [WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES] + = { .min_len = sizeof(struct hal_reg_capabilities) }, + [WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ] + = { .min_len = sizeof(struct wlan_host_mem_req) }, + [WMI_TLV_TAG_STRUCT_READY_EVENT] + = { .min_len = sizeof(struct wmi_tlv_rdy_ev) }, +}; + +static int +ath10k_wmi_tlv_iter(struct ath10k *ar, const void *ptr, size_t len, + int (*iter)(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data), + void *data) +{ + const void *begin = ptr; + const struct wmi_tlv *tlv; + u16 tlv_tag, tlv_len; + int ret; + + while (len > 0) { + if (len < sizeof(*tlv)) { + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n", + ptr - begin, len, sizeof(*tlv)); + return -EINVAL; + } + + tlv = ptr; + tlv_tag = __le16_to_cpu(tlv->tag); + tlv_len = __le16_to_cpu(tlv->len); + ptr += sizeof(*tlv); + len -= sizeof(*tlv); + + if (tlv_len > len) { + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv parse failure of tag %hhu at byte %zd (%zu bytes left, %hhu expected)\n", + tlv_tag, ptr - begin, len, tlv_len); + return -EINVAL; + } + + if (tlv_tag < ARRAY_SIZE(wmi_tlv_policies) && + wmi_tlv_policies[tlv_tag].min_len && + wmi_tlv_policies[tlv_tag].min_len > tlv_len) { + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv parse failure of tag %hhu at byte %zd (%hhu bytes is less than min length %zu)\n", + tlv_tag, ptr - begin, tlv_len, + wmi_tlv_policies[tlv_tag].min_len); + return -EINVAL; + } + + ret = iter(ar, tlv_tag, tlv_len, ptr, data); + if (ret) + return ret; + + ptr += tlv_len; + len -= tlv_len; + } + + return 0; +} + +static int ath10k_wmi_tlv_iter_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + const void **tb = data; + + if (tag < WMI_TLV_TAG_MAX) + tb[tag] = ptr; + + return 0; +} + +static int ath10k_wmi_tlv_parse(struct ath10k *ar, const void **tb, + const void *ptr, size_t len) +{ + return ath10k_wmi_tlv_iter(ar, ptr, len, ath10k_wmi_tlv_iter_parse, + (void *)tb); +} + +static const void ** +ath10k_wmi_tlv_parse_alloc(struct ath10k *ar, const void *ptr, + size_t len, gfp_t gfp) +{ + const void **tb; + int ret; + + tb = kzalloc(sizeof(*tb) * WMI_TLV_TAG_MAX, gfp); + if (!tb) + return ERR_PTR(-ENOMEM); + + ret = ath10k_wmi_tlv_parse(ar, tb, ptr, len); + if (ret) { + kfree(tb); + return ERR_PTR(ret); + } + + return tb; +} + +static u16 ath10k_wmi_tlv_len(const void *ptr) +{ + return __le16_to_cpu((((const struct wmi_tlv *)ptr) - 1)->len); +} + +/***********/ +/* TLV ops */ +/***********/ + +static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_cmd_hdr *cmd_hdr; + enum wmi_tlv_event_id id; + + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); + + if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) + return; + + trace_ath10k_wmi_event(ar, id, skb->data, skb->len); + + switch (id) { + case WMI_TLV_MGMT_RX_EVENTID: + ath10k_wmi_event_mgmt_rx(ar, skb); + /* mgmt_rx() owns the skb now! */ + return; + case WMI_TLV_SCAN_EVENTID: + ath10k_wmi_event_scan(ar, skb); + break; + case WMI_TLV_CHAN_INFO_EVENTID: + ath10k_wmi_event_chan_info(ar, skb); + break; + case WMI_TLV_ECHO_EVENTID: + ath10k_wmi_event_echo(ar, skb); + break; + case WMI_TLV_DEBUG_MESG_EVENTID: + ath10k_wmi_event_debug_mesg(ar, skb); + break; + case WMI_TLV_UPDATE_STATS_EVENTID: + ath10k_wmi_event_update_stats(ar, skb); + break; + case WMI_TLV_VDEV_START_RESP_EVENTID: + ath10k_wmi_event_vdev_start_resp(ar, skb); + break; + case WMI_TLV_VDEV_STOPPED_EVENTID: + ath10k_wmi_event_vdev_stopped(ar, skb); + break; + case WMI_TLV_PEER_STA_KICKOUT_EVENTID: + ath10k_wmi_event_peer_sta_kickout(ar, skb); + break; + case WMI_TLV_HOST_SWBA_EVENTID: + ath10k_wmi_event_host_swba(ar, skb); + break; + case WMI_TLV_TBTTOFFSET_UPDATE_EVENTID: + ath10k_wmi_event_tbttoffset_update(ar, skb); + break; + case WMI_TLV_PHYERR_EVENTID: + ath10k_wmi_event_phyerr(ar, skb); + break; + case WMI_TLV_ROAM_EVENTID: + ath10k_wmi_event_roam(ar, skb); + break; + case WMI_TLV_PROFILE_MATCH: + ath10k_wmi_event_profile_match(ar, skb); + break; + case WMI_TLV_DEBUG_PRINT_EVENTID: + ath10k_wmi_event_debug_print(ar, skb); + break; + case WMI_TLV_PDEV_QVIT_EVENTID: + ath10k_wmi_event_pdev_qvit(ar, skb); + break; + case WMI_TLV_WLAN_PROFILE_DATA_EVENTID: + ath10k_wmi_event_wlan_profile_data(ar, skb); + break; + case WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID: + ath10k_wmi_event_rtt_measurement_report(ar, skb); + break; + case WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID: + ath10k_wmi_event_tsf_measurement_report(ar, skb); + break; + case WMI_TLV_RTT_ERROR_REPORT_EVENTID: + ath10k_wmi_event_rtt_error_report(ar, skb); + break; + case WMI_TLV_WOW_WAKEUP_HOST_EVENTID: + ath10k_wmi_event_wow_wakeup_host(ar, skb); + break; + case WMI_TLV_DCS_INTERFERENCE_EVENTID: + ath10k_wmi_event_dcs_interference(ar, skb); + break; + case WMI_TLV_PDEV_TPC_CONFIG_EVENTID: + ath10k_wmi_event_pdev_tpc_config(ar, skb); + break; + case WMI_TLV_PDEV_FTM_INTG_EVENTID: + ath10k_wmi_event_pdev_ftm_intg(ar, skb); + break; + case WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID: + ath10k_wmi_event_gtk_offload_status(ar, skb); + break; + case WMI_TLV_GTK_REKEY_FAIL_EVENTID: + ath10k_wmi_event_gtk_rekey_fail(ar, skb); + break; + case WMI_TLV_TX_DELBA_COMPLETE_EVENTID: + ath10k_wmi_event_delba_complete(ar, skb); + break; + case WMI_TLV_TX_ADDBA_COMPLETE_EVENTID: + ath10k_wmi_event_addba_complete(ar, skb); + break; + case WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID: + ath10k_wmi_event_vdev_install_key_complete(ar, skb); + break; + case WMI_TLV_SERVICE_READY_EVENTID: + ath10k_wmi_event_service_ready(ar, skb); + break; + case WMI_TLV_READY_EVENTID: + ath10k_wmi_event_ready(ar, skb); + break; + default: + ath10k_warn(ar, "Unknown eventid: %d\n", id); + break; + } + + dev_kfree_skb(skb); +} + +static int ath10k_wmi_tlv_op_pull_scan_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_scan_ev_arg *arg) +{ + const void **tb; + const struct wmi_scan_event *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_SCAN_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + arg->event_type = ev->event_type; + arg->reason = ev->reason; + arg->channel_freq = ev->channel_freq; + arg->scan_req_id = ev->scan_req_id; + arg->scan_id = ev->scan_id; + arg->vdev_id = ev->vdev_id; + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg) +{ + const void **tb; + const struct wmi_tlv_mgmt_rx_ev *ev; + const u8 *frame; + u32 msdu_len; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_MGMT_RX_HDR]; + frame = tb[WMI_TLV_TAG_ARRAY_BYTE]; + + if (!ev || !frame) { + kfree(tb); + return -EPROTO; + } + + arg->channel = ev->channel; + arg->buf_len = ev->buf_len; + arg->status = ev->status; + arg->snr = ev->snr; + arg->phy_mode = ev->phy_mode; + arg->rate = ev->rate; + + msdu_len = __le32_to_cpu(arg->buf_len); + + if (skb->len < (frame - skb->data) + msdu_len) { + kfree(tb); + return -EPROTO; + } + + /* shift the sk_buff to point to `frame` */ + skb_trim(skb, 0); + skb_put(skb, frame - skb->data); + skb_pull(skb, frame - skb->data); + skb_put(skb, msdu_len); + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg) +{ + const void **tb; + const struct wmi_chan_info_event *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + arg->err_code = ev->err_code; + arg->freq = ev->freq; + arg->cmd_flags = ev->cmd_flags; + arg->noise_floor = ev->noise_floor; + arg->rx_clear_count = ev->rx_clear_count; + arg->cycle_count = ev->cycle_count; + + kfree(tb); + return 0; +} + +static int +ath10k_wmi_tlv_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_vdev_start_ev_arg *arg) +{ + const void **tb; + const struct wmi_vdev_start_response_event *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + skb_pull(skb, sizeof(*ev)); + arg->vdev_id = ev->vdev_id; + arg->req_id = ev->req_id; + arg->resp_type = ev->resp_type; + arg->status = ev->status; + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_op_pull_peer_kick_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_peer_kick_ev_arg *arg) +{ + const void **tb; + const struct wmi_peer_sta_kickout_event *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + arg->mac_addr = ev->peer_macaddr.addr; + + kfree(tb); + return 0; +} + +struct wmi_tlv_swba_parse { + const struct wmi_host_swba_event *ev; + bool tim_done; + bool noa_done; + size_t n_tim; + size_t n_noa; + struct wmi_swba_ev_arg *arg; +}; + +static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_swba_parse *swba = data; + + if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO) + return -EPROTO; + + if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info)) + return -ENOBUFS; + + swba->arg->tim_info[swba->n_tim++] = ptr; + return 0; +} + +static int ath10k_wmi_tlv_swba_noa_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_swba_parse *swba = data; + + if (tag != WMI_TLV_TAG_STRUCT_P2P_NOA_INFO) + return -EPROTO; + + if (swba->n_noa >= ARRAY_SIZE(swba->arg->noa_info)) + return -ENOBUFS; + + swba->arg->noa_info[swba->n_noa++] = ptr; + return 0; +} + +static int ath10k_wmi_tlv_swba_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_swba_parse *swba = data; + int ret; + + switch (tag) { + case WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT: + swba->ev = ptr; + break; + case WMI_TLV_TAG_ARRAY_STRUCT: + if (!swba->tim_done) { + swba->tim_done = true; + ret = ath10k_wmi_tlv_iter(ar, ptr, len, + ath10k_wmi_tlv_swba_tim_parse, + swba); + if (ret) + return ret; + } else if (!swba->noa_done) { + swba->noa_done = true; + ret = ath10k_wmi_tlv_iter(ar, ptr, len, + ath10k_wmi_tlv_swba_noa_parse, + swba); + if (ret) + return ret; + } + break; + default: + break; + } + return 0; +} + +static int ath10k_wmi_tlv_op_pull_swba_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) +{ + struct wmi_tlv_swba_parse swba = { .arg = arg }; + u32 map; + size_t n_vdevs; + int ret; + + ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len, + ath10k_wmi_tlv_swba_parse, &swba); + if (ret) { + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + if (!swba.ev) + return -EPROTO; + + arg->vdev_map = swba.ev->vdev_map; + + for (map = __le32_to_cpu(arg->vdev_map), n_vdevs = 0; map; map >>= 1) + if (map & BIT(0)) + n_vdevs++; + + if (n_vdevs != swba.n_tim || + n_vdevs != swba.n_noa) + return -EPROTO; + + return 0; +} + +static int ath10k_wmi_tlv_op_pull_phyerr_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_phyerr_ev_arg *arg) +{ + const void **tb; + const struct wmi_tlv_phyerr_ev *ev; + const void *phyerrs; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR]; + phyerrs = tb[WMI_TLV_TAG_ARRAY_BYTE]; + + if (!ev || !phyerrs) { + kfree(tb); + return -EPROTO; + } + + arg->num_phyerrs = ev->num_phyerrs; + arg->tsf_l32 = ev->tsf_l32; + arg->tsf_u32 = ev->tsf_u32; + arg->buf_len = ev->buf_len; + arg->phyerrs = phyerrs; + + kfree(tb); + return 0; +} + +#define WMI_TLV_ABI_VER_NS0 0x5F414351 +#define WMI_TLV_ABI_VER_NS1 0x00004C4D +#define WMI_TLV_ABI_VER_NS2 0x00000000 +#define WMI_TLV_ABI_VER_NS3 0x00000000 + +#define WMI_TLV_ABI_VER0_MAJOR 1 +#define WMI_TLV_ABI_VER0_MINOR 0 +#define WMI_TLV_ABI_VER0 ((((WMI_TLV_ABI_VER0_MAJOR) << 24) & 0xFF000000) | \ + (((WMI_TLV_ABI_VER0_MINOR) << 0) & 0x00FFFFFF)) +#define WMI_TLV_ABI_VER1 53 + +static int +ath10k_wmi_tlv_parse_mem_reqs(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_svc_rdy_ev_arg *arg = data; + int i; + + if (tag != WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ) + return -EPROTO; + + for (i = 0; i < ARRAY_SIZE(arg->mem_reqs); i++) { + if (!arg->mem_reqs[i]) { + arg->mem_reqs[i] = ptr; + return 0; + } + } + + return -ENOMEM; +} + +static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg) +{ + const void **tb; + const struct hal_reg_capabilities *reg; + const struct wmi_tlv_svc_rdy_ev *ev; + const __le32 *svc_bmap; + const struct wlan_host_mem_req *mem_reqs; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT]; + reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES]; + svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32]; + mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT]; + + if (!ev || !reg || !svc_bmap || !mem_reqs) { + kfree(tb); + return -EPROTO; + } + + /* This is an internal ABI compatibility check for WMI TLV so check it + * here instead of the generic WMI code. + */ + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv abi 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x\n", + __le32_to_cpu(ev->abi.abi_ver0), WMI_TLV_ABI_VER0, + __le32_to_cpu(ev->abi.abi_ver_ns0), WMI_TLV_ABI_VER_NS0, + __le32_to_cpu(ev->abi.abi_ver_ns1), WMI_TLV_ABI_VER_NS1, + __le32_to_cpu(ev->abi.abi_ver_ns2), WMI_TLV_ABI_VER_NS2, + __le32_to_cpu(ev->abi.abi_ver_ns3), WMI_TLV_ABI_VER_NS3); + + if (__le32_to_cpu(ev->abi.abi_ver0) != WMI_TLV_ABI_VER0 || + __le32_to_cpu(ev->abi.abi_ver_ns0) != WMI_TLV_ABI_VER_NS0 || + __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 || + __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 || + __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) { + kfree(tb); + return -ENOTSUPP; + } + + arg->min_tx_power = ev->hw_min_tx_power; + arg->max_tx_power = ev->hw_max_tx_power; + arg->ht_cap = ev->ht_cap_info; + arg->vht_cap = ev->vht_cap_info; + arg->sw_ver0 = ev->abi.abi_ver0; + arg->sw_ver1 = ev->abi.abi_ver1; + arg->fw_build = ev->fw_build_vers; + arg->phy_capab = ev->phy_capability; + arg->num_rf_chains = ev->num_rf_chains; + arg->eeprom_rd = reg->eeprom_rd; + arg->num_mem_reqs = ev->num_mem_reqs; + arg->service_map = svc_bmap; + arg->service_map_len = ath10k_wmi_tlv_len(svc_bmap); + + ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs), + ath10k_wmi_tlv_parse_mem_reqs, arg); + if (ret) { + kfree(tb); + ath10k_warn(ar, "failed to parse mem_reqs tlv: %d\n", ret); + return ret; + } + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_rdy_ev_arg *arg) +{ + const void **tb; + const struct wmi_tlv_rdy_ev *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_READY_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + arg->sw_version = ev->abi.abi_ver0; + arg->abi_version = ev->abi.abi_ver1; + arg->status = ev->status; + arg->mac_addr = ev->mac_addr.addr; + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) +{ + const void **tb; + const struct wmi_stats_event *ev; + const void *data; + u32 num_pdev_stats, num_vdev_stats, num_peer_stats; + size_t data_len; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_STATS_EVENT]; + data = tb[WMI_TLV_TAG_ARRAY_BYTE]; + + if (!ev || !data) { + kfree(tb); + return -EPROTO; + } + + data_len = ath10k_wmi_tlv_len(data); + num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); + num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); + num_peer_stats = __le32_to_cpu(ev->num_peer_stats); + + WARN_ON(1); /* FIXME: not implemented yet */ + + kfree(tb); + return 0; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_suspend(struct ath10k *ar, u32 opt) +{ + struct wmi_tlv_pdev_suspend *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->opt = __cpu_to_le32(opt); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev suspend\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_resume(struct ath10k *ar) +{ + struct wmi_tlv_resume_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->reserved = __cpu_to_le32(0); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev resume\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_set_rd(struct ath10k *ar, + u16 rd, u16 rd2g, u16 rd5g, + u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) +{ + struct wmi_tlv_pdev_set_rd_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->regd = __cpu_to_le32(rd); + cmd->regd_2ghz = __cpu_to_le32(rd2g); + cmd->regd_5ghz = __cpu_to_le32(rd5g); + cmd->conform_limit_2ghz = __cpu_to_le32(rd2g); + cmd->conform_limit_5ghz = __cpu_to_le32(rd5g); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set rd\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id, + u32 param_value) +{ + struct wmi_tlv_pdev_set_param_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->param_id = __cpu_to_le32(param_id); + cmd->param_value = __cpu_to_le32(param_value); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set param\n"); + return skb; +} + +static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) +{ + struct sk_buff *skb; + struct wmi_tlv *tlv; + struct wmi_tlv_init_cmd *cmd; + struct wmi_tlv_resource_config *cfg; + struct wmi_host_mem_chunks *chunks; + size_t len, chunks_len; + void *ptr; + + chunks_len = ar->wmi.num_mem_chunks * sizeof(struct host_memory_chunk); + len = (sizeof(*tlv) + sizeof(*cmd)) + + (sizeof(*tlv) + sizeof(*cfg)) + + (sizeof(*tlv) + chunks_len); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = skb->data; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_INIT_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG); + tlv->len = __cpu_to_le16(sizeof(*cfg)); + cfg = (void *)tlv->value; + ptr += sizeof(*tlv); + ptr += sizeof(*cfg); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(chunks_len); + chunks = (void *)tlv->value; + + ptr += sizeof(*tlv); + ptr += chunks_len; + + cmd->abi.abi_ver0 = __cpu_to_le32(WMI_TLV_ABI_VER0); + cmd->abi.abi_ver1 = __cpu_to_le32(WMI_TLV_ABI_VER1); + cmd->abi.abi_ver_ns0 = __cpu_to_le32(WMI_TLV_ABI_VER_NS0); + cmd->abi.abi_ver_ns1 = __cpu_to_le32(WMI_TLV_ABI_VER_NS1); + cmd->abi.abi_ver_ns2 = __cpu_to_le32(WMI_TLV_ABI_VER_NS2); + cmd->abi.abi_ver_ns3 = __cpu_to_le32(WMI_TLV_ABI_VER_NS3); + cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); + + cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); + cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS); + cfg->num_offload_peers = __cpu_to_le32(0); + cfg->num_offload_reorder_bufs = __cpu_to_le32(0); + cfg->num_peer_keys = __cpu_to_le32(2); + cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS); + cfg->ast_skid_limit = __cpu_to_le32(0x10); + cfg->tx_chain_mask = __cpu_to_le32(0x7); + cfg->rx_chain_mask = __cpu_to_le32(0x7); + cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64); + cfg->rx_timeout_pri[1] = __cpu_to_le32(0x64); + cfg->rx_timeout_pri[2] = __cpu_to_le32(0x64); + cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28); + cfg->rx_decap_mode = __cpu_to_le32(1); + cfg->scan_max_pending_reqs = __cpu_to_le32(4); + cfg->bmiss_offload_max_vdev = __cpu_to_le32(3); + cfg->roam_offload_max_vdev = __cpu_to_le32(3); + cfg->roam_offload_max_ap_profiles = __cpu_to_le32(8); + cfg->num_mcast_groups = __cpu_to_le32(0); + cfg->num_mcast_table_elems = __cpu_to_le32(0); + cfg->mcast2ucast_mode = __cpu_to_le32(0); + cfg->tx_dbg_log_size = __cpu_to_le32(0x400); + cfg->num_wds_entries = __cpu_to_le32(0x20); + cfg->dma_burst_size = __cpu_to_le32(0); + cfg->mac_aggr_delim = __cpu_to_le32(0); + cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0); + cfg->vow_config = __cpu_to_le32(0); + cfg->gtk_offload_max_vdev = __cpu_to_le32(2); + cfg->num_msdu_desc = __cpu_to_le32(TARGET_TLV_NUM_MSDU_DESC); + cfg->max_frag_entries = __cpu_to_le32(2); + cfg->num_tdls_vdevs = __cpu_to_le32(1); + cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20); + cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(2); + cfg->num_multicast_filter_entries = __cpu_to_le32(5); + cfg->num_wow_filters = __cpu_to_le32(0x16); + cfg->num_keep_alive_pattern = __cpu_to_le32(6); + cfg->keep_alive_pattern_size = __cpu_to_le32(0); + cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1); + cfg->max_tdls_concurrent_buffer_sta = __cpu_to_le32(1); + + ath10k_wmi_put_host_mem_chunks(ar, chunks); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv init\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar, + const struct wmi_start_scan_arg *arg) +{ + struct wmi_tlv_start_scan_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len, chan_len, ssid_len, bssid_len, ie_len; + __le32 *chans; + struct wmi_ssid *ssids; + struct wmi_mac_addr *addrs; + void *ptr; + int i, ret; + + ret = ath10k_wmi_start_scan_verify(arg); + if (ret) + return ERR_PTR(ret); + + chan_len = arg->n_channels * sizeof(__le32); + ssid_len = arg->n_ssids * sizeof(struct wmi_ssid); + bssid_len = arg->n_bssids * sizeof(struct wmi_mac_addr); + ie_len = roundup(arg->ie_len, 4); + len = (sizeof(*tlv) + sizeof(*cmd)) + + (arg->n_channels ? sizeof(*tlv) + chan_len : 0) + + (arg->n_ssids ? sizeof(*tlv) + ssid_len : 0) + + (arg->n_bssids ? sizeof(*tlv) + bssid_len : 0) + + (arg->ie_len ? sizeof(*tlv) + ie_len : 0); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_START_SCAN_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + ath10k_wmi_put_start_scan_common(&cmd->common, arg); + cmd->burst_duration_ms = __cpu_to_le32(0); + cmd->num_channels = __cpu_to_le32(arg->n_channels); + cmd->num_ssids = __cpu_to_le32(arg->n_ssids); + cmd->num_bssids = __cpu_to_le32(arg->n_bssids); + cmd->ie_len = __cpu_to_le32(arg->ie_len); + cmd->num_probes = __cpu_to_le32(3); + + /* FIXME: There are some scan flag inconsistencies across firmwares, + * e.g. WMI-TLV inverts the logic behind the following flag. + */ + cmd->common.scan_ctrl_flags ^= __cpu_to_le32(WMI_SCAN_FILTER_PROBE_REQ); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32); + tlv->len = __cpu_to_le16(chan_len); + chans = (void *)tlv->value; + for (i = 0; i < arg->n_channels; i++) + chans[i] = __cpu_to_le32(arg->channels[i]); + + ptr += sizeof(*tlv); + ptr += chan_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT); + tlv->len = __cpu_to_le16(ssid_len); + ssids = (void *)tlv->value; + for (i = 0; i < arg->n_ssids; i++) { + ssids[i].ssid_len = __cpu_to_le32(arg->ssids[i].len); + memcpy(ssids[i].ssid, arg->ssids[i].ssid, arg->ssids[i].len); + } + + ptr += sizeof(*tlv); + ptr += ssid_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT); + tlv->len = __cpu_to_le16(bssid_len); + addrs = (void *)tlv->value; + for (i = 0; i < arg->n_bssids; i++) + ether_addr_copy(addrs[i].addr, arg->bssids[i].bssid); + + ptr += sizeof(*tlv); + ptr += bssid_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(ie_len); + memcpy(tlv->value, arg->ie, arg->ie_len); + + ptr += sizeof(*tlv); + ptr += ie_len; + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv start scan\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_stop_scan(struct ath10k *ar, + const struct wmi_stop_scan_arg *arg) +{ + struct wmi_stop_scan_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + u32 scan_id; + u32 req_id; + + if (arg->req_id > 0xFFF) + return ERR_PTR(-EINVAL); + if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + scan_id = arg->u.scan_id; + scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX; + + req_id = arg->req_id; + req_id |= WMI_HOST_SCAN_REQUESTOR_ID_PREFIX; + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->req_type = __cpu_to_le32(arg->req_type); + cmd->vdev_id = __cpu_to_le32(arg->u.vdev_id); + cmd->scan_id = __cpu_to_le32(scan_id); + cmd->scan_req_id = __cpu_to_le32(req_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv stop scan\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_create(struct ath10k *ar, + u32 vdev_id, + enum wmi_vdev_type vdev_type, + enum wmi_vdev_subtype vdev_subtype, + const u8 mac_addr[ETH_ALEN]) +{ + struct wmi_vdev_create_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->vdev_type = __cpu_to_le32(vdev_type); + cmd->vdev_subtype = __cpu_to_le32(vdev_subtype); + ether_addr_copy(cmd->vdev_macaddr.addr, mac_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev create\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id) +{ + struct wmi_vdev_delete_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev delete\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar, + const struct wmi_vdev_start_request_arg *arg, + bool restart) +{ + struct wmi_tlv_vdev_start_cmd *cmd; + struct wmi_channel *ch; + struct wmi_p2p_noa_descriptor *noa; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + void *ptr; + u32 flags = 0; + + if (WARN_ON(arg->ssid && arg->ssid_len == 0)) + return ERR_PTR(-EINVAL); + if (WARN_ON(arg->hidden_ssid && !arg->ssid)) + return ERR_PTR(-EINVAL); + if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid))) + return ERR_PTR(-EINVAL); + + len = (sizeof(*tlv) + sizeof(*cmd)) + + (sizeof(*tlv) + sizeof(*ch)) + + (sizeof(*tlv) + 0); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + if (arg->hidden_ssid) + flags |= WMI_VDEV_START_HIDDEN_SSID; + if (arg->pmf_enabled) + flags |= WMI_VDEV_START_PMF_ENABLED; + + ptr = (void *)skb->data; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + cmd->bcn_intval = __cpu_to_le32(arg->bcn_intval); + cmd->dtim_period = __cpu_to_le32(arg->dtim_period); + cmd->flags = __cpu_to_le32(flags); + cmd->bcn_tx_rate = __cpu_to_le32(arg->bcn_tx_rate); + cmd->bcn_tx_power = __cpu_to_le32(arg->bcn_tx_power); + cmd->disable_hw_ack = __cpu_to_le32(arg->disable_hw_ack); + + if (arg->ssid) { + cmd->ssid.ssid_len = __cpu_to_le32(arg->ssid_len); + memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len); + } + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL); + tlv->len = __cpu_to_le16(sizeof(*ch)); + ch = (void *)tlv->value; + ath10k_wmi_put_wmi_channel(ch, &arg->channel); + + ptr += sizeof(*tlv); + ptr += sizeof(*ch); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = 0; + noa = (void *)tlv->value; + + /* Note: This is a nested TLV containing: + * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv].. + */ + + ptr += sizeof(*tlv); + ptr += 0; + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev start\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id) +{ + struct wmi_vdev_stop_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev stop\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, + const u8 *bssid) + +{ + struct wmi_vdev_up_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_UP_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->vdev_assoc_id = __cpu_to_le32(aid); + ether_addr_copy(cmd->vdev_bssid.addr, bssid); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev up\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id) +{ + struct wmi_vdev_down_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev down\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id, + u32 param_id, u32 param_value) +{ + struct wmi_vdev_set_param_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->param_id = __cpu_to_le32(param_id); + cmd->param_value = __cpu_to_le32(param_value); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev set param\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_install_key(struct ath10k *ar, + const struct wmi_vdev_install_key_arg *arg) +{ + struct wmi_vdev_install_key_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + void *ptr; + + if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL) + return ERR_PTR(-EINVAL); + if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL) + return ERR_PTR(-EINVAL); + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + roundup(arg->key_len, sizeof(__le32)); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + cmd->key_idx = __cpu_to_le32(arg->key_idx); + cmd->key_flags = __cpu_to_le32(arg->key_flags); + cmd->key_cipher = __cpu_to_le32(arg->key_cipher); + cmd->key_len = __cpu_to_le32(arg->key_len); + cmd->key_txmic_len = __cpu_to_le32(arg->key_txmic_len); + cmd->key_rxmic_len = __cpu_to_le32(arg->key_rxmic_len); + + if (arg->macaddr) + ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(roundup(arg->key_len, sizeof(__le32))); + if (arg->key_data) + memcpy(tlv->value, arg->key_data, arg->key_len); + + ptr += sizeof(*tlv); + ptr += roundup(arg->key_len, sizeof(__le32)); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev install key\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) +{ + struct wmi_tlv_peer_create_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->peer_type = __cpu_to_le32(WMI_TLV_PEER_TYPE_DEFAULT); /* FIXME */ + ether_addr_copy(cmd->peer_addr.addr, peer_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer create\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) +{ + struct wmi_peer_delete_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer delete\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) +{ + struct wmi_peer_flush_tids_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap); + ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer flush\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id, + const u8 *peer_addr, + enum wmi_peer_param param_id, + u32 param_value) +{ + struct wmi_peer_set_param_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->param_id = __cpu_to_le32(param_id); + cmd->param_value = __cpu_to_le32(param_value); + ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer set param\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + struct wmi_tlv_peer_assoc_cmd *cmd; + struct wmi_vht_rate_set *vht_rate; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len, legacy_rate_len, ht_rate_len; + void *ptr; + + if (arg->peer_mpdu_density > 16) + return ERR_PTR(-EINVAL); + if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES) + return ERR_PTR(-EINVAL); + if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES) + return ERR_PTR(-EINVAL); + + legacy_rate_len = roundup(arg->peer_legacy_rates.num_rates, + sizeof(__le32)); + ht_rate_len = roundup(arg->peer_ht_rates.num_rates, sizeof(__le32)); + len = (sizeof(*tlv) + sizeof(*cmd)) + + (sizeof(*tlv) + legacy_rate_len) + + (sizeof(*tlv) + ht_rate_len) + + (sizeof(*tlv) + sizeof(*vht_rate)); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + cmd->new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1); + cmd->assoc_id = __cpu_to_le32(arg->peer_aid); + cmd->flags = __cpu_to_le32(arg->peer_flags); + cmd->caps = __cpu_to_le32(arg->peer_caps); + cmd->listen_intval = __cpu_to_le32(arg->peer_listen_intval); + cmd->ht_caps = __cpu_to_le32(arg->peer_ht_caps); + cmd->max_mpdu = __cpu_to_le32(arg->peer_max_mpdu); + cmd->mpdu_density = __cpu_to_le32(arg->peer_mpdu_density); + cmd->rate_caps = __cpu_to_le32(arg->peer_rate_caps); + cmd->nss = __cpu_to_le32(arg->peer_num_spatial_streams); + cmd->vht_caps = __cpu_to_le32(arg->peer_vht_caps); + cmd->phy_mode = __cpu_to_le32(arg->peer_phymode); + cmd->num_legacy_rates = __cpu_to_le32(arg->peer_legacy_rates.num_rates); + cmd->num_ht_rates = __cpu_to_le32(arg->peer_ht_rates.num_rates); + ether_addr_copy(cmd->mac_addr.addr, arg->addr); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(legacy_rate_len); + memcpy(tlv->value, arg->peer_legacy_rates.rates, + arg->peer_legacy_rates.num_rates); + + ptr += sizeof(*tlv); + ptr += legacy_rate_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(ht_rate_len); + memcpy(tlv->value, arg->peer_ht_rates.rates, + arg->peer_ht_rates.num_rates); + + ptr += sizeof(*tlv); + ptr += ht_rate_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VHT_RATE_SET); + tlv->len = __cpu_to_le16(sizeof(*vht_rate)); + vht_rate = (void *)tlv->value; + + vht_rate->rx_max_rate = __cpu_to_le32(arg->peer_vht_rates.rx_max_rate); + vht_rate->rx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.rx_mcs_set); + vht_rate->tx_max_rate = __cpu_to_le32(arg->peer_vht_rates.tx_max_rate); + vht_rate->tx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); + + ptr += sizeof(*tlv); + ptr += sizeof(*vht_rate); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer assoc\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_ps_mode psmode) +{ + struct wmi_sta_powersave_mode_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->sta_ps_mode = __cpu_to_le32(psmode); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set psmode\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_powersave_param param_id, + u32 param_value) +{ + struct wmi_sta_powersave_param_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->param_id = __cpu_to_le32(param_id); + cmd->param_value = __cpu_to_le32(param_value); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set sta ps\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac, + enum wmi_ap_ps_peer_param param_id, u32 value) +{ + struct wmi_ap_ps_peer_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + if (!mac) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->param_id = __cpu_to_le32(param_id); + cmd->param_value = __cpu_to_le32(value); + ether_addr_copy(cmd->peer_macaddr.addr, mac); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv ap ps param\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar, + const struct wmi_scan_chan_list_arg *arg) +{ + struct wmi_tlv_scan_chan_list_cmd *cmd; + struct wmi_channel *ci; + struct wmi_channel_arg *ch; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t chans_len, len; + int i; + void *ptr, *chans; + + chans_len = arg->n_channels * (sizeof(*tlv) + sizeof(*ci)); + len = (sizeof(*tlv) + sizeof(*cmd)) + + (sizeof(*tlv) + chans_len); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->num_scan_chans = __cpu_to_le32(arg->n_channels); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(chans_len); + chans = (void *)tlv->value; + + for (i = 0; i < arg->n_channels; i++) { + ch = &arg->channels[i]; + + tlv = chans; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL); + tlv->len = __cpu_to_le16(sizeof(*ci)); + ci = (void *)tlv->value; + + ath10k_wmi_put_wmi_channel(ci, ch); + + chans += sizeof(*tlv); + chans += sizeof(*ci); + } + + ptr += sizeof(*tlv); + ptr += chans_len; + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv scan chan list\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + struct wmi_bcn_tx_ref_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + struct sk_buff *beacon = arvif->beacon; + struct ieee80211_hdr *hdr; + u16 fc; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + hdr = (struct ieee80211_hdr *)beacon->data; + fc = le16_to_cpu(hdr->frame_control); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); + cmd->data_len = __cpu_to_le32(beacon->len); + cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr); + cmd->msdu_id = 0; + cmd->frame_control = __cpu_to_le32(fc); + cmd->flags = 0; + + if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero) + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); + + if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab) + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv beacon dma\n"); + return skb; +} + +static void *ath10k_wmi_tlv_put_wmm(void *ptr, + const struct wmi_wmm_params_arg *arg) +{ + struct wmi_wmm_params *wmm; + struct wmi_tlv *tlv; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WMM_PARAMS); + tlv->len = __cpu_to_le16(sizeof(*wmm)); + wmm = (void *)tlv->value; + ath10k_wmi_pdev_set_wmm_param(wmm, arg); + + return ptr + sizeof(*tlv) + sizeof(*wmm); +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar, + const struct wmi_pdev_set_wmm_params_arg *arg) +{ + struct wmi_tlv_pdev_set_wmm_cmd *cmd; + struct wmi_wmm_params *wmm; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + void *ptr; + + len = (sizeof(*tlv) + sizeof(*cmd)) + + (4 * (sizeof(*tlv) + sizeof(*wmm))); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + /* nothing to set here */ + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set wmm\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, + enum wmi_stats_id stats_id) +{ + struct wmi_request_stats_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->stats_id = __cpu_to_le32(stats_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request stats\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar, + enum wmi_force_fw_hang_type type, + u32 delay_ms) +{ + struct wmi_force_fw_hang_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->type = __cpu_to_le32(type); + cmd->delay_ms = __cpu_to_le32(delay_ms); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv force fw hang\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable) +{ + struct wmi_tlv_dbglog_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len, bmap_len; + u32 value; + void *ptr; + + if (module_enable) { + value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE( + module_enable, + WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE); + } else { + value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE( + WMI_TLV_DBGLOG_ALL_MODULES, + WMI_TLV_DBGLOG_LOG_LEVEL_WARN); + } + + bmap_len = 0; + len = sizeof(*tlv) + sizeof(*cmd) + sizeof(*tlv) + bmap_len; + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->param = __cpu_to_le32(WMI_TLV_DBGLOG_PARAM_LOG_LEVEL); + cmd->value = __cpu_to_le32(value); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32); + tlv->len = __cpu_to_le16(bmap_len); + + /* nothing to do here */ + + ptr += sizeof(*tlv); + ptr += sizeof(bmap_len); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv dbglog value 0x%08x\n", value); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pktlog_enable(struct ath10k *ar, u32 filter) +{ + struct wmi_tlv_pktlog_enable *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->filter = __cpu_to_le32(filter); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog enable filter 0x%08x\n", + filter); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar) +{ + struct wmi_tlv_pktlog_disable *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog disable\n"); + return skb; +} + +/****************/ +/* TLV mappings */ +/****************/ + +static struct wmi_cmd_map wmi_tlv_cmd_map = { + .init_cmdid = WMI_TLV_INIT_CMDID, + .start_scan_cmdid = WMI_TLV_START_SCAN_CMDID, + .stop_scan_cmdid = WMI_TLV_STOP_SCAN_CMDID, + .scan_chan_list_cmdid = WMI_TLV_SCAN_CHAN_LIST_CMDID, + .scan_sch_prio_tbl_cmdid = WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID, + .pdev_set_regdomain_cmdid = WMI_TLV_PDEV_SET_REGDOMAIN_CMDID, + .pdev_set_channel_cmdid = WMI_TLV_PDEV_SET_CHANNEL_CMDID, + .pdev_set_param_cmdid = WMI_TLV_PDEV_SET_PARAM_CMDID, + .pdev_pktlog_enable_cmdid = WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID, + .pdev_pktlog_disable_cmdid = WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID, + .pdev_set_wmm_params_cmdid = WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID, + .pdev_set_ht_cap_ie_cmdid = WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID, + .pdev_set_vht_cap_ie_cmdid = WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID, + .pdev_set_dscp_tid_map_cmdid = WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID, + .pdev_set_quiet_mode_cmdid = WMI_TLV_PDEV_SET_QUIET_MODE_CMDID, + .pdev_green_ap_ps_enable_cmdid = WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID, + .pdev_get_tpc_config_cmdid = WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID, + .pdev_set_base_macaddr_cmdid = WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID, + .vdev_create_cmdid = WMI_TLV_VDEV_CREATE_CMDID, + .vdev_delete_cmdid = WMI_TLV_VDEV_DELETE_CMDID, + .vdev_start_request_cmdid = WMI_TLV_VDEV_START_REQUEST_CMDID, + .vdev_restart_request_cmdid = WMI_TLV_VDEV_RESTART_REQUEST_CMDID, + .vdev_up_cmdid = WMI_TLV_VDEV_UP_CMDID, + .vdev_stop_cmdid = WMI_TLV_VDEV_STOP_CMDID, + .vdev_down_cmdid = WMI_TLV_VDEV_DOWN_CMDID, + .vdev_set_param_cmdid = WMI_TLV_VDEV_SET_PARAM_CMDID, + .vdev_install_key_cmdid = WMI_TLV_VDEV_INSTALL_KEY_CMDID, + .peer_create_cmdid = WMI_TLV_PEER_CREATE_CMDID, + .peer_delete_cmdid = WMI_TLV_PEER_DELETE_CMDID, + .peer_flush_tids_cmdid = WMI_TLV_PEER_FLUSH_TIDS_CMDID, + .peer_set_param_cmdid = WMI_TLV_PEER_SET_PARAM_CMDID, + .peer_assoc_cmdid = WMI_TLV_PEER_ASSOC_CMDID, + .peer_add_wds_entry_cmdid = WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID, + .peer_remove_wds_entry_cmdid = WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID, + .peer_mcast_group_cmdid = WMI_TLV_PEER_MCAST_GROUP_CMDID, + .bcn_tx_cmdid = WMI_TLV_BCN_TX_CMDID, + .pdev_send_bcn_cmdid = WMI_TLV_PDEV_SEND_BCN_CMDID, + .bcn_tmpl_cmdid = WMI_TLV_BCN_TMPL_CMDID, + .bcn_filter_rx_cmdid = WMI_TLV_BCN_FILTER_RX_CMDID, + .prb_req_filter_rx_cmdid = WMI_TLV_PRB_REQ_FILTER_RX_CMDID, + .mgmt_tx_cmdid = WMI_TLV_MGMT_TX_CMDID, + .prb_tmpl_cmdid = WMI_TLV_PRB_TMPL_CMDID, + .addba_clear_resp_cmdid = WMI_TLV_ADDBA_CLEAR_RESP_CMDID, + .addba_send_cmdid = WMI_TLV_ADDBA_SEND_CMDID, + .addba_status_cmdid = WMI_TLV_ADDBA_STATUS_CMDID, + .delba_send_cmdid = WMI_TLV_DELBA_SEND_CMDID, + .addba_set_resp_cmdid = WMI_TLV_ADDBA_SET_RESP_CMDID, + .send_singleamsdu_cmdid = WMI_TLV_SEND_SINGLEAMSDU_CMDID, + .sta_powersave_mode_cmdid = WMI_TLV_STA_POWERSAVE_MODE_CMDID, + .sta_powersave_param_cmdid = WMI_TLV_STA_POWERSAVE_PARAM_CMDID, + .sta_mimo_ps_mode_cmdid = WMI_TLV_STA_MIMO_PS_MODE_CMDID, + .pdev_dfs_enable_cmdid = WMI_TLV_PDEV_DFS_ENABLE_CMDID, + .pdev_dfs_disable_cmdid = WMI_TLV_PDEV_DFS_DISABLE_CMDID, + .roam_scan_mode = WMI_TLV_ROAM_SCAN_MODE, + .roam_scan_rssi_threshold = WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD, + .roam_scan_period = WMI_TLV_ROAM_SCAN_PERIOD, + .roam_scan_rssi_change_threshold = + WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + .roam_ap_profile = WMI_TLV_ROAM_AP_PROFILE, + .ofl_scan_add_ap_profile = WMI_TLV_ROAM_AP_PROFILE, + .ofl_scan_remove_ap_profile = WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE, + .ofl_scan_period = WMI_TLV_OFL_SCAN_PERIOD, + .p2p_dev_set_device_info = WMI_TLV_P2P_DEV_SET_DEVICE_INFO, + .p2p_dev_set_discoverability = WMI_TLV_P2P_DEV_SET_DISCOVERABILITY, + .p2p_go_set_beacon_ie = WMI_TLV_P2P_GO_SET_BEACON_IE, + .p2p_go_set_probe_resp_ie = WMI_TLV_P2P_GO_SET_PROBE_RESP_IE, + .p2p_set_vendor_ie_data_cmdid = WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID, + .ap_ps_peer_param_cmdid = WMI_TLV_AP_PS_PEER_PARAM_CMDID, + .ap_ps_peer_uapsd_coex_cmdid = WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID, + .peer_rate_retry_sched_cmdid = WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID, + .wlan_profile_trigger_cmdid = WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID, + .wlan_profile_set_hist_intvl_cmdid = + WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + .wlan_profile_get_profile_data_cmdid = + WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + .wlan_profile_enable_profile_id_cmdid = + WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + .wlan_profile_list_profile_id_cmdid = + WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + .pdev_suspend_cmdid = WMI_TLV_PDEV_SUSPEND_CMDID, + .pdev_resume_cmdid = WMI_TLV_PDEV_RESUME_CMDID, + .add_bcn_filter_cmdid = WMI_TLV_ADD_BCN_FILTER_CMDID, + .rmv_bcn_filter_cmdid = WMI_TLV_RMV_BCN_FILTER_CMDID, + .wow_add_wake_pattern_cmdid = WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID, + .wow_del_wake_pattern_cmdid = WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID, + .wow_enable_disable_wake_event_cmdid = + WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + .wow_enable_cmdid = WMI_TLV_WOW_ENABLE_CMDID, + .wow_hostwakeup_from_sleep_cmdid = + WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + .rtt_measreq_cmdid = WMI_TLV_RTT_MEASREQ_CMDID, + .rtt_tsf_cmdid = WMI_TLV_RTT_TSF_CMDID, + .vdev_spectral_scan_configure_cmdid = WMI_TLV_SPECTRAL_SCAN_CONF_CMDID, + .vdev_spectral_scan_enable_cmdid = WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID, + .request_stats_cmdid = WMI_TLV_REQUEST_STATS_CMDID, + .set_arp_ns_offload_cmdid = WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID, + .network_list_offload_config_cmdid = + WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID, + .gtk_offload_cmdid = WMI_TLV_GTK_OFFLOAD_CMDID, + .csa_offload_enable_cmdid = WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID, + .csa_offload_chanswitch_cmdid = WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID, + .chatter_set_mode_cmdid = WMI_TLV_CHATTER_SET_MODE_CMDID, + .peer_tid_addba_cmdid = WMI_TLV_PEER_TID_ADDBA_CMDID, + .peer_tid_delba_cmdid = WMI_TLV_PEER_TID_DELBA_CMDID, + .sta_dtim_ps_method_cmdid = WMI_TLV_STA_DTIM_PS_METHOD_CMDID, + .sta_uapsd_auto_trig_cmdid = WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID, + .sta_keepalive_cmd = WMI_TLV_STA_KEEPALIVE_CMDID, + .echo_cmdid = WMI_TLV_ECHO_CMDID, + .pdev_utf_cmdid = WMI_TLV_PDEV_UTF_CMDID, + .dbglog_cfg_cmdid = WMI_TLV_DBGLOG_CFG_CMDID, + .pdev_qvit_cmdid = WMI_TLV_PDEV_QVIT_CMDID, + .pdev_ftm_intg_cmdid = WMI_TLV_PDEV_FTM_INTG_CMDID, + .vdev_set_keepalive_cmdid = WMI_TLV_VDEV_SET_KEEPALIVE_CMDID, + .vdev_get_keepalive_cmdid = WMI_TLV_VDEV_GET_KEEPALIVE_CMDID, + .force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID, + .gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID, + .gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID, +}; + +static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { + .tx_chain_mask = WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK, + .rx_chain_mask = WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK, + .txpower_limit2g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G, + .txpower_limit5g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G, + .txpower_scale = WMI_TLV_PDEV_PARAM_TXPOWER_SCALE, + .beacon_gen_mode = WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE, + .beacon_tx_mode = WMI_TLV_PDEV_PARAM_BEACON_TX_MODE, + .resmgr_offchan_mode = WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + .protection_mode = WMI_TLV_PDEV_PARAM_PROTECTION_MODE, + .dynamic_bw = WMI_TLV_PDEV_PARAM_DYNAMIC_BW, + .non_agg_sw_retry_th = WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + .agg_sw_retry_th = WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH, + .sta_kickout_th = WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH, + .ac_aggrsize_scaling = WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING, + .ltr_enable = WMI_TLV_PDEV_PARAM_LTR_ENABLE, + .ltr_ac_latency_be = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE, + .ltr_ac_latency_bk = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK, + .ltr_ac_latency_vi = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI, + .ltr_ac_latency_vo = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO, + .ltr_ac_latency_timeout = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + .ltr_sleep_override = WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + .ltr_rx_override = WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE, + .ltr_tx_activity_timeout = WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + .l1ss_enable = WMI_TLV_PDEV_PARAM_L1SS_ENABLE, + .dsleep_enable = WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE, + .pcielp_txbuf_flush = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + .pcielp_txbuf_watermark = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + .pcielp_txbuf_tmo_en = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + .pcielp_txbuf_tmo_value = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + .pdev_stats_update_period = WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + .vdev_stats_update_period = WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + .peer_stats_update_period = WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + .bcnflt_stats_update_period = + WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + .pmf_qos = WMI_TLV_PDEV_PARAM_PMF_QOS, + .arp_ac_override = WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE, + .dcs = WMI_TLV_PDEV_PARAM_DCS, + .ani_enable = WMI_TLV_PDEV_PARAM_ANI_ENABLE, + .ani_poll_period = WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD, + .ani_listen_period = WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD, + .ani_ofdm_level = WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL, + .ani_cck_level = WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL, + .dyntxchain = WMI_TLV_PDEV_PARAM_DYNTXCHAIN, + .proxy_sta = WMI_TLV_PDEV_PARAM_PROXY_STA, + .idle_ps_config = WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG, + .power_gating_sleep = WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP, + .fast_channel_reset = WMI_TLV_PDEV_PARAM_UNSUPPORTED, + .burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR, + .burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE, +}; + +static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { + .rts_threshold = WMI_TLV_VDEV_PARAM_RTS_THRESHOLD, + .fragmentation_threshold = WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + .beacon_interval = WMI_TLV_VDEV_PARAM_BEACON_INTERVAL, + .listen_interval = WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL, + .multicast_rate = WMI_TLV_VDEV_PARAM_MULTICAST_RATE, + .mgmt_tx_rate = WMI_TLV_VDEV_PARAM_MGMT_TX_RATE, + .slot_time = WMI_TLV_VDEV_PARAM_SLOT_TIME, + .preamble = WMI_TLV_VDEV_PARAM_PREAMBLE, + .swba_time = WMI_TLV_VDEV_PARAM_SWBA_TIME, + .wmi_vdev_stats_update_period = WMI_TLV_VDEV_STATS_UPDATE_PERIOD, + .wmi_vdev_pwrsave_ageout_time = WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME, + .wmi_vdev_host_swba_interval = WMI_TLV_VDEV_HOST_SWBA_INTERVAL, + .dtim_period = WMI_TLV_VDEV_PARAM_DTIM_PERIOD, + .wmi_vdev_oc_scheduler_air_time_limit = + WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + .wds = WMI_TLV_VDEV_PARAM_WDS, + .atim_window = WMI_TLV_VDEV_PARAM_ATIM_WINDOW, + .bmiss_count_max = WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX, + .bmiss_first_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT, + .bmiss_final_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT, + .feature_wmm = WMI_TLV_VDEV_PARAM_FEATURE_WMM, + .chwidth = WMI_TLV_VDEV_PARAM_CHWIDTH, + .chextoffset = WMI_TLV_VDEV_PARAM_CHEXTOFFSET, + .disable_htprotection = WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION, + .sta_quickkickout = WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT, + .mgmt_rate = WMI_TLV_VDEV_PARAM_MGMT_RATE, + .protection_mode = WMI_TLV_VDEV_PARAM_PROTECTION_MODE, + .fixed_rate = WMI_TLV_VDEV_PARAM_FIXED_RATE, + .sgi = WMI_TLV_VDEV_PARAM_SGI, + .ldpc = WMI_TLV_VDEV_PARAM_LDPC, + .tx_stbc = WMI_TLV_VDEV_PARAM_TX_STBC, + .rx_stbc = WMI_TLV_VDEV_PARAM_RX_STBC, + .intra_bss_fwd = WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD, + .def_keyid = WMI_TLV_VDEV_PARAM_DEF_KEYID, + .nss = WMI_TLV_VDEV_PARAM_NSS, + .bcast_data_rate = WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE, + .mcast_data_rate = WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE, + .mcast_indicate = WMI_TLV_VDEV_PARAM_MCAST_INDICATE, + .dhcp_indicate = WMI_TLV_VDEV_PARAM_DHCP_INDICATE, + .unknown_dest_indicate = WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + .ap_keepalive_min_idle_inactive_time_secs = + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_idle_inactive_time_secs = + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_unresponsive_time_secs = + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + .ap_enable_nawds = WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS, + .mcast2ucast_set = WMI_TLV_VDEV_PARAM_UNSUPPORTED, + .enable_rtscts = WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS, + .txbf = WMI_TLV_VDEV_PARAM_TXBF, + .packet_powersave = WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE, + .drop_unencry = WMI_TLV_VDEV_PARAM_DROP_UNENCRY, + .tx_encap_type = WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE, + .ap_detect_out_of_sync_sleeping_sta_time_secs = + WMI_TLV_VDEV_PARAM_UNSUPPORTED, +}; + +static const struct wmi_ops wmi_tlv_ops = { + .rx = ath10k_wmi_tlv_op_rx, + .map_svc = wmi_tlv_svc_map, + + .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_tlv_op_pull_swba_ev, + .pull_phyerr = ath10k_wmi_tlv_op_pull_phyerr_ev, + .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev, + .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev, + .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats, + + .gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume, + .gen_pdev_set_rd = ath10k_wmi_tlv_op_gen_pdev_set_rd, + .gen_pdev_set_param = ath10k_wmi_tlv_op_gen_pdev_set_param, + .gen_init = ath10k_wmi_tlv_op_gen_init, + .gen_start_scan = ath10k_wmi_tlv_op_gen_start_scan, + .gen_stop_scan = ath10k_wmi_tlv_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_tlv_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_tlv_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_tlv_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_tlv_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_tlv_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_tlv_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_tlv_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_tlv_op_gen_vdev_install_key, + .gen_peer_create = ath10k_wmi_tlv_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_tlv_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_tlv_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_tlv_op_gen_peer_set_param, + .gen_peer_assoc = ath10k_wmi_tlv_op_gen_peer_assoc, + .gen_set_psmode = ath10k_wmi_tlv_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang, + /* .gen_mgmt_tx = not implemented; HTT is used */ + .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, +}; + +/************/ +/* TLV init */ +/************/ + +void ath10k_wmi_tlv_attach(struct ath10k *ar) +{ + ar->wmi.cmd = &wmi_tlv_cmd_map; + ar->wmi.vdev_param = &wmi_tlv_vdev_param_map; + ar->wmi.pdev_param = &wmi_tlv_pdev_param_map; + ar->wmi.ops = &wmi_tlv_ops; +} diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h new file mode 100644 index 000000000000..54ffa120cd60 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -0,0 +1,1380 @@ +/* + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _WMI_TLV_H +#define _WMI_TLV_H + +#define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1) +#define WMI_TLV_EV(grp_id) (((grp_id) << 12) | 0x1) +#define WMI_TLV_CMD_UNSUPPORTED 0 +#define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0 +#define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0 + +enum wmi_tlv_grp_id { + WMI_TLV_GRP_START = 0x3, + WMI_TLV_GRP_SCAN = WMI_TLV_GRP_START, + WMI_TLV_GRP_PDEV, + WMI_TLV_GRP_VDEV, + WMI_TLV_GRP_PEER, + WMI_TLV_GRP_MGMT, + WMI_TLV_GRP_BA_NEG, + WMI_TLV_GRP_STA_PS, + WMI_TLV_GRP_DFS, + WMI_TLV_GRP_ROAM, + WMI_TLV_GRP_OFL_SCAN, + WMI_TLV_GRP_P2P, + WMI_TLV_GRP_AP_PS, + WMI_TLV_GRP_RATECTL, + WMI_TLV_GRP_PROFILE, + WMI_TLV_GRP_SUSPEND, + WMI_TLV_GRP_BCN_FILTER, + WMI_TLV_GRP_WOW, + WMI_TLV_GRP_RTT, + WMI_TLV_GRP_SPECTRAL, + WMI_TLV_GRP_STATS, + WMI_TLV_GRP_ARP_NS_OFL, + WMI_TLV_GRP_NLO_OFL, + WMI_TLV_GRP_GTK_OFL, + WMI_TLV_GRP_CSA_OFL, + WMI_TLV_GRP_CHATTER, + WMI_TLV_GRP_TID_ADDBA, + WMI_TLV_GRP_MISC, + WMI_TLV_GRP_GPIO, + WMI_TLV_GRP_FWTEST, + WMI_TLV_GRP_TDLS, + WMI_TLV_GRP_RESMGR, + WMI_TLV_GRP_STA_SMPS, + WMI_TLV_GRP_WLAN_HB, + WMI_TLV_GRP_RMC, + WMI_TLV_GRP_MHF_OFL, + WMI_TLV_GRP_LOCATION_SCAN, + WMI_TLV_GRP_OEM, + WMI_TLV_GRP_NAN, + WMI_TLV_GRP_COEX, + WMI_TLV_GRP_OBSS_OFL, + WMI_TLV_GRP_LPI, + WMI_TLV_GRP_EXTSCAN, + WMI_TLV_GRP_DHCP_OFL, + WMI_TLV_GRP_IPA, + WMI_TLV_GRP_MDNS_OFL, + WMI_TLV_GRP_SAP_OFL, +}; + +enum wmi_tlv_cmd_id { + WMI_TLV_INIT_CMDID = 0x1, + WMI_TLV_START_SCAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SCAN), + WMI_TLV_STOP_SCAN_CMDID, + WMI_TLV_SCAN_CHAN_LIST_CMDID, + WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID, + WMI_TLV_SCAN_UPDATE_REQUEST_CMDID, + WMI_TLV_SCAN_PROB_REQ_OUI_CMDID, + WMI_TLV_PDEV_SET_REGDOMAIN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PDEV), + WMI_TLV_PDEV_SET_CHANNEL_CMDID, + WMI_TLV_PDEV_SET_PARAM_CMDID, + WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID, + WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID, + WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID, + WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID, + WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID, + WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID, + WMI_TLV_PDEV_SET_QUIET_MODE_CMDID, + WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID, + WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID, + WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID, + WMI_TLV_PDEV_DUMP_CMDID, + WMI_TLV_PDEV_SET_LED_CONFIG_CMDID, + WMI_TLV_PDEV_GET_TEMPERATURE_CMDID, + WMI_TLV_PDEV_SET_LED_FLASHING_CMDID, + WMI_TLV_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_VDEV), + WMI_TLV_VDEV_DELETE_CMDID, + WMI_TLV_VDEV_START_REQUEST_CMDID, + WMI_TLV_VDEV_RESTART_REQUEST_CMDID, + WMI_TLV_VDEV_UP_CMDID, + WMI_TLV_VDEV_STOP_CMDID, + WMI_TLV_VDEV_DOWN_CMDID, + WMI_TLV_VDEV_SET_PARAM_CMDID, + WMI_TLV_VDEV_INSTALL_KEY_CMDID, + WMI_TLV_VDEV_WNM_SLEEPMODE_CMDID, + WMI_TLV_VDEV_WMM_ADDTS_CMDID, + WMI_TLV_VDEV_WMM_DELTS_CMDID, + WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID, + WMI_TLV_VDEV_SET_GTX_PARAMS_CMDID, + WMI_TLV_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID, + WMI_TLV_VDEV_PLMREQ_START_CMDID, + WMI_TLV_VDEV_PLMREQ_STOP_CMDID, + WMI_TLV_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PEER), + WMI_TLV_PEER_DELETE_CMDID, + WMI_TLV_PEER_FLUSH_TIDS_CMDID, + WMI_TLV_PEER_SET_PARAM_CMDID, + WMI_TLV_PEER_ASSOC_CMDID, + WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID, + WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID, + WMI_TLV_PEER_MCAST_GROUP_CMDID, + WMI_TLV_PEER_INFO_REQ_CMDID, + WMI_TLV_PEER_GET_ESTIMATED_LINKSPEED_CMDID, + WMI_TLV_BCN_TX_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MGMT), + WMI_TLV_PDEV_SEND_BCN_CMDID, + WMI_TLV_BCN_TMPL_CMDID, + WMI_TLV_BCN_FILTER_RX_CMDID, + WMI_TLV_PRB_REQ_FILTER_RX_CMDID, + WMI_TLV_MGMT_TX_CMDID, + WMI_TLV_PRB_TMPL_CMDID, + WMI_TLV_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BA_NEG), + WMI_TLV_ADDBA_SEND_CMDID, + WMI_TLV_ADDBA_STATUS_CMDID, + WMI_TLV_DELBA_SEND_CMDID, + WMI_TLV_ADDBA_SET_RESP_CMDID, + WMI_TLV_SEND_SINGLEAMSDU_CMDID, + WMI_TLV_STA_POWERSAVE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_PS), + WMI_TLV_STA_POWERSAVE_PARAM_CMDID, + WMI_TLV_STA_MIMO_PS_MODE_CMDID, + WMI_TLV_PDEV_DFS_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_DFS), + WMI_TLV_PDEV_DFS_DISABLE_CMDID, + WMI_TLV_DFS_PHYERR_FILTER_ENA_CMDID, + WMI_TLV_DFS_PHYERR_FILTER_DIS_CMDID, + WMI_TLV_ROAM_SCAN_MODE = WMI_TLV_CMD(WMI_TLV_GRP_ROAM), + WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD, + WMI_TLV_ROAM_SCAN_PERIOD, + WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + WMI_TLV_ROAM_AP_PROFILE, + WMI_TLV_ROAM_CHAN_LIST, + WMI_TLV_ROAM_SCAN_CMD, + WMI_TLV_ROAM_SYNCH_COMPLETE, + WMI_TLV_ROAM_SET_RIC_REQUEST_CMDID, + WMI_TLV_ROAM_INVOKE_CMDID, + WMI_TLV_OFL_SCAN_ADD_AP_PROFILE = WMI_TLV_CMD(WMI_TLV_GRP_OFL_SCAN), + WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE, + WMI_TLV_OFL_SCAN_PERIOD, + WMI_TLV_P2P_DEV_SET_DEVICE_INFO = WMI_TLV_CMD(WMI_TLV_GRP_P2P), + WMI_TLV_P2P_DEV_SET_DISCOVERABILITY, + WMI_TLV_P2P_GO_SET_BEACON_IE, + WMI_TLV_P2P_GO_SET_PROBE_RESP_IE, + WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID, + WMI_TLV_P2P_DISC_OFFLOAD_CONFIG_CMDID, + WMI_TLV_P2P_DISC_OFFLOAD_APPIE_CMDID, + WMI_TLV_P2P_DISC_OFFLOAD_PATTERN_CMDID, + WMI_TLV_P2P_SET_OPPPS_PARAM_CMDID, + WMI_TLV_AP_PS_PEER_PARAM_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_AP_PS), + WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID, + WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RATECTL), + WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PROFILE), + WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + WMI_TLV_PDEV_SUSPEND_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SUSPEND), + WMI_TLV_PDEV_RESUME_CMDID, + WMI_TLV_ADD_BCN_FILTER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BCN_FILTER), + WMI_TLV_RMV_BCN_FILTER_CMDID, + WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WOW), + WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID, + WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + WMI_TLV_WOW_ENABLE_CMDID, + WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + WMI_TLV_WOW_ACER_IOAC_ADD_KEEPALIVE_CMDID, + WMI_TLV_WOW_ACER_IOAC_DEL_KEEPALIVE_CMDID, + WMI_TLV_WOW_ACER_IOAC_ADD_WAKE_PATTERN_CMDID, + WMI_TLV_WOW_ACER_IOAC_DEL_WAKE_PATTERN_CMDID, + WMI_TLV_D0_WOW_ENABLE_DISABLE_CMDID, + WMI_TLV_EXTWOW_ENABLE_CMDID, + WMI_TLV_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID, + WMI_TLV_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID, + WMI_TLV_RTT_MEASREQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RTT), + WMI_TLV_RTT_TSF_CMDID, + WMI_TLV_SPECTRAL_SCAN_CONF_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SPECTRAL), + WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID, + WMI_TLV_REQUEST_STATS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STATS), + WMI_TLV_MCC_SCHED_TRAFFIC_STATS_CMDID, + WMI_TLV_REQUEST_STATS_EXT_CMDID, + WMI_TLV_REQUEST_LINK_STATS_CMDID, + WMI_TLV_START_LINK_STATS_CMDID, + WMI_TLV_CLEAR_LINK_STATS_CMDID, + WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_ARP_NS_OFL), + WMI_TLV_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID, + WMI_TLV_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID, + WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID = + WMI_TLV_CMD(WMI_TLV_GRP_NLO_OFL), + WMI_TLV_APFIND_CMDID, + WMI_TLV_GTK_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GTK_OFL), + WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CSA_OFL), + WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID, + WMI_TLV_CHATTER_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CHATTER), + WMI_TLV_CHATTER_ADD_COALESCING_FILTER_CMDID, + WMI_TLV_CHATTER_DELETE_COALESCING_FILTER_CMDID, + WMI_TLV_CHATTER_COALESCING_QUERY_CMDID, + WMI_TLV_PEER_TID_ADDBA_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TID_ADDBA), + WMI_TLV_PEER_TID_DELBA_CMDID, + WMI_TLV_STA_DTIM_PS_METHOD_CMDID, + WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID, + WMI_TLV_STA_KEEPALIVE_CMDID, + WMI_TLV_BA_REQ_SSN_CMDID, + WMI_TLV_ECHO_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MISC), + WMI_TLV_PDEV_UTF_CMDID, + WMI_TLV_DBGLOG_CFG_CMDID, + WMI_TLV_PDEV_QVIT_CMDID, + WMI_TLV_PDEV_FTM_INTG_CMDID, + WMI_TLV_VDEV_SET_KEEPALIVE_CMDID, + WMI_TLV_VDEV_GET_KEEPALIVE_CMDID, + WMI_TLV_FORCE_FW_HANG_CMDID, + WMI_TLV_SET_MCASTBCAST_FILTER_CMDID, + WMI_TLV_THERMAL_MGMT_CMDID, + WMI_TLV_HOST_AUTO_SHUTDOWN_CFG_CMDID, + WMI_TLV_TPC_CHAINMASK_CONFIG_CMDID, + WMI_TLV_SET_ANTENNA_DIVERSITY_CMDID, + WMI_TLV_GPIO_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GPIO), + WMI_TLV_GPIO_OUTPUT_CMDID, + WMI_TLV_TXBF_CMDID, + WMI_TLV_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID = + WMI_TLV_CMD(WMI_TLV_GRP_FWTEST), + WMI_TLV_FWTEST_P2P_SET_NOA_PARAM_CMDID, + WMI_TLV_UNIT_TEST_CMDID, + WMI_TLV_TDLS_SET_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TDLS), + WMI_TLV_TDLS_PEER_UPDATE_CMDID, + WMI_TLV_TDLS_SET_OFFCHAN_MODE_CMDID, + WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RESMGR), + WMI_TLV_RESMGR_SET_CHAN_TIME_QUOTA_CMDID, + WMI_TLV_RESMGR_SET_CHAN_LATENCY_CMDID, + WMI_TLV_STA_SMPS_FORCE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_SMPS), + WMI_TLV_STA_SMPS_PARAM_CMDID, + WMI_TLV_HB_SET_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WLAN_HB), + WMI_TLV_HB_SET_TCP_PARAMS_CMDID, + WMI_TLV_HB_SET_TCP_PKT_FILTER_CMDID, + WMI_TLV_HB_SET_UDP_PARAMS_CMDID, + WMI_TLV_HB_SET_UDP_PKT_FILTER_CMDID, + WMI_TLV_RMC_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RMC), + WMI_TLV_RMC_SET_ACTION_PERIOD_CMDID, + WMI_TLV_RMC_CONFIG_CMDID, + WMI_TLV_MHF_OFFLOAD_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MHF_OFL), + WMI_TLV_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID, + WMI_TLV_BATCH_SCAN_ENABLE_CMDID = + WMI_TLV_CMD(WMI_TLV_GRP_LOCATION_SCAN), + WMI_TLV_BATCH_SCAN_DISABLE_CMDID, + WMI_TLV_BATCH_SCAN_TRIGGER_RESULT_CMDID, + WMI_TLV_OEM_REQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OEM), + WMI_TLV_NAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_NAN), + WMI_TLV_MODEM_POWER_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_COEX), + WMI_TLV_CHAN_AVOID_UPDATE_CMDID, + WMI_TLV_OBSS_SCAN_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OBSS_OFL), + WMI_TLV_OBSS_SCAN_DISABLE_CMDID, + WMI_TLV_LPI_MGMT_SNOOPING_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_LPI), + WMI_TLV_LPI_START_SCAN_CMDID, + WMI_TLV_LPI_STOP_SCAN_CMDID, + WMI_TLV_EXTSCAN_START_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_EXTSCAN), + WMI_TLV_EXTSCAN_STOP_CMDID, + WMI_TLV_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID, + WMI_TLV_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID, + WMI_TLV_EXTSCAN_GET_CACHED_RESULTS_CMDID, + WMI_TLV_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID, + WMI_TLV_EXTSCAN_SET_CAPABILITIES_CMDID, + WMI_TLV_EXTSCAN_GET_CAPABILITIES_CMDID, + WMI_TLV_SET_DHCP_SERVER_OFFLOAD_CMDID = + WMI_TLV_CMD(WMI_TLV_GRP_DHCP_OFL), + WMI_TLV_IPA_OFFLOAD_ENABLE_DISABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_IPA), + WMI_TLV_MDNS_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MDNS_OFL), + WMI_TLV_MDNS_SET_FQDN_CMDID, + WMI_TLV_MDNS_SET_RESPONSE_CMDID, + WMI_TLV_MDNS_GET_STATS_CMDID, + WMI_TLV_SAP_OFL_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SAP_OFL), +}; + +enum wmi_tlv_event_id { + WMI_TLV_SERVICE_READY_EVENTID = 0x1, + WMI_TLV_READY_EVENTID, + WMI_TLV_SCAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SCAN), + WMI_TLV_PDEV_TPC_CONFIG_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PDEV), + WMI_TLV_CHAN_INFO_EVENTID, + WMI_TLV_PHYERR_EVENTID, + WMI_TLV_PDEV_DUMP_EVENTID, + WMI_TLV_TX_PAUSE_EVENTID, + WMI_TLV_DFS_RADAR_EVENTID, + WMI_TLV_PDEV_L1SS_TRACK_EVENTID, + WMI_TLV_PDEV_TEMPERATURE_EVENTID, + WMI_TLV_VDEV_START_RESP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_VDEV), + WMI_TLV_VDEV_STOPPED_EVENTID, + WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID, + WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID, + WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER), + WMI_TLV_PEER_INFO_EVENTID, + WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID, + WMI_TLV_PEER_ESTIMATED_LINKSPEED_EVENTID, + WMI_TLV_PEER_STATE_EVENTID, + WMI_TLV_MGMT_RX_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MGMT), + WMI_TLV_HOST_SWBA_EVENTID, + WMI_TLV_TBTTOFFSET_UPDATE_EVENTID, + WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID, + WMI_TLV_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID, + WMI_TLV_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_BA_NEG), + WMI_TLV_TX_ADDBA_COMPLETE_EVENTID, + WMI_TLV_BA_RSP_SSN_EVENTID, + WMI_TLV_AGGR_STATE_TRIG_EVENTID, + WMI_TLV_ROAM_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_ROAM), + WMI_TLV_PROFILE_MATCH, + WMI_TLV_ROAM_SYNCH_EVENTID, + WMI_TLV_P2P_DISC_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_P2P), + WMI_TLV_P2P_NOA_EVENTID, + WMI_TLV_PDEV_RESUME_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SUSPEND), + WMI_TLV_WOW_WAKEUP_HOST_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_WOW), + WMI_TLV_D0_WOW_DISABLE_ACK_EVENTID, + WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_RTT), + WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID, + WMI_TLV_RTT_ERROR_REPORT_EVENTID, + WMI_TLV_STATS_EXT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_STATS), + WMI_TLV_IFACE_LINK_STATS_EVENTID, + WMI_TLV_PEER_LINK_STATS_EVENTID, + WMI_TLV_RADIO_LINK_STATS_EVENTID, + WMI_TLV_NLO_MATCH_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NLO_OFL), + WMI_TLV_NLO_SCAN_COMPLETE_EVENTID, + WMI_TLV_APFIND_EVENTID, + WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GTK_OFL), + WMI_TLV_GTK_REKEY_FAIL_EVENTID, + WMI_TLV_CSA_HANDLING_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CSA_OFL), + WMI_TLV_CHATTER_PC_QUERY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CHATTER), + WMI_TLV_ECHO_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MISC), + WMI_TLV_PDEV_UTF_EVENTID, + WMI_TLV_DEBUG_MESG_EVENTID, + WMI_TLV_UPDATE_STATS_EVENTID, + WMI_TLV_DEBUG_PRINT_EVENTID, + WMI_TLV_DCS_INTERFERENCE_EVENTID, + WMI_TLV_PDEV_QVIT_EVENTID, + WMI_TLV_WLAN_PROFILE_DATA_EVENTID, + WMI_TLV_PDEV_FTM_INTG_EVENTID, + WMI_TLV_WLAN_FREQ_AVOID_EVENTID, + WMI_TLV_VDEV_GET_KEEPALIVE_EVENTID, + WMI_TLV_THERMAL_MGMT_EVENTID, + WMI_TLV_DIAG_DATA_CONTAINER_EVENTID, + WMI_TLV_HOST_AUTO_SHUTDOWN_EVENTID, + WMI_TLV_UPDATE_WHAL_MIB_STATS_EVENTID, + WMI_TLV_UPDATE_VDEV_RATE_STATS_EVENTID, + WMI_TLV_DIAG_EVENTID, + WMI_TLV_GPIO_INPUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GPIO), + WMI_TLV_UPLOADH_EVENTID, + WMI_TLV_CAPTUREH_EVENTID, + WMI_TLV_RFKILL_STATE_CHANGE_EVENTID, + WMI_TLV_TDLS_PEER_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_TDLS), + WMI_TLV_BATCH_SCAN_ENABLED_EVENTID = + WMI_TLV_EV(WMI_TLV_GRP_LOCATION_SCAN), + WMI_TLV_BATCH_SCAN_RESULT_EVENTID, + WMI_TLV_OEM_CAPABILITY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_OEM), + WMI_TLV_OEM_MEASUREMENT_REPORT_EVENTID, + WMI_TLV_OEM_ERROR_REPORT_EVENTID, + WMI_TLV_NAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NAN), + WMI_TLV_LPI_RESULT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_LPI), + WMI_TLV_LPI_STATUS_EVENTID, + WMI_TLV_LPI_HANDOFF_EVENTID, + WMI_TLV_EXTSCAN_START_STOP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_EXTSCAN), + WMI_TLV_EXTSCAN_OPERATION_EVENTID, + WMI_TLV_EXTSCAN_TABLE_USAGE_EVENTID, + WMI_TLV_EXTSCAN_CACHED_RESULTS_EVENTID, + WMI_TLV_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID, + WMI_TLV_EXTSCAN_HOTLIST_MATCH_EVENTID, + WMI_TLV_EXTSCAN_CAPABILITIES_EVENTID, + WMI_TLV_MDNS_STATS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MDNS_OFL), + WMI_TLV_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SAP_OFL), + WMI_TLV_SAP_OFL_DEL_STA_EVENTID, +}; + +enum wmi_tlv_pdev_param { + WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK = 0x1, + WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK, + WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G, + WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G, + WMI_TLV_PDEV_PARAM_TXPOWER_SCALE, + WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE, + WMI_TLV_PDEV_PARAM_BEACON_TX_MODE, + WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + WMI_TLV_PDEV_PARAM_PROTECTION_MODE, + WMI_TLV_PDEV_PARAM_DYNAMIC_BW, + WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH, + WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH, + WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING, + WMI_TLV_PDEV_PARAM_LTR_ENABLE, + WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE, + WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK, + WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI, + WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO, + WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE, + WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + WMI_TLV_PDEV_PARAM_L1SS_ENABLE, + WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE, + WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, + WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + WMI_TLV_PDEV_PARAM_PMF_QOS, + WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE, + WMI_TLV_PDEV_PARAM_DCS, + WMI_TLV_PDEV_PARAM_ANI_ENABLE, + WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD, + WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD, + WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL, + WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL, + WMI_TLV_PDEV_PARAM_DYNTXCHAIN, + WMI_TLV_PDEV_PARAM_PROXY_STA, + WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG, + WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP, + WMI_TLV_PDEV_PARAM_RFKILL_ENABLE, + WMI_TLV_PDEV_PARAM_BURST_DUR, + WMI_TLV_PDEV_PARAM_BURST_ENABLE, + WMI_TLV_PDEV_PARAM_HW_RFKILL_CONFIG, + WMI_TLV_PDEV_PARAM_LOW_POWER_RF_ENABLE, + WMI_TLV_PDEV_PARAM_L1SS_TRACK, + WMI_TLV_PDEV_PARAM_HYST_EN, + WMI_TLV_PDEV_PARAM_POWER_COLLAPSE_ENABLE, + WMI_TLV_PDEV_PARAM_LED_SYS_STATE, + WMI_TLV_PDEV_PARAM_LED_ENABLE, + WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_LATENCY, + WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_ENABLE, + WMI_TLV_PDEV_PARAM_WHAL_MIB_STATS_UPDATE_ENABLE, + WMI_TLV_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD, + WMI_TLV_PDEV_PARAM_TXPOWER_REASON_NONE, + WMI_TLV_PDEV_PARAM_TXPOWER_REASON_SAR, + WMI_TLV_PDEV_PARAM_TXPOWER_REASON_MAX, +}; + +enum wmi_tlv_vdev_param { + WMI_TLV_VDEV_PARAM_RTS_THRESHOLD = 0x1, + WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + WMI_TLV_VDEV_PARAM_BEACON_INTERVAL, + WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL, + WMI_TLV_VDEV_PARAM_MULTICAST_RATE, + WMI_TLV_VDEV_PARAM_MGMT_TX_RATE, + WMI_TLV_VDEV_PARAM_SLOT_TIME, + WMI_TLV_VDEV_PARAM_PREAMBLE, + WMI_TLV_VDEV_PARAM_SWBA_TIME, + WMI_TLV_VDEV_STATS_UPDATE_PERIOD, + WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME, + WMI_TLV_VDEV_HOST_SWBA_INTERVAL, + WMI_TLV_VDEV_PARAM_DTIM_PERIOD, + WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + WMI_TLV_VDEV_PARAM_WDS, + WMI_TLV_VDEV_PARAM_ATIM_WINDOW, + WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX, + WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT, + WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT, + WMI_TLV_VDEV_PARAM_FEATURE_WMM, + WMI_TLV_VDEV_PARAM_CHWIDTH, + WMI_TLV_VDEV_PARAM_CHEXTOFFSET, + WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION, + WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT, + WMI_TLV_VDEV_PARAM_MGMT_RATE, + WMI_TLV_VDEV_PARAM_PROTECTION_MODE, + WMI_TLV_VDEV_PARAM_FIXED_RATE, + WMI_TLV_VDEV_PARAM_SGI, + WMI_TLV_VDEV_PARAM_LDPC, + WMI_TLV_VDEV_PARAM_TX_STBC, + WMI_TLV_VDEV_PARAM_RX_STBC, + WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD, + WMI_TLV_VDEV_PARAM_DEF_KEYID, + WMI_TLV_VDEV_PARAM_NSS, + WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE, + WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE, + WMI_TLV_VDEV_PARAM_MCAST_INDICATE, + WMI_TLV_VDEV_PARAM_DHCP_INDICATE, + WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS, + WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS, + WMI_TLV_VDEV_PARAM_TXBF, + WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE, + WMI_TLV_VDEV_PARAM_DROP_UNENCRY, + WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE, + WMI_TLV_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + WMI_TLV_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + WMI_TLV_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + WMI_TLV_VDEV_PARAM_EARLY_RX_SLOP_STEP, + WMI_TLV_VDEV_PARAM_EARLY_RX_INIT_SLOP, + WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + WMI_TLV_VDEV_PARAM_TX_PWRLIMIT, + WMI_TLV_VDEV_PARAM_SNR_NUM_FOR_CAL, + WMI_TLV_VDEV_PARAM_ROAM_FW_OFFLOAD, + WMI_TLV_VDEV_PARAM_ENABLE_RMC, + WMI_TLV_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS, + WMI_TLV_VDEV_PARAM_MAX_RATE, + WMI_TLV_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE, + WMI_TLV_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR, + WMI_TLV_VDEV_PARAM_EBT_RESYNC_TIMEOUT, + WMI_TLV_VDEV_PARAM_AGGR_TRIG_EVENT_ENABLE, + WMI_TLV_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED, + WMI_TLV_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED, + WMI_TLV_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED, + WMI_TLV_VDEV_PARAM_INACTIVITY_CNT, + WMI_TLV_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS, + WMI_TLV_VDEV_PARAM_DTIM_POLICY, + WMI_TLV_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS, + WMI_TLV_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, +}; + +enum wmi_tlv_tag { + WMI_TLV_TAG_LAST_RESERVED = 15, + + WMI_TLV_TAG_FIRST_ARRAY_ENUM, + WMI_TLV_TAG_ARRAY_UINT32 = WMI_TLV_TAG_FIRST_ARRAY_ENUM, + WMI_TLV_TAG_ARRAY_BYTE, + WMI_TLV_TAG_ARRAY_STRUCT, + WMI_TLV_TAG_ARRAY_FIXED_STRUCT, + WMI_TLV_TAG_LAST_ARRAY_ENUM = 31, + + WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT, + WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES, + WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ, + WMI_TLV_TAG_STRUCT_READY_EVENT, + WMI_TLV_TAG_STRUCT_SCAN_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_TPC_CONFIG_EVENT, + WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT, + WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR, + WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_STOPPED_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT, + WMI_TLV_TAG_STRUCT_MGMT_RX_HDR, + WMI_TLV_TAG_STRUCT_TBTT_OFFSET_EVENT, + WMI_TLV_TAG_STRUCT_TX_DELBA_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_TX_ADDBA_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_EVENT, + WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO, + WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO_SECTION_BITMAP, + WMI_TLV_TAG_STRUCT_RTT_EVENT_HEADER, + WMI_TLV_TAG_STRUCT_RTT_ERROR_REPORT_EVENT, + WMI_TLV_TAG_STRUCT_RTT_MEAS_EVENT, + WMI_TLV_TAG_STRUCT_ECHO_EVENT, + WMI_TLV_TAG_STRUCT_FTM_INTG_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_EVENT, + WMI_TLV_TAG_STRUCT_GPIO_INPUT_EVENT, + WMI_TLV_TAG_STRUCT_CSA_EVENT, + WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_IGTK_INFO, + WMI_TLV_TAG_STRUCT_DCS_INTERFERENCE_EVENT, + WMI_TLV_TAG_STRUCT_ATH_DCS_CW_INT, + WMI_TLV_TAG_STRUCT_ATH_DCS_WLAN_INT_STAT, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_CTX_T, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_T, + WMI_TLV_TAG_STRUCT_PDEV_QVIT_EVENT, + WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT, + WMI_TLV_TAG_STRUCT_TIM_INFO, + WMI_TLV_TAG_STRUCT_P2P_NOA_INFO, + WMI_TLV_TAG_STRUCT_STATS_EVENT, + WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGES_EVENT, + WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGE_DESC, + WMI_TLV_TAG_STRUCT_GTK_REKEY_FAIL_EVENT, + WMI_TLV_TAG_STRUCT_INIT_CMD, + WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG, + WMI_TLV_TAG_STRUCT_WLAN_HOST_MEMORY_CHUNK, + WMI_TLV_TAG_STRUCT_START_SCAN_CMD, + WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD, + WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD, + WMI_TLV_TAG_STRUCT_CHANNEL, + WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_WMM_PARAMS, + WMI_TLV_TAG_STRUCT_PDEV_SET_QUIET_CMD, + WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD, + WMI_TLV_TAG_STRUCT_P2P_NOA_DESCRIPTOR, + WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE, + WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_VDEV_UP_CMD, + WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD, + WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD, + WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD, + WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD, + WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD, + WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD, + WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD, + WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD, + WMI_TLV_TAG_STRUCT_VHT_RATE_SET, + WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD, + WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD, + WMI_TLV_TAG_STRUCT_BCN_PRB_INFO, + WMI_TLV_TAG_STRUCT_PEER_TID_ADDBA_CMD, + WMI_TLV_TAG_STRUCT_PEER_TID_DELBA_CMD, + WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD, + WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD, + WMI_TLV_TAG_STRUCT_STA_DTIM_PS_METHOD_CMD, + WMI_TLV_TAG_STRUCT_ROAM_SCAN_MODE, + WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_THRESHOLD, + WMI_TLV_TAG_STRUCT_ROAM_SCAN_PERIOD, + WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD, + WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD, + WMI_TLV_TAG_STRUCT_ADD_BCN_FILTER_CMD, + WMI_TLV_TAG_STRUCT_RMV_BCN_FILTER_CMD, + WMI_TLV_TAG_STRUCT_WOW_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_WOW_HOSTWAKEUP_FROM_SLEEP_CMD, + WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD, + WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM, + WMI_TLV_TAG_STRUCT_SET_ARP_NS_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_ARP_OFFLOAD_TUPLE, + WMI_TLV_TAG_STRUCT_NS_OFFLOAD_TUPLE, + WMI_TLV_TAG_STRUCT_FTM_INTG_CMD, + WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD, + WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE, + WMI_TLV_TAG_STRUCT_P2P_SET_VENDOR_IE_DATA_CMD, + WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD, + WMI_TLV_TAG_STRUCT_PEER_RATE_RETRY_SCHED_CMD, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_TRIGGER_CMD, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_SET_HIST_INTVL_CMD, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_GET_PROF_DATA_CMD, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_ENABLE_PROFILE_ID_CMD, + WMI_TLV_TAG_STRUCT_WOW_DEL_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_WOW_ADD_DEL_EVT_CMD, + WMI_TLV_TAG_STRUCT_RTT_MEASREQ_HEAD, + WMI_TLV_TAG_STRUCT_RTT_MEASREQ_BODY, + WMI_TLV_TAG_STRUCT_RTT_TSF_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_CONFIGURE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD, + WMI_TLV_TAG_STRUCT_NLO_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_NLO_CONFIGURED_PARAMETERS, + WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_CHANSWITCH_CMD, + WMI_TLV_TAG_STRUCT_CHATTER_SET_MODE_CMD, + WMI_TLV_TAG_STRUCT_ECHO_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SET_KEEPALIVE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_CMD, + WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD, + WMI_TLV_TAG_STRUCT_GPIO_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_GPIO_OUTPUT_CMD, + WMI_TLV_TAG_STRUCT_PEER_ADD_WDS_ENTRY_CMD, + WMI_TLV_TAG_STRUCT_PEER_REMOVE_WDS_ENTRY_CMD, + WMI_TLV_TAG_STRUCT_BCN_TX_HDR, + WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD, + WMI_TLV_TAG_STRUCT_MGMT_TX_HDR, + WMI_TLV_TAG_STRUCT_ADDBA_CLEAR_RESP_CMD, + WMI_TLV_TAG_STRUCT_ADDBA_SEND_CMD, + WMI_TLV_TAG_STRUCT_DELBA_SEND_CMD, + WMI_TLV_TAG_STRUCT_ADDBA_SETRESPONSE_CMD, + WMI_TLV_TAG_STRUCT_SEND_SINGLEAMSDU_CMD, + WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_HT_IE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_VHT_IE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_DSCP_TID_MAP_CMD, + WMI_TLV_TAG_STRUCT_PDEV_GREEN_AP_PS_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_GET_TPC_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_BASE_MACADDR_CMD, + WMI_TLV_TAG_STRUCT_PEER_MCAST_GROUP_CMD, + WMI_TLV_TAG_STRUCT_ROAM_AP_PROFILE, + WMI_TLV_TAG_STRUCT_AP_PROFILE, + WMI_TLV_TAG_STRUCT_SCAN_SCH_PRIORITY_TABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_DFS_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_DFS_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_WOW_ADD_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_WOW_BITMAP_PATTERN_T, + WMI_TLV_TAG_STRUCT_WOW_IPV4_SYNC_PATTERN_T, + WMI_TLV_TAG_STRUCT_WOW_IPV6_SYNC_PATTERN_T, + WMI_TLV_TAG_STRUCT_WOW_MAGIC_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_SCAN_UPDATE_REQUEST_CMD, + WMI_TLV_TAG_STRUCT_CHATTER_PKT_COALESCING_FILTER, + WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_ADD_FILTER_CMD, + WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_DELETE_FILTER_CMD, + WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_QUERY_CMD, + WMI_TLV_TAG_STRUCT_TXBF_CMD, + WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_NLO_EVENT, + WMI_TLV_TAG_STRUCT_CHATTER_QUERY_REPLY_EVENT, + WMI_TLV_TAG_STRUCT_UPLOAD_H_HDR, + WMI_TLV_TAG_STRUCT_CAPTURE_H_EVENT_HDR, + WMI_TLV_TAG_STRUCT_VDEV_WNM_SLEEPMODE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD, + WMI_TLV_TAG_STRUCT_VDEV_WMM_ADDTS_CMD, + WMI_TLV_TAG_STRUCT_VDEV_WMM_DELTS_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD, + WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD, + WMI_TLV_TAG_STRUCT_TDLS_PEER_EVENT, + WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES, + WMI_TLV_TAG_STRUCT_VDEV_MCC_SET_TBTT_MODE_CMD, + WMI_TLV_TAG_STRUCT_ROAM_CHAN_LIST, + WMI_TLV_TAG_STRUCT_VDEV_MCC_BCN_INTVL_CHANGE_EVENT, + WMI_TLV_TAG_STRUCT_RESMGR_ADAPTIVE_OCS_CMD, + WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_TIME_QUOTA_CMD, + WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_LATENCY_CMD, + WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD, + WMI_TLV_TAG_STRUCT_BA_RSP_SSN_EVENT, + WMI_TLV_TAG_STRUCT_STA_SMPS_FORCE_MODE_CMD, + WMI_TLV_TAG_STRUCT_SET_MCASTBCAST_FILTER_CMD, + WMI_TLV_TAG_STRUCT_P2P_SET_OPPPS_CMD, + WMI_TLV_TAG_STRUCT_P2P_SET_NOA_CMD, + WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD_SUB_STRUCT_PARAM, + WMI_TLV_TAG_STRUCT_BA_REQ_SSN_EVENT_SUB_STRUCT_PARAM, + WMI_TLV_TAG_STRUCT_STA_SMPS_PARAM_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SET_GTX_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_MCC_SCHED_TRAFFIC_STATS_CMD, + WMI_TLV_TAG_STRUCT_MCC_SCHED_STA_TRAFFIC_STATS, + WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_P2P_NOA_EVENT, + WMI_TLV_TAG_STRUCT_HB_SET_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_HB_SET_TCP_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_HB_SET_TCP_PKT_FILTER_CMD, + WMI_TLV_TAG_STRUCT_HB_SET_UDP_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_HB_SET_UDP_PKT_FILTER_CMD, + WMI_TLV_TAG_STRUCT_HB_IND_EVENT, + WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT, + WMI_TLV_TAG_STRUCT_RFKILL_EVENT, + WMI_TLV_TAG_STRUCT_DFS_RADAR_EVENT, + WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_ENA_CMD, + WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_DIS_CMD, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_SCAN_LIST, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_NETWORK_INFO, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_TRIGGER_RESULT_CMD, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLED_EVENT, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_START_CMD, + WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_STOP_CMD, + WMI_TLV_TAG_STRUCT_THERMAL_MGMT_CMD, + WMI_TLV_TAG_STRUCT_THERMAL_MGMT_EVENT, + WMI_TLV_TAG_STRUCT_PEER_INFO_REQ_CMD, + WMI_TLV_TAG_STRUCT_PEER_INFO_EVENT, + WMI_TLV_TAG_STRUCT_PEER_INFO, + WMI_TLV_TAG_STRUCT_PEER_TX_FAIL_CNT_THR_EVENT, + WMI_TLV_TAG_STRUCT_RMC_SET_MODE_CMD, + WMI_TLV_TAG_STRUCT_RMC_SET_ACTION_PERIOD_CMD, + WMI_TLV_TAG_STRUCT_RMC_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_SET_MODE_CMD, + WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_PLUMB_ROUTING_TABLE_CMD, + WMI_TLV_TAG_STRUCT_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_NAN_CMD_PARAM, + WMI_TLV_TAG_STRUCT_NAN_EVENT_HDR, + WMI_TLV_TAG_STRUCT_PDEV_L1SS_TRACK_EVENT, + WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT, + WMI_TLV_TAG_STRUCT_MODEM_POWER_STATE_CMD_PARAM, + WMI_TLV_TAG_STRUCT_PEER_GET_ESTIMATED_LINKSPEED_CMD, + WMI_TLV_TAG_STRUCT_PEER_ESTIMATED_LINKSPEED_EVENT, + WMI_TLV_TAG_STRUCT_AGGR_STATE_TRIG_EVENT, + WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_ROUTING_TABLE_ENTRY, + WMI_TLV_TAG_STRUCT_ROAM_SCAN_CMD, + WMI_TLV_TAG_STRUCT_REQ_STATS_EXT_CMD, + WMI_TLV_TAG_STRUCT_STATS_EXT_EVENT, + WMI_TLV_TAG_STRUCT_OBSS_SCAN_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_OBSS_SCAN_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_OFFLOAD_PRB_RSP_TX_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_SET_LED_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_CFG_CMD, + WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_EVENT, + WMI_TLV_TAG_STRUCT_UPDATE_WHAL_MIB_STATS_EVENT, + WMI_TLV_TAG_STRUCT_CHAN_AVOID_UPDATE_CMD_PARAM, + WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_PKT_PATTERN_T, + WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_TMR_PATTERN_T, + WMI_TLV_TAG_STRUCT_WOW_IOAC_ADD_KEEPALIVE_CMD, + WMI_TLV_TAG_STRUCT_WOW_IOAC_DEL_KEEPALIVE_CMD, + WMI_TLV_TAG_STRUCT_WOW_IOAC_KEEPALIVE_T, + WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_ADD_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_DEL_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_START_LINK_STATS_CMD, + WMI_TLV_TAG_STRUCT_CLEAR_LINK_STATS_CMD, + WMI_TLV_TAG_STRUCT_REQUEST_LINK_STATS_CMD, + WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS_EVENT, + WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS_EVENT, + WMI_TLV_TAG_STRUCT_PEER_STATS_EVENT, + WMI_TLV_TAG_STRUCT_CHANNEL_STATS, + WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS, + WMI_TLV_TAG_STRUCT_RATE_STATS, + WMI_TLV_TAG_STRUCT_PEER_LINK_STATS, + WMI_TLV_TAG_STRUCT_WMM_AC_STATS, + WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS, + WMI_TLV_TAG_STRUCT_LPI_MGMT_SNOOPING_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_LPI_START_SCAN_CMD, + WMI_TLV_TAG_STRUCT_LPI_STOP_SCAN_CMD, + WMI_TLV_TAG_STRUCT_LPI_RESULT_EVENT, + WMI_TLV_TAG_STRUCT_PEER_STATE_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CHANNEL_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_START_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_STOP_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_BSSID_PARAM_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CACHED_RESULTS_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_SET_CAPABILITIES_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CAPABILITIES_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_OPERATION_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_START_STOP_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_TABLE_USAGE_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_DESCRIPTOR_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_RSSI_INFO_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_CACHED_RESULTS_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULTS_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULT_BSSID_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MATCH_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_CAPABILITIES_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_CACHE_CAPABILITIES_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_MONITOR_CAPABILITIES_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MONITOR_CAPABILITIES_EVENT, + WMI_TLV_TAG_STRUCT_D0_WOW_ENABLE_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_D0_WOW_DISABLE_ACK_EVENT, + WMI_TLV_TAG_STRUCT_UNIT_TEST_CMD, + WMI_TLV_TAG_STRUCT_ROAM_OFFLOAD_TLV_PARAM, + WMI_TLV_TAG_STRUCT_ROAM_11I_OFFLOAD_TLV_PARAM, + WMI_TLV_TAG_STRUCT_ROAM_11R_OFFLOAD_TLV_PARAM, + WMI_TLV_TAG_STRUCT_ROAM_ESE_OFFLOAD_TLV_PARAM, + WMI_TLV_TAG_STRUCT_ROAM_SYNCH_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_SYNCH_COMPLETE, + WMI_TLV_TAG_STRUCT_EXTWOW_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE1_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE2_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_LPI_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_LPI_HANDOFF_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_RATE_STATS_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_RATE_HT_INFO, + WMI_TLV_TAG_STRUCT_RIC_REQUEST, + WMI_TLV_TAG_STRUCT_PDEV_GET_TEMPERATURE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_TEMPERATURE_EVENT, + WMI_TLV_TAG_STRUCT_SET_DHCP_SERVER_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_RIC_TSPEC, + WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG, + WMI_TLV_TAG_STRUCT_IPA_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_SCAN_PROB_REQ_OUI_CMD, + WMI_TLV_TAG_STRUCT_KEY_MATERIAL, + WMI_TLV_TAG_STRUCT_TDLS_SET_OFFCHAN_MODE_CMD, + WMI_TLV_TAG_STRUCT_SET_LED_FLASHING_CMD, + WMI_TLV_TAG_STRUCT_MDNS_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_MDNS_SET_FQDN_CMD, + WMI_TLV_TAG_STRUCT_MDNS_SET_RESP_CMD, + WMI_TLV_TAG_STRUCT_MDNS_GET_STATS_CMD, + WMI_TLV_TAG_STRUCT_MDNS_STATS_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_INVOKE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_RESUME_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_SET_ANTENNA_DIVERSITY_CMD, + WMI_TLV_TAG_STRUCT_SAP_OFL_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_SAP_OFL_ADD_STA_EVENT, + WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT, + WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM, + WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR, + + WMI_TLV_TAG_MAX +}; + +enum wmi_tlv_service { + WMI_TLV_SERVICE_BEACON_OFFLOAD = 0, + WMI_TLV_SERVICE_SCAN_OFFLOAD, + WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD, + WMI_TLV_SERVICE_BCN_MISS_OFFLOAD, + WMI_TLV_SERVICE_STA_PWRSAVE, + WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_TLV_SERVICE_AP_UAPSD, + WMI_TLV_SERVICE_AP_DFS, + WMI_TLV_SERVICE_11AC, + WMI_TLV_SERVICE_BLOCKACK, + WMI_TLV_SERVICE_PHYERR, + WMI_TLV_SERVICE_BCN_FILTER, + WMI_TLV_SERVICE_RTT, + WMI_TLV_SERVICE_WOW, + WMI_TLV_SERVICE_RATECTRL_CACHE, + WMI_TLV_SERVICE_IRAM_TIDS, + WMI_TLV_SERVICE_ARPNS_OFFLOAD, + WMI_TLV_SERVICE_NLO, + WMI_TLV_SERVICE_GTK_OFFLOAD, + WMI_TLV_SERVICE_SCAN_SCH, + WMI_TLV_SERVICE_CSA_OFFLOAD, + WMI_TLV_SERVICE_CHATTER, + WMI_TLV_SERVICE_COEX_FREQAVOID, + WMI_TLV_SERVICE_PACKET_POWER_SAVE, + WMI_TLV_SERVICE_FORCE_FW_HANG, + WMI_TLV_SERVICE_GPIO, + WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM, + WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_TLV_SERVICE_STA_KEEP_ALIVE, + WMI_TLV_SERVICE_TX_ENCAP, + WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_TLV_SERVICE_EARLY_RX, + WMI_TLV_SERVICE_STA_SMPS, + WMI_TLV_SERVICE_FWTEST, + WMI_TLV_SERVICE_STA_WMMAC, + WMI_TLV_SERVICE_TDLS, + WMI_TLV_SERVICE_BURST, + WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE, + WMI_TLV_SERVICE_ADAPTIVE_OCS, + WMI_TLV_SERVICE_BA_SSN_SUPPORT, + WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE, + WMI_TLV_SERVICE_WLAN_HB, + WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT, + WMI_TLV_SERVICE_BATCH_SCAN, + WMI_TLV_SERVICE_QPOWER, + WMI_TLV_SERVICE_PLMREQ, + WMI_TLV_SERVICE_THERMAL_MGMT, + WMI_TLV_SERVICE_RMC, + WMI_TLV_SERVICE_MHF_OFFLOAD, + WMI_TLV_SERVICE_COEX_SAR, + WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE, + WMI_TLV_SERVICE_NAN, + WMI_TLV_SERVICE_L1SS_STAT, + WMI_TLV_SERVICE_ESTIMATE_LINKSPEED, + WMI_TLV_SERVICE_OBSS_SCAN, + WMI_TLV_SERVICE_TDLS_OFFCHAN, + WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA, + WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA, + WMI_TLV_SERVICE_IBSS_PWRSAVE, + WMI_TLV_SERVICE_LPASS, + WMI_TLV_SERVICE_EXTSCAN, + WMI_TLV_SERVICE_D0WOW, + WMI_TLV_SERVICE_HSOFFLOAD, + WMI_TLV_SERVICE_ROAM_HO_OFFLOAD, + WMI_TLV_SERVICE_RX_FULL_REORDER, + WMI_TLV_SERVICE_DHCP_OFFLOAD, + WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, + WMI_TLV_SERVICE_MDNS_OFFLOAD, + WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD, +}; + +#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ + ((svc_id) < (len) && \ + __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ + BIT((svc_id)%(sizeof(u32)))) + +#define SVCMAP(x, y, len) \ + do { \ + if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \ + __set_bit(y, out); \ + } while (0) + +static inline void +wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) +{ + SVCMAP(WMI_TLV_SERVICE_BEACON_OFFLOAD, + WMI_SERVICE_BEACON_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_SCAN_OFFLOAD, + WMI_SERVICE_SCAN_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD, + WMI_SERVICE_ROAM_SCAN_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_BCN_MISS_OFFLOAD, + WMI_SERVICE_BCN_MISS_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_STA_PWRSAVE, + WMI_SERVICE_STA_PWRSAVE, len); + SVCMAP(WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); + SVCMAP(WMI_TLV_SERVICE_AP_UAPSD, + WMI_SERVICE_AP_UAPSD, len); + SVCMAP(WMI_TLV_SERVICE_AP_DFS, + WMI_SERVICE_AP_DFS, len); + SVCMAP(WMI_TLV_SERVICE_11AC, + WMI_SERVICE_11AC, len); + SVCMAP(WMI_TLV_SERVICE_BLOCKACK, + WMI_SERVICE_BLOCKACK, len); + SVCMAP(WMI_TLV_SERVICE_PHYERR, + WMI_SERVICE_PHYERR, len); + SVCMAP(WMI_TLV_SERVICE_BCN_FILTER, + WMI_SERVICE_BCN_FILTER, len); + SVCMAP(WMI_TLV_SERVICE_RTT, + WMI_SERVICE_RTT, len); + SVCMAP(WMI_TLV_SERVICE_WOW, + WMI_SERVICE_WOW, len); + SVCMAP(WMI_TLV_SERVICE_RATECTRL_CACHE, + WMI_SERVICE_RATECTRL_CACHE, len); + SVCMAP(WMI_TLV_SERVICE_IRAM_TIDS, + WMI_SERVICE_IRAM_TIDS, len); + SVCMAP(WMI_TLV_SERVICE_ARPNS_OFFLOAD, + WMI_SERVICE_ARPNS_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_NLO, + WMI_SERVICE_NLO, len); + SVCMAP(WMI_TLV_SERVICE_GTK_OFFLOAD, + WMI_SERVICE_GTK_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_SCAN_SCH, + WMI_SERVICE_SCAN_SCH, len); + SVCMAP(WMI_TLV_SERVICE_CSA_OFFLOAD, + WMI_SERVICE_CSA_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_CHATTER, + WMI_SERVICE_CHATTER, len); + SVCMAP(WMI_TLV_SERVICE_COEX_FREQAVOID, + WMI_SERVICE_COEX_FREQAVOID, len); + SVCMAP(WMI_TLV_SERVICE_PACKET_POWER_SAVE, + WMI_SERVICE_PACKET_POWER_SAVE, len); + SVCMAP(WMI_TLV_SERVICE_FORCE_FW_HANG, + WMI_SERVICE_FORCE_FW_HANG, len); + SVCMAP(WMI_TLV_SERVICE_GPIO, + WMI_SERVICE_GPIO, len); + SVCMAP(WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM, + WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len); + SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len); + SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len); + SVCMAP(WMI_TLV_SERVICE_STA_KEEP_ALIVE, + WMI_SERVICE_STA_KEEP_ALIVE, len); + SVCMAP(WMI_TLV_SERVICE_TX_ENCAP, + WMI_SERVICE_TX_ENCAP, len); + SVCMAP(WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, len); + SVCMAP(WMI_TLV_SERVICE_EARLY_RX, + WMI_SERVICE_EARLY_RX, len); + SVCMAP(WMI_TLV_SERVICE_STA_SMPS, + WMI_SERVICE_STA_SMPS, len); + SVCMAP(WMI_TLV_SERVICE_FWTEST, + WMI_SERVICE_FWTEST, len); + SVCMAP(WMI_TLV_SERVICE_STA_WMMAC, + WMI_SERVICE_STA_WMMAC, len); + SVCMAP(WMI_TLV_SERVICE_TDLS, + WMI_SERVICE_TDLS, len); + SVCMAP(WMI_TLV_SERVICE_BURST, + WMI_SERVICE_BURST, len); + SVCMAP(WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE, + WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE, len); + SVCMAP(WMI_TLV_SERVICE_ADAPTIVE_OCS, + WMI_SERVICE_ADAPTIVE_OCS, len); + SVCMAP(WMI_TLV_SERVICE_BA_SSN_SUPPORT, + WMI_SERVICE_BA_SSN_SUPPORT, len); + SVCMAP(WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE, + WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE, len); + SVCMAP(WMI_TLV_SERVICE_WLAN_HB, + WMI_SERVICE_WLAN_HB, len); + SVCMAP(WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT, + WMI_SERVICE_LTE_ANT_SHARE_SUPPORT, len); + SVCMAP(WMI_TLV_SERVICE_BATCH_SCAN, + WMI_SERVICE_BATCH_SCAN, len); + SVCMAP(WMI_TLV_SERVICE_QPOWER, + WMI_SERVICE_QPOWER, len); + SVCMAP(WMI_TLV_SERVICE_PLMREQ, + WMI_SERVICE_PLMREQ, len); + SVCMAP(WMI_TLV_SERVICE_THERMAL_MGMT, + WMI_SERVICE_THERMAL_MGMT, len); + SVCMAP(WMI_TLV_SERVICE_RMC, + WMI_SERVICE_RMC, len); + SVCMAP(WMI_TLV_SERVICE_MHF_OFFLOAD, + WMI_SERVICE_MHF_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_COEX_SAR, + WMI_SERVICE_COEX_SAR, len); + SVCMAP(WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE, + WMI_SERVICE_BCN_TXRATE_OVERRIDE, len); + SVCMAP(WMI_TLV_SERVICE_NAN, + WMI_SERVICE_NAN, len); + SVCMAP(WMI_TLV_SERVICE_L1SS_STAT, + WMI_SERVICE_L1SS_STAT, len); + SVCMAP(WMI_TLV_SERVICE_ESTIMATE_LINKSPEED, + WMI_SERVICE_ESTIMATE_LINKSPEED, len); + SVCMAP(WMI_TLV_SERVICE_OBSS_SCAN, + WMI_SERVICE_OBSS_SCAN, len); + SVCMAP(WMI_TLV_SERVICE_TDLS_OFFCHAN, + WMI_SERVICE_TDLS_OFFCHAN, len); + SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA, + WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, len); + SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA, + WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, len); + SVCMAP(WMI_TLV_SERVICE_IBSS_PWRSAVE, + WMI_SERVICE_IBSS_PWRSAVE, len); + SVCMAP(WMI_TLV_SERVICE_LPASS, + WMI_SERVICE_LPASS, len); + SVCMAP(WMI_TLV_SERVICE_EXTSCAN, + WMI_SERVICE_EXTSCAN, len); + SVCMAP(WMI_TLV_SERVICE_D0WOW, + WMI_SERVICE_D0WOW, len); + SVCMAP(WMI_TLV_SERVICE_HSOFFLOAD, + WMI_SERVICE_HSOFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_ROAM_HO_OFFLOAD, + WMI_SERVICE_ROAM_HO_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_RX_FULL_REORDER, + WMI_SERVICE_RX_FULL_REORDER, len); + SVCMAP(WMI_TLV_SERVICE_DHCP_OFFLOAD, + WMI_SERVICE_DHCP_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, + WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, len); + SVCMAP(WMI_TLV_SERVICE_MDNS_OFFLOAD, + WMI_SERVICE_MDNS_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD, + WMI_SERVICE_SAP_AUTH_OFFLOAD, len); +} + +#undef SVCMAP + +struct wmi_tlv { + __le16 len; + __le16 tag; + u8 value[0]; +} __packed; + +#define WMI_TLV_MGMT_RX_NUM_RSSI 4 + +struct wmi_tlv_mgmt_rx_ev { + __le32 channel; + __le32 snr; + __le32 rate; + __le32 phy_mode; + __le32 buf_len; + __le32 status; + __le32 rssi[WMI_TLV_MGMT_RX_NUM_RSSI]; +} __packed; + +struct wmi_tlv_abi_version { + __le32 abi_ver0; + __le32 abi_ver1; + __le32 abi_ver_ns0; + __le32 abi_ver_ns1; + __le32 abi_ver_ns2; + __le32 abi_ver_ns3; +} __packed; + +enum wmi_tlv_hw_bd_id { + WMI_TLV_HW_BD_LEGACY = 0, + WMI_TLV_HW_BD_QCA6174 = 1, + WMI_TLV_HW_BD_QCA2582 = 2, +}; + +struct wmi_tlv_hw_bd_info { + u8 rev; + u8 project_id; + u8 custom_id; + u8 reference_design_id; +} __packed; + +struct wmi_tlv_svc_rdy_ev { + __le32 fw_build_vers; + struct wmi_tlv_abi_version abi; + __le32 phy_capability; + __le32 max_frag_entry; + __le32 num_rf_chains; + __le32 ht_cap_info; + __le32 vht_cap_info; + __le32 vht_supp_mcs; + __le32 hw_min_tx_power; + __le32 hw_max_tx_power; + __le32 sys_cap_info; + __le32 min_pkt_size_enable; + __le32 max_bcn_ie_size; + __le32 num_mem_reqs; + __le32 max_num_scan_chans; + __le32 hw_bd_id; /* 0 means hw_bd_info is invalid */ + struct wmi_tlv_hw_bd_info hw_bd_info[5]; +} __packed; + +struct wmi_tlv_rdy_ev { + struct wmi_tlv_abi_version abi; + struct wmi_mac_addr mac_addr; + __le32 status; +} __packed; + +struct wmi_tlv_resource_config { + __le32 num_vdevs; + __le32 num_peers; + __le32 num_offload_peers; + __le32 num_offload_reorder_bufs; + __le32 num_peer_keys; + __le32 num_tids; + __le32 ast_skid_limit; + __le32 tx_chain_mask; + __le32 rx_chain_mask; + __le32 rx_timeout_pri[4]; + __le32 rx_decap_mode; + __le32 scan_max_pending_reqs; + __le32 bmiss_offload_max_vdev; + __le32 roam_offload_max_vdev; + __le32 roam_offload_max_ap_profiles; + __le32 num_mcast_groups; + __le32 num_mcast_table_elems; + __le32 mcast2ucast_mode; + __le32 tx_dbg_log_size; + __le32 num_wds_entries; + __le32 dma_burst_size; + __le32 mac_aggr_delim; + __le32 rx_skip_defrag_timeout_dup_detection_check; + __le32 vow_config; + __le32 gtk_offload_max_vdev; + __le32 num_msdu_desc; + __le32 max_frag_entries; + __le32 num_tdls_vdevs; + __le32 num_tdls_conn_table_entries; + __le32 beacon_tx_offload_max_vdev; + __le32 num_multicast_filter_entries; + __le32 num_wow_filters; + __le32 num_keep_alive_pattern; + __le32 keep_alive_pattern_size; + __le32 max_tdls_concurrent_sleep_sta; + __le32 max_tdls_concurrent_buffer_sta; +} __packed; + +struct wmi_tlv_init_cmd { + struct wmi_tlv_abi_version abi; + __le32 num_host_mem_chunks; +} __packed; + +struct wmi_tlv_pdev_set_param_cmd { + __le32 pdev_id; /* not used yet */ + __le32 param_id; + __le32 param_value; +} __packed; + +struct wmi_tlv_pdev_set_rd_cmd { + __le32 pdev_id; /* not used yet */ + __le32 regd; + __le32 regd_2ghz; + __le32 regd_5ghz; + __le32 conform_limit_2ghz; + __le32 conform_limit_5ghz; +} __packed; + +struct wmi_tlv_scan_chan_list_cmd { + __le32 num_scan_chans; +} __packed; + +struct wmi_tlv_start_scan_cmd { + struct wmi_start_scan_common common; + __le32 burst_duration_ms; + __le32 num_channels; + __le32 num_bssids; + __le32 num_ssids; + __le32 ie_len; + __le32 num_probes; +} __packed; + +struct wmi_tlv_vdev_start_cmd { + __le32 vdev_id; + __le32 requestor_id; + __le32 bcn_intval; + __le32 dtim_period; + __le32 flags; + struct wmi_ssid ssid; + __le32 bcn_tx_rate; + __le32 bcn_tx_power; + __le32 num_noa_descr; + __le32 disable_hw_ack; +} __packed; + +enum { + WMI_TLV_PEER_TYPE_DEFAULT = 0, /* generic / non-BSS / self-peer */ + WMI_TLV_PEER_TYPE_BSS = 1, + WMI_TLV_PEER_TYPE_TDLS = 2, + WMI_TLV_PEER_TYPE_HOST_MAX = 127, + WMI_TLV_PEER_TYPE_ROAMOFFLOAD_TMP = 128, +}; + +struct wmi_tlv_peer_create_cmd { + __le32 vdev_id; + struct wmi_mac_addr peer_addr; + __le32 peer_type; +} __packed; + +struct wmi_tlv_peer_assoc_cmd { + struct wmi_mac_addr mac_addr; + __le32 vdev_id; + __le32 new_assoc; + __le32 assoc_id; + __le32 flags; + __le32 caps; + __le32 listen_intval; + __le32 ht_caps; + __le32 max_mpdu; + __le32 mpdu_density; + __le32 rate_caps; + __le32 nss; + __le32 vht_caps; + __le32 phy_mode; + __le32 ht_info[2]; + __le32 num_legacy_rates; + __le32 num_ht_rates; +} __packed; + +struct wmi_tlv_pdev_suspend { + __le32 pdev_id; /* not used yet */ + __le32 opt; +} __packed; + +struct wmi_tlv_pdev_set_wmm_cmd { + __le32 pdev_id; /* not used yet */ + __le32 dg_type; /* no idea.. */ +} __packed; + +struct wmi_tlv_phyerr_ev { + __le32 num_phyerrs; + __le32 tsf_l32; + __le32 tsf_u32; + __le32 buf_len; +} __packed; + +enum wmi_tlv_dbglog_param { + WMI_TLV_DBGLOG_PARAM_LOG_LEVEL = 1, + WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE, + WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE, + WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE_BITMAP, + WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE_BITMAP, +}; + +enum wmi_tlv_dbglog_log_level { + WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE = 0, + WMI_TLV_DBGLOG_LOG_LEVEL_INFO, + WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_1, + WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_2, + WMI_TLV_DBGLOG_LOG_LEVEL_WARN, + WMI_TLV_DBGLOG_LOG_LEVEL_ERR, +}; + +#define WMI_TLV_DBGLOG_BITMAP_MAX_IDS 512 +#define WMI_TLV_DBGLOG_BITMAP_MAX_WORDS (WMI_TLV_DBGLOG_BITMAP_MAX_IDS / \ + sizeof(__le32)) +#define WMI_TLV_DBGLOG_ALL_MODULES 0xffff +#define WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(module_id, log_level) \ + (((module_id << 16) & 0xffff0000) | \ + ((log_level << 0) & 0x000000ff)) + +struct wmi_tlv_dbglog_cmd { + __le32 param; + __le32 value; +} __packed; + +struct wmi_tlv_resume_cmd { + __le32 reserved; +} __packed; + +struct wmi_tlv_req_stats_cmd { + __le32 stats_id; /* wmi_stats_id */ + __le32 vdev_id; + struct wmi_mac_addr peer_macaddr; +} __packed; + +struct wmi_tlv_vdev_stats { + __le32 vdev_id; + __le32 beacon_snr; + __le32 data_snr; + __le32 num_tx_frames[4]; /* per-AC */ + __le32 num_rx_frames; + __le32 num_tx_frames_retries[4]; + __le32 num_tx_frames_failures[4]; + __le32 num_rts_fail; + __le32 num_rts_success; + __le32 num_rx_err; + __le32 num_rx_discard; + __le32 num_tx_not_acked; + __le32 tx_rate_history[10]; + __le32 beacon_rssi_history[10]; +} __packed; + +struct wmi_tlv_pktlog_enable { + __le32 reserved; + __le32 filter; +} __packed; + +struct wmi_tlv_pktlog_disable { + __le32 reserved; +} __packed; + +void ath10k_wmi_tlv_attach(struct ath10k *ar); + +#endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index cc0c9e0ff457..69f79354f615 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -22,6 +22,7 @@ #include "htc.h" #include "debug.h" #include "wmi.h" +#include "wmi-tlv.h" #include "mac.h" #include "testmode.h" #include "wmi-ops.h" @@ -2735,13 +2736,14 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) } ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n", + "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n", __le32_to_cpu(arg.min_tx_power), __le32_to_cpu(arg.max_tx_power), __le32_to_cpu(arg.ht_cap), __le32_to_cpu(arg.vht_cap), __le32_to_cpu(arg.sw_ver0), __le32_to_cpu(arg.sw_ver1), + __le32_to_cpu(arg.fw_build), __le32_to_cpu(arg.phy_capab), __le32_to_cpu(arg.num_rf_chains), __le32_to_cpu(arg.eeprom_rd), @@ -4762,6 +4764,9 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.vdev_param = &wmi_vdev_param_map; ar->wmi.pdev_param = &wmi_pdev_param_map; break; + case ATH10K_FW_WMI_OP_VERSION_TLV: + ath10k_wmi_tlv_attach(ar); + break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: ath10k_err(ar, "unsupported WMI op version: %d\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 032a8bdb0420..7d091a74d3f3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -109,6 +109,45 @@ enum wmi_service { WMI_SERVICE_BURST, WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_SERVICE_ROAM_SCAN_OFFLOAD, + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_SERVICE_EARLY_RX, + WMI_SERVICE_STA_SMPS, + WMI_SERVICE_FWTEST, + WMI_SERVICE_STA_WMMAC, + WMI_SERVICE_TDLS, + WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE, + WMI_SERVICE_ADAPTIVE_OCS, + WMI_SERVICE_BA_SSN_SUPPORT, + WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE, + WMI_SERVICE_WLAN_HB, + WMI_SERVICE_LTE_ANT_SHARE_SUPPORT, + WMI_SERVICE_BATCH_SCAN, + WMI_SERVICE_QPOWER, + WMI_SERVICE_PLMREQ, + WMI_SERVICE_THERMAL_MGMT, + WMI_SERVICE_RMC, + WMI_SERVICE_MHF_OFFLOAD, + WMI_SERVICE_COEX_SAR, + WMI_SERVICE_BCN_TXRATE_OVERRIDE, + WMI_SERVICE_NAN, + WMI_SERVICE_L1SS_STAT, + WMI_SERVICE_ESTIMATE_LINKSPEED, + WMI_SERVICE_OBSS_SCAN, + WMI_SERVICE_TDLS_OFFCHAN, + WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, + WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, + WMI_SERVICE_IBSS_PWRSAVE, + WMI_SERVICE_LPASS, + WMI_SERVICE_EXTSCAN, + WMI_SERVICE_D0WOW, + WMI_SERVICE_HSOFFLOAD, + WMI_SERVICE_ROAM_HO_OFFLOAD, + WMI_SERVICE_RX_FULL_REORDER, + WMI_SERVICE_DHCP_OFFLOAD, + WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, + WMI_SERVICE_MDNS_OFFLOAD, + WMI_SERVICE_SAP_AUTH_OFFLOAD, /* keep last */ WMI_SERVICE_MAX, @@ -215,6 +254,45 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_BURST); SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT); SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT); + SVCSTR(WMI_SERVICE_ROAM_SCAN_OFFLOAD); + SVCSTR(WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC); + SVCSTR(WMI_SERVICE_EARLY_RX); + SVCSTR(WMI_SERVICE_STA_SMPS); + SVCSTR(WMI_SERVICE_FWTEST); + SVCSTR(WMI_SERVICE_STA_WMMAC); + SVCSTR(WMI_SERVICE_TDLS); + SVCSTR(WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE); + SVCSTR(WMI_SERVICE_ADAPTIVE_OCS); + SVCSTR(WMI_SERVICE_BA_SSN_SUPPORT); + SVCSTR(WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE); + SVCSTR(WMI_SERVICE_WLAN_HB); + SVCSTR(WMI_SERVICE_LTE_ANT_SHARE_SUPPORT); + SVCSTR(WMI_SERVICE_BATCH_SCAN); + SVCSTR(WMI_SERVICE_QPOWER); + SVCSTR(WMI_SERVICE_PLMREQ); + SVCSTR(WMI_SERVICE_THERMAL_MGMT); + SVCSTR(WMI_SERVICE_RMC); + SVCSTR(WMI_SERVICE_MHF_OFFLOAD); + SVCSTR(WMI_SERVICE_COEX_SAR); + SVCSTR(WMI_SERVICE_BCN_TXRATE_OVERRIDE); + SVCSTR(WMI_SERVICE_NAN); + SVCSTR(WMI_SERVICE_L1SS_STAT); + SVCSTR(WMI_SERVICE_ESTIMATE_LINKSPEED); + SVCSTR(WMI_SERVICE_OBSS_SCAN); + SVCSTR(WMI_SERVICE_TDLS_OFFCHAN); + SVCSTR(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA); + SVCSTR(WMI_SERVICE_TDLS_UAPSD_SLEEP_STA); + SVCSTR(WMI_SERVICE_IBSS_PWRSAVE); + SVCSTR(WMI_SERVICE_LPASS); + SVCSTR(WMI_SERVICE_EXTSCAN); + SVCSTR(WMI_SERVICE_D0WOW); + SVCSTR(WMI_SERVICE_HSOFFLOAD); + SVCSTR(WMI_SERVICE_ROAM_HO_OFFLOAD); + SVCSTR(WMI_SERVICE_RX_FULL_REORDER); + SVCSTR(WMI_SERVICE_DHCP_OFFLOAD); + SVCSTR(WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT); + SVCSTR(WMI_SERVICE_MDNS_OFFLOAD); + SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD); default: return NULL; } @@ -4626,6 +4704,7 @@ struct wmi_svc_rdy_ev_arg { __le32 vht_cap; __le32 sw_ver0; __le32 sw_ver1; + __le32 fw_build; __le32 phy_capab; __le32 num_rf_chains; __le32 eeprom_rd; -- cgit v1.2.1 From b43bf97ef786aed3daae4c63a6abb50ea913802e Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Tue, 2 Dec 2014 13:06:53 +0200 Subject: ath10k: add new pdev parameters for fw 10.2 New pdev paramters have been added to firmware 10.2, hence update wmi interfaces to sync with. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 7d091a74d3f3..4b31da5d3c4c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2793,6 +2793,9 @@ enum wmi_10x_pdev_param { WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE, WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, + WMI_10X_PDEV_PARAM_PEER_STA_PS_STATECHG_ENABLE, + WMI_10X_PDEV_PARAM_RTS_FIXED_RATE, + WMI_10X_PDEV_PARAM_CAL_PERIOD }; struct wmi_pdev_set_param_cmd { -- cgit v1.2.1 From a7bd3e9901634b1185eb91c3f986d64cb3506e19 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Tue, 2 Dec 2014 13:07:14 +0200 Subject: ath10k: add new wmi interface of NF cal period Introduce a new wmi interface controls noise floor (NF) calibration period via debugfs as firmware has introduced it on v10.2. It allows users to modify frequency of NF calibration in millisecond and changes RSSI reporting frequency consequently. Short calibration period will trigger more frequent NF calibration, so that RSSI reported in receive frames is more realistic. Till now calibration was done at 30 seconds. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/debug.c | 80 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 2 + drivers/net/wireless/ath/ath10k/wmi.h | 4 ++ 5 files changed, 88 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 3f15c134b90e..613355cc6895 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -327,6 +327,7 @@ struct ath10k_debug { u32 fw_dbglog_mask; u32 pktlog_filter; u32 reg_addr; + u32 nf_cal_period; u8 htt_max_amsdu; u8 htt_max_ampdu; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index c15b5774dd20..70a9599aeb7a 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1608,6 +1608,73 @@ static const struct file_operations fops_cal_data = { .llseek = default_llseek, }; +static ssize_t ath10k_read_nf_cal_period(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + unsigned int len; + char buf[32]; + + len = scnprintf(buf, sizeof(buf), "%d\n", + ar->debug.nf_cal_period); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath10k_write_nf_cal_period(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + unsigned long period; + int ret; + + ret = kstrtoul_from_user(user_buf, count, 0, &period); + if (ret) + return ret; + + if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX) + return -EINVAL; + + /* there's no way to switch back to the firmware default */ + if (period == 0) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + + ar->debug.nf_cal_period = period; + + if (ar->state != ATH10K_STATE_ON) { + /* firmware is not running, nothing else to do */ + ret = count; + goto exit; + } + + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period, + ar->debug.nf_cal_period); + if (ret) { + ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n", + ret); + goto exit; + } + + ret = count; + +exit: + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static const struct file_operations fops_nf_cal_period = { + .read = ath10k_read_nf_cal_period, + .write = ath10k_write_nf_cal_period, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath10k_debug_start(struct ath10k *ar) { int ret; @@ -1643,6 +1710,16 @@ int ath10k_debug_start(struct ath10k *ar) ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); } + if (ar->debug.nf_cal_period) { + ret = ath10k_wmi_pdev_set_param(ar, + ar->wmi.pdev_param->cal_period, + ar->debug.nf_cal_period); + if (ret) + /* not serious */ + ath10k_warn(ar, "cal period cfg failed from debug start: %d\n", + ret); + } + return ret; } @@ -1881,6 +1958,9 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_cal_data); + debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR, + ar->debug.debugfs_phy, ar, &fops_nf_cal_period); + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { debugfs_create_file("dfs_simulate_radar", S_IWUSR, ar->debug.debugfs_phy, ar, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index b21048c2a52e..1627ec58a229 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2096,6 +2096,7 @@ static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { .fast_channel_reset = WMI_TLV_PDEV_PARAM_UNSUPPORTED, .burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE, + .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 69f79354f615..fa486f69cce7 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -436,6 +436,7 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = { .fast_channel_reset = WMI_PDEV_PARAM_UNSUPPORTED, .burst_dur = WMI_PDEV_PARAM_UNSUPPORTED, .burst_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { @@ -488,6 +489,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET, .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, + .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, }; /* firmware 10.2 specific mappings */ diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4b31da5d3c4c..97f902f03ec5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2583,6 +2583,7 @@ struct wmi_pdev_param_map { u32 fast_channel_reset; u32 burst_dur; u32 burst_enable; + u32 cal_period; }; #define WMI_PDEV_PARAM_UNSUPPORTED 0 @@ -2803,6 +2804,9 @@ struct wmi_pdev_set_param_cmd { __le32 param_value; } __packed; +/* valid period is 1 ~ 60000ms, unit in millisecond */ +#define WMI_PDEV_PARAM_CAL_PERIOD_MAX 60000 + struct wmi_pdev_get_tpc_config_cmd { /* parameter */ __le32 param; -- cgit v1.2.1 From 6b127c71fbdd3daacfd8b9f80b8e6ebfb70a889e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 10 Dec 2014 21:26:10 +0530 Subject: mac80211: Move IEEE80211_TX_CTL_PS_RESPONSE Move IEEE80211_TX_CTL_PS_RESPONSE to info->control.flags since this is used only in the TX path (by ath9k). This frees up a bit which can be used for other purposes. Signed-off-by: Sujith Manoharan Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath9k/xmit.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index e9bd02c2e844..4caee66e5f79 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2259,7 +2259,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_txq *txq = txctl->txq; struct ath_atx_tid *tid = NULL; struct ath_buf *bf; - bool queue, skip_uapsd = false; + bool queue, skip_uapsd = false, ps_resp; int q, ret; if (vif) @@ -2268,6 +2268,8 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) txctl->force_channel = true; + ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE); + ret = ath_tx_prepare(hw, skb, txctl); if (ret) return ret; @@ -2310,7 +2312,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, if (txctl->an && queue) tid = ath_get_skb_tid(sc, txctl->an, skb); - if (!skip_uapsd && (info->flags & IEEE80211_TX_CTL_PS_RESPONSE)) { + if (!skip_uapsd && ps_resp) { ath_txq_unlock(sc, txq); txq = sc->tx.uapsdq; ath_txq_lock(sc, txq); -- cgit v1.2.1 From 848955ccf0bdf42fff33e021a76f6daec98fe59b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 Nov 2014 12:48:42 +0100 Subject: mac80211: move U-APSD enablement to vif flags In order to let drivers have more dynamic U-APSD support, move the enablement flag to the virtual interface driver flags. This lets drivers not only set it up differently for different interfaces, but also enable/disable on the fly if needed. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 3 ++- drivers/net/wireless/cw1200/main.c | 1 - drivers/net/wireless/cw1200/sta.c | 1 + drivers/net/wireless/iwlwifi/mvm/mac80211.c | 13 ++++++------- drivers/net/wireless/ti/wl1251/main.c | 5 ++--- drivers/net/wireless/ti/wlcore/main.c | 2 +- 6 files changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c4005670cba2..2619db1e3e74 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2871,6 +2871,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, int bit; u32 vdev_param; + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; + mutex_lock(&ar->conf_mutex); memset(arvif, 0, sizeof(*arvif)); @@ -5024,7 +5026,6 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | - IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_HAS_RATE_CONTROL | diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c index 3e78cc3ccb78..0da6e423da63 100644 --- a/drivers/net/wireless/cw1200/main.c +++ b/drivers/net/wireless/cw1200/main.c @@ -282,7 +282,6 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | IEEE80211_HW_REPORTS_TX_ACK_STATUS | - IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c index 5b84664db13b..a1e3237c0be8 100644 --- a/drivers/net/wireless/cw1200/sta.c +++ b/drivers/net/wireless/cw1200/sta.c @@ -213,6 +213,7 @@ int cw1200_add_interface(struct ieee80211_hw *dev, /* __le32 auto_calibration_mode = __cpu_to_le32(1); */ vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_UAPSD | IEEE80211_VIF_SUPPORTS_CQM_RSSI; mutex_lock(&priv->conf_mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 31a5b3f4266c..346331d3c696 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -326,6 +326,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC | IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED; hw->rate_control_algorithm = "iwl-mvm-rs"; + hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; + hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; /* * Enable 11w if advertised by firmware and software crypto @@ -336,13 +338,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) !iwlwifi_mod_params.sw_crypto) hw->flags |= IEEE80211_HW_MFP_CAPABLE; - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && - !iwlwifi_mod_params.uapsd_disable) { - hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; - hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; - hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; - } - if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN || mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; @@ -1147,6 +1142,10 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, mvm->bf_allowed_vif = mvmvif; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_CQM_RSSI; + if (mvm->fw->ucode_capa.flags & + IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && + !iwlwifi_mod_params.uapsd_disable) + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; } /* diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 0b30a7b4d663..d4ba009ac9aa 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -500,6 +500,7 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, int ret = 0; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_UAPSD | IEEE80211_VIF_SUPPORTS_CQM_RSSI; wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", @@ -1480,9 +1481,7 @@ int wl1251_init_ieee80211(struct wl1251 *wl) /* unit us */ /* FIXME: find a proper value */ - wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_UAPSD; + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 6ad3fcedab9b..2a99456b6b8f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -2508,6 +2508,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, } vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_UAPSD | IEEE80211_VIF_SUPPORTS_CQM_RSSI; wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", @@ -5776,7 +5777,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | - IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_REPORTS_TX_ACK_STATUS | -- cgit v1.2.1 From 1010ba4c5d1cb7e884100e54c0909885dc53a755 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Fri, 5 Dec 2014 09:16:26 -0800 Subject: ath10k: unregister and remove frag_threshold callback Setting fragmentation threshold has not been supported by any of firmware versions, hence unregister the callback and remove the function. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 5475f0fbbe41..fe61201d2e72 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3991,29 +3991,6 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct ath10k *ar = hw->priv; - struct ath10k_vif *arvif; - int ret = 0; - - mutex_lock(&ar->conf_mutex); - list_for_each_entry(arvif, &ar->arvifs, list) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n", - arvif->vdev_id, value); - - ret = ath10k_mac_set_frag(arvif, value); - if (ret) { - ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n", - arvif->vdev_id, ret); - break; - } - } - mutex_unlock(&ar->conf_mutex); - - return ret; -} - static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { @@ -4657,7 +4634,6 @@ static const struct ieee80211_ops ath10k_ops = { .remain_on_channel = ath10k_remain_on_channel, .cancel_remain_on_channel = ath10k_cancel_remain_on_channel, .set_rts_threshold = ath10k_set_rts_threshold, - .set_frag_threshold = ath10k_set_frag_threshold, .flush = ath10k_flush, .tx_last_beacon = ath10k_tx_last_beacon, .set_antenna = ath10k_set_antenna, -- cgit v1.2.1 From 91b12089b18a17cf510f636e29c2cb3a901fe7a5 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 12 Dec 2014 12:41:35 +0100 Subject: ath10k: improve 11b coex Some firmware revisions need peer phymode to be specified as MODE_11B when associating as station to a 11b AP. Otherwise they can starve other stations. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index fe61201d2e72..950322d646a5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1416,6 +1416,12 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, } } +static bool ath10k_mac_sta_has_11g_rates(struct ieee80211_sta *sta) +{ + /* First 4 rates in ath10k_rates are CCK (11b) rates. */ + return sta->supp_rates[IEEE80211_BAND_2GHZ] >> 4; +} + static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -1430,8 +1436,10 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, phymode = MODE_11NG_HT40; else phymode = MODE_11NG_HT20; - } else { + } else if (ath10k_mac_sta_has_11g_rates(sta)) { phymode = MODE_11G; + } else { + phymode = MODE_11B; } break; @@ -4724,6 +4732,9 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = { CHAN5G(165, 5825, 0), }; +/* Note: Be careful if you re-order these. There is code which depends on this + * ordering. + */ static struct ieee80211_rate ath10k_rates[] = { /* CCK */ RATETAB_ENT(10, 0x82, 0), -- cgit v1.2.1 From 9f9b5746246014890b85a4bfd83b9bbd0f223ac2 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 12 Dec 2014 12:41:36 +0100 Subject: ath10k: fix STA u-APSD To comply with WMM-PS the device shouldn't wake up with a NullFunc frame pair when tx-ing. Instead PM bit on each tx frame should be used. To make this work correctly firmware needs to be told to use a different STA PS wake threshold when u-APSD is enabled. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 79 ++++++++++++++++++++++++++++++----- drivers/net/wireless/ath/ath10k/wmi.h | 7 ++++ 2 files changed, 76 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 950322d646a5..13c2bad71c21 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1048,6 +1048,57 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, arvif->vdev_id, ret); } +static int ath10k_mac_vif_recalc_ps_wake_threshold(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + u32 param; + u32 value; + int ret; + + lockdep_assert_held(&arvif->ar->conf_mutex); + + if (arvif->u.sta.uapsd) + value = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER; + else + value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; + + param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD; + ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); + if (ret) { + ath10k_warn(ar, "failed to submit ps wake threshold %u on vdev %i: %d\n", + value, arvif->vdev_id, ret); + return ret; + } + + return 0; +} + +static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + u32 param; + u32 value; + int ret; + + lockdep_assert_held(&arvif->ar->conf_mutex); + + if (arvif->u.sta.uapsd) + value = WMI_STA_PS_PSPOLL_COUNT_UAPSD; + else + value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; + + param = WMI_STA_PS_PARAM_PSPOLL_COUNT; + ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, + param, value); + if (ret) { + ath10k_warn(ar, "failed to submit ps poll count %u on vdev %i: %d\n", + value, arvif->vdev_id, ret); + return ret; + } + + return 0; +} + /* * Review this when mac80211 gains per-interface powersave support. */ @@ -3036,22 +3087,16 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err_peer_delete; } - param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD; - value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; - ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, - param, value); + ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif); if (ret) { - ath10k_warn(ar, "failed to set vdev %i TX wake thresh: %d\n", + ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } - param = WMI_STA_PS_PARAM_PSPOLL_COUNT; - value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; - ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, - param, value); + ret = ath10k_mac_vif_recalc_ps_poll_count(arvif); if (ret) { - ath10k_warn(ar, "failed to set vdev %i PSPOLL count: %d\n", + ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -3818,6 +3863,20 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, if (ret) ath10k_warn(ar, "failed to set rx wake param: %d\n", ret); + ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif); + if (ret) { + ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + ret = ath10k_mac_vif_recalc_ps_poll_count(arvif); + if (ret) { + ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + exit: return ret; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 97f902f03ec5..ff2d0765cbb2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4015,6 +4015,13 @@ enum wmi_sta_ps_param_pspoll_count { * Values greater than 0 indicate the maximum numer of PS-Poll frames * FW will send before waking up. */ + + /* When u-APSD is enabled the firmware will be very reluctant to exit + * STA PS. This could result in very poor Rx performance with STA doing + * PS-Poll for each and every buffered frame. This value is a bit + * arbitrary. + */ + WMI_STA_PS_PSPOLL_COUNT_UAPSD = 3, }; /* -- cgit v1.2.1 From 526549a850bf6f549b88a271c7df9dd847e02bcf Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 12 Dec 2014 12:41:37 +0100 Subject: ath10k: prevent invalid ps timeout config Setting 0 ps timeout to firmware yields very poor latency and traffic issues. This is the case when multi-vif is active. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 13c2bad71c21..2804952448c5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1105,10 +1105,12 @@ static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) { struct ath10k *ar = arvif->ar; + struct ieee80211_vif *vif = arvif->vif; struct ieee80211_conf *conf = &ar->hw->conf; enum wmi_sta_powersave_param param; enum wmi_sta_ps_mode psmode; int ret; + int ps_timeout; lockdep_assert_held(&arvif->ar->conf_mutex); @@ -1119,8 +1121,15 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) psmode = WMI_STA_PS_MODE_ENABLED; param = WMI_STA_PS_PARAM_INACTIVITY_TIME; + ps_timeout = conf->dynamic_ps_timeout; + if (ps_timeout == 0) { + /* Firmware doesn't like 0 */ + ps_timeout = ieee80211_tu_to_usec( + vif->bss_conf.beacon_int) / 1000; + } + ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, - conf->dynamic_ps_timeout); + ps_timeout); if (ret) { ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n", arvif->vdev_id, ret); -- cgit v1.2.1 From bf14e65cb750be9837c8b0f61471145a03ba4a36 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 12 Dec 2014 12:41:38 +0100 Subject: ath10k: enable per-vif sta powersave Per-vif bss_conf.ps should be used to configure powersave. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2804952448c5..19ddbc6e19e0 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1099,9 +1099,6 @@ static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) return 0; } -/* - * Review this when mac80211 gains per-interface powersave support. - */ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) { struct ath10k *ar = arvif->ar; @@ -1117,7 +1114,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) if (arvif->vif->type != NL80211_IFTYPE_STATION) return 0; - if (conf->flags & IEEE80211_CONF_PS) { + if (vif->bss_conf.ps) { psmode = WMI_STA_PS_MODE_ENABLED; param = WMI_STA_PS_PARAM_INACTIVITY_TIME; @@ -3378,6 +3375,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to recalc tx power: %d\n", ret); } + if (changed & BSS_CHANGED_PS) { + ret = ath10k_mac_vif_setup_ps(arvif); + if (ret) + ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n", + arvif->vdev_id, ret); + } + mutex_unlock(&ar->conf_mutex); } -- cgit v1.2.1 From 75d2bd488301dbe81c2eb402bfcde5f988f72044 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 12 Dec 2014 12:41:39 +0100 Subject: ath10k: advertise p2p dev support Firmware doesn't allow precise tx rate control so P2P wasn't entirely spec compliant (it was using CCK rates in some cases). The only way to make sure firmware doesn't use CCK rates is to have a vdev with P2P subtype used for scanning and tx. This can be done via a special dedicated P2P device interface support. This also removes the ancient hack from ath10k in favor of p2pdev. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 6 ------ drivers/net/wireless/ath/ath10k/mac.c | 12 +++++++++--- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 577a3d76df22..c83f1e7f8029 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -32,17 +32,14 @@ unsigned int ath10k_debug_mask; static bool uart_print; -static unsigned int ath10k_p2p; static bool skip_otp; module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); module_param(uart_print, bool, 0644); -module_param_named(p2p, ath10k_p2p, uint, 0644); module_param(skip_otp, bool, 0644); MODULE_PARM_DESC(debug_mask, "Debugging mask"); MODULE_PARM_DESC(uart_print, "Uart target debugging"); -MODULE_PARM_DESC(p2p, "Enable ath10k P2P support"); MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); static const struct ath10k_hw_params ath10k_hw_params_list[] = { @@ -1290,10 +1287,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ar->ath_common.priv = ar; ar->ath_common.hw = ar->hw; - - ar->p2p = !!ath10k_p2p; ar->dev = dev; - ar->hif.ops = hif_ops; ar->hif.bus = bus; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 19ddbc6e19e0..42f6a4ddeb5e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2961,10 +2961,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, arvif->vdev_id = bit; arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; - if (ar->p2p) - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; - switch (vif->type) { + case NL80211_IFTYPE_P2P_DEVICE: + arvif->vdev_type = WMI_VDEV_TYPE_STA; + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; + break; case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: arvif->vdev_type = WMI_VDEV_TYPE_STA; @@ -4860,6 +4861,10 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = { .types = BIT(NL80211_IFTYPE_P2P_GO) }, { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE) + }, + { .max = 7, .types = BIT(NL80211_IFTYPE_AP) }, @@ -5079,6 +5084,7 @@ int ath10k_mac_register(struct ath10k *ar) if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features)) ar->hw->wiphy->interface_modes |= + BIT(NL80211_IFTYPE_P2P_DEVICE) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); -- cgit v1.2.1 From 7fe9a3882bb37195c41ab125a0f2852398d2646a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 10 Dec 2014 15:33:12 +0100 Subject: ieee802154: rework cca setting The current cca setting handle is a driver specific call. We need to introduce some 802.15.4 specific layer and mapping 802.15.4 cca modes to driver specific ones inside the 802.15.4 driver. This patch will add such 802.15.4 layer and mapping the cca settings to driver specific ones. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 1c0135620c62..1ac46ba41fd8 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1146,11 +1146,37 @@ at86rf230_set_lbt(struct ieee802154_hw *hw, bool on) } static int -at86rf230_set_cca_mode(struct ieee802154_hw *hw, u8 mode) +at86rf230_set_cca_mode(struct ieee802154_hw *hw, + const struct wpan_phy_cca *cca) { struct at86rf230_local *lp = hw->priv; + u8 val; - return at86rf230_write_subreg(lp, SR_CCA_MODE, mode); + /* mapping 802.15.4 to driver spec */ + switch (cca->mode) { + case NL802154_CCA_ENERGY: + val = 1; + break; + case NL802154_CCA_CARRIER: + val = 2; + break; + case NL802154_CCA_ENERGY_CARRIER: + switch (cca->opt) { + case NL802154_CCA_OPT_ENERGY_CARRIER_AND: + val = 3; + break; + case NL802154_CCA_OPT_ENERGY_CARRIER_OR: + val = 0; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return at86rf230_write_subreg(lp, SR_CCA_MODE, val); } static int -- cgit v1.2.1 From b48a7c1880e10be30a7b61db0108498693d41eb5 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 10 Dec 2014 15:33:14 +0100 Subject: at86rf230: add reset state cca handling This patch adds the default cca setting after device reset for at86rf230 driver. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 1ac46ba41fd8..0626e7d09a72 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1441,6 +1441,8 @@ at86rf230_detect_device(struct at86rf230_local *lp) IEEE802154_HW_TXPOWER | IEEE802154_HW_ARET | IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS; + lp->hw->phy->cca.mode = NL802154_CCA_ENERGY; + switch (part) { case 2: chip = "at86rf230"; -- cgit v1.2.1 From ca28849d01cc72876b1c5183c7fbef4ee8f2133b Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 12 Dec 2014 12:45:28 +0100 Subject: ieee802154/at86rf230: Remove unneeded blank lines Signed-off-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 0626e7d09a72..318bc4b001e4 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -524,7 +524,6 @@ at86rf230_async_state_assert(void *context) } } - dev_warn(&lp->spi->dev, "unexcept state change from 0x%02x to 0x%02x. Actual state: 0x%02x\n", ctx->from_state, ctx->to_state, trx_state); } @@ -762,7 +761,6 @@ at86rf230_tx_trac_check(void *context) at86rf230_tx_on(context); } - static void at86rf230_tx_trac_status(void *context) { -- cgit v1.2.1 From e80fb5eea3fc0631624c71bf604d5b6244379d40 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 12 Dec 2014 12:45:29 +0100 Subject: ieee802154/at86rf230: Align to opening parenthesis Signed-off-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 318bc4b001e4..3523d9e63f21 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1080,7 +1080,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, u16 addr = le16_to_cpu(filt->short_addr); dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for saddr\n"); + "at86rf230_set_hw_addr_filt called for saddr\n"); __at86rf230_write(lp, RG_SHORT_ADDR_0, addr); __at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8); } @@ -1089,7 +1089,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, u16 pan = le16_to_cpu(filt->pan_id); dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for pan id\n"); + "at86rf230_set_hw_addr_filt called for pan id\n"); __at86rf230_write(lp, RG_PAN_ID_0, pan); __at86rf230_write(lp, RG_PAN_ID_1, pan >> 8); } @@ -1099,14 +1099,14 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, memcpy(addr, &filt->ieee_addr, 8); dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for IEEE addr\n"); + "at86rf230_set_hw_addr_filt called for IEEE addr\n"); for (i = 0; i < 8; i++) __at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]); } if (changed & IEEE802154_AFILT_PANC_CHANGED) { dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for panc change\n"); + "at86rf230_set_hw_addr_filt called for panc change\n"); if (filt->pan_coord) at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 1); else -- cgit v1.2.1 From 2b8b7e29c4e282edadfeda70e739694594efb7b5 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 12 Dec 2014 12:45:30 +0100 Subject: ieee802154/at86rf230: Fix typo unkown -> unknown Signed-off-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 3523d9e63f21..2f66b8a81acd 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1474,7 +1474,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) lp->hw->phy->symbol_duration = 16; break; default: - chip = "unkown"; + chip = "unknown"; rc = -ENOTSUPP; break; } -- cgit v1.2.1 From cda8c203b37bcacb79227538f3bd3bb26ab708c2 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 12 Dec 2014 12:45:31 +0100 Subject: ieee802154/cc2520: Remove extra blank lines CC: Varka Bhadram Signed-off-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index f9df9fa86d5f..c2b7da3da183 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -513,7 +513,6 @@ err_tx: return rc; } - static int cc2520_rx(struct cc2520_private *priv) { u8 len = 0, lqi = 0, bytes = 1; @@ -947,7 +946,6 @@ static int cc2520_probe(struct spi_device *spi) if (ret) goto err_hw_init; - gpio_set_value(pdata->vreg, HIGH); usleep_range(100, 150); -- cgit v1.2.1 From 5c1be06a3dec9ae957e759dec7a6c012960e53bf Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 12 Dec 2014 12:45:32 +0100 Subject: ieee802154/mrf24j40: Fix typo begining -> beginning CC: Alan Ott Signed-off-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/mrf24j40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index a200fa16beae..ec605c9cc70a 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -289,7 +289,7 @@ static int mrf24j40_read_rx_buf(struct mrf24j40 *devrec, goto out; /* Range check the RX FIFO length, accounting for the one-byte - * length field at the begining. */ + * length field at the beginning. */ if (rx_len > RX_FIFO_SIZE-1) { dev_err(printdev(devrec), "Invalid length read from device. Performing short read.\n"); rx_len = RX_FIFO_SIZE-1; -- cgit v1.2.1 From ce261bc3ff376ef5e85b682c760326893ab22ba5 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 12 Dec 2014 12:45:33 +0100 Subject: ieee802154/mrf24j40: Fix alignment of parenthesis CC: Alan Ott Signed-off-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/mrf24j40.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index ec605c9cc70a..fba2dfd910f7 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -323,7 +323,7 @@ static int mrf24j40_read_rx_buf(struct mrf24j40 *devrec, #ifdef DEBUG print_hex_dump(KERN_DEBUG, "mrf24j40 rx: ", - DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0); + DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0); pr_debug("mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n", lqi_rssi[0], lqi_rssi[1]); #endif @@ -521,7 +521,7 @@ static int mrf24j40_filter(struct ieee802154_hw *hw, */ dev_dbg(printdev(devrec), "Set Pan Coord to %s\n", - filt->pan_coord ? "on" : "off"); + filt->pan_coord ? "on" : "off"); } return 0; -- cgit v1.2.1 From 5f5c5c23e3b71110c0215f9ea20e5434b68871f1 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 15 Dec 2014 10:25:53 +0100 Subject: at86rf230: remove if branch This patch removes an unnecessary if branch inside the tx complete handler. Signed-off-by: Alexander Aring Reviewed-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 2f66b8a81acd..59209f35ec6b 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -714,10 +714,7 @@ at86rf230_tx_complete(void *context) enable_irq(lp->spi->irq); - if (lp->max_frame_retries <= 0) - ieee802154_xmit_complete(lp->hw, skb, true); - else - ieee802154_xmit_complete(lp->hw, skb, false); + ieee802154_xmit_complete(lp->hw, skb, !lp->tx_aret); } static void -- cgit v1.2.1 From fc50c6e36de742229492117d8e005102a1d21900 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 15 Dec 2014 10:25:54 +0100 Subject: at86rf230: make at86rf230_async_error inline This patch makes the at86rf230_async_error inline. This function is small enough to handle inline. Signed-off-by: Alexander Aring Reviewed-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 59209f35ec6b..8fee326a6b96 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -450,7 +450,7 @@ at86rf230_async_error_recover(void *context) ieee802154_wake_queue(lp->hw); } -static void +static inline void at86rf230_async_error(struct at86rf230_local *lp, struct at86rf230_state_change *ctx, int rc) { -- cgit v1.2.1 From 4fef7d3b0151576019a7a055ffd18fced6e55944 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 15 Dec 2014 10:25:55 +0100 Subject: at86rf230: fix context pointer handling This patch changes the context pointer to the parameter given one inside function at86rf230_async_state_change_start. This could occur problem if context isn't pointed to lp->state. Signed-off-by: Alexander Aring Reviewed-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 8fee326a6b96..6d1ef83a3a5b 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -654,7 +654,7 @@ at86rf230_async_state_change_start(void *context) if (ctx->irq_enable) enable_irq(lp->spi->irq); - at86rf230_async_error(lp, &lp->state, rc); + at86rf230_async_error(lp, ctx, rc); } } -- cgit v1.2.1 From 2a100501605461dab8e59ec6c642075dcac672aa Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 15 Dec 2014 10:25:57 +0100 Subject: at86rf230: remove unnecessary assign The attribute extra_tx_headroom should already be zero. Signed-off-by: Alexander Aring Reviewed-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 6d1ef83a3a5b..2ebaba34e408 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1431,7 +1431,6 @@ at86rf230_detect_device(struct at86rf230_local *lp) return -EINVAL; } - lp->hw->extra_tx_headroom = 0; lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK | IEEE802154_HW_TXPOWER | IEEE802154_HW_ARET | IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS; -- cgit v1.2.1 From 7598968d6fdbe8960b941246cc6ebef725899c59 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Wed, 17 Dec 2014 13:14:42 -0800 Subject: at86rf230: fix register read for part version The driver was reading the PART_NUM register for both the part number (type of device) and the part version, the version is actually in register 0x1D, VERSION_NUM. I believe that this was a copy-paste error. Tested on AT86RF212B where the part is detected to be the expected part number (0x07) and version (0x03 on mine). Signed-off-by: Andrey Yurovsky Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 2ebaba34e408..b37c0249080d 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1421,7 +1421,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) if (rc) return rc; - rc = __at86rf230_read(lp, RG_PART_NUM, &version); + rc = __at86rf230_read(lp, RG_VERSION_NUM, &version); if (rc) return rc; -- cgit v1.2.1 From 4ecc8a559bc5173708a33bbd719b27af05bdce34 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Thu, 18 Dec 2014 15:36:18 -0800 Subject: at86rf230: remove version check for AT86RF212 This version check allows the driver to only work with v=1 hardware however there is no driver-facing difference with newer versions (confirmed by Atmel FAEs) so this check needlessly prevents the driver from being used with radios now in production. Tested on AT86RF212B radio (which came up as v=3). Signed-off-by: Andrey Yurovsky Reviewed-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index b37c0249080d..79fbf3809745 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1451,16 +1451,12 @@ at86rf230_detect_device(struct at86rf230_local *lp) break; case 7: chip = "at86rf212"; - if (version == 1) { - lp->data = &at86rf212_data; - lp->hw->flags |= IEEE802154_HW_LBT; - lp->hw->phy->channels_supported[0] = 0x00007FF; - lp->hw->phy->channels_supported[2] = 0x00007FF; - lp->hw->phy->current_channel = 5; - lp->hw->phy->symbol_duration = 25; - } else { - rc = -ENOTSUPP; - } + lp->data = &at86rf212_data; + lp->hw->flags |= IEEE802154_HW_LBT; + lp->hw->phy->channels_supported[0] = 0x00007FF; + lp->hw->phy->channels_supported[2] = 0x00007FF; + lp->hw->phy->current_channel = 5; + lp->hw->phy->symbol_duration = 25; break; case 11: chip = "at86rf233"; -- cgit v1.2.1 From c8c7e3db819f4fc483793d55655cbbae045203f0 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 19 Dec 2014 10:36:50 +0100 Subject: at86rf230: cleanup check on trac status Signed-off-by: Alexander Aring Reviewed-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 79fbf3809745..80632fc59756 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -749,13 +749,11 @@ at86rf230_tx_trac_check(void *context) * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver * state to TX_ON. */ - if (trac) { + if (trac) at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, at86rf230_tx_trac_error, true); - return; - } - - at86rf230_tx_on(context); + else + at86rf230_tx_on(context); } static void -- cgit v1.2.1 From 5875755c577b00b06aba77ba471175c3e3a33c25 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 22 Dec 2014 12:51:25 +0100 Subject: mac80211_hwsim: fix check for custom world regdom array size David Binderman reports that the conditions in the first loop are the wrong way around - checking the array contents before the size. Instead of leaving the empty loop there and reordering the two checks unify it into a single loop that skips over non-matches and exits after the first match. Reported-by: David Binderman Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index a71b9d5e353d..057a99e01637 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2150,14 +2150,14 @@ static int append_radio_msg(struct sk_buff *skb, int id, if (param->regd) { int i; - for (i = 0; hwsim_world_regdom_custom[i] != param->regd && - i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) - ; + for (i = 0; i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) { + if (hwsim_world_regdom_custom[i] != param->regd) + continue; - if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) { ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i); if (ret < 0) return ret; + break; } } -- cgit v1.2.1 From 30c78167bc6536d9074aa79385a575596343bf69 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 17 Dec 2014 12:20:45 +0200 Subject: ath10k: set max_num_vdevs based on wmi op version To make it easier to manage firmware differences, we should not use ATH10K_FW_FEATURE_WMI_10X outside ath10k_core_init_firmware_features(). To achieve that create new field ar->max_num_vdevs and set it based on wmi op version. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 7 +++---- drivers/net/wireless/ath/ath10k/core.h | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c83f1e7f8029..bf4a46a82b63 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -904,12 +904,14 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_MAIN: ar->max_num_peers = TARGET_NUM_PEERS; ar->max_num_stations = TARGET_NUM_STATIONS; + ar->max_num_vdevs = TARGET_NUM_VDEVS; ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC; break; case ATH10K_FW_WMI_OP_VERSION_10_1: case ATH10K_FW_WMI_OP_VERSION_10_2: ar->max_num_peers = TARGET_10X_NUM_PEERS; ar->max_num_stations = TARGET_10X_NUM_STATIONS; + ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; break; case ATH10K_FW_WMI_OP_VERSION_TLV: @@ -1061,10 +1063,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) if (status) goto err_hif_stop; - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - ar->free_vdev_map = (1LL << TARGET_10X_NUM_VDEVS) - 1; - else - ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1; + ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1; INIT_LIST_HEAD(&ar->arvifs); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 613355cc6895..3998f1e33874 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -581,6 +581,7 @@ struct ath10k { int max_num_peers; int max_num_stations; + int max_num_vdevs; struct work_struct offchan_tx_work; struct sk_buff_head offchan_tx_queue; -- cgit v1.2.1 From 5cc7caf46cb8823f0a86b25b96ebbc531bd1a21c Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 17 Dec 2014 12:20:54 +0200 Subject: ath10k: use wmi op version to check which iface combination to use ATH10K_FW_FEATURE_WMI_10X should not be used for anymore as that's now deprecated, instead use wmi op version. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 42f6a4ddeb5e..780c63bad807 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5129,16 +5129,25 @@ int ath10k_mac_register(struct ath10k *ar) */ ar->hw->queues = 4; - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; - ar->hw->wiphy->n_iface_combinations = - ARRAY_SIZE(ath10k_10x_if_comb); - } else { + switch (ar->wmi.op_version) { + case ATH10K_FW_WMI_OP_VERSION_MAIN: + case ATH10K_FW_WMI_OP_VERSION_TLV: ar->hw->wiphy->iface_combinations = ath10k_if_comb; ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_if_comb); - ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); + break; + case ATH10K_FW_WMI_OP_VERSION_10_1: + case ATH10K_FW_WMI_OP_VERSION_10_2: + ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; + ar->hw->wiphy->n_iface_combinations = + ARRAY_SIZE(ath10k_10x_if_comb); + break; + case ATH10K_FW_WMI_OP_VERSION_UNSET: + case ATH10K_FW_WMI_OP_VERSION_MAX: + WARN_ON(1); + ret = -EINVAL; + goto err_free; } ar->hw->netdev_features = NETIF_F_HW_CSUM; -- cgit v1.2.1 From ffdd07576fb6722f2bdeb67783d7a85af4b6dd44 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 17 Dec 2014 12:21:03 +0200 Subject: ath10k: print ath10k wmi op version The internal firmware version doesn't tell much to the user, it's more informative to use that field to print the wmi op version. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 70a9599aeb7a..6ca24427e184 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL(ath10k_info); void ath10k_print_driver_info(struct ath10k *ar) { - ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s max_sta %d\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -132,10 +132,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->fw_api, ar->htt.target_version_major, ar->htt.target_version_minor, - ar->fw_version_major, - ar->fw_version_minor, - ar->fw_version_release, - ar->fw_version_build, + ar->wmi.op_version, ath10k_cal_mode_str(ar->cal_mode), ar->max_num_stations); ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", -- cgit v1.2.1 From 4a16fbec1cd0a760d17f3d2b587d504a6eae4da6 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 17 Dec 2014 12:21:12 +0200 Subject: ath10k: add 10.2.4 firmware support 10.2.4 firmware uses bitmask in wmi_resource_config to configure 10.2 firmware features like airtime fairness and rx batch mode instead of maintaining separete bool entry. This allows new features that can be configure during init time without breaking backward compatibility. kvalo: use WMI op version, bump up FW API to 4 to not break older versions of ath10k Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 11 +- drivers/net/wireless/ath/ath10k/hw.h | 4 + drivers/net/wireless/ath/ath10k/mac.c | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 291 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 7 +- 5 files changed, 312 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index bf4a46a82b63..7e377f85a478 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -687,6 +687,13 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) /* calibration file is optional, don't check for any errors */ ath10k_fetch_cal_file(ar); + ar->fw_api = 4; + ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); + + ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API4_FILE); + if (ret == 0) + goto success; + ar->fw_api = 3; ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); @@ -891,7 +898,8 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) */ if (ar->wmi.op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) { if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, + ar->fw_features)) ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_2; else ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; @@ -909,6 +917,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) break; case ATH10K_FW_WMI_OP_VERSION_10_1: case ATH10K_FW_WMI_OP_VERSION_10_2: + case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->max_num_peers = TARGET_10X_NUM_PEERS; ar->max_num_stations = TARGET_10X_NUM_STATIONS; ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 809c2521adb3..5729901923ac 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -37,6 +37,9 @@ #define ATH10K_FW_API2_FILE "firmware-2.bin" #define ATH10K_FW_API3_FILE "firmware-3.bin" +/* added support for ATH10K_FW_IE_WMI_OP_VERSION */ +#define ATH10K_FW_API4_FILE "firmware-4.bin" + #define ATH10K_FW_UTF_FILE "utf.bin" /* includes also the null byte */ @@ -72,6 +75,7 @@ enum ath10k_fw_wmi_op_version { ATH10K_FW_WMI_OP_VERSION_10_1 = 2, ATH10K_FW_WMI_OP_VERSION_10_2 = 3, ATH10K_FW_WMI_OP_VERSION_TLV = 4, + ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5, /* keep last */ ATH10K_FW_WMI_OP_VERSION_MAX, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 780c63bad807..31354dbebd02 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5139,6 +5139,7 @@ int ath10k_mac_register(struct ath10k *ar) break; case ATH10K_FW_WMI_OP_VERSION_10_1: case ATH10K_FW_WMI_OP_VERSION_10_2: + case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_10x_if_comb); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index fa486f69cce7..cf9c727dc7d3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -269,6 +269,127 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID, }; +/* 10.2.4 WMI cmd track */ +static struct wmi_cmd_map wmi_10_2_4_cmd_map = { + .init_cmdid = WMI_10_2_INIT_CMDID, + .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID, + .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID, + .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID, + .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, + .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID, + .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID, + .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID, + .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID, + .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID, + .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID, + .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID, + .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID, + .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID, + .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID, + .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID, + .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID, + .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID, + .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID, + .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID, + .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID, + .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID, + .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID, + .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID, + .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID, + .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID, + .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID, + .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID, + .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID, + .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID, + .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID, + .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID, + .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID, + .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID, + .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID, + .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED, + .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID, + .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID, + .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID, + .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED, + .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID, + .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID, + .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID, + .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID, + .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID, + .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID, + .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID, + .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID, + .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID, + .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID, + .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID, + .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE, + .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD, + .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD, + .roam_scan_rssi_change_threshold = + WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE, + .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE, + .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE, + .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD, + .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO, + .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY, + .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE, + .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE, + .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, + .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID, + .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED, + .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID, + .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID, + .wlan_profile_set_hist_intvl_cmdid = + WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + .wlan_profile_get_profile_data_cmdid = + WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + .wlan_profile_enable_profile_id_cmdid = + WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + .wlan_profile_list_profile_id_cmdid = + WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID, + .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID, + .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID, + .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID, + .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID, + .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID, + .wow_enable_disable_wake_event_cmdid = + WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID, + .wow_hostwakeup_from_sleep_cmdid = + WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID, + .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID, + .vdev_spectral_scan_configure_cmdid = + WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, + .vdev_spectral_scan_enable_cmdid = + WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID, + .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED, + .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED, + .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED, + .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED, + .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED, + .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED, + .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED, + .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED, + .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED, + .echo_cmdid = WMI_10_2_ECHO_CMDID, + .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID, + .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID, + .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID, + .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, + .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, + .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, +}; + /* MAIN WMI VDEV param map */ static struct wmi_vdev_param_map wmi_vdev_param_map = { .rts_threshold = WMI_VDEV_PARAM_RTS_THRESHOLD, @@ -387,6 +508,64 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = { WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, }; +static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { + .rts_threshold = WMI_10X_VDEV_PARAM_RTS_THRESHOLD, + .fragmentation_threshold = WMI_10X_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + .beacon_interval = WMI_10X_VDEV_PARAM_BEACON_INTERVAL, + .listen_interval = WMI_10X_VDEV_PARAM_LISTEN_INTERVAL, + .multicast_rate = WMI_10X_VDEV_PARAM_MULTICAST_RATE, + .mgmt_tx_rate = WMI_10X_VDEV_PARAM_MGMT_TX_RATE, + .slot_time = WMI_10X_VDEV_PARAM_SLOT_TIME, + .preamble = WMI_10X_VDEV_PARAM_PREAMBLE, + .swba_time = WMI_10X_VDEV_PARAM_SWBA_TIME, + .wmi_vdev_stats_update_period = WMI_10X_VDEV_STATS_UPDATE_PERIOD, + .wmi_vdev_pwrsave_ageout_time = WMI_10X_VDEV_PWRSAVE_AGEOUT_TIME, + .wmi_vdev_host_swba_interval = WMI_10X_VDEV_HOST_SWBA_INTERVAL, + .dtim_period = WMI_10X_VDEV_PARAM_DTIM_PERIOD, + .wmi_vdev_oc_scheduler_air_time_limit = + WMI_10X_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + .wds = WMI_10X_VDEV_PARAM_WDS, + .atim_window = WMI_10X_VDEV_PARAM_ATIM_WINDOW, + .bmiss_count_max = WMI_10X_VDEV_PARAM_BMISS_COUNT_MAX, + .bmiss_first_bcnt = WMI_VDEV_PARAM_UNSUPPORTED, + .bmiss_final_bcnt = WMI_VDEV_PARAM_UNSUPPORTED, + .feature_wmm = WMI_10X_VDEV_PARAM_FEATURE_WMM, + .chwidth = WMI_10X_VDEV_PARAM_CHWIDTH, + .chextoffset = WMI_10X_VDEV_PARAM_CHEXTOFFSET, + .disable_htprotection = WMI_10X_VDEV_PARAM_DISABLE_HTPROTECTION, + .sta_quickkickout = WMI_10X_VDEV_PARAM_STA_QUICKKICKOUT, + .mgmt_rate = WMI_10X_VDEV_PARAM_MGMT_RATE, + .protection_mode = WMI_10X_VDEV_PARAM_PROTECTION_MODE, + .fixed_rate = WMI_10X_VDEV_PARAM_FIXED_RATE, + .sgi = WMI_10X_VDEV_PARAM_SGI, + .ldpc = WMI_10X_VDEV_PARAM_LDPC, + .tx_stbc = WMI_10X_VDEV_PARAM_TX_STBC, + .rx_stbc = WMI_10X_VDEV_PARAM_RX_STBC, + .intra_bss_fwd = WMI_10X_VDEV_PARAM_INTRA_BSS_FWD, + .def_keyid = WMI_10X_VDEV_PARAM_DEF_KEYID, + .nss = WMI_10X_VDEV_PARAM_NSS, + .bcast_data_rate = WMI_10X_VDEV_PARAM_BCAST_DATA_RATE, + .mcast_data_rate = WMI_10X_VDEV_PARAM_MCAST_DATA_RATE, + .mcast_indicate = WMI_10X_VDEV_PARAM_MCAST_INDICATE, + .dhcp_indicate = WMI_10X_VDEV_PARAM_DHCP_INDICATE, + .unknown_dest_indicate = WMI_10X_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + .ap_keepalive_min_idle_inactive_time_secs = + WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_idle_inactive_time_secs = + WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_unresponsive_time_secs = + WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + .ap_enable_nawds = WMI_10X_VDEV_PARAM_AP_ENABLE_NAWDS, + .mcast2ucast_set = WMI_10X_VDEV_PARAM_MCAST2UCAST_SET, + .enable_rtscts = WMI_10X_VDEV_PARAM_ENABLE_RTSCTS, + .txbf = WMI_VDEV_PARAM_UNSUPPORTED, + .packet_powersave = WMI_VDEV_PARAM_UNSUPPORTED, + .drop_unencry = WMI_VDEV_PARAM_UNSUPPORTED, + .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .ap_detect_out_of_sync_sleeping_sta_time_secs = + WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +}; + static struct wmi_pdev_param_map wmi_pdev_param_map = { .tx_chain_mask = WMI_PDEV_PARAM_TX_CHAIN_MASK, .rx_chain_mask = WMI_PDEV_PARAM_RX_CHAIN_MASK, @@ -492,6 +671,59 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, }; +static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { + .tx_chain_mask = WMI_10X_PDEV_PARAM_TX_CHAIN_MASK, + .rx_chain_mask = WMI_10X_PDEV_PARAM_RX_CHAIN_MASK, + .txpower_limit2g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT2G, + .txpower_limit5g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT5G, + .txpower_scale = WMI_10X_PDEV_PARAM_TXPOWER_SCALE, + .beacon_gen_mode = WMI_10X_PDEV_PARAM_BEACON_GEN_MODE, + .beacon_tx_mode = WMI_10X_PDEV_PARAM_BEACON_TX_MODE, + .resmgr_offchan_mode = WMI_10X_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + .protection_mode = WMI_10X_PDEV_PARAM_PROTECTION_MODE, + .dynamic_bw = WMI_10X_PDEV_PARAM_DYNAMIC_BW, + .non_agg_sw_retry_th = WMI_10X_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + .agg_sw_retry_th = WMI_10X_PDEV_PARAM_AGG_SW_RETRY_TH, + .sta_kickout_th = WMI_10X_PDEV_PARAM_STA_KICKOUT_TH, + .ac_aggrsize_scaling = WMI_10X_PDEV_PARAM_AC_AGGRSIZE_SCALING, + .ltr_enable = WMI_10X_PDEV_PARAM_LTR_ENABLE, + .ltr_ac_latency_be = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BE, + .ltr_ac_latency_bk = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BK, + .ltr_ac_latency_vi = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VI, + .ltr_ac_latency_vo = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VO, + .ltr_ac_latency_timeout = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + .ltr_sleep_override = WMI_10X_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + .ltr_rx_override = WMI_10X_PDEV_PARAM_LTR_RX_OVERRIDE, + .ltr_tx_activity_timeout = WMI_10X_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + .l1ss_enable = WMI_10X_PDEV_PARAM_L1SS_ENABLE, + .dsleep_enable = WMI_10X_PDEV_PARAM_DSLEEP_ENABLE, + .pcielp_txbuf_flush = WMI_PDEV_PARAM_UNSUPPORTED, + .pcielp_txbuf_watermark = WMI_PDEV_PARAM_UNSUPPORTED, + .pcielp_txbuf_tmo_en = WMI_PDEV_PARAM_UNSUPPORTED, + .pcielp_txbuf_tmo_value = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_stats_update_period = WMI_10X_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + .vdev_stats_update_period = WMI_10X_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + .peer_stats_update_period = WMI_10X_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + .bcnflt_stats_update_period = + WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS, + .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, + .dcs = WMI_10X_PDEV_PARAM_DCS, + .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE, + .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD, + .ani_listen_period = WMI_10X_PDEV_PARAM_ANI_LISTEN_PERIOD, + .ani_ofdm_level = WMI_10X_PDEV_PARAM_ANI_OFDM_LEVEL, + .ani_cck_level = WMI_10X_PDEV_PARAM_ANI_CCK_LEVEL, + .dyntxchain = WMI_10X_PDEV_PARAM_DYNTXCHAIN, + .proxy_sta = WMI_PDEV_PARAM_UNSUPPORTED, + .idle_ps_config = WMI_PDEV_PARAM_UNSUPPORTED, + .power_gating_sleep = WMI_PDEV_PARAM_UNSUPPORTED, + .fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET, + .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, + .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, + .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, +}; + /* firmware 10.2 specific mappings */ static struct wmi_cmd_map wmi_10_2_cmd_map = { .init_cmdid = WMI_10_2_INIT_CMDID, @@ -4745,9 +4977,68 @@ static const struct wmi_ops wmi_10_2_ops = { .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, }; +static const struct wmi_ops wmi_10_2_4_ops = { + .rx = ath10k_wmi_10_2_op_rx, + .gen_init = ath10k_wmi_10_2_op_gen_init, + .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, + + /* shared with 10.1 */ + .map_svc = wmi_10x_svc_map, + .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, + .pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats, + .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, + .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, + + .pull_scan = ath10k_wmi_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, +}; + int ath10k_wmi_attach(struct ath10k *ar) { switch (ar->wmi.op_version) { + case ATH10K_FW_WMI_OP_VERSION_10_2_4: + ar->wmi.cmd = &wmi_10_2_4_cmd_map; + ar->wmi.ops = &wmi_10_2_4_ops; + ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map; + ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map; + break; case ATH10K_FW_WMI_OP_VERSION_10_2: ar->wmi.cmd = &wmi_10_2_cmd_map; ar->wmi.ops = &wmi_10_2_ops; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index ff2d0765cbb2..7f34093f6778 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -1940,6 +1940,11 @@ struct wmi_resource_config_10x { __le32 max_frag_entries; } __packed; +enum wmi_10_2_feature_mask { + WMI_10_2_RX_BATCH_MODE = BIT(0), + WMI_10_2_ATF_CONFIG = BIT(1), +}; + struct wmi_resource_config_10_2 { struct wmi_resource_config_10x common; __le32 max_peer_ext_stats; @@ -1948,7 +1953,7 @@ struct wmi_resource_config_10_2 { __le32 be_min_free; __le32 vi_min_free; __le32 vo_min_free; - __le32 rx_batchmode; /* 0-disable, 1-enable */ + __le32 feature_mask; } __packed; #define NUM_UNITS_IS_NUM_VDEVS 0x1 -- cgit v1.2.1 From ffdd738d90f0d9d609e3d790059ab4d351a75963 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 17 Dec 2014 12:21:40 +0200 Subject: ath10k: add wmi support for pdev_set_quiet_mode Add WMI support to send pdev_set_quiet_mode command to target. This will be used for thermal mitigation purpose. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 22 ++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 1fbc5207b870..feed0fe5e117 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -114,6 +114,10 @@ struct wmi_ops { struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u32 module_enable); struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter); struct sk_buff *(*gen_pktlog_disable)(struct ath10k *ar); + struct sk_buff *(*gen_pdev_set_quiet_mode)(struct ath10k *ar, + u32 period, u32 duration, + u32 next_offset, + u32 enabled); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -818,4 +822,22 @@ ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar) ar->wmi.cmd->pdev_pktlog_disable_cmdid); } +static inline int +ath10k_wmi_pdev_set_quiet_mode(struct ath10k *ar, u32 period, u32 duration, + u32 next_offset, u32 enabled) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_set_quiet_mode) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_set_quiet_mode(ar, period, duration, + next_offset, enabled); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_set_quiet_mode_cmdid); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 1627ec58a229..e203dadf1c0f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2204,6 +2204,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, + /* .gen_pdev_set_quiet_mode not implemented */ }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index cf9c727dc7d3..77bb3313ca47 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4821,6 +4821,30 @@ ath10k_wmi_op_gen_pktlog_disable(struct ath10k *ar) return skb; } +static struct sk_buff * +ath10k_wmi_op_gen_pdev_set_quiet_mode(struct ath10k *ar, u32 period, + u32 duration, u32 next_offset, + u32 enabled) +{ + struct wmi_pdev_set_quiet_cmd *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_pdev_set_quiet_cmd *)skb->data; + cmd->period = __cpu_to_le32(period); + cmd->duration = __cpu_to_le32(duration); + cmd->next_start = __cpu_to_le32(next_offset); + cmd->enabled = __cpu_to_le32(enabled); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi quiet param: period %u duration %u enabled %d\n", + period, duration, enabled); + return skb; +} + static const struct wmi_ops wmi_ops = { .rx = ath10k_wmi_op_rx, .map_svc = wmi_main_svc_map, @@ -4870,6 +4894,7 @@ static const struct wmi_ops wmi_ops = { .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, }; static const struct wmi_ops wmi_10_1_ops = { @@ -4922,6 +4947,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, }; static const struct wmi_ops wmi_10_2_ops = { @@ -4975,6 +5001,7 @@ static const struct wmi_ops wmi_10_2_ops = { .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, }; static const struct wmi_ops wmi_10_2_4_ops = { @@ -5028,6 +5055,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, }; int ath10k_wmi_attach(struct ath10k *ar) -- cgit v1.2.1 From fe6f36d62152ba85a8928e46fc2cbb919538c51d Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 17 Dec 2014 12:22:07 +0200 Subject: ath10k: add thermal cooling device support Thermal cooling device support is added to control the temperature by throttling the data transmission for the given duration. Throttling is done using hw MAC quiet time setting. Period, duration and offset from TBTT can be set up to quiet the MAC transmits for the required duty cycle (% of quiet duration). The thermal device allows user to configure duty cycle. The quiet params are derived as follows. period = max(25TU, beacon interval / number of bss) duration = period * duty cycle / 100 Quiet mode can be disabled by setting the duty cycle to 0. The cooling device can be found under /sys/class/thermal/cooling_deviceX/. Corresponding soft link to this device can be found under phy folder. /sys/class/ieee80211/phy*/device/cooling_device. To set duty cycle as 40%, echo 40 >/sys/class/ieee80211/phy*/device/cooling_device/cur_state Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Makefile | 1 + drivers/net/wireless/ath/ath10k/core.c | 10 ++ drivers/net/wireless/ath/ath10k/core.h | 3 + drivers/net/wireless/ath/ath10k/thermal.c | 155 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/thermal.h | 44 +++++++++ 5 files changed, 213 insertions(+) create mode 100644 drivers/net/wireless/ath/ath10k/thermal.c create mode 100644 drivers/net/wireless/ath/ath10k/thermal.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 8abb66ceb99c..ffa3b1a8745f 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -14,6 +14,7 @@ ath10k_core-y += mac.o \ ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o +ath10k_core-$(CONFIG_THERMAL) += thermal.o obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o ath10k_pci-y += pci.o \ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7e377f85a478..70d53e65c53d 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1231,9 +1231,18 @@ static void ath10k_core_register_work(struct work_struct *work) goto err_debug_destroy; } + status = ath10k_thermal_register(ar); + if (status) { + ath10k_err(ar, "could not register thermal device: %d\n", + status); + goto err_spectral_destroy; + } + set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags); return; +err_spectral_destroy: + ath10k_spectral_destroy(ar); err_debug_destroy: ath10k_debug_destroy(ar); err_unregister_mac: @@ -1263,6 +1272,7 @@ void ath10k_core_unregister(struct ath10k *ar) if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) return; + ath10k_thermal_unregister(ar); /* Stop spectral before unregistering from mac80211 to remove the * relayfs debugfs file cleanly. Otherwise the parent debugfs tree * would be already be free'd recursively, leading to a double free. diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 3998f1e33874..7b6d9e4567a3 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -34,6 +34,7 @@ #include "../regd.h" #include "../dfs_pattern_detector.h" #include "spectral.h" +#include "thermal.h" #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -634,6 +635,8 @@ struct ath10k { u32 fw_cold_reset_counter; } stats; + struct ath10k_thermal thermal; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c new file mode 100644 index 000000000000..e98ce8ce27e2 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include "core.h" +#include "debug.h" +#include "wmi-ops.h" + +static int ath10k_thermal_get_active_vifs(struct ath10k *ar, + enum wmi_vdev_type type) +{ + struct ath10k_vif *arvif; + int count = 0; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (!arvif->is_started) + continue; + + if (!arvif->is_up) + continue; + + if (arvif->vdev_type != type) + continue; + + count++; + } + return count; +} + +static int ath10k_thermal_get_max_dutycycle(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = ATH10K_QUIET_DUTY_CYCLE_MAX; + + return 0; +} + +static int ath10k_thermal_get_cur_dutycycle(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct ath10k *ar = cdev->devdata; + + mutex_lock(&ar->conf_mutex); + *state = ar->thermal.duty_cycle; + mutex_unlock(&ar->conf_mutex); + + return 0; +} + +static int ath10k_thermal_set_cur_dutycycle(struct thermal_cooling_device *cdev, + unsigned long duty_cycle) +{ + struct ath10k *ar = cdev->devdata; + u32 period, duration, enabled; + int num_bss, ret = 0; + + mutex_lock(&ar->conf_mutex); + if (ar->state != ATH10K_STATE_ON) { + ret = -ENETDOWN; + goto out; + } + + if (duty_cycle > ATH10K_QUIET_DUTY_CYCLE_MAX) { + ath10k_warn(ar, "duty cycle %ld is exceeding the limit %d\n", + duty_cycle, ATH10K_QUIET_DUTY_CYCLE_MAX); + ret = -EINVAL; + goto out; + } + /* TODO: Right now, thermal mitigation is handled only for single/multi + * vif AP mode. Since quiet param is not validated in STA mode, it needs + * to be investigated further to handle multi STA and multi-vif (AP+STA) + * mode properly. + */ + num_bss = ath10k_thermal_get_active_vifs(ar, WMI_VDEV_TYPE_AP); + if (!num_bss) { + ath10k_warn(ar, "no active AP interfaces\n"); + ret = -ENETDOWN; + goto out; + } + period = max(ATH10K_QUIET_PERIOD_MIN, + (ATH10K_QUIET_PERIOD_DEFAULT / num_bss)); + duration = period * (duty_cycle / 100); + enabled = duration ? 1 : 0; + + ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration, + ATH10K_QUIET_START_OFFSET, + enabled); + if (ret) { + ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n", + period, duration, enabled, ret); + goto out; + } + ar->thermal.duty_cycle = duty_cycle; +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static struct thermal_cooling_device_ops ath10k_thermal_ops = { + .get_max_state = ath10k_thermal_get_max_dutycycle, + .get_cur_state = ath10k_thermal_get_cur_dutycycle, + .set_cur_state = ath10k_thermal_set_cur_dutycycle, +}; + +int ath10k_thermal_register(struct ath10k *ar) +{ + struct thermal_cooling_device *cdev; + int ret; + + cdev = thermal_cooling_device_register("ath10k_thermal", ar, + &ath10k_thermal_ops); + + if (IS_ERR(cdev)) { + ath10k_err(ar, "failed to setup thermal device result: %ld\n", + PTR_ERR(cdev)); + return -EINVAL; + } + + ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj, + "cooling_device"); + if (ret) { + ath10k_err(ar, "failed to create thermal symlink\n"); + goto err_cooling_destroy; + } + + ar->thermal.cdev = cdev; + return 0; + +err_cooling_destroy: + thermal_cooling_device_unregister(cdev); + return ret; +} + +void ath10k_thermal_unregister(struct ath10k *ar) +{ + thermal_cooling_device_unregister(ar->thermal.cdev); + sysfs_remove_link(&ar->dev->kobj, "cooling_device"); +} diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h new file mode 100644 index 000000000000..e20bb87849ae --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/thermal.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _THERMAL_ +#define _THERMAL_ + +#define ATH10K_QUIET_PERIOD_DEFAULT 100 +#define ATH10K_QUIET_PERIOD_MIN 25 +#define ATH10K_QUIET_START_OFFSET 10 +#define ATH10K_QUIET_DUTY_CYCLE_MAX 70 + +struct ath10k_thermal { + struct thermal_cooling_device *cdev; + + /* protected by conf_mutex */ + u32 duty_cycle; +}; + +#ifdef CONFIG_THERMAL +int ath10k_thermal_register(struct ath10k *ar); +void ath10k_thermal_unregister(struct ath10k *ar); +#else +static inline int ath10k_thermal_register(struct ath10k *ar) +{ + return 0; +} + +static inline void ath10k_thermal_unregister(struct ath10k *ar) +{ +} +#endif +#endif /* _THERMAL_ */ -- cgit v1.2.1 From a57a6a2753ac4a85cb083dd32dc0be414d52e001 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 17 Dec 2014 12:22:17 +0200 Subject: ath10k: add wmi interface for pdev_get_temperature Add WMI command support for reading temperature from the target and corresponding WMI temperature event handler. The pdev_get_temperature command is currently supported in 10.2 firmware alone. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 17 +++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 ++ drivers/net/wireless/ath/ath10k/wmi.c | 35 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 13 ++++++++++++ 4 files changed, 67 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index feed0fe5e117..20e2c3002bb5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -118,6 +118,7 @@ struct wmi_ops { u32 period, u32 duration, u32 next_offset, u32 enabled); + struct sk_buff *(*gen_pdev_get_temperature)(struct ath10k *ar); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -840,4 +841,20 @@ ath10k_wmi_pdev_set_quiet_mode(struct ath10k *ar, u32 period, u32 duration, ar->wmi.cmd->pdev_set_quiet_mode_cmdid); } +static inline int +ath10k_wmi_pdev_get_temperature(struct ath10k *ar) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_get_temperature) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_get_temperature(ar); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_get_temperature_cmdid); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index e203dadf1c0f..4c050cec3966 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2044,6 +2044,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = { .force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID, .gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { @@ -2205,6 +2206,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, /* .gen_pdev_set_quiet_mode not implemented */ + /* .gen_pdev_get_temperature not implemented */ }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 77bb3313ca47..c2d7ac31fd78 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -145,6 +145,7 @@ static struct wmi_cmd_map wmi_cmd_map = { .force_fw_hang_cmdid = WMI_FORCE_FW_HANG_CMDID, .gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.X WMI cmd track */ @@ -267,6 +268,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, .gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.2.4 WMI cmd track */ @@ -388,6 +390,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, }; /* MAIN WMI VDEV param map */ @@ -843,6 +846,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, }; void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, @@ -3026,6 +3030,17 @@ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) return 0; } +static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb) +{ + const struct wmi_pdev_temperature_event *ev; + + ev = (struct wmi_pdev_temperature_event *)skb->data; + if (WARN_ON(skb->len < sizeof(*ev))) + return -EPROTO; + + return 0; +} + static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -3365,6 +3380,9 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_2_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_10_2_PDEV_TEMPERATURE_EVENTID: + ath10k_wmi_event_temperature(ar, skb); + break; case WMI_10_2_RTT_KEEPALIVE_EVENTID: case WMI_10_2_GPIO_INPUT_EVENTID: case WMI_10_2_PEER_RATECODE_LIST_EVENTID: @@ -4646,6 +4664,19 @@ ath10k_wmi_10_2_op_gen_peer_assoc(struct ath10k *ar, return skb; } +static struct sk_buff * +ath10k_wmi_10_2_op_gen_pdev_get_temperature(struct ath10k *ar) +{ + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, 0); + if (!skb) + return ERR_PTR(-ENOMEM); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev get temperature\n"); + return skb; +} + /* This function assumes the beacon is already DMA mapped */ static struct sk_buff * ath10k_wmi_op_gen_beacon_dma(struct ath10k_vif *arvif) @@ -4895,6 +4926,7 @@ static const struct wmi_ops wmi_ops = { .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + /* .gen_pdev_get_temperature not implemented */ }; static const struct wmi_ops wmi_10_1_ops = { @@ -4906,6 +4938,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, .gen_peer_assoc = ath10k_wmi_10_1_op_gen_peer_assoc, + /* .gen_pdev_get_temperature not implemented */ /* shared with main branch */ .pull_scan = ath10k_wmi_op_pull_scan_ev, @@ -4954,6 +4987,7 @@ static const struct wmi_ops wmi_10_2_ops = { .rx = ath10k_wmi_10_2_op_rx, .gen_init = ath10k_wmi_10_2_op_gen_init, .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, + /* .gen_pdev_get_temperature not implemented */ /* shared with 10.1 */ .map_svc = wmi_10x_svc_map, @@ -5008,6 +5042,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .rx = ath10k_wmi_10_2_op_rx, .gen_init = ath10k_wmi_10_2_op_gen_init, .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, + .gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature, /* shared with 10.1 */ .map_svc = wmi_10x_svc_map, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 7f34093f6778..bd7f29a3a122 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -550,6 +550,7 @@ struct wmi_cmd_map { u32 force_fw_hang_cmdid; u32 gpio_config_cmdid; u32 gpio_output_cmdid; + u32 pdev_get_temperature_cmdid; }; /* @@ -1154,6 +1155,11 @@ enum wmi_10_2_cmd_id { WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID, WMI_10_2_PDEV_RATEPWR_TABLE_CMDID, WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, + WMI_10_2_PDEV_GET_INFO, + WMI_10_2_VDEV_GET_INFO, + WMI_10_2_VDEV_ATF_REQUEST_CMDID, + WMI_10_2_PEER_ATF_REQUEST_CMDID, + WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1, }; @@ -1195,6 +1201,8 @@ enum wmi_10_2_event_id { WMI_10_2_MCAST_BUF_RELEASE_EVENTID, WMI_10_2_MCAST_LIST_AGEOUT_EVENTID, WMI_10_2_WDS_PEER_EVENTID, + WMI_10_2_PEER_STA_PS_STATECHG_EVENTID, + WMI_10_2_PDEV_TEMPERATURE_EVENTID, WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1, }; @@ -4740,6 +4748,11 @@ struct wmi_rdy_ev_arg { const u8 *mac_addr; }; +struct wmi_pdev_temperature_event { + /* temperature value in Celcius degree */ + __le32 temperature; +} __packed; + struct ath10k; struct ath10k_vif; struct ath10k_fw_stats_pdev; -- cgit v1.2.1 From ac2953fcc35871181bfafb11238b757ae1a4ce9f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 17 Dec 2014 12:22:26 +0200 Subject: ath10k: add thermal sensor device support Temperature sensor generates electrical analog voltage from temperature of each chain. The analog voltage is converted to digital value through ADC. For reading temperature values fom user space, hw monitoring device is used. Whenever the user requests for current temperature, the driver sends WMI command and wait for response. For reading temperature, cat /sys/class/ieee80211/phy*/device/hwmon/hwmon2/temp1_input Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 + drivers/net/wireless/ath/ath10k/thermal.c | 83 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/thermal.h | 14 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 1 + 4 files changed, 100 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 70d53e65c53d..2d0671ebcf2b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -844,6 +844,7 @@ static void ath10k_core_restart(struct work_struct *work) complete_all(&ar->offchan_tx_completed); complete_all(&ar->install_key_done); complete_all(&ar->vdev_setup_done); + complete_all(&ar->thermal.wmi_sync); wake_up(&ar->htt.empty_tx_wq); wake_up(&ar->wmi.tx_credits_wq); wake_up(&ar->peer_mapping_wq); @@ -1316,6 +1317,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, init_completion(&ar->install_key_done); init_completion(&ar->vdev_setup_done); + init_completion(&ar->thermal.wmi_sync); INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work); diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index e98ce8ce27e2..d93913538d18 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "core.h" #include "debug.h" #include "wmi-ops.h" @@ -119,9 +121,72 @@ static struct thermal_cooling_device_ops ath10k_thermal_ops = { .set_cur_state = ath10k_thermal_set_cur_dutycycle, }; +static ssize_t ath10k_thermal_show_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ath10k *ar = dev_get_drvdata(dev); + int ret, temperature; + + mutex_lock(&ar->conf_mutex); + + /* Can't get temperature when the card is off */ + if (ar->state != ATH10K_STATE_ON) { + ret = -ENETDOWN; + goto out; + } + + reinit_completion(&ar->thermal.wmi_sync); + ret = ath10k_wmi_pdev_get_temperature(ar); + if (ret) { + ath10k_warn(ar, "failed to read temperature %d\n", ret); + goto out; + } + + if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { + ret = -ESHUTDOWN; + goto out; + } + + ret = wait_for_completion_timeout(&ar->thermal.wmi_sync, + ATH10K_THERMAL_SYNC_TIMEOUT_HZ); + if (ret == 0) { + ath10k_warn(ar, "failed to synchronize thermal read\n"); + ret = -ETIMEDOUT; + goto out; + } + + spin_lock_bh(&ar->data_lock); + temperature = ar->thermal.temperature; + spin_unlock_bh(&ar->data_lock); + + ret = snprintf(buf, PAGE_SIZE, "%d", temperature); +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature) +{ + spin_lock_bh(&ar->data_lock); + ar->thermal.temperature = temperature; + spin_unlock_bh(&ar->data_lock); + complete(&ar->thermal.wmi_sync); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ath10k_thermal_show_temp, + NULL, 0); + +static struct attribute *ath10k_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(ath10k_hwmon); + int ath10k_thermal_register(struct ath10k *ar) { struct thermal_cooling_device *cdev; + struct device *hwmon_dev; int ret; cdev = thermal_cooling_device_register("ath10k_thermal", ar, @@ -141,8 +206,26 @@ int ath10k_thermal_register(struct ath10k *ar) } ar->thermal.cdev = cdev; + + /* Do not register hwmon device when temperature reading is not + * supported by firmware + */ + if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4) + return 0; + + hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev, + "ath10k_hwmon", ar, + ath10k_hwmon_groups); + if (IS_ERR(hwmon_dev)) { + ath10k_err(ar, "failed to register hwmon device: %ld\n", + PTR_ERR(hwmon_dev)); + ret = -EINVAL; + goto err_remove_link; + } return 0; +err_remove_link: + sysfs_remove_link(&ar->dev->kobj, "thermal_sensor"); err_cooling_destroy: thermal_cooling_device_unregister(cdev); return ret; diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h index e20bb87849ae..bccc17ae0fde 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.h +++ b/drivers/net/wireless/ath/ath10k/thermal.h @@ -20,17 +20,25 @@ #define ATH10K_QUIET_PERIOD_MIN 25 #define ATH10K_QUIET_START_OFFSET 10 #define ATH10K_QUIET_DUTY_CYCLE_MAX 70 +#define ATH10K_HWMON_NAME_LEN 15 +#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ) struct ath10k_thermal { struct thermal_cooling_device *cdev; + struct completion wmi_sync; /* protected by conf_mutex */ u32 duty_cycle; + /* temperature value in Celcius degree + * protected by data_lock + */ + int temperature; }; #ifdef CONFIG_THERMAL int ath10k_thermal_register(struct ath10k *ar); void ath10k_thermal_unregister(struct ath10k *ar); +void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature); #else static inline int ath10k_thermal_register(struct ath10k *ar) { @@ -40,5 +48,11 @@ static inline int ath10k_thermal_register(struct ath10k *ar) static inline void ath10k_thermal_unregister(struct ath10k *ar) { } + +static inline void ath10k_thermal_event_temperature(struct ath10k *ar, + int temperature) +{ +} + #endif #endif /* _THERMAL_ */ diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c2d7ac31fd78..ac742905331b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3038,6 +3038,7 @@ static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb) if (WARN_ON(skb->len < sizeof(*ev))) return -EPROTO; + ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature)); return 0; } -- cgit v1.2.1 From 627d9841eaa623e34657af7af0e6293805e07888 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 17 Dec 2014 12:29:54 +0200 Subject: ath10k: fix low TX rates when IBSS and HT This fix TX problem when IBSS used in HT mode. Before we used 6Mbps all the time for TX direction. Reported-by: Yeoh Chun-Yeow Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 31354dbebd02..719e599dd8e0 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1468,9 +1468,16 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, if (vif->bss_conf.qos) arg->peer_flags |= WMI_PEER_QOS; break; + case WMI_VDEV_TYPE_IBSS: + if (sta->wme) + arg->peer_flags |= WMI_PEER_QOS; + break; default: break; } + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n", + sta->addr, !!(arg->peer_flags & WMI_PEER_QOS)); } static bool ath10k_mac_sta_has_11g_rates(struct ieee80211_sta *sta) -- cgit v1.2.1 From 55884c045d31a29cf69db8332d1064a1b61dd159 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 17 Dec 2014 12:30:02 +0200 Subject: ath10k: send (re)assoc peer command when NSS changed Assoc peer command contain information about NSS. When we will get IEEE80211_RC_NSS_CHANGED we should also send (re) assoc peer command to be sure firmware will know about it and RC will work correctly. This was found during code review. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 719e599dd8e0..827faf07332a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3659,8 +3659,9 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, smps, err); } - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", + if (changed & IEEE80211_RC_SUPP_RATES_CHANGED || + changed & IEEE80211_RC_NSS_CHANGED) { + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n", sta->addr); err = ath10k_station_assoc(ar, arvif->vif, sta, true); -- cgit v1.2.1 From 6faab1273f79788a7d90f8c3c99b9b8f3b404c98 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Thu, 18 Dec 2014 10:13:00 -0800 Subject: ath10k: set phymode to 11b when NO_OFDM flag set phymode should use 11b only if NO_OFDM flags is set. Hence check up channel flag for NO_OFDM and set to 11b. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 827faf07332a..5085f558d010 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -269,7 +269,10 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef) case IEEE80211_BAND_2GHZ: switch (chandef->width) { case NL80211_CHAN_WIDTH_20_NOHT: - phymode = MODE_11G; + if (chandef->chan->flags & IEEE80211_CHAN_NO_OFDM) + phymode = MODE_11B; + else + phymode = MODE_11G; break; case NL80211_CHAN_WIDTH_20: phymode = MODE_11NG_HT20; -- cgit v1.2.1 From 18e0c0bf3a5ea0f54384149570274d535341dc06 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 7 Dec 2014 23:00:13 +0100 Subject: rtlwifi: rtl8192de: fw.c: Remove unused function Remove the function rtl92d_set_fw_pwrmode_cmd() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192de/fw.c | 17 ----------------- drivers/net/wireless/rtlwifi/rtl8192de/fw.h | 1 - 2 files changed, 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c index 23177076b97f..62ef8209718f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c @@ -540,23 +540,6 @@ void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, return; } -void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 u1_h2c_set_pwrmode[3] = { 0 }; - struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); - SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode); - SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1); - SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, - ppsc->reg_max_lps_awakeintvl); - RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, - "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode", - u1_h2c_set_pwrmode, 3); - rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); -} - static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h index a55a803a0b4d..1646e7c3d0f8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h @@ -136,7 +136,6 @@ int rtl92d_download_fw(struct ieee80211_hw *hw); void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); void rtl92d_firmware_selfreset(struct ieee80211_hw *hw); -void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); -- cgit v1.2.1 From eae79b4f3e82ca63a53478a161b190a0d38fe526 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 13 Dec 2014 00:43:55 +0300 Subject: rsi: fix memory leak in rsi_load_ta_instructions() Memory allocated by kmemdup() in rsi_load_ta_instructions() is leaked. But duplication of firmware data here is useless, so the patch removes kmemdup() at all. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 4834a9abc171..b6cc9ff47fc2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -172,7 +172,6 @@ static int rsi_load_ta_instructions(struct rsi_common *common) (struct rsi_91x_sdiodev *)adapter->rsi_dev; u32 len; u32 num_blocks; - const u8 *fw; const struct firmware *fw_entry = NULL; u32 block_size = dev->tx_blk_size; int status = 0; @@ -201,7 +200,6 @@ static int rsi_load_ta_instructions(struct rsi_common *common) return status; } - fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); len = fw_entry->size; if (len % 4) @@ -212,7 +210,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common) rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); - status = rsi_copy_to_card(common, fw, len, num_blocks); + status = rsi_copy_to_card(common, fw_entry->data, len, num_blocks); release_firmware(fw_entry); return status; } -- cgit v1.2.1 From a844bae38bf8c07ce18944d8b3d484911d75c8dd Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Mon, 15 Dec 2014 10:55:34 -0800 Subject: ath: fix incorrect PPB on FCC radar type 5 The minimum number of pulses per burst on FCC radar type 5 is 1. Use this number for correct radar detection. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/dfs_pattern_detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index cfd0554cf140..3d57f8772389 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c @@ -86,7 +86,7 @@ static const struct radar_detector_specs fcc_radar_ref_types[] = { FCC_PATTERN(1, 0, 5, 150, 230, 1, 23), FCC_PATTERN(2, 6, 10, 200, 500, 1, 16), FCC_PATTERN(3, 11, 20, 200, 500, 1, 12), - FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 20), + FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 1), FCC_PATTERN(5, 0, 1, 333, 333, 1, 9), }; -- cgit v1.2.1 From fe89707f0afa17edbb1bf8381fea1d2457aeebaa Mon Sep 17 00:00:00 2001 From: Troy Tan Date: Thu, 18 Dec 2014 03:05:25 -0600 Subject: rtlwifi: rtl8821ae: Simplify loading of WOWLAN firmware The existing method for loading both normal and WOWLAN firmware for the device duplicates a lot of code. This solution is much cleaner. Signed-off-by: Troy Tan Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/core.c | 24 +++++++++- drivers/net/wireless/rtlwifi/core.h | 1 + drivers/net/wireless/rtlwifi/rtl8821ae/sw.c | 74 ++++++++++------------------- drivers/net/wireless/rtlwifi/wifi.h | 3 +- 4 files changed, 48 insertions(+), 54 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 5fc6f52641bd..deab85236bfd 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -95,7 +95,8 @@ void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data) } EXPORT_SYMBOL(rtl_bb_delay); -void rtl_fw_cb(const struct firmware *firmware, void *context) +static void rtl_fw_do_work(const struct firmware *firmware, void *context, + bool is_wow) { struct ieee80211_hw *hw = context; struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -125,12 +126,31 @@ found_alt: release_firmware(firmware); return; } - memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); + if (!is_wow) { + memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, + firmware->size); + rtlpriv->rtlhal.fwsize = firmware->size; + } else { + memcpy(rtlpriv->rtlhal.wowlan_firmware, firmware->data, + firmware->size); + rtlpriv->rtlhal.wowlan_fwsize = firmware->size; + } rtlpriv->rtlhal.fwsize = firmware->size; release_firmware(firmware); } + +void rtl_fw_cb(const struct firmware *firmware, void *context) +{ + rtl_fw_do_work(firmware, context, false); +} EXPORT_SYMBOL(rtl_fw_cb); +void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context) +{ + rtl_fw_do_work(firmware, context, true); +} +EXPORT_SYMBOL(rtl_wowlan_fw_cb); + /*mutex for start & stop is must here. */ static int rtl_op_start(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index 624e1dc16d31..8c87eb54be66 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h @@ -37,6 +37,7 @@ extern const struct ieee80211_ops rtl_ops; void rtl_fw_cb(const struct firmware *firmware, void *context); +void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context); void rtl_addr_delay(u32 addr); void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, u32 mask, u32 data); diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c index fc92dd6a0d07..a4988121e1ab 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c @@ -85,52 +85,6 @@ static void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw) rtlpci->const_support_pciaspm = 1; } -static void load_wowlan_fw(struct rtl_priv *rtlpriv) -{ - /* callback routine to load wowlan firmware after main fw has - * been loaded - */ - const struct firmware *wowlan_firmware; - char *fw_name = NULL; - int err; - - /* for wowlan firmware buf */ - rtlpriv->rtlhal.wowlan_firmware = vzalloc(0x8000); - if (!rtlpriv->rtlhal.wowlan_firmware) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Can't alloc buffer for wowlan fw.\n"); - return; - } - - if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE) - fw_name = "rtlwifi/rtl8821aefw_wowlan.bin"; - else - fw_name = "rtlwifi/rtl8812aefw_wowlan.bin"; - err = request_firmware(&wowlan_firmware, fw_name, rtlpriv->io.dev); - if (err) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Failed to request wowlan firmware!\n"); - goto error; - } - - if (wowlan_firmware->size > 0x8000) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Wowlan Firmware is too big!\n"); - goto error; - } - - memcpy(rtlpriv->rtlhal.wowlan_firmware, wowlan_firmware->data, - wowlan_firmware->size); - rtlpriv->rtlhal.wowlan_fwsize = wowlan_firmware->size; - release_firmware(wowlan_firmware); - - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "WOWLAN FirmwareDownload OK\n"); - return; -error: - release_firmware(wowlan_firmware); - vfree(rtlpriv->rtlhal.wowlan_firmware); -} - /*InitializeVariables8812E*/ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) { @@ -231,7 +185,6 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) else if (rtlpriv->psc.reg_fwctrl_lps == 3) rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; - rtlpriv->rtl_fw_second_cb = load_wowlan_fw; /* for firmware buf */ rtlpriv->rtlhal.pfirmware = vzalloc(0x8000); if (!rtlpriv->rtlhal.pfirmware) { @@ -239,20 +192,41 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) "Can't alloc buffer for fw.\n"); return 1; } + rtlpriv->rtlhal.wowlan_firmware = vzalloc(0x8000); + if (!rtlpriv->rtlhal.wowlan_firmware) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Can't alloc buffer for wowlan fw.\n"); + return 1; + } - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { rtlpriv->cfg->fw_name = "rtlwifi/rtl8812aefw.bin"; - else + rtlpriv->cfg->wowlan_fw_name = "rtlwifi/rtl8812aefw_wowlan.bin"; + } else { rtlpriv->cfg->fw_name = "rtlwifi/rtl8821aefw.bin"; + rtlpriv->cfg->wowlan_fw_name = "rtlwifi/rtl8821aefw_wowlan.bin"; + } rtlpriv->max_fw_size = 0x8000; + /*load normal firmware*/ pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Failed to request firmware!\n"); + "Failed to request normal firmware!\n"); + return 1; + } + /*load wowlan firmware*/ + pr_info("Using firmware %s\n", rtlpriv->cfg->wowlan_fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, + rtlpriv->cfg->wowlan_fw_name, + rtlpriv->io.dev, GFP_KERNEL, hw, + rtl_wowlan_fw_cb); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to request wowlan firmware!\n"); return 1; } return 0; diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 6866dcf24340..a233b26ac134 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -2242,6 +2242,7 @@ struct rtl_hal_cfg { char *name; char *fw_name; char *alt_fw_name; + char *wowlan_fw_name; struct rtl_hal_ops *ops; struct rtl_mod_params *mod_params; struct rtl_hal_usbint_cfg *usb_interface_cfg; @@ -2518,8 +2519,6 @@ struct proxim { struct rtl_priv { struct ieee80211_hw *hw; - /* Used to load a second firmware */ - void (*rtl_fw_second_cb)(struct rtl_priv *rtlpriv); struct completion firmware_loading_complete; struct list_head list; struct rtl_priv *buddy_priv; -- cgit v1.2.1 From f091282fd367faa014ebc2aa0a2fd178a48b476d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:26 -0600 Subject: rtlwifi: rtl8821ae: Fix typos in power-sequence macro Two of the macros that control power sequencing have values to be set that contain bits that are not covered by the associated mask. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h index bf0b0ce9519c..36b3e91d996e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h @@ -93,9 +93,9 @@ #define RTL8812_TRANS_CARDEMU_TO_SUS \ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\ - PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc}, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xc0}, \ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\ - PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC}, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xE0}, \ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07 \ /* gpio11 input mode, gpio10~8 output mode */}, \ -- cgit v1.2.1 From 1ed03272b58f1ed6545b99dde39c42358156af69 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:27 -0600 Subject: rtlwifi: rtl8192ce: Add code to set the keep-alive operation This change helps the device maintain a connection. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h | 1 + drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h index b64ae45dc674..e9f4281f5067 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h @@ -37,6 +37,7 @@ #define FW_8192C_POLLING_DELAY 5 #define FW_8192C_POLLING_TIMEOUT_COUNT 100 #define NORMAL_CHIP BIT(4) +#define H2C_92C_KEEP_ALIVE_CTRL 48 #define IS_FW_HEADER_EXIST(_pfwhdr) \ ((le16_to_cpu(_pfwhdr->signature)&0xFFF0) == 0x92C0 ||\ diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 5c646d5f7bb8..b63b78b772b9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -544,8 +544,13 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) (u8 *)(&fw_current_inps)); } break; } - case HW_VAR_KEEP_ALIVE: - break; + case HW_VAR_KEEP_ALIVE: { + u8 array[2]; + + array[0] = 0xff; + array[1] = *((u8 *)val); + rtl92c_fill_h2c_cmd(hw, H2C_92C_KEEP_ALIVE_CTRL, 2, array); + break; } default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "switch case %d not processed\n", variable); -- cgit v1.2.1 From 9d62c5531b515ef427cee13cca87777dba617c94 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:28 -0600 Subject: rtlwifi: rtl8192ce: Update setting of the media status This patch applies changes found in the latest vendor driver. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 51 ++++++++++++++++++----------- 1 file changed, 31 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index b63b78b772b9..2ee778ae202d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -1161,36 +1161,24 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); u8 bt_msr = rtl_read_byte(rtlpriv, MSR); enum led_ctl_mode ledaction = LED_CTL_NO_LINK; - bt_msr &= 0xfc; + u8 mode = MSR_NOLINK; - if (type == NL80211_IFTYPE_UNSPECIFIED || - type == NL80211_IFTYPE_STATION) { - _rtl92ce_stop_tx_beacon(hw); - _rtl92ce_enable_bcn_sub_func(hw); - } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP || - type == NL80211_IFTYPE_MESH_POINT) { - _rtl92ce_resume_tx_beacon(hw); - _rtl92ce_disable_bcn_sub_func(hw); - } else { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "Set HW_VAR_MEDIA_STATUS: No such media status(%x)\n", - type); - } + bt_msr &= 0xfc; switch (type) { case NL80211_IFTYPE_UNSPECIFIED: - bt_msr |= MSR_NOLINK; + mode = MSR_NOLINK; ledaction = LED_CTL_LINK; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to NO LINK!\n"); break; case NL80211_IFTYPE_ADHOC: - bt_msr |= MSR_ADHOC; + mode = MSR_ADHOC; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to Ad Hoc!\n"); break; case NL80211_IFTYPE_STATION: - bt_msr |= MSR_INFRA; + mode = MSR_INFRA; ledaction = LED_CTL_LINK; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to STA!\n"); @@ -1201,7 +1189,7 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, "Set Network type to AP!\n"); break; case NL80211_IFTYPE_MESH_POINT: - bt_msr |= MSR_ADHOC; + mode = MSR_ADHOC; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to Mesh Point!\n"); break; @@ -1212,9 +1200,32 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, } - rtl_write_byte(rtlpriv, (MSR), bt_msr); + /* MSR_INFRA == Link in infrastructure network; + * MSR_ADHOC == Link in ad hoc network; + * Therefore, check link state is necessary. + * + * MSR_AP == AP mode; link state does not matter here. + */ + if (mode != MSR_AP && + rtlpriv->mac80211.link_state < MAC80211_LINKED) { + mode = MSR_NOLINK; + ledaction = LED_CTL_NO_LINK; + } + if (mode == MSR_NOLINK || mode == MSR_INFRA) { + _rtl92ce_stop_tx_beacon(hw); + _rtl92ce_enable_bcn_sub_func(hw); + } else if (mode == MSR_ADHOC || mode == MSR_AP) { + _rtl92ce_resume_tx_beacon(hw); + _rtl92ce_disable_bcn_sub_func(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n", + mode); + } + rtl_write_byte(rtlpriv, (MSR), bt_msr | mode); + rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & MSR_MASK) == MSR_AP) + if (mode == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); -- cgit v1.2.1 From ff6ee6b0ce1f62936a916ef1c33015a2ec48925e Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:29 -0600 Subject: rtlwifi: rtl8192ce: Update rate setting routines These changes were found in the latest vendor driver. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 107 ++++++++++++---------------- 1 file changed, 44 insertions(+), 63 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 2ee778ae202d..303b299376c9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -1168,7 +1168,6 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, switch (type) { case NL80211_IFTYPE_UNSPECIFIED: mode = MSR_NOLINK; - ledaction = LED_CTL_LINK; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to NO LINK!\n"); break; @@ -1184,7 +1183,8 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, "Set Network type to STA!\n"); break; case NL80211_IFTYPE_AP: - bt_msr |= MSR_AP; + mode = MSR_AP; + ledaction = LED_CTL_LINK; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to AP!\n"); break; @@ -1222,7 +1222,7 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n", mode); } - rtl_write_byte(rtlpriv, (MSR), bt_msr | mode); + rtl_write_byte(rtlpriv, MSR, bt_msr | mode); rtlpriv->cfg->ops->led_control(hw, ledaction); if (mode == MSR_AP) @@ -1849,7 +1849,6 @@ static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw, u32 ratr_value; u8 ratr_index = 0; u8 nmode = mac->ht_enable; - u8 mimo_ps = IEEE80211_SMPS_OFF; u16 shortgi_rate; u32 tmp_ratr_value; u8 curtxbw_40mhz = mac->bw_40; @@ -1858,6 +1857,7 @@ static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw, u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? 1 : 0; enum wireless_mode wirelessmode = mac->mode; + u32 ratr_mask; if (rtlhal->current_bandtype == BAND_ON_5G) ratr_value = sta->supp_rates[1] << 4; @@ -1881,19 +1881,13 @@ static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw, case WIRELESS_MODE_N_24G: case WIRELESS_MODE_N_5G: nmode = 1; - if (mimo_ps == IEEE80211_SMPS_STATIC) { - ratr_value &= 0x0007F005; - } else { - u32 ratr_mask; - - if (get_rf_type(rtlphy) == RF_1T2R || - get_rf_type(rtlphy) == RF_1T1R) - ratr_mask = 0x000ff005; - else - ratr_mask = 0x0f0ff005; + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) + ratr_mask = 0x000ff005; + else + ratr_mask = 0x0f0ff005; - ratr_value &= ratr_mask; - } + ratr_value &= ratr_mask; break; default: if (rtlphy->rf_type == RF_1T2R) @@ -1946,17 +1940,16 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, struct rtl_sta_info *sta_entry = NULL; u32 ratr_bitmap; u8 ratr_index; - u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; - u8 curshortgi_40mhz = curtxbw_40mhz && - (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? - 1 : 0; + u8 curtxbw_40mhz = (sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & + IEEE80211_HT_CAP_SGI_40) ? 1 : 0; u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? 1 : 0; enum wireless_mode wirelessmode = 0; bool shortgi = false; u8 rate_mask[5]; u8 macid = 0; - u8 mimo_ps = IEEE80211_SMPS_OFF; sta_entry = (struct rtl_sta_info *) sta->drv_priv; wirelessmode = sta_entry->wireless_mode; @@ -2001,47 +1994,38 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, case WIRELESS_MODE_N_5G: ratr_index = RATR_INX_WIRELESS_NGB; - if (mimo_ps == IEEE80211_SMPS_STATIC) { - if (rssi_level == 1) - ratr_bitmap &= 0x00070000; - else if (rssi_level == 2) - ratr_bitmap &= 0x0007f000; - else - ratr_bitmap &= 0x0007f005; + if (rtlphy->rf_type == RF_1T2R || + rtlphy->rf_type == RF_1T1R) { + if (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x000f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x000ff000; + else + ratr_bitmap &= 0x000ff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x000f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x000ff000; + else + ratr_bitmap &= 0x000ff005; + } } else { - if (rtlphy->rf_type == RF_1T2R || - rtlphy->rf_type == RF_1T1R) { - if (curtxbw_40mhz) { - if (rssi_level == 1) - ratr_bitmap &= 0x000f0000; - else if (rssi_level == 2) - ratr_bitmap &= 0x000ff000; - else - ratr_bitmap &= 0x000ff015; - } else { - if (rssi_level == 1) - ratr_bitmap &= 0x000f0000; - else if (rssi_level == 2) - ratr_bitmap &= 0x000ff000; - else - ratr_bitmap &= 0x000ff005; - } + if (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff015; } else { - if (curtxbw_40mhz) { - if (rssi_level == 1) - ratr_bitmap &= 0x0f0f0000; - else if (rssi_level == 2) - ratr_bitmap &= 0x0f0ff000; - else - ratr_bitmap &= 0x0f0ff015; - } else { - if (rssi_level == 1) - ratr_bitmap &= 0x0f0f0000; - else if (rssi_level == 2) - ratr_bitmap &= 0x0f0ff000; - else - ratr_bitmap &= 0x0f0ff005; - } + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff005; } } @@ -2074,9 +2058,6 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, "Rate_index:%x, ratr_val:%x, %5phC\n", ratr_index, ratr_bitmap, rate_mask); rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); - - if (macid != 0) - sta_entry->ratr_index = ratr_index; } void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw, -- cgit v1.2.1 From 99057920a2f7360977979dc4c2ba60d5f9dc9e23 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:30 -0600 Subject: rtlwifi: rtl8192ce: Improve RF sleep routine These changes match those of the latest vendor driver. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ce/phy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index bc5ca989b915..1ee5a6ae9960 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -518,11 +518,12 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, } case ERFSLEEP:{ if (ppsc->rfpwr_state == ERFOFF) - return false; + break; for (queue_id = 0, i = 0; queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { ring = &pcipriv->dev.tx_ring[queue_id]; - if (skb_queue_len(&ring->queue) == 0) { + if (queue_id == BEACON_QUEUE || + skb_queue_len(&ring->queue) == 0) { queue_id++; continue; } else { -- cgit v1.2.1 From f1f21770b11ca83d688b2791b163c2b892ca6fa6 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:31 -0600 Subject: rtlwifi: Remove extraneous argument for rate mapping Four of the drivers (92ce, 92cu, 92de, and 92se) supply an argument to the rate-mapping routine that is never used, thus it can be removed. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/base.c | 2 +- drivers/net/wireless/rtlwifi/base.h | 2 +- drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 5 ++--- drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | 6 ++---- drivers/net/wireless/rtlwifi/rtl8192de/trx.c | 3 +-- drivers/net/wireless/rtlwifi/rtl8192se/trx.c | 11 +++++------ 6 files changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 40b6d1d006d7..d4c8e95f22de 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -883,7 +883,7 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw, * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15 */ int rtlwifi_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate, bool first_ampdu) + bool isht, u8 desc_rate) { int rate_idx; diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index 982f2450feea..936c2bba54d4 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -124,7 +124,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw); bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); int rtlwifi_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate, bool first_ampdu); + bool isht, u8 desc_rate); bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index e88dcd0e0af1..d25aeeb60b09 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -400,9 +400,8 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, * are use (RX_FLAG_HT) * Notice: this is diff with windows define */ - rx_status->rate_idx = rtlwifi_rate_mapping(hw, - stats->is_ht, stats->rate, - stats->isfirst_ampdu); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, + stats->rate); rx_status->mactime = stats->timestamp_low; if (phystatus) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index f383d5f1fed5..fa30b260e5ba 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -340,8 +340,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, rx_status->flag |= RX_FLAG_DECRYPTED; rx_status->rate_idx = rtlwifi_rate_mapping(hw, (bool)GET_RX_DESC_RX_HT(pdesc), - (u8)GET_RX_DESC_RX_MCS(pdesc), - (bool)GET_RX_DESC_PAGGR(pdesc)); + (u8)GET_RX_DESC_RX_MCS(pdesc)); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { p_drvinfo = (struct rx_fwinfo_92c *)(skb->data + @@ -408,8 +407,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) /* Data rate */ rx_status->rate_idx = rtlwifi_rate_mapping(hw, (bool)GET_RX_DESC_RX_HT(rxdesc), - (u8)GET_RX_DESC_RX_MCS(rxdesc), - (bool)GET_RX_DESC_PAGGR(rxdesc)); + (u8)GET_RX_DESC_RX_MCS(rxdesc)); /* There is a phy status after this rx descriptor. */ if (GET_RX_DESC_PHY_STATUS(rxdesc)) { p_drvinfo = (struct rx_fwinfo_92c *)(rxdesc + RTL_RX_DESC_SIZE); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index 8efbcc7af250..7fbae49b53b6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -514,8 +514,7 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, rx_status->flag |= RX_FLAG_DECRYPTED; rx_status->rate_idx = rtlwifi_rate_mapping(hw, (bool)GET_RX_DESC_RXHT(pdesc), - (u8)GET_RX_DESC_RXMCS(pdesc), - (bool)GET_RX_DESC_PAGGR(pdesc)); + (u8)GET_RX_DESC_RXMCS(pdesc)); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { p_drvinfo = (struct rx_fwinfo_92d *)(skb->data + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index 672fd3b02835..da053cbdf621 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -264,7 +264,6 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct rx_fwinfo *p_drvinfo; u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc); struct ieee80211_hdr *hdr; - bool first_ampdu = false; stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc); stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8; @@ -319,8 +318,8 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, rx_status->flag |= RX_FLAG_DECRYPTED; } - rx_status->rate_idx = rtlwifi_rate_mapping(hw, - stats->is_ht, stats->rate, first_ampdu); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, + stats->rate); rx_status->mactime = stats->timestamp_low; if (phystatus) { @@ -398,9 +397,9 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, if (rtlhal->version == VERSION_8192S_ACUT) { if (ptcb_desc->hw_rate == DESC92_RATE1M || - ptcb_desc->hw_rate == DESC92_RATE2M || - ptcb_desc->hw_rate == DESC92_RATE5_5M || - ptcb_desc->hw_rate == DESC92_RATE11M) { + ptcb_desc->hw_rate == DESC92_RATE2M || + ptcb_desc->hw_rate == DESC92_RATE5_5M || + ptcb_desc->hw_rate == DESC92_RATE11M) { ptcb_desc->hw_rate = DESC92_RATE12M; } } -- cgit v1.2.1 From 7e0dde9248c413485aa2eb2079782d8941f062c8 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:32 -0600 Subject: rtlwifi: rtl8723be: Switch to use common rate-mapping routine This driver currently has its owm version of this routine that duplicates a routine in rtlwifi. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8723be/trx.c | 160 +-------------------------- 1 file changed, 1 insertion(+), 159 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c index d6a1c70cb657..cb23bed34706 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c @@ -47,164 +47,6 @@ static u8 _rtl8723be_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -/* mac80211's rate_idx is like this: - * - * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ - * - * B/G rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - * - * 5G band:rx_status->band == IEEE80211_BAND_5GHZ - * A rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - */ -static int _rtl8723be_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate) -{ - int rate_idx; - - if (!isht) { - if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - switch (desc_rate) { - case DESC92C_RATE6M: - rate_idx = 0; - break; - case DESC92C_RATE9M: - rate_idx = 1; - break; - case DESC92C_RATE12M: - rate_idx = 2; - break; - case DESC92C_RATE18M: - rate_idx = 3; - break; - case DESC92C_RATE24M: - rate_idx = 4; - break; - case DESC92C_RATE36M: - rate_idx = 5; - break; - case DESC92C_RATE48M: - rate_idx = 6; - break; - case DESC92C_RATE54M: - rate_idx = 7; - break; - default: - rate_idx = 0; - break; - } - } - } else { - switch (desc_rate) { - case DESC92C_RATEMCS0: - rate_idx = 0; - break; - case DESC92C_RATEMCS1: - rate_idx = 1; - break; - case DESC92C_RATEMCS2: - rate_idx = 2; - break; - case DESC92C_RATEMCS3: - rate_idx = 3; - break; - case DESC92C_RATEMCS4: - rate_idx = 4; - break; - case DESC92C_RATEMCS5: - rate_idx = 5; - break; - case DESC92C_RATEMCS6: - rate_idx = 6; - break; - case DESC92C_RATEMCS7: - rate_idx = 7; - break; - case DESC92C_RATEMCS8: - rate_idx = 8; - break; - case DESC92C_RATEMCS9: - rate_idx = 9; - break; - case DESC92C_RATEMCS10: - rate_idx = 10; - break; - case DESC92C_RATEMCS11: - rate_idx = 11; - break; - case DESC92C_RATEMCS12: - rate_idx = 12; - break; - case DESC92C_RATEMCS13: - rate_idx = 13; - break; - case DESC92C_RATEMCS14: - rate_idx = 14; - break; - case DESC92C_RATEMCS15: - rate_idx = 15; - break; - default: - rate_idx = 0; - break; - } - } - return rate_idx; -} - static void _rtl8723be_query_rxphystatus(struct ieee80211_hw *hw, struct rtl_stats *pstatus, u8 *pdesc, struct rx_fwinfo_8723be *p_drvinfo, @@ -558,7 +400,7 @@ bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw, * supported rates or MCS index if HT rates * are use (RX_FLAG_HT) */ - rx_status->rate_idx = _rtl8723be_rate_mapping(hw, status->is_ht, + rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, status->rate); rx_status->mactime = status->timestamp_low; -- cgit v1.2.1 From 5b243feff35ab6050893741bc1a7016fa3ae5a8b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:33 -0600 Subject: rtlwifi: rtl8188ee: Switch to use common rate-mapping routine This driver duplicates a routine found in the core. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8188ee/trx.c | 162 +-------------------------- 1 file changed, 2 insertions(+), 160 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c index df549c96adef..d430884426ab 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c @@ -47,164 +47,6 @@ static u8 _rtl88ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -/* mac80211's rate_idx is like this: - * - * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ - * - * B/G rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - * - * 5G band:rx_status->band == IEEE80211_BAND_5GHZ - * A rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - */ -static int _rtl88ee_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate) -{ - int rate_idx; - - if (!isht) { - if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - switch (desc_rate) { - case DESC92C_RATE6M: - rate_idx = 0; - break; - case DESC92C_RATE9M: - rate_idx = 1; - break; - case DESC92C_RATE12M: - rate_idx = 2; - break; - case DESC92C_RATE18M: - rate_idx = 3; - break; - case DESC92C_RATE24M: - rate_idx = 4; - break; - case DESC92C_RATE36M: - rate_idx = 5; - break; - case DESC92C_RATE48M: - rate_idx = 6; - break; - case DESC92C_RATE54M: - rate_idx = 7; - break; - default: - rate_idx = 0; - break; - } - } - } else { - switch (desc_rate) { - case DESC92C_RATEMCS0: - rate_idx = 0; - break; - case DESC92C_RATEMCS1: - rate_idx = 1; - break; - case DESC92C_RATEMCS2: - rate_idx = 2; - break; - case DESC92C_RATEMCS3: - rate_idx = 3; - break; - case DESC92C_RATEMCS4: - rate_idx = 4; - break; - case DESC92C_RATEMCS5: - rate_idx = 5; - break; - case DESC92C_RATEMCS6: - rate_idx = 6; - break; - case DESC92C_RATEMCS7: - rate_idx = 7; - break; - case DESC92C_RATEMCS8: - rate_idx = 8; - break; - case DESC92C_RATEMCS9: - rate_idx = 9; - break; - case DESC92C_RATEMCS10: - rate_idx = 10; - break; - case DESC92C_RATEMCS11: - rate_idx = 11; - break; - case DESC92C_RATEMCS12: - rate_idx = 12; - break; - case DESC92C_RATEMCS13: - rate_idx = 13; - break; - case DESC92C_RATEMCS14: - rate_idx = 14; - break; - case DESC92C_RATEMCS15: - rate_idx = 15; - break; - default: - rate_idx = 0; - break; - } - } - return rate_idx; -} - static void _rtl88ee_query_rxphystatus(struct ieee80211_hw *hw, struct rtl_stats *pstatus, u8 *pdesc, struct rx_fwinfo_88e *p_drvinfo, @@ -630,8 +472,8 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw, * are use (RX_FLAG_HT) * Notice: this is diff with windows define */ - rx_status->rate_idx = _rtl88ee_rate_mapping(hw, - status->is_ht, status->rate); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, + status->rate); rx_status->mactime = status->timestamp_low; if (phystatus == true) { -- cgit v1.2.1 From 8d3fc3a64ba34d859d6bb0de76bd1860b234cd1c Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:34 -0600 Subject: rtlwifi: rtl8723ae: Modify driver to use rate-mapping routine in core This driver is also converted to use the rate-mapping code in the core. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | 162 +-------------------------- 1 file changed, 2 insertions(+), 160 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index d372ccaf3465..662a09461a6b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -45,164 +45,6 @@ static u8 _rtl8723e_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -/* mac80211's rate_idx is like this: - * - * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ - * - * B/G rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - * - * 5G band:rx_status->band == IEEE80211_BAND_5GHZ - * A rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - */ -static int _rtl8723e_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate) -{ - int rate_idx; - - if (!isht) { - if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - switch (desc_rate) { - case DESC92C_RATE6M: - rate_idx = 0; - break; - case DESC92C_RATE9M: - rate_idx = 1; - break; - case DESC92C_RATE12M: - rate_idx = 2; - break; - case DESC92C_RATE18M: - rate_idx = 3; - break; - case DESC92C_RATE24M: - rate_idx = 4; - break; - case DESC92C_RATE36M: - rate_idx = 5; - break; - case DESC92C_RATE48M: - rate_idx = 6; - break; - case DESC92C_RATE54M: - rate_idx = 7; - break; - default: - rate_idx = 0; - break; - } - } - } else { - switch (desc_rate) { - case DESC92C_RATEMCS0: - rate_idx = 0; - break; - case DESC92C_RATEMCS1: - rate_idx = 1; - break; - case DESC92C_RATEMCS2: - rate_idx = 2; - break; - case DESC92C_RATEMCS3: - rate_idx = 3; - break; - case DESC92C_RATEMCS4: - rate_idx = 4; - break; - case DESC92C_RATEMCS5: - rate_idx = 5; - break; - case DESC92C_RATEMCS6: - rate_idx = 6; - break; - case DESC92C_RATEMCS7: - rate_idx = 7; - break; - case DESC92C_RATEMCS8: - rate_idx = 8; - break; - case DESC92C_RATEMCS9: - rate_idx = 9; - break; - case DESC92C_RATEMCS10: - rate_idx = 10; - break; - case DESC92C_RATEMCS11: - rate_idx = 11; - break; - case DESC92C_RATEMCS12: - rate_idx = 12; - break; - case DESC92C_RATEMCS13: - rate_idx = 13; - break; - case DESC92C_RATEMCS14: - rate_idx = 14; - break; - case DESC92C_RATEMCS15: - rate_idx = 15; - break; - default: - rate_idx = 0; - break; - } - } - return rate_idx; -} - static void _rtl8723e_query_rxphystatus(struct ieee80211_hw *hw, struct rtl_stats *pstatus, u8 *pdesc, struct rx_fwinfo_8723e *p_drvinfo, @@ -503,8 +345,8 @@ bool rtl8723e_rx_query_desc(struct ieee80211_hw *hw, * are use (RX_FLAG_HT) * Notice: this is diff with windows define */ - rx_status->rate_idx = _rtl8723e_rate_mapping(hw, - status->is_ht, status->rate); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, + status->rate); rx_status->mactime = status->timestamp_low; if (phystatus == true) { -- cgit v1.2.1 From 7b7d0d60a558d80165a18c0eceb1cc7b0c7d6439 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:35 -0600 Subject: rtlwifi: rtl8192ee: Convert driver to use common rate-mapping code Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ee/trx.c | 163 +-------------------------- 1 file changed, 2 insertions(+), 161 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c index 2fcbef1d029f..fb46fb9c095e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c @@ -47,164 +47,6 @@ static u8 _rtl92ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -/* mac80211's rate_idx is like this: - * - * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ - * - * B/G rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - * - * 5G band:rx_status->band == IEEE80211_BAND_5GHZ - * A rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - */ -static int _rtl92ee_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate) -{ - int rate_idx; - - if (!isht) { - if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - switch (desc_rate) { - case DESC92C_RATE6M: - rate_idx = 0; - break; - case DESC92C_RATE9M: - rate_idx = 1; - break; - case DESC92C_RATE12M: - rate_idx = 2; - break; - case DESC92C_RATE18M: - rate_idx = 3; - break; - case DESC92C_RATE24M: - rate_idx = 4; - break; - case DESC92C_RATE36M: - rate_idx = 5; - break; - case DESC92C_RATE48M: - rate_idx = 6; - break; - case DESC92C_RATE54M: - rate_idx = 7; - break; - default: - rate_idx = 0; - break; - } - } - } else { - switch (desc_rate) { - case DESC92C_RATEMCS0: - rate_idx = 0; - break; - case DESC92C_RATEMCS1: - rate_idx = 1; - break; - case DESC92C_RATEMCS2: - rate_idx = 2; - break; - case DESC92C_RATEMCS3: - rate_idx = 3; - break; - case DESC92C_RATEMCS4: - rate_idx = 4; - break; - case DESC92C_RATEMCS5: - rate_idx = 5; - break; - case DESC92C_RATEMCS6: - rate_idx = 6; - break; - case DESC92C_RATEMCS7: - rate_idx = 7; - break; - case DESC92C_RATEMCS8: - rate_idx = 8; - break; - case DESC92C_RATEMCS9: - rate_idx = 9; - break; - case DESC92C_RATEMCS10: - rate_idx = 10; - break; - case DESC92C_RATEMCS11: - rate_idx = 11; - break; - case DESC92C_RATEMCS12: - rate_idx = 12; - break; - case DESC92C_RATEMCS13: - rate_idx = 13; - break; - case DESC92C_RATEMCS14: - rate_idx = 14; - break; - case DESC92C_RATEMCS15: - rate_idx = 15; - break; - default: - rate_idx = 0; - break; - } - } - return rate_idx; -} - static void _rtl92ee_query_rxphystatus(struct ieee80211_hw *hw, struct rtl_stats *pstatus, u8 *pdesc, struct rx_fwinfo *p_drvinfo, @@ -576,9 +418,8 @@ bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw, * are use (RX_FLAG_HT) * Notice: this is diff with windows define */ - rx_status->rate_idx = _rtl92ee_rate_mapping(hw, - status->is_ht, - status->rate); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, + status->rate); rx_status->mactime = status->timestamp_low; if (phystatus) { -- cgit v1.2.1 From e0e776a3c85c27751ab4399616fc50a474cc8379 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:36 -0600 Subject: rtlwifi: Convert all drivers to use a common set of rate descriptors This common set of rate descriptors is renamed to be DESC_RATExx. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/base.c | 80 ++++++++++++++-------------- drivers/net/wireless/rtlwifi/rtl8192ce/sw.c | 30 +++++------ drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 8 +-- drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | 4 +- drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 28 +++++----- drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | 6 +-- drivers/net/wireless/rtlwifi/rtl8192de/sw.c | 30 +++++------ drivers/net/wireless/rtlwifi/rtl8192de/trx.c | 20 +++---- drivers/net/wireless/rtlwifi/rtl8192ee/trx.c | 12 ++--- drivers/net/wireless/rtlwifi/rtl8192ee/trx.h | 8 +-- drivers/net/wireless/rtlwifi/rtl8192se/def.h | 8 +-- drivers/net/wireless/rtlwifi/rtl8192se/sw.c | 30 +++++------ drivers/net/wireless/rtlwifi/rtl8192se/trx.c | 18 +++---- drivers/net/wireless/rtlwifi/rtl8821ae/def.h | 31 ----------- drivers/net/wireless/rtlwifi/wifi.h | 72 ++++++++++++------------- 15 files changed, 177 insertions(+), 208 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index d4c8e95f22de..23fc51e1c3dc 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -867,20 +867,20 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw, * * B/G rate: * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92_RATE1M-->DESC92_RATE54M ==> idx is 0-->11, + * DESC_RATE1M-->DESC_RATE54M ==> idx is 0-->11, * * N rate: * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15 + * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 * * 5G band:rx_status->band == IEEE80211_BAND_5GHZ * A rate: * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92_RATE6M-->DESC92_RATE54M ==> idx is 0-->7, + * DESC_RATE6M-->DESC_RATE54M ==> idx is 0-->7, * * N rate: * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15 + * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 */ int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, u8 desc_rate) @@ -890,40 +890,40 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw, if (false == isht) { if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { switch (desc_rate) { - case DESC92_RATE1M: + case DESC_RATE1M: rate_idx = 0; break; - case DESC92_RATE2M: + case DESC_RATE2M: rate_idx = 1; break; - case DESC92_RATE5_5M: + case DESC_RATE5_5M: rate_idx = 2; break; - case DESC92_RATE11M: + case DESC_RATE11M: rate_idx = 3; break; - case DESC92_RATE6M: + case DESC_RATE6M: rate_idx = 4; break; - case DESC92_RATE9M: + case DESC_RATE9M: rate_idx = 5; break; - case DESC92_RATE12M: + case DESC_RATE12M: rate_idx = 6; break; - case DESC92_RATE18M: + case DESC_RATE18M: rate_idx = 7; break; - case DESC92_RATE24M: + case DESC_RATE24M: rate_idx = 8; break; - case DESC92_RATE36M: + case DESC_RATE36M: rate_idx = 9; break; - case DESC92_RATE48M: + case DESC_RATE48M: rate_idx = 10; break; - case DESC92_RATE54M: + case DESC_RATE54M: rate_idx = 11; break; default: @@ -932,28 +932,28 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw, } } else { switch (desc_rate) { - case DESC92_RATE6M: + case DESC_RATE6M: rate_idx = 0; break; - case DESC92_RATE9M: + case DESC_RATE9M: rate_idx = 1; break; - case DESC92_RATE12M: + case DESC_RATE12M: rate_idx = 2; break; - case DESC92_RATE18M: + case DESC_RATE18M: rate_idx = 3; break; - case DESC92_RATE24M: + case DESC_RATE24M: rate_idx = 4; break; - case DESC92_RATE36M: + case DESC_RATE36M: rate_idx = 5; break; - case DESC92_RATE48M: + case DESC_RATE48M: rate_idx = 6; break; - case DESC92_RATE54M: + case DESC_RATE54M: rate_idx = 7; break; default: @@ -963,52 +963,52 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw, } } else { switch (desc_rate) { - case DESC92_RATEMCS0: + case DESC_RATEMCS0: rate_idx = 0; break; - case DESC92_RATEMCS1: + case DESC_RATEMCS1: rate_idx = 1; break; - case DESC92_RATEMCS2: + case DESC_RATEMCS2: rate_idx = 2; break; - case DESC92_RATEMCS3: + case DESC_RATEMCS3: rate_idx = 3; break; - case DESC92_RATEMCS4: + case DESC_RATEMCS4: rate_idx = 4; break; - case DESC92_RATEMCS5: + case DESC_RATEMCS5: rate_idx = 5; break; - case DESC92_RATEMCS6: + case DESC_RATEMCS6: rate_idx = 6; break; - case DESC92_RATEMCS7: + case DESC_RATEMCS7: rate_idx = 7; break; - case DESC92_RATEMCS8: + case DESC_RATEMCS8: rate_idx = 8; break; - case DESC92_RATEMCS9: + case DESC_RATEMCS9: rate_idx = 9; break; - case DESC92_RATEMCS10: + case DESC_RATEMCS10: rate_idx = 10; break; - case DESC92_RATEMCS11: + case DESC_RATEMCS11: rate_idx = 11; break; - case DESC92_RATEMCS12: + case DESC_RATEMCS12: rate_idx = 12; break; - case DESC92_RATEMCS13: + case DESC_RATEMCS13: rate_idx = 13; break; - case DESC92_RATEMCS14: + case DESC_RATEMCS14: rate_idx = 14; break; - case DESC92_RATEMCS15: + case DESC_RATEMCS15: rate_idx = 15; break; default: diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index dd5aa089126a..de6cb6c3a48c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -334,21 +334,21 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, - - .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, + .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, }; static const struct pci_device_id rtl92ce_pci_ids[] = { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index d25aeeb60b09..685faea111af 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -257,8 +257,8 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, pstats->recvsignalpower = rx_pwr_all; /* (3)EVM of HT rate */ - if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 && - pstats->rate <= DESC92_RATEMCS15) + if (pstats->is_ht && pstats->rate >= DESC_RATEMCS8 && + pstats->rate <= DESC_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -500,7 +500,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_BW(pdesc, 0); SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, - ((tcb_desc->rts_rate <= DESC92_RATE54M) ? + ((tcb_desc->rts_rate <= DESC_RATE54M) ? (tcb_desc->rts_use_shortpreamble ? 1 : 0) : (tcb_desc->rts_use_shortgi ? 1 : 0))); @@ -623,7 +623,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, if (firstseg) SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); - SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M); SET_TX_DESC_SEQ(pdesc, 0); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index c2d8ec6afcda..133e395b7401 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -880,8 +880,8 @@ static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw, pstats->rxpower = rx_pwr_all; pstats->recvsignalpower = rx_pwr_all; if (GET_RX_DESC_RX_MCS(pdesc) && - GET_RX_DESC_RX_MCS(pdesc) >= DESC92_RATEMCS8 && - GET_RX_DESC_RX_MCS(pdesc) <= DESC92_RATEMCS15) + GET_RX_DESC_RX_MCS(pdesc) >= DESC_RATEMCS8 && + GET_RX_DESC_RX_MCS(pdesc) <= DESC_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index e06bafee37f9..90a714c189a8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -257,20 +257,20 @@ static struct rtl_hal_cfg rtl92cu_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, - .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, + .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M, + .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, }; #define USB_VENDER_ID_REALTEK 0x0bda diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index fa30b260e5ba..fe298766ea88 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -543,7 +543,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_BW(txdesc, 0); SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(txdesc, - ((tcb_desc->rts_rate <= DESC92_RATE54M) ? + ((tcb_desc->rts_rate <= DESC_RATE54M) ? (tcb_desc->rts_use_shortpreamble ? 1 : 0) : (tcb_desc->rts_use_shortgi ? 1 : 0))); if (mac->bw_40) { @@ -642,7 +642,7 @@ void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, } SET_TX_DESC_USE_RATE(pDesc, 1); /* use data rate which is set by Sw */ SET_TX_DESC_OWN(pDesc, 1); - SET_TX_DESC_TX_RATE(pDesc, DESC92_RATE1M); + SET_TX_DESC_TX_RATE(pDesc, DESC_RATE1M); _rtl_tx_desc_checksum(pDesc); } @@ -658,7 +658,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE); if (firstseg) SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE); - SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M); SET_TX_DESC_SEQ(pdesc, 0); SET_TX_DESC_LINIP(pdesc, 0); SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c index a0aba088259a..b19d0398215f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -337,21 +337,21 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, - - .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, + .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, }; static struct pci_device_id rtl92de_pci_ids[] = { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index 7fbae49b53b6..381a4c016dda 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -235,8 +235,8 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw, pstats->rx_pwdb_all = pwdb_all; pstats->rxpower = rx_pwr_all; pstats->recvsignalpower = rx_pwr_all; - if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 && - pdesc->rxmcs <= DESC92_RATEMCS15) + if (pdesc->rxht && pdesc->rxmcs >= DESC_RATEMCS8 && + pdesc->rxmcs <= DESC_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -611,14 +611,14 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, } /* 5G have no CCK rate */ if (rtlhal->current_bandtype == BAND_ON_5G) - if (ptcb_desc->hw_rate < DESC92_RATE6M) - ptcb_desc->hw_rate = DESC92_RATE6M; + if (ptcb_desc->hw_rate < DESC_RATE6M) + ptcb_desc->hw_rate = DESC_RATE6M; SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) SET_TX_DESC_DATA_SHORTGI(pdesc, 1); if (rtlhal->macphymode == DUALMAC_DUALPHY && - ptcb_desc->hw_rate == DESC92_RATEMCS7) + ptcb_desc->hw_rate == DESC_RATEMCS7) SET_TX_DESC_DATA_SHORTGI(pdesc, 1); if (info->flags & IEEE80211_TX_CTL_AMPDU) { @@ -634,13 +634,13 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); /* 5G have no CCK rate */ if (rtlhal->current_bandtype == BAND_ON_5G) - if (ptcb_desc->rts_rate < DESC92_RATE6M) - ptcb_desc->rts_rate = DESC92_RATE6M; + if (ptcb_desc->rts_rate < DESC_RATE6M) + ptcb_desc->rts_rate = DESC_RATE6M; SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); SET_TX_DESC_RTS_BW(pdesc, 0); SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= - DESC92_RATE54M) ? + DESC_RATE54M) ? (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : (ptcb_desc->rts_use_shortgi ? 1 : 0))); if (bw_40) { @@ -755,9 +755,9 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, * The braces are needed no matter what checkpatch says */ if (rtlhal->current_bandtype == BAND_ON_5G) { - SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE6M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE6M); } else { - SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M); } SET_TX_DESC_SEQ(pdesc, 0); SET_TX_DESC_LINIP(pdesc, 0); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c index fb46fb9c095e..3ea7367727af 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c @@ -187,8 +187,8 @@ static void _rtl92ee_query_rxphystatus(struct ieee80211_hw *hw, pstatus->recvsignalpower = rx_pwr_all; /* (3)EVM of HT rate */ - if (pstatus->rate >= DESC92C_RATEMCS8 && - pstatus->rate <= DESC92C_RATEMCS15) + if (pstatus->rate >= DESC_RATEMCS8 && + pstatus->rate <= DESC_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -742,13 +742,13 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, } else { if (rtlpriv->ra.is_special_data) { ptcb_desc->use_driver_rate = true; - SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE11M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE11M); } else { ptcb_desc->use_driver_rate = false; } } - if (ptcb_desc->hw_rate > DESC92C_RATEMCS0) + if (ptcb_desc->hw_rate > DESC_RATEMCS0) short_gi = (ptcb_desc->use_shortgi) ? 1 : 0; else short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0; @@ -768,7 +768,7 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, - ((ptcb_desc->rts_rate <= DESC92C_RATE54M) ? + ((ptcb_desc->rts_rate <= DESC_RATE54M) ? (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : (ptcb_desc->rts_use_shortgi ? 1 : 0))); @@ -879,7 +879,7 @@ void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw, if (firstseg) SET_TX_DESC_OFFSET(pdesc, txdesc_len); - SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M); SET_TX_DESC_SEQ(pdesc, 0); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h index 6f9be1c7515c..45fd9db8cc40 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h @@ -591,10 +591,10 @@ do { \ } while (0) #define RTL92EE_RX_HAL_IS_CCK_RATE(rxmcs)\ - (rxmcs == DESC92C_RATE1M ||\ - rxmcs == DESC92C_RATE2M ||\ - rxmcs == DESC92C_RATE5_5M ||\ - rxmcs == DESC92C_RATE11M) + (rxmcs == DESC_RATE1M ||\ + rxmcs == DESC_RATE2M ||\ + rxmcs == DESC_RATE5_5M ||\ + rxmcs == DESC_RATE11M) #define IS_LITTLE_ENDIAN 1 diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h index 6e7a70b43949..ef87c09b77d0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h @@ -450,10 +450,10 @@ SHIFT_AND_MASK_LE(__pdesc + 24, 0, 32) #define SE_RX_HAL_IS_CCK_RATE(_pdesc)\ - (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M || \ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE2M || \ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE5_5M ||\ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE11M) + (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE1M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE2M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE5_5M ||\ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE11M) enum rf_optype { RF_OP_BY_SW_3WIRE = 0, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index fb003868bdef..e1fd27c888bf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -383,21 +383,21 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, - - .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, + .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, }; static struct pci_device_id rtl92se_pci_ids[] = { diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index da053cbdf621..95eebff4f558 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -191,8 +191,8 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, pstats->rxpower = rx_pwr_all; pstats->recvsignalpower = rx_pwr_all; - if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 && - pstats->rate <= DESC92_RATEMCS15) + if (pstats->is_ht && pstats->rate >= DESC_RATEMCS8 && + pstats->rate <= DESC_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -393,14 +393,14 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid); SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >= - DESC92_RATEMCS0) ? 1 : 0)); + DESC_RATEMCS0) ? 1 : 0)); if (rtlhal->version == VERSION_8192S_ACUT) { - if (ptcb_desc->hw_rate == DESC92_RATE1M || - ptcb_desc->hw_rate == DESC92_RATE2M || - ptcb_desc->hw_rate == DESC92_RATE5_5M || - ptcb_desc->hw_rate == DESC92_RATE11M) { - ptcb_desc->hw_rate = DESC92_RATE12M; + if (ptcb_desc->hw_rate == DESC_RATE1M || + ptcb_desc->hw_rate == DESC_RATE2M || + ptcb_desc->hw_rate == DESC_RATE5_5M || + ptcb_desc->hw_rate == DESC_RATE11M) { + ptcb_desc->hw_rate = DESC_RATE12M; } } @@ -429,7 +429,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0); SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= - DESC92_RATE54M) ? + DESC_RATE54M) ? (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : (ptcb_desc->rts_use_shortgi ? 1 : 0))); diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/def.h b/drivers/net/wireless/rtlwifi/rtl8821ae/def.h index a730985ae81d..53dc522db47a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/def.h @@ -374,37 +374,6 @@ enum rtl_desc_qsel { }; enum rtl_desc8821ae_rate { - DESC_RATE1M = 0x00, - DESC_RATE2M = 0x01, - DESC_RATE5_5M = 0x02, - DESC_RATE11M = 0x03, - - DESC_RATE6M = 0x04, - DESC_RATE9M = 0x05, - DESC_RATE12M = 0x06, - DESC_RATE18M = 0x07, - DESC_RATE24M = 0x08, - DESC_RATE36M = 0x09, - DESC_RATE48M = 0x0a, - DESC_RATE54M = 0x0b, - - DESC_RATEMCS0 = 0x0c, - DESC_RATEMCS1 = 0x0d, - DESC_RATEMCS2 = 0x0e, - DESC_RATEMCS3 = 0x0f, - DESC_RATEMCS4 = 0x10, - DESC_RATEMCS5 = 0x11, - DESC_RATEMCS6 = 0x12, - DESC_RATEMCS7 = 0x13, - DESC_RATEMCS8 = 0x14, - DESC_RATEMCS9 = 0x15, - DESC_RATEMCS10 = 0x16, - DESC_RATEMCS11 = 0x17, - DESC_RATEMCS12 = 0x18, - DESC_RATEMCS13 = 0x19, - DESC_RATEMCS14 = 0x1a, - DESC_RATEMCS15 = 0x1b, - DESC_RATEVHT1SS_MCS0 = 0x2c, DESC_RATEVHT1SS_MCS1 = 0x2d, DESC_RATEVHT1SS_MCS2 = 0x2e, diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index a233b26ac134..26fd9601fd41 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -331,10 +331,10 @@ enum hardware_type { (IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal)) #define RX_HAL_IS_CCK_RATE(rxmcs) \ - ((rxmcs) == DESC92_RATE1M || \ - (rxmcs) == DESC92_RATE2M || \ - (rxmcs) == DESC92_RATE5_5M || \ - (rxmcs) == DESC92_RATE11M) + ((rxmcs) == DESC_RATE1M || \ + (rxmcs) == DESC_RATE2M || \ + (rxmcs) == DESC_RATE5_5M || \ + (rxmcs) == DESC_RATE11M) enum scan_operation_backup_opt { SCAN_OPT_BACKUP = 0, @@ -579,38 +579,38 @@ enum rtl_hal_state { }; enum rtl_desc92_rate { - DESC92_RATE1M = 0x00, - DESC92_RATE2M = 0x01, - DESC92_RATE5_5M = 0x02, - DESC92_RATE11M = 0x03, - - DESC92_RATE6M = 0x04, - DESC92_RATE9M = 0x05, - DESC92_RATE12M = 0x06, - DESC92_RATE18M = 0x07, - DESC92_RATE24M = 0x08, - DESC92_RATE36M = 0x09, - DESC92_RATE48M = 0x0a, - DESC92_RATE54M = 0x0b, - - DESC92_RATEMCS0 = 0x0c, - DESC92_RATEMCS1 = 0x0d, - DESC92_RATEMCS2 = 0x0e, - DESC92_RATEMCS3 = 0x0f, - DESC92_RATEMCS4 = 0x10, - DESC92_RATEMCS5 = 0x11, - DESC92_RATEMCS6 = 0x12, - DESC92_RATEMCS7 = 0x13, - DESC92_RATEMCS8 = 0x14, - DESC92_RATEMCS9 = 0x15, - DESC92_RATEMCS10 = 0x16, - DESC92_RATEMCS11 = 0x17, - DESC92_RATEMCS12 = 0x18, - DESC92_RATEMCS13 = 0x19, - DESC92_RATEMCS14 = 0x1a, - DESC92_RATEMCS15 = 0x1b, - DESC92_RATEMCS15_SG = 0x1c, - DESC92_RATEMCS32 = 0x20, + DESC_RATE1M = 0x00, + DESC_RATE2M = 0x01, + DESC_RATE5_5M = 0x02, + DESC_RATE11M = 0x03, + + DESC_RATE6M = 0x04, + DESC_RATE9M = 0x05, + DESC_RATE12M = 0x06, + DESC_RATE18M = 0x07, + DESC_RATE24M = 0x08, + DESC_RATE36M = 0x09, + DESC_RATE48M = 0x0a, + DESC_RATE54M = 0x0b, + + DESC_RATEMCS0 = 0x0c, + DESC_RATEMCS1 = 0x0d, + DESC_RATEMCS2 = 0x0e, + DESC_RATEMCS3 = 0x0f, + DESC_RATEMCS4 = 0x10, + DESC_RATEMCS5 = 0x11, + DESC_RATEMCS6 = 0x12, + DESC_RATEMCS7 = 0x13, + DESC_RATEMCS8 = 0x14, + DESC_RATEMCS9 = 0x15, + DESC_RATEMCS10 = 0x16, + DESC_RATEMCS11 = 0x17, + DESC_RATEMCS12 = 0x18, + DESC_RATEMCS13 = 0x19, + DESC_RATEMCS14 = 0x1a, + DESC_RATEMCS15 = 0x1b, + DESC_RATEMCS15_SG = 0x1c, + DESC_RATEMCS32 = 0x20, }; enum rtl_var_map { -- cgit v1.2.1 From 5a0791d0f5511bac894bc753cc68705ed5dea2c4 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:37 -0600 Subject: rtlwifi: rtl8821ae: Add VHT rate descriptors Device RTL8821AE is the first if the rtlwifi devices to implement 802.11ac capability. As a result, VHT rate descriptors are needed. In addition, the driver is converted to use the descriptors in rtlwifi. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8821ae/def.h | 23 ----------------------- drivers/net/wireless/rtlwifi/wifi.h | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/def.h b/drivers/net/wireless/rtlwifi/rtl8821ae/def.h index 53dc522db47a..ee7c208bd070 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/def.h @@ -373,29 +373,6 @@ enum rtl_desc_qsel { QSLT_CMD = 0x13, }; -enum rtl_desc8821ae_rate { - DESC_RATEVHT1SS_MCS0 = 0x2c, - DESC_RATEVHT1SS_MCS1 = 0x2d, - DESC_RATEVHT1SS_MCS2 = 0x2e, - DESC_RATEVHT1SS_MCS3 = 0x2f, - DESC_RATEVHT1SS_MCS4 = 0x30, - DESC_RATEVHT1SS_MCS5 = 0x31, - DESC_RATEVHT1SS_MCS6 = 0x32, - DESC_RATEVHT1SS_MCS7 = 0x33, - DESC_RATEVHT1SS_MCS8 = 0x34, - DESC_RATEVHT1SS_MCS9 = 0x35, - DESC_RATEVHT2SS_MCS0 = 0x36, - DESC_RATEVHT2SS_MCS1 = 0x37, - DESC_RATEVHT2SS_MCS2 = 0x38, - DESC_RATEVHT2SS_MCS3 = 0x39, - DESC_RATEVHT2SS_MCS4 = 0x3a, - DESC_RATEVHT2SS_MCS5 = 0x3b, - DESC_RATEVHT2SS_MCS6 = 0x3c, - DESC_RATEVHT2SS_MCS7 = 0x3d, - DESC_RATEVHT2SS_MCS8 = 0x3e, - DESC_RATEVHT2SS_MCS9 = 0x3f, -}; - enum rx_packet_type { NORMAL_RX, TX_REPORT1, diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 26fd9601fd41..7a718fdb82cd 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -611,6 +611,27 @@ enum rtl_desc92_rate { DESC_RATEMCS15 = 0x1b, DESC_RATEMCS15_SG = 0x1c, DESC_RATEMCS32 = 0x20, + + DESC_RATEVHT1SS_MCS0 = 0x2c, + DESC_RATEVHT1SS_MCS1 = 0x2d, + DESC_RATEVHT1SS_MCS2 = 0x2e, + DESC_RATEVHT1SS_MCS3 = 0x2f, + DESC_RATEVHT1SS_MCS4 = 0x30, + DESC_RATEVHT1SS_MCS5 = 0x31, + DESC_RATEVHT1SS_MCS6 = 0x32, + DESC_RATEVHT1SS_MCS7 = 0x33, + DESC_RATEVHT1SS_MCS8 = 0x34, + DESC_RATEVHT1SS_MCS9 = 0x35, + DESC_RATEVHT2SS_MCS0 = 0x36, + DESC_RATEVHT2SS_MCS1 = 0x37, + DESC_RATEVHT2SS_MCS2 = 0x38, + DESC_RATEVHT2SS_MCS3 = 0x39, + DESC_RATEVHT2SS_MCS4 = 0x3a, + DESC_RATEVHT2SS_MCS5 = 0x3b, + DESC_RATEVHT2SS_MCS6 = 0x3c, + DESC_RATEVHT2SS_MCS7 = 0x3d, + DESC_RATEVHT2SS_MCS8 = 0x3e, + DESC_RATEVHT2SS_MCS9 = 0x3f, }; enum rtl_var_map { -- cgit v1.2.1 From 6a7fd777078f02ba9c14fe1af4c4c3f3a5285a41 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:38 -0600 Subject: rtlwifi: rtl8192cu: Rework calls to rate-control routine The code uses macros to determine the parameters that are passed to the rate setting routine. A simpler method is implemented. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index fe298766ea88..5eccaba79d42 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -325,6 +325,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, && (GET_RX_DESC_FAGGR(pdesc) == 1)); stats->timestamp_low = GET_RX_DESC_TSFL(pdesc); stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + stats->is_ht = (bool)GET_RX_DESC_RX_HT(pdesc); rx_status->freq = hw->conf.chandef.chan->center_freq; rx_status->band = hw->conf.chandef.chan->band; if (GET_RX_DESC_CRC32(pdesc)) @@ -338,9 +339,8 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, rx_status->flag |= RX_FLAG_MACTIME_START; if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; - rx_status->rate_idx = rtlwifi_rate_mapping(hw, - (bool)GET_RX_DESC_RX_HT(pdesc), - (u8)GET_RX_DESC_RX_MCS(pdesc)); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, + stats->rate); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { p_drvinfo = (struct rx_fwinfo_92c *)(skb->data + @@ -392,6 +392,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) && (GET_RX_DESC_FAGGR(rxdesc) == 1)); stats.timestamp_low = GET_RX_DESC_TSFL(rxdesc); stats.rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(rxdesc); + stats.is_ht = (bool)GET_RX_DESC_RX_HT(rxdesc); /* TODO: is center_freq changed when doing scan? */ /* TODO: Shall we add protection or just skip those two step? */ rx_status->freq = hw->conf.chandef.chan->center_freq; @@ -405,9 +406,8 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) if (GET_RX_DESC_RX_HT(rxdesc)) rx_status->flag |= RX_FLAG_HT; /* Data rate */ - rx_status->rate_idx = rtlwifi_rate_mapping(hw, - (bool)GET_RX_DESC_RX_HT(rxdesc), - (u8)GET_RX_DESC_RX_MCS(rxdesc)); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats.is_ht, + stats.rate); /* There is a phy status after this rx descriptor. */ if (GET_RX_DESC_PHY_STATUS(rxdesc)) { p_drvinfo = (struct rx_fwinfo_92c *)(rxdesc + RTL_RX_DESC_SIZE); -- cgit v1.2.1 From a160ba06c1bde5e0609f7ac475a9650224337933 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:39 -0600 Subject: rtlwifi: rtl8192de: Rework calls to rate-control routine The code uses macros to determine the parameters that are passed to the rate setting routine. A simpler method is implemented. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192de/trx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index 381a4c016dda..547c6d0ff627 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -499,6 +499,7 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, && (GET_RX_DESC_FAGGR(pdesc) == 1)); stats->timestamp_low = GET_RX_DESC_TSFL(pdesc); stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + stats->is_ht = (bool)GET_RX_DESC_RXHT(pdesc); rx_status->freq = hw->conf.chandef.chan->center_freq; rx_status->band = hw->conf.chandef.chan->band; if (GET_RX_DESC_CRC32(pdesc)) @@ -512,9 +513,8 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, rx_status->flag |= RX_FLAG_MACTIME_START; if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; - rx_status->rate_idx = rtlwifi_rate_mapping(hw, - (bool)GET_RX_DESC_RXHT(pdesc), - (u8)GET_RX_DESC_RXMCS(pdesc)); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, + stats->rate); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { p_drvinfo = (struct rx_fwinfo_92d *)(skb->data + -- cgit v1.2.1 From fd3cb22ad87fd53eb47dc64fd0cafd665d4124a1 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 18 Dec 2014 03:05:40 -0600 Subject: rtlwifi: rtl8821ae: Switch to use common rate control routine With this change, all of the drivers now use the common routine. As this driver has VHT capability, an additional parameter is needed, thus all the drivers had to be modified. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/base.c | 76 ++++++++- drivers/net/wireless/rtlwifi/base.h | 4 +- drivers/net/wireless/rtlwifi/rtl8188ee/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | 4 +- drivers/net/wireless/rtlwifi/rtl8192de/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192ee/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192se/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8723be/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8821ae/trx.c | 232 +-------------------------- 11 files changed, 88 insertions(+), 242 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 23fc51e1c3dc..1d4677460711 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -881,12 +881,84 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw, * N rate: * (rx_status->flag & RX_FLAG_HT) = 1, * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 + * + * VHT rates: + * DESC_RATEVHT1SS_MCS0-->DESC_RATEVHT1SS_MCS9 ==> idx is 0-->9 + * DESC_RATEVHT2SS_MCS0-->DESC_RATEVHT2SS_MCS9 ==> idx is 0-->9 */ -int rtlwifi_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate) +int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, bool isvht, + u8 desc_rate) { int rate_idx; + if (isvht) { + switch (desc_rate) { + case DESC_RATEVHT1SS_MCS0: + rate_idx = 0; + break; + case DESC_RATEVHT1SS_MCS1: + rate_idx = 1; + break; + case DESC_RATEVHT1SS_MCS2: + rate_idx = 2; + break; + case DESC_RATEVHT1SS_MCS3: + rate_idx = 3; + break; + case DESC_RATEVHT1SS_MCS4: + rate_idx = 4; + break; + case DESC_RATEVHT1SS_MCS5: + rate_idx = 5; + break; + case DESC_RATEVHT1SS_MCS6: + rate_idx = 6; + break; + case DESC_RATEVHT1SS_MCS7: + rate_idx = 7; + break; + case DESC_RATEVHT1SS_MCS8: + rate_idx = 8; + break; + case DESC_RATEVHT1SS_MCS9: + rate_idx = 9; + break; + case DESC_RATEVHT2SS_MCS0: + rate_idx = 0; + break; + case DESC_RATEVHT2SS_MCS1: + rate_idx = 1; + break; + case DESC_RATEVHT2SS_MCS2: + rate_idx = 2; + break; + case DESC_RATEVHT2SS_MCS3: + rate_idx = 3; + break; + case DESC_RATEVHT2SS_MCS4: + rate_idx = 4; + break; + case DESC_RATEVHT2SS_MCS5: + rate_idx = 5; + break; + case DESC_RATEVHT2SS_MCS6: + rate_idx = 6; + break; + case DESC_RATEVHT2SS_MCS7: + rate_idx = 7; + break; + case DESC_RATEVHT2SS_MCS8: + rate_idx = 8; + break; + case DESC_RATEVHT2SS_MCS9: + rate_idx = 9; + break; + default: + rate_idx = 0; + break; + } + return rate_idx; + } if (false == isht) { if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { switch (desc_rate) { diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index 936c2bba54d4..c6cb49c3ee32 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -123,8 +123,8 @@ void rtl_watch_dog_timer_callback(unsigned long data); void rtl_deinit_deferred_work(struct ieee80211_hw *hw); bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); -int rtlwifi_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate); +int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, + bool isvht, u8 desc_rate); bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c index d430884426ab..791efbe6b18c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c @@ -473,7 +473,7 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw, * Notice: this is diff with windows define */ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, - status->rate); + false, status->rate); rx_status->mactime = status->timestamp_low; if (phystatus == true) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 685faea111af..84ddd4d07a1d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -401,7 +401,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, * Notice: this is diff with windows define */ rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, - stats->rate); + false, stats->rate); rx_status->mactime = stats->timestamp_low; if (phystatus) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index 5eccaba79d42..cbead007171f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -340,7 +340,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, - stats->rate); + false, stats->rate); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { p_drvinfo = (struct rx_fwinfo_92c *)(skb->data + @@ -407,7 +407,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) rx_status->flag |= RX_FLAG_HT; /* Data rate */ rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats.is_ht, - stats.rate); + false, stats.rate); /* There is a phy status after this rx descriptor. */ if (GET_RX_DESC_PHY_STATUS(rxdesc)) { p_drvinfo = (struct rx_fwinfo_92c *)(rxdesc + RTL_RX_DESC_SIZE); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index 547c6d0ff627..1feaa629dd4f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -514,7 +514,7 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, - stats->rate); + false, stats->rate); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { p_drvinfo = (struct rx_fwinfo_92d *)(skb->data + diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c index 3ea7367727af..51806aca2318 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c @@ -419,7 +419,7 @@ bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw, * Notice: this is diff with windows define */ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, - status->rate); + false, status->rate); rx_status->mactime = status->timestamp_low; if (phystatus) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index 95eebff4f558..125b29bd2f93 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -319,7 +319,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, } rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, - stats->rate); + false, stats->rate); rx_status->mactime = stats->timestamp_low; if (phystatus) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index 662a09461a6b..2f7c144d7980 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -346,7 +346,7 @@ bool rtl8723e_rx_query_desc(struct ieee80211_hw *hw, * Notice: this is diff with windows define */ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, - status->rate); + false, status->rate); rx_status->mactime = status->timestamp_low; if (phystatus == true) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c index cb23bed34706..338ec9a9d09b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c @@ -401,7 +401,7 @@ bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw, * are use (RX_FLAG_HT) */ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, - status->rate); + false, status->rate); rx_status->mactime = status->timestamp_low; if (phystatus) { diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c index 383b86b05cba..72af4b9ee32b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c @@ -48,232 +48,6 @@ static u8 _rtl8821ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -/* mac80211's rate_idx is like this: - * - * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ - * - * B/G rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC_RATE1M-->DESC_RATE54M ==> idx is 0-->11, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 - * - * 5G band:rx_status->band == IEEE80211_BAND_5GHZ - * A rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC_RATE6M-->DESC_RATE54M ==> idx is 0-->7, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 - */ -static int _rtl8821ae_rate_mapping(struct ieee80211_hw *hw, - bool isht, bool isvht, u8 desc_rate) -{ - int rate_idx; - - if (!isht) { - if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { - switch (desc_rate) { - case DESC_RATE1M: - rate_idx = 0; - break; - case DESC_RATE2M: - rate_idx = 1; - break; - case DESC_RATE5_5M: - rate_idx = 2; - break; - case DESC_RATE11M: - rate_idx = 3; - break; - case DESC_RATE6M: - rate_idx = 4; - break; - case DESC_RATE9M: - rate_idx = 5; - break; - case DESC_RATE12M: - rate_idx = 6; - break; - case DESC_RATE18M: - rate_idx = 7; - break; - case DESC_RATE24M: - rate_idx = 8; - break; - case DESC_RATE36M: - rate_idx = 9; - break; - case DESC_RATE48M: - rate_idx = 10; - break; - case DESC_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - switch (desc_rate) { - case DESC_RATE6M: - rate_idx = 0; - break; - case DESC_RATE9M: - rate_idx = 1; - break; - case DESC_RATE12M: - rate_idx = 2; - break; - case DESC_RATE18M: - rate_idx = 3; - break; - case DESC_RATE24M: - rate_idx = 4; - break; - case DESC_RATE36M: - rate_idx = 5; - break; - case DESC_RATE48M: - rate_idx = 6; - break; - case DESC_RATE54M: - rate_idx = 7; - break; - default: - rate_idx = 0; - break; - } - } - } else { - switch (desc_rate) { - case DESC_RATEMCS0: - rate_idx = 0; - break; - case DESC_RATEMCS1: - rate_idx = 1; - break; - case DESC_RATEMCS2: - rate_idx = 2; - break; - case DESC_RATEMCS3: - rate_idx = 3; - break; - case DESC_RATEMCS4: - rate_idx = 4; - break; - case DESC_RATEMCS5: - rate_idx = 5; - break; - case DESC_RATEMCS6: - rate_idx = 6; - break; - case DESC_RATEMCS7: - rate_idx = 7; - break; - case DESC_RATEMCS8: - rate_idx = 8; - break; - case DESC_RATEMCS9: - rate_idx = 9; - break; - case DESC_RATEMCS10: - rate_idx = 10; - break; - case DESC_RATEMCS11: - rate_idx = 11; - break; - case DESC_RATEMCS12: - rate_idx = 12; - break; - case DESC_RATEMCS13: - rate_idx = 13; - break; - case DESC_RATEMCS14: - rate_idx = 14; - break; - case DESC_RATEMCS15: - rate_idx = 15; - break; - default: - rate_idx = 0; - break; - } - } - - if (isvht) { - switch (desc_rate) { - case DESC_RATEVHT1SS_MCS0: - rate_idx = 0; - break; - case DESC_RATEVHT1SS_MCS1: - rate_idx = 1; - break; - case DESC_RATEVHT1SS_MCS2: - rate_idx = 2; - break; - case DESC_RATEVHT1SS_MCS3: - rate_idx = 3; - break; - case DESC_RATEVHT1SS_MCS4: - rate_idx = 4; - break; - case DESC_RATEVHT1SS_MCS5: - rate_idx = 5; - break; - case DESC_RATEVHT1SS_MCS6: - rate_idx = 6; - break; - case DESC_RATEVHT1SS_MCS7: - rate_idx = 7; - break; - case DESC_RATEVHT1SS_MCS8: - rate_idx = 8; - break; - case DESC_RATEVHT1SS_MCS9: - rate_idx = 9; - break; - case DESC_RATEVHT2SS_MCS0: - rate_idx = 0; - break; - case DESC_RATEVHT2SS_MCS1: - rate_idx = 1; - break; - case DESC_RATEVHT2SS_MCS2: - rate_idx = 2; - break; - case DESC_RATEVHT2SS_MCS3: - rate_idx = 3; - break; - case DESC_RATEVHT2SS_MCS4: - rate_idx = 4; - break; - case DESC_RATEVHT2SS_MCS5: - rate_idx = 5; - break; - case DESC_RATEVHT2SS_MCS6: - rate_idx = 6; - break; - case DESC_RATEVHT2SS_MCS7: - rate_idx = 7; - break; - case DESC_RATEVHT2SS_MCS8: - rate_idx = 8; - break; - case DESC_RATEVHT2SS_MCS9: - rate_idx = 9; - break; - default: - rate_idx = 0; - break; - } - } - return rate_idx; -} - static u16 odm_cfo(char value) { int ret_val; @@ -766,9 +540,9 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw, * supported rates or MCS index if HT rates * are use (RX_FLAG_HT) */ - rx_status->rate_idx = - _rtl8821ae_rate_mapping(hw, status->is_ht, - status->is_vht, status->rate); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, + status->is_vht, + status->rate); rx_status->mactime = status->timestamp_low; if (phystatus) { -- cgit v1.2.1 From 9898b77536b8569be2704964d3c519ef070e4a27 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sat, 20 Dec 2014 13:48:14 +0100 Subject: rtlwifi: rtl8192ee: trx.c: Remove unused function Remove the function rtl92ee_get_available_desc() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ee/trx.c | 21 --------------------- drivers/net/wireless/rtlwifi/rtl8192ee/trx.h | 1 - 2 files changed, 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c index 51806aca2318..55d1da5e162b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c @@ -551,27 +551,6 @@ static u16 get_desc_addr_fr_q_idx(u16 queue_index) return desc_address; } -void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx) -{ - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - struct rtl_priv *rtlpriv = rtl_priv(hw); - u16 point_diff = 0; - u16 current_tx_read_point = 0, current_tx_write_point = 0; - u32 tmp_4byte; - - tmp_4byte = rtl_read_dword(rtlpriv, - get_desc_addr_fr_q_idx(q_idx)); - current_tx_read_point = (u16)((tmp_4byte >> 16) & 0x0fff); - current_tx_write_point = (u16)((tmp_4byte) & 0x0fff); - - point_diff = ((current_tx_read_point > current_tx_write_point) ? - (current_tx_read_point - current_tx_write_point) : - (TX_DESC_NUM_92E - current_tx_write_point + - current_tx_read_point)); - - rtlpci->tx_ring[q_idx].avl_desc = point_diff; -} - void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, u8 *tx_bd_desc, u8 *desc, u8 queue_index, struct sk_buff *skb, dma_addr_t addr) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h index 45fd9db8cc40..48504c25fffb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h @@ -829,7 +829,6 @@ void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc, u8 queue_index); u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index); -void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 queue_index); void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, u8 *tx_bd_desc, u8 *desc, u8 queue_index, struct sk_buff *skb, dma_addr_t addr); -- cgit v1.2.1 From b30b2e0f3dbcde630b911bdc8fda8ae8300fff6a Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sat, 20 Dec 2014 23:59:18 +0100 Subject: rtlwifi: rtl8723be: phy.c: Remove unused function Remove the function rtl8723be_phy_get_txpower_level() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8723be/phy.c | 25 ------------------------- drivers/net/wireless/rtlwifi/rtl8723be/phy.h | 2 -- 2 files changed, 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c index 20dcc25c506c..b7b73cbe346d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c @@ -874,31 +874,6 @@ void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) ROFDM0_RXDETECTOR3, rtlphy->framesync); } -void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &rtlpriv->phy; - u8 txpwr_level; - long txpwr_dbm; - - txpwr_level = rtlphy->cur_cck_txpwridx; - txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, - txpwr_level); - txpwr_level = rtlphy->cur_ofdm24g_txpwridx; - if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > - txpwr_dbm) - txpwr_dbm = - rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, - txpwr_level); - txpwr_level = rtlphy->cur_ofdm24g_txpwridx; - if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, - txpwr_level) > txpwr_dbm) - txpwr_dbm = - rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, - txpwr_level); - *powerlevel = txpwr_dbm; -} - static u8 _rtl8723be_phy_get_ratesection_intxpower_byrate(enum radio_path path, u8 rate) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h index 6339738a0e33..9021d4745ab7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h @@ -114,8 +114,6 @@ bool rtl8723be_phy_mac_config(struct ieee80211_hw *hw); bool rtl8723be_phy_bb_config(struct ieee80211_hw *hw); bool rtl8723be_phy_rf_config(struct ieee80211_hw *hw); void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); -void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw, - long *powerlevel); void rtl8723be_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); void rtl8723be_phy_scan_operation_backup(struct ieee80211_hw *hw, -- cgit v1.2.1 From a9abe3023ace441ce9e27425b263f2dabd28cf32 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 19 Dec 2014 00:18:12 +0100 Subject: ath9k: enable TPC by default Enable hw TPC by default on AR9003 based chips Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6d4b273469b1..258c4d236cbe 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -422,6 +422,9 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->power_mode = ATH9K_PM_UNDEFINED; ah->htc_reset_init = true; + /* ar9002 does not support TPC for the moment */ + ah->tpc_enabled = !!AR_SREV_9300_20_OR_LATER(ah); + ah->ani_function = ATH9K_ANI_ALL; if (!AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_MRC_CCK; -- cgit v1.2.1 From 8718389b1ca8c911b5a143090b880c3474da508b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 19 Dec 2014 00:18:13 +0100 Subject: ath9k: add debugfs support for hw TPC Add tpc entry to ath9k debugfs in order to enable/disable hw TPC Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug.c | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 871e969409bf..c43e2ad36587 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1115,6 +1115,75 @@ static const struct file_operations fops_ackto = { }; #endif +static ssize_t read_file_tpc(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + unsigned int len = 0, size = 32; + ssize_t retval; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += scnprintf(buf + len, size - len, "%s\n", + ah->tpc_enabled ? "ENABLED" : "DISABLED"); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static ssize_t write_file_tpc(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + unsigned long val; + char buf[32]; + ssize_t len; + bool tpc_enabled; + + if (!AR_SREV_9300_20_OR_LATER(ah)) { + /* ar9002 does not support TPC for the moment */ + return -EOPNOTSUPP; + } + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val < 0 || val > 1) + return -EINVAL; + + tpc_enabled = !!val; + + if (tpc_enabled != ah->tpc_enabled) { + ah->tpc_enabled = tpc_enabled; + ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); + } + + return count; +} + +static const struct file_operations fops_tpc = { + .read = read_file_tpc, + .write = write_file_tpc, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + /* Ethtool support for get-stats */ #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" @@ -1324,6 +1393,8 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_ackto); #endif + debugfs_create_file("tpc", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_tpc); return 0; } -- cgit v1.2.1 From 354f473ee2c5d01c1cf90f747f95218ee3e73e95 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 19 Dec 2014 00:18:14 +0100 Subject: ath9k: fix typo Fix typo Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index e9bd02c2e844..52d63de4a93d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1106,7 +1106,7 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, return MAX_RATE_POWER; if (!AR_SREV_9300_20_OR_LATER(ah)) { - /* ar9002 is not sipported for the moment */ + /* ar9002 does not support TPC for the moment */ return MAX_RATE_POWER; } -- cgit v1.2.1 From e32ec12fd11fbccc1cb4656e34f35ad457e19e29 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Oct 2014 11:22:56 +0200 Subject: iwlwifi: remove MODULE_VERSION The module version "in-tree:" or "in-tree:d" is useless; there should be better (functional) ways to detect whether debugging is enabled and other than that the version says nothing. Therefore remove the driver version completely. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/main.c | 14 -------------- drivers/net/wireless/iwlwifi/iwl-drv.c | 15 +-------------- drivers/net/wireless/iwlwifi/iwl-drv.h | 1 - drivers/net/wireless/iwlwifi/mvm/ops.c | 7 ------- 4 files changed, 1 insertion(+), 36 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 0b7f46f0b079..fcdc128298ea 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -64,22 +64,8 @@ * ******************************************************************************/ -/* - * module name, copyright, version, etc. - */ #define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux" - -#ifdef CONFIG_IWLWIFI_DEBUG -#define VD "d" -#else -#define VD -#endif - -#define DRV_VERSION IWLWIFI_VERSION VD - - MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 38de1513e4de..36ae19134d11 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -84,21 +84,8 @@ * ******************************************************************************/ -/* - * module name, copyright, version, etc. - */ #define DRV_DESCRIPTION "Intel(R) Wireless WiFi driver for Linux" - -#ifdef CONFIG_IWLWIFI_DEBUG -#define VD "d" -#else -#define VD -#endif - -#define DRV_VERSION IWLWIFI_VERSION VD - MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); @@ -1492,7 +1479,7 @@ static int __init iwl_drv_init(void) for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv); - pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); + pr_info(DRV_DESCRIPTION "\n"); pr_info(DRV_COPYRIGHT "\n"); #ifdef CONFIG_IWLWIFI_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index be4f8972241a..adf522c756e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -68,7 +68,6 @@ /* for all modules */ #define DRV_NAME "iwlwifi" -#define IWLWIFI_VERSION "in-tree:" #define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation" #define DRV_AUTHOR "" diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 97dfba50c682..552a776962af 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -84,15 +84,8 @@ #include "time-event.h" #include "iwl-fw-error-dump.h" -/* - * module name, copyright, version, etc. - */ #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" - -#define DRV_VERSION IWLWIFI_VERSION - MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); -- cgit v1.2.1 From f53bf4c758c0fbe728c031621f4c5f9979cdb044 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Mon, 1 Dec 2014 10:44:18 +0200 Subject: iwlwifi: mvm: add fw runtime stack to dump data The allocation of the DCCM between the data and the stack can theoretically change without notice to the driver, but the total size is HW-fixed. Since the stack CCM (runtime stack) has also data important to the FW - this patch allows pulling the whole DCCM in one piece and adds it to the dump data. If the size isn't known - just use the data part of the DCCM as it appears in the FW TLVs. Signed-off-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 23 ++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-8000.c | 8 +++++++- drivers/net/wireless/iwlwifi/iwl-config.h | 4 ++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 15 +++++++++++---- 4 files changed, 44 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index e5be2d21868f..9e76799c4750 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -92,6 +92,12 @@ #define IWL7265D_NVM_VERSION 0x0c11 #define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ +/* DCCM offsets and lengths */ +#define IWL7000_DCCM_OFFSET 0x800000 +#define IWL7260_DCCM_LEN 0x14000 +#define IWL3160_DCCM_LEN 0x10000 +#define IWL7265_DCCM_LEN 0x17A00 + #define IWL7260_FW_PRE "iwlwifi-7260-" #define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" @@ -138,7 +144,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ .non_shared_ant = ANT_A, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .dccm_offset = IWL7000_DCCM_OFFSET const struct iwl_cfg iwl7260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 7260", @@ -149,6 +156,7 @@ const struct iwl_cfg iwl7260_2ac_cfg = { .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, }; const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { @@ -161,6 +169,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { .high_temp = true, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, }; const struct iwl_cfg iwl7260_2n_cfg = { @@ -172,6 +181,7 @@ const struct iwl_cfg iwl7260_2n_cfg = { .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, }; const struct iwl_cfg iwl7260_n_cfg = { @@ -183,6 +193,7 @@ const struct iwl_cfg iwl7260_n_cfg = { .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, }; const struct iwl_cfg iwl3160_2ac_cfg = { @@ -193,6 +204,7 @@ const struct iwl_cfg iwl3160_2ac_cfg = { .nvm_ver = IWL3160_NVM_VERSION, .nvm_calib_ver = IWL3160_TX_POWER_VERSION, .host_interrupt_operation_mode = true, + .dccm_len = IWL3160_DCCM_LEN, }; const struct iwl_cfg iwl3160_2n_cfg = { @@ -203,6 +215,7 @@ const struct iwl_cfg iwl3160_2n_cfg = { .nvm_ver = IWL3160_NVM_VERSION, .nvm_calib_ver = IWL3160_TX_POWER_VERSION, .host_interrupt_operation_mode = true, + .dccm_len = IWL3160_DCCM_LEN, }; const struct iwl_cfg iwl3160_n_cfg = { @@ -213,6 +226,7 @@ const struct iwl_cfg iwl3160_n_cfg = { .nvm_ver = IWL3160_NVM_VERSION, .nvm_calib_ver = IWL3160_TX_POWER_VERSION, .host_interrupt_operation_mode = true, + .dccm_len = IWL3160_DCCM_LEN, }; static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { @@ -240,6 +254,7 @@ const struct iwl_cfg iwl3165_2ac_cfg = { .nvm_ver = IWL3165_NVM_VERSION, .nvm_calib_ver = IWL3165_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265_2ac_cfg = { @@ -250,6 +265,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = { .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265_2n_cfg = { @@ -260,6 +276,7 @@ const struct iwl_cfg iwl7265_2n_cfg = { .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265_n_cfg = { @@ -270,6 +287,7 @@ const struct iwl_cfg iwl7265_n_cfg = { .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265d_2ac_cfg = { @@ -280,6 +298,7 @@ const struct iwl_cfg iwl7265d_2ac_cfg = { .nvm_ver = IWL7265D_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265d_2n_cfg = { @@ -290,6 +309,7 @@ const struct iwl_cfg iwl7265d_2n_cfg = { .nvm_ver = IWL7265D_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265d_n_cfg = { @@ -300,6 +320,7 @@ const struct iwl_cfg iwl7265d_n_cfg = { .nvm_ver = IWL7265D_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index bf0a95cb7153..6c5c55856a35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -81,6 +81,10 @@ #define IWL8000_NVM_VERSION 0x0a1d #define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ +/* DCCM offsets and lengths */ +#define IWL8260_DCCM_OFFSET 0x800000 +#define IWL8260_DCCM_LEN 0x18000 + #define IWL8000_FW_PRE "iwlwifi-8000" #define IWL8000_MODULE_FIRMWARE(api) \ IWL8000_FW_PRE "-" __stringify(api) ".ucode" @@ -124,7 +128,9 @@ static const struct iwl_ht_params iwl8000_ht_params = { .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ .d0i3 = true, \ - .non_shared_ant = ANT_A + .non_shared_ant = ANT_A, \ + .dccm_offset = IWL8260_DCCM_OFFSET, \ + .dccm_len = IWL8260_DCCM_LEN const struct iwl_cfg iwl8260_2n_cfg = { .name = "Intel(R) Dual Band Wireless N 8260", diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 3a4b9c7fc083..31c67dfabf55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -261,6 +261,8 @@ struct iwl_pwr_tx_backoff { * station can receive in HT * @max_vht_ampdu_exponent: the exponent of the max length of A-MPDU that the * station can receive in VHT + * @dccm_offset: offset from which DCCM begins + * @dccm_len: length of DCCM (including runtime stack CCM) * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -303,6 +305,8 @@ struct iwl_cfg { unsigned int max_tx_agg_size; unsigned int max_ht_ampdu_exponent; unsigned int max_vht_ampdu_exponent; + const u32 dccm_offset; + const u32 dccm_len; }; /* diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 31a5b3f4266c..2d62b5617a56 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -767,7 +767,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; struct iwl_mvm_dump_ptrs *fw_error_dump; - const struct fw_img *img; u32 sram_len, sram_ofs; u32 file_len, rxf_len; unsigned long flags; @@ -779,9 +778,17 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) if (!fw_error_dump) return; - img = &mvm->fw->img[mvm->cur_ucode]; - sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; - sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; + /* SRAM - include stack CCM if driver knows the values for it */ + if (!mvm->cfg->dccm_offset || !mvm->cfg->dccm_len) { + const struct fw_img *img; + + img = &mvm->fw->img[mvm->cur_ucode]; + sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; + sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; + } else { + sram_ofs = mvm->cfg->dccm_offset; + sram_len = mvm->cfg->dccm_len; + } /* reading buffer size */ reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); -- cgit v1.2.1 From 7074cc4280463c27161a1eba89dfaa01685161bd Mon Sep 17 00:00:00 2001 From: Dor Shaish Date: Wed, 10 Dec 2014 12:44:57 +0200 Subject: Revert "iwlwifi: use correct fw file in 8000 b-step" Signed-off-by: Dor Shaish Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 55 ---------------------------------- 1 file changed, 55 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 36ae19134d11..afa63f7b2d3e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -237,9 +237,6 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) /* * Starting 8000B - FW name format has changed. This overwrites the * previous name and uses the new format. - * - * TODO: - * Once there is only one supported step for 8000 family - delete this! */ if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { char rev_step[2] = { @@ -250,13 +247,6 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) if (CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP) rev_step[0] = 0; - /* - * If hw_rev wasn't set yet - default as B-step. If it IS A-step - * we'll reload that FW later instead. - */ - if (drv->trans->hw_rev == 0) - rev_step[0] = 'B'; - snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s-%s.ucode", name_pre, rev_step, tag); } @@ -1069,7 +1059,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) u32 api_ver; int i; bool load_module = false; - u32 hw_rev = drv->trans->hw_rev; fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; fw->ucode_capa.standard_phy_calibration_size = @@ -1262,50 +1251,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) op->name, err); #endif } - - /* - * We may have loaded the wrong FW file in 8000 HW family if it is an - * A-step card, and if drv->trans->hw_rev wasn't properly read when - * the FW file had been loaded. (This might happen in SDIO.) In such a - * case - unload and reload the correct file. - * - * TODO: - * Once there is only one supported step for 8000 family - delete this! - */ - if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP && - drv->trans->hw_rev != hw_rev) { - char firmware_name[32]; - - /* Free previous FW resources */ - if (drv->op_mode) - _iwl_op_mode_stop(drv); - iwl_dealloc_ucode(drv); - - /* Build name of correct-step FW */ - snprintf(firmware_name, sizeof(firmware_name), - strrchr(drv->firmware_name, '-')); - snprintf(drv->firmware_name, sizeof(drv->firmware_name), - "%s%s", drv->cfg->fw_name_pre, firmware_name); - - /* Clear data before loading correct FW */ - list_del(&drv->list); - - /* Request correct FW file this time */ - IWL_DEBUG_INFO(drv, "attempting to load A-step FW %s\n", - drv->firmware_name); - err = request_firmware(&ucode_raw, drv->firmware_name, - drv->trans->dev); - if (err) { - IWL_ERR(drv, "Failed swapping FW!\n"); - goto out_unbind; - } - - /* Redo callback function - this time with right FW */ - iwl_req_fw_callback(ucode_raw, context); - } - - kfree(pieces); return; try_again: -- cgit v1.2.1 From a054427244158552e91dacc0a4fc0a1b5e7342b9 Mon Sep 17 00:00:00 2001 From: Moshe Harel Date: Mon, 8 Dec 2014 21:13:14 +0200 Subject: iwlwifi: mvm: support LnP 1x1 antenna configuration The antenna configuration has to be read also from OTP Currently read only from FW image Guideline: An antenna exists only if appears both in FW image & NVM Signed-off-by: Moshe Harel Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 6 ++++++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw.c | 8 ++++---- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 27 +++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 15 ++++++++------- drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | 2 +- drivers/net/wireless/iwlwifi/mvm/rs.c | 22 +++++++++++----------- drivers/net/wireless/iwlwifi/mvm/scan.c | 6 +++--- drivers/net/wireless/iwlwifi/mvm/tx.c | 2 +- drivers/net/wireless/iwlwifi/mvm/utils.c | 4 ++-- 11 files changed, 65 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 06e02fcd6f7b..c74f1a4edf23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -468,6 +468,8 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg); data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg); data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg); + data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg); + data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg); } static void iwl_set_hw_address(const struct iwl_cfg *cfg, @@ -592,6 +594,10 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw); iwl_set_radio_cfg(cfg, data, radio_cfg); + if (data->valid_tx_ant) + tx_chains &= data->valid_tx_ant; + if (data->valid_rx_ant) + rx_chains &= data->valid_rx_ant; sku = iwl_get_sku(cfg, nvm_sw); data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 33bf915cd7ea..0507647228af 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -933,7 +933,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, return -EINVAL; if (scan_rx_ant > ANT_ABC) return -EINVAL; - if (scan_rx_ant & ~mvm->fw->valid_rx_ant) + if (scan_rx_ant & ~(iwl_mvm_get_valid_rx_ant(mvm))) return -EINVAL; if (mvm->scan_rx_ant != scan_rx_ant) { diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index d0fa6e9ed590..60d0c9fdc2e7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -269,7 +269,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) enum iwl_ucode_type ucode_type = mvm->cur_ucode; /* Set parameters */ - phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config); + phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm)); phy_cfg_cmd.calib_control.event_trigger = mvm->fw->default_calib[ucode_type].event_trigger; phy_cfg_cmd.calib_control.flow_trigger = @@ -346,7 +346,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) mvm->calibrating = true; /* Send TX valid antennas before triggering calibrations */ - ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); + ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); if (ret) goto error; @@ -489,7 +489,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) mvm->fw_dbg_conf = FW_DBG_INVALID; iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_CUSTOM); - ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); + ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); if (ret) goto error; @@ -584,7 +584,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) goto error; } - ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); + ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); if (ret) goto error; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index f6d86ccce6a8..7196b4d6b7cc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -975,7 +975,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags); mvm->mgmt_last_antenna_idx = - iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, + iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), mvm->mgmt_last_antenna_idx); beacon_cmd.tx.rate_n_flags = diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d24660fb4ef2..f3cb08976e23 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -937,6 +937,33 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic); int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm); +static inline u8 iwl_mvm_get_valid_tx_ant(struct iwl_mvm *mvm) +{ + return mvm->nvm_data && mvm->nvm_data->valid_tx_ant ? + mvm->fw->valid_tx_ant & mvm->nvm_data->valid_tx_ant : + mvm->fw->valid_tx_ant; +} + +static inline u8 iwl_mvm_get_valid_rx_ant(struct iwl_mvm *mvm) +{ + return mvm->nvm_data && mvm->nvm_data->valid_rx_ant ? + mvm->fw->valid_rx_ant & mvm->nvm_data->valid_rx_ant : + mvm->fw->valid_rx_ant; +} + +static inline u32 iwl_mvm_get_phy_config(struct iwl_mvm *mvm) +{ + u32 phy_config = ~(FW_PHY_CFG_TX_CHAIN | + FW_PHY_CFG_RX_CHAIN); + u32 valid_rx_ant = iwl_mvm_get_valid_rx_ant(mvm); + u32 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); + + phy_config |= valid_tx_ant << FW_PHY_CFG_TX_CHAIN_POS | + valid_rx_ant << FW_PHY_CFG_RX_CHAIN_POS; + + return mvm->fw->phy_config & phy_config; +} + int iwl_mvm_up(struct iwl_mvm *mvm); int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 552a776962af..146554c88c14 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -139,13 +139,14 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; u32 reg_val = 0; - - radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >> - FW_PHY_CFG_RADIO_TYPE_POS; - radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >> - FW_PHY_CFG_RADIO_STEP_POS; - radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >> - FW_PHY_CFG_RADIO_DASH_POS; + u32 phy_config = iwl_mvm_get_phy_config(mvm); + + radio_cfg_type = (phy_config & FW_PHY_CFG_RADIO_TYPE) >> + FW_PHY_CFG_RADIO_TYPE_POS; + radio_cfg_step = (phy_config & FW_PHY_CFG_RADIO_STEP) >> + FW_PHY_CFG_RADIO_STEP_POS; + radio_cfg_dash = (phy_config & FW_PHY_CFG_RADIO_DASH) >> + FW_PHY_CFG_RADIO_DASH_POS; /* SKU control */ reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 1c0d4a45c1a8..540c36bae268 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -176,7 +176,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, cmd->rxchain_info |= cpu_to_le32(active_cnt << PHY_RX_CHAIN_MIMO_CNT_POS); - cmd->txchain_info = cpu_to_le32(mvm->fw->valid_tx_ant); + cmd->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); } /* diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 30ceb67ed7a7..b9682d7e82fe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -173,7 +173,7 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (sta->smps_mode == IEEE80211_SMPS_STATIC) return false; - if (num_of_ant(mvm->fw->valid_tx_ant) < 2) + if (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) < 2) return false; if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) @@ -1004,7 +1004,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, } if (num_of_ant(rate->ant) > 1) - rate->ant = first_antenna(mvm->fw->valid_tx_ant); + rate->ant = first_antenna(iwl_mvm_get_valid_tx_ant(mvm)); /* Relevant in both switching to SISO or Legacy */ rate->sgi = false; @@ -1567,7 +1567,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column]; const struct rs_tx_column *next_col; allow_column_func_t allow_func; - u8 valid_ants = mvm->fw->valid_tx_ant; + u8 valid_ants = iwl_mvm_get_valid_tx_ant(mvm); const u16 *expected_tpt_tbl; u16 tpt, max_expected_tpt; @@ -2385,7 +2385,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, int i, nentries; s8 best_rssi = S8_MIN; u8 best_ant = ANT_NONE; - u8 valid_tx_ant = mvm->fw->valid_tx_ant; + u8 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); const struct rs_init_rate_info *initial_rates; for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) { @@ -2745,7 +2745,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->ldpc = true; if (mvm->cfg->ht_params->stbc && - (num_of_ant(mvm->fw->valid_tx_ant) > 1) && + (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) lq_sta->stbc = true; } else { @@ -2757,7 +2757,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->ldpc = true; if (mvm->cfg->ht_params->stbc && - (num_of_ant(mvm->fw->valid_tx_ant) > 1) && + (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) lq_sta->stbc = true; } @@ -2785,7 +2785,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, /* These values will be overridden later */ lq_sta->lq.single_stream_ant_msk = - first_antenna(mvm->fw->valid_tx_ant); + first_antenna(iwl_mvm_get_valid_tx_ant(mvm)); lq_sta->lq.dual_stream_ant_msk = ANT_AB; /* as default allow aggregation for all tids */ @@ -2913,7 +2913,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, memcpy(&rate, initial_rate, sizeof(rate)); - valid_tx_ant = mvm->fw->valid_tx_ant; + valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); rate.stbc = rs_stbc_allow(mvm, sta, lq_sta); if (is_siso(&rate)) { @@ -3167,9 +3167,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, desc += sprintf(buff+desc, "fixed rate 0x%X\n", lq_sta->pers.dbg_fixed_rate); desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", - (mvm->fw->valid_tx_ant & ANT_A) ? "ANT_A," : "", - (mvm->fw->valid_tx_ant & ANT_B) ? "ANT_B," : "", - (mvm->fw->valid_tx_ant & ANT_C) ? "ANT_C" : ""); + (iwl_mvm_get_valid_tx_ant(mvm) & ANT_A) ? "ANT_A," : "", + (iwl_mvm_get_valid_tx_ant(mvm) & ANT_B) ? "ANT_B," : "", + (iwl_mvm_get_valid_tx_ant(mvm) & ANT_C) ? "ANT_C" : ""); desc += sprintf(buff+desc, "lq type %s\n", (is_legacy(rate)) ? "legacy" : is_vht(rate) ? "VHT" : "HT"); diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index e5294d01181e..243367650b13 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -97,7 +97,7 @@ static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) { if (mvm->scan_rx_ant != ANT_NONE) return mvm->scan_rx_ant; - return mvm->fw->valid_rx_ant; + return iwl_mvm_get_valid_rx_ant(mvm); } static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) @@ -128,7 +128,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, u32 tx_ant; mvm->scan_last_antenna_idx = - iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, + iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), mvm->scan_last_antenna_idx); tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; @@ -1603,7 +1603,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) SCAN_CONFIG_FLAG_SET_MAC_ADDR | SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| SCAN_CONFIG_N_CHANNELS(num_channels)); - scan_config->tx_chains = cpu_to_le32(mvm->fw->valid_tx_ant); + scan_config->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); scan_config->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm)); scan_config->legacy_rates = iwl_mvm_scan_config_rates(mvm); scan_config->out_of_channel_time = cpu_to_le32(170); diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 4f15d9decc81..d6cdb770881a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -209,7 +209,7 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); mvm->mgmt_last_antenna_idx = - iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, + iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), mvm->mgmt_last_antenna_idx); if (info->band == IEEE80211_BAND_2GHZ && diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index e56e77ef5d2e..f0a114102c3f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -620,7 +620,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */ - if (num_of_ant(mvm->fw->valid_rx_ant) == 1) + if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1) return; if (vif->type == NL80211_IFTYPE_AP) @@ -662,7 +662,7 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); - if (num_of_ant(mvm->fw->valid_rx_ant) == 1) + if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1) return false; if (!mvm->cfg->rx_with_siso_diversity) -- cgit v1.2.1 From b7aaeae478d352bca5e877f97898a9668c2c74fb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 7 Dec 2014 19:44:30 +0200 Subject: iwlwifi: pcie: let the Manageability Engine know when we leave When the driver is unload, the Manageability Engine should know about that - send an event to inform it about this event. Reviewed-by: Reuven Borok Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-csr.h | 1 + drivers/net/wireless/iwlwifi/iwl-prph.h | 1 + drivers/net/wireless/iwlwifi/pcie/trans.c | 21 ++++++++++++++++++--- 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index aff63c3f5bf8..7f40cf36ec0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -184,6 +184,7 @@ #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ #define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ +#define CSR_HW_IF_CONFIG_REG_ENABLE_PME (0x10000000) #define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ #define CSR_MBOX_SET_REG_OS_ALIVE BIT(5) diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 2df51eab1348..ea3b9706cbd8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -99,6 +99,7 @@ #define APMG_PCIDEV_STT_VAL_PERSIST_DIS (0x00000200) #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) +#define APMG_PCIDEV_STT_VAL_WAKE_ME (0x00004000) #define APMG_RTC_INT_STT_RFKILL (0x10000000) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 5d79a1f44b8e..4b42de3b0674 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -443,10 +443,25 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) return ret; } -static void iwl_pcie_apm_stop(struct iwl_trans *trans) +static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) { IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n"); + if (op_mode_leave) { + if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) + iwl_pcie_apm_init(trans); + + /* inform ME that we are leaving */ + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) + iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_WAKE_ME); + else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PREPARE | + CSR_HW_IF_CONFIG_REG_ENABLE_PME); + mdelay(5); + } + clear_bit(STATUS_DEVICE_ENABLED, &trans->status); /* Stop device's DMA activity */ @@ -1010,7 +1025,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* Stop the device, and put it in low power state */ - iwl_pcie_apm_stop(trans); + iwl_pcie_apm_stop(trans, false); /* Upon stop, the APM issues an interrupt if HW RF kill is set. * Clean again the interrupt here @@ -1187,7 +1202,7 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) iwl_disable_interrupts(trans); spin_unlock(&trans_pcie->irq_lock); - iwl_pcie_apm_stop(trans); + iwl_pcie_apm_stop(trans, true); spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); -- cgit v1.2.1 From 8c23f95cca0efd2b6e0a8fedd9c9285b352579c8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 4 Dec 2014 10:07:47 +0200 Subject: iwlwifi: mvm: add debugfs to trigger fw debug logs collection This allows to collect the logs even if the firmware hasn't crashed. Of course, crashing the firmware is an option, but this is easier and nicer. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 4 +++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 54 ++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw.c | 23 +++++++++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 ++ 4 files changed, 82 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index ea3b9706cbd8..83ab4239082c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -366,11 +366,15 @@ enum secure_load_status_reg { #define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c) /* FW monitor */ +#define MON_BUFF_SAMPLE_CTL (0xa03c00) #define MON_BUFF_BASE_ADDR (0xa03c3c) #define MON_BUFF_END_ADDR (0xa03c40) #define MON_BUFF_WRPTR (0xa03c44) #define MON_BUFF_CYCLE_CNT (0xa03c48) +#define DBGC_IN_SAMPLE (0xa03c00) +#define DBGC_OUT_CTRL (0xa03c0c) + /* FW chicken bits */ #define LMPM_CHICK 0xA01FF8 enum { diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 0507647228af..a1b276c4dee0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -945,6 +945,56 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, return count; } +static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + enum iwl_fw_dbg_conf conf; + char buf[8]; + const size_t bufsz = sizeof(buf); + int pos = 0; + + mutex_lock(&mvm->mutex); + conf = mvm->fw_dbg_conf; + mutex_unlock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + int ret, conf_id; + + ret = kstrtoint(buf, 0, &conf_id); + if (ret) + return ret; + + if (WARN_ON(conf_id >= FW_DBG_MAX)) + return -EINVAL; + + mutex_lock(&mvm->mutex); + ret = iwl_mvm_start_fw_dbg_conf(mvm, conf_id); + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + +static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + mutex_lock(&mvm->mutex); + iwl_mvm_fw_dbg_collect(mvm); + mutex_unlock(&mvm->mutex); + + return count; +} + #define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__) #ifdef CONFIG_IWLWIFI_BCAST_FILTERING static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file, @@ -1459,6 +1509,8 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); 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(d0i3_refs, 8); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 8); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); @@ -1500,6 +1552,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 60d0c9fdc2e7..534ee3123a63 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -70,6 +70,7 @@ #include "iwl-debug.h" #include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */ #include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */ +#include "iwl-prph.h" #include "iwl-eeprom-parse.h" #include "mvm.h" @@ -399,8 +400,26 @@ out: return ret; } -static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, - enum iwl_fw_dbg_conf conf_id) +void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm) +{ + lockdep_assert_held(&mvm->mutex); + + /* stop recording */ + if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { + iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); + } else { + iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); + iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0); + } + + iwl_mvm_fw_error_dump(mvm); + + /* start recording again */ + WARN_ON_ONCE(mvm->fw->dbg_dest_tlv && + iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf)); +} + +int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id) { u8 *ptr; int ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index f3cb08976e23..ff1a40970ac1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1371,4 +1371,7 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); +int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf id); +void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm); + #endif /* __IWL_MVM_H__ */ -- cgit v1.2.1 From f1a68542424191df21953da3cf9ac2d4116dc482 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 16 Dec 2014 12:31:13 +0200 Subject: iwlwifi: mvm: allow RSSI compensation The firmware is able to compensate the rssi when we hear the frame on a different channel. This is true for an offset up to 3 channels. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 2d62b5617a56..bec588dc1945 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -377,6 +377,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->max_remain_on_channel_duration = 10000; hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; + /* we can compensate an offset of up to 3 channels = 15 MHz */ + hw->wiphy->max_adj_channel_rssi_comp = 3 * 5; /* Extract MAC address */ memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); -- cgit v1.2.1 From 435da2ce52365d7d7c0056786eca2464d70e90a5 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 11 Dec 2014 16:11:01 -0500 Subject: iwlwifi: mvm: Set the HW step in the core dump The HW step member was left out of the core dump information. Fix this. Signed-off-by: Ido Yariv Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index bec588dc1945..2293a51f3c3a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -823,6 +823,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); + dump_info->hw_step = cpu_to_le32(CSR_HW_REV_STEP(mvm->trans->hw_rev)); memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, sizeof(dump_info->fw_human_readable)); strncpy(dump_info->dev_human_readable, mvm->cfg->name, -- cgit v1.2.1 From 19789abbe5dcd9ac1730b6acf04f2bddfeadefce Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 15 Dec 2014 14:15:15 +0200 Subject: iwlwifi: mvm: clear tt values when entering CT-kill Clear the thermal throttling values when entering CT-kill, since everything will be reinitialized anyway when we exit CT-kill. Additionally, clear the dynamic_smps value in the initialization funciton, for consistency. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 2b1e61fac34a..ba615ad2176c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -69,6 +69,7 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) { + struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; u32 duration = mvm->thermal_throttle.params->ct_kill_duration; if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) @@ -77,12 +78,15 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) IWL_ERR(mvm, "Enter CT Kill\n"); iwl_mvm_set_hw_ctkill_state(mvm, true); + tt->throttle = false; + tt->dynamic_smps = false; + /* Don't schedule an exit work if we're in test mode, since * the temperature will not change unless we manually set it * again (or disable testing). */ if (!mvm->temperature_test) - schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, + schedule_delayed_work(&tt->ct_kill_exit, round_jiffies_relative(duration * HZ)); } @@ -452,6 +456,7 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff) tt->params = &iwl7000_tt_params; tt->throttle = false; + tt->dynamic_smps = false; tt->min_backoff = min_backoff; INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); } -- cgit v1.2.1 From 6a028d9a26446a937fa5c2eaca9407985ef98add Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 7 Dec 2014 18:18:27 +0200 Subject: iwlwifi: mvm: rs: fix max rate allowed if no rate is allowed In case the rate mask for one of the modulations was zero the max rate idx for that modulation was set to 32 (BITS_PER_LONG). This is bad as it would later lead to an out of bounds access to the expected tpt table. In most cases there was no real effect as the expected tpt was set to 0 and this led to avoiding the modulation effectively. Fix the out of bounds access and explicitly skip the modulation in case there's no rate allowed in it. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index b9682d7e82fe..999efc33b9da 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1318,6 +1318,13 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, lq_sta->visited_columns = 0; } +static inline int rs_get_max_rate_from_mask(unsigned long rate_mask) +{ + if (rate_mask) + return find_last_bit(&rate_mask, BITS_PER_LONG); + return IWL_RATE_INVALID; +} + static int rs_get_max_allowed_rate(struct iwl_lq_sta *lq_sta, const struct rs_tx_column *column) { @@ -1613,8 +1620,12 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, continue; max_rate = rs_get_max_allowed_rate(lq_sta, next_col); - if (WARN_ON_ONCE(max_rate == IWL_RATE_INVALID)) + if (max_rate == IWL_RATE_INVALID) { + IWL_DEBUG_RATE(mvm, + "Skip column %d: no rate is allowed in this column\n", + next_col_id); continue; + } max_expected_tpt = expected_tpt_tbl[max_rate]; if (tpt >= max_expected_tpt) { @@ -2765,12 +2776,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (IWL_MVM_RS_DISABLE_MIMO) lq_sta->active_mimo2_rate = 0; - lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate, - BITS_PER_LONG); - lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate, - BITS_PER_LONG); - lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate, - BITS_PER_LONG); + lq_sta->max_legacy_rate_idx = + rs_get_max_rate_from_mask(lq_sta->active_legacy_rate); + lq_sta->max_siso_rate_idx = + rs_get_max_rate_from_mask(lq_sta->active_siso_rate); + lq_sta->max_mimo2_rate_idx = + rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate); IWL_DEBUG_RATE(mvm, "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n", -- cgit v1.2.1 From 363039be5b9dcbb9df9136c7106d8775f71e43c6 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Tue, 2 Dec 2014 15:19:22 +0200 Subject: iwlwifi: mvm: support additional nvm_file in family 8000 B step nvm_file in family 8000 B step and A step differ. This means that the driver should support 2 file name as default. Signed-off-by: Eran Harary Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 5 ++++- drivers/net/wireless/iwlwifi/iwl-config.h | 1 + drivers/net/wireless/iwlwifi/mvm/mac80211.c | 1 + drivers/net/wireless/iwlwifi/mvm/ops.c | 11 ++++++++--- 4 files changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 6c5c55856a35..8f64928aeb42 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -90,7 +90,8 @@ IWL8000_FW_PRE "-" __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_8000 10 -#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin" +#define DEFAULT_NVM_FILE_FAMILY_8000A "iwl_nvm_8000.bin" +#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000B.bin" /* Max SDIO RX aggregation size of the ADDBA request/response */ #define MAX_RX_AGG_SIZE_8260_SDIO 28 @@ -159,6 +160,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, + .default_nvm_file_8000A = DEFAULT_NVM_FILE_FAMILY_8000A, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, .disable_dummy_notification = true, .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, @@ -173,6 +175,7 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = { .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, + .default_nvm_file_8000A = DEFAULT_NVM_FILE_FAMILY_8000A, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, .bt_shared_single_ant = true, .disable_dummy_notification = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 31c67dfabf55..2daabab7ec3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -300,6 +300,7 @@ struct iwl_cfg { const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; bool no_power_up_nic_in_init; const char *default_nvm_file; + const char *default_nvm_file_8000A; unsigned int max_rx_agg_size; bool disable_dummy_notification; unsigned int max_tx_agg_size; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 2293a51f3c3a..f53bfd6e8df8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -85,6 +85,7 @@ #include "testmode.h" #include "iwl-fw-error-dump.h" #include "iwl-prph.h" +#include "iwl-csr.h" static const struct ieee80211_iface_limit iwl_mvm_limits[] = { { diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 146554c88c14..b2fa3b878f79 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -511,10 +511,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, min_backoff = calc_min_backoff(trans, cfg); iwl_mvm_tt_initialize(mvm, min_backoff); /* set the nvm_file_name according to priority */ - if (iwlwifi_mod_params.nvm_file) + if (iwlwifi_mod_params.nvm_file) { mvm->nvm_file_name = iwlwifi_mod_params.nvm_file; - else - mvm->nvm_file_name = mvm->cfg->default_nvm_file; + } else { + if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) && + (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) + mvm->nvm_file_name = mvm->cfg->default_nvm_file_8000A; + else + mvm->nvm_file_name = mvm->cfg->default_nvm_file; + } if (WARN(cfg->no_power_up_nic_in_init && !mvm->nvm_file_name, "not allowing power-up and not having nvm_file\n")) -- cgit v1.2.1 From addfaada8fd044ad8cb365a792a09b1b3265376f Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Tue, 2 Dec 2014 11:16:04 +0200 Subject: iwlwifi: mvm: add smem content to dump data In NICs that have SMEM - add its content to the dump data for later debug. Signed-off-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 8 ++++++-- drivers/net/wireless/iwlwifi/iwl-config.h | 4 ++++ drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 8f64928aeb42..46e9c9ac6ba2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -81,9 +81,11 @@ #define IWL8000_NVM_VERSION 0x0a1d #define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ -/* DCCM offsets and lengths */ +/* Memory offsets and lengths */ #define IWL8260_DCCM_OFFSET 0x800000 #define IWL8260_DCCM_LEN 0x18000 +#define IWL8260_SMEM_OFFSET 0x400000 +#define IWL8260_SMEM_LEN 0x68000 #define IWL8000_FW_PRE "iwlwifi-8000" #define IWL8000_MODULE_FIRMWARE(api) \ @@ -131,7 +133,9 @@ static const struct iwl_ht_params iwl8000_ht_params = { .d0i3 = true, \ .non_shared_ant = ANT_A, \ .dccm_offset = IWL8260_DCCM_OFFSET, \ - .dccm_len = IWL8260_DCCM_LEN + .dccm_len = IWL8260_DCCM_LEN, \ + .smem_offset = IWL8260_SMEM_OFFSET, \ + .smem_len = IWL8260_SMEM_LEN const struct iwl_cfg iwl8260_2n_cfg = { .name = "Intel(R) Dual Band Wireless N 8260", diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 2daabab7ec3f..398505121b59 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -263,6 +263,8 @@ struct iwl_pwr_tx_backoff { * station can receive in VHT * @dccm_offset: offset from which DCCM begins * @dccm_len: length of DCCM (including runtime stack CCM) + * @smem_offset: offset from which the SMEM begins + * @smem_len: the length of SMEM * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -308,6 +310,8 @@ struct iwl_cfg { unsigned int max_vht_ampdu_exponent; const u32 dccm_offset; const u32 dccm_len; + const u32 smem_offset; + const u32 smem_len; }; /* diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index 20a8a64c9fe3..c6a81a760cf6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -82,6 +82,7 @@ * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several * sections like this in a single file. * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers + * @IWL_FW_ERROR_DUMP_SMEM: */ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_SRAM = 0, @@ -93,6 +94,7 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_PRPH = 6, IWL_FW_ERROR_DUMP_TXF = 7, IWL_FW_ERROR_DUMP_FH_REGS = 8, + IWL_FW_ERROR_DUMP_SMEM = 9, IWL_FW_ERROR_DUMP_MAX, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index f53bfd6e8df8..d5d1cdaa0310 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -774,9 +774,16 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) u32 file_len, rxf_len; unsigned long flags; int reg_val; + u32 smem_len = mvm->cfg->smem_len; lockdep_assert_held(&mvm->mutex); + /* W/A for 8000 HW family A-step */ + if (mvm->cfg->smem_len && + mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) + smem_len = 0x38000; + fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); if (!fw_error_dump) return; @@ -806,6 +813,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) rxf_len + sizeof(*dump_info); + /* Make room for the SMEM, if it exists */ + if (smem_len) + file_len += sizeof(*dump_data) + smem_len; + dump_file = vzalloc(file_len); if (!dump_file) { kfree(fw_error_dump); @@ -856,6 +867,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, sram_len); + if (smem_len) { + dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SMEM); + dump_data->len = cpu_to_le32(smem_len); + iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->smem_offset, + dump_data->data, smem_len); + } + fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); fw_error_dump->op_mode_len = file_len; if (fw_error_dump->trans_ptr) -- cgit v1.2.1 From e06d8437cdf903a39bf93f16338c5b5a37810017 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 9 Dec 2014 14:36:41 +0200 Subject: iwlwifi: mvm: change SMEM dump to general purpose memory dump Instead of adding a dump type for each type of memory, change the SMEM type to be a general purpose memory dump. Add the type of the memory and its offset in the device in the dump itself. This will allow an external parser to know where this memory came from. Note that since this type isn't really in use yet, this is not a real problem. Reviewed-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 21 +++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 14 ++++++++++---- 2 files changed, 29 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index c6a81a760cf6..c0fe82c13007 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -82,7 +82,7 @@ * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several * sections like this in a single file. * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers - * @IWL_FW_ERROR_DUMP_SMEM: + * @IWL_FW_ERROR_DUMP_MEM: chunk of memory */ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_SRAM = 0, @@ -94,7 +94,7 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_PRPH = 6, IWL_FW_ERROR_DUMP_TXF = 7, IWL_FW_ERROR_DUMP_FH_REGS = 8, - IWL_FW_ERROR_DUMP_SMEM = 9, + IWL_FW_ERROR_DUMP_MEM = 9, IWL_FW_ERROR_DUMP_MAX, }; @@ -182,6 +182,23 @@ struct iwl_fw_error_dump_prph { __le32 data[]; }; +enum iwl_fw_error_dump_mem_type { + IWL_FW_ERROR_DUMP_MEM_SRAM, + IWL_FW_ERROR_DUMP_MEM_SMEM, +}; + +/** + * struct iwl_fw_error_dump_mem - chunk of memory + * @type: %enum iwl_fw_error_dump_mem_type + * @offset: the offset from which the memory was read + * @data: the content of the memory + */ +struct iwl_fw_error_dump_mem { + __le32 type; + __le32 offset; + u8 data[]; +}; + /** * iwl_fw_error_next_data - advance fw error dump data pointer * @data: previous data block diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index d5d1cdaa0310..e24de9712476 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -815,7 +815,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) /* Make room for the SMEM, if it exists */ if (smem_len) - file_len += sizeof(*dump_data) + smem_len; + file_len += sizeof(*dump_data) + + sizeof(struct iwl_fw_error_dump_mem) + smem_len; dump_file = vzalloc(file_len); if (!dump_file) { @@ -868,11 +869,16 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) sram_len); if (smem_len) { + struct iwl_fw_error_dump_mem *dump_mem; + dump_data = iwl_fw_error_next_data(dump_data); - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SMEM); - dump_data->len = cpu_to_le32(smem_len); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem)); + dump_mem = (void *)dump_data->data; + dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM); + dump_mem->offset = cpu_to_le32(mvm->cfg->smem_offset); iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->smem_offset, - dump_data->data, smem_len); + dump_mem->data, smem_len); } fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); -- cgit v1.2.1 From a549b296228497cec90d3a5f5ecaa1934cec4bf1 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 9 Dec 2014 14:47:57 +0200 Subject: iwlwifi: mvm: convert the SRAM dump to the generic memory dump This allows to add the offset. The type of the generic memory dump will let the parser know that this is SRAM. Reviewed-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 3 +-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 17 +++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index c0fe82c13007..ec115bded88a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -71,7 +71,6 @@ /** * enum iwl_fw_error_dump_type - types of data in the dump file - * @IWL_FW_ERROR_DUMP_SRAM: * @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0 * @IWL_FW_ERROR_DUMP_RXF: * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as @@ -85,7 +84,7 @@ * @IWL_FW_ERROR_DUMP_MEM: chunk of memory */ enum iwl_fw_error_dump_type { - IWL_FW_ERROR_DUMP_SRAM = 0, + /* 0 is deprecated */ IWL_FW_ERROR_DUMP_CSR = 1, IWL_FW_ERROR_DUMP_RXF = 2, IWL_FW_ERROR_DUMP_TXCMD = 3, diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e24de9712476..b2f4ea597473 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -769,6 +769,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; + struct iwl_fw_error_dump_mem *dump_mem; struct iwl_mvm_dump_ptrs *fw_error_dump; u32 sram_len, sram_ofs; u32 file_len, rxf_len; @@ -809,14 +810,13 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) file_len = sizeof(*dump_file) + sizeof(*dump_data) * 3 + - sram_len + + sram_len + sizeof(*dump_mem) + rxf_len + sizeof(*dump_info); /* Make room for the SMEM, if it exists */ if (smem_len) - file_len += sizeof(*dump_data) + - sizeof(struct iwl_fw_error_dump_mem) + smem_len; + file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; dump_file = vzalloc(file_len); if (!dump_file) { @@ -863,14 +863,15 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } dump_data = iwl_fw_error_next_data(dump_data); - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); - dump_data->len = cpu_to_le32(sram_len); - iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); + dump_mem = (void *)dump_data->data; + dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); + dump_mem->offset = cpu_to_le32(sram_ofs); + iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_mem->data, sram_len); if (smem_len) { - struct iwl_fw_error_dump_mem *dump_mem; - dump_data = iwl_fw_error_next_data(dump_data); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem)); -- cgit v1.2.1 From 7616f334e6d441aa9824221b1352ebec9de57ad7 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 20 Nov 2014 17:33:43 +0200 Subject: iwlwifi: pcie: add basic reference accounting Implement the ref/unref trans ops and track both tx and host command queues (and hold references while they are not empty). Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 5 ++++ drivers/net/wireless/iwlwifi/iwl-modparams.h | 2 ++ drivers/net/wireless/iwlwifi/pcie/internal.h | 8 ++++++ drivers/net/wireless/iwlwifi/pcie/trans.c | 39 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/pcie/tx.c | 34 ++++++++++++++++++++---- 5 files changed, 83 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index afa63f7b2d3e..0381dc495b1c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1362,6 +1362,7 @@ struct iwl_mod_params iwlwifi_mod_params = { .bt_coex_active = true, .power_level = IWL_POWER_INDEX_1, .wd_disable = true, + .d0i3_disable = true, #ifndef CONFIG_IWLWIFI_UAPSD .uapsd_disable = true, #endif /* CONFIG_IWLWIFI_UAPSD */ @@ -1478,6 +1479,10 @@ MODULE_PARM_DESC(wd_disable, module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); MODULE_PARM_DESC(nvm_file, "NVM file name"); +module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable, + bool, S_IRUGO); +MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)"); + module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, bool, S_IRUGO); #ifdef CONFIG_IWLWIFI_UAPSD diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index 71507cf490e6..2a8cf4b2445c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -103,6 +103,7 @@ enum iwl_disable_11n { * @power_level: power level, default = 1 * @debug_level: levels are IWL_DL_* * @ant_coupling: antenna coupling in dB, default = 0 + * @d0i3_disable: disable d0i3, default = 1, * @fw_monitor: allow to use firmware monitor */ struct iwl_mod_params { @@ -121,6 +122,7 @@ struct iwl_mod_params { int ant_coupling; char *nvm_file; bool uapsd_disable; + bool d0i3_disable; bool fw_monitor; }; diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 1aea6b66c594..e5652d82d79e 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -318,6 +318,11 @@ struct iwl_trans_pcie { /*protect hw register */ spinlock_t reg_lock; bool cmd_in_flight; + bool ref_cmd_in_flight; + + /* protect ref counter */ + spinlock_t ref_lock; + u32 ref_count; dma_addr_t fw_mon_phys; struct page *fw_mon_page; @@ -381,6 +386,9 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs); void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); +void iwl_trans_pcie_ref(struct iwl_trans *trans); +void iwl_trans_pcie_unref(struct iwl_trans *trans); + static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) { struct iwl_tfd_tb *tb = &tfd->tbs[idx]; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 4b42de3b0674..fbdbec89ad70 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -931,6 +931,7 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; bool hw_rfkill; @@ -960,6 +961,9 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, return ret; } + /* init ref_count to 1 (should be cleared when ucode is loaded) */ + trans_pcie->ref_count = 1; + /* make sure rfkill handshake bits are cleared */ iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, @@ -1550,6 +1554,38 @@ static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg, spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); } +void iwl_trans_pcie_ref(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned long flags; + + if (iwlwifi_mod_params.d0i3_disable) + return; + + spin_lock_irqsave(&trans_pcie->ref_lock, flags); + IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count); + trans_pcie->ref_count++; + spin_unlock_irqrestore(&trans_pcie->ref_lock, flags); +} + +void iwl_trans_pcie_unref(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned long flags; + + if (iwlwifi_mod_params.d0i3_disable) + return; + + spin_lock_irqsave(&trans_pcie->ref_lock, flags); + IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count); + if (WARN_ON_ONCE(trans_pcie->ref_count == 0)) { + spin_unlock_irqrestore(&trans_pcie->ref_lock, flags); + return; + } + trans_pcie->ref_count--; + spin_unlock_irqrestore(&trans_pcie->ref_lock, flags); +} + static const char *get_csr_string(int cmd) { #define IWL_CMD(x) case x: return #x @@ -2274,6 +2310,9 @@ static const struct iwl_trans_ops trans_ops_pcie = { .release_nic_access = iwl_trans_pcie_release_nic_access, .set_bits_mask = iwl_trans_pcie_set_bits_mask, + .ref = iwl_trans_pcie_ref, + .unref = iwl_trans_pcie_unref, + .dump_data = iwl_trans_pcie_dump_data, }; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8a6c7a084aa1..c1c4c75026b2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -985,17 +985,31 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, if (iwl_queue_space(&txq->q) > txq->q.low_mark) iwl_wake_queue(trans, txq); + + if (q->read_ptr == q->write_ptr) { + IWL_DEBUG_RPM(trans, "Q %d - last tx reclaimed\n", q->id); + iwl_trans_pcie_unref(trans); + } + out: spin_unlock_bh(&txq->lock); } -static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans) +static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, + const struct iwl_host_cmd *cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; lockdep_assert_held(&trans_pcie->reg_lock); + if (!(cmd->flags & CMD_SEND_IN_IDLE) && + !trans_pcie->ref_cmd_in_flight) { + trans_pcie->ref_cmd_in_flight = true; + IWL_DEBUG_RPM(trans, "set ref_cmd_in_flight - ref\n"); + iwl_trans_pcie_ref(trans); + } + if (trans_pcie->cmd_in_flight) return 0; @@ -1036,6 +1050,12 @@ static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) lockdep_assert_held(&trans_pcie->reg_lock); + if (trans_pcie->ref_cmd_in_flight) { + trans_pcie->ref_cmd_in_flight = false; + IWL_DEBUG_RPM(trans, "clear ref_cmd_in_flight - unref\n"); + iwl_trans_pcie_unref(trans); + } + if (WARN_ON(!trans_pcie->cmd_in_flight)) return 0; @@ -1473,7 +1493,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); spin_lock_irqsave(&trans_pcie->reg_lock, flags); - ret = iwl_pcie_set_cmd_in_flight(trans); + ret = iwl_pcie_set_cmd_in_flight(trans, cmd); if (ret < 0) { idx = ret; spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); @@ -1819,9 +1839,13 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, wait_write_ptr = ieee80211_has_morefrags(fc); /* start timer if queue currently empty */ - if (txq->need_update && q->read_ptr == q->write_ptr && - trans_pcie->wd_timeout) - mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); + if (q->read_ptr == q->write_ptr) { + if (txq->need_update && trans_pcie->wd_timeout) + mod_timer(&txq->stuck_timer, + jiffies + trans_pcie->wd_timeout); + IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id); + iwl_trans_pcie_ref(trans); + } /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr); -- cgit v1.2.1 From 91742449479bd8666f9533efd9594a7d9f87bd0d Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 9 Dec 2014 15:54:46 +0200 Subject: iwlwifi: mvm: allow both d0i3 and d3 wowlan configuration modes d3 and d0i3 shouldn't be mutually exclusive. Set supported wowlan triggers by looking for each of them, and check on suspend/resume which flow should be used ("any" trigger is supported by d0i3, and all the others by d3) Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 7 +++++-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 14 ++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 744de262373e..a64894c40e8f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1142,7 +1142,8 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); iwl_trans_suspend(mvm->trans); - if (iwl_mvm_is_d0i3_supported(mvm)) { + if (wowlan->any) { + /* 'any' trigger means d0i3 usage */ mutex_lock(&mvm->d0i3_suspend_mutex); __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); mutex_unlock(&mvm->d0i3_suspend_mutex); @@ -1876,8 +1877,10 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) iwl_trans_resume(mvm->trans); - if (iwl_mvm_is_d0i3_supported(mvm)) + if (mvm->hw->wiphy->wowlan_config->any) { + /* 'any' trigger means d0i3 usage */ return 0; + } return __iwl_mvm_resume(mvm, false); } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index b2f4ea597473..fd0f8ce0f79d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -462,15 +462,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) device_can_wakeup(mvm->trans->dev)) { mvm->wowlan.flags = WIPHY_WOWLAN_ANY; hw->wiphy->wowlan = &mvm->wowlan; - } else if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && + } + + if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && mvm->trans->ops->d3_suspend && mvm->trans->ops->d3_resume && device_can_wakeup(mvm->trans->dev)) { - mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | - WIPHY_WOWLAN_DISCONNECT | - WIPHY_WOWLAN_EAP_IDENTITY_REQ | - WIPHY_WOWLAN_RFKILL_RELEASE | - WIPHY_WOWLAN_NET_DETECT; + mvm->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_RFKILL_RELEASE | + WIPHY_WOWLAN_NET_DETECT; if (!iwlwifi_mod_params.sw_crypto) mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_GTK_REKEY_FAILURE | -- cgit v1.2.1 From 0f8f93d6c81817d902fb46b0d741164992cc685a Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 9 Dec 2014 15:11:56 +0200 Subject: iwlwifi: support multiple d0i3 modes Allow configuring additional d0i3 mode, in which the fw will be configured to enter d0i3 only on suspend (while keeping the wake_lock accounting as usual) The d0i3 mode to use will be determined by the underlying trans layer. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 17 +++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + 2 files changed, 18 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 028408a6ecba..10ae9d7da0af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -551,6 +551,21 @@ enum iwl_trans_state { IWL_TRANS_FW_ALIVE = 1, }; +/** + * enum iwl_d0i3_mode - d0i3 mode + * + * @IWL_D0I3_MODE_OFF - d0i3 is disabled + * @IWL_D0I3_MODE_ON_IDLE - enter d0i3 when device is idle + * (e.g. no active references) + * @IWL_D0I3_MODE_ON_SUSPEND - enter d0i3 only on suspend + * (in case of 'any' trigger) + */ +enum iwl_d0i3_mode { + IWL_D0I3_MODE_OFF = 0, + IWL_D0I3_MODE_ON_IDLE, + IWL_D0I3_MODE_ON_SUSPEND, +}; + /** * struct iwl_trans - transport common data * @@ -612,6 +627,8 @@ struct iwl_trans { const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; u8 dbg_dest_reg_num; + enum iwl_d0i3_mode d0i3_mode; + /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ char trans_specific[0] __aligned(sizeof(void *)); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index ff1a40970ac1..e608dc4e76e1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -850,6 +850,7 @@ iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) { return mvm->trans->cfg->d0i3 && + mvm->trans->d0i3_mode != IWL_D0I3_MODE_OFF && (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); } -- cgit v1.2.1 From 6735943fafeaf55223b8704e52568b89ac3129e3 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 9 Dec 2014 15:23:54 +0200 Subject: iwlwifi: mvm: support IWL_D0I3_MODE_ON_SUSPEND d0i3 mode Enter d0i3 on suspend, and exit d0i3. Wait for the command responses in both cases. Use this mode in case of pcie trans. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 40 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 7 +++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/ops.c | 5 ++-- drivers/net/wireless/iwlwifi/pcie/trans.c | 1 + 5 files changed, 53 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index a64894c40e8f..4b5849eaac61 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1137,6 +1137,29 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, return ret; } +static int iwl_mvm_enter_d0i3_sync(struct iwl_mvm *mvm) +{ + struct iwl_notification_wait wait_d3; + static const u8 d3_notif[] = { D3_CONFIG_CMD }; + int ret; + + iwl_init_notification_wait(&mvm->notif_wait, &wait_d3, + d3_notif, ARRAY_SIZE(d3_notif), + NULL, NULL); + + ret = iwl_mvm_enter_d0i3(mvm->hw->priv); + if (ret) + goto remove_notif; + + ret = iwl_wait_notification(&mvm->notif_wait, &wait_d3, HZ); + WARN_ON_ONCE(ret); + return ret; + +remove_notif: + iwl_remove_notification(&mvm->notif_wait, &wait_d3); + return ret; +} + int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -1144,6 +1167,13 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) iwl_trans_suspend(mvm->trans); if (wowlan->any) { /* 'any' trigger means d0i3 usage */ + if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { + int ret = iwl_mvm_enter_d0i3_sync(mvm); + + if (ret) + return ret; + } + mutex_lock(&mvm->d0i3_suspend_mutex); __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); mutex_unlock(&mvm->d0i3_suspend_mutex); @@ -1879,6 +1909,16 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) if (mvm->hw->wiphy->wowlan_config->any) { /* 'any' trigger means d0i3 usage */ + if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { + int ret = iwl_mvm_exit_d0i3(hw->priv); + + if (ret) + return ret; + /* + * d0i3 exit will be deferred until reconfig_complete. + * make sure there we are out of d0i3. + */ + } return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index fd0f8ce0f79d..29f0feb1dbd2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1021,6 +1021,13 @@ static void iwl_mvm_resume_complete(struct iwl_mvm *mvm) IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n"); _iwl_mvm_exit_d0i3(mvm); } + + if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) + if (!wait_event_timeout(mvm->d0i3_exit_waitq, + !test_bit(IWL_MVM_STATUS_IN_D0I3, + &mvm->status), + HZ)) + WARN_ONCE(1, "D0i3 exit on resume timed out\n"); } static void diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e608dc4e76e1..33a674af606c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1187,6 +1187,8 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); bool iwl_mvm_ref_taken(struct iwl_mvm *mvm); void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); +int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode); +int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode); int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); /* BT Coex */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index b2fa3b878f79..17f58ca4bcba 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -1030,7 +1030,8 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, out: rcu_read_unlock(); } -static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) + +int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; @@ -1244,7 +1245,7 @@ out: return ret; } -static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) +int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index fbdbec89ad70..daec2f86eec0 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2453,6 +2453,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } trans_pcie->inta_mask = CSR_INI_SET_MASK; + trans->d0i3_mode = IWL_D0I3_MODE_ON_SUSPEND; return trans; -- cgit v1.2.1 From b0677f71333032c384641b874c26b8871431a009 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Dec 2014 17:49:28 +0200 Subject: iwlwifi: mvm: consider d0i3_disable in iwl_mvm_is_d0i3_supported() Consider the iwlwifi module param d0i3_disable when considering whether d0i3 is supported. (There is currently no need to differentiate between supported and enabled, so keep the function as-is) Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 33a674af606c..b2100b414055 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -851,6 +851,7 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) { return mvm->trans->cfg->d0i3 && mvm->trans->d0i3_mode != IWL_D0I3_MODE_OFF && + !iwlwifi_mod_params.d0i3_disable && (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); } -- cgit v1.2.1 From 37948fcfd0bef2344df4245f231947cbadb6341a Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 11 Dec 2014 10:48:18 +0200 Subject: iwlwifi: mvm: wait for d0i3 exit on hw restart On hw restart, make sure to wait for d0i3 exit (by checking the IN_D0I3 status bit). This is needed in order to avoid the stale d0i3_exit_work from doing harm (e.g. unref cleared reference). Signed-off-by: Eliad Peller Reviewed-by: Gregory Greenman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 29f0feb1dbd2..9ccecbc588f9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -972,6 +972,19 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; + /* Some hw restart cleanups must not hold the mutex */ + if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + /* + * Make sure we are out of d0i3. This is needed + * to make sure the reference accounting is correct + * (and there is no stale d0i3_exit_work). + */ + wait_event_timeout(mvm->d0i3_exit_waitq, + !test_bit(IWL_MVM_STATUS_IN_D0I3, + &mvm->status), + HZ); + } + mutex_lock(&mvm->mutex); ret = __iwl_mvm_mac_start(mvm); mutex_unlock(&mvm->mutex); -- cgit v1.2.1 From 2624a5ca76eff87e92ec2be9ea76dd382993bd19 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 16 Dec 2014 13:02:03 +0200 Subject: iwlwifi: mvm: support 2 different channels The driver and the firmware now support 2 different channels at the same time. Advertise this capability to the stack. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 9ccecbc588f9..4db051d84f1c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -106,7 +106,7 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = { static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { { - .num_different_channels = 1, + .num_different_channels = 2, .max_interfaces = 3, .limits = iwl_mvm_limits, .n_limits = ARRAY_SIZE(iwl_mvm_limits), -- cgit v1.2.1 From c1dc8288fe15425bb0620df9959182f32de51b4c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:43 +0100 Subject: iwlwifi: dvm: tt: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.data = d; -t.function = f; // Signed-off-by: Julia Lawall Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/tt.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c index acb981a0a0aa..c4736c8834c5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/iwlwifi/dvm/tt.c @@ -612,15 +612,10 @@ void iwl_tt_initialize(struct iwl_priv *priv) memset(tt, 0, sizeof(struct iwl_tt_mgmt)); tt->state = IWL_TI_0; - init_timer(&priv->thermal_throttle.ct_kill_exit_tm); - priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; - priv->thermal_throttle.ct_kill_exit_tm.function = - iwl_tt_check_exit_ct_kill; - init_timer(&priv->thermal_throttle.ct_kill_waiting_tm); - priv->thermal_throttle.ct_kill_waiting_tm.data = - (unsigned long)priv; - priv->thermal_throttle.ct_kill_waiting_tm.function = - iwl_tt_ready_for_ct_kill; + setup_timer(&priv->thermal_throttle.ct_kill_exit_tm, + iwl_tt_check_exit_ct_kill, (unsigned long)priv); + setup_timer(&priv->thermal_throttle.ct_kill_waiting_tm, + iwl_tt_ready_for_ct_kill, (unsigned long)priv); /* setup deferred ct kill work */ INIT_WORK(&priv->tt_work, iwl_bg_tt_work); INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); -- cgit v1.2.1 From bd9c504bfd659e58d3537123e6798a9b83a2263d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:44 +0100 Subject: iwlwifi: dvm: main: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.data = d; -t.function = f; // Signed-off-by: Julia Lawall Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/main.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index fcdc128298ea..de43dd7e170a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -997,13 +997,11 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) if (priv->lib->bt_params) iwlagn_bt_setup_deferred_work(priv); - init_timer(&priv->statistics_periodic); - priv->statistics_periodic.data = (unsigned long)priv; - priv->statistics_periodic.function = iwl_bg_statistics_periodic; + setup_timer(&priv->statistics_periodic, iwl_bg_statistics_periodic, + (unsigned long)priv); - init_timer(&priv->ucode_trace); - priv->ucode_trace.data = (unsigned long)priv; - priv->ucode_trace.function = iwl_bg_ucode_trace; + setup_timer(&priv->ucode_trace, iwl_bg_ucode_trace, + (unsigned long)priv); } void iwl_cancel_deferred_work(struct iwl_priv *priv) -- cgit v1.2.1 From 744cb695643ac111c422e4c517961646561b6895 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 10 Dec 2014 18:44:13 +0200 Subject: iwlwifi: mvm: clean refs before stop_device() Some implementations (i.e. mini_rpm) assume the references are managed only while the device is started. Move the stale reference cleanup before stopping the device in order to make them happy. Signed-off-by: Eliad Peller Signed-off-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 4db051d84f1c..084689b9b93c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -903,6 +903,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) iwl_mvm_fw_error_dump(mvm); + /* cleanup all stale references (scan, roc), but keep the + * ucode_down ref until reconfig is complete + */ + iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); + iwl_trans_stop_device(mvm->trans); mvm->scan_status = IWL_MVM_SCAN_NONE; @@ -932,10 +937,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) ieee80211_wake_queues(mvm->hw); - /* cleanup all stale references (scan, roc), but keep the - * ucode_down ref until reconfig is complete */ - iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); - /* clear any stale d0i3 state */ clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); -- cgit v1.2.1 From a70393fc4ec15777afeba21df08335ddd09c2ed0 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 18 Dec 2014 09:15:13 +0200 Subject: iwlwifi: remove useless extern definition of iwl4265_2ac_sdio_cfg This device was renamed, but the external definition remained there. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-config.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 398505121b59..fa0bc4845e1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -379,7 +379,6 @@ extern const struct iwl_cfg iwl7265d_n_cfg; extern const struct iwl_cfg iwl8260_2n_cfg; extern const struct iwl_cfg iwl8260_2ac_cfg; extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; -extern const struct iwl_cfg iwl4265_2ac_sdio_cfg; extern const struct iwl_cfg iwl4165_2ac_sdio_cfg; #endif /* CONFIG_IWLMVM */ -- cgit v1.2.1 From 5b530e95a95d17f004702cd829e42e171179f529 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Dec 2014 16:00:17 +0100 Subject: iwlwifi: mvm: use iwl_mvm_vif_from_mac80211() consistently There are a few places not using it, use it at those places. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/sta.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index a3bfda45d9e6..d2fd48c31d3d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -989,7 +989,7 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_bt_iterator_data *data = _data; struct iwl_mvm *mvm = data->mvm; @@ -1025,7 +1025,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event rssi_event) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_bt_iterator_data data = { .mvm = mvm, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index b3210cfbecc8..973f2881dd1d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -1034,7 +1034,7 @@ int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_bt_iterator_data *data = _data; struct iwl_mvm *mvm = data->mvm; @@ -1070,7 +1070,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event rssi_event) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_bt_iterator_data data = { .mvm = mvm, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index d86fe432e51f..9eaa96ec6bad 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1144,7 +1144,7 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); if (sta) { struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; @@ -1280,7 +1280,7 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); if (sta) return sta->addr; -- cgit v1.2.1 From 9d8ce6afe19e8b5fea175ece550ec1f9d1024f8d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Dec 2014 16:02:40 +0100 Subject: iwlwifi: mvm: use iwl_mvm_sta_from_mac80211() consistently A number of places (still) use a direct operation, use iwl_mvm_sta_from_mac80211() consistently. In one place also move it into the variable initializer. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- drivers/net/wireless/iwlwifi/mvm/rs.c | 13 +++++-------- drivers/net/wireless/iwlwifi/mvm/sta.c | 12 ++++++------ 6 files changed, 17 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 4b5849eaac61..14e8fd661889 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -793,7 +793,7 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, struct ieee80211_sta *ap_sta) { int ret; - struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; + struct iwl_mvm_sta *mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); /* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */ @@ -1657,7 +1657,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, if (IS_ERR_OR_NULL(ap_sta)) goto out_free; - mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; + mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); for (i = 0; i < IWL_MAX_TID_COUNT; i++) { u16 seq = status.qos_seq_ctr[i]; /* firmware stores last-used value, we store next value */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 9aa2311a776c..8dc3ca9f4904 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -268,7 +268,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id], lockdep_is_held(&mvm->mutex)); if (!IS_ERR_OR_NULL(sta)) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); pos += scnprintf(buf+pos, bufsz-pos, "ap_sta_id %d - reduced Tx power %d\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 084689b9b93c..c4552b5f5c19 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2137,7 +2137,7 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); /* * This is called before mac80211 does RCU synchronisation, @@ -3152,7 +3152,7 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw, bool set) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); if (!mvm_sta || !mvm_sta->vif) { IWL_ERR(mvm, "Station is not associated to a vif\n"); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 17f58ca4bcba..6bb6546a734b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -1146,7 +1146,7 @@ void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) if (mvm->d0i3_offloading && qos_seq) { /* update qos seq numbers if offloading was enabled */ - mvm_ap_sta = (struct iwl_mvm_sta *)sta->drv_priv; + mvm_ap_sta = iwl_mvm_sta_from_mac80211(sta); for (i = 0; i < IWL_MAX_TID_COUNT; i++) { u16 seq = le16_to_cpu(qos_seq[i]); /* firmware stores last-used one, we store next one */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 999efc33b9da..568829db2119 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1946,7 +1946,7 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct ieee80211_vif *vif = mvm_sta->vif; struct ieee80211_chanctx_conf *chanctx_conf; enum ieee80211_band band; @@ -2055,7 +2055,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, u16 high_low; s32 sr; u8 prev_agg = lq_sta->is_agg; - struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; + struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data; struct rs_rate *rate; @@ -2541,7 +2541,7 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, gfp_t gfp) { - struct iwl_mvm_sta *sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; + struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_rate; struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta; @@ -2694,14 +2694,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct ieee80211_hw *hw = mvm->hw; struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; - struct iwl_mvm_sta *sta_priv; - struct iwl_lq_sta *lq_sta; + struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); + struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta; struct ieee80211_supported_band *sband; unsigned long supp; /* must be unsigned long for for_each_set_bit */ - sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; - lq_sta = &sta_priv->lq_sta; - /* clear all non-persistent lq data */ memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers)); diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 9eaa96ec6bad..ad327984b099 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -99,7 +99,7 @@ static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, bool update) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd add_sta_cmd = { .sta_id = mvm_sta->sta_id, .mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color), @@ -259,7 +259,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); int i, ret, sta_id; lockdep_assert_held(&mvm->mutex); @@ -481,7 +481,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); int ret; lockdep_assert_held(&mvm->mutex); @@ -774,7 +774,7 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u16 ssn, bool start) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd cmd = {}; int ret; u32 status; @@ -834,7 +834,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u8 queue, bool start) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd cmd = {}; int ret; u32 status; @@ -1147,7 +1147,7 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); if (sta) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); return mvm_sta->sta_id; } -- cgit v1.2.1 From b48217670f6e98491b7cff6b66534b4651347763 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 19 Oct 2014 16:58:15 +0200 Subject: iwlwifi: tlv: add support for IWL_UCODE_TLV_SDIO_ADMA_ADDR TLV A new TLV supplies the ADMA address for SDIO mode, allowing the driver to configure the default base address to be this (as given in the FW), rather than hardcoding the values to use until the FW sends the ALIVE message. Use the value given by the FW in the IWL_UCODE_TLV_SDIO_ADMA_ADDR TLV for setting the default SDTM base address until the FW sends the ALIVE message. If it isn't given in the FW - use the current hardcoded values. Signed-off-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 6 ++++++ drivers/net/wireless/iwlwifi/iwl-fw-file.h | 1 + drivers/net/wireless/iwlwifi/iwl-fw.h | 4 ++++ drivers/net/wireless/iwlwifi/iwl-trans.h | 4 ++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 2 ++ 5 files changed, 17 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 0381dc495b1c..0d3472679e4d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -903,6 +903,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, IWL_UCODE_REGULAR_USNIFFER, tlv_len); break; + case IWL_UCODE_TLV_SDIO_ADMA_ADDR: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + drv->fw.sdio_adma_addr = + le32_to_cpup((__le32 *)tlv_data); + break; default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); break; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index f2a047f6bb3e..752c72b77fba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -132,6 +132,7 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, IWL_UCODE_TLV_SEC_RT_USNIFFER = 34, + IWL_UCODE_TLV_SDIO_ADMA_ADDR = 35, IWL_UCODE_TLV_FW_DBG_DEST = 38, IWL_UCODE_TLV_FW_DBG_CONF = 39, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index e6dc3b870949..ffd785cc67d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -152,6 +152,8 @@ struct iwl_fw_cscheme_list { * @mvm_fw: indicates this is MVM firmware * @cipher_scheme: optional external cipher scheme. * @human_readable: human readable version + * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until + * we get the ALIVE from the uCode * @dbg_dest_tlv: points to the destination TLV for debug * @dbg_conf_tlv: array of pointers to configuration TLVs for debug * @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries @@ -181,6 +183,8 @@ struct iwl_fw { struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; + u32 sdio_adma_addr; + struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; size_t dbg_conf_tlv_len[FW_DBG_MAX]; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 10ae9d7da0af..84d8477432a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -382,6 +382,8 @@ enum iwl_trans_status { * are considered stuck and will trigger device restart * @command_names: array of command names, must be 256 entries * (one for each command); for debugging only + * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until + * we get the ALIVE from the uCode */ struct iwl_trans_config { struct iwl_op_mode *op_mode; @@ -396,6 +398,8 @@ struct iwl_trans_config { bool scd_set_active; unsigned int queue_watchdog_timeout; const char *const *command_names; + + u32 sdio_adma_addr; }; struct iwl_trans_dump_data { diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 6bb6546a734b..490696791cfd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -481,6 +481,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; trans_cfg.scd_set_active = true; + trans_cfg.sdio_adma_addr = fw->sdio_adma_addr; + snprintf(mvm->hw->wiphy->fw_version, sizeof(mvm->hw->wiphy->fw_version), "%s", fw->fw_version); -- cgit v1.2.1 From d9f1fc209fdb18d0edd6cc633a8725adbfb0ca01 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 23 Dec 2014 15:05:14 +0200 Subject: iwlwifi: mvm: ask the fw to wakeup (from d0i3) on sysassert Set the wakeup flag (of the d3 command) to configure the fw to wakeup when sysassert happens while in d0i3. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 490696791cfd..239f033e3b93 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -1049,6 +1049,7 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) }; struct iwl_d3_manager_config d3_cfg_cmd = { .min_sleep_time = cpu_to_le32(1000), + .wakeup_flags = cpu_to_le32(IWL_WAKEUP_D3_CONFIG_FW_ERROR), }; IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); -- cgit v1.2.1 From a1ed4025765cceec180f57eab032c770140d6b8f Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Mon, 1 Dec 2014 23:30:07 +0200 Subject: iwlwifi: mvm: Configure EBS scan ratio This configuration defines the ratio between number of scan iterations where EBS is involved to those where it is not. This configuration was left unconfigured due to inaccurate documentation. Fix documentation as well. Signed-off-by: Haim Dreyfuss Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 7 +++++-- drivers/net/wireless/iwlwifi/mvm/scan.c | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 1f2acf47bfb2..2d1a81c493f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -653,8 +653,11 @@ enum iwl_scan_channel_flags { }; /* iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S - * @flags: enum iwl_scan_channel_flgs - * @non_ebs_ratio: how many regular scan iteration before EBS + * @flags: enum iwl_scan_channel_flags + * @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is + * involved. + * 1 - EBS is disabled. + * 2 - every second scan will be full scan(and so on). */ struct iwl_scan_channel_opt { __le16 flags; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 243367650b13..ed229a8daf4a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -72,6 +72,8 @@ #define IWL_PLCP_QUIET_THRESH 1 #define IWL_ACTIVE_QUIET_TIME 10 +#define IWL_DENSE_EBS_SCAN_RATIO 5 +#define IWL_SPARSE_EBS_SCAN_RATIO 1 struct iwl_mvm_scan_params { u32 max_out_time; @@ -1296,10 +1298,14 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm, cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); + cmd->channel_opt[0].non_ebs_ratio = + cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO); cmd->channel_opt[1].flags = cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); + cmd->channel_opt[1].non_ebs_ratio = + cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO); } if (iwl_mvm_rrm_scan_needed(mvm)) -- cgit v1.2.1 From ff2986246471c564ccd7beb02427a32ec7f3f9d5 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Thu, 11 Dec 2014 13:23:01 +0200 Subject: iwlwifi: mvm: call to pcie_apply_destination also on family 8000 B step In order to config the FW and to allocate monitor buffer driver should run the function iwl_pcie_apply_destination immediately after FW sections are loaded. Signed-off-by: Eran Harary Reviewed-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index daec2f86eec0..09696ca2a654 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -908,6 +908,9 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, if (ret) return ret; + if (trans->dbg_dest_tlv) + iwl_pcie_apply_destination(trans); + /* Notify FW loading is done */ iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF); -- cgit v1.2.1 From c3f8d0a3afbc54db0b7ef079d42bc3c72f06d668 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Tue, 2 Dec 2014 11:03:16 +0200 Subject: iwlwifi: mvm: Alter passive scan fragmentation parameters in case of multi-MAC Make passive scan fragmentation depends on the number of active interfaces. In case of single-MAC, make passive scan less fragmented. Signed-off-by: Haim Dreyfuss Reviewed-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index ed229a8daf4a..348b9c4b694a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -284,11 +284,11 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool *global_bound = data; + int *global_cnt = data; if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS) - *global_bound = true; + *global_cnt += 1; } static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, @@ -296,16 +296,16 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, int n_ssids, u32 flags, struct iwl_mvm_scan_params *params) { - bool global_bound = false; + int global_cnt = 0; enum ieee80211_band band; u8 frag_passive_dwell = 0; ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_scan_condition_iterator, - &global_bound); + &global_cnt); - if (!global_bound) + if (!global_cnt) goto not_bound; params->suspend_time = 30; @@ -316,7 +316,11 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, IWL_UCODE_TLV_API_FRAGMENTED_SCAN) { params->suspend_time = 105; params->max_out_time = 70; - frag_passive_dwell = 20; + /* + * If there is more than one active interface make + * passive scan more fragmented. + */ + frag_passive_dwell = (global_cnt < 2) ? 40 : 20; } else { params->suspend_time = 120; params->max_out_time = 120; -- cgit v1.2.1 From 834437dab96c751bb013aaac86b19974f6cb444e Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 17 Dec 2014 15:38:58 +0200 Subject: iwlwifi: mvm: rs: organize and cleanup consts Organize and cleanup the consts used by rs. This is part of making some of these configurable. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/constants.h | 28 +++++++ drivers/net/wireless/iwlwifi/mvm/rs.c | 109 +++++++++++++-------------- drivers/net/wireless/iwlwifi/mvm/rs.h | 39 ---------- 3 files changed, 79 insertions(+), 97 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 3bd93476ec1c..7cd1de820ca7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -102,5 +102,33 @@ #define IWL_MVM_QUOTA_THRESHOLD 8 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_DISABLE_MIMO 0 +#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 +#define IWL_MVM_RS_LEGACY_RETRIES_PER_RATE 1 +#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 +#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 +#define IWL_MVM_RS_INITIAL_MIMO_NUM_RATES 3 +#define IWL_MVM_RS_INITIAL_SISO_NUM_RATES 3 +#define IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES 16 +#define IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES 16 +#define IWL_MVM_RS_SECONDARY_SISO_NUM_RATES 3 +#define IWL_MVM_RS_SECONDARY_SISO_RETRIES 1 +#define IWL_MVM_RS_RATE_MIN_FAILURE_TH 3 +#define IWL_MVM_RS_RATE_MIN_SUCCESS_TH 8 +#define IWL_MVM_RS_STAY_IN_COLUMN_TIMEOUT 5 /* Seconds */ +#define IWL_MVM_RS_IDLE_TIMEOUT 5 /* Seconds */ +#define IWL_MVM_RS_MISSED_RATE_MAX 15 +#define IWL_MVM_RS_LEGACY_FAILURE_LIMIT 160 +#define IWL_MVM_RS_LEGACY_SUCCESS_LIMIT 480 +#define IWL_MVM_RS_LEGACY_TABLE_COUNT 160 +#define IWL_MVM_RS_NON_LEGACY_FAILURE_LIMIT 400 +#define IWL_MVM_RS_NON_LEGACY_SUCCESS_LIMIT 4500 +#define IWL_MVM_RS_NON_LEGACY_TABLE_COUNT 1500 +#define IWL_MVM_RS_SR_FORCE_DECREASE 15 /* percent */ +#define IWL_MVM_RS_SR_NO_DECREASE 85 /* percent */ +#define IWL_MVM_RS_AGG_TIME_LIMIT 4000 /* 4 msecs. valid 100-8000 */ +#define IWL_MVM_RS_AGG_DISABLE_START 3 +#define IWL_MVM_RS_TPC_SR_FORCE_INCREASE 75 /* percent */ +#define IWL_MVM_RS_TPC_SR_NO_INCREASE 85 /* percent */ +#define IWL_MVM_RS_TPC_TX_POWER_STEP 3 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 568829db2119..7ba6e5dbbbd0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -42,25 +42,12 @@ #define RS_NAME "iwl-mvm-rs" -#define NUM_TRY_BEFORE_ANT_TOGGLE 1 -#define RS_LEGACY_RETRIES_PER_RATE 1 -#define RS_HT_VHT_RETRIES_PER_RATE 2 -#define RS_HT_VHT_RETRIES_PER_RATE_TW 1 -#define RS_INITIAL_MIMO_NUM_RATES 3 -#define RS_INITIAL_SISO_NUM_RATES 3 -#define RS_INITIAL_LEGACY_NUM_RATES LINK_QUAL_MAX_RETRY_NUM -#define RS_SECONDARY_LEGACY_NUM_RATES LINK_QUAL_MAX_RETRY_NUM -#define RS_SECONDARY_SISO_NUM_RATES 3 -#define RS_SECONDARY_SISO_RETRIES 1 - #define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ -#define IWL_RATE_MIN_FAILURE_TH 3 /* min failures to calc tpt */ -#define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */ -/* max allowed rate miss before sync LQ cmd */ -#define IWL_MISSED_RATE_MAX 15 -#define RS_STAY_IN_COLUMN_TIMEOUT (5*HZ) -#define RS_IDLE_TIMEOUT (5*HZ) +/* Calculations of success ratio are done in fixed point where 12800 is 100%. + * Use this macro when dealing with thresholds consts set as a percentage + */ +#define RS_PERCENT(x) (128 * x) static u8 rs_ht_to_legacy[] = { [IWL_RATE_MCS_0_INDEX] = IWL_RATE_6M_INDEX, @@ -613,7 +600,8 @@ static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) * at this rate. window->data contains the bitmask of successful * packets. */ -static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, +static int _rs_collect_tx_data(struct iwl_mvm *mvm, + struct iwl_scale_tbl_info *tbl, int scale_index, int attempts, int successes, struct iwl_rate_scale_data *window) { @@ -668,8 +656,8 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, fail_count = window->counter - window->success_counter; /* Calculate average throughput, if we have enough history. */ - if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || - (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) + if ((fail_count >= IWL_MVM_RS_RATE_MIN_FAILURE_TH) || + (window->success_counter >= IWL_MVM_RS_RATE_MIN_SUCCESS_TH)) window->average_tpt = (window->success_ratio * tpt + 64) / 128; else window->average_tpt = IWL_INVALID_VALUE; @@ -677,7 +665,8 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, return 0; } -static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, +static int rs_collect_tx_data(struct iwl_mvm *mvm, + struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl, int scale_index, int attempts, int successes, u8 reduced_txp) @@ -698,7 +687,7 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, /* Select window for current tx bit rate */ window = &(tbl->win[scale_index]); - ret = _rs_collect_tx_data(tbl, scale_index, attempts, successes, + ret = _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes, window); if (ret) return ret; @@ -707,7 +696,7 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, return -EINVAL; window = &tbl->tpc_win[reduced_txp]; - return _rs_collect_tx_data(tbl, scale_index, attempts, successes, + return _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes, window); } @@ -1125,7 +1114,8 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, } if (time_after(jiffies, - (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) { + (unsigned long)(lq_sta->last_tx + + (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { int t; IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); @@ -1158,7 +1148,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, * ... driver. */ lq_sta->missed_rate_counter++; - if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { + if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) { lq_sta->missed_rate_counter = 0; IWL_DEBUG_RATE(mvm, "Too many rates mismatch. Send sync LQ. rs_state %d\n", @@ -1213,7 +1203,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ucode_rate = le32_to_cpu(table->rs_table[0]); rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); - rs_collect_tx_data(lq_sta, curr_tbl, rate.index, + rs_collect_tx_data(mvm, lq_sta, curr_tbl, rate.index, info->status.ampdu_len, info->status.ampdu_ack_len, reduced_txp); @@ -1249,7 +1239,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, else continue; - rs_collect_tx_data(lq_sta, tmp_tbl, rate.index, 1, + rs_collect_tx_data(mvm, lq_sta, tmp_tbl, rate.index, 1, i < retries ? 0 : legacy_success, reduced_txp); } @@ -1303,13 +1293,13 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, IWL_DEBUG_RATE(mvm, "Moving to RS_STATE_STAY_IN_COLUMN\n"); lq_sta->rs_state = RS_STATE_STAY_IN_COLUMN; if (is_legacy) { - lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; - lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; - lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT; + lq_sta->table_count_limit = IWL_MVM_RS_LEGACY_TABLE_COUNT; + lq_sta->max_failure_limit = IWL_MVM_RS_LEGACY_FAILURE_LIMIT; + lq_sta->max_success_limit = IWL_MVM_RS_LEGACY_SUCCESS_LIMIT; } else { - lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT; - lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT; - lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT; + lq_sta->table_count_limit = IWL_MVM_RS_NON_LEGACY_TABLE_COUNT; + lq_sta->max_failure_limit = IWL_MVM_RS_NON_LEGACY_FAILURE_LIMIT; + lq_sta->max_success_limit = IWL_MVM_RS_NON_LEGACY_SUCCESS_LIMIT; } lq_sta->table_count = 0; lq_sta->total_failed = 0; @@ -1427,7 +1417,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, u32 target_tpt; int rate_idx; - if (success_ratio > RS_SR_NO_DECREASE) { + if (success_ratio > IWL_MVM_RS_SR_NO_DECREASE) { target_tpt = 100 * expected_current_tpt; IWL_DEBUG_RATE(mvm, "SR %d high. Find rate exceeding EXPECTED_CURRENT %d\n", @@ -1495,7 +1485,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) flush_interval_passed = time_after(jiffies, (unsigned long)(lq_sta->flush_timer + - RS_STAY_IN_COLUMN_TIMEOUT)); + (IWL_MVM_RS_STAY_IN_COLUMN_TIMEOUT * HZ))); /* * Check if we should allow search for new modulation mode. @@ -1735,7 +1725,8 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm, { enum rs_action action = RS_ACTION_STAY; - if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) { + if ((sr <= RS_PERCENT(IWL_MVM_RS_SR_FORCE_DECREASE)) || + (current_tpt == 0)) { IWL_DEBUG_RATE(mvm, "Decrease rate because of low SR\n"); return RS_ACTION_DOWNSCALE; @@ -1794,7 +1785,7 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm, out: if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID)) { - if (sr >= RS_SR_NO_DECREASE) { + if (sr >= RS_PERCENT(IWL_MVM_RS_SR_NO_DECREASE)) { IWL_DEBUG_RATE(mvm, "SR is above NO DECREASE. Avoid downscale\n"); action = RS_ACTION_STAY; @@ -1836,11 +1827,11 @@ static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index, int *weaker, int *stronger) { - *weaker = index + TPC_TX_POWER_STEP; + *weaker = index + IWL_MVM_RS_TPC_TX_POWER_STEP; if (*weaker > TPC_MAX_REDUCTION) *weaker = TPC_INVALID; - *stronger = index - TPC_TX_POWER_STEP; + *stronger = index - IWL_MVM_RS_TPC_TX_POWER_STEP; if (*stronger < 0) *stronger = TPC_INVALID; } @@ -1896,7 +1887,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm, } /* Too many failures, increase txp */ - if (sr <= TPC_SR_FORCE_INCREASE || current_tpt == 0) { + if (sr <= RS_PERCENT(IWL_MVM_RS_TPC_SR_FORCE_INCREASE) || + current_tpt == 0) { IWL_DEBUG_RATE(mvm, "increase txp because of weak SR\n"); return TPC_ACTION_NO_RESTIRCTION; } @@ -1919,7 +1911,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm, } /* next, increase if needed */ - if (sr < TPC_SR_NO_INCREASE && strong != TPC_INVALID) { + if (sr < RS_PERCENT(IWL_MVM_RS_TPC_SR_NO_INCREASE) && + strong != TPC_INVALID) { if (weak_tpt == IWL_INVALID_VALUE && strong_tpt != IWL_INVALID_VALUE && current_tpt < strong_tpt) { @@ -2117,8 +2110,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, * in current association (use new rate found above). */ fail_count = window->counter - window->success_counter; - if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && - (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { + if ((fail_count < IWL_MVM_RS_RATE_MIN_FAILURE_TH) && + (window->success_counter < IWL_MVM_RS_RATE_MIN_SUCCESS_TH)) { IWL_DEBUG_RATE(mvm, "(%s: %d): Test Window: succ %d total %d\n", rs_pretty_lq_type(rate->type), @@ -2720,7 +2713,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ - lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; + lq_sta->missed_rate_counter = IWL_MVM_RS_MISSED_RATE_MAX; lq_sta->band = sband->band; /* * active legacy rates as per supported rates bitmap @@ -2925,14 +2918,14 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, rate.stbc = rs_stbc_allow(mvm, sta, lq_sta); if (is_siso(&rate)) { - num_rates = RS_INITIAL_SISO_NUM_RATES; - num_retries = RS_HT_VHT_RETRIES_PER_RATE; + num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES; + num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE; } else if (is_mimo(&rate)) { - num_rates = RS_INITIAL_MIMO_NUM_RATES; - num_retries = RS_HT_VHT_RETRIES_PER_RATE; + num_rates = IWL_MVM_RS_INITIAL_MIMO_NUM_RATES; + num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE; } else { - num_rates = RS_INITIAL_LEGACY_NUM_RATES; - num_retries = RS_LEGACY_RETRIES_PER_RATE; + num_rates = IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES; + num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE; toggle_ant = true; } @@ -2943,12 +2936,12 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, rs_get_lower_rate_down_column(lq_sta, &rate); if (is_siso(&rate)) { - num_rates = RS_SECONDARY_SISO_NUM_RATES; - num_retries = RS_SECONDARY_SISO_RETRIES; + num_rates = IWL_MVM_RS_SECONDARY_SISO_NUM_RATES; + num_retries = IWL_MVM_RS_SECONDARY_SISO_RETRIES; lq_cmd->mimo_delim = index; } else if (is_legacy(&rate)) { - num_rates = RS_SECONDARY_LEGACY_NUM_RATES; - num_retries = RS_LEGACY_RETRIES_PER_RATE; + num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES; + num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE; } else { WARN_ON_ONCE(1); } @@ -2961,8 +2954,8 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, rs_get_lower_rate_down_column(lq_sta, &rate); - num_rates = RS_SECONDARY_LEGACY_NUM_RATES; - num_retries = RS_LEGACY_RETRIES_PER_RATE; + num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES; + num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE; rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index, num_rates, num_retries, valid_tx_ant, @@ -2979,9 +2972,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta; struct iwl_mvm_vif *mvmvif; - lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + lq_cmd->agg_disable_start_th = IWL_MVM_RS_AGG_DISABLE_START; lq_cmd->agg_time_limit = - cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); + cpu_to_le16(IWL_MVM_RS_AGG_TIME_LIMIT); #ifdef CONFIG_MAC80211_DEBUGFS if (lq_sta->pers.dbg_fixed_rate) { diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index defd70a6d9e6..f8f5bf21cc38 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -137,42 +137,10 @@ enum { #define IWL_INVALID_VALUE -1 -#define IWL_MIN_RSSI_VAL -100 -#define IWL_MAX_RSSI_VAL 0 - -/* These values specify how many Tx frame attempts before - * searching for a new modulation mode */ -#define IWL_LEGACY_FAILURE_LIMIT 160 -#define IWL_LEGACY_SUCCESS_LIMIT 480 -#define IWL_LEGACY_TABLE_COUNT 160 - -#define IWL_NONE_LEGACY_FAILURE_LIMIT 400 -#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500 -#define IWL_NONE_LEGACY_TABLE_COUNT 1500 - -/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */ -#define IWL_RS_GOOD_RATIO 12800 /* 100% */ -#define IWL_RATE_SCALE_SWITCH 10880 /* 85% */ -#define IWL_RATE_HIGH_TH 10880 /* 85% */ -#define IWL_RATE_INCREASE_TH 6400 /* 50% */ -#define RS_SR_FORCE_DECREASE 1920 /* 15% */ -#define RS_SR_NO_DECREASE 10880 /* 85% */ - -#define TPC_SR_FORCE_INCREASE 9600 /* 75% */ -#define TPC_SR_NO_INCREASE 10880 /* 85% */ -#define TPC_TX_POWER_STEP 3 #define TPC_MAX_REDUCTION 15 #define TPC_NO_REDUCTION 0 #define TPC_INVALID 0xff -#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ -#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000) -#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100) - -#define LINK_QUAL_AGG_DISABLE_START_DEF (3) -#define LINK_QUAL_AGG_DISABLE_START_MAX (255) -#define LINK_QUAL_AGG_DISABLE_START_MIN (0) - #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) @@ -181,14 +149,7 @@ enum { /* load per tid defines for A-MPDU activation */ #define IWL_AGG_TPT_THREHOLD 0 -#define IWL_AGG_LOAD_THRESHOLD 10 #define IWL_AGG_ALL_TID 0xff -#define TID_QUEUE_CELL_SPACING 50 /*mS */ -#define TID_QUEUE_MAX_SIZE 20 -#define TID_ROUND_VALUE 5 /* mS */ - -#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) -#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) enum iwl_table_type { LQ_NONE, -- cgit v1.2.1 From 589a55b07dfb71d4c45e008a8df8bb94ff813fe6 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 22 Dec 2014 23:16:55 +0100 Subject: net: ieee802154: don't use devm_pinctrl_get_select_default() in probe Since commit ab78029ecc34 (drivers/pinctrl: grab default handles from device core), we can rely on device core for setting the default pins. Signed-off-by: Wolfram Sang Acked-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index c2b7da3da183..033473448d9f 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -841,7 +840,6 @@ done: static int cc2520_probe(struct spi_device *spi) { struct cc2520_private *priv; - struct pinctrl *pinctrl; struct cc2520_platform_data *pdata; int ret; @@ -854,11 +852,6 @@ static int cc2520_probe(struct spi_device *spi) spi_set_drvdata(spi, priv); - pinctrl = devm_pinctrl_get_select_default(&spi->dev); - if (IS_ERR(pinctrl)) - dev_warn(&spi->dev, - "pinctrl pins are not configured\n"); - pdata = cc2520_get_platform_data(spi); if (!pdata) { dev_err(&spi->dev, "no platform data\n"); -- cgit v1.2.1 From 5eb9f8caac333842e840325fe7299465bcdf2111 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 26 Dec 2014 10:13:38 +0530 Subject: cc2520: use devm_kzalloc(.., sizeof(*pointer), ..) pattern Signed-off-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 033473448d9f..bc24d9aab292 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -843,8 +843,7 @@ static int cc2520_probe(struct spi_device *spi) struct cc2520_platform_data *pdata; int ret; - priv = devm_kzalloc(&spi->dev, - sizeof(struct cc2520_private), GFP_KERNEL); + priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; goto err_ret; -- cgit v1.2.1 From f50f1c37a663b7b76013638f60a400a16ddd2158 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 26 Dec 2014 10:13:39 +0530 Subject: cc2520: remove 'ret' goto label If allocation of memory fails instead of going to ret goto label and returning from there, we can directly return -ENOMEM on failure. Signed-off-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index bc24d9aab292..64017f1eca7f 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -844,10 +844,8 @@ static int cc2520_probe(struct spi_device *spi) int ret; priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_ret; - } + if (!priv) + return -ENOMEM; spi_set_drvdata(spi, priv); @@ -861,10 +859,8 @@ static int cc2520_probe(struct spi_device *spi) priv->buf = devm_kzalloc(&spi->dev, SPI_COMMAND_BUFFER, GFP_KERNEL); - if (!priv->buf) { - ret = -ENOMEM; - goto err_ret; - } + if (!priv->buf) + return -ENOMEM; mutex_init(&priv->buffer_mutex); INIT_WORK(&priv->fifop_irqwork, cc2520_fifop_irqwork); @@ -981,8 +977,6 @@ static int cc2520_probe(struct spi_device *spi) err_hw_init: mutex_destroy(&priv->buffer_mutex); flush_work(&priv->fifop_irqwork); - -err_ret: return ret; } -- cgit v1.2.1 From 7fc1b2d56f399f65e96559fe449c0ca09d2c36c7 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 26 Dec 2014 10:13:40 +0530 Subject: cc2520: fix zero perm_extended_addr address It will remove the bug of havine zero perm_extended_addr address. Signed-off-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 64017f1eca7f..a43c8acb7268 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -650,6 +650,7 @@ static int cc2520_register(struct cc2520_private *priv) priv->hw->parent = &priv->spi->dev; priv->hw->extra_tx_headroom = 0; priv->hw->vif_data_size = sizeof(*priv); + ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr); /* We do support only 2.4 Ghz */ priv->hw->phy->channels_supported[0] = 0x7FFF800; -- cgit v1.2.1 From 74d23cc704d19732e70ef1579a669f7d5f09dd9a Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Sun, 21 Dec 2014 19:46:56 +0100 Subject: time: move the timecounter/cyclecounter code into its own file. The timecounter code has almost nothing to do with the clocksource code. Let it live in its own file. This will help isolate the timecounter users from the clocksource users in the source tree. Signed-off-by: Richard Cochran Acked-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe.h | 2 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 2 +- drivers/net/ethernet/freescale/fec.h | 1 + drivers/net/ethernet/intel/e1000e/e1000.h | 2 +- drivers/net/ethernet/intel/igb/igb.h | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 2 +- drivers/net/ethernet/ti/cpts.h | 1 + 7 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index f9ec762ac3f0..2af6affc35a7 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -124,7 +124,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index c3a6072134f5..792ba72fb5c8 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -22,7 +22,7 @@ #include #include -#include +#include /* compilation time flags */ diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 469691ad4a1e..df8bbddaeb37 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -16,6 +16,7 @@ #include #include #include +#include #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 7785240a0da1..9416e5a7e0c8 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 82d891e183b1..ee22da391474 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -29,7 +29,7 @@ #include "e1000_mac.h" #include "e1000_82575.h" -#include +#include #include #include #include diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index b6137be43920..38fc64cf5dca 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h index 1a581ef7eee8..69a46b92c7d6 100644 --- a/drivers/net/ethernet/ti/cpts.h +++ b/drivers/net/ethernet/ti/cpts.h @@ -27,6 +27,7 @@ #include #include #include +#include struct cpsw_cpts { u32 idver; /* Identification and version */ -- cgit v1.2.1 From 8b976e97772cfb7e0e4eb8682d5017861dbd8796 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Sun, 21 Dec 2014 19:46:58 +0100 Subject: net: xgbe: convert to timecounter adjtime. This patch changes the driver to use the new and improved method for adjusting the offset of a timecounter. Compile tested only. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-ptp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c index a1bf9d1cdae1..f5acf4cc69bd 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c @@ -171,15 +171,9 @@ static int xgbe_adjtime(struct ptp_clock_info *info, s64 delta) struct xgbe_prv_data, ptp_clock_info); unsigned long flags; - u64 nsec; spin_lock_irqsave(&pdata->tstamp_lock, flags); - - nsec = timecounter_read(&pdata->tstamp_tc); - - nsec += delta; - timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec); - + timecounter_adjtime(&pdata->tstamp_tc, delta); spin_unlock_irqrestore(&pdata->tstamp_lock, flags); return 0; -- cgit v1.2.1 From 2e5601f9aca1a83980a031f9385a95062d12e689 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Sun, 21 Dec 2014 19:46:59 +0100 Subject: net: bnx2x: convert to timecounter adjtime. This patch changes the driver to use the new and improved method for adjusting the offset of a timecounter. Compile tested only. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 72eef9fc883e..2c951326a85d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -13267,14 +13267,10 @@ static int bnx2x_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) static int bnx2x_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info); - u64 now; DP(BNX2X_MSG_PTP, "PTP adjtime called, delta = %llx\n", delta); - now = timecounter_read(&bp->timecounter); - now += delta; - /* Re-init the timecounter */ - timecounter_init(&bp->timecounter, &bp->cyclecounter, now); + timecounter_adjtime(&bp->timecounter, delta); return 0; } -- cgit v1.2.1 From 59e16961c688a50d4dae9827cc3e5c69ae98e0cb Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Sun, 21 Dec 2014 19:47:00 +0100 Subject: net: fec: convert to timecounter adjtime. This patch changes the driver to use the new and improved method for adjusting the offset of a timecounter. Compile tested only. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_ptp.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 992c8c3db553..1f9cf2345266 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -374,23 +374,9 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) struct fec_enet_private *fep = container_of(ptp, struct fec_enet_private, ptp_caps); unsigned long flags; - u64 now; - u32 counter; spin_lock_irqsave(&fep->tmreg_lock, flags); - - now = timecounter_read(&fep->tc); - now += delta; - - /* Get the timer value based on adjusted timestamp. - * Update the counter with the masked value. - */ - counter = now & fep->cc.mask; - writel(counter, fep->hwp + FEC_ATIME); - - /* reset the timecounter */ - timecounter_init(&fep->tc, &fep->cc, now); - + timecounter_adjtime(&fep->tc, delta); spin_unlock_irqrestore(&fep->tmreg_lock, flags); return 0; -- cgit v1.2.1 From f4de2b95688eba646d677dd2bed8c49540c00f1e Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Sun, 21 Dec 2014 19:47:01 +0100 Subject: net: e1000e: convert to timecounter adjtime. This patch changes the driver to use the new and improved method for adjusting the offset of a timecounter. Signed-off-by: Richard Cochran Acked-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/e1000e/ptp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c index fb1a914a3ad4..978ef9c4a043 100644 --- a/drivers/net/ethernet/intel/e1000e/ptp.c +++ b/drivers/net/ethernet/intel/e1000e/ptp.c @@ -90,12 +90,9 @@ static int e1000e_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter, ptp_clock_info); unsigned long flags; - s64 now; spin_lock_irqsave(&adapter->systim_lock, flags); - now = timecounter_read(&adapter->tc); - now += delta; - timecounter_init(&adapter->tc, &adapter->cc, now); + timecounter_adjtime(&adapter->tc, delta); spin_unlock_irqrestore(&adapter->systim_lock, flags); return 0; -- cgit v1.2.1 From 5ee698e3677a1af8b731cc891e94be33b6572cfd Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Sun, 21 Dec 2014 19:47:02 +0100 Subject: net: igb: convert to timecounter adjtime. This patch changes the driver to use the new and improved method for adjusting the offset of a timecounter. Signed-off-by: Richard Cochran Acked-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igb/igb_ptp.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 794c139f0cc0..1d27f2d3b57c 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -256,14 +256,9 @@ static int igb_ptp_adjtime_82576(struct ptp_clock_info *ptp, s64 delta) struct igb_adapter *igb = container_of(ptp, struct igb_adapter, ptp_caps); unsigned long flags; - s64 now; spin_lock_irqsave(&igb->tmreg_lock, flags); - - now = timecounter_read(&igb->tc); - now += delta; - timecounter_init(&igb->tc, &igb->cc, now); - + timecounter_adjtime(&igb->tc, delta); spin_unlock_irqrestore(&igb->tmreg_lock, flags); return 0; -- cgit v1.2.1 From 826ef90dc4727c9f9cd999c830023e54d9ea3f58 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Sun, 21 Dec 2014 19:47:03 +0100 Subject: net: ixgbe: convert to timecounter adjtime. This patch changes the driver to use the new and improved method for adjusting the offset of a timecounter. Compile tested only. Signed-off-by: Richard Cochran Acked-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 5fd4b5271f9a..47c29eaaa140 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -261,18 +261,9 @@ static int ixgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) struct ixgbe_adapter *adapter = container_of(ptp, struct ixgbe_adapter, ptp_caps); unsigned long flags; - u64 now; spin_lock_irqsave(&adapter->tmreg_lock, flags); - - now = timecounter_read(&adapter->tc); - now += delta; - - /* reset the timecounter */ - timecounter_init(&adapter->tc, - &adapter->cc, - now); - + timecounter_adjtime(&adapter->tc, delta); spin_unlock_irqrestore(&adapter->tmreg_lock, flags); ixgbe_ptp_setup_sdp(adapter); -- cgit v1.2.1 From ce51ff0937bd5596aeafd67f5a60d36016d5e040 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Sun, 21 Dec 2014 19:47:04 +0100 Subject: net: mlx4: convert to timecounter adjtime. This patch changes the driver to use the new and improved method for adjusting the offset of a timecounter. Compile tested only. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_clock.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c index 999014413b1a..df35d0e1b899 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c @@ -147,12 +147,9 @@ static int mlx4_en_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev, ptp_clock_info); unsigned long flags; - s64 now; write_lock_irqsave(&mdev->clock_lock, flags); - now = timecounter_read(&mdev->clock); - now += delta; - timecounter_init(&mdev->clock, &mdev->cycles, now); + timecounter_adjtime(&mdev->clock, delta); write_unlock_irqrestore(&mdev->clock_lock, flags); return 0; -- cgit v1.2.1 From f25a30be359d0535fb1c7c1619cabb0ad17cfbf1 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Sun, 21 Dec 2014 19:47:05 +0100 Subject: net: cpts: convert to timecounter adjtime. This patch changes the driver to use the new and improved method for adjusting the offset of a timecounter. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpts.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c index 4a4388b813ac..fbe42cb107ec 100644 --- a/drivers/net/ethernet/ti/cpts.c +++ b/drivers/net/ethernet/ti/cpts.c @@ -157,14 +157,11 @@ static int cpts_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) static int cpts_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { - s64 now; unsigned long flags; struct cpts *cpts = container_of(ptp, struct cpts, info); spin_lock_irqsave(&cpts->lock, flags); - now = timecounter_read(&cpts->tc); - now += delta; - timecounter_init(&cpts->tc, &cpts->cc, now); + timecounter_adjtime(&cpts->tc, delta); spin_unlock_irqrestore(&cpts->lock, flags); return 0; -- cgit v1.2.1 From 2eebdde6528a722fbf8e2cffcf7aa52cbb4c2de0 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Sun, 21 Dec 2014 19:47:06 +0100 Subject: timecounter: keep track of accumulated fractional nanoseconds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current timecounter implementation will drop a variable amount of resolution, depending on the magnitude of the time delta. In other words, reading the clock too often or too close to a time stamp conversion will introduce errors into the time values. This patch fixes the issue by introducing a fractional nanosecond field that accumulates the low order bits. Reported-by: Janusz Użycki Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c index df35d0e1b899..e9cce4f72b24 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c @@ -240,7 +240,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev) { struct mlx4_dev *dev = mdev->dev; unsigned long flags; - u64 ns; + u64 ns, zero = 0; rwlock_init(&mdev->clock_lock); @@ -265,7 +265,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev) /* Calculate period in seconds to call the overflow watchdog - to make * sure counter is checked at least once every wrap around. */ - ns = cyclecounter_cyc2ns(&mdev->cycles, mdev->cycles.mask); + ns = cyclecounter_cyc2ns(&mdev->cycles, mdev->cycles.mask, zero, &zero); do_div(ns, NSEC_PER_SEC / 2 / HZ); mdev->overflow_period = ns; -- cgit v1.2.1 From d0e520ef63a23f8bd7806450f5d2820d35594ba9 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:34 +0100 Subject: atheros: atlx: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.function = f; -t.data = d; // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/ethernet/atheros/atlx/atl2.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index 84a09e8ddd9c..482a7cabb0a1 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -1436,13 +1436,11 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) atl2_check_options(adapter); - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = atl2_watchdog; - adapter->watchdog_timer.data = (unsigned long) adapter; + setup_timer(&adapter->watchdog_timer, atl2_watchdog, + (unsigned long)adapter); - init_timer(&adapter->phy_config_timer); - adapter->phy_config_timer.function = atl2_phy_config; - adapter->phy_config_timer.data = (unsigned long) adapter; + setup_timer(&adapter->phy_config_timer, atl2_phy_config, + (unsigned long)adapter); INIT_WORK(&adapter->reset_task, atl2_reset_task); INIT_WORK(&adapter->link_chg_task, atl2_link_chg_task); -- cgit v1.2.1 From cc73e41f17be97eb4e387610bd95e952127e3216 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:35 +0100 Subject: atl1e: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.function = f; -t.data = d; // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/ethernet/atheros/atl1e/atl1e_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c index 2326579f9454..c88abf5b6415 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c @@ -2373,9 +2373,8 @@ static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(netdev, &adapter->napi, atl1e_clean, 64); - init_timer(&adapter->phy_config_timer); - adapter->phy_config_timer.function = atl1e_phy_config; - adapter->phy_config_timer.data = (unsigned long) adapter; + setup_timer(&adapter->phy_config_timer, atl1e_phy_config, + (unsigned long)adapter); /* get user settings */ atl1e_check_options(adapter); -- cgit v1.2.1 From fea3cb063bf9b9d6b4efd5c973217a708812f5e2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:42 +0100 Subject: ksz884x: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.function = f; -t.data = d; // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/ethernet/micrel/ksz884x.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index 2fa6ae026e4f..10988fbf47eb 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -4342,9 +4342,7 @@ static void ksz_init_timer(struct ksz_timer_info *info, int period, { info->max = 0; info->period = period; - init_timer(&info->timer); - info->timer.function = function; - info->timer.data = (unsigned long) data; + setup_timer(&info->timer, function, (unsigned long)data); } static void ksz_update_timer(struct ksz_timer_info *info) -- cgit v1.2.1 From 12141337af54b57e222b7a52d52415aa5e332ff0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:46 +0100 Subject: net: sxgbe: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.function = f; -t.data = d; // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 698494481d18..b6612d6090ac 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -133,9 +133,8 @@ bool sxgbe_eee_init(struct sxgbe_priv_data * const priv) return false; priv->eee_active = 1; - init_timer(&priv->eee_ctrl_timer); - priv->eee_ctrl_timer.function = sxgbe_eee_ctrl_timer; - priv->eee_ctrl_timer.data = (unsigned long)priv; + setup_timer(&priv->eee_ctrl_timer, sxgbe_eee_ctrl_timer, + (unsigned long)priv); priv->eee_ctrl_timer.expires = SXGBE_LPI_TIMER(eee_timer); add_timer(&priv->eee_ctrl_timer); @@ -1009,10 +1008,9 @@ static void sxgbe_tx_init_coalesce(struct sxgbe_priv_data *priv) struct sxgbe_tx_queue *p = priv->txq[queue_num]; p->tx_coal_frames = SXGBE_TX_FRAMES; p->tx_coal_timer = SXGBE_COAL_TX_TIMER; - init_timer(&p->txtimer); + setup_timer(&p->txtimer, sxgbe_tx_timer, + (unsigned long)&priv->txq[queue_num]); p->txtimer.expires = SXGBE_COAL_TIMER(p->tx_coal_timer); - p->txtimer.data = (unsigned long)&priv->txq[queue_num]; - p->txtimer.function = sxgbe_tx_timer; add_timer(&p->txtimer); } } -- cgit v1.2.1 From dd450777990baae668c1143064f2f234dbab1b9b Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 24 Dec 2014 01:14:14 +0300 Subject: arm: sa1100: move irda header to linux/platform_data In the end asm/mach/irda.h header is not used by anybody except sa1100. Move the header to the platform data includes dir and rename it to irda-sa11x0.h. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller --- drivers/net/irda/sa1100_ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 7b17fa2114e1..b6e44ff4e373 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -38,7 +38,7 @@ #include #include -#include +#include static int power_level = 3; static int tx_lpm; -- cgit v1.2.1 From 41f2f1273caee29ce9e2854c9aba996b56303b4a Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 24 Dec 2014 11:03:52 +0800 Subject: virtio-net: don't do header check for dodgy gso packets There's no need to do header check for virtio-net since: - Host sets dodgy for all gso packets from guest and check the header. - Host should be prepared for all kinds of evil packets from guest, since malicious guest can send any kinds of packet. So this patch sets NETIF_F_GSO_ROBUST for virtio-net to skip the check. Cc: Rusty Russell Cc: Michael S. Tsirkin Acked-by: Michael S. Tsirkin Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 5ca97713bfb3..11e2e8131359 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1759,6 +1759,8 @@ static int virtnet_probe(struct virtio_device *vdev) if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) dev->hw_features |= NETIF_F_TSO_ECN; + dev->features |= NETIF_F_GSO_ROBUST; + if (gso) dev->features |= dev->hw_features & NETIF_F_ALL_TSO; /* (!csum && gso) case will be fixed by register_netdev() */ -- cgit v1.2.1 From 91c53f76352980ef37ed816a73bf356de3d1705a Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Wed, 24 Dec 2014 14:05:44 +0800 Subject: net: gianfar: mark the local functions static Signed-off-by: Kevin Hao Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 5645342f5b28..d2a67ed10a38 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -116,7 +116,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); static void gfar_reset_task(struct work_struct *work); static void gfar_timeout(struct net_device *dev); static int gfar_close(struct net_device *dev); -struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr); +static struct sk_buff *gfar_new_skb(struct net_device *dev, + dma_addr_t *bufaddr); static int gfar_set_mac_address(struct net_device *dev); static int gfar_change_mtu(struct net_device *dev, int new_mtu); static irqreturn_t gfar_error(int irq, void *dev_id); @@ -554,7 +555,7 @@ static void gfar_ints_enable(struct gfar_private *priv) } } -void lock_tx_qs(struct gfar_private *priv) +static void lock_tx_qs(struct gfar_private *priv) { int i; @@ -562,7 +563,7 @@ void lock_tx_qs(struct gfar_private *priv) spin_lock(&priv->tx_queue[i]->txlock); } -void unlock_tx_qs(struct gfar_private *priv) +static void unlock_tx_qs(struct gfar_private *priv) { int i; @@ -2671,7 +2672,7 @@ static struct sk_buff *gfar_alloc_skb(struct net_device *dev) return skb; } -struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr) +static struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr) { struct gfar_private *priv = netdev_priv(dev); struct sk_buff *skb; -- cgit v1.2.1 From 03366a33db91abd298457b0f707187247f1a6b7d Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Wed, 24 Dec 2014 14:05:45 +0800 Subject: net: gianfar: add missing __iomem annotation Fix the following spare warning: drivers/net/ethernet/freescale/gianfar.c:3521:60: warning: incorrect type in argument 1 (different address spaces) drivers/net/ethernet/freescale/gianfar.c:3521:60: expected unsigned int [noderef] *addr drivers/net/ethernet/freescale/gianfar.c:3521:60: got unsigned int [usertype] *rfbptr drivers/net/ethernet/freescale/gianfar.c:205:16: warning: incorrect type in assignment (different address spaces) drivers/net/ethernet/freescale/gianfar.c:205:16: expected unsigned int [usertype] *rfbptr drivers/net/ethernet/freescale/gianfar.c:205:16: got unsigned int [noderef] * drivers/net/ethernet/freescale/gianfar.c:2918:44: warning: incorrect type in argument 1 (different address spaces) drivers/net/ethernet/freescale/gianfar.c:2918:44: expected unsigned int [noderef] *addr drivers/net/ethernet/freescale/gianfar.c:2918:44: got unsigned int [usertype] *rfbptr Signed-off-by: Kevin Hao Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 2 +- drivers/net/ethernet/freescale/gianfar.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index d2a67ed10a38..e54b1e39f9b4 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -177,7 +177,7 @@ static int gfar_init_bds(struct net_device *ndev) struct gfar_priv_rx_q *rx_queue = NULL; struct txbd8 *txbdp; struct rxbd8 *rxbdp; - u32 *rfbptr; + u32 __iomem *rfbptr; int i, j; dma_addr_t bufaddr; diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index b581b8823a2a..9e1802400c23 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -1039,7 +1039,7 @@ struct gfar_priv_rx_q { /* RX Coalescing values */ unsigned char rxcoalescing; unsigned long rxic; - u32 *rfbptr; + u32 __iomem *rfbptr; }; enum gfar_irqinfo_id { -- cgit v1.2.1 From de40ed31b3c577cefd7b54972365a272ecbe9dd6 Mon Sep 17 00:00:00 2001 From: Nimrod Andy Date: Wed, 24 Dec 2014 17:30:39 +0800 Subject: net: fec: add Wake-on-LAN support Support for Wake-on-LAN using Magic Packet. ENET IP supports sleep mode in low power status, when system enter suspend status, Magic packet can wake up system even if all SOC clocks are gate. The patch doing below things: - flagging the device as a wakeup source for the system, as well as its Wake-on-LAN interrupt - prepare the hardware for entering WoL mode - add standard ethtool WOL interface - enable the ENET interrupt to wake us Tested on i.MX6q/dl sabresd, sabreauto boards, i.MX6SX arm2 boards. Signed-off-by: Fugang Duan Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec.h | 2 + drivers/net/ethernet/freescale/fec_main.c | 104 +++++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index df8bbddaeb37..d77a96fdf1dd 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -357,6 +357,7 @@ struct bufdesc_ex { #define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ #define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ #define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ +#define FEC_ENET_WAKEUP ((uint)0x00020000) /* Wakeup request */ #define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2) #define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2) #define FEC_ENET_TS_AVAIL ((uint)0x00010000) @@ -512,6 +513,7 @@ struct fec_enet_private { int irq[FEC_IRQ_NUM]; bool bufdesc_ex; int pause_flag; + int wol_flag; u32 quirks; struct napi_struct napi; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 5ebdf8dc8a31..49cd358c30fa 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -187,6 +187,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_MMFR_RA(v) ((v & 0x1f) << 18) #define FEC_MMFR_TA (2 << 16) #define FEC_MMFR_DATA(v) (v & 0xffff) +/* FEC ECR bits definition */ +#define FEC_ECR_MAGICEN (1 << 2) +#define FEC_ECR_SLEEP (1 << 3) #define FEC_MII_TIMEOUT 30000 /* us */ @@ -195,6 +198,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_PAUSE_FLAG_AUTONEG 0x1 #define FEC_PAUSE_FLAG_ENABLE 0x2 +#define FEC_WOL_HAS_MAGIC_PACKET (0x1 << 0) +#define FEC_WOL_FLAG_ENABLE (0x1 << 1) +#define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2) #define COPYBREAK_DEFAULT 256 @@ -1089,7 +1095,9 @@ static void fec_stop(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); + struct fec_platform_data *pdata = fep->pdev->dev.platform_data; u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); + u32 val; /* We cannot expect a graceful transmit stop without link !!! */ if (fep->link) { @@ -1103,17 +1111,28 @@ fec_stop(struct net_device *ndev) * For i.MX6SX SOC, enet use AXI bus, we use disable MAC * instead of reset MAC itself. */ - if (fep->quirks & FEC_QUIRK_HAS_AVB) { - writel(0, fep->hwp + FEC_ECNTRL); + if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { + if (fep->quirks & FEC_QUIRK_HAS_AVB) { + writel(0, fep->hwp + FEC_ECNTRL); + } else { + writel(1, fep->hwp + FEC_ECNTRL); + udelay(10); + } + writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); } else { - writel(1, fep->hwp + FEC_ECNTRL); - udelay(10); + writel(FEC_DEFAULT_IMASK | FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK); + val = readl(fep->hwp + FEC_ECNTRL); + val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); + writel(val, fep->hwp + FEC_ECNTRL); + + if (pdata && pdata->sleep_mode_enable) + pdata->sleep_mode_enable(true); } writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); - writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); /* We have to keep ENET enabled to have MII interrupt stay working */ - if (fep->quirks & FEC_QUIRK_ENET_MAC) { + if (fep->quirks & FEC_QUIRK_ENET_MAC && + !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { writel(2, fep->hwp + FEC_ECNTRL); writel(rmii_mode, fep->hwp + FEC_R_CNTRL); } @@ -2427,6 +2446,44 @@ static int fec_enet_set_tunable(struct net_device *netdev, return ret; } +static void +fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + if (fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET) { + wol->supported = WAKE_MAGIC; + wol->wolopts = fep->wol_flag & FEC_WOL_FLAG_ENABLE ? WAKE_MAGIC : 0; + } else { + wol->supported = wol->wolopts = 0; + } +} + +static int +fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + if (!(fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET)) + return -EINVAL; + + if (wol->wolopts & ~WAKE_MAGIC) + return -EINVAL; + + device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC); + if (device_may_wakeup(&ndev->dev)) { + fep->wol_flag |= FEC_WOL_FLAG_ENABLE; + if (fep->irq[0] > 0) + enable_irq_wake(fep->irq[0]); + } else { + fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE); + if (fep->irq[0] > 0) + disable_irq_wake(fep->irq[0]); + } + + return 0; +} + static const struct ethtool_ops fec_enet_ethtool_ops = { .get_settings = fec_enet_get_settings, .set_settings = fec_enet_set_settings, @@ -2445,6 +2502,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = { .get_ts_info = fec_enet_get_ts_info, .get_tunable = fec_enet_get_tunable, .set_tunable = fec_enet_set_tunable, + .get_wol = fec_enet_get_wol, + .set_wol = fec_enet_set_wol, }; static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) @@ -2705,6 +2764,9 @@ fec_enet_open(struct net_device *ndev) phy_start(fep->phy_dev); netif_tx_start_all_queues(ndev); + device_set_wakeup_enable(&ndev->dev, fep->wol_flag & + FEC_WOL_FLAG_ENABLE); + return 0; err_enet_mii_probe: @@ -3153,6 +3215,9 @@ fec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); + if (of_get_property(np, "fsl,magic-packet", NULL)) + fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET; + phy_node = of_parse_phandle(np, "phy-handle", 0); if (!phy_node && of_phy_is_fixed_link(np)) { ret = of_phy_register_fixed_link(np); @@ -3247,6 +3312,8 @@ fec_probe(struct platform_device *pdev) 0, pdev->name, ndev); if (ret) goto failed_irq; + + fep->irq[i] = irq; } init_completion(&fep->mdio_done); @@ -3263,6 +3330,9 @@ fec_probe(struct platform_device *pdev) if (ret) goto failed_register; + device_init_wakeup(&ndev->dev, fep->wol_flag & + FEC_WOL_HAS_MAGIC_PACKET); + if (fep->bufdesc_ex && fep->ptp_clock) netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); @@ -3316,6 +3386,8 @@ static int __maybe_unused fec_suspend(struct device *dev) rtnl_lock(); if (netif_running(ndev)) { + if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) + fep->wol_flag |= FEC_WOL_FLAG_SLEEP_ON; phy_stop(fep->phy_dev); napi_disable(&fep->napi); netif_tx_lock_bh(ndev); @@ -3323,11 +3395,12 @@ static int __maybe_unused fec_suspend(struct device *dev) netif_tx_unlock_bh(ndev); fec_stop(ndev); fec_enet_clk_enable(ndev, false); - pinctrl_pm_select_sleep_state(&fep->pdev->dev); + if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) + pinctrl_pm_select_sleep_state(&fep->pdev->dev); } rtnl_unlock(); - if (fep->reg_phy) + if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) regulator_disable(fep->reg_phy); /* SOC supply clock to phy, when clock is disabled, phy link down @@ -3343,9 +3416,11 @@ static int __maybe_unused fec_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); + struct fec_platform_data *pdata = fep->pdev->dev.platform_data; int ret; + int val; - if (fep->reg_phy) { + if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) { ret = regulator_enable(fep->reg_phy); if (ret) return ret; @@ -3353,12 +3428,21 @@ static int __maybe_unused fec_resume(struct device *dev) rtnl_lock(); if (netif_running(ndev)) { - pinctrl_pm_select_default_state(&fep->pdev->dev); ret = fec_enet_clk_enable(ndev, true); if (ret) { rtnl_unlock(); goto failed_clk; } + if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) { + if (pdata && pdata->sleep_mode_enable) + pdata->sleep_mode_enable(false); + val = readl(fep->hwp + FEC_ECNTRL); + val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP); + writel(val, fep->hwp + FEC_ECNTRL); + fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON; + } else { + pinctrl_pm_select_default_state(&fep->pdev->dev); + } fec_restart(ndev); netif_tx_lock_bh(ndev); netif_device_attach(ndev); -- cgit v1.2.1 From 5e32066d0085af3c53834323c90b7c69a8f788f6 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Wed, 24 Dec 2014 15:59:36 +0530 Subject: enic: make vnic_wq_buf doubly linked This patch makes vnic_wq_buf doubly liked list. This is needed for dma_mapping error check, in case some frag's dma map fails, we need to move back and remove previously queued buffers. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/vnic_wq.c | 3 +++ drivers/net/ethernet/cisco/enic/vnic_wq.h | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cisco/enic/vnic_wq.c b/drivers/net/ethernet/cisco/enic/vnic_wq.c index 3e6b8d54dafc..b5a1c937fad2 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_wq.c +++ b/drivers/net/ethernet/cisco/enic/vnic_wq.c @@ -47,11 +47,14 @@ static int vnic_wq_alloc_bufs(struct vnic_wq *wq) wq->ring.desc_size * buf->index; if (buf->index + 1 == count) { buf->next = wq->bufs[0]; + buf->next->prev = buf; break; } else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES(count)) { buf->next = wq->bufs[i + 1]; + buf->next->prev = buf; } else { buf->next = buf + 1; + buf->next->prev = buf; buf++; } } diff --git a/drivers/net/ethernet/cisco/enic/vnic_wq.h b/drivers/net/ethernet/cisco/enic/vnic_wq.h index 816f1ad6072f..296154351823 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_wq.h +++ b/drivers/net/ethernet/cisco/enic/vnic_wq.h @@ -62,6 +62,7 @@ struct vnic_wq_buf { uint8_t cq_entry; /* Gets completion event from hw */ uint8_t desc_skip_cnt; /* Num descs to occupy */ uint8_t compressed_send; /* Both hdr and payload in one desc */ + struct vnic_wq_buf *prev; }; /* Break the vnic_wq_buf allocations into blocks of 32/64 entries */ -- cgit v1.2.1 From 065df159ec588630a360a689e4e3043c6622a6e9 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Wed, 24 Dec 2014 15:59:37 +0530 Subject: enic: check dma_mapping_error This patch checks for pci_dma_mapping_error() after dma mapping the data. If the dma mapping fails we remove the previously queued frags and return NETDEV_TX_OK. Reported-by: Jan Stancek Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic.h | 12 +++ drivers/net/ethernet/cisco/enic/enic_main.c | 152 +++++++++++++++++----------- 2 files changed, 106 insertions(+), 58 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 25c4d88853d8..b2ea35a3a881 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -242,6 +242,18 @@ static inline unsigned int enic_msix_notify_intr(struct enic *enic) return enic->rq_count + enic->wq_count + 1; } +static inline int enic_dma_map_check(struct enic *enic, dma_addr_t dma_addr) +{ + if (unlikely(pci_dma_mapping_error(enic->pdev, dma_addr))) { + net_warn_ratelimited("%s: PCI dma mapping failed!\n", + enic->netdev->name); + + return -ENOMEM; + } + + return 0; +} + void enic_reset_addr_lists(struct enic *enic); int enic_sriov_enabled(struct enic *enic); int enic_is_valid_vf(struct enic *enic, int vf); diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 705f334ebb85..142c9b5509ae 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -351,80 +351,94 @@ static irqreturn_t enic_isr_msix_notify(int irq, void *data) return IRQ_HANDLED; } -static inline void enic_queue_wq_skb_cont(struct enic *enic, - struct vnic_wq *wq, struct sk_buff *skb, - unsigned int len_left, int loopback) +static int enic_queue_wq_skb_cont(struct enic *enic, struct vnic_wq *wq, + struct sk_buff *skb, unsigned int len_left, + int loopback) { const skb_frag_t *frag; + dma_addr_t dma_addr; /* Queue additional data fragments */ for (frag = skb_shinfo(skb)->frags; len_left; frag++) { len_left -= skb_frag_size(frag); - enic_queue_wq_desc_cont(wq, skb, - skb_frag_dma_map(&enic->pdev->dev, - frag, 0, skb_frag_size(frag), - DMA_TO_DEVICE), - skb_frag_size(frag), - (len_left == 0), /* EOP? */ - loopback); + dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag, 0, + skb_frag_size(frag), + DMA_TO_DEVICE); + if (unlikely(enic_dma_map_check(enic, dma_addr))) + return -ENOMEM; + enic_queue_wq_desc_cont(wq, skb, dma_addr, skb_frag_size(frag), + (len_left == 0), /* EOP? */ + loopback); } + + return 0; } -static inline void enic_queue_wq_skb_vlan(struct enic *enic, - struct vnic_wq *wq, struct sk_buff *skb, - int vlan_tag_insert, unsigned int vlan_tag, int loopback) +static int enic_queue_wq_skb_vlan(struct enic *enic, struct vnic_wq *wq, + struct sk_buff *skb, int vlan_tag_insert, + unsigned int vlan_tag, int loopback) { unsigned int head_len = skb_headlen(skb); unsigned int len_left = skb->len - head_len; int eop = (len_left == 0); + dma_addr_t dma_addr; + int err = 0; + + dma_addr = pci_map_single(enic->pdev, skb->data, head_len, + PCI_DMA_TODEVICE); + if (unlikely(enic_dma_map_check(enic, dma_addr))) + return -ENOMEM; /* Queue the main skb fragment. The fragments are no larger * than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less * than WQ_ENET_MAX_DESC_LEN length. So only one descriptor * per fragment is queued. */ - enic_queue_wq_desc(wq, skb, - pci_map_single(enic->pdev, skb->data, - head_len, PCI_DMA_TODEVICE), - head_len, - vlan_tag_insert, vlan_tag, - eop, loopback); + enic_queue_wq_desc(wq, skb, dma_addr, head_len, vlan_tag_insert, + vlan_tag, eop, loopback); if (!eop) - enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); + err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); + + return err; } -static inline void enic_queue_wq_skb_csum_l4(struct enic *enic, - struct vnic_wq *wq, struct sk_buff *skb, - int vlan_tag_insert, unsigned int vlan_tag, int loopback) +static int enic_queue_wq_skb_csum_l4(struct enic *enic, struct vnic_wq *wq, + struct sk_buff *skb, int vlan_tag_insert, + unsigned int vlan_tag, int loopback) { unsigned int head_len = skb_headlen(skb); unsigned int len_left = skb->len - head_len; unsigned int hdr_len = skb_checksum_start_offset(skb); unsigned int csum_offset = hdr_len + skb->csum_offset; int eop = (len_left == 0); + dma_addr_t dma_addr; + int err = 0; + + dma_addr = pci_map_single(enic->pdev, skb->data, head_len, + PCI_DMA_TODEVICE); + if (unlikely(enic_dma_map_check(enic, dma_addr))) + return -ENOMEM; /* Queue the main skb fragment. The fragments are no larger * than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less * than WQ_ENET_MAX_DESC_LEN length. So only one descriptor * per fragment is queued. */ - enic_queue_wq_desc_csum_l4(wq, skb, - pci_map_single(enic->pdev, skb->data, - head_len, PCI_DMA_TODEVICE), - head_len, - csum_offset, - hdr_len, - vlan_tag_insert, vlan_tag, - eop, loopback); + enic_queue_wq_desc_csum_l4(wq, skb, dma_addr, head_len, csum_offset, + hdr_len, vlan_tag_insert, vlan_tag, eop, + loopback); if (!eop) - enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); + err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); + + return err; } -static inline void enic_queue_wq_skb_tso(struct enic *enic, - struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss, - int vlan_tag_insert, unsigned int vlan_tag, int loopback) +static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq, + struct sk_buff *skb, unsigned int mss, + int vlan_tag_insert, unsigned int vlan_tag, + int loopback) { unsigned int frag_len_left = skb_headlen(skb); unsigned int len_left = skb->len - frag_len_left; @@ -454,20 +468,19 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic, */ while (frag_len_left) { len = min(frag_len_left, (unsigned int)WQ_ENET_MAX_DESC_LEN); - dma_addr = pci_map_single(enic->pdev, skb->data + offset, - len, PCI_DMA_TODEVICE); - enic_queue_wq_desc_tso(wq, skb, - dma_addr, - len, - mss, hdr_len, - vlan_tag_insert, vlan_tag, - eop && (len == frag_len_left), loopback); + dma_addr = pci_map_single(enic->pdev, skb->data + offset, len, + PCI_DMA_TODEVICE); + if (unlikely(enic_dma_map_check(enic, dma_addr))) + return -ENOMEM; + enic_queue_wq_desc_tso(wq, skb, dma_addr, len, mss, hdr_len, + vlan_tag_insert, vlan_tag, + eop && (len == frag_len_left), loopback); frag_len_left -= len; offset += len; } if (eop) - return; + return 0; /* Queue WQ_ENET_MAX_DESC_LEN length descriptors * for additional data fragments @@ -483,16 +496,18 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic, dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag, offset, len, DMA_TO_DEVICE); - enic_queue_wq_desc_cont(wq, skb, - dma_addr, - len, - (len_left == 0) && - (len == frag_len_left), /* EOP? */ - loopback); + if (unlikely(enic_dma_map_check(enic, dma_addr))) + return -ENOMEM; + enic_queue_wq_desc_cont(wq, skb, dma_addr, len, + (len_left == 0) && + (len == frag_len_left),/*EOP*/ + loopback); frag_len_left -= len; offset += len; } } + + return 0; } static inline void enic_queue_wq_skb(struct enic *enic, @@ -502,6 +517,7 @@ static inline void enic_queue_wq_skb(struct enic *enic, unsigned int vlan_tag = 0; int vlan_tag_insert = 0; int loopback = 0; + int err; if (vlan_tx_tag_present(skb)) { /* VLAN tag from trunking driver */ @@ -513,14 +529,30 @@ static inline void enic_queue_wq_skb(struct enic *enic, } if (mss) - enic_queue_wq_skb_tso(enic, wq, skb, mss, - vlan_tag_insert, vlan_tag, loopback); + err = enic_queue_wq_skb_tso(enic, wq, skb, mss, + vlan_tag_insert, vlan_tag, + loopback); else if (skb->ip_summed == CHECKSUM_PARTIAL) - enic_queue_wq_skb_csum_l4(enic, wq, skb, - vlan_tag_insert, vlan_tag, loopback); + err = enic_queue_wq_skb_csum_l4(enic, wq, skb, vlan_tag_insert, + vlan_tag, loopback); else - enic_queue_wq_skb_vlan(enic, wq, skb, - vlan_tag_insert, vlan_tag, loopback); + err = enic_queue_wq_skb_vlan(enic, wq, skb, vlan_tag_insert, + vlan_tag, loopback); + if (unlikely(err)) { + struct vnic_wq_buf *buf; + + buf = wq->to_use->prev; + /* while not EOP of previous pkt && queue not empty. + * For all non EOP bufs, os_buf is NULL. + */ + while (!buf->os_buf && (buf->next != wq->to_clean)) { + enic_free_wq_buf(wq, buf); + wq->ring.desc_avail++; + buf = buf->prev; + } + wq->to_use = buf->next; + dev_kfree_skb(skb); + } } /* netif_tx_lock held, process context with BHs disabled, or BH */ @@ -950,8 +982,12 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq) if (!skb) return -ENOMEM; - dma_addr = pci_map_single(enic->pdev, skb->data, - len, PCI_DMA_FROMDEVICE); + dma_addr = pci_map_single(enic->pdev, skb->data, len, + PCI_DMA_FROMDEVICE); + if (unlikely(enic_dma_map_check(enic, dma_addr))) { + dev_kfree_skb(skb); + return -ENOMEM; + } enic_queue_rq_desc(rq, skb, os_buf_index, dma_addr, len); -- cgit v1.2.1 From 58feff07e9c964a88f82d13d272d384bd4274a33 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Wed, 24 Dec 2014 15:59:38 +0530 Subject: enic: add stats for dma mapping error This patch adds generic statistics for enic. As of now dma_map_error is the only member. dma_map_erro is incremented every time dma maping error happens. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic.h | 2 ++ drivers/net/ethernet/cisco/enic/enic_ethtool.c | 19 ++++++++++++++++++- drivers/net/ethernet/cisco/enic/vnic_stats.h | 5 +++++ 3 files changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index b2ea35a3a881..d2a103547c67 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -188,6 +188,7 @@ struct enic { struct enic_rfs_flw_tbl rfs_h; u32 rx_copybreak; u8 rss_key[ENIC_RSS_LEN]; + struct vnic_gen_stats gen_stats; }; static inline struct device *enic_get_dev(struct enic *enic) @@ -247,6 +248,7 @@ static inline int enic_dma_map_check(struct enic *enic, dma_addr_t dma_addr) if (unlikely(pci_dma_mapping_error(enic->pdev, dma_addr))) { net_warn_ratelimited("%s: PCI dma mapping failed!\n", enic->netdev->name); + enic->gen_stats.dma_map_error++; return -ENOMEM; } diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index eba1eb846d34..0c396c1f55dc 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -24,6 +24,7 @@ #include "enic_dev.h" #include "enic_clsf.h" #include "vnic_rss.h" +#include "vnic_stats.h" struct enic_stat { char name[ETH_GSTRING_LEN]; @@ -40,6 +41,11 @@ struct enic_stat { .index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \ } +#define ENIC_GEN_STAT(stat) { \ + .name = #stat, \ + .index = offsetof(struct vnic_gen_stats, stat) / sizeof(u64)\ +} + static const struct enic_stat enic_tx_stats[] = { ENIC_TX_STAT(tx_frames_ok), ENIC_TX_STAT(tx_unicast_frames_ok), @@ -78,8 +84,13 @@ static const struct enic_stat enic_rx_stats[] = { ENIC_RX_STAT(rx_frames_to_max), }; +static const struct enic_stat enic_gen_stats[] = { + ENIC_GEN_STAT(dma_map_error), +}; + static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats); static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats); +static const unsigned int enic_n_gen_stats = ARRAY_SIZE(enic_gen_stats); void enic_intr_coal_set_rx(struct enic *enic, u32 timer) { @@ -146,6 +157,10 @@ static void enic_get_strings(struct net_device *netdev, u32 stringset, memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN); data += ETH_GSTRING_LEN; } + for (i = 0; i < enic_n_gen_stats; i++) { + memcpy(data, enic_gen_stats[i].name, ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } break; } } @@ -154,7 +169,7 @@ static int enic_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { case ETH_SS_STATS: - return enic_n_tx_stats + enic_n_rx_stats; + return enic_n_tx_stats + enic_n_rx_stats + enic_n_gen_stats; default: return -EOPNOTSUPP; } @@ -173,6 +188,8 @@ static void enic_get_ethtool_stats(struct net_device *netdev, *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index]; for (i = 0; i < enic_n_rx_stats; i++) *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index]; + for (i = 0; i < enic_n_gen_stats; i++) + *(data++) = ((u64 *)&enic->gen_stats)[enic_gen_stats[i].index]; } static u32 enic_get_msglevel(struct net_device *netdev) diff --git a/drivers/net/ethernet/cisco/enic/vnic_stats.h b/drivers/net/ethernet/cisco/enic/vnic_stats.h index 77750ec93954..74c81ed6fdab 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_stats.h +++ b/drivers/net/ethernet/cisco/enic/vnic_stats.h @@ -62,6 +62,11 @@ struct vnic_rx_stats { u64 rsvd[16]; }; +/* Generic statistics */ +struct vnic_gen_stats { + u64 dma_map_error; +}; + struct vnic_stats { struct vnic_tx_stats tx; struct vnic_rx_stats rx; -- cgit v1.2.1 From 87897931c83038af4931990af5b9365b41829921 Mon Sep 17 00:00:00 2001 From: Alex Gartrell Date: Thu, 25 Dec 2014 23:05:03 -0800 Subject: tun: Fixed unsigned/signed comparison Validated that this was actually using the unsigned comparison with gdb. Signed-off-by: Alex Gartrell Signed-off-by: David S. Miller --- drivers/net/tun.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8c8dc16839a7..df5e94871844 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1501,7 +1501,7 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT); - if (ret > total_len) { + if (ret > (ssize_t)total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; } -- cgit v1.2.1 From 957f094f221f81e457133b1f4c4d95ffa49ff731 Mon Sep 17 00:00:00 2001 From: Alex Gartrell Date: Thu, 25 Dec 2014 23:22:49 -0800 Subject: tun: return proper error code from tun_do_read Instead of -1 with EAGAIN, read on a O_NONBLOCK tun fd will return 0. This fixes this by properly returning the error code from __skb_recv_datagram. Signed-off-by: Alex Gartrell Signed-off-by: David S. Miller --- drivers/net/tun.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index df5e94871844..c0df872f5b8c 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1380,7 +1380,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0, &peeked, &off, &err); if (!skb) - return 0; + return err; ret = tun_put_user(tun, tfile, skb, to); if (unlikely(ret < 0)) -- cgit v1.2.1 From 54da5083b71f01596ac3112685920fdde4540685 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 31 Dec 2014 18:32:25 -0500 Subject: e1000e: Include clocksource.h to get CLOCKSOURCE_MASK. Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/e1000e/netdev.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index e14fd85f64eb..2537d36a47cc 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "e1000.h" -- cgit v1.2.1 From 9aacfb2023c67c8e797bf1f9ba5e095c5a09d296 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 31 Dec 2014 18:32:40 -0500 Subject: igb_ptp: Include clocksource.h to get CLOCKSOURCE_MASK. Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igb/igb_ptp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 1d27f2d3b57c..8baf3fd459e4 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "igb.h" -- cgit v1.2.1 From 7ad269ea1a2b7ddc8ae26794162c21bad2d9b2e5 Mon Sep 17 00:00:00 2001 From: Roger Chen Date: Mon, 29 Dec 2014 17:43:36 +0800 Subject: GMAC: add driver for Rockchip RK3288 SoCs integrated GMAC This driver is based on stmmac driver. changes since v2: - use tab instead of space for macros - use HIWORD_UPDATE macro for GMAC_CLK_RX_DL_CFG and GMAC_CLK_TX_DL_CFG - remove drive-strength setting in the driver and set it in the pinctrl settings - use dev_err instead of pr_err - remove clock names's macros, just use the real name of the clock - use devm_clk_get() instead of clk_get() - remove clk_set_parent(bsp_priv->clk_mac, bsp_priv->clk_mac_pll) - remove gpio setting for LDO, just use regulator API - remove phy reset using gpio in the glue layer, it has been handled in the stmmac driver - remove handling phy interrupt (mii interrupt) changes since v1: - use BIT() to set register - combine two remap_write() operations into one for the same register - use macros for register value setting - remove grf fail check in rk_gmac_setup() and save all the check in set_rgmii_speed() - remove .tx_coe=1 in rk_gmac_data Signed-off-by: Roger Chen Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 459 +++++++++++++++++++++ .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 1 + .../net/ethernet/stmicro/stmmac/stmmac_platform.h | 1 + 4 files changed, 462 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index ac4d5629d905..73c2715a27f3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o \ - dwmac-sti.o dwmac-socfpga.o + dwmac-sti.o dwmac-socfpga.o dwmac-rk.o obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o stmmac-pci-objs:= stmmac_pci.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c new file mode 100644 index 000000000000..35f9b86bc9e5 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -0,0 +1,459 @@ +/** + * dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer + * + * Copyright (C) 2014 Chen-Zhi (Roger Chen) + * + * Chen-Zhi (Roger Chen) + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rk_priv_data { + struct platform_device *pdev; + int phy_iface; + char regulator[32]; + + bool clk_enabled; + bool clock_input; + + struct clk *clk_mac; + struct clk *clk_mac_pll; + struct clk *gmac_clkin; + struct clk *mac_clk_rx; + struct clk *mac_clk_tx; + struct clk *clk_mac_ref; + struct clk *clk_mac_refout; + struct clk *aclk_mac; + struct clk *pclk_mac; + + int tx_delay; + int rx_delay; + + struct regmap *grf; +}; + +#define HIWORD_UPDATE(val, mask, shift) \ + ((val) << (shift) | (mask) << ((shift) + 16)) + +#define GRF_BIT(nr) (BIT(nr) | BIT(nr+16)) +#define GRF_CLR_BIT(nr) (BIT(nr+16)) + +#define RK3288_GRF_SOC_CON1 0x0248 +#define RK3288_GRF_SOC_CON3 0x0250 +#define RK3288_GRF_GPIO3D_E 0x01ec +#define RK3288_GRF_GPIO4A_E 0x01f0 +#define RK3288_GRF_GPIO4B_E 0x01f4 + +/*RK3288_GRF_SOC_CON1*/ +#define GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8)) +#define GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8)) +#define GMAC_FLOW_CTRL GRF_BIT(9) +#define GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9) +#define GMAC_SPEED_10M GRF_CLR_BIT(10) +#define GMAC_SPEED_100M GRF_BIT(10) +#define GMAC_RMII_CLK_25M GRF_BIT(11) +#define GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11) +#define GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13)) +#define GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13)) +#define GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13)) +#define GMAC_RMII_MODE GRF_BIT(14) +#define GMAC_RMII_MODE_CLR GRF_CLR_BIT(14) + +/*RK3288_GRF_SOC_CON3*/ +#define GMAC_TXCLK_DLY_ENABLE GRF_BIT(14) +#define GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14) +#define GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) +#define GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) +#define GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7) +#define GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) + +static void set_to_rgmii(struct rk_priv_data *bsp_priv, + int tx_delay, int rx_delay) +{ + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { + dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); + return; + } + + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, + GMAC_PHY_INTF_SEL_RGMII | GMAC_RMII_MODE_CLR); + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3, + GMAC_RXCLK_DLY_ENABLE | GMAC_TXCLK_DLY_ENABLE | + GMAC_CLK_RX_DL_CFG(rx_delay) | + GMAC_CLK_TX_DL_CFG(tx_delay)); +} + +static void set_to_rmii(struct rk_priv_data *bsp_priv) +{ + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { + dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); + return; + } + + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, + GMAC_PHY_INTF_SEL_RMII | GMAC_RMII_MODE); +} + +static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) +{ + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { + dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); + return; + } + + if (speed == 10) + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M); + else if (speed == 100) + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_25M); + else if (speed == 1000) + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_125M); + else + dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); +} + +static void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +{ + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { + dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); + return; + } + + if (speed == 10) { + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, + GMAC_RMII_CLK_2_5M | GMAC_SPEED_10M); + } else if (speed == 100) { + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, + GMAC_RMII_CLK_25M | GMAC_SPEED_100M); + } else { + dev_err(dev, "unknown speed value for RMII! speed=%d", speed); + } +} + +static int gmac_clk_init(struct rk_priv_data *bsp_priv) +{ + struct device *dev = &bsp_priv->pdev->dev; + + bsp_priv->clk_enabled = false; + + bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx"); + if (IS_ERR(bsp_priv->mac_clk_rx)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "mac_clk_rx"); + + bsp_priv->mac_clk_tx = devm_clk_get(dev, "mac_clk_tx"); + if (IS_ERR(bsp_priv->mac_clk_tx)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "mac_clk_tx"); + + bsp_priv->aclk_mac = devm_clk_get(dev, "aclk_mac"); + if (IS_ERR(bsp_priv->aclk_mac)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "aclk_mac"); + + bsp_priv->pclk_mac = devm_clk_get(dev, "pclk_mac"); + if (IS_ERR(bsp_priv->pclk_mac)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "pclk_mac"); + + bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth"); + if (IS_ERR(bsp_priv->clk_mac)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "stmmaceth"); + + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) { + bsp_priv->clk_mac_ref = devm_clk_get(dev, "clk_mac_ref"); + if (IS_ERR(bsp_priv->clk_mac_ref)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "clk_mac_ref"); + + if (!bsp_priv->clock_input) { + bsp_priv->clk_mac_refout = + devm_clk_get(dev, "clk_mac_refout"); + if (IS_ERR(bsp_priv->clk_mac_refout)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "clk_mac_refout"); + } + } + + if (bsp_priv->clock_input) { + dev_info(dev, "%s: clock input from PHY\n", __func__); + } else { + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) + clk_set_rate(bsp_priv->clk_mac_pll, 50000000); + } + + return 0; +} + +static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable) +{ + int phy_iface = phy_iface = bsp_priv->phy_iface; + + if (enable) { + if (!bsp_priv->clk_enabled) { + if (phy_iface == PHY_INTERFACE_MODE_RMII) { + if (!IS_ERR(bsp_priv->mac_clk_rx)) + clk_prepare_enable( + bsp_priv->mac_clk_rx); + + if (!IS_ERR(bsp_priv->clk_mac_ref)) + clk_prepare_enable( + bsp_priv->clk_mac_ref); + + if (!IS_ERR(bsp_priv->clk_mac_refout)) + clk_prepare_enable( + bsp_priv->clk_mac_refout); + } + + if (!IS_ERR(bsp_priv->aclk_mac)) + clk_prepare_enable(bsp_priv->aclk_mac); + + if (!IS_ERR(bsp_priv->pclk_mac)) + clk_prepare_enable(bsp_priv->pclk_mac); + + if (!IS_ERR(bsp_priv->mac_clk_tx)) + clk_prepare_enable(bsp_priv->mac_clk_tx); + + /** + * if (!IS_ERR(bsp_priv->clk_mac)) + * clk_prepare_enable(bsp_priv->clk_mac); + */ + mdelay(5); + bsp_priv->clk_enabled = true; + } + } else { + if (bsp_priv->clk_enabled) { + if (phy_iface == PHY_INTERFACE_MODE_RMII) { + if (!IS_ERR(bsp_priv->mac_clk_rx)) + clk_disable_unprepare( + bsp_priv->mac_clk_rx); + + if (!IS_ERR(bsp_priv->clk_mac_ref)) + clk_disable_unprepare( + bsp_priv->clk_mac_ref); + + if (!IS_ERR(bsp_priv->clk_mac_refout)) + clk_disable_unprepare( + bsp_priv->clk_mac_refout); + } + + if (!IS_ERR(bsp_priv->aclk_mac)) + clk_disable_unprepare(bsp_priv->aclk_mac); + + if (!IS_ERR(bsp_priv->pclk_mac)) + clk_disable_unprepare(bsp_priv->pclk_mac); + + if (!IS_ERR(bsp_priv->mac_clk_tx)) + clk_disable_unprepare(bsp_priv->mac_clk_tx); + /** + * if (!IS_ERR(bsp_priv->clk_mac)) + * clk_disable_unprepare(bsp_priv->clk_mac); + */ + bsp_priv->clk_enabled = false; + } + } + + return 0; +} + +static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable) +{ + struct regulator *ldo; + char *ldostr = bsp_priv->regulator; + int ret; + struct device *dev = &bsp_priv->pdev->dev; + + if (!ldostr) { + dev_err(dev, "%s: no ldo found\n", __func__); + return -1; + } + + ldo = regulator_get(NULL, ldostr); + if (!ldo) { + dev_err(dev, "\n%s get ldo %s failed\n", __func__, ldostr); + } else { + if (enable) { + if (!regulator_is_enabled(ldo)) { + regulator_set_voltage(ldo, 3300000, 3300000); + ret = regulator_enable(ldo); + if (ret != 0) + dev_err(dev, "%s: fail to enable %s\n", + __func__, ldostr); + else + dev_info(dev, "turn on ldo done.\n"); + } else { + dev_warn(dev, "%s is enabled before enable", + ldostr); + } + } else { + if (regulator_is_enabled(ldo)) { + ret = regulator_disable(ldo); + if (ret != 0) + dev_err(dev, "%s: fail to disable %s\n", + __func__, ldostr); + else + dev_info(dev, "turn off ldo done.\n"); + } else { + dev_warn(dev, "%s is disabled before disable", + ldostr); + } + } + regulator_put(ldo); + } + + return 0; +} + +static void *rk_gmac_setup(struct platform_device *pdev) +{ + struct rk_priv_data *bsp_priv; + struct device *dev = &pdev->dev; + int ret; + const char *strings = NULL; + int value; + + bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL); + if (!bsp_priv) + return ERR_PTR(-ENOMEM); + + bsp_priv->phy_iface = of_get_phy_mode(dev->of_node); + + ret = of_property_read_string(dev->of_node, "phy_regulator", &strings); + if (ret) { + dev_warn(dev, "%s: Can not read property: phy_regulator.\n", + __func__); + } else { + dev_info(dev, "%s: PHY power controlled by regulator(%s).\n", + __func__, strings); + strcpy(bsp_priv->regulator, strings); + } + + ret = of_property_read_string(dev->of_node, "clock_in_out", &strings); + if (ret) { + dev_err(dev, "%s: Can not read property: clock_in_out.\n", + __func__); + bsp_priv->clock_input = true; + } else { + dev_info(dev, "%s: clock input or output? (%s).\n", + __func__, strings); + if (!strcmp(strings, "input")) + bsp_priv->clock_input = true; + else + bsp_priv->clock_input = false; + } + + ret = of_property_read_u32(dev->of_node, "tx_delay", &value); + if (ret) { + bsp_priv->tx_delay = 0x30; + dev_err(dev, "%s: Can not read property: tx_delay.", __func__); + dev_err(dev, "%s: set tx_delay to 0x%x\n", + __func__, bsp_priv->tx_delay); + } else { + dev_info(dev, "%s: TX delay(0x%x).\n", __func__, value); + bsp_priv->tx_delay = value; + } + + ret = of_property_read_u32(dev->of_node, "rx_delay", &value); + if (ret) { + bsp_priv->rx_delay = 0x10; + dev_err(dev, "%s: Can not read property: rx_delay.", __func__); + dev_err(dev, "%s: set rx_delay to 0x%x\n", + __func__, bsp_priv->rx_delay); + } else { + dev_info(dev, "%s: RX delay(0x%x).\n", __func__, value); + bsp_priv->rx_delay = value; + } + + bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,grf"); + bsp_priv->pdev = pdev; + + /*rmii or rgmii*/ + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) { + dev_info(dev, "%s: init for RGMII\n", __func__); + set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay); + } else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) { + dev_info(dev, "%s: init for RMII\n", __func__); + set_to_rmii(bsp_priv); + } else { + dev_err(dev, "%s: NO interface defined!\n", __func__); + } + + gmac_clk_init(bsp_priv); + + return bsp_priv; +} + +static int rk_gmac_init(struct platform_device *pdev, void *priv) +{ + struct rk_priv_data *bsp_priv = priv; + int ret; + + ret = phy_power_on(bsp_priv, true); + if (ret) + return ret; + + ret = gmac_clk_enable(bsp_priv, true); + if (ret) + return ret; + + return 0; +} + +static void rk_gmac_exit(struct platform_device *pdev, void *priv) +{ + struct rk_priv_data *gmac = priv; + + phy_power_on(gmac, false); + gmac_clk_enable(gmac, false); +} + +static void rk_fix_speed(void *priv, unsigned int speed) +{ + struct rk_priv_data *bsp_priv = priv; + struct device *dev = &bsp_priv->pdev->dev; + + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) + set_rgmii_speed(bsp_priv, speed); + else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) + set_rmii_speed(bsp_priv, speed); + else + dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface); +} + +const struct stmmac_of_data rk3288_gmac_data = { + .has_gmac = 1, + .fix_mac_speed = rk_fix_speed, + .setup = rk_gmac_setup, + .init = rk_gmac_init, + .exit = rk_gmac_exit, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 3039de2465ba..879e29f48a89 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -33,6 +33,7 @@ static const struct of_device_id stmmac_dt_ids[] = { /* SoC specific glue layers should come before generic bindings */ + { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data}, { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data}, { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data}, { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data}, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 25dd1f7ace02..093eb99e5ffd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -24,5 +24,6 @@ extern const struct stmmac_of_data sun7i_gmac_data; extern const struct stmmac_of_data stih4xx_dwmac_data; extern const struct stmmac_of_data stid127_dwmac_data; extern const struct stmmac_of_data socfpga_gmac_data; +extern const struct stmmac_of_data rk3288_gmac_data; #endif /* __STMMAC_PLATFORM_H__ */ -- cgit v1.2.1 From cef27f971e04785bc1c711a74a9e0d81bfd0b150 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Tue, 30 Dec 2014 16:27:33 +0800 Subject: net/fsl: remove reset from xgmac_mdio Since the reset is just clock setting, individual mdio reset is not available. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/xgmac_mdio.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index 6e7db66069aa..90adba19de6a 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -174,24 +174,6 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) return value; } -/* Reset the MIIM registers, and wait for the bus to free */ -static int xgmac_mdio_reset(struct mii_bus *bus) -{ - struct tgec_mdio_controller __iomem *regs = bus->priv; - int ret; - - mutex_lock(&bus->mdio_lock); - - /* Setup the MII Mgmt clock speed */ - out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); - - ret = xgmac_wait_until_free(&bus->dev, regs); - - mutex_unlock(&bus->mdio_lock); - - return ret; -} - static int xgmac_mdio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -212,7 +194,6 @@ static int xgmac_mdio_probe(struct platform_device *pdev) bus->name = "Freescale XGMAC MDIO Bus"; bus->read = xgmac_mdio_read; bus->write = xgmac_mdio_write; - bus->reset = xgmac_mdio_reset; bus->irq = bus->priv; bus->parent = &pdev->dev; snprintf(bus->id, MII_BUS_ID_SIZE, "%llx", (unsigned long long)res.start); -- cgit v1.2.1 From aa842478044ff3e5a9e4b339f3bde5a0e78440e0 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Tue, 30 Dec 2014 16:28:00 +0800 Subject: net/fsl: remove irq assignment from xgmac_mdio Which is wrong and not used, so no extra space needed by mdiobus_alloc_size(), use mdiobus_alloc() instead. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/xgmac_mdio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index 90adba19de6a..9de526891da0 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -187,14 +187,13 @@ static int xgmac_mdio_probe(struct platform_device *pdev) return ret; } - bus = mdiobus_alloc_size(PHY_MAX_ADDR * sizeof(int)); + bus = mdiobus_alloc(); if (!bus) return -ENOMEM; bus->name = "Freescale XGMAC MDIO Bus"; bus->read = xgmac_mdio_read; bus->write = xgmac_mdio_write; - bus->irq = bus->priv; bus->parent = &pdev->dev; snprintf(bus->id, MII_BUS_ID_SIZE, "%llx", (unsigned long long)res.start); -- cgit v1.2.1 From 05930b5ec1d3b2a5c76e1959b54cae15587009c7 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Tue, 30 Dec 2014 16:28:21 +0800 Subject: net/fsl: remove hardcoded clock setting from xgmac_mdio There is no need to set the clock speed in read/write which will be performed unnecessarily for each mdio access. Init it during probe is enough. Also, the hardcoded clock value is not a proper way for all SoCs. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/xgmac_mdio.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index 9de526891da0..a35244586a63 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -94,13 +94,6 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 val uint16_t dev_addr = regnum >> 16; int ret; - /* Setup the MII Mgmt clock speed */ - out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); - - ret = xgmac_wait_until_free(&bus->dev, regs); - if (ret) - return ret; - /* Set the port and dev addr */ out_be32(®s->mdio_ctl, MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr)); @@ -135,13 +128,6 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) uint16_t value; int ret; - /* Setup the MII Mgmt clock speed */ - out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); - - ret = xgmac_wait_until_free(&bus->dev, regs); - if (ret) - return ret; - /* Set the Port and Device Addrs */ mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); out_be32(®s->mdio_ctl, mdio_ctl); -- cgit v1.2.1 From 9b174d88c257150562b0101fcc6cb6c3cb74275c Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Tue, 30 Dec 2014 19:10:15 -0800 Subject: net: Add Transparent Ethernet Bridging GRO support. Currently the only tunnel protocol that supports GRO with encapsulated Ethernet is VXLAN. This pulls out the Ethernet code into a proper layer so that it can be used by other tunnel protocols such as GRE and Geneve. Signed-off-by: Jesse Gross Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 53 ++++++----------------------------------------------- 1 file changed, 6 insertions(+), 47 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 7fbd89fbe107..2ab0922af0b4 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -549,10 +549,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff { struct sk_buff *p, **pp = NULL; struct vxlanhdr *vh, *vh2; - struct ethhdr *eh, *eh2; - unsigned int hlen, off_vx, off_eth; - const struct packet_offload *ptype; - __be16 type; + unsigned int hlen, off_vx; int flush = 1; off_vx = skb_gro_offset(skb); @@ -563,17 +560,6 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff if (unlikely(!vh)) goto out; } - skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */ - skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr)); - - off_eth = skb_gro_offset(skb); - hlen = off_eth + sizeof(*eh); - eh = skb_gro_header_fast(skb, off_eth); - if (skb_gro_header_hard(skb, hlen)) { - eh = skb_gro_header_slow(skb, hlen, off_eth); - if (unlikely(!eh)) - goto out; - } flush = 0; @@ -582,28 +568,16 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff continue; vh2 = (struct vxlanhdr *)(p->data + off_vx); - eh2 = (struct ethhdr *)(p->data + off_eth); - if (vh->vx_vni != vh2->vx_vni || compare_ether_header(eh, eh2)) { + if (vh->vx_vni != vh2->vx_vni) { NAPI_GRO_CB(p)->same_flow = 0; continue; } } - type = eh->h_proto; - - rcu_read_lock(); - ptype = gro_find_receive_by_type(type); - if (ptype == NULL) { - flush = 1; - goto out_unlock; - } - - skb_gro_pull(skb, sizeof(*eh)); /* pull inner eth header */ - skb_gro_postpull_rcsum(skb, eh, sizeof(*eh)); - pp = ptype->callbacks.gro_receive(head, skb); + skb_gro_pull(skb, sizeof(struct vxlanhdr)); + skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr)); + pp = eth_gro_receive(head, skb); -out_unlock: - rcu_read_unlock(); out: NAPI_GRO_CB(skb)->flush |= flush; @@ -612,24 +586,9 @@ out: static int vxlan_gro_complete(struct sk_buff *skb, int nhoff) { - struct ethhdr *eh; - struct packet_offload *ptype; - __be16 type; - int vxlan_len = sizeof(struct vxlanhdr) + sizeof(struct ethhdr); - int err = -ENOSYS; - udp_tunnel_gro_complete(skb, nhoff); - eh = (struct ethhdr *)(skb->data + nhoff + sizeof(struct vxlanhdr)); - type = eh->h_proto; - - rcu_read_lock(); - ptype = gro_find_complete_by_type(type); - if (ptype != NULL) - err = ptype->callbacks.gro_complete(skb, nhoff + vxlan_len); - - rcu_read_unlock(); - return err; + return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr)); } /* Notify netdevs that UDP port started listening */ -- cgit v1.2.1 From 7841d5d622f8fb537e401f5b172c42bb111daf4a Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Thu, 1 Jan 2015 17:49:55 +0100 Subject: net: ethernet: chelsio: cxgb3: mc5.c: Remove some unused functions Removes some functions that are not used anywhere: dbgi_rd_rsp3() dbgi_wr_addr3() This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb3/mc5.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb3/mc5.c b/drivers/net/ethernet/chelsio/cxgb3/mc5.c index e13b7fe9d082..338301b11518 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/mc5.c +++ b/drivers/net/ethernet/chelsio/cxgb3/mc5.c @@ -97,14 +97,6 @@ static int mc5_cmd_write(struct adapter *adapter, u32 cmd) F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1); } -static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2, - u32 v3) -{ - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1); - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2); - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3); -} - static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2, u32 v3) { @@ -113,14 +105,6 @@ static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2, t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3); } -static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2, - u32 *v3) -{ - *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0); - *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1); - *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2); -} - /* * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM * command cmd. The data to be written must have been set up by the caller. -- cgit v1.2.1 From 6af01a70f4f457dd6fdc556973e5429405bdf3aa Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Thu, 1 Jan 2015 18:01:26 +0100 Subject: net: fddi: skfp: smt.c: Remove unused function Remove the function smt_ifconfig() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: David S. Miller --- drivers/net/fddi/skfp/smt.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/fddi/skfp/smt.c b/drivers/net/fddi/skfp/smt.c index 9edada85ed02..cd78b7cacc75 100644 --- a/drivers/net/fddi/skfp/smt.c +++ b/drivers/net/fddi/skfp/smt.c @@ -1736,18 +1736,6 @@ char *addr_to_string(struct fddi_addr *addr) } #endif -#ifdef AM29K -int smt_ifconfig(int argc, char *argv[]) -{ - if (argc >= 2 && !strcmp(argv[0],"opt_bypass") && - !strcmp(argv[1],"yes")) { - smc->mib.fddiSMTBypassPresent = 1 ; - return 0; - } - return amdfddi_config(0, argc, argv); -} -#endif - /* * return static mac index */ -- cgit v1.2.1 From 3adc0becfec27cd582506b778df65d7c237e3215 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Fri, 2 Jan 2015 21:29:24 +0100 Subject: net: ethernet: cisco: enic: enic_dev: Remove some unused functions Removes some functions that are not used anywhere: enic_dev_enable2_done() enic_dev_enable2() enic_dev_deinit_done() enic_dev_init_prov2() enic_vnic_dev_deinit() This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_dev.c | 56 ------------------------------ drivers/net/ethernet/cisco/enic/enic_dev.h | 5 --- 2 files changed, 61 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.c b/drivers/net/ethernet/cisco/enic/enic_dev.c index 87ddc44b590e..f8d2a6a34282 100644 --- a/drivers/net/ethernet/cisco/enic/enic_dev.c +++ b/drivers/net/ethernet/cisco/enic/enic_dev.c @@ -177,40 +177,6 @@ int enic_dev_intr_coal_timer_info(struct enic *enic) return err; } -int enic_vnic_dev_deinit(struct enic *enic) -{ - int err; - - spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_deinit(enic->vdev); - spin_unlock_bh(&enic->devcmd_lock); - - return err; -} - -int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp) -{ - int err; - - spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_init_prov2(enic->vdev, - (u8 *)vp, vic_provinfo_size(vp)); - spin_unlock_bh(&enic->devcmd_lock); - - return err; -} - -int enic_dev_deinit_done(struct enic *enic, int *status) -{ - int err; - - spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_deinit_done(enic->vdev, status); - spin_unlock_bh(&enic->devcmd_lock); - - return err; -} - /* rtnl lock is held */ int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) { @@ -237,28 +203,6 @@ int enic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) return err; } -int enic_dev_enable2(struct enic *enic, int active) -{ - int err; - - spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_enable2(enic->vdev, active); - spin_unlock_bh(&enic->devcmd_lock); - - return err; -} - -int enic_dev_enable2_done(struct enic *enic, int *status) -{ - int err; - - spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_enable2_done(enic->vdev, status); - spin_unlock_bh(&enic->devcmd_lock); - - return err; -} - int enic_dev_status_to_errno(int devcmd_status) { switch (devcmd_status) { diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.h b/drivers/net/ethernet/cisco/enic/enic_dev.h index 10bb970b2f35..f5bb058b3f96 100644 --- a/drivers/net/ethernet/cisco/enic/enic_dev.h +++ b/drivers/net/ethernet/cisco/enic/enic_dev.h @@ -55,11 +55,6 @@ int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic); int enic_dev_enable(struct enic *enic); int enic_dev_disable(struct enic *enic); int enic_dev_intr_coal_timer_info(struct enic *enic); -int enic_vnic_dev_deinit(struct enic *enic); -int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp); -int enic_dev_deinit_done(struct enic *enic, int *status); -int enic_dev_enable2(struct enic *enic, int arg); -int enic_dev_enable2_done(struct enic *enic, int *status); int enic_dev_status_to_errno(int devcmd_status); #endif /* _ENIC_DEV_H_ */ -- cgit v1.2.1 From f28ba401dbd9e9fe63d9a7f9101638ca709185b2 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 2 Jan 2015 20:22:04 +0100 Subject: bnx2x: convert to CYCLECOUNTER_MASK macro. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 2c951326a85d..0758c8bef4ba 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -14610,7 +14610,7 @@ static void bnx2x_init_cyclecounter(struct bnx2x *bp) { memset(&bp->cyclecounter, 0, sizeof(bp->cyclecounter)); bp->cyclecounter.read = bnx2x_cyclecounter_read; - bp->cyclecounter.mask = CLOCKSOURCE_MASK(64); + bp->cyclecounter.mask = CYCLECOUNTER_MASK(64); bp->cyclecounter.shift = 1; bp->cyclecounter.mult = 1; } -- cgit v1.2.1 From 4d045b4c06b1f7d65d8e69d39821dcfaa783feea Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 2 Jan 2015 20:22:05 +0100 Subject: e1000e: convert to CYCLECOUNTER_MASK macro. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/e1000e/netdev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 2537d36a47cc..332a298e95b5 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -43,7 +43,6 @@ #include #include #include -#include #include "e1000.h" @@ -4190,7 +4189,7 @@ static int e1000_sw_init(struct e1000_adapter *adapter) /* Setup hardware time stamping cyclecounter */ if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) { adapter->cc.read = e1000e_cyclecounter_read; - adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mask = CYCLECOUNTER_MASK(64); adapter->cc.mult = 1; /* cc.shift set in e1000e_get_base_tininca() */ -- cgit v1.2.1 From b57c894040893da41085334d31f159df94c814b4 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 2 Jan 2015 20:22:06 +0100 Subject: igb: convert to CYCLECOUNTER_MASK macro. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igb/igb_ptp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 8baf3fd459e4..5e7a4e30a7b6 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "igb.h" @@ -766,7 +765,7 @@ void igb_ptp_init(struct igb_adapter *adapter) adapter->ptp_caps.settime = igb_ptp_settime_82576; adapter->ptp_caps.enable = igb_ptp_feature_enable; adapter->cc.read = igb_ptp_read_82576; - adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mask = CYCLECOUNTER_MASK(64); adapter->cc.mult = 1; adapter->cc.shift = IGB_82576_TSYNC_SHIFT; /* Dial the nominal frequency. */ @@ -786,7 +785,7 @@ void igb_ptp_init(struct igb_adapter *adapter) adapter->ptp_caps.settime = igb_ptp_settime_82576; adapter->ptp_caps.enable = igb_ptp_feature_enable; adapter->cc.read = igb_ptp_read_82580; - adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580); + adapter->cc.mask = CYCLECOUNTER_MASK(IGB_NBITS_82580); adapter->cc.mult = 1; adapter->cc.shift = 0; /* Enable the timer functions by clearing bit 31. */ -- cgit v1.2.1 From d312da293f787e1b19c57acb58e8c1b171c4a04a Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 2 Jan 2015 20:22:07 +0100 Subject: ixgbe: convert to CYCLECOUNTER_MASK macro. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 47c29eaaa140..79c00f57d3e7 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -793,7 +793,7 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter) memset(&adapter->cc, 0, sizeof(adapter->cc)); adapter->cc.read = ixgbe_ptp_read; - adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mask = CYCLECOUNTER_MASK(64); adapter->cc.shift = shift; adapter->cc.mult = 1; -- cgit v1.2.1 From d9f393734af52b7b09f02439164cc7182e17063c Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 2 Jan 2015 20:22:08 +0100 Subject: mlx4: include clocksource.h again This driver uses the function, clocksource_khz2mult, and so it really must include clocksource.h. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_clock.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c index e9cce4f72b24..90b5309cdb5c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c @@ -32,6 +32,7 @@ */ #include +#include #include "mlx4_en.h" -- cgit v1.2.1 From 3f255dcc970aede74463d863c9cf3cd9fb9146e3 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Sat, 3 Jan 2015 19:35:44 +0530 Subject: enic: reconfigure resources for kdump crash kernel When running in kdump kernel, reduce number of resources used by the driver. This will enable NIC to operate in low memory kdump kernel environment. Also change the driver version to .83 Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic.h | 2 +- drivers/net/ethernet/cisco/enic/enic_main.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index d2a103547c67..84b6a2b46aec 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -33,7 +33,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "2.1.1.67" +#define DRV_VERSION "2.1.1.83" #define DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 142c9b5509ae..9027fc1cc5f7 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -45,6 +45,7 @@ #ifdef CONFIG_NET_RX_BUSY_POLL #include #endif +#include #include "cq_enet_desc.h" #include "vnic_dev.h" @@ -2265,6 +2266,18 @@ static void enic_dev_deinit(struct enic *enic) enic_clear_intr_mode(enic); } +static void enic_kdump_kernel_config(struct enic *enic) +{ + if (is_kdump_kernel()) { + dev_info(enic_get_dev(enic), "Running from within kdump kernel. Using minimal resources\n"); + enic->rq_count = 1; + enic->wq_count = 1; + enic->config.rq_desc_count = ENIC_MIN_RQ_DESCS; + enic->config.wq_desc_count = ENIC_MIN_WQ_DESCS; + enic->config.mtu = min_t(u16, 1500, enic->config.mtu); + } +} + static int enic_dev_init(struct enic *enic) { struct device *dev = enic_get_dev(enic); @@ -2294,6 +2307,10 @@ static int enic_dev_init(struct enic *enic) enic_get_res_counts(enic); + /* modify resource count if we are in kdump_kernel + */ + enic_kdump_kernel_config(enic); + /* Set interrupt mode based on resource counts and system * capabilities */ -- cgit v1.2.1 From 3620af0efa89f167a4baf1acf9f6528d16ff45f4 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 3 Jan 2015 17:50:16 -0800 Subject: qlcnic: Fix dump_skb output Use normal facilities to avoid printing each byte on a separate line. Now emits at KERN_DEBUG instead of KERN_INFO. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 18e5de72e9b4..d166e534925d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "qlcnic.h" @@ -1465,14 +1466,14 @@ void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, static void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter) { - int i; - unsigned char *data = skb->data; - - pr_info(KERN_INFO "\n"); - for (i = 0; i < skb->len; i++) { - QLCDB(adapter, DRV, "%02x ", data[i]); - if ((i & 0x0f) == 8) - pr_info(KERN_INFO "\n"); + if (adapter->ahw->msg_enable & NETIF_MSG_DRV) { + char prefix[30]; + + scnprintf(prefix, sizeof(prefix), "%s: %s: ", + dev_name(&adapter->pdev->dev), __func__); + + print_hex_dump_debug(prefix, DUMP_PREFIX_NONE, 16, 1, + skb->data, skb->len, true); } } -- cgit v1.2.1 From 889ee2c7d70e1ae9fc9341d0e82676c519ffede2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:02:31 +0100 Subject: at86rf230: Constify struct regmap_config The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Signed-off-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 80632fc59756..7b051eacb7f1 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -427,7 +427,7 @@ at86rf230_reg_precious(struct device *dev, unsigned int reg) } } -static struct regmap_config at86rf230_regmap_spi_config = { +static const struct regmap_config at86rf230_regmap_spi_config = { .reg_bits = 8, .val_bits = 8, .write_flag_mask = CMD_REG | CMD_WRITE, -- cgit v1.2.1 From 5f07b3c51abe330c3dd702622c419efffb5757f0 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 5 Jan 2015 05:48:34 -0500 Subject: be2net: support TX batching using skb->xmit_more flag This patch uses skb->xmit_more flag to batch TX requests. TX is flushed either when xmit_more is false or there is no more space in the TXQ. Skyhawk-R and BEx chips require an even number of wrbs to be posted. So, when a batch of TX requests is accumulated, the last header wrb may need to be fixed with an extra dummy wrb. This patch refactors be_xmit() routine as a sequence of be_xmit_enqueue() and be_xmit_flush() calls. The Tx completion code is also updated to be able to unmap/free a batch of skbs rather than a single skb. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 4 +- drivers/net/ethernet/emulex/benet/be_ethtool.c | 2 - drivers/net/ethernet/emulex/benet/be_hw.h | 5 + drivers/net/ethernet/emulex/benet/be_main.c | 238 +++++++++++++------------ 4 files changed, 133 insertions(+), 116 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 712e7f8e1df7..9fa2569f56cb 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -243,7 +243,6 @@ struct be_tx_stats { u64 tx_bytes; u64 tx_pkts; u64 tx_reqs; - u64 tx_wrbs; u64 tx_compl; ulong tx_jiffies; u32 tx_stops; @@ -266,6 +265,9 @@ struct be_tx_obj { /* Remember the skbs that were transmitted */ struct sk_buff *sent_skb_list[TX_Q_LEN]; struct be_tx_stats stats; + u16 pend_wrb_cnt; /* Number of WRBs yet to be given to HW */ + u16 last_req_wrb_cnt; /* wrb cnt of the last req in the Q */ + u16 last_req_hdr; /* index of the last req's hdr-wrb */ } ____cacheline_aligned_in_smp; /* Struct to remember the pages posted for rx frags */ diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 73a500ccbf69..32c53bc0e07a 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -193,8 +193,6 @@ static const struct be_ethtool_stat et_tx_stats[] = { {DRVSTAT_TX_INFO(tx_pkts)}, /* Number of skbs queued for trasmission by the driver */ {DRVSTAT_TX_INFO(tx_reqs)}, - /* Number of TX work request blocks DMAed to HW */ - {DRVSTAT_TX_INFO(tx_wrbs)}, /* Number of times the TX queue was stopped due to lack * of spaces in the TXQ. */ diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index 295ee0835ba0..6d7b3a4d3cff 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -311,6 +311,11 @@ struct amap_eth_hdr_wrb { u8 vlan_tag[16]; } __packed; +#define TX_HDR_WRB_COMPL 1 /* word 2 */ +#define TX_HDR_WRB_EVT (1 << 1) /* word 2 */ +#define TX_HDR_WRB_NUM_SHIFT 13 /* word 2: bits 13:17 */ +#define TX_HDR_WRB_NUM_MASK 0x1F /* word 2: bits 13:17 */ + struct be_eth_hdr_wrb { u32 dw[4]; }; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 41a0a5498da7..37a26b0b7e33 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -662,41 +662,22 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status) netif_carrier_off(netdev); } -static void be_tx_stats_update(struct be_tx_obj *txo, - u32 wrb_cnt, u32 copied, u32 gso_segs, - bool stopped) +static void be_tx_stats_update(struct be_tx_obj *txo, struct sk_buff *skb) { struct be_tx_stats *stats = tx_stats(txo); u64_stats_update_begin(&stats->sync); stats->tx_reqs++; - stats->tx_wrbs += wrb_cnt; - stats->tx_bytes += copied; - stats->tx_pkts += (gso_segs ? gso_segs : 1); - if (stopped) - stats->tx_stops++; + stats->tx_bytes += skb->len; + stats->tx_pkts += (skb_shinfo(skb)->gso_segs ? : 1); u64_stats_update_end(&stats->sync); } -/* Determine number of WRB entries needed to xmit data in an skb */ -static u32 wrb_cnt_for_skb(struct be_adapter *adapter, struct sk_buff *skb, - bool *dummy) +/* Returns number of WRBs needed for the skb */ +static u32 skb_wrb_cnt(struct sk_buff *skb) { - int cnt = (skb->len > skb->data_len); - - cnt += skb_shinfo(skb)->nr_frags; - - /* to account for hdr wrb */ - cnt++; - if (lancer_chip(adapter) || !(cnt & 1)) { - *dummy = false; - } else { - /* add a dummy to make it an even num */ - cnt++; - *dummy = true; - } - BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT); - return cnt; + /* +1 for the header wrb */ + return 1 + (skb_headlen(skb) ? 1 : 0) + skb_shinfo(skb)->nr_frags; } static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len) @@ -770,11 +751,14 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag); } - /* To skip HW VLAN tagging: evt = 1, compl = 0 */ - SET_TX_WRB_HDR_BITS(complete, hdr, !skip_hw_vlan); - SET_TX_WRB_HDR_BITS(event, hdr, 1); SET_TX_WRB_HDR_BITS(num_wrb, hdr, wrb_cnt); SET_TX_WRB_HDR_BITS(len, hdr, len); + + /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0 + * When this hack is not needed, the evt bit is set while ringing DB + */ + if (skip_hw_vlan) + SET_TX_WRB_HDR_BITS(event, hdr, 1); } static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, @@ -794,22 +778,24 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, } } -static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, - struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb, - bool skip_hw_vlan) +/* Returns the number of WRBs used up by the skb */ +static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, + struct sk_buff *skb, bool skip_hw_vlan) { - dma_addr_t busaddr; - int i, copied = 0; + u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb); struct device *dev = &adapter->pdev->dev; - struct sk_buff *first_skb = skb; - struct be_eth_wrb *wrb; + struct be_queue_info *txq = &txo->q; struct be_eth_hdr_wrb *hdr; bool map_single = false; - u16 map_head; + struct be_eth_wrb *wrb; + dma_addr_t busaddr; + u16 head = txq->head; hdr = queue_head_node(txq); + wrb_fill_hdr(adapter, hdr, skb, wrb_cnt, skb->len, skip_hw_vlan); + be_dws_cpu_to_le(hdr, sizeof(*hdr)); + queue_head_inc(txq); - map_head = txq->head; if (skb->len > skb->data_len) { int len = skb_headlen(skb); @@ -839,19 +825,23 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, copied += skb_frag_size(frag); } - if (dummy_wrb) { - wrb = queue_head_node(txq); - wrb_fill(wrb, 0, 0); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - } + BUG_ON(txo->sent_skb_list[head]); + txo->sent_skb_list[head] = skb; + txo->last_req_hdr = head; + atomic_add(wrb_cnt, &txq->used); + txo->last_req_wrb_cnt = wrb_cnt; + txo->pend_wrb_cnt += wrb_cnt; - wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied, skip_hw_vlan); - be_dws_cpu_to_le(hdr, sizeof(*hdr)); + be_tx_stats_update(txo, skb); + return wrb_cnt; - return copied; dma_err: - txq->head = map_head; + /* Bring the queue back to the state it was in before this + * routine was invoked. + */ + txq->head = head; + /* skip the first wrb (hdr); it's not mapped */ + queue_head_inc(txq); while (copied) { wrb = queue_head_node(txq); unmap_tx_frag(dev, wrb, map_single); @@ -860,6 +850,7 @@ dma_err: adapter->drv_stats.dma_map_errors++; queue_head_inc(txq); } + txq->head = head; return 0; } @@ -1030,52 +1021,64 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, return skb; } +static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo) +{ + struct be_queue_info *txq = &txo->q; + struct be_eth_hdr_wrb *hdr = queue_index_node(txq, txo->last_req_hdr); + + /* Mark the last request eventable if it hasn't been marked already */ + if (!(hdr->dw[2] & cpu_to_le32(TX_HDR_WRB_EVT))) + hdr->dw[2] |= cpu_to_le32(TX_HDR_WRB_EVT | TX_HDR_WRB_COMPL); + + /* compose a dummy wrb if there are odd set of wrbs to notify */ + if (!lancer_chip(adapter) && (txo->pend_wrb_cnt & 1)) { + wrb_fill(queue_head_node(txq), 0, 0); + queue_head_inc(txq); + atomic_inc(&txq->used); + txo->pend_wrb_cnt++; + hdr->dw[2] &= ~cpu_to_le32(TX_HDR_WRB_NUM_MASK << + TX_HDR_WRB_NUM_SHIFT); + hdr->dw[2] |= cpu_to_le32((txo->last_req_wrb_cnt + 1) << + TX_HDR_WRB_NUM_SHIFT); + } + be_txq_notify(adapter, txo, txo->pend_wrb_cnt); + txo->pend_wrb_cnt = 0; +} + static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) { + bool skip_hw_vlan = false, flush = !skb->xmit_more; struct be_adapter *adapter = netdev_priv(netdev); - struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)]; + u16 q_idx = skb_get_queue_mapping(skb); + struct be_tx_obj *txo = &adapter->tx_obj[q_idx]; struct be_queue_info *txq = &txo->q; - bool dummy_wrb, stopped = false; - u32 wrb_cnt = 0, copied = 0; - bool skip_hw_vlan = false; - u32 start = txq->head; + u16 wrb_cnt; skb = be_xmit_workarounds(adapter, skb, &skip_hw_vlan); - if (!skb) { - tx_stats(txo)->tx_drv_drops++; - return NETDEV_TX_OK; - } - - wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); + if (unlikely(!skb)) + goto drop; - copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb, - skip_hw_vlan); - if (copied) { - int gso_segs = skb_shinfo(skb)->gso_segs; + wrb_cnt = be_xmit_enqueue(adapter, txo, skb, skip_hw_vlan); + if (unlikely(!wrb_cnt)) { + dev_kfree_skb_any(skb); + goto drop; + } - /* record the sent skb in the sent_skb table */ - BUG_ON(txo->sent_skb_list[start]); - txo->sent_skb_list[start] = skb; + if ((atomic_read(&txq->used) + BE_MAX_TX_FRAG_COUNT) >= txq->len) { + netif_stop_subqueue(netdev, q_idx); + tx_stats(txo)->tx_stops++; + } - /* Ensure txq has space for the next skb; Else stop the queue - * *BEFORE* ringing the tx doorbell, so that we serialze the - * tx compls of the current transmit which'll wake up the queue - */ - atomic_add(wrb_cnt, &txq->used); - if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= - txq->len) { - netif_stop_subqueue(netdev, skb_get_queue_mapping(skb)); - stopped = true; - } + if (flush || __netif_subqueue_stopped(netdev, q_idx)) + be_xmit_flush(adapter, txo); - be_txq_notify(adapter, txo, wrb_cnt); + return NETDEV_TX_OK; +drop: + tx_stats(txo)->tx_drv_drops++; + /* Flush the already enqueued tx requests */ + if (flush && txo->pend_wrb_cnt) + be_xmit_flush(adapter, txo); - be_tx_stats_update(txo, wrb_cnt, copied, gso_segs, stopped); - } else { - txq->head = start; - tx_stats(txo)->tx_drv_drops++; - dev_kfree_skb_any(skb); - } return NETDEV_TX_OK; } @@ -1959,32 +1962,34 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) static u16 be_tx_compl_process(struct be_adapter *adapter, struct be_tx_obj *txo, u16 last_index) { + struct sk_buff **sent_skbs = txo->sent_skb_list; struct be_queue_info *txq = &txo->q; + u16 frag_index, num_wrbs = 0; + struct sk_buff *skb = NULL; + bool unmap_skb_hdr = false; struct be_eth_wrb *wrb; - struct sk_buff **sent_skbs = txo->sent_skb_list; - struct sk_buff *sent_skb; - u16 cur_index, num_wrbs = 1; /* account for hdr wrb */ - bool unmap_skb_hdr = true; - - sent_skb = sent_skbs[txq->tail]; - BUG_ON(!sent_skb); - sent_skbs[txq->tail] = NULL; - - /* skip header wrb */ - queue_tail_inc(txq); do { - cur_index = txq->tail; + if (sent_skbs[txq->tail]) { + /* Free skb from prev req */ + if (skb) + dev_consume_skb_any(skb); + skb = sent_skbs[txq->tail]; + sent_skbs[txq->tail] = NULL; + queue_tail_inc(txq); /* skip hdr wrb */ + num_wrbs++; + unmap_skb_hdr = true; + } wrb = queue_tail_node(txq); + frag_index = txq->tail; unmap_tx_frag(&adapter->pdev->dev, wrb, - (unmap_skb_hdr && skb_headlen(sent_skb))); + (unmap_skb_hdr && skb_headlen(skb))); unmap_skb_hdr = false; - - num_wrbs++; queue_tail_inc(txq); - } while (cur_index != last_index); + num_wrbs++; + } while (frag_index != last_index); + dev_consume_skb_any(skb); - dev_consume_skb_any(sent_skb); return num_wrbs; } @@ -2068,12 +2073,11 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo) static void be_tx_compl_clean(struct be_adapter *adapter) { + u16 end_idx, notified_idx, cmpl = 0, timeo = 0, num_wrbs = 0; + struct device *dev = &adapter->pdev->dev; struct be_tx_obj *txo; struct be_queue_info *txq; struct be_eth_tx_compl *txcp; - u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0; - struct sk_buff *sent_skb; - bool dummy_wrb; int i, pending_txqs; /* Stop polling for compls when HW has been silent for 10ms */ @@ -2095,7 +2099,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter) atomic_sub(num_wrbs, &txq->used); timeo = 0; } - if (atomic_read(&txq->used) == 0) + if (atomic_read(&txq->used) == txo->pend_wrb_cnt) pending_txqs--; } @@ -2105,21 +2109,29 @@ static void be_tx_compl_clean(struct be_adapter *adapter) mdelay(1); } while (true); + /* Free enqueued TX that was never notified to HW */ for_all_tx_queues(adapter, txo, i) { txq = &txo->q; - if (atomic_read(&txq->used)) - dev_err(&adapter->pdev->dev, "%d pending tx-compls\n", - atomic_read(&txq->used)); - /* free posted tx for which compls will never arrive */ - while (atomic_read(&txq->used)) { - sent_skb = txo->sent_skb_list[txq->tail]; + if (atomic_read(&txq->used)) { + dev_info(dev, "txq%d: cleaning %d pending tx-wrbs\n", + i, atomic_read(&txq->used)); + notified_idx = txq->tail; end_idx = txq->tail; - num_wrbs = wrb_cnt_for_skb(adapter, sent_skb, - &dummy_wrb); - index_adv(&end_idx, num_wrbs - 1, txq->len); + index_adv(&end_idx, atomic_read(&txq->used) - 1, + txq->len); + /* Use the tx-compl process logic to handle requests + * that were not sent to the HW. + */ num_wrbs = be_tx_compl_process(adapter, txo, end_idx); atomic_sub(num_wrbs, &txq->used); + BUG_ON(atomic_read(&txq->used)); + txo->pend_wrb_cnt = 0; + /* Since hw was never notified of these requests, + * reset TXQ indices + */ + txq->head = notified_idx; + txq->tail = notified_idx; } } } -- cgit v1.2.1 From f612b815d75b054ec06c8be260409a7ab271c253 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 5 Jan 2015 16:30:43 +0530 Subject: RDMA/cxgb4/cxgb4vf/csiostor: Cleanup SGE register defines This patch cleanups all SGE related macros/register defines that are defined in t4_regs.h and the affected files. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 76 ++-- drivers/net/ethernet/chelsio/cxgb4/sge.c | 96 ++-- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 118 ++--- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 498 ++++++++++++--------- drivers/net/ethernet/chelsio/cxgb4/t4_values.h | 81 ++++ .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 24 +- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 47 +- drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 17 +- 8 files changed, 566 insertions(+), 391 deletions(-) create mode 100644 drivers/net/ethernet/chelsio/cxgb4/t4_values.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index ccf3436024bc..5e0d57a7b3b6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -66,6 +66,7 @@ #include "cxgb4.h" #include "t4_regs.h" +#include "t4_values.h" #include "t4_msg.h" #include "t4fw_api.h" #include "cxgb4_dcb.h" @@ -1050,9 +1051,9 @@ static void enable_rx(struct adapter *adap) if (q->handler) napi_enable(&q->napi); /* 0-increment GTS to start the timer and enable interrupts */ - t4_write_reg(adap, MYPF_REG(SGE_PF_GTS), - SEINTARM(q->intr_params) | - INGRESSQID(q->cntxt_id)); + t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), + SEINTARM_V(q->intr_params) | + INGRESSQID_V(q->cntxt_id)); } } @@ -3702,14 +3703,20 @@ int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, if (pidx != hw_pidx) { u16 delta; + u32 val; if (pidx >= hw_pidx) delta = pidx - hw_pidx; else delta = size - hw_pidx + pidx; + + if (is_t4(adap->params.chip)) + val = PIDX_V(delta); + else + val = PIDX_T5_V(delta); wmb(); - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - QID(qid) | PIDX(delta)); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), + QID_V(qid) | val); } out: return ret; @@ -3721,8 +3728,8 @@ void cxgb4_disable_db_coalescing(struct net_device *dev) struct adapter *adap; adap = netdev2adap(dev); - t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_NOCOALESCE, - F_NOCOALESCE); + t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, NOCOALESCE_F, + NOCOALESCE_F); } EXPORT_SYMBOL(cxgb4_disable_db_coalescing); @@ -3731,7 +3738,7 @@ void cxgb4_enable_db_coalescing(struct net_device *dev) struct adapter *adap; adap = netdev2adap(dev); - t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_NOCOALESCE, 0); + t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, NOCOALESCE_F, 0); } EXPORT_SYMBOL(cxgb4_enable_db_coalescing); @@ -3809,8 +3816,8 @@ u64 cxgb4_read_sge_timestamp(struct net_device *dev) struct adapter *adap; adap = netdev2adap(dev); - lo = t4_read_reg(adap, SGE_TIMESTAMP_LO); - hi = GET_TSVAL(t4_read_reg(adap, SGE_TIMESTAMP_HI)); + lo = t4_read_reg(adap, SGE_TIMESTAMP_LO_A); + hi = TSVAL_G(t4_read_reg(adap, SGE_TIMESTAMP_HI_A)); return ((u64)hi << 32) | (u64)lo; } @@ -3904,8 +3911,8 @@ static void enable_txq_db(struct adapter *adap, struct sge_txq *q) * are committed before we tell HW about them. */ wmb(); - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - QID(q->cntxt_id) | PIDX(q->db_pidx_inc)); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), + QID_V(q->cntxt_id) | PIDX_V(q->db_pidx_inc)); q->db_pidx_inc = 0; } q->db_disabled = 0; @@ -3952,9 +3959,9 @@ static void process_db_full(struct work_struct *work) drain_db_fifo(adap, dbfifo_drain_delay); enable_dbs(adap); notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY); - t4_set_reg_field(adap, SGE_INT_ENABLE3, - DBFIFO_HP_INT | DBFIFO_LP_INT, - DBFIFO_HP_INT | DBFIFO_LP_INT); + t4_set_reg_field(adap, SGE_INT_ENABLE3_A, + DBFIFO_HP_INT_F | DBFIFO_LP_INT_F, + DBFIFO_HP_INT_F | DBFIFO_LP_INT_F); } static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q) @@ -3968,14 +3975,20 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q) goto out; if (q->db_pidx != hw_pidx) { u16 delta; + u32 val; if (q->db_pidx >= hw_pidx) delta = q->db_pidx - hw_pidx; else delta = q->size - hw_pidx + q->db_pidx; + + if (is_t4(adap->params.chip)) + val = PIDX_V(delta); + else + val = PIDX_T5_V(delta); wmb(); - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - QID(q->cntxt_id) | PIDX(delta)); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), + QID_V(q->cntxt_id) | val); } out: q->db_disabled = 0; @@ -4024,7 +4037,7 @@ static void process_db_drop(struct work_struct *work) dev_err(adap->pdev_dev, "doorbell drop recovery: " "qid=%d, pidx_inc=%d\n", qid, pidx_inc); else - writel(PIDX_T5(pidx_inc) | QID(bar2_qid), + writel(PIDX_T5_V(pidx_inc) | QID_V(bar2_qid), adap->bar2 + bar2_qoffset + SGE_UDB_KDOORBELL); /* Re-enable BAR2 WC */ @@ -4039,8 +4052,8 @@ void t4_db_full(struct adapter *adap) if (is_t4(adap->params.chip)) { disable_dbs(adap); notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); - t4_set_reg_field(adap, SGE_INT_ENABLE3, - DBFIFO_HP_INT | DBFIFO_LP_INT, 0); + t4_set_reg_field(adap, SGE_INT_ENABLE3_A, + DBFIFO_HP_INT_F | DBFIFO_LP_INT_F, 0); queue_work(adap->workq, &adap->db_full_task); } } @@ -4089,8 +4102,8 @@ static void uld_attach(struct adapter *adap, unsigned int uld) /* MODQ_REQ_MAP sets queues 0-3 to chan 0-3 */ for (i = 0; i < NCHAN; i++) lli.tx_modq[i] = i; - lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS); - lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL); + lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS_A); + lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL_A); lli.fw_vers = adap->params.fw_vers; lli.dbfifo_int_thresh = dbfifo_int_thresh; lli.sge_ingpadboundary = adap->sge.fl_align; @@ -4783,7 +4796,7 @@ static const struct net_device_ops cxgb4_netdev_ops = { void t4_fatal_err(struct adapter *adap) { - t4_set_reg_field(adap, SGE_CONTROL, GLOBALENABLE, 0); + t4_set_reg_field(adap, SGE_CONTROL_A, GLOBALENABLE_F, 0); t4_intr_disable(adap); dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n"); } @@ -5013,9 +5026,9 @@ static int adap_init0_tweaks(struct adapter *adapter) rx_dma_offset); rx_dma_offset = 2; } - t4_set_reg_field(adapter, SGE_CONTROL, - PKTSHIFT_MASK, - PKTSHIFT(rx_dma_offset)); + t4_set_reg_field(adapter, SGE_CONTROL_A, + PKTSHIFT_V(PKTSHIFT_M), + PKTSHIFT_V(rx_dma_offset)); /* * Don't include the "IP Pseudo Header" in CPL_RX_PKT checksums: Linux @@ -5332,8 +5345,7 @@ static int adap_init0_no_config(struct adapter *adapter, int reset) s->timer_val[SGE_NTIMERS - 1] = MAX_SGE_TIMERVAL; s->counter_val[0] = 1; for (i = 1; i < SGE_NCOUNTERS; i++) - s->counter_val[i] = min(intr_cnt[i - 1], - THRESHOLD_0_GET(THRESHOLD_0_MASK)); + s->counter_val[i] = min(intr_cnt[i - 1], THRESHOLD_0_M); t4_sge_init(adapter); #ifdef CONFIG_PCI_IOV @@ -6467,9 +6479,11 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!is_t4(adapter->params.chip)) { - s_qpp = QUEUESPERPAGEPF1 * adapter->fn; - qpp = 1 << QUEUESPERPAGEPF0_GET(t4_read_reg(adapter, - SGE_EGRESS_QUEUES_PER_PAGE_PF) >> s_qpp); + s_qpp = (QUEUESPERPAGEPF0_S + + (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * + adapter->fn); + qpp = 1 << QUEUESPERPAGEPF0_G(t4_read_reg(adapter, + SGE_EGRESS_QUEUES_PER_PAGE_PF_A) >> s_qpp); num_seg = PAGE_SIZE / SEGMENT_SIZE; /* Each segment size is 128B. Write coalescing is enabled only diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index ebf935a1e352..4449fc7ec14e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -45,6 +45,7 @@ #include #include "cxgb4.h" #include "t4_regs.h" +#include "t4_values.h" #include "t4_msg.h" #include "t4fw_api.h" @@ -521,10 +522,12 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) { u32 val; if (q->pend_cred >= 8) { - val = PIDX(q->pend_cred / 8); - if (!is_t4(adap->params.chip)) - val |= DBTYPE(1); - val |= DBPRIO(1); + if (is_t4(adap->params.chip)) + val = PIDX_V(q->pend_cred / 8); + else + val = PIDX_T5_V(q->pend_cred / 8) | + DBTYPE_F; + val |= DBPRIO_F; wmb(); /* If we don't have access to the new User Doorbell (T5+), use @@ -532,10 +535,10 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) * mechanism. */ if (unlikely(q->bar2_addr == NULL)) { - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - val | QID(q->cntxt_id)); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), + val | QID_V(q->cntxt_id)); } else { - writel(val | QID(q->bar2_qid), + writel(val | QID_V(q->bar2_qid), q->bar2_addr + SGE_UDB_KDOORBELL); /* This Write memory Barrier will force the write to @@ -884,7 +887,7 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) * doorbell mechanism; otherwise use the new BAR2 mechanism. */ if (unlikely(q->bar2_addr == NULL)) { - u32 val = PIDX(n); + u32 val = PIDX_V(n); unsigned long flags; /* For T4 we need to participate in the Doorbell Recovery @@ -892,14 +895,14 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) */ spin_lock_irqsave(&q->db_lock, flags); if (!q->db_disabled) - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - QID(q->cntxt_id) | val); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), + QID_V(q->cntxt_id) | val); else q->db_pidx_inc += n; q->db_pidx = q->pidx; spin_unlock_irqrestore(&q->db_lock, flags); } else { - u32 val = PIDX_T5(n); + u32 val = PIDX_T5_V(n); /* T4 and later chips share the same PIDX field offset within * the doorbell, but T5 and later shrank the field in order to @@ -907,7 +910,7 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) * large in the first place (14 bits) so we just use the T5 * and later limits and warn if a Queue ID is too large. */ - WARN_ON(val & DBPRIO(1)); + WARN_ON(val & DBPRIO_F); /* If we're only writing a single TX Descriptor and we can use * Inferred QID registers, we can use the Write Combining @@ -923,7 +926,7 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) (q->bar2_addr + SGE_UDB_WCDOORBELL), wr); } else { - writel(val | QID(q->bar2_qid), + writel(val | QID_V(q->bar2_qid), q->bar2_addr + SGE_UDB_KDOORBELL); } @@ -2001,16 +2004,16 @@ static int napi_rx_handler(struct napi_struct *napi, int budget) } else params = QINTR_TIMER_IDX(7); - val = CIDXINC(work_done) | SEINTARM(params); + val = CIDXINC_V(work_done) | SEINTARM_V(params); /* If we don't have access to the new User GTS (T5+), use the old * doorbell mechanism; otherwise use the new BAR2 mechanism. */ if (unlikely(q->bar2_addr == NULL)) { - t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS), - val | INGRESSQID((u32)q->cntxt_id)); + t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS_A), + val | INGRESSQID_V((u32)q->cntxt_id)); } else { - writel(val | INGRESSQID(q->bar2_qid), + writel(val | INGRESSQID_V(q->bar2_qid), q->bar2_addr + SGE_UDB_GTS); wmb(); } @@ -2056,16 +2059,16 @@ static unsigned int process_intrq(struct adapter *adap) rspq_next(q); } - val = CIDXINC(credits) | SEINTARM(q->intr_params); + val = CIDXINC_V(credits) | SEINTARM_V(q->intr_params); /* If we don't have access to the new User GTS (T5+), use the old * doorbell mechanism; otherwise use the new BAR2 mechanism. */ if (unlikely(q->bar2_addr == NULL)) { - t4_write_reg(adap, MYPF_REG(SGE_PF_GTS), - val | INGRESSQID(q->cntxt_id)); + t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), + val | INGRESSQID_V(q->cntxt_id)); } else { - writel(val | INGRESSQID(q->bar2_qid), + writel(val | INGRESSQID_V(q->bar2_qid), q->bar2_addr + SGE_UDB_GTS); wmb(); } @@ -2770,8 +2773,8 @@ static int t4_sge_init_soft(struct adapter *adap) * process_responses() and that only packet data is going to the * Free Lists. */ - if ((t4_read_reg(adap, SGE_CONTROL) & RXPKTCPLMODE_MASK) != - RXPKTCPLMODE(X_RXPKTCPLMODE_SPLIT)) { + if ((t4_read_reg(adap, SGE_CONTROL_A) & RXPKTCPLMODE_F) != + RXPKTCPLMODE_V(RXPKTCPLMODE_SPLIT_X)) { dev_err(adap->pdev_dev, "bad SGE CPL MODE\n"); return -EINVAL; } @@ -2785,7 +2788,7 @@ static int t4_sge_init_soft(struct adapter *adap) * XXX meet our needs! */ #define READ_FL_BUF(x) \ - t4_read_reg(adap, SGE_FL_BUFFER_SIZE0+(x)*sizeof(u32)) + t4_read_reg(adap, SGE_FL_BUFFER_SIZE0_A+(x)*sizeof(u32)) fl_small_pg = READ_FL_BUF(RX_SMALL_PG_BUF); fl_large_pg = READ_FL_BUF(RX_LARGE_PG_BUF); @@ -2839,11 +2842,11 @@ static int t4_sge_init_soft(struct adapter *adap) s->timer_val[5] = core_ticks_to_us(adap, TIMERVALUE5_GET(timer_value_4_and_5)); - ingress_rx_threshold = t4_read_reg(adap, SGE_INGRESS_RX_THRESHOLD); - s->counter_val[0] = THRESHOLD_0_GET(ingress_rx_threshold); - s->counter_val[1] = THRESHOLD_1_GET(ingress_rx_threshold); - s->counter_val[2] = THRESHOLD_2_GET(ingress_rx_threshold); - s->counter_val[3] = THRESHOLD_3_GET(ingress_rx_threshold); + ingress_rx_threshold = t4_read_reg(adap, SGE_INGRESS_RX_THRESHOLD_A); + s->counter_val[0] = THRESHOLD_0_G(ingress_rx_threshold); + s->counter_val[1] = THRESHOLD_1_G(ingress_rx_threshold); + s->counter_val[2] = THRESHOLD_2_G(ingress_rx_threshold); + s->counter_val[3] = THRESHOLD_3_G(ingress_rx_threshold); return 0; } @@ -2856,8 +2859,7 @@ static int t4_sge_init_hard(struct adapter *adap) * Set up our basic SGE mode to deliver CPL messages to our Ingress * Queue and Packet Date to the Free List. */ - t4_set_reg_field(adap, SGE_CONTROL, RXPKTCPLMODE_MASK, - RXPKTCPLMODE_MASK); + t4_set_reg_field(adap, SGE_CONTROL_A, RXPKTCPLMODE_F, RXPKTCPLMODE_F); /* * Set up to drop DOORBELL writes when the DOORBELL FIFO overflows @@ -2887,22 +2889,22 @@ static int t4_sge_init_hard(struct adapter *adap) s->fl_pg_order = FL_PG_ORDER; if (s->fl_pg_order) t4_write_reg(adap, - SGE_FL_BUFFER_SIZE0+RX_LARGE_PG_BUF*sizeof(u32), + SGE_FL_BUFFER_SIZE0_A+RX_LARGE_PG_BUF*sizeof(u32), PAGE_SIZE << FL_PG_ORDER); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE0+RX_SMALL_MTU_BUF*sizeof(u32), + t4_write_reg(adap, SGE_FL_BUFFER_SIZE0_A+RX_SMALL_MTU_BUF*sizeof(u32), FL_MTU_SMALL_BUFSIZE(adap)); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE0+RX_LARGE_MTU_BUF*sizeof(u32), + t4_write_reg(adap, SGE_FL_BUFFER_SIZE0_A+RX_LARGE_MTU_BUF*sizeof(u32), FL_MTU_LARGE_BUFSIZE(adap)); /* * Note that the SGE Ingress Packet Count Interrupt Threshold and * Timer Holdoff values must be supplied by our caller. */ - t4_write_reg(adap, SGE_INGRESS_RX_THRESHOLD, - THRESHOLD_0(s->counter_val[0]) | - THRESHOLD_1(s->counter_val[1]) | - THRESHOLD_2(s->counter_val[2]) | - THRESHOLD_3(s->counter_val[3])); + t4_write_reg(adap, SGE_INGRESS_RX_THRESHOLD_A, + THRESHOLD_0_V(s->counter_val[0]) | + THRESHOLD_1_V(s->counter_val[1]) | + THRESHOLD_2_V(s->counter_val[2]) | + THRESHOLD_3_V(s->counter_val[3])); t4_write_reg(adap, SGE_TIMER_VALUE_0_AND_1, TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[0])) | TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[1]))); @@ -2927,9 +2929,9 @@ int t4_sge_init(struct adapter *adap) * Ingress Padding Boundary and Egress Status Page Size are set up by * t4_fixup_host_params(). */ - sge_control = t4_read_reg(adap, SGE_CONTROL); - s->pktshift = PKTSHIFT_GET(sge_control); - s->stat_len = (sge_control & EGRSTATUSPAGESIZE_MASK) ? 128 : 64; + sge_control = t4_read_reg(adap, SGE_CONTROL_A); + s->pktshift = PKTSHIFT_G(sge_control); + s->stat_len = (sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64; /* T4 uses a single control field to specify both the PCIe Padding and * Packing Boundary. T5 introduced the ability to specify these @@ -2937,8 +2939,8 @@ int t4_sge_init(struct adapter *adap) * within Packed Buffer Mode is the maximum of these two * specifications. */ - ingpadboundary = 1 << (INGPADBOUNDARY_GET(sge_control) + - X_INGPADBOUNDARY_SHIFT); + ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_control) + + INGPADBOUNDARY_SHIFT_X); if (is_t4(adap->params.chip)) { s->fl_align = ingpadboundary; } else { @@ -2975,11 +2977,11 @@ int t4_sge_init(struct adapter *adap) * buffers and a new field which only applies to Packed Mode Free List * buffers. */ - sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL); + sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL_A); if (is_t4(adap->params.chip)) - egress_threshold = EGRTHRESHOLD_GET(sge_conm_ctrl); + egress_threshold = EGRTHRESHOLD_G(sge_conm_ctrl); else - egress_threshold = EGRTHRESHOLDPACKING_GET(sge_conm_ctrl); + egress_threshold = EGRTHRESHOLDPACKING_G(sge_conm_ctrl); s->fl_starve_thres = 2*egress_threshold + 1; setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index c132d9030729..ac00cab0052b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -35,6 +35,7 @@ #include #include "cxgb4.h" #include "t4_regs.h" +#include "t4_values.h" #include "t4fw_api.h" /** @@ -1499,43 +1500,43 @@ static void sge_intr_handler(struct adapter *adapter) u64 v; static const struct intr_info sge_intr_info[] = { - { ERR_CPL_EXCEED_IQE_SIZE, + { ERR_CPL_EXCEED_IQE_SIZE_F, "SGE received CPL exceeding IQE size", -1, 1 }, - { ERR_INVALID_CIDX_INC, + { ERR_INVALID_CIDX_INC_F, "SGE GTS CIDX increment too large", -1, 0 }, - { ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, - { DBFIFO_LP_INT, NULL, -1, 0, t4_db_full }, - { DBFIFO_HP_INT, NULL, -1, 0, t4_db_full }, - { ERR_DROPPED_DB, NULL, -1, 0, t4_db_dropped }, - { ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0, + { ERR_CPL_OPCODE_0_F, "SGE received 0-length CPL", -1, 0 }, + { DBFIFO_LP_INT_F, NULL, -1, 0, t4_db_full }, + { DBFIFO_HP_INT_F, NULL, -1, 0, t4_db_full }, + { ERR_DROPPED_DB_F, NULL, -1, 0, t4_db_dropped }, + { ERR_DATA_CPL_ON_HIGH_QID1_F | ERR_DATA_CPL_ON_HIGH_QID0_F, "SGE IQID > 1023 received CPL for FL", -1, 0 }, - { ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1, + { ERR_BAD_DB_PIDX3_F, "SGE DBP 3 pidx increment too large", -1, 0 }, - { ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1, + { ERR_BAD_DB_PIDX2_F, "SGE DBP 2 pidx increment too large", -1, 0 }, - { ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1, + { ERR_BAD_DB_PIDX1_F, "SGE DBP 1 pidx increment too large", -1, 0 }, - { ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1, + { ERR_BAD_DB_PIDX0_F, "SGE DBP 0 pidx increment too large", -1, 0 }, - { ERR_ING_CTXT_PRIO, + { ERR_ING_CTXT_PRIO_F, "SGE too many priority ingress contexts", -1, 0 }, - { ERR_EGR_CTXT_PRIO, + { ERR_EGR_CTXT_PRIO_F, "SGE too many priority egress contexts", -1, 0 }, - { INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 }, - { EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 }, + { INGRESS_SIZE_ERR_F, "SGE illegal ingress QID", -1, 0 }, + { EGRESS_SIZE_ERR_F, "SGE illegal egress QID", -1, 0 }, { 0 } }; - v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1) | - ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32); + v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1_A) | + ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2_A) << 32); if (v) { dev_alert(adapter->pdev_dev, "SGE parity error (%#llx)\n", (unsigned long long)v); - t4_write_reg(adapter, SGE_INT_CAUSE1, v); - t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32); + t4_write_reg(adapter, SGE_INT_CAUSE1_A, v); + t4_write_reg(adapter, SGE_INT_CAUSE2_A, v >> 32); } - if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3, sge_intr_info) || + if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, sge_intr_info) || v != 0) t4_fatal_err(adapter); } @@ -2025,15 +2026,15 @@ void t4_intr_enable(struct adapter *adapter) { u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); - t4_write_reg(adapter, SGE_INT_ENABLE3, ERR_CPL_EXCEED_IQE_SIZE | - ERR_INVALID_CIDX_INC | ERR_CPL_OPCODE_0 | - ERR_DROPPED_DB | ERR_DATA_CPL_ON_HIGH_QID1 | - ERR_DATA_CPL_ON_HIGH_QID0 | ERR_BAD_DB_PIDX3 | - ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 | - ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO | - ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR | - DBFIFO_HP_INT | DBFIFO_LP_INT | - EGRESS_SIZE_ERR); + t4_write_reg(adapter, SGE_INT_ENABLE3_A, ERR_CPL_EXCEED_IQE_SIZE_F | + ERR_INVALID_CIDX_INC_F | ERR_CPL_OPCODE_0_F | + ERR_DROPPED_DB_F | ERR_DATA_CPL_ON_HIGH_QID1_F | + ERR_DATA_CPL_ON_HIGH_QID0_F | ERR_BAD_DB_PIDX3_F | + ERR_BAD_DB_PIDX2_F | ERR_BAD_DB_PIDX1_F | + ERR_BAD_DB_PIDX0_F | ERR_ING_CTXT_PRIO_F | + ERR_EGR_CTXT_PRIO_F | INGRESS_SIZE_ERR_F | + DBFIFO_HP_INT_F | DBFIFO_LP_INT_F | + EGRESS_SIZE_ERR_F); t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK); t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf); } @@ -3148,22 +3149,23 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size, unsigned int fl_align = cache_line_size < 32 ? 32 : cache_line_size; unsigned int fl_align_log = fls(fl_align) - 1; - t4_write_reg(adap, SGE_HOST_PAGE_SIZE, - HOSTPAGESIZEPF0(sge_hps) | - HOSTPAGESIZEPF1(sge_hps) | - HOSTPAGESIZEPF2(sge_hps) | - HOSTPAGESIZEPF3(sge_hps) | - HOSTPAGESIZEPF4(sge_hps) | - HOSTPAGESIZEPF5(sge_hps) | - HOSTPAGESIZEPF6(sge_hps) | - HOSTPAGESIZEPF7(sge_hps)); + t4_write_reg(adap, SGE_HOST_PAGE_SIZE_A, + HOSTPAGESIZEPF0_V(sge_hps) | + HOSTPAGESIZEPF1_V(sge_hps) | + HOSTPAGESIZEPF2_V(sge_hps) | + HOSTPAGESIZEPF3_V(sge_hps) | + HOSTPAGESIZEPF4_V(sge_hps) | + HOSTPAGESIZEPF5_V(sge_hps) | + HOSTPAGESIZEPF6_V(sge_hps) | + HOSTPAGESIZEPF7_V(sge_hps)); if (is_t4(adap->params.chip)) { - t4_set_reg_field(adap, SGE_CONTROL, - INGPADBOUNDARY_MASK | - EGRSTATUSPAGESIZE_MASK, - INGPADBOUNDARY(fl_align_log - 5) | - EGRSTATUSPAGESIZE(stat_len != 64)); + t4_set_reg_field(adap, SGE_CONTROL_A, + INGPADBOUNDARY_V(INGPADBOUNDARY_M) | + EGRSTATUSPAGESIZE_F, + INGPADBOUNDARY_V(fl_align_log - + INGPADBOUNDARY_SHIFT_X) | + EGRSTATUSPAGESIZE_V(stat_len != 64)); } else { /* T5 introduced the separation of the Free List Padding and * Packing Boundaries. Thus, we can select a smaller Padding @@ -3193,15 +3195,15 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size, fl_align = 64; fl_align_log = 6; } - t4_set_reg_field(adap, SGE_CONTROL, - INGPADBOUNDARY_MASK | - EGRSTATUSPAGESIZE_MASK, - INGPADBOUNDARY(INGPCIEBOUNDARY_32B_X) | - EGRSTATUSPAGESIZE(stat_len != 64)); + t4_set_reg_field(adap, SGE_CONTROL_A, + INGPADBOUNDARY_V(INGPADBOUNDARY_M) | + EGRSTATUSPAGESIZE_F, + INGPADBOUNDARY_V(INGPCIEBOUNDARY_32B_X) | + EGRSTATUSPAGESIZE_V(stat_len != 64)); t4_set_reg_field(adap, SGE_CONTROL2_A, INGPACKBOUNDARY_V(INGPACKBOUNDARY_M), INGPACKBOUNDARY_V(fl_align_log - - INGPACKBOUNDARY_SHIFT_X)); + INGPACKBOUNDARY_SHIFT_X)); } /* * Adjust various SGE Free List Host Buffer Sizes. @@ -3224,12 +3226,12 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size, * Default Firmware Configuration File but we need to adjust it for * this host's cache line size. */ - t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, page_size); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE2, - (t4_read_reg(adap, SGE_FL_BUFFER_SIZE2) + fl_align-1) + t4_write_reg(adap, SGE_FL_BUFFER_SIZE0_A, page_size); + t4_write_reg(adap, SGE_FL_BUFFER_SIZE2_A, + (t4_read_reg(adap, SGE_FL_BUFFER_SIZE2_A) + fl_align-1) & ~(fl_align-1)); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE3, - (t4_read_reg(adap, SGE_FL_BUFFER_SIZE3) + fl_align-1) + t4_write_reg(adap, SGE_FL_BUFFER_SIZE3_A, + (t4_read_reg(adap, SGE_FL_BUFFER_SIZE3_A) + fl_align-1) & ~(fl_align-1)); t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(page_shift - 12)); @@ -4133,7 +4135,7 @@ int t4_init_sge_params(struct adapter *adapter) /* Extract the SGE Page Size for our PF. */ - hps = t4_read_reg(adapter, SGE_HOST_PAGE_SIZE); + hps = t4_read_reg(adapter, SGE_HOST_PAGE_SIZE_A); s_hps = (HOSTPAGESIZEPF0_S + (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * adapter->fn); sge_params->hps = ((hps >> s_hps) & HOSTPAGESIZEPF0_M); @@ -4142,10 +4144,10 @@ int t4_init_sge_params(struct adapter *adapter) */ s_qpp = (QUEUESPERPAGEPF0_S + (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * adapter->fn); - qpp = t4_read_reg(adapter, SGE_EGRESS_QUEUES_PER_PAGE_PF); - sge_params->eq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_MASK); + qpp = t4_read_reg(adapter, SGE_EGRESS_QUEUES_PER_PAGE_PF_A); + sge_params->eq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M); qpp = t4_read_reg(adapter, SGE_INGRESS_QUEUES_PER_PAGE_PF); - sge_params->iq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_MASK); + sge_params->iq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M); return 0; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index d7bd34ee65bd..29c09113c13b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -63,233 +63,311 @@ #define MC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) #define EDC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) -#define SGE_PF_KDOORBELL 0x0 -#define QID_MASK 0xffff8000U -#define QID_SHIFT 15 -#define QID(x) ((x) << QID_SHIFT) -#define DBPRIO(x) ((x) << 14) -#define DBTYPE(x) ((x) << 13) -#define PIDX_MASK 0x00003fffU -#define PIDX_SHIFT 0 -#define PIDX(x) ((x) << PIDX_SHIFT) -#define PIDX_SHIFT_T5 0 -#define PIDX_T5(x) ((x) << PIDX_SHIFT_T5) - - -#define SGE_TIMERREGS 6 -#define SGE_PF_GTS 0x4 -#define INGRESSQID_MASK 0xffff0000U -#define INGRESSQID_SHIFT 16 -#define INGRESSQID(x) ((x) << INGRESSQID_SHIFT) -#define TIMERREG_MASK 0x0000e000U -#define TIMERREG_SHIFT 13 -#define TIMERREG(x) ((x) << TIMERREG_SHIFT) -#define SEINTARM_MASK 0x00001000U -#define SEINTARM_SHIFT 12 -#define SEINTARM(x) ((x) << SEINTARM_SHIFT) -#define CIDXINC_MASK 0x00000fffU -#define CIDXINC_SHIFT 0 -#define CIDXINC(x) ((x) << CIDXINC_SHIFT) - -#define X_RXPKTCPLMODE_SPLIT 1 -#define X_INGPADBOUNDARY_SHIFT 5 - -#define SGE_CONTROL 0x1008 -#define SGE_CONTROL2_A 0x1124 -#define DCASYSTYPE 0x00080000U -#define RXPKTCPLMODE_MASK 0x00040000U -#define RXPKTCPLMODE_SHIFT 18 -#define RXPKTCPLMODE(x) ((x) << RXPKTCPLMODE_SHIFT) -#define EGRSTATUSPAGESIZE_MASK 0x00020000U -#define EGRSTATUSPAGESIZE_SHIFT 17 -#define EGRSTATUSPAGESIZE(x) ((x) << EGRSTATUSPAGESIZE_SHIFT) -#define PKTSHIFT_MASK 0x00001c00U -#define PKTSHIFT_SHIFT 10 -#define PKTSHIFT(x) ((x) << PKTSHIFT_SHIFT) -#define PKTSHIFT_GET(x) (((x) & PKTSHIFT_MASK) >> PKTSHIFT_SHIFT) -#define INGPCIEBOUNDARY_32B_X 0 -#define INGPCIEBOUNDARY_MASK 0x00000380U -#define INGPCIEBOUNDARY_SHIFT 7 -#define INGPCIEBOUNDARY(x) ((x) << INGPCIEBOUNDARY_SHIFT) -#define INGPADBOUNDARY_MASK 0x00000070U -#define INGPADBOUNDARY_SHIFT 4 -#define INGPADBOUNDARY(x) ((x) << INGPADBOUNDARY_SHIFT) -#define INGPADBOUNDARY_GET(x) (((x) & INGPADBOUNDARY_MASK) \ - >> INGPADBOUNDARY_SHIFT) -#define INGPACKBOUNDARY_16B_X 0 -#define INGPACKBOUNDARY_SHIFT_X 5 +#define SGE_PF_KDOORBELL_A 0x0 -#define INGPACKBOUNDARY_S 16 -#define INGPACKBOUNDARY_M 0x7U -#define INGPACKBOUNDARY_V(x) ((x) << INGPACKBOUNDARY_S) -#define INGPACKBOUNDARY_G(x) (((x) >> INGPACKBOUNDARY_S) \ - & INGPACKBOUNDARY_M) -#define EGRPCIEBOUNDARY_MASK 0x0000000eU -#define EGRPCIEBOUNDARY_SHIFT 1 -#define EGRPCIEBOUNDARY(x) ((x) << EGRPCIEBOUNDARY_SHIFT) -#define GLOBALENABLE 0x00000001U +#define QID_S 15 +#define QID_V(x) ((x) << QID_S) + +#define DBPRIO_S 14 +#define DBPRIO_V(x) ((x) << DBPRIO_S) +#define DBPRIO_F DBPRIO_V(1U) + +#define PIDX_S 0 +#define PIDX_V(x) ((x) << PIDX_S) + +#define SGE_VF_KDOORBELL_A 0x0 + +#define DBTYPE_S 13 +#define DBTYPE_V(x) ((x) << DBTYPE_S) +#define DBTYPE_F DBTYPE_V(1U) + +#define PIDX_T5_S 0 +#define PIDX_T5_M 0x1fffU +#define PIDX_T5_V(x) ((x) << PIDX_T5_S) +#define PIDX_T5_G(x) (((x) >> PIDX_T5_S) & PIDX_T5_M) + +#define SGE_PF_GTS_A 0x4 -#define SGE_HOST_PAGE_SIZE 0x100c +#define INGRESSQID_S 16 +#define INGRESSQID_V(x) ((x) << INGRESSQID_S) -#define HOSTPAGESIZEPF7_MASK 0x0000000fU -#define HOSTPAGESIZEPF7_SHIFT 28 -#define HOSTPAGESIZEPF7(x) ((x) << HOSTPAGESIZEPF7_SHIFT) +#define TIMERREG_S 13 +#define TIMERREG_V(x) ((x) << TIMERREG_S) -#define HOSTPAGESIZEPF6_MASK 0x0000000fU -#define HOSTPAGESIZEPF6_SHIFT 24 -#define HOSTPAGESIZEPF6(x) ((x) << HOSTPAGESIZEPF6_SHIFT) +#define SEINTARM_S 12 +#define SEINTARM_V(x) ((x) << SEINTARM_S) -#define HOSTPAGESIZEPF5_MASK 0x0000000fU -#define HOSTPAGESIZEPF5_SHIFT 20 -#define HOSTPAGESIZEPF5(x) ((x) << HOSTPAGESIZEPF5_SHIFT) +#define CIDXINC_S 0 +#define CIDXINC_M 0xfffU +#define CIDXINC_V(x) ((x) << CIDXINC_S) -#define HOSTPAGESIZEPF4_MASK 0x0000000fU -#define HOSTPAGESIZEPF4_SHIFT 16 -#define HOSTPAGESIZEPF4(x) ((x) << HOSTPAGESIZEPF4_SHIFT) +#define SGE_CONTROL_A 0x1008 +#define SGE_CONTROL2_A 0x1124 -#define HOSTPAGESIZEPF3_MASK 0x0000000fU -#define HOSTPAGESIZEPF3_SHIFT 12 -#define HOSTPAGESIZEPF3(x) ((x) << HOSTPAGESIZEPF3_SHIFT) +#define RXPKTCPLMODE_S 18 +#define RXPKTCPLMODE_V(x) ((x) << RXPKTCPLMODE_S) +#define RXPKTCPLMODE_F RXPKTCPLMODE_V(1U) -#define HOSTPAGESIZEPF2_MASK 0x0000000fU -#define HOSTPAGESIZEPF2_SHIFT 8 -#define HOSTPAGESIZEPF2(x) ((x) << HOSTPAGESIZEPF2_SHIFT) +#define EGRSTATUSPAGESIZE_S 17 +#define EGRSTATUSPAGESIZE_V(x) ((x) << EGRSTATUSPAGESIZE_S) +#define EGRSTATUSPAGESIZE_F EGRSTATUSPAGESIZE_V(1U) -#define HOSTPAGESIZEPF1_M 0x0000000fU -#define HOSTPAGESIZEPF1_S 4 -#define HOSTPAGESIZEPF1(x) ((x) << HOSTPAGESIZEPF1_S) +#define PKTSHIFT_S 10 +#define PKTSHIFT_M 0x7U +#define PKTSHIFT_V(x) ((x) << PKTSHIFT_S) +#define PKTSHIFT_G(x) (((x) >> PKTSHIFT_S) & PKTSHIFT_M) -#define HOSTPAGESIZEPF0_M 0x0000000fU -#define HOSTPAGESIZEPF0_S 0 -#define HOSTPAGESIZEPF0(x) ((x) << HOSTPAGESIZEPF0_S) +#define INGPCIEBOUNDARY_S 7 +#define INGPCIEBOUNDARY_V(x) ((x) << INGPCIEBOUNDARY_S) -#define SGE_EGRESS_QUEUES_PER_PAGE_PF 0x1010 +#define INGPADBOUNDARY_S 4 +#define INGPADBOUNDARY_M 0x7U +#define INGPADBOUNDARY_V(x) ((x) << INGPADBOUNDARY_S) +#define INGPADBOUNDARY_G(x) (((x) >> INGPADBOUNDARY_S) & INGPADBOUNDARY_M) + +#define EGRPCIEBOUNDARY_S 1 +#define EGRPCIEBOUNDARY_V(x) ((x) << EGRPCIEBOUNDARY_S) + +#define INGPACKBOUNDARY_S 16 +#define INGPACKBOUNDARY_M 0x7U +#define INGPACKBOUNDARY_V(x) ((x) << INGPACKBOUNDARY_S) +#define INGPACKBOUNDARY_G(x) (((x) >> INGPACKBOUNDARY_S) \ + & INGPACKBOUNDARY_M) + +#define GLOBALENABLE_S 0 +#define GLOBALENABLE_V(x) ((x) << GLOBALENABLE_S) +#define GLOBALENABLE_F GLOBALENABLE_V(1U) + +#define SGE_HOST_PAGE_SIZE_A 0x100c + +#define HOSTPAGESIZEPF7_S 28 +#define HOSTPAGESIZEPF7_M 0xfU +#define HOSTPAGESIZEPF7_V(x) ((x) << HOSTPAGESIZEPF7_S) +#define HOSTPAGESIZEPF7_G(x) (((x) >> HOSTPAGESIZEPF7_S) & HOSTPAGESIZEPF7_M) + +#define HOSTPAGESIZEPF6_S 24 +#define HOSTPAGESIZEPF6_M 0xfU +#define HOSTPAGESIZEPF6_V(x) ((x) << HOSTPAGESIZEPF6_S) +#define HOSTPAGESIZEPF6_G(x) (((x) >> HOSTPAGESIZEPF6_S) & HOSTPAGESIZEPF6_M) + +#define HOSTPAGESIZEPF5_S 20 +#define HOSTPAGESIZEPF5_M 0xfU +#define HOSTPAGESIZEPF5_V(x) ((x) << HOSTPAGESIZEPF5_S) +#define HOSTPAGESIZEPF5_G(x) (((x) >> HOSTPAGESIZEPF5_S) & HOSTPAGESIZEPF5_M) + +#define HOSTPAGESIZEPF4_S 16 +#define HOSTPAGESIZEPF4_M 0xfU +#define HOSTPAGESIZEPF4_V(x) ((x) << HOSTPAGESIZEPF4_S) +#define HOSTPAGESIZEPF4_G(x) (((x) >> HOSTPAGESIZEPF4_S) & HOSTPAGESIZEPF4_M) + +#define HOSTPAGESIZEPF3_S 12 +#define HOSTPAGESIZEPF3_M 0xfU +#define HOSTPAGESIZEPF3_V(x) ((x) << HOSTPAGESIZEPF3_S) +#define HOSTPAGESIZEPF3_G(x) (((x) >> HOSTPAGESIZEPF3_S) & HOSTPAGESIZEPF3_M) + +#define HOSTPAGESIZEPF2_S 8 +#define HOSTPAGESIZEPF2_M 0xfU +#define HOSTPAGESIZEPF2_V(x) ((x) << HOSTPAGESIZEPF2_S) +#define HOSTPAGESIZEPF2_G(x) (((x) >> HOSTPAGESIZEPF2_S) & HOSTPAGESIZEPF2_M) + +#define HOSTPAGESIZEPF1_S 4 +#define HOSTPAGESIZEPF1_M 0xfU +#define HOSTPAGESIZEPF1_V(x) ((x) << HOSTPAGESIZEPF1_S) +#define HOSTPAGESIZEPF1_G(x) (((x) >> HOSTPAGESIZEPF1_S) & HOSTPAGESIZEPF1_M) + +#define HOSTPAGESIZEPF0_S 0 +#define HOSTPAGESIZEPF0_M 0xfU +#define HOSTPAGESIZEPF0_V(x) ((x) << HOSTPAGESIZEPF0_S) +#define HOSTPAGESIZEPF0_G(x) (((x) >> HOSTPAGESIZEPF0_S) & HOSTPAGESIZEPF0_M) + +#define SGE_EGRESS_QUEUES_PER_PAGE_PF_A 0x1010 #define SGE_EGRESS_QUEUES_PER_PAGE_VF_A 0x1014 #define QUEUESPERPAGEPF1_S 4 #define QUEUESPERPAGEPF0_S 0 -#define QUEUESPERPAGEPF0_MASK 0x0000000fU -#define QUEUESPERPAGEPF0_GET(x) ((x) & QUEUESPERPAGEPF0_MASK) - -#define QUEUESPERPAGEPF0 0 -#define QUEUESPERPAGEPF1 4 +#define QUEUESPERPAGEPF0_M 0xfU +#define QUEUESPERPAGEPF0_V(x) ((x) << QUEUESPERPAGEPF0_S) +#define QUEUESPERPAGEPF0_G(x) (((x) >> QUEUESPERPAGEPF0_S) & QUEUESPERPAGEPF0_M) -/* T5 and later support a new BAR2-based doorbell mechanism for Egress Queues. - * The User Doorbells are each 128 bytes in length with a Simple Doorbell at - * offsets 8x and a Write Combining single 64-byte Egress Queue Unit - * (X_IDXSIZE_UNIT) Gather Buffer interface at offset 64. For Ingress Queues, - * we have a Going To Sleep register at offsets 8x+4. - * - * As noted above, we have many instances of the Simple Doorbell and Going To - * Sleep registers at offsets 8x and 8x+4, respectively. We want to use a - * non-64-byte aligned offset for the Simple Doorbell in order to attempt to - * avoid buffering of the writes to the Simple Doorbell and we want to use a - * non-contiguous offset for the Going To Sleep writes in order to avoid - * possible combining between them. - */ -#define SGE_UDB_SIZE 128 -#define SGE_UDB_KDOORBELL 8 -#define SGE_UDB_GTS 20 -#define SGE_UDB_WCDOORBELL 64 - -#define SGE_INT_CAUSE1 0x1024 -#define SGE_INT_CAUSE2 0x1030 -#define SGE_INT_CAUSE3 0x103c -#define ERR_FLM_DBP 0x80000000U -#define ERR_FLM_IDMA1 0x40000000U -#define ERR_FLM_IDMA0 0x20000000U -#define ERR_FLM_HINT 0x10000000U -#define ERR_PCIE_ERROR3 0x08000000U -#define ERR_PCIE_ERROR2 0x04000000U -#define ERR_PCIE_ERROR1 0x02000000U -#define ERR_PCIE_ERROR0 0x01000000U -#define ERR_TIMER_ABOVE_MAX_QID 0x00800000U -#define ERR_CPL_EXCEED_IQE_SIZE 0x00400000U -#define ERR_INVALID_CIDX_INC 0x00200000U -#define ERR_ITP_TIME_PAUSED 0x00100000U -#define ERR_CPL_OPCODE_0 0x00080000U -#define ERR_DROPPED_DB 0x00040000U -#define ERR_DATA_CPL_ON_HIGH_QID1 0x00020000U -#define ERR_DATA_CPL_ON_HIGH_QID0 0x00010000U -#define ERR_BAD_DB_PIDX3 0x00008000U -#define ERR_BAD_DB_PIDX2 0x00004000U -#define ERR_BAD_DB_PIDX1 0x00002000U -#define ERR_BAD_DB_PIDX0 0x00001000U -#define ERR_ING_PCIE_CHAN 0x00000800U -#define ERR_ING_CTXT_PRIO 0x00000400U -#define ERR_EGR_CTXT_PRIO 0x00000200U -#define DBFIFO_HP_INT 0x00000100U -#define DBFIFO_LP_INT 0x00000080U -#define REG_ADDRESS_ERR 0x00000040U -#define INGRESS_SIZE_ERR 0x00000020U -#define EGRESS_SIZE_ERR 0x00000010U -#define ERR_INV_CTXT3 0x00000008U -#define ERR_INV_CTXT2 0x00000004U -#define ERR_INV_CTXT1 0x00000002U -#define ERR_INV_CTXT0 0x00000001U - -#define SGE_INT_ENABLE3 0x1040 -#define SGE_FL_BUFFER_SIZE0 0x1044 -#define SGE_FL_BUFFER_SIZE1 0x1048 -#define SGE_FL_BUFFER_SIZE2 0x104c -#define SGE_FL_BUFFER_SIZE3 0x1050 -#define SGE_FL_BUFFER_SIZE4 0x1054 -#define SGE_FL_BUFFER_SIZE5 0x1058 -#define SGE_FL_BUFFER_SIZE6 0x105c -#define SGE_FL_BUFFER_SIZE7 0x1060 -#define SGE_FL_BUFFER_SIZE8 0x1064 - -#define SGE_INGRESS_RX_THRESHOLD 0x10a0 -#define THRESHOLD_0_MASK 0x3f000000U -#define THRESHOLD_0_SHIFT 24 -#define THRESHOLD_0(x) ((x) << THRESHOLD_0_SHIFT) -#define THRESHOLD_0_GET(x) (((x) & THRESHOLD_0_MASK) >> THRESHOLD_0_SHIFT) -#define THRESHOLD_1_MASK 0x003f0000U -#define THRESHOLD_1_SHIFT 16 -#define THRESHOLD_1(x) ((x) << THRESHOLD_1_SHIFT) -#define THRESHOLD_1_GET(x) (((x) & THRESHOLD_1_MASK) >> THRESHOLD_1_SHIFT) -#define THRESHOLD_2_MASK 0x00003f00U -#define THRESHOLD_2_SHIFT 8 -#define THRESHOLD_2(x) ((x) << THRESHOLD_2_SHIFT) -#define THRESHOLD_2_GET(x) (((x) & THRESHOLD_2_MASK) >> THRESHOLD_2_SHIFT) -#define THRESHOLD_3_MASK 0x0000003fU -#define THRESHOLD_3_SHIFT 0 -#define THRESHOLD_3(x) ((x) << THRESHOLD_3_SHIFT) -#define THRESHOLD_3_GET(x) (((x) & THRESHOLD_3_MASK) >> THRESHOLD_3_SHIFT) - -#define SGE_CONM_CTRL 0x1094 -#define EGRTHRESHOLD_MASK 0x00003f00U -#define EGRTHRESHOLDshift 8 -#define EGRTHRESHOLD(x) ((x) << EGRTHRESHOLDshift) -#define EGRTHRESHOLD_GET(x) (((x) & EGRTHRESHOLD_MASK) >> EGRTHRESHOLDshift) - -#define EGRTHRESHOLDPACKING_MASK 0x3fU -#define EGRTHRESHOLDPACKING_SHIFT 14 -#define EGRTHRESHOLDPACKING(x) ((x) << EGRTHRESHOLDPACKING_SHIFT) -#define EGRTHRESHOLDPACKING_GET(x) (((x) >> EGRTHRESHOLDPACKING_SHIFT) & \ - EGRTHRESHOLDPACKING_MASK) - -#define SGE_DBFIFO_STATUS 0x10a4 -#define HP_INT_THRESH_SHIFT 28 -#define HP_INT_THRESH_MASK 0xfU -#define HP_INT_THRESH(x) ((x) << HP_INT_THRESH_SHIFT) -#define LP_INT_THRESH_SHIFT 12 -#define LP_INT_THRESH_MASK 0xfU -#define LP_INT_THRESH(x) ((x) << LP_INT_THRESH_SHIFT) - -#define SGE_DOORBELL_CONTROL 0x10a8 -#define ENABLE_DROP (1 << 13) - -#define S_NOCOALESCE 26 -#define V_NOCOALESCE(x) ((x) << S_NOCOALESCE) -#define F_NOCOALESCE V_NOCOALESCE(1U) - -#define SGE_TIMESTAMP_LO 0x1098 -#define SGE_TIMESTAMP_HI 0x109c -#define S_TSVAL 0 -#define M_TSVAL 0xfffffffU -#define GET_TSVAL(x) (((x) >> S_TSVAL) & M_TSVAL) +#define SGE_INT_CAUSE1_A 0x1024 +#define SGE_INT_CAUSE2_A 0x1030 +#define SGE_INT_CAUSE3_A 0x103c + +#define ERR_FLM_DBP_S 31 +#define ERR_FLM_DBP_V(x) ((x) << ERR_FLM_DBP_S) +#define ERR_FLM_DBP_F ERR_FLM_DBP_V(1U) + +#define ERR_FLM_IDMA1_S 30 +#define ERR_FLM_IDMA1_V(x) ((x) << ERR_FLM_IDMA1_S) +#define ERR_FLM_IDMA1_F ERR_FLM_IDMA1_V(1U) + +#define ERR_FLM_IDMA0_S 29 +#define ERR_FLM_IDMA0_V(x) ((x) << ERR_FLM_IDMA0_S) +#define ERR_FLM_IDMA0_F ERR_FLM_IDMA0_V(1U) + +#define ERR_FLM_HINT_S 28 +#define ERR_FLM_HINT_V(x) ((x) << ERR_FLM_HINT_S) +#define ERR_FLM_HINT_F ERR_FLM_HINT_V(1U) + +#define ERR_PCIE_ERROR3_S 27 +#define ERR_PCIE_ERROR3_V(x) ((x) << ERR_PCIE_ERROR3_S) +#define ERR_PCIE_ERROR3_F ERR_PCIE_ERROR3_V(1U) + +#define ERR_PCIE_ERROR2_S 26 +#define ERR_PCIE_ERROR2_V(x) ((x) << ERR_PCIE_ERROR2_S) +#define ERR_PCIE_ERROR2_F ERR_PCIE_ERROR2_V(1U) + +#define ERR_PCIE_ERROR1_S 25 +#define ERR_PCIE_ERROR1_V(x) ((x) << ERR_PCIE_ERROR1_S) +#define ERR_PCIE_ERROR1_F ERR_PCIE_ERROR1_V(1U) + +#define ERR_PCIE_ERROR0_S 24 +#define ERR_PCIE_ERROR0_V(x) ((x) << ERR_PCIE_ERROR0_S) +#define ERR_PCIE_ERROR0_F ERR_PCIE_ERROR0_V(1U) + +#define ERR_CPL_EXCEED_IQE_SIZE_S 22 +#define ERR_CPL_EXCEED_IQE_SIZE_V(x) ((x) << ERR_CPL_EXCEED_IQE_SIZE_S) +#define ERR_CPL_EXCEED_IQE_SIZE_F ERR_CPL_EXCEED_IQE_SIZE_V(1U) + +#define ERR_INVALID_CIDX_INC_S 21 +#define ERR_INVALID_CIDX_INC_V(x) ((x) << ERR_INVALID_CIDX_INC_S) +#define ERR_INVALID_CIDX_INC_F ERR_INVALID_CIDX_INC_V(1U) + +#define ERR_CPL_OPCODE_0_S 19 +#define ERR_CPL_OPCODE_0_V(x) ((x) << ERR_CPL_OPCODE_0_S) +#define ERR_CPL_OPCODE_0_F ERR_CPL_OPCODE_0_V(1U) + +#define ERR_DROPPED_DB_S 18 +#define ERR_DROPPED_DB_V(x) ((x) << ERR_DROPPED_DB_S) +#define ERR_DROPPED_DB_F ERR_DROPPED_DB_V(1U) + +#define ERR_DATA_CPL_ON_HIGH_QID1_S 17 +#define ERR_DATA_CPL_ON_HIGH_QID1_V(x) ((x) << ERR_DATA_CPL_ON_HIGH_QID1_S) +#define ERR_DATA_CPL_ON_HIGH_QID1_F ERR_DATA_CPL_ON_HIGH_QID1_V(1U) + +#define ERR_DATA_CPL_ON_HIGH_QID0_S 16 +#define ERR_DATA_CPL_ON_HIGH_QID0_V(x) ((x) << ERR_DATA_CPL_ON_HIGH_QID0_S) +#define ERR_DATA_CPL_ON_HIGH_QID0_F ERR_DATA_CPL_ON_HIGH_QID0_V(1U) + +#define ERR_BAD_DB_PIDX3_S 15 +#define ERR_BAD_DB_PIDX3_V(x) ((x) << ERR_BAD_DB_PIDX3_S) +#define ERR_BAD_DB_PIDX3_F ERR_BAD_DB_PIDX3_V(1U) + +#define ERR_BAD_DB_PIDX2_S 14 +#define ERR_BAD_DB_PIDX2_V(x) ((x) << ERR_BAD_DB_PIDX2_S) +#define ERR_BAD_DB_PIDX2_F ERR_BAD_DB_PIDX2_V(1U) + +#define ERR_BAD_DB_PIDX1_S 13 +#define ERR_BAD_DB_PIDX1_V(x) ((x) << ERR_BAD_DB_PIDX1_S) +#define ERR_BAD_DB_PIDX1_F ERR_BAD_DB_PIDX1_V(1U) + +#define ERR_BAD_DB_PIDX0_S 12 +#define ERR_BAD_DB_PIDX0_V(x) ((x) << ERR_BAD_DB_PIDX0_S) +#define ERR_BAD_DB_PIDX0_F ERR_BAD_DB_PIDX0_V(1U) + +#define ERR_ING_CTXT_PRIO_S 10 +#define ERR_ING_CTXT_PRIO_V(x) ((x) << ERR_ING_CTXT_PRIO_S) +#define ERR_ING_CTXT_PRIO_F ERR_ING_CTXT_PRIO_V(1U) + +#define ERR_EGR_CTXT_PRIO_S 9 +#define ERR_EGR_CTXT_PRIO_V(x) ((x) << ERR_EGR_CTXT_PRIO_S) +#define ERR_EGR_CTXT_PRIO_F ERR_EGR_CTXT_PRIO_V(1U) + +#define DBFIFO_HP_INT_S 8 +#define DBFIFO_HP_INT_V(x) ((x) << DBFIFO_HP_INT_S) +#define DBFIFO_HP_INT_F DBFIFO_HP_INT_V(1U) + +#define DBFIFO_LP_INT_S 7 +#define DBFIFO_LP_INT_V(x) ((x) << DBFIFO_LP_INT_S) +#define DBFIFO_LP_INT_F DBFIFO_LP_INT_V(1U) + +#define INGRESS_SIZE_ERR_S 5 +#define INGRESS_SIZE_ERR_V(x) ((x) << INGRESS_SIZE_ERR_S) +#define INGRESS_SIZE_ERR_F INGRESS_SIZE_ERR_V(1U) + +#define EGRESS_SIZE_ERR_S 4 +#define EGRESS_SIZE_ERR_V(x) ((x) << EGRESS_SIZE_ERR_S) +#define EGRESS_SIZE_ERR_F EGRESS_SIZE_ERR_V(1U) + +#define SGE_INT_ENABLE3_A 0x1040 +#define SGE_FL_BUFFER_SIZE0_A 0x1044 +#define SGE_FL_BUFFER_SIZE1_A 0x1048 +#define SGE_FL_BUFFER_SIZE2_A 0x104c +#define SGE_FL_BUFFER_SIZE3_A 0x1050 +#define SGE_FL_BUFFER_SIZE4_A 0x1054 +#define SGE_FL_BUFFER_SIZE5_A 0x1058 +#define SGE_FL_BUFFER_SIZE6_A 0x105c +#define SGE_FL_BUFFER_SIZE7_A 0x1060 +#define SGE_FL_BUFFER_SIZE8_A 0x1064 + +#define SGE_INGRESS_RX_THRESHOLD_A 0x10a0 + +#define THRESHOLD_0_S 24 +#define THRESHOLD_0_M 0x3fU +#define THRESHOLD_0_V(x) ((x) << THRESHOLD_0_S) +#define THRESHOLD_0_G(x) (((x) >> THRESHOLD_0_S) & THRESHOLD_0_M) + +#define THRESHOLD_1_S 16 +#define THRESHOLD_1_M 0x3fU +#define THRESHOLD_1_V(x) ((x) << THRESHOLD_1_S) +#define THRESHOLD_1_G(x) (((x) >> THRESHOLD_1_S) & THRESHOLD_1_M) + +#define THRESHOLD_2_S 8 +#define THRESHOLD_2_M 0x3fU +#define THRESHOLD_2_V(x) ((x) << THRESHOLD_2_S) +#define THRESHOLD_2_G(x) (((x) >> THRESHOLD_2_S) & THRESHOLD_2_M) + +#define THRESHOLD_3_S 0 +#define THRESHOLD_3_M 0x3fU +#define THRESHOLD_3_V(x) ((x) << THRESHOLD_3_S) +#define THRESHOLD_3_G(x) (((x) >> THRESHOLD_3_S) & THRESHOLD_3_M) + +#define SGE_CONM_CTRL_A 0x1094 + +#define EGRTHRESHOLD_S 8 +#define EGRTHRESHOLD_M 0x3fU +#define EGRTHRESHOLD_V(x) ((x) << EGRTHRESHOLD_S) +#define EGRTHRESHOLD_G(x) (((x) >> EGRTHRESHOLD_S) & EGRTHRESHOLD_M) + +#define EGRTHRESHOLDPACKING_S 14 +#define EGRTHRESHOLDPACKING_M 0x3fU +#define EGRTHRESHOLDPACKING_V(x) ((x) << EGRTHRESHOLDPACKING_S) +#define EGRTHRESHOLDPACKING_G(x) \ + (((x) >> EGRTHRESHOLDPACKING_S) & EGRTHRESHOLDPACKING_M) + +#define SGE_TIMESTAMP_LO_A 0x1098 +#define SGE_TIMESTAMP_HI_A 0x109c + +#define TSOP_S 28 +#define TSOP_M 0x3U +#define TSOP_V(x) ((x) << TSOP_S) +#define TSOP_G(x) (((x) >> TSOP_S) & TSOP_M) + +#define TSVAL_S 0 +#define TSVAL_M 0xfffffffU +#define TSVAL_V(x) ((x) << TSVAL_S) +#define TSVAL_G(x) (((x) >> TSVAL_S) & TSVAL_M) + +#define SGE_DBFIFO_STATUS_A 0x10a4 + +#define HP_INT_THRESH_S 28 +#define HP_INT_THRESH_M 0xfU +#define HP_INT_THRESH_V(x) ((x) << HP_INT_THRESH_S) + +#define LP_INT_THRESH_S 12 +#define LP_INT_THRESH_M 0xfU +#define LP_INT_THRESH_V(x) ((x) << LP_INT_THRESH_S) + +#define SGE_DOORBELL_CONTROL_A 0x10a8 + +#define NOCOALESCE_S 26 +#define NOCOALESCE_V(x) ((x) << NOCOALESCE_S) +#define NOCOALESCE_F NOCOALESCE_V(1U) + +#define ENABLE_DROP_S 13 +#define ENABLE_DROP_V(x) ((x) << ENABLE_DROP_S) +#define ENABLE_DROP_F ENABLE_DROP_V(1U) #define SGE_TIMER_VALUE_0_AND_1 0x10b8 #define TIMERVALUE0_MASK 0xffff0000U diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h new file mode 100644 index 000000000000..769968644853 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h @@ -0,0 +1,81 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4_VALUES_H__ +#define __T4_VALUES_H__ + +/* This file contains definitions for various T4 register value hardware + * constants. The types of values encoded here are predominantly those for + * register fields which control "modal" behavior. For the most part, we do + * not include definitions for register fields which are simple numeric + * metrics, etc. + */ + +/* SGE register field values. + */ + +/* CONTROL1 register */ +#define RXPKTCPLMODE_SPLIT_X 1 + +#define INGPCIEBOUNDARY_SHIFT_X 5 +#define INGPCIEBOUNDARY_32B_X 0 + +#define INGPADBOUNDARY_SHIFT_X 5 + +/* CONTROL2 register */ +#define INGPACKBOUNDARY_SHIFT_X 5 +#define INGPACKBOUNDARY_16B_X 0 + +/* GTS register */ +#define SGE_TIMERREGS 6 + +/* T5 and later support a new BAR2-based doorbell mechanism for Egress Queues. + * The User Doorbells are each 128 bytes in length with a Simple Doorbell at + * offsets 8x and a Write Combining single 64-byte Egress Queue Unit + * (IDXSIZE_UNIT_X) Gather Buffer interface at offset 64. For Ingress Queues, + * we have a Going To Sleep register at offsets 8x+4. + * + * As noted above, we have many instances of the Simple Doorbell and Going To + * Sleep registers at offsets 8x and 8x+4, respectively. We want to use a + * non-64-byte aligned offset for the Simple Doorbell in order to attempt to + * avoid buffering of the writes to the Simple Doorbell and we want to use a + * non-contiguous offset for the Going To Sleep writes in order to avoid + * possible combining between them. + */ +#define SGE_UDB_SIZE 128 +#define SGE_UDB_KDOORBELL 8 +#define SGE_UDB_GTS 20 +#define SGE_UDB_WCDOORBELL 64 + +#endif /* __T4_VALUES_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index 2215d432a059..b645e33bbc8f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -380,9 +380,9 @@ static void qenable(struct sge_rspq *rspq) * enable interrupts. */ t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - CIDXINC(0) | - SEINTARM(rspq->intr_params) | - INGRESSQID(rspq->cntxt_id)); + CIDXINC_V(0) | + SEINTARM_V(rspq->intr_params) | + INGRESSQID_V(rspq->cntxt_id)); } /* @@ -403,9 +403,9 @@ static void enable_rx(struct adapter *adapter) */ if (adapter->flags & USING_MSI) t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - CIDXINC(0) | - SEINTARM(s->intrq.intr_params) | - INGRESSQID(s->intrq.cntxt_id)); + CIDXINC_V(0) | + SEINTARM_V(s->intrq.intr_params) | + INGRESSQID_V(s->intrq.cntxt_id)); } @@ -2306,14 +2306,10 @@ static int adap_init0(struct adapter *adapter) s->timer_val[5] = core_ticks_to_us(adapter, TIMERVALUE1_GET(sge_params->sge_timer_value_4_and_5)); - s->counter_val[0] = - THRESHOLD_0_GET(sge_params->sge_ingress_rx_threshold); - s->counter_val[1] = - THRESHOLD_1_GET(sge_params->sge_ingress_rx_threshold); - s->counter_val[2] = - THRESHOLD_2_GET(sge_params->sge_ingress_rx_threshold); - s->counter_val[3] = - THRESHOLD_3_GET(sge_params->sge_ingress_rx_threshold); + s->counter_val[0] = THRESHOLD_0_G(sge_params->sge_ingress_rx_threshold); + s->counter_val[1] = THRESHOLD_1_G(sge_params->sge_ingress_rx_threshold); + s->counter_val[2] = THRESHOLD_2_G(sge_params->sge_ingress_rx_threshold); + s->counter_val[3] = THRESHOLD_3_G(sge_params->sge_ingress_rx_threshold); /* * Grab our Virtual Interface resource allocation, extract the diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index f7fd1317d996..ef4da3e1829b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -47,6 +47,7 @@ #include "t4vf_defs.h" #include "../cxgb4/t4_regs.h" +#include "../cxgb4/t4_values.h" #include "../cxgb4/t4fw_api.h" #include "../cxgb4/t4_msg.h" @@ -531,11 +532,11 @@ static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl) */ if (fl->pend_cred >= FL_PER_EQ_UNIT) { if (is_t4(adapter->params.chip)) - val = PIDX(fl->pend_cred / FL_PER_EQ_UNIT); + val = PIDX_V(fl->pend_cred / FL_PER_EQ_UNIT); else - val = PIDX_T5(fl->pend_cred / FL_PER_EQ_UNIT) | - DBTYPE(1); - val |= DBPRIO(1); + val = PIDX_T5_V(fl->pend_cred / FL_PER_EQ_UNIT) | + DBTYPE_F; + val |= DBPRIO_F; /* Make sure all memory writes to the Free List queue are * committed before we tell the hardware about them. @@ -549,9 +550,9 @@ static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl) if (unlikely(fl->bar2_addr == NULL)) { t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL, - QID(fl->cntxt_id) | val); + QID_V(fl->cntxt_id) | val); } else { - writel(val | QID(fl->bar2_qid), + writel(val | QID_V(fl->bar2_qid), fl->bar2_addr + SGE_UDB_KDOORBELL); /* This Write memory Barrier will force the write to @@ -979,12 +980,12 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, * doorbell mechanism; otherwise use the new BAR2 mechanism. */ if (unlikely(tq->bar2_addr == NULL)) { - u32 val = PIDX(n); + u32 val = PIDX_V(n); t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL, - QID(tq->cntxt_id) | val); + QID_V(tq->cntxt_id) | val); } else { - u32 val = PIDX_T5(n); + u32 val = PIDX_T5_V(n); /* T4 and later chips share the same PIDX field offset within * the doorbell, but T5 and later shrank the field in order to @@ -992,7 +993,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, * large in the first place (14 bits) so we just use the T5 * and later limits and warn if a Queue ID is too large. */ - WARN_ON(val & DBPRIO(1)); + WARN_ON(val & DBPRIO_F); /* If we're only writing a single Egress Unit and the BAR2 * Queue ID is 0, we can use the Write Combining Doorbell @@ -1023,7 +1024,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, count--; } } else - writel(val | QID(tq->bar2_qid), + writel(val | QID_V(tq->bar2_qid), tq->bar2_addr + SGE_UDB_KDOORBELL); /* This Write Memory Barrier will force the write to the User @@ -1875,13 +1876,13 @@ static int napi_rx_handler(struct napi_struct *napi, int budget) if (unlikely(work_done == 0)) rspq->unhandled_irqs++; - val = CIDXINC(work_done) | SEINTARM(intr_params); + val = CIDXINC_V(work_done) | SEINTARM_V(intr_params); if (is_t4(rspq->adapter->params.chip)) { t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - val | INGRESSQID((u32)rspq->cntxt_id)); + val | INGRESSQID_V((u32)rspq->cntxt_id)); } else { - writel(val | INGRESSQID(rspq->bar2_qid), + writel(val | INGRESSQID_V(rspq->bar2_qid), rspq->bar2_addr + SGE_UDB_GTS); wmb(); } @@ -1975,12 +1976,12 @@ static unsigned int process_intrq(struct adapter *adapter) rspq_next(intrq); } - val = CIDXINC(work_done) | SEINTARM(intrq->intr_params); + val = CIDXINC_V(work_done) | SEINTARM_V(intrq->intr_params); if (is_t4(adapter->params.chip)) t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - val | INGRESSQID(intrq->cntxt_id)); + val | INGRESSQID_V(intrq->cntxt_id)); else { - writel(val | INGRESSQID(intrq->bar2_qid), + writel(val | INGRESSQID_V(intrq->bar2_qid), intrq->bar2_addr + SGE_UDB_GTS); wmb(); } @@ -2583,7 +2584,7 @@ int t4vf_sge_init(struct adapter *adapter) fl0, fl1); return -EINVAL; } - if ((sge_params->sge_control & RXPKTCPLMODE_MASK) == 0) { + if ((sge_params->sge_control & RXPKTCPLMODE_F) == 0) { dev_err(adapter->pdev_dev, "bad SGE CPL MODE\n"); return -EINVAL; } @@ -2593,9 +2594,9 @@ int t4vf_sge_init(struct adapter *adapter) */ if (fl1) s->fl_pg_order = ilog2(fl1) - PAGE_SHIFT; - s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_MASK) + s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64); - s->pktshift = PKTSHIFT_GET(sge_params->sge_control); + s->pktshift = PKTSHIFT_G(sge_params->sge_control); /* T4 uses a single control field to specify both the PCIe Padding and * Packing Boundary. T5 introduced the ability to specify these @@ -2607,8 +2608,8 @@ int t4vf_sge_init(struct adapter *adapter) * end doing this because it would initialize the Padding Boundary and * leave the Packing Boundary initialized to 0 (16 bytes).) */ - ingpadboundary = 1 << (INGPADBOUNDARY_GET(sge_params->sge_control) + - X_INGPADBOUNDARY_SHIFT); + ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_params->sge_control) + + INGPADBOUNDARY_SHIFT_X); if (is_t4(adapter->params.chip)) { s->fl_align = ingpadboundary; } else { @@ -2633,7 +2634,7 @@ int t4vf_sge_init(struct adapter *adapter) * Congestion Threshold is in units of 2 Free List pointers.) */ s->fl_starve_thres - = EGRTHRESHOLD_GET(sge_params->sge_congestion_control)*2 + 1; + = EGRTHRESHOLD_G(sge_params->sge_congestion_control)*2 + 1; /* * Set up tasklet timers. diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 21dc9a20308c..6929d1f13c8f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -39,6 +39,7 @@ #include "t4vf_defs.h" #include "../cxgb4/t4_regs.h" +#include "../cxgb4/t4_values.h" #include "../cxgb4/t4fw_api.h" /* @@ -528,13 +529,13 @@ int t4vf_get_sge_params(struct adapter *adapter) int v; params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_CONTROL)); + FW_PARAMS_PARAM_XYZ_V(SGE_CONTROL_A)); params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_HOST_PAGE_SIZE)); + FW_PARAMS_PARAM_XYZ_V(SGE_HOST_PAGE_SIZE_A)); params[2] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE0)); + FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE0_A)); params[3] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE1)); + FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE1_A)); params[4] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_0_AND_1)); params[5] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | @@ -576,9 +577,9 @@ int t4vf_get_sge_params(struct adapter *adapter) } params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_INGRESS_RX_THRESHOLD)); + FW_PARAMS_PARAM_XYZ_V(SGE_INGRESS_RX_THRESHOLD_A)); params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_CONM_CTRL)); + FW_PARAMS_PARAM_XYZ_V(SGE_CONM_CTRL_A)); v = t4vf_query_params(adapter, 2, params, vals); if (v) return v; @@ -628,10 +629,10 @@ int t4vf_get_sge_params(struct adapter *adapter) (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * pf); sge_params->sge_vf_eq_qpp = ((sge_params->sge_egress_queues_per_page >> s_qpp) - & QUEUESPERPAGEPF0_MASK); + & QUEUESPERPAGEPF0_M); sge_params->sge_vf_iq_qpp = ((sge_params->sge_ingress_queues_per_page >> s_qpp) - & QUEUESPERPAGEPF0_MASK); + & QUEUESPERPAGEPF0_M); } return 0; -- cgit v1.2.1 From f061de42e6ae697dd22cd0acbfd50fa3c4ecb9b8 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 5 Jan 2015 16:30:44 +0530 Subject: cxgb4/cxgb4vf/csiostor: Cleanup SGE and PCI related register defines This patch cleansup remaining SGE related macros/register defines and all PCI related ones that are defined in t4_regs.h and the affected files. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 68 +-- drivers/net/ethernet/chelsio/cxgb4/sge.c | 78 +-- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 224 ++++---- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 605 ++++++++++++++------- drivers/net/ethernet/chelsio/cxgb4/t4_values.h | 4 + .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 12 +- drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 6 +- 7 files changed, 615 insertions(+), 382 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 5e0d57a7b3b6..16c633f4bf8b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1590,9 +1590,9 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats, collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); data += sizeof(struct queue_port_stats) / sizeof(u64); if (!is_t4(adapter->params.chip)) { - t4_write_reg(adapter, SGE_STAT_CFG, STATSOURCE_T5(7)); - val1 = t4_read_reg(adapter, SGE_STAT_TOTAL); - val2 = t4_read_reg(adapter, SGE_STAT_MATCH); + t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7)); + val1 = t4_read_reg(adapter, SGE_STAT_TOTAL_A); + val2 = t4_read_reg(adapter, SGE_STAT_MATCH_A); *data = val1 - val2; data++; *data = val2; @@ -3601,14 +3601,14 @@ unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo) struct adapter *adap = netdev2adap(dev); u32 v1, v2, lp_count, hp_count; - v1 = t4_read_reg(adap, A_SGE_DBFIFO_STATUS); - v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2); + v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A); + v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A); if (is_t4(adap->params.chip)) { - lp_count = G_LP_COUNT(v1); - hp_count = G_HP_COUNT(v1); + lp_count = LP_COUNT_G(v1); + hp_count = HP_COUNT_G(v1); } else { - lp_count = G_LP_COUNT_T5(v1); - hp_count = G_HP_COUNT_T5(v2); + lp_count = LP_COUNT_T5_G(v1); + hp_count = HP_COUNT_T5_G(v2); } return lpfifo ? lp_count : hp_count; } @@ -3667,14 +3667,14 @@ int cxgb4_flush_eq_cache(struct net_device *dev) int ret; ret = t4_fwaddrspace_write(adap, adap->mbox, - 0xe1000000 + A_SGE_CTXT_CMD, 0x20000000); + 0xe1000000 + SGE_CTXT_CMD_A, 0x20000000); return ret; } EXPORT_SYMBOL(cxgb4_flush_eq_cache); static int read_eq_indices(struct adapter *adap, u16 qid, u16 *pidx, u16 *cidx) { - u32 addr = t4_read_reg(adap, A_SGE_DBQ_CTXT_BADDR) + 24 * qid + 8; + u32 addr = t4_read_reg(adap, SGE_DBQ_CTXT_BADDR_A) + 24 * qid + 8; __be64 indices; int ret; @@ -3728,7 +3728,7 @@ void cxgb4_disable_db_coalescing(struct net_device *dev) struct adapter *adap; adap = netdev2adap(dev); - t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, NOCOALESCE_F, + t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, NOCOALESCE_F, NOCOALESCE_F); } EXPORT_SYMBOL(cxgb4_disable_db_coalescing); @@ -3738,7 +3738,7 @@ void cxgb4_enable_db_coalescing(struct net_device *dev) struct adapter *adap; adap = netdev2adap(dev); - t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, NOCOALESCE_F, 0); + t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, NOCOALESCE_F, 0); } EXPORT_SYMBOL(cxgb4_enable_db_coalescing); @@ -3877,14 +3877,14 @@ static void drain_db_fifo(struct adapter *adap, int usecs) u32 v1, v2, lp_count, hp_count; do { - v1 = t4_read_reg(adap, A_SGE_DBFIFO_STATUS); - v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2); + v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A); + v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A); if (is_t4(adap->params.chip)) { - lp_count = G_LP_COUNT(v1); - hp_count = G_HP_COUNT(v1); + lp_count = LP_COUNT_G(v1); + hp_count = HP_COUNT_G(v1); } else { - lp_count = G_LP_COUNT_T5(v1); - hp_count = G_HP_COUNT_T5(v2); + lp_count = LP_COUNT_T5_G(v1); + hp_count = HP_COUNT_T5_G(v2); } if (lp_count == 0 && hp_count == 0) @@ -4044,7 +4044,7 @@ static void process_db_drop(struct work_struct *work) t4_set_reg_field(adap, 0x10b0, 1<<15, 1<<15); } - t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_DROPPED_DB, 0); + t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, DROPPED_DB_F, 0); } void t4_db_full(struct adapter *adap) @@ -4871,16 +4871,16 @@ static void setup_memwin(struct adapter *adap) mem_win2_base = MEMWIN2_BASE_T5; mem_win2_aperture = MEMWIN2_APERTURE_T5; } - t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0), - mem_win0_base | BIR(0) | - WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); - t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 1), - mem_win1_base | BIR(0) | - WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); - t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2), - mem_win2_base | BIR(0) | - WINDOW(ilog2(mem_win2_aperture) - 10)); - t4_read_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2)); + t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 0), + mem_win0_base | BIR_V(0) | + WINDOW_V(ilog2(MEMWIN0_APERTURE) - 10)); + t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 1), + mem_win1_base | BIR_V(0) | + WINDOW_V(ilog2(MEMWIN1_APERTURE) - 10)); + t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 2), + mem_win2_base | BIR_V(0) | + WINDOW_V(ilog2(mem_win2_aperture) - 10)); + t4_read_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 2)); } static void setup_memwin_rdma(struct adapter *adap) @@ -4894,13 +4894,13 @@ static void setup_memwin_rdma(struct adapter *adap) start += OCQ_WIN_OFFSET(adap->pdev, &adap->vres); sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10; t4_write_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 3), - start | BIR(1) | WINDOW(ilog2(sz_kb))); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 3), + start | BIR_V(1) | WINDOW_V(ilog2(sz_kb))); t4_write_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3), + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3), adap->vres.ocq.start); t4_read_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3)); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3)); } } diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 4449fc7ec14e..d7c301c77060 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2098,7 +2098,7 @@ static irqreturn_t t4_intr_intx(int irq, void *cookie) { struct adapter *adap = cookie; - t4_write_reg(adap, MYPF_REG(PCIE_PF_CLI), 0); + t4_write_reg(adap, MYPF_REG(PCIE_PF_CLI_A), 0); if (t4_slow_intr_handler(adap) | process_intrq(adap)) return IRQ_HANDLED; return IRQ_NONE; /* probably shared interrupt */ @@ -2145,9 +2145,9 @@ static void sge_rx_timer_cb(unsigned long data) } } - t4_write_reg(adap, SGE_DEBUG_INDEX, 13); - idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH); - idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + t4_write_reg(adap, SGE_DEBUG_INDEX_A, 13); + idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH_A); + idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A); for (i = 0; i < 2; i++) { u32 debug0, debug11; @@ -2191,12 +2191,12 @@ static void sge_rx_timer_cb(unsigned long data) /* Read and save the SGE IDMA State and Queue ID information. * We do this every time in case it changes across time ... */ - t4_write_reg(adap, SGE_DEBUG_INDEX, 0); - debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + t4_write_reg(adap, SGE_DEBUG_INDEX_A, 0); + debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A); s->idma_state[i] = (debug0 >> (i * 9)) & 0x3f; - t4_write_reg(adap, SGE_DEBUG_INDEX, 11); - debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + t4_write_reg(adap, SGE_DEBUG_INDEX_A, 11); + debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A); s->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff; CH_WARN(adap, "SGE idma%u, queue%u, maybe stuck state%u %dsecs (debug0=%#x, debug11=%#x)\n", @@ -2826,21 +2826,21 @@ static int t4_sge_init_soft(struct adapter *adap) * Retrieve our RX interrupt holdoff timer values and counter * threshold values from the SGE parameters. */ - timer_value_0_and_1 = t4_read_reg(adap, SGE_TIMER_VALUE_0_AND_1); - timer_value_2_and_3 = t4_read_reg(adap, SGE_TIMER_VALUE_2_AND_3); - timer_value_4_and_5 = t4_read_reg(adap, SGE_TIMER_VALUE_4_AND_5); + timer_value_0_and_1 = t4_read_reg(adap, SGE_TIMER_VALUE_0_AND_1_A); + timer_value_2_and_3 = t4_read_reg(adap, SGE_TIMER_VALUE_2_AND_3_A); + timer_value_4_and_5 = t4_read_reg(adap, SGE_TIMER_VALUE_4_AND_5_A); s->timer_val[0] = core_ticks_to_us(adap, - TIMERVALUE0_GET(timer_value_0_and_1)); + TIMERVALUE0_G(timer_value_0_and_1)); s->timer_val[1] = core_ticks_to_us(adap, - TIMERVALUE1_GET(timer_value_0_and_1)); + TIMERVALUE1_G(timer_value_0_and_1)); s->timer_val[2] = core_ticks_to_us(adap, - TIMERVALUE2_GET(timer_value_2_and_3)); + TIMERVALUE2_G(timer_value_2_and_3)); s->timer_val[3] = core_ticks_to_us(adap, - TIMERVALUE3_GET(timer_value_2_and_3)); + TIMERVALUE3_G(timer_value_2_and_3)); s->timer_val[4] = core_ticks_to_us(adap, - TIMERVALUE4_GET(timer_value_4_and_5)); + TIMERVALUE4_G(timer_value_4_and_5)); s->timer_val[5] = core_ticks_to_us(adap, - TIMERVALUE5_GET(timer_value_4_and_5)); + TIMERVALUE5_G(timer_value_4_and_5)); ingress_rx_threshold = t4_read_reg(adap, SGE_INGRESS_RX_THRESHOLD_A); s->counter_val[0] = THRESHOLD_0_G(ingress_rx_threshold); @@ -2866,21 +2866,21 @@ static int t4_sge_init_hard(struct adapter *adap) * and generate an interrupt when this occurs so we can recover. */ if (is_t4(adap->params.chip)) { - t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS, - V_HP_INT_THRESH(M_HP_INT_THRESH) | - V_LP_INT_THRESH(M_LP_INT_THRESH), - V_HP_INT_THRESH(dbfifo_int_thresh) | - V_LP_INT_THRESH(dbfifo_int_thresh)); + t4_set_reg_field(adap, SGE_DBFIFO_STATUS_A, + HP_INT_THRESH_V(HP_INT_THRESH_M) | + LP_INT_THRESH_V(LP_INT_THRESH_M), + HP_INT_THRESH_V(dbfifo_int_thresh) | + LP_INT_THRESH_V(dbfifo_int_thresh)); } else { - t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS, - V_LP_INT_THRESH_T5(M_LP_INT_THRESH_T5), - V_LP_INT_THRESH_T5(dbfifo_int_thresh)); - t4_set_reg_field(adap, SGE_DBFIFO_STATUS2, - V_HP_INT_THRESH_T5(M_HP_INT_THRESH_T5), - V_HP_INT_THRESH_T5(dbfifo_int_thresh)); + t4_set_reg_field(adap, SGE_DBFIFO_STATUS_A, + LP_INT_THRESH_T5_V(LP_INT_THRESH_T5_M), + LP_INT_THRESH_T5_V(dbfifo_int_thresh)); + t4_set_reg_field(adap, SGE_DBFIFO_STATUS2_A, + HP_INT_THRESH_T5_V(HP_INT_THRESH_T5_M), + HP_INT_THRESH_T5_V(dbfifo_int_thresh)); } - t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_ENABLE_DROP, - F_ENABLE_DROP); + t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, ENABLE_DROP_F, + ENABLE_DROP_F); /* * SGE_FL_BUFFER_SIZE0 (RX_SMALL_PG_BUF) is set up by @@ -2905,15 +2905,15 @@ static int t4_sge_init_hard(struct adapter *adap) THRESHOLD_1_V(s->counter_val[1]) | THRESHOLD_2_V(s->counter_val[2]) | THRESHOLD_3_V(s->counter_val[3])); - t4_write_reg(adap, SGE_TIMER_VALUE_0_AND_1, - TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[0])) | - TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[1]))); - t4_write_reg(adap, SGE_TIMER_VALUE_2_AND_3, - TIMERVALUE2(us_to_core_ticks(adap, s->timer_val[2])) | - TIMERVALUE3(us_to_core_ticks(adap, s->timer_val[3]))); - t4_write_reg(adap, SGE_TIMER_VALUE_4_AND_5, - TIMERVALUE4(us_to_core_ticks(adap, s->timer_val[4])) | - TIMERVALUE5(us_to_core_ticks(adap, s->timer_val[5]))); + t4_write_reg(adap, SGE_TIMER_VALUE_0_AND_1_A, + TIMERVALUE0_V(us_to_core_ticks(adap, s->timer_val[0])) | + TIMERVALUE1_V(us_to_core_ticks(adap, s->timer_val[1]))); + t4_write_reg(adap, SGE_TIMER_VALUE_2_AND_3_A, + TIMERVALUE2_V(us_to_core_ticks(adap, s->timer_val[2])) | + TIMERVALUE3_V(us_to_core_ticks(adap, s->timer_val[3]))); + t4_write_reg(adap, SGE_TIMER_VALUE_4_AND_5_A, + TIMERVALUE4_V(us_to_core_ticks(adap, s->timer_val[4])) | + TIMERVALUE5_V(us_to_core_ticks(adap, s->timer_val[5]))); return 0; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index ac00cab0052b..9f8cd561250a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -150,20 +150,20 @@ void t4_write_indirect(struct adapter *adap, unsigned int addr_reg, */ void t4_hw_pci_read_cfg4(struct adapter *adap, int reg, u32 *val) { - u32 req = ENABLE | FUNCTION(adap->fn) | reg; + u32 req = ENABLE_F | FUNCTION_V(adap->fn) | REGISTER_V(reg); if (is_t4(adap->params.chip)) - req |= F_LOCALCFG; + req |= LOCALCFG_F; - t4_write_reg(adap, PCIE_CFG_SPACE_REQ, req); - *val = t4_read_reg(adap, PCIE_CFG_SPACE_DATA); + t4_write_reg(adap, PCIE_CFG_SPACE_REQ_A, req); + *val = t4_read_reg(adap, PCIE_CFG_SPACE_DATA_A); /* Reset ENABLE to 0 so reads of PCIE_CFG_SPACE_DATA won't cause a * Configuration Space read. (None of the other fields matter when * ENABLE is 0 so a simple register write is easier than a * read-modify-write via t4_set_reg_field().) */ - t4_write_reg(adap, PCIE_CFG_SPACE_REQ, 0); + t4_write_reg(adap, PCIE_CFG_SPACE_REQ_A, 0); } /* @@ -188,8 +188,8 @@ static void t4_report_fw_error(struct adapter *adap) }; u32 pcie_fw; - pcie_fw = t4_read_reg(adap, MA_PCIE_FW); - if (pcie_fw & PCIE_FW_ERR) + pcie_fw = t4_read_reg(adap, PCIE_FW_A); + if (pcie_fw & PCIE_FW_ERR_F) dev_err(adap->pdev_dev, "Firmware reports adapter error: %s\n", reason[PCIE_FW_EVAL_G(pcie_fw)]); } @@ -506,13 +506,13 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, * the address is relative to BAR0. */ mem_reg = t4_read_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, win)); - mem_aperture = 1 << (GET_WINDOW(mem_reg) + 10); - mem_base = GET_PCIEOFST(mem_reg) << 10; + mem_aperture = 1 << (WINDOW_G(mem_reg) + WINDOW_SHIFT_X); + mem_base = PCIEOFST_G(mem_reg) << PCIEOFST_SHIFT_X; if (is_t4(adap->params.chip)) mem_base -= adap->t4_bar0; - win_pf = is_t4(adap->params.chip) ? 0 : V_PFNUM(adap->fn); + win_pf = is_t4(adap->params.chip) ? 0 : PFNUM_V(adap->fn); /* Calculate our initial PCI-E Memory Window Position and Offset into * that Window. @@ -525,10 +525,10 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, * attempt to use the new value.) */ t4_write_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win), + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win), pos | win_pf); t4_read_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win)); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win)); /* Transfer data to/from the adapter as long as there's an integral * number of 32-bit transfers to complete. @@ -553,11 +553,11 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, pos += mem_aperture; offset = 0; t4_write_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, - win), pos | win_pf); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, + win), pos | win_pf); t4_read_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, - win)); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, + win)); } } @@ -1366,95 +1366,97 @@ static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg, static void pcie_intr_handler(struct adapter *adapter) { static const struct intr_info sysbus_intr_info[] = { - { RNPP, "RXNP array parity error", -1, 1 }, - { RPCP, "RXPC array parity error", -1, 1 }, - { RCIP, "RXCIF array parity error", -1, 1 }, - { RCCP, "Rx completions control array parity error", -1, 1 }, - { RFTP, "RXFT array parity error", -1, 1 }, + { RNPP_F, "RXNP array parity error", -1, 1 }, + { RPCP_F, "RXPC array parity error", -1, 1 }, + { RCIP_F, "RXCIF array parity error", -1, 1 }, + { RCCP_F, "Rx completions control array parity error", -1, 1 }, + { RFTP_F, "RXFT array parity error", -1, 1 }, { 0 } }; static const struct intr_info pcie_port_intr_info[] = { - { TPCP, "TXPC array parity error", -1, 1 }, - { TNPP, "TXNP array parity error", -1, 1 }, - { TFTP, "TXFT array parity error", -1, 1 }, - { TCAP, "TXCA array parity error", -1, 1 }, - { TCIP, "TXCIF array parity error", -1, 1 }, - { RCAP, "RXCA array parity error", -1, 1 }, - { OTDD, "outbound request TLP discarded", -1, 1 }, - { RDPE, "Rx data parity error", -1, 1 }, - { TDUE, "Tx uncorrectable data error", -1, 1 }, + { TPCP_F, "TXPC array parity error", -1, 1 }, + { TNPP_F, "TXNP array parity error", -1, 1 }, + { TFTP_F, "TXFT array parity error", -1, 1 }, + { TCAP_F, "TXCA array parity error", -1, 1 }, + { TCIP_F, "TXCIF array parity error", -1, 1 }, + { RCAP_F, "RXCA array parity error", -1, 1 }, + { OTDD_F, "outbound request TLP discarded", -1, 1 }, + { RDPE_F, "Rx data parity error", -1, 1 }, + { TDUE_F, "Tx uncorrectable data error", -1, 1 }, { 0 } }; static const struct intr_info pcie_intr_info[] = { - { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 }, - { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 }, - { MSIDATAPERR, "MSI data parity error", -1, 1 }, - { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, - { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, - { MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, - { MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, - { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 }, - { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 }, - { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, - { CCNTPERR, "PCI CMD channel count parity error", -1, 1 }, - { CREQPERR, "PCI CMD channel request parity error", -1, 1 }, - { CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, - { DCNTPERR, "PCI DMA channel count parity error", -1, 1 }, - { DREQPERR, "PCI DMA channel request parity error", -1, 1 }, - { DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, - { HCNTPERR, "PCI HMA channel count parity error", -1, 1 }, - { HREQPERR, "PCI HMA channel request parity error", -1, 1 }, - { HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, - { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, - { FIDPERR, "PCI FID parity error", -1, 1 }, - { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 }, - { MATAGPERR, "PCI MA tag parity error", -1, 1 }, - { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, - { RXCPLPERR, "PCI Rx completion parity error", -1, 1 }, - { RXWRPERR, "PCI Rx write parity error", -1, 1 }, - { RPLPERR, "PCI replay buffer parity error", -1, 1 }, - { PCIESINT, "PCI core secondary fault", -1, 1 }, - { PCIEPINT, "PCI core primary fault", -1, 1 }, - { UNXSPLCPLERR, "PCI unexpected split completion error", -1, 0 }, + { MSIADDRLPERR_F, "MSI AddrL parity error", -1, 1 }, + { MSIADDRHPERR_F, "MSI AddrH parity error", -1, 1 }, + { MSIDATAPERR_F, "MSI data parity error", -1, 1 }, + { MSIXADDRLPERR_F, "MSI-X AddrL parity error", -1, 1 }, + { MSIXADDRHPERR_F, "MSI-X AddrH parity error", -1, 1 }, + { MSIXDATAPERR_F, "MSI-X data parity error", -1, 1 }, + { MSIXDIPERR_F, "MSI-X DI parity error", -1, 1 }, + { PIOCPLPERR_F, "PCI PIO completion FIFO parity error", -1, 1 }, + { PIOREQPERR_F, "PCI PIO request FIFO parity error", -1, 1 }, + { TARTAGPERR_F, "PCI PCI target tag FIFO parity error", -1, 1 }, + { CCNTPERR_F, "PCI CMD channel count parity error", -1, 1 }, + { CREQPERR_F, "PCI CMD channel request parity error", -1, 1 }, + { CRSPPERR_F, "PCI CMD channel response parity error", -1, 1 }, + { DCNTPERR_F, "PCI DMA channel count parity error", -1, 1 }, + { DREQPERR_F, "PCI DMA channel request parity error", -1, 1 }, + { DRSPPERR_F, "PCI DMA channel response parity error", -1, 1 }, + { HCNTPERR_F, "PCI HMA channel count parity error", -1, 1 }, + { HREQPERR_F, "PCI HMA channel request parity error", -1, 1 }, + { HRSPPERR_F, "PCI HMA channel response parity error", -1, 1 }, + { CFGSNPPERR_F, "PCI config snoop FIFO parity error", -1, 1 }, + { FIDPERR_F, "PCI FID parity error", -1, 1 }, + { INTXCLRPERR_F, "PCI INTx clear parity error", -1, 1 }, + { MATAGPERR_F, "PCI MA tag parity error", -1, 1 }, + { PIOTAGPERR_F, "PCI PIO tag parity error", -1, 1 }, + { RXCPLPERR_F, "PCI Rx completion parity error", -1, 1 }, + { RXWRPERR_F, "PCI Rx write parity error", -1, 1 }, + { RPLPERR_F, "PCI replay buffer parity error", -1, 1 }, + { PCIESINT_F, "PCI core secondary fault", -1, 1 }, + { PCIEPINT_F, "PCI core primary fault", -1, 1 }, + { UNXSPLCPLERR_F, "PCI unexpected split completion error", + -1, 0 }, { 0 } }; static struct intr_info t5_pcie_intr_info[] = { - { MSTGRPPERR, "Master Response Read Queue parity error", + { MSTGRPPERR_F, "Master Response Read Queue parity error", -1, 1 }, - { MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 }, - { MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 }, - { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, - { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, - { MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, - { MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, - { PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error", + { MSTTIMEOUTPERR_F, "Master Timeout FIFO parity error", -1, 1 }, + { MSIXSTIPERR_F, "MSI-X STI SRAM parity error", -1, 1 }, + { MSIXADDRLPERR_F, "MSI-X AddrL parity error", -1, 1 }, + { MSIXADDRHPERR_F, "MSI-X AddrH parity error", -1, 1 }, + { MSIXDATAPERR_F, "MSI-X data parity error", -1, 1 }, + { MSIXDIPERR_F, "MSI-X DI parity error", -1, 1 }, + { PIOCPLGRPPERR_F, "PCI PIO completion Group FIFO parity error", -1, 1 }, - { PIOREQGRPPERR, "PCI PIO request Group FIFO parity error", + { PIOREQGRPPERR_F, "PCI PIO request Group FIFO parity error", -1, 1 }, - { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, - { MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 }, - { CREQPERR, "PCI CMD channel request parity error", -1, 1 }, - { CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, - { DREQWRPERR, "PCI DMA channel write request parity error", + { TARTAGPERR_F, "PCI PCI target tag FIFO parity error", -1, 1 }, + { MSTTAGQPERR_F, "PCI master tag queue parity error", -1, 1 }, + { CREQPERR_F, "PCI CMD channel request parity error", -1, 1 }, + { CRSPPERR_F, "PCI CMD channel response parity error", -1, 1 }, + { DREQWRPERR_F, "PCI DMA channel write request parity error", -1, 1 }, - { DREQPERR, "PCI DMA channel request parity error", -1, 1 }, - { DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, - { HREQWRPERR, "PCI HMA channel count parity error", -1, 1 }, - { HREQPERR, "PCI HMA channel request parity error", -1, 1 }, - { HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, - { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, - { FIDPERR, "PCI FID parity error", -1, 1 }, - { VFIDPERR, "PCI INTx clear parity error", -1, 1 }, - { MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 }, - { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, - { IPRXHDRGRPPERR, "PCI IP Rx header group parity error", + { DREQPERR_F, "PCI DMA channel request parity error", -1, 1 }, + { DRSPPERR_F, "PCI DMA channel response parity error", -1, 1 }, + { HREQWRPERR_F, "PCI HMA channel count parity error", -1, 1 }, + { HREQPERR_F, "PCI HMA channel request parity error", -1, 1 }, + { HRSPPERR_F, "PCI HMA channel response parity error", -1, 1 }, + { CFGSNPPERR_F, "PCI config snoop FIFO parity error", -1, 1 }, + { FIDPERR_F, "PCI FID parity error", -1, 1 }, + { VFIDPERR_F, "PCI INTx clear parity error", -1, 1 }, + { MAGRPPERR_F, "PCI MA group FIFO parity error", -1, 1 }, + { PIOTAGPERR_F, "PCI PIO tag parity error", -1, 1 }, + { IPRXHDRGRPPERR_F, "PCI IP Rx header group parity error", -1, 1 }, - { IPRXDATAGRPPERR, "PCI IP Rx data group parity error", -1, 1 }, - { RPLPERR, "PCI IP replay buffer parity error", -1, 1 }, - { IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 }, - { TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 }, - { READRSPERR, "Outbound read error", -1, 0 }, + { IPRXDATAGRPPERR_F, "PCI IP Rx data group parity error", + -1, 1 }, + { RPLPERR_F, "PCI IP replay buffer parity error", -1, 1 }, + { IPSOTPERR_F, "PCI IP SOT buffer parity error", -1, 1 }, + { TRGT1GRPPERR_F, "PCI TRGT1 group FIFOs parity error", -1, 1 }, + { READRSPERR_F, "Outbound read error", -1, 0 }, { 0 } }; @@ -1462,15 +1464,15 @@ static void pcie_intr_handler(struct adapter *adapter) if (is_t4(adapter->params.chip)) fat = t4_handle_intr_status(adapter, - PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, - sysbus_intr_info) + + PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A, + sysbus_intr_info) + t4_handle_intr_status(adapter, - PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, - pcie_port_intr_info) + - t4_handle_intr_status(adapter, PCIE_INT_CAUSE, + PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS_A, + pcie_port_intr_info) + + t4_handle_intr_status(adapter, PCIE_INT_CAUSE_A, pcie_intr_info); else - fat = t4_handle_intr_status(adapter, PCIE_INT_CAUSE, + fat = t4_handle_intr_status(adapter, PCIE_INT_CAUSE_A, t5_pcie_intr_info); if (fat) @@ -1590,7 +1592,7 @@ static void cim_intr_handler(struct adapter *adapter) int fat; - if (t4_read_reg(adapter, MA_PCIE_FW) & PCIE_FW_ERR) + if (t4_read_reg(adapter, PCIE_FW_A) & PCIE_FW_ERR_F) t4_report_fw_error(adapter); fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE, @@ -2750,9 +2752,9 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state) "IDMA_FL_SEND_COMPLETION_TO_IMSG", }; static const u32 sge_regs[] = { - SGE_DEBUG_DATA_LOW_INDEX_2, - SGE_DEBUG_DATA_LOW_INDEX_3, - SGE_DEBUG_DATA_HIGH_INDEX_10, + SGE_DEBUG_DATA_LOW_INDEX_2_A, + SGE_DEBUG_DATA_LOW_INDEX_3_A, + SGE_DEBUG_DATA_HIGH_INDEX_10_A, }; const char **sge_idma_decode; int sge_idma_decode_nstates; @@ -2819,7 +2821,7 @@ retry: if (ret < 0) { if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0) goto retry; - if (t4_read_reg(adap, MA_PCIE_FW) & PCIE_FW_ERR) + if (t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_ERR_F) t4_report_fw_error(adap); return ret; } @@ -2869,8 +2871,8 @@ retry: * timeout ... and then retry if we haven't exhausted * our retries ... */ - pcie_fw = t4_read_reg(adap, MA_PCIE_FW); - if (!(pcie_fw & (PCIE_FW_ERR|PCIE_FW_INIT))) { + pcie_fw = t4_read_reg(adap, PCIE_FW_A); + if (!(pcie_fw & (PCIE_FW_ERR_F|PCIE_FW_INIT_F))) { if (waiting <= 0) { if (retries-- > 0) goto retry; @@ -2885,9 +2887,9 @@ retry: * report errors preferentially. */ if (state) { - if (pcie_fw & PCIE_FW_ERR) + if (pcie_fw & PCIE_FW_ERR_F) *state = DEV_STATE_ERR; - else if (pcie_fw & PCIE_FW_INIT) + else if (pcie_fw & PCIE_FW_INIT_F) *state = DEV_STATE_INIT; } @@ -2897,7 +2899,7 @@ retry: * for our caller. */ if (master_mbox == PCIE_FW_MASTER_M && - (pcie_fw & PCIE_FW_MASTER_VLD)) + (pcie_fw & PCIE_FW_MASTER_VLD_F)) master_mbox = PCIE_FW_MASTER_G(pcie_fw); break; } @@ -3006,7 +3008,7 @@ static int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force) */ if (ret == 0 || force) { t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, UPCRST); - t4_set_reg_field(adap, PCIE_FW, PCIE_FW_HALT_F, + t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F, PCIE_FW_HALT_F); } @@ -3046,7 +3048,7 @@ static int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset) * doing it automatically, we need to clear the PCIE_FW.HALT * bit. */ - t4_set_reg_field(adap, PCIE_FW, PCIE_FW_HALT_F, 0); + t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F, 0); /* * If we've been given a valid mailbox, first try to get the @@ -3070,7 +3072,7 @@ static int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset) t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, 0); for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) { - if (!(t4_read_reg(adap, PCIE_FW) & PCIE_FW_HALT_F)) + if (!(t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_HALT_F)) return 0; msleep(100); ms += 100; @@ -4146,7 +4148,7 @@ int t4_init_sge_params(struct adapter *adapter) (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * adapter->fn); qpp = t4_read_reg(adapter, SGE_EGRESS_QUEUES_PER_PAGE_PF_A); sge_params->eq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M); - qpp = t4_read_reg(adapter, SGE_INGRESS_QUEUES_PER_PAGE_PF); + qpp = t4_read_reg(adapter, SGE_INGRESS_QUEUES_PER_PAGE_PF_A); sge_params->iq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M); return 0; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 29c09113c13b..9b7382448019 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -369,196 +369,424 @@ #define ENABLE_DROP_V(x) ((x) << ENABLE_DROP_S) #define ENABLE_DROP_F ENABLE_DROP_V(1U) -#define SGE_TIMER_VALUE_0_AND_1 0x10b8 -#define TIMERVALUE0_MASK 0xffff0000U -#define TIMERVALUE0_SHIFT 16 -#define TIMERVALUE0(x) ((x) << TIMERVALUE0_SHIFT) -#define TIMERVALUE0_GET(x) (((x) & TIMERVALUE0_MASK) >> TIMERVALUE0_SHIFT) -#define TIMERVALUE1_MASK 0x0000ffffU -#define TIMERVALUE1_SHIFT 0 -#define TIMERVALUE1(x) ((x) << TIMERVALUE1_SHIFT) -#define TIMERVALUE1_GET(x) (((x) & TIMERVALUE1_MASK) >> TIMERVALUE1_SHIFT) - -#define SGE_TIMER_VALUE_2_AND_3 0x10bc -#define TIMERVALUE2_MASK 0xffff0000U -#define TIMERVALUE2_SHIFT 16 -#define TIMERVALUE2(x) ((x) << TIMERVALUE2_SHIFT) -#define TIMERVALUE2_GET(x) (((x) & TIMERVALUE2_MASK) >> TIMERVALUE2_SHIFT) -#define TIMERVALUE3_MASK 0x0000ffffU -#define TIMERVALUE3_SHIFT 0 -#define TIMERVALUE3(x) ((x) << TIMERVALUE3_SHIFT) -#define TIMERVALUE3_GET(x) (((x) & TIMERVALUE3_MASK) >> TIMERVALUE3_SHIFT) - -#define SGE_TIMER_VALUE_4_AND_5 0x10c0 -#define TIMERVALUE4_MASK 0xffff0000U -#define TIMERVALUE4_SHIFT 16 -#define TIMERVALUE4(x) ((x) << TIMERVALUE4_SHIFT) -#define TIMERVALUE4_GET(x) (((x) & TIMERVALUE4_MASK) >> TIMERVALUE4_SHIFT) -#define TIMERVALUE5_MASK 0x0000ffffU -#define TIMERVALUE5_SHIFT 0 -#define TIMERVALUE5(x) ((x) << TIMERVALUE5_SHIFT) -#define TIMERVALUE5_GET(x) (((x) & TIMERVALUE5_MASK) >> TIMERVALUE5_SHIFT) - -#define SGE_DEBUG_INDEX 0x10cc -#define SGE_DEBUG_DATA_HIGH 0x10d0 -#define SGE_DEBUG_DATA_LOW 0x10d4 -#define SGE_DEBUG_DATA_LOW_INDEX_2 0x12c8 -#define SGE_DEBUG_DATA_LOW_INDEX_3 0x12cc -#define SGE_DEBUG_DATA_HIGH_INDEX_10 0x12a8 -#define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4 +#define SGE_TIMER_VALUE_0_AND_1_A 0x10b8 + +#define TIMERVALUE0_S 16 +#define TIMERVALUE0_M 0xffffU +#define TIMERVALUE0_V(x) ((x) << TIMERVALUE0_S) +#define TIMERVALUE0_G(x) (((x) >> TIMERVALUE0_S) & TIMERVALUE0_M) + +#define TIMERVALUE1_S 0 +#define TIMERVALUE1_M 0xffffU +#define TIMERVALUE1_V(x) ((x) << TIMERVALUE1_S) +#define TIMERVALUE1_G(x) (((x) >> TIMERVALUE1_S) & TIMERVALUE1_M) + +#define SGE_TIMER_VALUE_2_AND_3_A 0x10bc + +#define TIMERVALUE2_S 16 +#define TIMERVALUE2_M 0xffffU +#define TIMERVALUE2_V(x) ((x) << TIMERVALUE2_S) +#define TIMERVALUE2_G(x) (((x) >> TIMERVALUE2_S) & TIMERVALUE2_M) + +#define TIMERVALUE3_S 0 +#define TIMERVALUE3_M 0xffffU +#define TIMERVALUE3_V(x) ((x) << TIMERVALUE3_S) +#define TIMERVALUE3_G(x) (((x) >> TIMERVALUE3_S) & TIMERVALUE3_M) + +#define SGE_TIMER_VALUE_4_AND_5_A 0x10c0 + +#define TIMERVALUE4_S 16 +#define TIMERVALUE4_M 0xffffU +#define TIMERVALUE4_V(x) ((x) << TIMERVALUE4_S) +#define TIMERVALUE4_G(x) (((x) >> TIMERVALUE4_S) & TIMERVALUE4_M) + +#define TIMERVALUE5_S 0 +#define TIMERVALUE5_M 0xffffU +#define TIMERVALUE5_V(x) ((x) << TIMERVALUE5_S) +#define TIMERVALUE5_G(x) (((x) >> TIMERVALUE5_S) & TIMERVALUE5_M) + +#define SGE_DEBUG_INDEX_A 0x10cc +#define SGE_DEBUG_DATA_HIGH_A 0x10d0 +#define SGE_DEBUG_DATA_LOW_A 0x10d4 + +#define SGE_DEBUG_DATA_LOW_INDEX_2_A 0x12c8 +#define SGE_DEBUG_DATA_LOW_INDEX_3_A 0x12cc +#define SGE_DEBUG_DATA_HIGH_INDEX_10_A 0x12a8 + +#define SGE_INGRESS_QUEUES_PER_PAGE_PF_A 0x10f4 #define SGE_INGRESS_QUEUES_PER_PAGE_VF_A 0x10f8 -#define S_HP_INT_THRESH 28 -#define M_HP_INT_THRESH 0xfU -#define V_HP_INT_THRESH(x) ((x) << S_HP_INT_THRESH) -#define S_LP_INT_THRESH_T5 18 -#define V_LP_INT_THRESH_T5(x) ((x) << S_LP_INT_THRESH_T5) -#define M_LP_COUNT_T5 0x3ffffU -#define G_LP_COUNT_T5(x) (((x) >> S_LP_COUNT) & M_LP_COUNT_T5) -#define M_HP_COUNT 0x7ffU -#define S_HP_COUNT 16 -#define G_HP_COUNT(x) (((x) >> S_HP_COUNT) & M_HP_COUNT) -#define S_LP_INT_THRESH 12 -#define M_LP_INT_THRESH 0xfU -#define M_LP_INT_THRESH_T5 0xfffU -#define V_LP_INT_THRESH(x) ((x) << S_LP_INT_THRESH) -#define M_LP_COUNT 0x7ffU -#define S_LP_COUNT 0 -#define G_LP_COUNT(x) (((x) >> S_LP_COUNT) & M_LP_COUNT) -#define A_SGE_DBFIFO_STATUS 0x10a4 - -#define SGE_STAT_TOTAL 0x10e4 -#define SGE_STAT_MATCH 0x10e8 - -#define SGE_STAT_CFG 0x10ec -#define S_STATSOURCE_T5 9 -#define STATSOURCE_T5(x) ((x) << S_STATSOURCE_T5) - -#define SGE_DBFIFO_STATUS2 0x1118 -#define M_HP_COUNT_T5 0x3ffU -#define G_HP_COUNT_T5(x) ((x) & M_HP_COUNT_T5) -#define S_HP_INT_THRESH_T5 10 -#define M_HP_INT_THRESH_T5 0xfU -#define V_HP_INT_THRESH_T5(x) ((x) << S_HP_INT_THRESH_T5) - -#define S_ENABLE_DROP 13 -#define V_ENABLE_DROP(x) ((x) << S_ENABLE_DROP) -#define F_ENABLE_DROP V_ENABLE_DROP(1U) -#define S_DROPPED_DB 0 -#define V_DROPPED_DB(x) ((x) << S_DROPPED_DB) -#define F_DROPPED_DB V_DROPPED_DB(1U) -#define A_SGE_DOORBELL_CONTROL 0x10a8 - -#define A_SGE_CTXT_CMD 0x11fc -#define A_SGE_DBQ_CTXT_BADDR 0x1084 - -#define PCIE_PF_CFG 0x40 -#define AIVEC(x) ((x) << 4) -#define AIVEC_MASK 0x3ffU - -#define PCIE_PF_CLI 0x44 -#define PCIE_INT_CAUSE 0x3004 -#define UNXSPLCPLERR 0x20000000U -#define PCIEPINT 0x10000000U -#define PCIESINT 0x08000000U -#define RPLPERR 0x04000000U -#define RXWRPERR 0x02000000U -#define RXCPLPERR 0x01000000U -#define PIOTAGPERR 0x00800000U -#define MATAGPERR 0x00400000U -#define INTXCLRPERR 0x00200000U -#define FIDPERR 0x00100000U -#define CFGSNPPERR 0x00080000U -#define HRSPPERR 0x00040000U -#define HREQPERR 0x00020000U -#define HCNTPERR 0x00010000U -#define DRSPPERR 0x00008000U -#define DREQPERR 0x00004000U -#define DCNTPERR 0x00002000U -#define CRSPPERR 0x00001000U -#define CREQPERR 0x00000800U -#define CCNTPERR 0x00000400U -#define TARTAGPERR 0x00000200U -#define PIOREQPERR 0x00000100U -#define PIOCPLPERR 0x00000080U -#define MSIXDIPERR 0x00000040U -#define MSIXDATAPERR 0x00000020U -#define MSIXADDRHPERR 0x00000010U -#define MSIXADDRLPERR 0x00000008U -#define MSIDATAPERR 0x00000004U -#define MSIADDRHPERR 0x00000002U -#define MSIADDRLPERR 0x00000001U - -#define READRSPERR 0x20000000U -#define TRGT1GRPPERR 0x10000000U -#define IPSOTPERR 0x08000000U -#define IPRXDATAGRPPERR 0x02000000U -#define IPRXHDRGRPPERR 0x01000000U -#define MAGRPPERR 0x00400000U -#define VFIDPERR 0x00200000U -#define HREQWRPERR 0x00010000U -#define DREQWRPERR 0x00002000U -#define MSTTAGQPERR 0x00000400U -#define PIOREQGRPPERR 0x00000100U -#define PIOCPLGRPPERR 0x00000080U -#define MSIXSTIPERR 0x00000004U -#define MSTTIMEOUTPERR 0x00000002U -#define MSTGRPPERR 0x00000001U - -#define PCIE_NONFAT_ERR 0x3010 -#define PCIE_CFG_SPACE_REQ 0x3060 -#define PCIE_CFG_SPACE_DATA 0x3064 -#define PCIE_MEM_ACCESS_BASE_WIN 0x3068 -#define S_PCIEOFST 10 -#define M_PCIEOFST 0x3fffffU -#define GET_PCIEOFST(x) (((x) >> S_PCIEOFST) & M_PCIEOFST) -#define PCIEOFST_MASK 0xfffffc00U -#define BIR_MASK 0x00000300U -#define BIR_SHIFT 8 -#define BIR(x) ((x) << BIR_SHIFT) -#define WINDOW_MASK 0x000000ffU -#define WINDOW_SHIFT 0 -#define WINDOW(x) ((x) << WINDOW_SHIFT) -#define GET_WINDOW(x) (((x) >> WINDOW_SHIFT) & WINDOW_MASK) -#define PCIE_MEM_ACCESS_OFFSET 0x306c -#define ENABLE (1U << 30) -#define FUNCTION(x) ((x) << 12) -#define F_LOCALCFG (1U << 28) - -#define S_PFNUM 0 -#define V_PFNUM(x) ((x) << S_PFNUM) - -#define PCIE_FW 0x30b8 -#define PCIE_FW_ERR 0x80000000U -#define PCIE_FW_INIT 0x40000000U -#define PCIE_FW_HALT 0x20000000U -#define PCIE_FW_MASTER_VLD 0x00008000U -#define PCIE_FW_MASTER(x) ((x) << 12) -#define PCIE_FW_MASTER_MASK 0x7 -#define PCIE_FW_MASTER_GET(x) (((x) >> 12) & PCIE_FW_MASTER_MASK) - -#define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908 -#define RNPP 0x80000000U -#define RPCP 0x20000000U -#define RCIP 0x08000000U -#define RCCP 0x04000000U -#define RFTP 0x00800000U -#define PTRP 0x00100000U - -#define PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS 0x59a4 -#define TPCP 0x40000000U -#define TNPP 0x20000000U -#define TFTP 0x10000000U -#define TCAP 0x08000000U -#define TCIP 0x04000000U -#define RCAP 0x02000000U -#define PLUP 0x00800000U -#define PLDN 0x00400000U -#define OTDD 0x00200000U -#define GTRP 0x00100000U -#define RDPE 0x00040000U -#define TDCE 0x00020000U -#define TDUE 0x00010000U +#define HP_INT_THRESH_S 28 +#define HP_INT_THRESH_M 0xfU +#define HP_INT_THRESH_V(x) ((x) << HP_INT_THRESH_S) + +#define HP_COUNT_S 16 +#define HP_COUNT_M 0x7ffU +#define HP_COUNT_G(x) (((x) >> HP_COUNT_S) & HP_COUNT_M) + +#define LP_INT_THRESH_S 12 +#define LP_INT_THRESH_M 0xfU +#define LP_INT_THRESH_V(x) ((x) << LP_INT_THRESH_S) + +#define LP_COUNT_S 0 +#define LP_COUNT_M 0x7ffU +#define LP_COUNT_G(x) (((x) >> LP_COUNT_S) & LP_COUNT_M) + +#define LP_INT_THRESH_T5_S 18 +#define LP_INT_THRESH_T5_M 0xfffU +#define LP_INT_THRESH_T5_V(x) ((x) << LP_INT_THRESH_T5_S) + +#define LP_COUNT_T5_S 0 +#define LP_COUNT_T5_M 0x3ffffU +#define LP_COUNT_T5_G(x) (((x) >> LP_COUNT_T5_S) & LP_COUNT_T5_M) + +#define SGE_DOORBELL_CONTROL_A 0x10a8 + +#define SGE_STAT_TOTAL_A 0x10e4 +#define SGE_STAT_MATCH_A 0x10e8 +#define SGE_STAT_CFG_A 0x10ec + +#define STATSOURCE_T5_S 9 +#define STATSOURCE_T5_V(x) ((x) << STATSOURCE_T5_S) + +#define SGE_DBFIFO_STATUS2_A 0x1118 + +#define HP_INT_THRESH_T5_S 10 +#define HP_INT_THRESH_T5_M 0xfU +#define HP_INT_THRESH_T5_V(x) ((x) << HP_INT_THRESH_T5_S) + +#define HP_COUNT_T5_S 0 +#define HP_COUNT_T5_M 0x3ffU +#define HP_COUNT_T5_G(x) (((x) >> HP_COUNT_T5_S) & HP_COUNT_T5_M) + +#define ENABLE_DROP_S 13 +#define ENABLE_DROP_V(x) ((x) << ENABLE_DROP_S) +#define ENABLE_DROP_F ENABLE_DROP_V(1U) + +#define DROPPED_DB_S 0 +#define DROPPED_DB_V(x) ((x) << DROPPED_DB_S) +#define DROPPED_DB_F DROPPED_DB_V(1U) + +#define SGE_CTXT_CMD_A 0x11fc +#define SGE_DBQ_CTXT_BADDR_A 0x1084 + +/* registers for module PCIE */ +#define PCIE_PF_CFG_A 0x40 + +#define AIVEC_S 4 +#define AIVEC_M 0x3ffU +#define AIVEC_V(x) ((x) << AIVEC_S) + +#define PCIE_PF_CLI_A 0x44 +#define PCIE_INT_CAUSE_A 0x3004 + +#define UNXSPLCPLERR_S 29 +#define UNXSPLCPLERR_V(x) ((x) << UNXSPLCPLERR_S) +#define UNXSPLCPLERR_F UNXSPLCPLERR_V(1U) + +#define PCIEPINT_S 28 +#define PCIEPINT_V(x) ((x) << PCIEPINT_S) +#define PCIEPINT_F PCIEPINT_V(1U) + +#define PCIESINT_S 27 +#define PCIESINT_V(x) ((x) << PCIESINT_S) +#define PCIESINT_F PCIESINT_V(1U) + +#define RPLPERR_S 26 +#define RPLPERR_V(x) ((x) << RPLPERR_S) +#define RPLPERR_F RPLPERR_V(1U) + +#define RXWRPERR_S 25 +#define RXWRPERR_V(x) ((x) << RXWRPERR_S) +#define RXWRPERR_F RXWRPERR_V(1U) + +#define RXCPLPERR_S 24 +#define RXCPLPERR_V(x) ((x) << RXCPLPERR_S) +#define RXCPLPERR_F RXCPLPERR_V(1U) + +#define PIOTAGPERR_S 23 +#define PIOTAGPERR_V(x) ((x) << PIOTAGPERR_S) +#define PIOTAGPERR_F PIOTAGPERR_V(1U) + +#define MATAGPERR_S 22 +#define MATAGPERR_V(x) ((x) << MATAGPERR_S) +#define MATAGPERR_F MATAGPERR_V(1U) + +#define INTXCLRPERR_S 21 +#define INTXCLRPERR_V(x) ((x) << INTXCLRPERR_S) +#define INTXCLRPERR_F INTXCLRPERR_V(1U) + +#define FIDPERR_S 20 +#define FIDPERR_V(x) ((x) << FIDPERR_S) +#define FIDPERR_F FIDPERR_V(1U) + +#define CFGSNPPERR_S 19 +#define CFGSNPPERR_V(x) ((x) << CFGSNPPERR_S) +#define CFGSNPPERR_F CFGSNPPERR_V(1U) + +#define HRSPPERR_S 18 +#define HRSPPERR_V(x) ((x) << HRSPPERR_S) +#define HRSPPERR_F HRSPPERR_V(1U) + +#define HREQPERR_S 17 +#define HREQPERR_V(x) ((x) << HREQPERR_S) +#define HREQPERR_F HREQPERR_V(1U) + +#define HCNTPERR_S 16 +#define HCNTPERR_V(x) ((x) << HCNTPERR_S) +#define HCNTPERR_F HCNTPERR_V(1U) + +#define DRSPPERR_S 15 +#define DRSPPERR_V(x) ((x) << DRSPPERR_S) +#define DRSPPERR_F DRSPPERR_V(1U) + +#define DREQPERR_S 14 +#define DREQPERR_V(x) ((x) << DREQPERR_S) +#define DREQPERR_F DREQPERR_V(1U) + +#define DCNTPERR_S 13 +#define DCNTPERR_V(x) ((x) << DCNTPERR_S) +#define DCNTPERR_F DCNTPERR_V(1U) + +#define CRSPPERR_S 12 +#define CRSPPERR_V(x) ((x) << CRSPPERR_S) +#define CRSPPERR_F CRSPPERR_V(1U) + +#define CREQPERR_S 11 +#define CREQPERR_V(x) ((x) << CREQPERR_S) +#define CREQPERR_F CREQPERR_V(1U) + +#define CCNTPERR_S 10 +#define CCNTPERR_V(x) ((x) << CCNTPERR_S) +#define CCNTPERR_F CCNTPERR_V(1U) + +#define TARTAGPERR_S 9 +#define TARTAGPERR_V(x) ((x) << TARTAGPERR_S) +#define TARTAGPERR_F TARTAGPERR_V(1U) + +#define PIOREQPERR_S 8 +#define PIOREQPERR_V(x) ((x) << PIOREQPERR_S) +#define PIOREQPERR_F PIOREQPERR_V(1U) + +#define PIOCPLPERR_S 7 +#define PIOCPLPERR_V(x) ((x) << PIOCPLPERR_S) +#define PIOCPLPERR_F PIOCPLPERR_V(1U) + +#define MSIXDIPERR_S 6 +#define MSIXDIPERR_V(x) ((x) << MSIXDIPERR_S) +#define MSIXDIPERR_F MSIXDIPERR_V(1U) + +#define MSIXDATAPERR_S 5 +#define MSIXDATAPERR_V(x) ((x) << MSIXDATAPERR_S) +#define MSIXDATAPERR_F MSIXDATAPERR_V(1U) + +#define MSIXADDRHPERR_S 4 +#define MSIXADDRHPERR_V(x) ((x) << MSIXADDRHPERR_S) +#define MSIXADDRHPERR_F MSIXADDRHPERR_V(1U) + +#define MSIXADDRLPERR_S 3 +#define MSIXADDRLPERR_V(x) ((x) << MSIXADDRLPERR_S) +#define MSIXADDRLPERR_F MSIXADDRLPERR_V(1U) + +#define MSIDATAPERR_S 2 +#define MSIDATAPERR_V(x) ((x) << MSIDATAPERR_S) +#define MSIDATAPERR_F MSIDATAPERR_V(1U) + +#define MSIADDRHPERR_S 1 +#define MSIADDRHPERR_V(x) ((x) << MSIADDRHPERR_S) +#define MSIADDRHPERR_F MSIADDRHPERR_V(1U) + +#define MSIADDRLPERR_S 0 +#define MSIADDRLPERR_V(x) ((x) << MSIADDRLPERR_S) +#define MSIADDRLPERR_F MSIADDRLPERR_V(1U) + +#define READRSPERR_S 29 +#define READRSPERR_V(x) ((x) << READRSPERR_S) +#define READRSPERR_F READRSPERR_V(1U) + +#define TRGT1GRPPERR_S 28 +#define TRGT1GRPPERR_V(x) ((x) << TRGT1GRPPERR_S) +#define TRGT1GRPPERR_F TRGT1GRPPERR_V(1U) + +#define IPSOTPERR_S 27 +#define IPSOTPERR_V(x) ((x) << IPSOTPERR_S) +#define IPSOTPERR_F IPSOTPERR_V(1U) + +#define IPRETRYPERR_S 26 +#define IPRETRYPERR_V(x) ((x) << IPRETRYPERR_S) +#define IPRETRYPERR_F IPRETRYPERR_V(1U) + +#define IPRXDATAGRPPERR_S 25 +#define IPRXDATAGRPPERR_V(x) ((x) << IPRXDATAGRPPERR_S) +#define IPRXDATAGRPPERR_F IPRXDATAGRPPERR_V(1U) + +#define IPRXHDRGRPPERR_S 24 +#define IPRXHDRGRPPERR_V(x) ((x) << IPRXHDRGRPPERR_S) +#define IPRXHDRGRPPERR_F IPRXHDRGRPPERR_V(1U) + +#define MAGRPPERR_S 22 +#define MAGRPPERR_V(x) ((x) << MAGRPPERR_S) +#define MAGRPPERR_F MAGRPPERR_V(1U) + +#define VFIDPERR_S 21 +#define VFIDPERR_V(x) ((x) << VFIDPERR_S) +#define VFIDPERR_F VFIDPERR_V(1U) + +#define HREQWRPERR_S 16 +#define HREQWRPERR_V(x) ((x) << HREQWRPERR_S) +#define HREQWRPERR_F HREQWRPERR_V(1U) + +#define DREQWRPERR_S 13 +#define DREQWRPERR_V(x) ((x) << DREQWRPERR_S) +#define DREQWRPERR_F DREQWRPERR_V(1U) + +#define CREQRDPERR_S 11 +#define CREQRDPERR_V(x) ((x) << CREQRDPERR_S) +#define CREQRDPERR_F CREQRDPERR_V(1U) + +#define MSTTAGQPERR_S 10 +#define MSTTAGQPERR_V(x) ((x) << MSTTAGQPERR_S) +#define MSTTAGQPERR_F MSTTAGQPERR_V(1U) + +#define PIOREQGRPPERR_S 8 +#define PIOREQGRPPERR_V(x) ((x) << PIOREQGRPPERR_S) +#define PIOREQGRPPERR_F PIOREQGRPPERR_V(1U) + +#define PIOCPLGRPPERR_S 7 +#define PIOCPLGRPPERR_V(x) ((x) << PIOCPLGRPPERR_S) +#define PIOCPLGRPPERR_F PIOCPLGRPPERR_V(1U) + +#define MSIXSTIPERR_S 2 +#define MSIXSTIPERR_V(x) ((x) << MSIXSTIPERR_S) +#define MSIXSTIPERR_F MSIXSTIPERR_V(1U) + +#define MSTTIMEOUTPERR_S 1 +#define MSTTIMEOUTPERR_V(x) ((x) << MSTTIMEOUTPERR_S) +#define MSTTIMEOUTPERR_F MSTTIMEOUTPERR_V(1U) + +#define MSTGRPPERR_S 0 +#define MSTGRPPERR_V(x) ((x) << MSTGRPPERR_S) +#define MSTGRPPERR_F MSTGRPPERR_V(1U) + +#define PCIE_NONFAT_ERR_A 0x3010 +#define PCIE_CFG_SPACE_REQ_A 0x3060 +#define PCIE_CFG_SPACE_DATA_A 0x3064 +#define PCIE_MEM_ACCESS_BASE_WIN_A 0x3068 + +#define PCIEOFST_S 10 +#define PCIEOFST_M 0x3fffffU +#define PCIEOFST_G(x) (((x) >> PCIEOFST_S) & PCIEOFST_M) + +#define BIR_S 8 +#define BIR_M 0x3U +#define BIR_V(x) ((x) << BIR_S) +#define BIR_G(x) (((x) >> BIR_S) & BIR_M) + +#define WINDOW_S 0 +#define WINDOW_M 0xffU +#define WINDOW_V(x) ((x) << WINDOW_S) +#define WINDOW_G(x) (((x) >> WINDOW_S) & WINDOW_M) + +#define PCIE_MEM_ACCESS_OFFSET_A 0x306c + +#define ENABLE_S 30 +#define ENABLE_V(x) ((x) << ENABLE_S) +#define ENABLE_F ENABLE_V(1U) + +#define LOCALCFG_S 28 +#define LOCALCFG_V(x) ((x) << LOCALCFG_S) +#define LOCALCFG_F LOCALCFG_V(1U) + +#define FUNCTION_S 12 +#define FUNCTION_V(x) ((x) << FUNCTION_S) + +#define REGISTER_S 0 +#define REGISTER_V(x) ((x) << REGISTER_S) + +#define PFNUM_S 0 +#define PFNUM_V(x) ((x) << PFNUM_S) + +#define PCIE_FW_A 0x30b8 + +#define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A 0x5908 + +#define RNPP_S 31 +#define RNPP_V(x) ((x) << RNPP_S) +#define RNPP_F RNPP_V(1U) + +#define RPCP_S 29 +#define RPCP_V(x) ((x) << RPCP_S) +#define RPCP_F RPCP_V(1U) + +#define RCIP_S 27 +#define RCIP_V(x) ((x) << RCIP_S) +#define RCIP_F RCIP_V(1U) + +#define RCCP_S 26 +#define RCCP_V(x) ((x) << RCCP_S) +#define RCCP_F RCCP_V(1U) + +#define RFTP_S 23 +#define RFTP_V(x) ((x) << RFTP_S) +#define RFTP_F RFTP_V(1U) + +#define PTRP_S 20 +#define PTRP_V(x) ((x) << PTRP_S) +#define PTRP_F PTRP_V(1U) + +#define PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS_A 0x59a4 + +#define TPCP_S 30 +#define TPCP_V(x) ((x) << TPCP_S) +#define TPCP_F TPCP_V(1U) + +#define TNPP_S 29 +#define TNPP_V(x) ((x) << TNPP_S) +#define TNPP_F TNPP_V(1U) + +#define TFTP_S 28 +#define TFTP_V(x) ((x) << TFTP_S) +#define TFTP_F TFTP_V(1U) + +#define TCAP_S 27 +#define TCAP_V(x) ((x) << TCAP_S) +#define TCAP_F TCAP_V(1U) + +#define TCIP_S 26 +#define TCIP_V(x) ((x) << TCIP_S) +#define TCIP_F TCIP_V(1U) + +#define RCAP_S 25 +#define RCAP_V(x) ((x) << RCAP_S) +#define RCAP_F RCAP_V(1U) + +#define PLUP_S 23 +#define PLUP_V(x) ((x) << PLUP_S) +#define PLUP_F PLUP_V(1U) + +#define PLDN_S 22 +#define PLDN_V(x) ((x) << PLDN_S) +#define PLDN_F PLDN_V(1U) + +#define OTDD_S 21 +#define OTDD_V(x) ((x) << OTDD_S) +#define OTDD_F OTDD_V(1U) + +#define GTRP_S 20 +#define GTRP_V(x) ((x) << GTRP_S) +#define GTRP_F GTRP_V(1U) + +#define RDPE_S 18 +#define RDPE_V(x) ((x) << RDPE_S) +#define RDPE_F RDPE_V(1U) + +#define TDCE_S 17 +#define TDCE_V(x) ((x) << TDCE_S) +#define TDCE_F TDCE_V(1U) + +#define TDUE_S 16 +#define TDUE_V(x) ((x) << TDUE_S) +#define TDUE_F TDUE_V(1U) #define MC_INT_CAUSE 0x7518 #define MC_P_INT_CAUSE 0x41318 @@ -663,7 +891,6 @@ #define MEM_WRAP_CLIENT_NUM_MASK 0x0000000fU #define MEM_WRAP_CLIENT_NUM_SHIFT 0 #define MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT) -#define MA_PCIE_FW 0x30b8 #define MA_PARITY_ERROR_STATUS 0x77f4 #define MA_PARITY_ERROR_STATUS2 0x7804 diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h index 769968644853..ecf7459f8217 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h @@ -78,4 +78,8 @@ #define SGE_UDB_GTS 20 #define SGE_UDB_WCDOORBELL 64 +/* PCI-E definitions */ +#define WINDOW_SHIFT_X 10 +#define PCIEOFST_SHIFT_X 10 + #endif /* __T4_VALUES_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index b645e33bbc8f..aa9f9cd7a3c7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -2294,17 +2294,17 @@ static int adap_init0(struct adapter *adapter) * threshold values from the SGE parameters. */ s->timer_val[0] = core_ticks_to_us(adapter, - TIMERVALUE0_GET(sge_params->sge_timer_value_0_and_1)); + TIMERVALUE0_G(sge_params->sge_timer_value_0_and_1)); s->timer_val[1] = core_ticks_to_us(adapter, - TIMERVALUE1_GET(sge_params->sge_timer_value_0_and_1)); + TIMERVALUE1_G(sge_params->sge_timer_value_0_and_1)); s->timer_val[2] = core_ticks_to_us(adapter, - TIMERVALUE0_GET(sge_params->sge_timer_value_2_and_3)); + TIMERVALUE0_G(sge_params->sge_timer_value_2_and_3)); s->timer_val[3] = core_ticks_to_us(adapter, - TIMERVALUE1_GET(sge_params->sge_timer_value_2_and_3)); + TIMERVALUE1_G(sge_params->sge_timer_value_2_and_3)); s->timer_val[4] = core_ticks_to_us(adapter, - TIMERVALUE0_GET(sge_params->sge_timer_value_4_and_5)); + TIMERVALUE0_G(sge_params->sge_timer_value_4_and_5)); s->timer_val[5] = core_ticks_to_us(adapter, - TIMERVALUE1_GET(sge_params->sge_timer_value_4_and_5)); + TIMERVALUE1_G(sge_params->sge_timer_value_4_and_5)); s->counter_val[0] = THRESHOLD_0_G(sge_params->sge_ingress_rx_threshold); s->counter_val[1] = THRESHOLD_1_G(sge_params->sge_ingress_rx_threshold); diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 6929d1f13c8f..fa60f714e972 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -537,11 +537,11 @@ int t4vf_get_sge_params(struct adapter *adapter) params[3] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE1_A)); params[4] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_0_AND_1)); + FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_0_AND_1_A)); params[5] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_2_AND_3)); + FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_2_AND_3_A)); params[6] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_4_AND_5)); + FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_4_AND_5_A)); v = t4vf_query_params(adapter, 7, params, vals); if (v) return v; -- cgit v1.2.1 From 89c3a86cc7e5e86b841dbd0c2a67ae7899e62fdb Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 5 Jan 2015 16:30:45 +0530 Subject: cxgb4/cxg4vf/csiostor: Cleanup MC, MA and CIM related register defines This patch cleanups all MC, MA and CIM related macros/register defines that are defined in t4_regs.h and the affected files. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 206 +++++----- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 501 ++++++++++++++++------- drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h | 4 +- drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 14 +- 4 files changed, 466 insertions(+), 259 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 9f8cd561250a..c9777e00cea4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -265,8 +265,8 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, u64 res; int i, ms, delay_idx; const __be64 *p = cmd; - u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA); - u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL); + u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA_A); + u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL_A); if ((size & 15) || size > MBOX_LEN) return -EINVAL; @@ -278,9 +278,9 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, if (adap->pdev->error_state != pci_channel_io_normal) return -EIO; - v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); + v = MBOWNER_G(t4_read_reg(adap, ctl_reg)); for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) - v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); + v = MBOWNER_G(t4_read_reg(adap, ctl_reg)); if (v != MBOX_OWNER_DRV) return v ? -EBUSY : -ETIMEDOUT; @@ -288,7 +288,7 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, for (i = 0; i < size; i += 8) t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++)); - t4_write_reg(adap, ctl_reg, MBMSGVALID | MBOWNER(MBOX_OWNER_FW)); + t4_write_reg(adap, ctl_reg, MBMSGVALID_F | MBOWNER_V(MBOX_OWNER_FW)); t4_read_reg(adap, ctl_reg); /* flush write */ delay_idx = 0; @@ -304,8 +304,8 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, mdelay(ms); v = t4_read_reg(adap, ctl_reg); - if (MBOWNER_GET(v) == MBOX_OWNER_DRV) { - if (!(v & MBMSGVALID)) { + if (MBOWNER_G(v) == MBOX_OWNER_DRV) { + if (!(v & MBMSGVALID_F)) { t4_write_reg(adap, ctl_reg, 0); continue; } @@ -351,27 +351,27 @@ int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) u32 mc_bist_status_rdata, mc_bist_data_pattern; if (is_t4(adap->params.chip)) { - mc_bist_cmd = MC_BIST_CMD; - mc_bist_cmd_addr = MC_BIST_CMD_ADDR; - mc_bist_cmd_len = MC_BIST_CMD_LEN; - mc_bist_status_rdata = MC_BIST_STATUS_RDATA; - mc_bist_data_pattern = MC_BIST_DATA_PATTERN; + mc_bist_cmd = MC_BIST_CMD_A; + mc_bist_cmd_addr = MC_BIST_CMD_ADDR_A; + mc_bist_cmd_len = MC_BIST_CMD_LEN_A; + mc_bist_status_rdata = MC_BIST_STATUS_RDATA_A; + mc_bist_data_pattern = MC_BIST_DATA_PATTERN_A; } else { - mc_bist_cmd = MC_REG(MC_P_BIST_CMD, idx); - mc_bist_cmd_addr = MC_REG(MC_P_BIST_CMD_ADDR, idx); - mc_bist_cmd_len = MC_REG(MC_P_BIST_CMD_LEN, idx); - mc_bist_status_rdata = MC_REG(MC_P_BIST_STATUS_RDATA, idx); - mc_bist_data_pattern = MC_REG(MC_P_BIST_DATA_PATTERN, idx); + mc_bist_cmd = MC_REG(MC_P_BIST_CMD_A, idx); + mc_bist_cmd_addr = MC_REG(MC_P_BIST_CMD_ADDR_A, idx); + mc_bist_cmd_len = MC_REG(MC_P_BIST_CMD_LEN_A, idx); + mc_bist_status_rdata = MC_REG(MC_P_BIST_STATUS_RDATA_A, idx); + mc_bist_data_pattern = MC_REG(MC_P_BIST_DATA_PATTERN_A, idx); } - if (t4_read_reg(adap, mc_bist_cmd) & START_BIST) + if (t4_read_reg(adap, mc_bist_cmd) & START_BIST_F) return -EBUSY; t4_write_reg(adap, mc_bist_cmd_addr, addr & ~0x3fU); t4_write_reg(adap, mc_bist_cmd_len, 64); t4_write_reg(adap, mc_bist_data_pattern, 0xc); - t4_write_reg(adap, mc_bist_cmd, BIST_OPCODE(1) | START_BIST | - BIST_CMD_GAP(1)); - i = t4_wait_op_done(adap, mc_bist_cmd, START_BIST, 0, 10, 1); + t4_write_reg(adap, mc_bist_cmd, BIST_OPCODE_V(1) | START_BIST_F | + BIST_CMD_GAP_V(1)); + i = t4_wait_op_done(adap, mc_bist_cmd, START_BIST_F, 0, 10, 1); if (i) return i; @@ -404,31 +404,31 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) u32 edc_bist_cmd_data_pattern, edc_bist_status_rdata; if (is_t4(adap->params.chip)) { - edc_bist_cmd = EDC_REG(EDC_BIST_CMD, idx); - edc_bist_cmd_addr = EDC_REG(EDC_BIST_CMD_ADDR, idx); - edc_bist_cmd_len = EDC_REG(EDC_BIST_CMD_LEN, idx); - edc_bist_cmd_data_pattern = EDC_REG(EDC_BIST_DATA_PATTERN, - idx); - edc_bist_status_rdata = EDC_REG(EDC_BIST_STATUS_RDATA, + edc_bist_cmd = EDC_REG(EDC_BIST_CMD_A, idx); + edc_bist_cmd_addr = EDC_REG(EDC_BIST_CMD_ADDR_A, idx); + edc_bist_cmd_len = EDC_REG(EDC_BIST_CMD_LEN_A, idx); + edc_bist_cmd_data_pattern = EDC_REG(EDC_BIST_DATA_PATTERN_A, idx); + edc_bist_status_rdata = EDC_REG(EDC_BIST_STATUS_RDATA_A, + idx); } else { - edc_bist_cmd = EDC_REG_T5(EDC_H_BIST_CMD, idx); - edc_bist_cmd_addr = EDC_REG_T5(EDC_H_BIST_CMD_ADDR, idx); - edc_bist_cmd_len = EDC_REG_T5(EDC_H_BIST_CMD_LEN, idx); + edc_bist_cmd = EDC_REG_T5(EDC_H_BIST_CMD_A, idx); + edc_bist_cmd_addr = EDC_REG_T5(EDC_H_BIST_CMD_ADDR_A, idx); + edc_bist_cmd_len = EDC_REG_T5(EDC_H_BIST_CMD_LEN_A, idx); edc_bist_cmd_data_pattern = - EDC_REG_T5(EDC_H_BIST_DATA_PATTERN, idx); + EDC_REG_T5(EDC_H_BIST_DATA_PATTERN_A, idx); edc_bist_status_rdata = - EDC_REG_T5(EDC_H_BIST_STATUS_RDATA, idx); + EDC_REG_T5(EDC_H_BIST_STATUS_RDATA_A, idx); } - if (t4_read_reg(adap, edc_bist_cmd) & START_BIST) + if (t4_read_reg(adap, edc_bist_cmd) & START_BIST_F) return -EBUSY; t4_write_reg(adap, edc_bist_cmd_addr, addr & ~0x3fU); t4_write_reg(adap, edc_bist_cmd_len, 64); t4_write_reg(adap, edc_bist_cmd_data_pattern, 0xc); t4_write_reg(adap, edc_bist_cmd, - BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST); - i = t4_wait_op_done(adap, edc_bist_cmd, START_BIST, 0, 10, 1); + BIST_OPCODE_V(1) | BIST_CMD_GAP_V(1) | START_BIST_F); + i = t4_wait_op_done(adap, edc_bist_cmd, START_BIST_F, 0, 10, 1); if (i) return i; @@ -1543,50 +1543,55 @@ static void sge_intr_handler(struct adapter *adapter) t4_fatal_err(adapter); } +#define CIM_OBQ_INTR (OBQULP0PARERR_F | OBQULP1PARERR_F | OBQULP2PARERR_F |\ + OBQULP3PARERR_F | OBQSGEPARERR_F | OBQNCSIPARERR_F) +#define CIM_IBQ_INTR (IBQTP0PARERR_F | IBQTP1PARERR_F | IBQULPPARERR_F |\ + IBQSGEHIPARERR_F | IBQSGELOPARERR_F | IBQNCSIPARERR_F) + /* * CIM interrupt handler. */ static void cim_intr_handler(struct adapter *adapter) { static const struct intr_info cim_intr_info[] = { - { PREFDROPINT, "CIM control register prefetch drop", -1, 1 }, - { OBQPARERR, "CIM OBQ parity error", -1, 1 }, - { IBQPARERR, "CIM IBQ parity error", -1, 1 }, - { MBUPPARERR, "CIM mailbox uP parity error", -1, 1 }, - { MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 }, - { TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 }, - { TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 }, + { PREFDROPINT_F, "CIM control register prefetch drop", -1, 1 }, + { CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 }, + { CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 }, + { MBUPPARERR_F, "CIM mailbox uP parity error", -1, 1 }, + { MBHOSTPARERR_F, "CIM mailbox host parity error", -1, 1 }, + { TIEQINPARERRINT_F, "CIM TIEQ outgoing parity error", -1, 1 }, + { TIEQOUTPARERRINT_F, "CIM TIEQ incoming parity error", -1, 1 }, { 0 } }; static const struct intr_info cim_upintr_info[] = { - { RSVDSPACEINT, "CIM reserved space access", -1, 1 }, - { ILLTRANSINT, "CIM illegal transaction", -1, 1 }, - { ILLWRINT, "CIM illegal write", -1, 1 }, - { ILLRDINT, "CIM illegal read", -1, 1 }, - { ILLRDBEINT, "CIM illegal read BE", -1, 1 }, - { ILLWRBEINT, "CIM illegal write BE", -1, 1 }, - { SGLRDBOOTINT, "CIM single read from boot space", -1, 1 }, - { SGLWRBOOTINT, "CIM single write to boot space", -1, 1 }, - { BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, - { SGLRDFLASHINT, "CIM single read from flash space", -1, 1 }, - { SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, - { BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, - { SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 }, - { SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 }, - { BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 }, - { BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 }, - { SGLRDCTLINT , "CIM single read from CTL space", -1, 1 }, - { SGLWRCTLINT , "CIM single write to CTL space", -1, 1 }, - { BLKRDCTLINT , "CIM block read from CTL space", -1, 1 }, - { BLKWRCTLINT , "CIM block write to CTL space", -1, 1 }, - { SGLRDPLINT , "CIM single read from PL space", -1, 1 }, - { SGLWRPLINT , "CIM single write to PL space", -1, 1 }, - { BLKRDPLINT , "CIM block read from PL space", -1, 1 }, - { BLKWRPLINT , "CIM block write to PL space", -1, 1 }, - { REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 }, - { RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 }, - { TIMEOUTINT , "CIM PIF timeout", -1, 1 }, - { TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 }, + { RSVDSPACEINT_F, "CIM reserved space access", -1, 1 }, + { ILLTRANSINT_F, "CIM illegal transaction", -1, 1 }, + { ILLWRINT_F, "CIM illegal write", -1, 1 }, + { ILLRDINT_F, "CIM illegal read", -1, 1 }, + { ILLRDBEINT_F, "CIM illegal read BE", -1, 1 }, + { ILLWRBEINT_F, "CIM illegal write BE", -1, 1 }, + { SGLRDBOOTINT_F, "CIM single read from boot space", -1, 1 }, + { SGLWRBOOTINT_F, "CIM single write to boot space", -1, 1 }, + { BLKWRBOOTINT_F, "CIM block write to boot space", -1, 1 }, + { SGLRDFLASHINT_F, "CIM single read from flash space", -1, 1 }, + { SGLWRFLASHINT_F, "CIM single write to flash space", -1, 1 }, + { BLKWRFLASHINT_F, "CIM block write to flash space", -1, 1 }, + { SGLRDEEPROMINT_F, "CIM single EEPROM read", -1, 1 }, + { SGLWREEPROMINT_F, "CIM single EEPROM write", -1, 1 }, + { BLKRDEEPROMINT_F, "CIM block EEPROM read", -1, 1 }, + { BLKWREEPROMINT_F, "CIM block EEPROM write", -1, 1 }, + { SGLRDCTLINT_F, "CIM single read from CTL space", -1, 1 }, + { SGLWRCTLINT_F, "CIM single write to CTL space", -1, 1 }, + { BLKRDCTLINT_F, "CIM block read from CTL space", -1, 1 }, + { BLKWRCTLINT_F, "CIM block write to CTL space", -1, 1 }, + { SGLRDPLINT_F, "CIM single read from PL space", -1, 1 }, + { SGLWRPLINT_F, "CIM single write to PL space", -1, 1 }, + { BLKRDPLINT_F, "CIM block read from PL space", -1, 1 }, + { BLKWRPLINT_F, "CIM block write to PL space", -1, 1 }, + { REQOVRLOOKUPINT_F, "CIM request FIFO overwrite", -1, 1 }, + { RSPOVRLOOKUPINT_F, "CIM response FIFO overwrite", -1, 1 }, + { TIMEOUTINT_F, "CIM PIF timeout", -1, 1 }, + { TIMEOUTMAINT_F, "CIM PIF MA timeout", -1, 1 }, { 0 } }; @@ -1595,9 +1600,9 @@ static void cim_intr_handler(struct adapter *adapter) if (t4_read_reg(adapter, PCIE_FW_A) & PCIE_FW_ERR_F) t4_report_fw_error(adapter); - fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE, + fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE_A, cim_intr_info) + - t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE, + t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE_A, cim_upintr_info); if (fat) t4_fatal_err(adapter); @@ -1786,7 +1791,8 @@ static void mps_intr_handler(struct adapter *adapter) t4_fatal_err(adapter); } -#define MEM_INT_MASK (PERR_INT_CAUSE | ECC_CE_INT_CAUSE | ECC_UE_INT_CAUSE) +#define MEM_INT_MASK (PERR_INT_CAUSE_F | ECC_CE_INT_CAUSE_F | \ + ECC_UE_INT_CAUSE_F) /* * EDC/MC interrupt handler. @@ -1798,40 +1804,40 @@ static void mem_intr_handler(struct adapter *adapter, int idx) unsigned int addr, cnt_addr, v; if (idx <= MEM_EDC1) { - addr = EDC_REG(EDC_INT_CAUSE, idx); - cnt_addr = EDC_REG(EDC_ECC_STATUS, idx); + addr = EDC_REG(EDC_INT_CAUSE_A, idx); + cnt_addr = EDC_REG(EDC_ECC_STATUS_A, idx); } else if (idx == MEM_MC) { if (is_t4(adapter->params.chip)) { - addr = MC_INT_CAUSE; - cnt_addr = MC_ECC_STATUS; + addr = MC_INT_CAUSE_A; + cnt_addr = MC_ECC_STATUS_A; } else { - addr = MC_P_INT_CAUSE; - cnt_addr = MC_P_ECC_STATUS; + addr = MC_P_INT_CAUSE_A; + cnt_addr = MC_P_ECC_STATUS_A; } } else { - addr = MC_REG(MC_P_INT_CAUSE, 1); - cnt_addr = MC_REG(MC_P_ECC_STATUS, 1); + addr = MC_REG(MC_P_INT_CAUSE_A, 1); + cnt_addr = MC_REG(MC_P_ECC_STATUS_A, 1); } v = t4_read_reg(adapter, addr) & MEM_INT_MASK; - if (v & PERR_INT_CAUSE) + if (v & PERR_INT_CAUSE_F) dev_alert(adapter->pdev_dev, "%s FIFO parity error\n", name[idx]); - if (v & ECC_CE_INT_CAUSE) { - u32 cnt = ECC_CECNT_GET(t4_read_reg(adapter, cnt_addr)); + if (v & ECC_CE_INT_CAUSE_F) { + u32 cnt = ECC_CECNT_G(t4_read_reg(adapter, cnt_addr)); - t4_write_reg(adapter, cnt_addr, ECC_CECNT_MASK); + t4_write_reg(adapter, cnt_addr, ECC_CECNT_V(ECC_CECNT_M)); if (printk_ratelimit()) dev_warn(adapter->pdev_dev, "%u %s correctable ECC data error%s\n", cnt, name[idx], cnt > 1 ? "s" : ""); } - if (v & ECC_UE_INT_CAUSE) + if (v & ECC_UE_INT_CAUSE_F) dev_alert(adapter->pdev_dev, "%s uncorrectable ECC data error\n", name[idx]); t4_write_reg(adapter, addr, v); - if (v & (PERR_INT_CAUSE | ECC_UE_INT_CAUSE)) + if (v & (PERR_INT_CAUSE_F | ECC_UE_INT_CAUSE_F)) t4_fatal_err(adapter); } @@ -1840,26 +1846,26 @@ static void mem_intr_handler(struct adapter *adapter, int idx) */ static void ma_intr_handler(struct adapter *adap) { - u32 v, status = t4_read_reg(adap, MA_INT_CAUSE); + u32 v, status = t4_read_reg(adap, MA_INT_CAUSE_A); - if (status & MEM_PERR_INT_CAUSE) { + if (status & MEM_PERR_INT_CAUSE_F) { dev_alert(adap->pdev_dev, "MA parity error, parity status %#x\n", - t4_read_reg(adap, MA_PARITY_ERROR_STATUS)); + t4_read_reg(adap, MA_PARITY_ERROR_STATUS1_A)); if (is_t5(adap->params.chip)) dev_alert(adap->pdev_dev, "MA parity error, parity status %#x\n", t4_read_reg(adap, - MA_PARITY_ERROR_STATUS2)); + MA_PARITY_ERROR_STATUS2_A)); } - if (status & MEM_WRAP_INT_CAUSE) { - v = t4_read_reg(adap, MA_INT_WRAP_STATUS); + if (status & MEM_WRAP_INT_CAUSE_F) { + v = t4_read_reg(adap, MA_INT_WRAP_STATUS_A); dev_alert(adap->pdev_dev, "MA address wrap-around error by " "client %u to address %#x\n", - MEM_WRAP_CLIENT_NUM_GET(v), - MEM_WRAP_ADDRESS_GET(v) << 4); + MEM_WRAP_CLIENT_NUM_G(v), + MEM_WRAP_ADDRESS_G(v) << 4); } - t4_write_reg(adap, MA_INT_CAUSE, status); + t4_write_reg(adap, MA_INT_CAUSE_A, status); t4_fatal_err(adap); } @@ -3007,7 +3013,7 @@ static int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force) * rather than a RESET ... if it's new enough to understand that ... */ if (ret == 0 || force) { - t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, UPCRST); + t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, UPCRST_F); t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F, PCIE_FW_HALT_F); } @@ -3058,7 +3064,7 @@ static int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset) * hitting the chip with a hammer. */ if (mbox <= PCIE_FW_MASTER_M) { - t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, 0); + t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0); msleep(100); if (t4_fw_reset(adap, mbox, PIORST | PIORSTMODE) == 0) @@ -3070,7 +3076,7 @@ static int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset) } else { int ms; - t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, 0); + t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0); for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) { if (!(t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_HALT_F)) return 0; @@ -3973,7 +3979,7 @@ static int get_flash_params(struct adapter *adap) return -EINVAL; adap->params.sf_size = 1 << info; adap->params.sf_fw_start = - t4_read_reg(adap, CIM_BOOT_CFG) & BOOTADDR_MASK; + t4_read_reg(adap, CIM_BOOT_CFG_A) & BOOTADDR_M; if (adap->params.sf_size < FLASH_MIN_SIZE) dev_warn(adap->pdev_dev, "WARNING!!! FLASH size %#x < %#x!!!\n", diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 9b7382448019..4b6681812b8a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -788,41 +788,54 @@ #define TDUE_V(x) ((x) << TDUE_S) #define TDUE_F TDUE_V(1U) -#define MC_INT_CAUSE 0x7518 -#define MC_P_INT_CAUSE 0x41318 -#define ECC_UE_INT_CAUSE 0x00000004U -#define ECC_CE_INT_CAUSE 0x00000002U -#define PERR_INT_CAUSE 0x00000001U - -#define MC_ECC_STATUS 0x751c -#define MC_P_ECC_STATUS 0x4131c -#define ECC_CECNT_MASK 0xffff0000U -#define ECC_CECNT_SHIFT 16 -#define ECC_CECNT(x) ((x) << ECC_CECNT_SHIFT) -#define ECC_CECNT_GET(x) (((x) & ECC_CECNT_MASK) >> ECC_CECNT_SHIFT) -#define ECC_UECNT_MASK 0x0000ffffU -#define ECC_UECNT_SHIFT 0 -#define ECC_UECNT(x) ((x) << ECC_UECNT_SHIFT) -#define ECC_UECNT_GET(x) (((x) & ECC_UECNT_MASK) >> ECC_UECNT_SHIFT) - -#define MC_BIST_CMD 0x7600 -#define START_BIST 0x80000000U -#define BIST_CMD_GAP_MASK 0x0000ff00U -#define BIST_CMD_GAP_SHIFT 8 -#define BIST_CMD_GAP(x) ((x) << BIST_CMD_GAP_SHIFT) -#define BIST_OPCODE_MASK 0x00000003U -#define BIST_OPCODE_SHIFT 0 -#define BIST_OPCODE(x) ((x) << BIST_OPCODE_SHIFT) - -#define MC_BIST_CMD_ADDR 0x7604 -#define MC_BIST_CMD_LEN 0x7608 -#define MC_BIST_DATA_PATTERN 0x760c -#define BIST_DATA_TYPE_MASK 0x0000000fU -#define BIST_DATA_TYPE_SHIFT 0 -#define BIST_DATA_TYPE(x) ((x) << BIST_DATA_TYPE_SHIFT) - -#define MC_BIST_STATUS_RDATA 0x7688 +/* registers for module MC */ +#define MC_INT_CAUSE_A 0x7518 +#define MC_P_INT_CAUSE_A 0x41318 +#define ECC_UE_INT_CAUSE_S 2 +#define ECC_UE_INT_CAUSE_V(x) ((x) << ECC_UE_INT_CAUSE_S) +#define ECC_UE_INT_CAUSE_F ECC_UE_INT_CAUSE_V(1U) + +#define ECC_CE_INT_CAUSE_S 1 +#define ECC_CE_INT_CAUSE_V(x) ((x) << ECC_CE_INT_CAUSE_S) +#define ECC_CE_INT_CAUSE_F ECC_CE_INT_CAUSE_V(1U) + +#define PERR_INT_CAUSE_S 0 +#define PERR_INT_CAUSE_V(x) ((x) << PERR_INT_CAUSE_S) +#define PERR_INT_CAUSE_F PERR_INT_CAUSE_V(1U) + +#define MC_ECC_STATUS_A 0x751c +#define MC_P_ECC_STATUS_A 0x4131c + +#define ECC_CECNT_S 16 +#define ECC_CECNT_M 0xffffU +#define ECC_CECNT_V(x) ((x) << ECC_CECNT_S) +#define ECC_CECNT_G(x) (((x) >> ECC_CECNT_S) & ECC_CECNT_M) + +#define ECC_UECNT_S 0 +#define ECC_UECNT_M 0xffffU +#define ECC_UECNT_V(x) ((x) << ECC_UECNT_S) +#define ECC_UECNT_G(x) (((x) >> ECC_UECNT_S) & ECC_UECNT_M) + +#define MC_BIST_CMD_A 0x7600 + +#define START_BIST_S 31 +#define START_BIST_V(x) ((x) << START_BIST_S) +#define START_BIST_F START_BIST_V(1U) + +#define BIST_CMD_GAP_S 8 +#define BIST_CMD_GAP_V(x) ((x) << BIST_CMD_GAP_S) + +#define BIST_OPCODE_S 0 +#define BIST_OPCODE_V(x) ((x) << BIST_OPCODE_S) + +#define MC_BIST_CMD_ADDR_A 0x7604 +#define MC_BIST_CMD_LEN_A 0x7608 +#define MC_BIST_DATA_PATTERN_A 0x760c + +#define MC_BIST_STATUS_RDATA_A 0x7688 + +/* registers for module MA */ #define MA_EDRAM0_BAR_A 0x77c0 #define EDRAM0_SIZE_S 0 @@ -880,109 +893,294 @@ #define EXT_MEM0_ENABLE_V(x) ((x) << EXT_MEM0_ENABLE_S) #define EXT_MEM0_ENABLE_F EXT_MEM0_ENABLE_V(1U) -#define MA_INT_CAUSE 0x77e0 -#define MEM_PERR_INT_CAUSE 0x00000002U -#define MEM_WRAP_INT_CAUSE 0x00000001U - -#define MA_INT_WRAP_STATUS 0x77e4 -#define MEM_WRAP_ADDRESS_MASK 0xfffffff0U -#define MEM_WRAP_ADDRESS_SHIFT 4 -#define MEM_WRAP_ADDRESS_GET(x) (((x) & MEM_WRAP_ADDRESS_MASK) >> MEM_WRAP_ADDRESS_SHIFT) -#define MEM_WRAP_CLIENT_NUM_MASK 0x0000000fU -#define MEM_WRAP_CLIENT_NUM_SHIFT 0 -#define MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT) -#define MA_PARITY_ERROR_STATUS 0x77f4 -#define MA_PARITY_ERROR_STATUS2 0x7804 - -#define EDC_0_BASE_ADDR 0x7900 - -#define EDC_BIST_CMD 0x7904 -#define EDC_BIST_CMD_ADDR 0x7908 -#define EDC_BIST_CMD_LEN 0x790c -#define EDC_BIST_DATA_PATTERN 0x7910 -#define EDC_BIST_STATUS_RDATA 0x7928 -#define EDC_INT_CAUSE 0x7978 -#define ECC_UE_PAR 0x00000020U -#define ECC_CE_PAR 0x00000010U -#define PERR_PAR_CAUSE 0x00000008U - -#define EDC_ECC_STATUS 0x797c - -#define EDC_1_BASE_ADDR 0x7980 - -#define CIM_BOOT_CFG 0x7b00 -#define BOOTADDR_MASK 0xffffff00U -#define UPCRST 0x1U - -#define CIM_PF_MAILBOX_DATA 0x240 -#define CIM_PF_MAILBOX_CTRL 0x280 -#define MBMSGVALID 0x00000008U -#define MBINTREQ 0x00000004U -#define MBOWNER_MASK 0x00000003U -#define MBOWNER_SHIFT 0 -#define MBOWNER(x) ((x) << MBOWNER_SHIFT) -#define MBOWNER_GET(x) (((x) & MBOWNER_MASK) >> MBOWNER_SHIFT) - -#define CIM_PF_HOST_INT_ENABLE 0x288 -#define MBMSGRDYINTEN(x) ((x) << 19) - -#define CIM_PF_HOST_INT_CAUSE 0x28c -#define MBMSGRDYINT 0x00080000U - -#define CIM_HOST_INT_CAUSE 0x7b2c -#define TIEQOUTPARERRINT 0x00100000U -#define TIEQINPARERRINT 0x00080000U -#define MBHOSTPARERR 0x00040000U -#define MBUPPARERR 0x00020000U -#define IBQPARERR 0x0001f800U -#define IBQTP0PARERR 0x00010000U -#define IBQTP1PARERR 0x00008000U -#define IBQULPPARERR 0x00004000U -#define IBQSGELOPARERR 0x00002000U -#define IBQSGEHIPARERR 0x00001000U -#define IBQNCSIPARERR 0x00000800U -#define OBQPARERR 0x000007e0U -#define OBQULP0PARERR 0x00000400U -#define OBQULP1PARERR 0x00000200U -#define OBQULP2PARERR 0x00000100U -#define OBQULP3PARERR 0x00000080U -#define OBQSGEPARERR 0x00000040U -#define OBQNCSIPARERR 0x00000020U -#define PREFDROPINT 0x00000002U -#define UPACCNONZERO 0x00000001U - -#define CIM_HOST_UPACC_INT_CAUSE 0x7b34 -#define EEPROMWRINT 0x40000000U -#define TIMEOUTMAINT 0x20000000U -#define TIMEOUTINT 0x10000000U -#define RSPOVRLOOKUPINT 0x08000000U -#define REQOVRLOOKUPINT 0x04000000U -#define BLKWRPLINT 0x02000000U -#define BLKRDPLINT 0x01000000U -#define SGLWRPLINT 0x00800000U -#define SGLRDPLINT 0x00400000U -#define BLKWRCTLINT 0x00200000U -#define BLKRDCTLINT 0x00100000U -#define SGLWRCTLINT 0x00080000U -#define SGLRDCTLINT 0x00040000U -#define BLKWREEPROMINT 0x00020000U -#define BLKRDEEPROMINT 0x00010000U -#define SGLWREEPROMINT 0x00008000U -#define SGLRDEEPROMINT 0x00004000U -#define BLKWRFLASHINT 0x00002000U -#define BLKRDFLASHINT 0x00001000U -#define SGLWRFLASHINT 0x00000800U -#define SGLRDFLASHINT 0x00000400U -#define BLKWRBOOTINT 0x00000200U -#define BLKRDBOOTINT 0x00000100U -#define SGLWRBOOTINT 0x00000080U -#define SGLRDBOOTINT 0x00000040U -#define ILLWRBEINT 0x00000020U -#define ILLRDBEINT 0x00000010U -#define ILLRDINT 0x00000008U -#define ILLWRINT 0x00000004U -#define ILLTRANSINT 0x00000002U -#define RSVDSPACEINT 0x00000001U +#define MA_INT_CAUSE_A 0x77e0 + +#define MEM_PERR_INT_CAUSE_S 1 +#define MEM_PERR_INT_CAUSE_V(x) ((x) << MEM_PERR_INT_CAUSE_S) +#define MEM_PERR_INT_CAUSE_F MEM_PERR_INT_CAUSE_V(1U) + +#define MEM_WRAP_INT_CAUSE_S 0 +#define MEM_WRAP_INT_CAUSE_V(x) ((x) << MEM_WRAP_INT_CAUSE_S) +#define MEM_WRAP_INT_CAUSE_F MEM_WRAP_INT_CAUSE_V(1U) + +#define MA_INT_WRAP_STATUS_A 0x77e4 + +#define MEM_WRAP_ADDRESS_S 4 +#define MEM_WRAP_ADDRESS_M 0xfffffffU +#define MEM_WRAP_ADDRESS_G(x) (((x) >> MEM_WRAP_ADDRESS_S) & MEM_WRAP_ADDRESS_M) + +#define MEM_WRAP_CLIENT_NUM_S 0 +#define MEM_WRAP_CLIENT_NUM_M 0xfU +#define MEM_WRAP_CLIENT_NUM_G(x) \ + (((x) >> MEM_WRAP_CLIENT_NUM_S) & MEM_WRAP_CLIENT_NUM_M) + +#define MA_PARITY_ERROR_STATUS_A 0x77f4 +#define MA_PARITY_ERROR_STATUS1_A 0x77f4 +#define MA_PARITY_ERROR_STATUS2_A 0x7804 + +/* registers for module EDC_0 */ +#define EDC_0_BASE_ADDR 0x7900 + +#define EDC_BIST_CMD_A 0x7904 +#define EDC_BIST_CMD_ADDR_A 0x7908 +#define EDC_BIST_CMD_LEN_A 0x790c +#define EDC_BIST_DATA_PATTERN_A 0x7910 +#define EDC_BIST_STATUS_RDATA_A 0x7928 +#define EDC_INT_CAUSE_A 0x7978 + +#define ECC_UE_PAR_S 5 +#define ECC_UE_PAR_V(x) ((x) << ECC_UE_PAR_S) +#define ECC_UE_PAR_F ECC_UE_PAR_V(1U) + +#define ECC_CE_PAR_S 4 +#define ECC_CE_PAR_V(x) ((x) << ECC_CE_PAR_S) +#define ECC_CE_PAR_F ECC_CE_PAR_V(1U) + +#define PERR_PAR_CAUSE_S 3 +#define PERR_PAR_CAUSE_V(x) ((x) << PERR_PAR_CAUSE_S) +#define PERR_PAR_CAUSE_F PERR_PAR_CAUSE_V(1U) + +#define EDC_ECC_STATUS_A 0x797c + +/* registers for module EDC_1 */ +#define EDC_1_BASE_ADDR 0x7980 + +/* registers for module CIM */ +#define CIM_BOOT_CFG_A 0x7b00 + +#define BOOTADDR_M 0xffffff00U + +#define UPCRST_S 0 +#define UPCRST_V(x) ((x) << UPCRST_S) +#define UPCRST_F UPCRST_V(1U) + +#define CIM_PF_MAILBOX_DATA_A 0x240 +#define CIM_PF_MAILBOX_CTRL_A 0x280 + +#define MBMSGVALID_S 3 +#define MBMSGVALID_V(x) ((x) << MBMSGVALID_S) +#define MBMSGVALID_F MBMSGVALID_V(1U) + +#define MBINTREQ_S 2 +#define MBINTREQ_V(x) ((x) << MBINTREQ_S) +#define MBINTREQ_F MBINTREQ_V(1U) + +#define MBOWNER_S 0 +#define MBOWNER_M 0x3U +#define MBOWNER_V(x) ((x) << MBOWNER_S) +#define MBOWNER_G(x) (((x) >> MBOWNER_S) & MBOWNER_M) + +#define CIM_PF_HOST_INT_ENABLE_A 0x288 + +#define MBMSGRDYINTEN_S 19 +#define MBMSGRDYINTEN_V(x) ((x) << MBMSGRDYINTEN_S) +#define MBMSGRDYINTEN_F MBMSGRDYINTEN_V(1U) + +#define CIM_PF_HOST_INT_CAUSE_A 0x28c + +#define MBMSGRDYINT_S 19 +#define MBMSGRDYINT_V(x) ((x) << MBMSGRDYINT_S) +#define MBMSGRDYINT_F MBMSGRDYINT_V(1U) + +#define CIM_HOST_INT_CAUSE_A 0x7b2c + +#define TIEQOUTPARERRINT_S 20 +#define TIEQOUTPARERRINT_V(x) ((x) << TIEQOUTPARERRINT_S) +#define TIEQOUTPARERRINT_F TIEQOUTPARERRINT_V(1U) + +#define TIEQINPARERRINT_S 19 +#define TIEQINPARERRINT_V(x) ((x) << TIEQINPARERRINT_S) +#define TIEQINPARERRINT_F TIEQINPARERRINT_V(1U) + +#define PREFDROPINT_S 1 +#define PREFDROPINT_V(x) ((x) << PREFDROPINT_S) +#define PREFDROPINT_F PREFDROPINT_V(1U) + +#define UPACCNONZERO_S 0 +#define UPACCNONZERO_V(x) ((x) << UPACCNONZERO_S) +#define UPACCNONZERO_F UPACCNONZERO_V(1U) + +#define MBHOSTPARERR_S 18 +#define MBHOSTPARERR_V(x) ((x) << MBHOSTPARERR_S) +#define MBHOSTPARERR_F MBHOSTPARERR_V(1U) + +#define MBUPPARERR_S 17 +#define MBUPPARERR_V(x) ((x) << MBUPPARERR_S) +#define MBUPPARERR_F MBUPPARERR_V(1U) + +#define IBQTP0PARERR_S 16 +#define IBQTP0PARERR_V(x) ((x) << IBQTP0PARERR_S) +#define IBQTP0PARERR_F IBQTP0PARERR_V(1U) + +#define IBQTP1PARERR_S 15 +#define IBQTP1PARERR_V(x) ((x) << IBQTP1PARERR_S) +#define IBQTP1PARERR_F IBQTP1PARERR_V(1U) + +#define IBQULPPARERR_S 14 +#define IBQULPPARERR_V(x) ((x) << IBQULPPARERR_S) +#define IBQULPPARERR_F IBQULPPARERR_V(1U) + +#define IBQSGELOPARERR_S 13 +#define IBQSGELOPARERR_V(x) ((x) << IBQSGELOPARERR_S) +#define IBQSGELOPARERR_F IBQSGELOPARERR_V(1U) + +#define IBQSGEHIPARERR_S 12 +#define IBQSGEHIPARERR_V(x) ((x) << IBQSGEHIPARERR_S) +#define IBQSGEHIPARERR_F IBQSGEHIPARERR_V(1U) + +#define IBQNCSIPARERR_S 11 +#define IBQNCSIPARERR_V(x) ((x) << IBQNCSIPARERR_S) +#define IBQNCSIPARERR_F IBQNCSIPARERR_V(1U) + +#define OBQULP0PARERR_S 10 +#define OBQULP0PARERR_V(x) ((x) << OBQULP0PARERR_S) +#define OBQULP0PARERR_F OBQULP0PARERR_V(1U) + +#define OBQULP1PARERR_S 9 +#define OBQULP1PARERR_V(x) ((x) << OBQULP1PARERR_S) +#define OBQULP1PARERR_F OBQULP1PARERR_V(1U) + +#define OBQULP2PARERR_S 8 +#define OBQULP2PARERR_V(x) ((x) << OBQULP2PARERR_S) +#define OBQULP2PARERR_F OBQULP2PARERR_V(1U) + +#define OBQULP3PARERR_S 7 +#define OBQULP3PARERR_V(x) ((x) << OBQULP3PARERR_S) +#define OBQULP3PARERR_F OBQULP3PARERR_V(1U) + +#define OBQSGEPARERR_S 6 +#define OBQSGEPARERR_V(x) ((x) << OBQSGEPARERR_S) +#define OBQSGEPARERR_F OBQSGEPARERR_V(1U) + +#define OBQNCSIPARERR_S 5 +#define OBQNCSIPARERR_V(x) ((x) << OBQNCSIPARERR_S) +#define OBQNCSIPARERR_F OBQNCSIPARERR_V(1U) + +#define CIM_HOST_UPACC_INT_CAUSE_A 0x7b34 + +#define EEPROMWRINT_S 30 +#define EEPROMWRINT_V(x) ((x) << EEPROMWRINT_S) +#define EEPROMWRINT_F EEPROMWRINT_V(1U) + +#define TIMEOUTMAINT_S 29 +#define TIMEOUTMAINT_V(x) ((x) << TIMEOUTMAINT_S) +#define TIMEOUTMAINT_F TIMEOUTMAINT_V(1U) + +#define TIMEOUTINT_S 28 +#define TIMEOUTINT_V(x) ((x) << TIMEOUTINT_S) +#define TIMEOUTINT_F TIMEOUTINT_V(1U) + +#define RSPOVRLOOKUPINT_S 27 +#define RSPOVRLOOKUPINT_V(x) ((x) << RSPOVRLOOKUPINT_S) +#define RSPOVRLOOKUPINT_F RSPOVRLOOKUPINT_V(1U) + +#define REQOVRLOOKUPINT_S 26 +#define REQOVRLOOKUPINT_V(x) ((x) << REQOVRLOOKUPINT_S) +#define REQOVRLOOKUPINT_F REQOVRLOOKUPINT_V(1U) + +#define BLKWRPLINT_S 25 +#define BLKWRPLINT_V(x) ((x) << BLKWRPLINT_S) +#define BLKWRPLINT_F BLKWRPLINT_V(1U) + +#define BLKRDPLINT_S 24 +#define BLKRDPLINT_V(x) ((x) << BLKRDPLINT_S) +#define BLKRDPLINT_F BLKRDPLINT_V(1U) + +#define SGLWRPLINT_S 23 +#define SGLWRPLINT_V(x) ((x) << SGLWRPLINT_S) +#define SGLWRPLINT_F SGLWRPLINT_V(1U) + +#define SGLRDPLINT_S 22 +#define SGLRDPLINT_V(x) ((x) << SGLRDPLINT_S) +#define SGLRDPLINT_F SGLRDPLINT_V(1U) + +#define BLKWRCTLINT_S 21 +#define BLKWRCTLINT_V(x) ((x) << BLKWRCTLINT_S) +#define BLKWRCTLINT_F BLKWRCTLINT_V(1U) + +#define BLKRDCTLINT_S 20 +#define BLKRDCTLINT_V(x) ((x) << BLKRDCTLINT_S) +#define BLKRDCTLINT_F BLKRDCTLINT_V(1U) + +#define SGLWRCTLINT_S 19 +#define SGLWRCTLINT_V(x) ((x) << SGLWRCTLINT_S) +#define SGLWRCTLINT_F SGLWRCTLINT_V(1U) + +#define SGLRDCTLINT_S 18 +#define SGLRDCTLINT_V(x) ((x) << SGLRDCTLINT_S) +#define SGLRDCTLINT_F SGLRDCTLINT_V(1U) + +#define BLKWREEPROMINT_S 17 +#define BLKWREEPROMINT_V(x) ((x) << BLKWREEPROMINT_S) +#define BLKWREEPROMINT_F BLKWREEPROMINT_V(1U) + +#define BLKRDEEPROMINT_S 16 +#define BLKRDEEPROMINT_V(x) ((x) << BLKRDEEPROMINT_S) +#define BLKRDEEPROMINT_F BLKRDEEPROMINT_V(1U) + +#define SGLWREEPROMINT_S 15 +#define SGLWREEPROMINT_V(x) ((x) << SGLWREEPROMINT_S) +#define SGLWREEPROMINT_F SGLWREEPROMINT_V(1U) + +#define SGLRDEEPROMINT_S 14 +#define SGLRDEEPROMINT_V(x) ((x) << SGLRDEEPROMINT_S) +#define SGLRDEEPROMINT_F SGLRDEEPROMINT_V(1U) + +#define BLKWRFLASHINT_S 13 +#define BLKWRFLASHINT_V(x) ((x) << BLKWRFLASHINT_S) +#define BLKWRFLASHINT_F BLKWRFLASHINT_V(1U) + +#define BLKRDFLASHINT_S 12 +#define BLKRDFLASHINT_V(x) ((x) << BLKRDFLASHINT_S) +#define BLKRDFLASHINT_F BLKRDFLASHINT_V(1U) + +#define SGLWRFLASHINT_S 11 +#define SGLWRFLASHINT_V(x) ((x) << SGLWRFLASHINT_S) +#define SGLWRFLASHINT_F SGLWRFLASHINT_V(1U) + +#define SGLRDFLASHINT_S 10 +#define SGLRDFLASHINT_V(x) ((x) << SGLRDFLASHINT_S) +#define SGLRDFLASHINT_F SGLRDFLASHINT_V(1U) + +#define BLKWRBOOTINT_S 9 +#define BLKWRBOOTINT_V(x) ((x) << BLKWRBOOTINT_S) +#define BLKWRBOOTINT_F BLKWRBOOTINT_V(1U) + +#define BLKRDBOOTINT_S 8 +#define BLKRDBOOTINT_V(x) ((x) << BLKRDBOOTINT_S) +#define BLKRDBOOTINT_F BLKRDBOOTINT_V(1U) + +#define SGLWRBOOTINT_S 7 +#define SGLWRBOOTINT_V(x) ((x) << SGLWRBOOTINT_S) +#define SGLWRBOOTINT_F SGLWRBOOTINT_V(1U) + +#define SGLRDBOOTINT_S 6 +#define SGLRDBOOTINT_V(x) ((x) << SGLRDBOOTINT_S) +#define SGLRDBOOTINT_F SGLRDBOOTINT_V(1U) + +#define ILLWRBEINT_S 5 +#define ILLWRBEINT_V(x) ((x) << ILLWRBEINT_S) +#define ILLWRBEINT_F ILLWRBEINT_V(1U) + +#define ILLRDBEINT_S 4 +#define ILLRDBEINT_V(x) ((x) << ILLRDBEINT_S) +#define ILLRDBEINT_F ILLRDBEINT_V(1U) + +#define ILLRDINT_S 3 +#define ILLRDINT_V(x) ((x) << ILLRDINT_S) +#define ILLRDINT_F ILLRDINT_V(1U) + +#define ILLWRINT_S 2 +#define ILLWRINT_V(x) ((x) << ILLWRINT_S) +#define ILLWRINT_F ILLWRINT_V(1U) + +#define ILLTRANSINT_S 1 +#define ILLTRANSINT_V(x) ((x) << ILLTRANSINT_S) +#define ILLTRANSINT_F ILLTRANSINT_V(1U) + +#define RSVDSPACEINT_S 0 +#define RSVDSPACEINT_V(x) ((x) << RSVDSPACEINT_S) +#define RSVDSPACEINT_F RSVDSPACEINT_V(1U) #define TP_OUT_CONFIG 0x7d04 #define VLANEXTENABLE_MASK 0x0000f000U @@ -1634,19 +1832,22 @@ #define MC_STRIDE (MC_1_BASE_ADDR - MC_0_BASE_ADDR) #define MC_REG(reg, idx) (reg + MC_STRIDE * idx) -#define MC_P_BIST_CMD 0x41400 -#define MC_P_BIST_CMD_ADDR 0x41404 -#define MC_P_BIST_CMD_LEN 0x41408 -#define MC_P_BIST_DATA_PATTERN 0x4140c -#define MC_P_BIST_STATUS_RDATA 0x41488 -#define EDC_T50_BASE_ADDR 0x50000 -#define EDC_H_BIST_CMD 0x50004 -#define EDC_H_BIST_CMD_ADDR 0x50008 -#define EDC_H_BIST_CMD_LEN 0x5000c -#define EDC_H_BIST_DATA_PATTERN 0x50010 -#define EDC_H_BIST_STATUS_RDATA 0x50028 - -#define EDC_T51_BASE_ADDR 0x50800 +#define MC_P_BIST_CMD_A 0x41400 +#define MC_P_BIST_CMD_ADDR_A 0x41404 +#define MC_P_BIST_CMD_LEN_A 0x41408 +#define MC_P_BIST_DATA_PATTERN_A 0x4140c +#define MC_P_BIST_STATUS_RDATA_A 0x41488 + +#define EDC_T50_BASE_ADDR 0x50000 + +#define EDC_H_BIST_CMD_A 0x50004 +#define EDC_H_BIST_CMD_ADDR_A 0x50008 +#define EDC_H_BIST_CMD_LEN_A 0x5000c +#define EDC_H_BIST_DATA_PATTERN_A 0x50010 +#define EDC_H_BIST_STATUS_RDATA_A 0x50028 + +#define EDC_T51_BASE_ADDR 0x50800 + #define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR) #define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h index c7b127d93767..b516b12b1884 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h @@ -64,8 +64,8 @@ * Mailbox Data in the fixed CIM PF map and the programmable VF map must * match. However, it's a useful convention ... */ -#if T4VF_MBDATA_BASE_ADDR != CIM_PF_MAILBOX_DATA -#error T4VF_MBDATA_BASE_ADDR must match CIM_PF_MAILBOX_DATA! +#if T4VF_MBDATA_BASE_ADDR != CIM_PF_MAILBOX_DATA_A +#error T4VF_MBDATA_BASE_ADDR must match CIM_PF_MAILBOX_DATA_A! #endif /* diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index fa60f714e972..5e83c183faa1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -138,9 +138,9 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, * Loop trying to get ownership of the mailbox. Return an error * if we can't gain ownership. */ - v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl)); + v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl)); for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) - v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl)); + v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl)); if (v != MBOX_OWNER_DRV) return v == MBOX_OWNER_FW ? -EBUSY : -ETIMEDOUT; @@ -162,7 +162,7 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, t4_read_reg(adapter, mbox_data); /* flush write */ t4_write_reg(adapter, mbox_ctl, - MBMSGVALID | MBOWNER(MBOX_OWNER_FW)); + MBMSGVALID_F | MBOWNER_V(MBOX_OWNER_FW)); t4_read_reg(adapter, mbox_ctl); /* flush write */ /* @@ -184,14 +184,14 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, * If we're the owner, see if this is the reply we wanted. */ v = t4_read_reg(adapter, mbox_ctl); - if (MBOWNER_GET(v) == MBOX_OWNER_DRV) { + if (MBOWNER_G(v) == MBOX_OWNER_DRV) { /* * If the Message Valid bit isn't on, revoke ownership * of the mailbox and continue waiting for our reply. */ - if ((v & MBMSGVALID) == 0) { + if ((v & MBMSGVALID_F) == 0) { t4_write_reg(adapter, mbox_ctl, - MBOWNER(MBOX_OWNER_NONE)); + MBOWNER_V(MBOX_OWNER_NONE)); continue; } @@ -217,7 +217,7 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, & FW_CMD_REQUEST_F) != 0); } t4_write_reg(adapter, mbox_ctl, - MBOWNER(MBOX_OWNER_NONE)); + MBOWNER_V(MBOX_OWNER_NONE)); return -FW_CMD_RETVAL_G(v); } } -- cgit v1.2.1 From 837e4a42bbb5c41ce555bcd544a9c24c28134e24 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 5 Jan 2015 16:30:46 +0530 Subject: cxgb4/csiostor: Cleanup TP, MPS and TCAM related register defines This patch cleanups all TP, MPS and TCAM related macros/register defines that are defined in t4_regs.h and the affected files Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 70 +-- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 154 +++--- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 607 ++++++++++++++---------- 3 files changed, 476 insertions(+), 355 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 16c633f4bf8b..53ad8d3d9e4c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -359,8 +359,8 @@ MODULE_PARM_DESC(select_queue, */ enum { TP_VLAN_PRI_MAP_DEFAULT = HW_TPL_FR_MT_PR_IV_P_FC, - TP_VLAN_PRI_MAP_FIRST = FCOE_SHIFT, - TP_VLAN_PRI_MAP_LAST = FRAGMENTATION_SHIFT, + TP_VLAN_PRI_MAP_FIRST = FCOE_S, + TP_VLAN_PRI_MAP_LAST = FRAGMENTATION_S, }; static unsigned int tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT; @@ -1177,10 +1177,10 @@ freeout: t4_free_sge_resources(adap); } t4_write_reg(adap, is_t4(adap->params.chip) ? - MPS_TRC_RSS_CONTROL : - MPS_T5_TRC_RSS_CONTROL, - RSSCONTROL(netdev2pinfo(adap->port[0])->tx_chan) | - QUEUENUMBER(s->ethrxq[0].rspq.abs_id)); + MPS_TRC_RSS_CONTROL_A : + MPS_T5_TRC_RSS_CONTROL_A, + RSSCONTROL_V(netdev2pinfo(adap->port[0])->tx_chan) | + QUEUENUMBER_V(s->ethrxq[0].rspq.abs_id)); return 0; } @@ -4094,7 +4094,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld) lli.nports = adap->params.nports; lli.wr_cred = adap->params.ofldq_wr_cred; lli.adapter_type = adap->params.chip; - lli.iscsi_iolen = MAXRXDATA_GET(t4_read_reg(adap, TP_PARA_REG2)); + lli.iscsi_iolen = MAXRXDATA_G(t4_read_reg(adap, TP_PARA_REG2_A)); lli.cclk_ps = 1000000000 / adap->params.vpd.cclk; lli.udb_density = 1 << adap->params.sge.eq_qpp; lli.ucq_density = 1 << adap->params.sge.iq_qpp; @@ -4949,11 +4949,11 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) t4_sge_init(adap); /* tweak some settings */ - t4_write_reg(adap, TP_SHIFT_CNT, 0x64f8849); + t4_write_reg(adap, TP_SHIFT_CNT_A, 0x64f8849); t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12)); - t4_write_reg(adap, TP_PIO_ADDR, TP_INGRESS_CONFIG); - v = t4_read_reg(adap, TP_PIO_DATA); - t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR); + t4_write_reg(adap, TP_PIO_ADDR_A, TP_INGRESS_CONFIG_A); + v = t4_read_reg(adap, TP_PIO_DATA_A); + t4_write_reg(adap, TP_PIO_DATA_A, v & ~CSUM_HAS_PSEUDO_HDR_F); /* first 4 Tx modulation queues point to consecutive Tx channels */ adap->params.tp.tx_modq_map = 0xE4; @@ -4962,11 +4962,11 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) /* associate each Tx modulation queue with consecutive Tx channels */ v = 0x84218421; - t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, + t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, &v, 1, A_TP_TX_SCHED_HDR); - t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, + t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, &v, 1, A_TP_TX_SCHED_FIFO); - t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, + t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, &v, 1, A_TP_TX_SCHED_PCMD); #define T4_TX_MODQ_10G_WEIGHT_DEFAULT 16 /* in KB units */ @@ -5034,8 +5034,8 @@ static int adap_init0_tweaks(struct adapter *adapter) * Don't include the "IP Pseudo Header" in CPL_RX_PKT checksums: Linux * adds the pseudo header itself. */ - t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG, - CSUM_HAS_PSEUDO_HDR, 0); + t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG_A, + CSUM_HAS_PSEUDO_HDR_F, 0); return 0; } @@ -5401,34 +5401,34 @@ static int adap_init0_no_config(struct adapter *adapter, int reset) case 0: /* compressed filter field not enabled */ break; - case FCOE_MASK: + case FCOE_F: bits += 1; break; - case PORT_MASK: + case PORT_F: bits += 3; break; - case VNIC_ID_MASK: + case VNIC_F: bits += 17; break; - case VLAN_MASK: + case VLAN_F: bits += 17; break; - case TOS_MASK: + case TOS_F: bits += 8; break; - case PROTOCOL_MASK: + case PROTOCOL_F: bits += 8; break; - case ETHERTYPE_MASK: + case ETHERTYPE_F: bits += 16; break; - case MACMATCH_MASK: + case MACMATCH_F: bits += 9; break; - case MPSHITTYPE_MASK: + case MPSHITTYPE_F: bits += 3; break; - case FRAGMENTATION_MASK: + case FRAGMENTATION_F: bits += 1; break; } @@ -5442,8 +5442,8 @@ static int adap_init0_no_config(struct adapter *adapter, int reset) } } v = tp_vlan_pri_map; - t4_write_indirect(adapter, TP_PIO_ADDR, TP_PIO_DATA, - &v, 1, TP_VLAN_PRI_MAP); + t4_write_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + &v, 1, TP_VLAN_PRI_MAP_A); /* * We need Five Tuple Lookup mode to be set in TP_GLOBAL_CONFIG order @@ -5456,17 +5456,17 @@ static int adap_init0_no_config(struct adapter *adapter, int reset) * performance impact). */ if (tp_vlan_pri_map) - t4_set_reg_field(adapter, TP_GLOBAL_CONFIG, - FIVETUPLELOOKUP_MASK, - FIVETUPLELOOKUP_MASK); + t4_set_reg_field(adapter, TP_GLOBAL_CONFIG_A, + FIVETUPLELOOKUP_V(FIVETUPLELOOKUP_M), + FIVETUPLELOOKUP_V(FIVETUPLELOOKUP_M)); /* * Tweak some settings. */ - t4_write_reg(adapter, TP_SHIFT_CNT, SYNSHIFTMAX(6) | - RXTSHIFTMAXR1(4) | RXTSHIFTMAXR2(15) | - PERSHIFTBACKOFFMAX(8) | PERSHIFTMAX(8) | - KEEPALIVEMAXR1(4) | KEEPALIVEMAXR2(9)); + t4_write_reg(adapter, TP_SHIFT_CNT_A, SYNSHIFTMAX_V(6) | + RXTSHIFTMAXR1_V(4) | RXTSHIFTMAXR2_V(15) | + PERSHIFTBACKOFFMAX_V(8) | PERSHIFTMAX_V(8) | + KEEPALIVEMAXR1_V(4) | KEEPALIVEMAXR2_V(9)); /* * Get basic stuff going by issuing the Firmware Initialize command. diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index c9777e00cea4..cf0bf79a6193 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -1486,11 +1486,11 @@ static void tp_intr_handler(struct adapter *adapter) { static const struct intr_info tp_intr_info[] = { { 0x3fffffff, "TP parity error", -1, 1 }, - { FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, + { FLMTXFLSTEMPTY_F, "TP out of Tx pages", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adapter, TP_INT_CAUSE, tp_intr_info)) + if (t4_handle_intr_status(adapter, TP_INT_CAUSE_A, tp_intr_info)) t4_fatal_err(adapter); } @@ -1629,19 +1629,19 @@ static void ulprx_intr_handler(struct adapter *adapter) static void ulptx_intr_handler(struct adapter *adapter) { static const struct intr_info ulptx_intr_info[] = { - { PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH3_F, "ULPTX channel 3 PBL out of bounds", -1, 0 }, - { PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH2_F, "ULPTX channel 2 PBL out of bounds", -1, 0 }, - { PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH1_F, "ULPTX channel 1 PBL out of bounds", -1, 0 }, - { PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH0_F, "ULPTX channel 0 PBL out of bounds", -1, 0 }, { 0xfffffff, "ULPTX parity error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE, ulptx_intr_info)) + if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE_A, ulptx_intr_info)) t4_fatal_err(adapter); } @@ -1651,19 +1651,20 @@ static void ulptx_intr_handler(struct adapter *adapter) static void pmtx_intr_handler(struct adapter *adapter) { static const struct intr_info pmtx_intr_info[] = { - { PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 }, - { PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 }, - { PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 }, - { ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, - { PMTX_FRAMING_ERROR, "PMTX framing error", -1, 1 }, - { OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 }, - { DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1, 1 }, - { ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 }, - { C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1}, + { PCMD_LEN_OVFL0_F, "PMTX channel 0 pcmd too large", -1, 1 }, + { PCMD_LEN_OVFL1_F, "PMTX channel 1 pcmd too large", -1, 1 }, + { PCMD_LEN_OVFL2_F, "PMTX channel 2 pcmd too large", -1, 1 }, + { ZERO_C_CMD_ERROR_F, "PMTX 0-length pcmd", -1, 1 }, + { PMTX_FRAMING_ERROR_F, "PMTX framing error", -1, 1 }, + { OESPI_PAR_ERROR_F, "PMTX oespi parity error", -1, 1 }, + { DB_OPTIONS_PAR_ERROR_F, "PMTX db_options parity error", + -1, 1 }, + { ICSPI_PAR_ERROR_F, "PMTX icspi parity error", -1, 1 }, + { PMTX_C_PCMD_PAR_ERROR_F, "PMTX c_pcmd parity error", -1, 1}, { 0 } }; - if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE, pmtx_intr_info)) + if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE_A, pmtx_intr_info)) t4_fatal_err(adapter); } @@ -1673,16 +1674,17 @@ static void pmtx_intr_handler(struct adapter *adapter) static void pmrx_intr_handler(struct adapter *adapter) { static const struct intr_info pmrx_intr_info[] = { - { ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, - { PMRX_FRAMING_ERROR, "PMRX framing error", -1, 1 }, - { OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 }, - { DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1, 1 }, - { IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 }, - { E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1}, + { ZERO_E_CMD_ERROR_F, "PMRX 0-length pcmd", -1, 1 }, + { PMRX_FRAMING_ERROR_F, "PMRX framing error", -1, 1 }, + { OCSPI_PAR_ERROR_F, "PMRX ocspi parity error", -1, 1 }, + { DB_OPTIONS_PAR_ERROR_F, "PMRX db_options parity error", + -1, 1 }, + { IESPI_PAR_ERROR_F, "PMRX iespi parity error", -1, 1 }, + { PMRX_E_PCMD_PAR_ERROR_F, "PMRX e_pcmd parity error", -1, 1}, { 0 } }; - if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE, pmrx_intr_info)) + if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE_A, pmrx_intr_info)) t4_fatal_err(adapter); } @@ -1733,19 +1735,22 @@ static void mps_intr_handler(struct adapter *adapter) { 0 } }; static const struct intr_info mps_tx_intr_info[] = { - { TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 }, - { NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 }, - { TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 }, - { TXDESCFIFO, "MPS Tx desc FIFO parity error", -1, 1 }, - { BUBBLE, "MPS Tx underflow", -1, 1 }, - { SECNTERR, "MPS Tx SOP/EOP error", -1, 1 }, - { FRMERR, "MPS Tx framing error", -1, 1 }, + { TPFIFO_V(TPFIFO_M), "MPS Tx TP FIFO parity error", -1, 1 }, + { NCSIFIFO_F, "MPS Tx NC-SI FIFO parity error", -1, 1 }, + { TXDATAFIFO_V(TXDATAFIFO_M), "MPS Tx data FIFO parity error", + -1, 1 }, + { TXDESCFIFO_V(TXDESCFIFO_M), "MPS Tx desc FIFO parity error", + -1, 1 }, + { BUBBLE_F, "MPS Tx underflow", -1, 1 }, + { SECNTERR_F, "MPS Tx SOP/EOP error", -1, 1 }, + { FRMERR_F, "MPS Tx framing error", -1, 1 }, { 0 } }; static const struct intr_info mps_trc_intr_info[] = { - { FILTMEM, "MPS TRC filter parity error", -1, 1 }, - { PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 }, - { MISCPERR, "MPS TRC misc parity error", -1, 1 }, + { FILTMEM_V(FILTMEM_M), "MPS TRC filter parity error", -1, 1 }, + { PKTFIFO_V(PKTFIFO_M), "MPS TRC packet FIFO parity error", + -1, 1 }, + { MISCPERR_F, "MPS TRC misc parity error", -1, 1 }, { 0 } }; static const struct intr_info mps_stat_sram_intr_info[] = { @@ -1761,32 +1766,31 @@ static void mps_intr_handler(struct adapter *adapter) { 0 } }; static const struct intr_info mps_cls_intr_info[] = { - { MATCHSRAM, "MPS match SRAM parity error", -1, 1 }, - { MATCHTCAM, "MPS match TCAM parity error", -1, 1 }, - { HASHSRAM, "MPS hash SRAM parity error", -1, 1 }, + { MATCHSRAM_F, "MPS match SRAM parity error", -1, 1 }, + { MATCHTCAM_F, "MPS match TCAM parity error", -1, 1 }, + { HASHSRAM_F, "MPS hash SRAM parity error", -1, 1 }, { 0 } }; int fat; - fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE, + fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE_A, mps_rx_intr_info) + - t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE, + t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE_A, mps_tx_intr_info) + - t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE, + t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE_A, mps_trc_intr_info) + - t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM, + t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM_A, mps_stat_sram_intr_info) + - t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO, + t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A, mps_stat_tx_intr_info) + - t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO, + t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A, mps_stat_rx_intr_info) + - t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE, + t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE_A, mps_cls_intr_info); - t4_write_reg(adapter, MPS_INT_CAUSE, CLSINT | TRCINT | - RXINT | TXINT | STATINT); - t4_read_reg(adapter, MPS_INT_CAUSE); /* flush */ + t4_write_reg(adapter, MPS_INT_CAUSE_A, 0); + t4_read_reg(adapter, MPS_INT_CAUSE_A); /* flush */ if (fat) t4_fatal_err(adapter); } @@ -2187,23 +2191,23 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, struct tp_tcp_stats *v6) { - u32 val[TP_MIB_TCP_RXT_SEG_LO - TP_MIB_TCP_OUT_RST + 1]; + u32 val[TP_MIB_TCP_RXT_SEG_LO_A - TP_MIB_TCP_OUT_RST_A + 1]; -#define STAT_IDX(x) ((TP_MIB_TCP_##x) - TP_MIB_TCP_OUT_RST) +#define STAT_IDX(x) ((TP_MIB_TCP_##x##_A) - TP_MIB_TCP_OUT_RST_A) #define STAT(x) val[STAT_IDX(x)] #define STAT64(x) (((u64)STAT(x##_HI) << 32) | STAT(x##_LO)) if (v4) { - t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val, - ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val, + ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST_A); v4->tcpOutRsts = STAT(OUT_RST); v4->tcpInSegs = STAT64(IN_SEG); v4->tcpOutSegs = STAT64(OUT_SEG); v4->tcpRetransSegs = STAT64(RXT_SEG); } if (v6) { - t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val, - ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val, + ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST_A); v6->tcpOutRsts = STAT(OUT_RST); v6->tcpInSegs = STAT64(IN_SEG); v6->tcpOutSegs = STAT64(OUT_SEG); @@ -2228,12 +2232,12 @@ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) int i; for (i = 0; i < NMTUS; ++i) { - t4_write_reg(adap, TP_MTU_TABLE, - MTUINDEX(0xff) | MTUVALUE(i)); - v = t4_read_reg(adap, TP_MTU_TABLE); - mtus[i] = MTUVALUE_GET(v); + t4_write_reg(adap, TP_MTU_TABLE_A, + MTUINDEX_V(0xff) | MTUVALUE_V(i)); + v = t4_read_reg(adap, TP_MTU_TABLE_A); + mtus[i] = MTUVALUE_G(v); if (mtu_log) - mtu_log[i] = MTUWIDTH_GET(v); + mtu_log[i] = MTUWIDTH_G(v); } } @@ -2249,9 +2253,9 @@ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr, unsigned int mask, unsigned int val) { - t4_write_reg(adap, TP_PIO_ADDR, addr); - val |= t4_read_reg(adap, TP_PIO_DATA) & ~mask; - t4_write_reg(adap, TP_PIO_DATA, val); + t4_write_reg(adap, TP_PIO_ADDR_A, addr); + val |= t4_read_reg(adap, TP_PIO_DATA_A) & ~mask; + t4_write_reg(adap, TP_PIO_DATA_A, val); } /** @@ -2330,8 +2334,8 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, if (!(mtu & ((1 << log2) >> 2))) /* round */ log2--; - t4_write_reg(adap, TP_MTU_TABLE, MTUINDEX(i) | - MTUWIDTH(log2) | MTUVALUE(mtu)); + t4_write_reg(adap, TP_MTU_TABLE_A, MTUINDEX_V(i) | + MTUWIDTH_V(log2) | MTUVALUE_V(mtu)); for (w = 0; w < NCCTRL_WIN; ++w) { unsigned int inc; @@ -2339,7 +2343,7 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], CC_MIN_INCR); - t4_write_reg(adap, TP_CCTRL_TABLE, (i << 21) | + t4_write_reg(adap, TP_CCTRL_TABLE_A, (i << 21) | (w << 16) | (beta[w] << 13) | inc); } } @@ -2356,7 +2360,7 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, */ static unsigned int get_mps_bg_map(struct adapter *adap, int idx) { - u32 n = NUMPORTS_GET(t4_read_reg(adap, MPS_CMN_CTL)); + u32 n = NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A)); if (n == 0) return idx == 0 ? 0xf : 0; @@ -2498,7 +2502,7 @@ void t4_wol_magic_enable(struct adapter *adap, unsigned int port, } else { mag_id_reg_l = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_LO); mag_id_reg_h = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_HI); - port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2); + port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A); } if (addr) { @@ -2536,7 +2540,7 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, if (is_t4(adap->params.chip)) port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2); else - port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2); + port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A); if (!enable) { t4_set_reg_field(adap, port_cfg_reg, PATEN, 0); @@ -2547,7 +2551,7 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, #define EPIO_REG(name) \ (is_t4(adap->params.chip) ? PORT_REG(port, XGMAC_PORT_EPIO_##name) : \ - T5_PORT_REG(port, MAC_PORT_EPIO_##name)) + T5_PORT_REG(port, MAC_PORT_EPIO_##name##_A)) t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32); t4_write_reg(adap, EPIO_REG(DATA2), mask1); @@ -4171,9 +4175,9 @@ int t4_init_tp_params(struct adapter *adap) int chan; u32 v; - v = t4_read_reg(adap, TP_TIMER_RESOLUTION); - adap->params.tp.tre = TIMERRESOLUTION_GET(v); - adap->params.tp.dack_re = DELAYEDACKRESOLUTION_GET(v); + v = t4_read_reg(adap, TP_TIMER_RESOLUTION_A); + adap->params.tp.tre = TIMERRESOLUTION_G(v); + adap->params.tp.dack_re = DELAYEDACKRESOLUTION_G(v); /* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */ for (chan = 0; chan < NCHAN; chan++) @@ -4182,12 +4186,12 @@ int t4_init_tp_params(struct adapter *adap) /* Cache the adapter's Compressed Filter Mode and global Incress * Configuration. */ - t4_read_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, + t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, &adap->params.tp.vlan_pri_map, 1, - TP_VLAN_PRI_MAP); - t4_read_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, + TP_VLAN_PRI_MAP_A); + t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, &adap->params.tp.ingress_config, 1, - TP_INGRESS_CONFIG); + TP_INGRESS_CONFIG_A); /* Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field * shift positions of several elements of the Compressed Filter Tuple diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 4b6681812b8a..ec0addc85bb6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1182,158 +1182,258 @@ #define RSVDSPACEINT_V(x) ((x) << RSVDSPACEINT_S) #define RSVDSPACEINT_F RSVDSPACEINT_V(1U) -#define TP_OUT_CONFIG 0x7d04 -#define VLANEXTENABLE_MASK 0x0000f000U -#define VLANEXTENABLE_SHIFT 12 - -#define TP_GLOBAL_CONFIG 0x7d08 -#define FIVETUPLELOOKUP_SHIFT 17 -#define FIVETUPLELOOKUP_MASK 0x00060000U -#define FIVETUPLELOOKUP(x) ((x) << FIVETUPLELOOKUP_SHIFT) -#define FIVETUPLELOOKUP_GET(x) (((x) & FIVETUPLELOOKUP_MASK) >> \ - FIVETUPLELOOKUP_SHIFT) - -#define TP_PARA_REG2 0x7d68 -#define MAXRXDATA_MASK 0xffff0000U -#define MAXRXDATA_SHIFT 16 -#define MAXRXDATA_GET(x) (((x) & MAXRXDATA_MASK) >> MAXRXDATA_SHIFT) - -#define TP_TIMER_RESOLUTION 0x7d90 -#define TIMERRESOLUTION_MASK 0x00ff0000U -#define TIMERRESOLUTION_SHIFT 16 -#define TIMERRESOLUTION_GET(x) (((x) & TIMERRESOLUTION_MASK) >> TIMERRESOLUTION_SHIFT) -#define DELAYEDACKRESOLUTION_MASK 0x000000ffU -#define DELAYEDACKRESOLUTION_SHIFT 0 -#define DELAYEDACKRESOLUTION_GET(x) \ - (((x) & DELAYEDACKRESOLUTION_MASK) >> DELAYEDACKRESOLUTION_SHIFT) - -#define TP_SHIFT_CNT 0x7dc0 -#define SYNSHIFTMAX_SHIFT 24 -#define SYNSHIFTMAX_MASK 0xff000000U -#define SYNSHIFTMAX(x) ((x) << SYNSHIFTMAX_SHIFT) -#define SYNSHIFTMAX_GET(x) (((x) & SYNSHIFTMAX_MASK) >> \ - SYNSHIFTMAX_SHIFT) -#define RXTSHIFTMAXR1_SHIFT 20 -#define RXTSHIFTMAXR1_MASK 0x00f00000U -#define RXTSHIFTMAXR1(x) ((x) << RXTSHIFTMAXR1_SHIFT) -#define RXTSHIFTMAXR1_GET(x) (((x) & RXTSHIFTMAXR1_MASK) >> \ - RXTSHIFTMAXR1_SHIFT) -#define RXTSHIFTMAXR2_SHIFT 16 -#define RXTSHIFTMAXR2_MASK 0x000f0000U -#define RXTSHIFTMAXR2(x) ((x) << RXTSHIFTMAXR2_SHIFT) -#define RXTSHIFTMAXR2_GET(x) (((x) & RXTSHIFTMAXR2_MASK) >> \ - RXTSHIFTMAXR2_SHIFT) -#define PERSHIFTBACKOFFMAX_SHIFT 12 -#define PERSHIFTBACKOFFMAX_MASK 0x0000f000U -#define PERSHIFTBACKOFFMAX(x) ((x) << PERSHIFTBACKOFFMAX_SHIFT) -#define PERSHIFTBACKOFFMAX_GET(x) (((x) & PERSHIFTBACKOFFMAX_MASK) >> \ - PERSHIFTBACKOFFMAX_SHIFT) -#define PERSHIFTMAX_SHIFT 8 -#define PERSHIFTMAX_MASK 0x00000f00U -#define PERSHIFTMAX(x) ((x) << PERSHIFTMAX_SHIFT) -#define PERSHIFTMAX_GET(x) (((x) & PERSHIFTMAX_MASK) >> \ - PERSHIFTMAX_SHIFT) -#define KEEPALIVEMAXR1_SHIFT 4 -#define KEEPALIVEMAXR1_MASK 0x000000f0U -#define KEEPALIVEMAXR1(x) ((x) << KEEPALIVEMAXR1_SHIFT) -#define KEEPALIVEMAXR1_GET(x) (((x) & KEEPALIVEMAXR1_MASK) >> \ - KEEPALIVEMAXR1_SHIFT) -#define KEEPALIVEMAXR2_SHIFT 0 -#define KEEPALIVEMAXR2_MASK 0x0000000fU -#define KEEPALIVEMAXR2(x) ((x) << KEEPALIVEMAXR2_SHIFT) -#define KEEPALIVEMAXR2_GET(x) (((x) & KEEPALIVEMAXR2_MASK) >> \ - KEEPALIVEMAXR2_SHIFT) - -#define TP_CCTRL_TABLE 0x7ddc -#define TP_MTU_TABLE 0x7de4 -#define MTUINDEX_MASK 0xff000000U -#define MTUINDEX_SHIFT 24 -#define MTUINDEX(x) ((x) << MTUINDEX_SHIFT) -#define MTUWIDTH_MASK 0x000f0000U -#define MTUWIDTH_SHIFT 16 -#define MTUWIDTH(x) ((x) << MTUWIDTH_SHIFT) -#define MTUWIDTH_GET(x) (((x) & MTUWIDTH_MASK) >> MTUWIDTH_SHIFT) -#define MTUVALUE_MASK 0x00003fffU -#define MTUVALUE_SHIFT 0 -#define MTUVALUE(x) ((x) << MTUVALUE_SHIFT) -#define MTUVALUE_GET(x) (((x) & MTUVALUE_MASK) >> MTUVALUE_SHIFT) - -#define TP_RSS_LKP_TABLE 0x7dec -#define LKPTBLROWVLD 0x80000000U -#define LKPTBLQUEUE1_MASK 0x000ffc00U -#define LKPTBLQUEUE1_SHIFT 10 -#define LKPTBLQUEUE1(x) ((x) << LKPTBLQUEUE1_SHIFT) -#define LKPTBLQUEUE1_GET(x) (((x) & LKPTBLQUEUE1_MASK) >> LKPTBLQUEUE1_SHIFT) -#define LKPTBLQUEUE0_MASK 0x000003ffU -#define LKPTBLQUEUE0_SHIFT 0 -#define LKPTBLQUEUE0(x) ((x) << LKPTBLQUEUE0_SHIFT) -#define LKPTBLQUEUE0_GET(x) (((x) & LKPTBLQUEUE0_MASK) >> LKPTBLQUEUE0_SHIFT) - -#define TP_PIO_ADDR 0x7e40 -#define TP_PIO_DATA 0x7e44 -#define TP_MIB_INDEX 0x7e50 -#define TP_MIB_DATA 0x7e54 -#define TP_INT_CAUSE 0x7e74 -#define FLMTXFLSTEMPTY 0x40000000U - -#define TP_VLAN_PRI_MAP 0x140 -#define FRAGMENTATION_SHIFT 9 -#define FRAGMENTATION_MASK 0x00000200U -#define MPSHITTYPE_MASK 0x00000100U -#define MACMATCH_MASK 0x00000080U -#define ETHERTYPE_MASK 0x00000040U -#define PROTOCOL_MASK 0x00000020U -#define TOS_MASK 0x00000010U -#define VLAN_MASK 0x00000008U -#define VNIC_ID_MASK 0x00000004U -#define PORT_MASK 0x00000002U -#define FCOE_SHIFT 0 -#define FCOE_MASK 0x00000001U - -#define TP_INGRESS_CONFIG 0x141 -#define VNIC 0x00000800U -#define CSUM_HAS_PSEUDO_HDR 0x00000400U -#define RM_OVLAN 0x00000200U -#define LOOKUPEVERYPKT 0x00000100U - -#define TP_MIB_MAC_IN_ERR_0 0x0 -#define TP_MIB_TCP_OUT_RST 0xc -#define TP_MIB_TCP_IN_SEG_HI 0x10 -#define TP_MIB_TCP_IN_SEG_LO 0x11 -#define TP_MIB_TCP_OUT_SEG_HI 0x12 -#define TP_MIB_TCP_OUT_SEG_LO 0x13 -#define TP_MIB_TCP_RXT_SEG_HI 0x14 -#define TP_MIB_TCP_RXT_SEG_LO 0x15 -#define TP_MIB_TNL_CNG_DROP_0 0x18 -#define TP_MIB_TCP_V6IN_ERR_0 0x28 -#define TP_MIB_TCP_V6OUT_RST 0x2c -#define TP_MIB_OFD_ARP_DROP 0x36 -#define TP_MIB_TNL_DROP_0 0x44 -#define TP_MIB_OFD_VLN_DROP_0 0x58 - -#define ULP_TX_INT_CAUSE 0x8dcc -#define PBL_BOUND_ERR_CH3 0x80000000U -#define PBL_BOUND_ERR_CH2 0x40000000U -#define PBL_BOUND_ERR_CH1 0x20000000U -#define PBL_BOUND_ERR_CH0 0x10000000U - -#define PM_RX_INT_CAUSE 0x8fdc -#define ZERO_E_CMD_ERROR 0x00400000U -#define PMRX_FRAMING_ERROR 0x003ffff0U -#define OCSPI_PAR_ERROR 0x00000008U -#define DB_OPTIONS_PAR_ERROR 0x00000004U -#define IESPI_PAR_ERROR 0x00000002U -#define E_PCMD_PAR_ERROR 0x00000001U - -#define PM_TX_INT_CAUSE 0x8ffc -#define PCMD_LEN_OVFL0 0x80000000U -#define PCMD_LEN_OVFL1 0x40000000U -#define PCMD_LEN_OVFL2 0x20000000U -#define ZERO_C_CMD_ERROR 0x10000000U -#define PMTX_FRAMING_ERROR 0x0ffffff0U -#define OESPI_PAR_ERROR 0x00000008U -#define ICSPI_PAR_ERROR 0x00000002U -#define C_PCMD_PAR_ERROR 0x00000001U +/* registers for module TP */ +#define TP_OUT_CONFIG_A 0x7d04 +#define TP_GLOBAL_CONFIG_A 0x7d08 + +#define FIVETUPLELOOKUP_S 17 +#define FIVETUPLELOOKUP_M 0x3U +#define FIVETUPLELOOKUP_V(x) ((x) << FIVETUPLELOOKUP_S) +#define FIVETUPLELOOKUP_G(x) (((x) >> FIVETUPLELOOKUP_S) & FIVETUPLELOOKUP_M) + +#define TP_PARA_REG2_A 0x7d68 + +#define MAXRXDATA_S 16 +#define MAXRXDATA_M 0xffffU +#define MAXRXDATA_G(x) (((x) >> MAXRXDATA_S) & MAXRXDATA_M) + +#define TP_TIMER_RESOLUTION_A 0x7d90 + +#define TIMERRESOLUTION_S 16 +#define TIMERRESOLUTION_M 0xffU +#define TIMERRESOLUTION_G(x) (((x) >> TIMERRESOLUTION_S) & TIMERRESOLUTION_M) + +#define DELAYEDACKRESOLUTION_S 0 +#define DELAYEDACKRESOLUTION_M 0xffU +#define DELAYEDACKRESOLUTION_G(x) \ + (((x) >> DELAYEDACKRESOLUTION_S) & DELAYEDACKRESOLUTION_M) + +#define TP_SHIFT_CNT_A 0x7dc0 + +#define SYNSHIFTMAX_S 24 +#define SYNSHIFTMAX_M 0xffU +#define SYNSHIFTMAX_V(x) ((x) << SYNSHIFTMAX_S) +#define SYNSHIFTMAX_G(x) (((x) >> SYNSHIFTMAX_S) & SYNSHIFTMAX_M) + +#define RXTSHIFTMAXR1_S 20 +#define RXTSHIFTMAXR1_M 0xfU +#define RXTSHIFTMAXR1_V(x) ((x) << RXTSHIFTMAXR1_S) +#define RXTSHIFTMAXR1_G(x) (((x) >> RXTSHIFTMAXR1_S) & RXTSHIFTMAXR1_M) + +#define RXTSHIFTMAXR2_S 16 +#define RXTSHIFTMAXR2_M 0xfU +#define RXTSHIFTMAXR2_V(x) ((x) << RXTSHIFTMAXR2_S) +#define RXTSHIFTMAXR2_G(x) (((x) >> RXTSHIFTMAXR2_S) & RXTSHIFTMAXR2_M) + +#define PERSHIFTBACKOFFMAX_S 12 +#define PERSHIFTBACKOFFMAX_M 0xfU +#define PERSHIFTBACKOFFMAX_V(x) ((x) << PERSHIFTBACKOFFMAX_S) +#define PERSHIFTBACKOFFMAX_G(x) \ + (((x) >> PERSHIFTBACKOFFMAX_S) & PERSHIFTBACKOFFMAX_M) + +#define PERSHIFTMAX_S 8 +#define PERSHIFTMAX_M 0xfU +#define PERSHIFTMAX_V(x) ((x) << PERSHIFTMAX_S) +#define PERSHIFTMAX_G(x) (((x) >> PERSHIFTMAX_S) & PERSHIFTMAX_M) + +#define KEEPALIVEMAXR1_S 4 +#define KEEPALIVEMAXR1_M 0xfU +#define KEEPALIVEMAXR1_V(x) ((x) << KEEPALIVEMAXR1_S) +#define KEEPALIVEMAXR1_G(x) (((x) >> KEEPALIVEMAXR1_S) & KEEPALIVEMAXR1_M) + +#define KEEPALIVEMAXR2_S 0 +#define KEEPALIVEMAXR2_M 0xfU +#define KEEPALIVEMAXR2_V(x) ((x) << KEEPALIVEMAXR2_S) +#define KEEPALIVEMAXR2_G(x) (((x) >> KEEPALIVEMAXR2_S) & KEEPALIVEMAXR2_M) + +#define TP_CCTRL_TABLE_A 0x7ddc +#define TP_MTU_TABLE_A 0x7de4 + +#define MTUINDEX_S 24 +#define MTUINDEX_V(x) ((x) << MTUINDEX_S) + +#define MTUWIDTH_S 16 +#define MTUWIDTH_M 0xfU +#define MTUWIDTH_V(x) ((x) << MTUWIDTH_S) +#define MTUWIDTH_G(x) (((x) >> MTUWIDTH_S) & MTUWIDTH_M) + +#define MTUVALUE_S 0 +#define MTUVALUE_M 0x3fffU +#define MTUVALUE_V(x) ((x) << MTUVALUE_S) +#define MTUVALUE_G(x) (((x) >> MTUVALUE_S) & MTUVALUE_M) + +#define TP_RSS_LKP_TABLE_A 0x7dec + +#define LKPTBLROWVLD_S 31 +#define LKPTBLROWVLD_V(x) ((x) << LKPTBLROWVLD_S) +#define LKPTBLROWVLD_F LKPTBLROWVLD_V(1U) + +#define LKPTBLQUEUE1_S 10 +#define LKPTBLQUEUE1_M 0x3ffU +#define LKPTBLQUEUE1_G(x) (((x) >> LKPTBLQUEUE1_S) & LKPTBLQUEUE1_M) + +#define LKPTBLQUEUE0_S 0 +#define LKPTBLQUEUE0_M 0x3ffU +#define LKPTBLQUEUE0_G(x) (((x) >> LKPTBLQUEUE0_S) & LKPTBLQUEUE0_M) + +#define TP_PIO_ADDR_A 0x7e40 +#define TP_PIO_DATA_A 0x7e44 +#define TP_MIB_INDEX_A 0x7e50 +#define TP_MIB_DATA_A 0x7e54 +#define TP_INT_CAUSE_A 0x7e74 + +#define FLMTXFLSTEMPTY_S 30 +#define FLMTXFLSTEMPTY_V(x) ((x) << FLMTXFLSTEMPTY_S) +#define FLMTXFLSTEMPTY_F FLMTXFLSTEMPTY_V(1U) + +#define TP_VLAN_PRI_MAP_A 0x140 + +#define FRAGMENTATION_S 9 +#define FRAGMENTATION_V(x) ((x) << FRAGMENTATION_S) +#define FRAGMENTATION_F FRAGMENTATION_V(1U) + +#define MPSHITTYPE_S 8 +#define MPSHITTYPE_V(x) ((x) << MPSHITTYPE_S) +#define MPSHITTYPE_F MPSHITTYPE_V(1U) + +#define MACMATCH_S 7 +#define MACMATCH_V(x) ((x) << MACMATCH_S) +#define MACMATCH_F MACMATCH_V(1U) + +#define ETHERTYPE_S 6 +#define ETHERTYPE_V(x) ((x) << ETHERTYPE_S) +#define ETHERTYPE_F ETHERTYPE_V(1U) + +#define PROTOCOL_S 5 +#define PROTOCOL_V(x) ((x) << PROTOCOL_S) +#define PROTOCOL_F PROTOCOL_V(1U) + +#define TOS_S 4 +#define TOS_V(x) ((x) << TOS_S) +#define TOS_F TOS_V(1U) + +#define VLAN_S 3 +#define VLAN_V(x) ((x) << VLAN_S) +#define VLAN_F VLAN_V(1U) + +#define VNIC_ID_S 2 +#define VNIC_ID_V(x) ((x) << VNIC_ID_S) +#define VNIC_ID_F VNIC_ID_V(1U) + +#define PORT_S 1 +#define PORT_V(x) ((x) << PORT_S) +#define PORT_F PORT_V(1U) + +#define FCOE_S 0 +#define FCOE_V(x) ((x) << FCOE_S) +#define FCOE_F FCOE_V(1U) + +#define FILTERMODE_S 15 +#define FILTERMODE_V(x) ((x) << FILTERMODE_S) +#define FILTERMODE_F FILTERMODE_V(1U) + +#define FCOEMASK_S 14 +#define FCOEMASK_V(x) ((x) << FCOEMASK_S) +#define FCOEMASK_F FCOEMASK_V(1U) + +#define TP_INGRESS_CONFIG_A 0x141 + +#define VNIC_S 11 +#define VNIC_V(x) ((x) << VNIC_S) +#define VNIC_F VNIC_V(1U) + +#define CSUM_HAS_PSEUDO_HDR_S 10 +#define CSUM_HAS_PSEUDO_HDR_V(x) ((x) << CSUM_HAS_PSEUDO_HDR_S) +#define CSUM_HAS_PSEUDO_HDR_F CSUM_HAS_PSEUDO_HDR_V(1U) + +#define TP_MIB_MAC_IN_ERR_0_A 0x0 +#define TP_MIB_TCP_OUT_RST_A 0xc +#define TP_MIB_TCP_IN_SEG_HI_A 0x10 +#define TP_MIB_TCP_IN_SEG_LO_A 0x11 +#define TP_MIB_TCP_OUT_SEG_HI_A 0x12 +#define TP_MIB_TCP_OUT_SEG_LO_A 0x13 +#define TP_MIB_TCP_RXT_SEG_HI_A 0x14 +#define TP_MIB_TCP_RXT_SEG_LO_A 0x15 +#define TP_MIB_TNL_CNG_DROP_0_A 0x18 +#define TP_MIB_TCP_V6IN_ERR_0_A 0x28 +#define TP_MIB_TCP_V6OUT_RST_A 0x2c +#define TP_MIB_OFD_ARP_DROP_A 0x36 +#define TP_MIB_TNL_DROP_0_A 0x44 +#define TP_MIB_OFD_VLN_DROP_0_A 0x58 + +#define ULP_TX_INT_CAUSE_A 0x8dcc + +#define PBL_BOUND_ERR_CH3_S 31 +#define PBL_BOUND_ERR_CH3_V(x) ((x) << PBL_BOUND_ERR_CH3_S) +#define PBL_BOUND_ERR_CH3_F PBL_BOUND_ERR_CH3_V(1U) + +#define PBL_BOUND_ERR_CH2_S 30 +#define PBL_BOUND_ERR_CH2_V(x) ((x) << PBL_BOUND_ERR_CH2_S) +#define PBL_BOUND_ERR_CH2_F PBL_BOUND_ERR_CH2_V(1U) + +#define PBL_BOUND_ERR_CH1_S 29 +#define PBL_BOUND_ERR_CH1_V(x) ((x) << PBL_BOUND_ERR_CH1_S) +#define PBL_BOUND_ERR_CH1_F PBL_BOUND_ERR_CH1_V(1U) + +#define PBL_BOUND_ERR_CH0_S 28 +#define PBL_BOUND_ERR_CH0_V(x) ((x) << PBL_BOUND_ERR_CH0_S) +#define PBL_BOUND_ERR_CH0_F PBL_BOUND_ERR_CH0_V(1U) + +#define PM_RX_INT_CAUSE_A 0x8fdc + +#define PMRX_FRAMING_ERROR_F 0x003ffff0U + +#define ZERO_E_CMD_ERROR_S 22 +#define ZERO_E_CMD_ERROR_V(x) ((x) << ZERO_E_CMD_ERROR_S) +#define ZERO_E_CMD_ERROR_F ZERO_E_CMD_ERROR_V(1U) + +#define OCSPI_PAR_ERROR_S 3 +#define OCSPI_PAR_ERROR_V(x) ((x) << OCSPI_PAR_ERROR_S) +#define OCSPI_PAR_ERROR_F OCSPI_PAR_ERROR_V(1U) + +#define DB_OPTIONS_PAR_ERROR_S 2 +#define DB_OPTIONS_PAR_ERROR_V(x) ((x) << DB_OPTIONS_PAR_ERROR_S) +#define DB_OPTIONS_PAR_ERROR_F DB_OPTIONS_PAR_ERROR_V(1U) + +#define IESPI_PAR_ERROR_S 1 +#define IESPI_PAR_ERROR_V(x) ((x) << IESPI_PAR_ERROR_S) +#define IESPI_PAR_ERROR_F IESPI_PAR_ERROR_V(1U) + +#define PMRX_E_PCMD_PAR_ERROR_S 0 +#define PMRX_E_PCMD_PAR_ERROR_V(x) ((x) << PMRX_E_PCMD_PAR_ERROR_S) +#define PMRX_E_PCMD_PAR_ERROR_F PMRX_E_PCMD_PAR_ERROR_V(1U) + +#define PM_TX_INT_CAUSE_A 0x8ffc + +#define PCMD_LEN_OVFL0_S 31 +#define PCMD_LEN_OVFL0_V(x) ((x) << PCMD_LEN_OVFL0_S) +#define PCMD_LEN_OVFL0_F PCMD_LEN_OVFL0_V(1U) + +#define PCMD_LEN_OVFL1_S 30 +#define PCMD_LEN_OVFL1_V(x) ((x) << PCMD_LEN_OVFL1_S) +#define PCMD_LEN_OVFL1_F PCMD_LEN_OVFL1_V(1U) + +#define PCMD_LEN_OVFL2_S 29 +#define PCMD_LEN_OVFL2_V(x) ((x) << PCMD_LEN_OVFL2_S) +#define PCMD_LEN_OVFL2_F PCMD_LEN_OVFL2_V(1U) + +#define ZERO_C_CMD_ERROR_S 28 +#define ZERO_C_CMD_ERROR_V(x) ((x) << ZERO_C_CMD_ERROR_S) +#define ZERO_C_CMD_ERROR_F ZERO_C_CMD_ERROR_V(1U) + +#define PMTX_FRAMING_ERROR_F 0x0ffffff0U + +#define OESPI_PAR_ERROR_S 3 +#define OESPI_PAR_ERROR_V(x) ((x) << OESPI_PAR_ERROR_S) +#define OESPI_PAR_ERROR_F OESPI_PAR_ERROR_V(1U) + +#define ICSPI_PAR_ERROR_S 1 +#define ICSPI_PAR_ERROR_V(x) ((x) << ICSPI_PAR_ERROR_S) +#define ICSPI_PAR_ERROR_F ICSPI_PAR_ERROR_V(1U) + +#define PMTX_C_PCMD_PAR_ERROR_S 0 +#define PMTX_C_PCMD_PAR_ERROR_V(x) ((x) << PMTX_C_PCMD_PAR_ERROR_S) +#define PMTX_C_PCMD_PAR_ERROR_F PMTX_C_PCMD_PAR_ERROR_V(1U) #define MPS_PORT_STAT_TX_PORT_BYTES_L 0x400 #define MPS_PORT_STAT_TX_PORT_BYTES_H 0x404 @@ -1462,41 +1562,57 @@ #define MPS_PORT_STAT_RX_PORT_PPP7_H 0x60c #define MPS_PORT_STAT_RX_PORT_LESS_64B_L 0x610 #define MPS_PORT_STAT_RX_PORT_LESS_64B_H 0x614 -#define MAC_PORT_CFG2 0x818 #define MAC_PORT_MAGIC_MACID_LO 0x824 #define MAC_PORT_MAGIC_MACID_HI 0x828 -#define MAC_PORT_EPIO_DATA0 0x8c0 -#define MAC_PORT_EPIO_DATA1 0x8c4 -#define MAC_PORT_EPIO_DATA2 0x8c8 -#define MAC_PORT_EPIO_DATA3 0x8cc -#define MAC_PORT_EPIO_OP 0x8d0 - -#define MPS_CMN_CTL 0x9000 -#define NUMPORTS_MASK 0x00000003U -#define NUMPORTS_SHIFT 0 -#define NUMPORTS_GET(x) (((x) & NUMPORTS_MASK) >> NUMPORTS_SHIFT) - -#define MPS_INT_CAUSE 0x9008 -#define STATINT 0x00000020U -#define TXINT 0x00000010U -#define RXINT 0x00000008U -#define TRCINT 0x00000004U -#define CLSINT 0x00000002U -#define PLINT 0x00000001U - -#define MPS_TX_INT_CAUSE 0x9408 -#define PORTERR 0x00010000U -#define FRMERR 0x00008000U -#define SECNTERR 0x00004000U -#define BUBBLE 0x00002000U -#define TXDESCFIFO 0x00001e00U -#define TXDATAFIFO 0x000001e0U -#define NCSIFIFO 0x00000010U -#define TPFIFO 0x0000000fU - -#define MPS_STAT_PERR_INT_CAUSE_SRAM 0x9614 -#define MPS_STAT_PERR_INT_CAUSE_TX_FIFO 0x9620 -#define MPS_STAT_PERR_INT_CAUSE_RX_FIFO 0x962c + +#define MAC_PORT_EPIO_DATA0_A 0x8c0 +#define MAC_PORT_EPIO_DATA1_A 0x8c4 +#define MAC_PORT_EPIO_DATA2_A 0x8c8 +#define MAC_PORT_EPIO_DATA3_A 0x8cc +#define MAC_PORT_EPIO_OP_A 0x8d0 + +#define MAC_PORT_CFG2_A 0x818 + +#define MPS_CMN_CTL_A 0x9000 + +#define NUMPORTS_S 0 +#define NUMPORTS_M 0x3U +#define NUMPORTS_G(x) (((x) >> NUMPORTS_S) & NUMPORTS_M) + +#define MPS_INT_CAUSE_A 0x9008 +#define MPS_TX_INT_CAUSE_A 0x9408 + +#define FRMERR_S 15 +#define FRMERR_V(x) ((x) << FRMERR_S) +#define FRMERR_F FRMERR_V(1U) + +#define SECNTERR_S 14 +#define SECNTERR_V(x) ((x) << SECNTERR_S) +#define SECNTERR_F SECNTERR_V(1U) + +#define BUBBLE_S 13 +#define BUBBLE_V(x) ((x) << BUBBLE_S) +#define BUBBLE_F BUBBLE_V(1U) + +#define TXDESCFIFO_S 9 +#define TXDESCFIFO_M 0xfU +#define TXDESCFIFO_V(x) ((x) << TXDESCFIFO_S) + +#define TXDATAFIFO_S 5 +#define TXDATAFIFO_M 0xfU +#define TXDATAFIFO_V(x) ((x) << TXDATAFIFO_S) + +#define NCSIFIFO_S 4 +#define NCSIFIFO_V(x) ((x) << NCSIFIFO_S) +#define NCSIFIFO_F NCSIFIFO_V(1U) + +#define TPFIFO_S 0 +#define TPFIFO_M 0xfU +#define TPFIFO_V(x) ((x) << TPFIFO_S) + +#define MPS_STAT_PERR_INT_CAUSE_SRAM_A 0x9614 +#define MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A 0x9620 +#define MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A 0x962c #define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L 0x9640 #define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_H 0x9644 @@ -1530,66 +1646,67 @@ #define MPS_STAT_RX_BG_2_LB_TRUNC_FRAME_H 0x96b4 #define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_L 0x96b8 #define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_H 0x96bc -#define MPS_TRC_CFG 0x9800 -#define TRCFIFOEMPTY 0x00000010U -#define TRCIGNOREDROPINPUT 0x00000008U -#define TRCKEEPDUPLICATES 0x00000004U -#define TRCEN 0x00000002U -#define TRCMULTIFILTER 0x00000001U - -#define MPS_TRC_RSS_CONTROL 0x9808 -#define MPS_T5_TRC_RSS_CONTROL 0xa00c -#define RSSCONTROL_MASK 0x00ff0000U -#define RSSCONTROL_SHIFT 16 -#define RSSCONTROL(x) ((x) << RSSCONTROL_SHIFT) -#define QUEUENUMBER_MASK 0x0000ffffU -#define QUEUENUMBER_SHIFT 0 -#define QUEUENUMBER(x) ((x) << QUEUENUMBER_SHIFT) - -#define MPS_TRC_FILTER_MATCH_CTL_A 0x9810 -#define TFINVERTMATCH 0x01000000U -#define TFPKTTOOLARGE 0x00800000U -#define TFEN 0x00400000U -#define TFPORT_MASK 0x003c0000U -#define TFPORT_SHIFT 18 -#define TFPORT(x) ((x) << TFPORT_SHIFT) -#define TFPORT_GET(x) (((x) & TFPORT_MASK) >> TFPORT_SHIFT) -#define TFDROP 0x00020000U -#define TFSOPEOPERR 0x00010000U -#define TFLENGTH_MASK 0x00001f00U -#define TFLENGTH_SHIFT 8 -#define TFLENGTH(x) ((x) << TFLENGTH_SHIFT) -#define TFLENGTH_GET(x) (((x) & TFLENGTH_MASK) >> TFLENGTH_SHIFT) -#define TFOFFSET_MASK 0x0000001fU -#define TFOFFSET_SHIFT 0 -#define TFOFFSET(x) ((x) << TFOFFSET_SHIFT) -#define TFOFFSET_GET(x) (((x) & TFOFFSET_MASK) >> TFOFFSET_SHIFT) - -#define MPS_TRC_FILTER_MATCH_CTL_B 0x9820 -#define TFMINPKTSIZE_MASK 0x01ff0000U -#define TFMINPKTSIZE_SHIFT 16 -#define TFMINPKTSIZE(x) ((x) << TFMINPKTSIZE_SHIFT) -#define TFMINPKTSIZE_GET(x) (((x) & TFMINPKTSIZE_MASK) >> TFMINPKTSIZE_SHIFT) -#define TFCAPTUREMAX_MASK 0x00003fffU -#define TFCAPTUREMAX_SHIFT 0 -#define TFCAPTUREMAX(x) ((x) << TFCAPTUREMAX_SHIFT) -#define TFCAPTUREMAX_GET(x) (((x) & TFCAPTUREMAX_MASK) >> TFCAPTUREMAX_SHIFT) - -#define MPS_TRC_INT_CAUSE 0x985c -#define MISCPERR 0x00000100U -#define PKTFIFO 0x000000f0U -#define FILTMEM 0x0000000fU - -#define MPS_TRC_FILTER0_MATCH 0x9c00 -#define MPS_TRC_FILTER0_DONT_CARE 0x9c80 -#define MPS_TRC_FILTER1_MATCH 0x9d00 -#define MPS_CLS_INT_CAUSE 0xd028 -#define PLERRENB 0x00000008U -#define HASHSRAM 0x00000004U -#define MATCHTCAM 0x00000002U -#define MATCHSRAM 0x00000001U - -#define MPS_RX_PERR_INT_CAUSE 0x11074 + +#define MPS_TRC_CFG_A 0x9800 + +#define TRCFIFOEMPTY_S 4 +#define TRCFIFOEMPTY_V(x) ((x) << TRCFIFOEMPTY_S) +#define TRCFIFOEMPTY_F TRCFIFOEMPTY_V(1U) + +#define TRCIGNOREDROPINPUT_S 3 +#define TRCIGNOREDROPINPUT_V(x) ((x) << TRCIGNOREDROPINPUT_S) +#define TRCIGNOREDROPINPUT_F TRCIGNOREDROPINPUT_V(1U) + +#define TRCKEEPDUPLICATES_S 2 +#define TRCKEEPDUPLICATES_V(x) ((x) << TRCKEEPDUPLICATES_S) +#define TRCKEEPDUPLICATES_F TRCKEEPDUPLICATES_V(1U) + +#define TRCEN_S 1 +#define TRCEN_V(x) ((x) << TRCEN_S) +#define TRCEN_F TRCEN_V(1U) + +#define TRCMULTIFILTER_S 0 +#define TRCMULTIFILTER_V(x) ((x) << TRCMULTIFILTER_S) +#define TRCMULTIFILTER_F TRCMULTIFILTER_V(1U) + +#define MPS_TRC_RSS_CONTROL_A 0x9808 +#define MPS_T5_TRC_RSS_CONTROL_A 0xa00c + +#define RSSCONTROL_S 16 +#define RSSCONTROL_V(x) ((x) << RSSCONTROL_S) + +#define QUEUENUMBER_S 0 +#define QUEUENUMBER_V(x) ((x) << QUEUENUMBER_S) + +#define MPS_TRC_INT_CAUSE_A 0x985c + +#define MISCPERR_S 8 +#define MISCPERR_V(x) ((x) << MISCPERR_S) +#define MISCPERR_F MISCPERR_V(1U) + +#define PKTFIFO_S 4 +#define PKTFIFO_M 0xfU +#define PKTFIFO_V(x) ((x) << PKTFIFO_S) + +#define FILTMEM_S 0 +#define FILTMEM_M 0xfU +#define FILTMEM_V(x) ((x) << FILTMEM_S) + +#define MPS_CLS_INT_CAUSE_A 0xd028 + +#define HASHSRAM_S 2 +#define HASHSRAM_V(x) ((x) << HASHSRAM_S) +#define HASHSRAM_F HASHSRAM_V(1U) + +#define MATCHTCAM_S 1 +#define MATCHTCAM_V(x) ((x) << MATCHTCAM_S) +#define MATCHTCAM_F MATCHTCAM_V(1U) + +#define MATCHSRAM_S 0 +#define MATCHSRAM_V(x) ((x) << MATCHSRAM_S) +#define MATCHSRAM_F MATCHSRAM_V(1U) + +#define MPS_RX_PERR_INT_CAUSE_A 0x11074 #define CPL_INTR_CAUSE 0x19054 #define CIM_OP_MAP_PERR 0x00000020U -- cgit v1.2.1 From 0d8043389bf3abc86016995bfe3d3314dd5b3db7 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 5 Jan 2015 16:30:47 +0530 Subject: cxgb4/cxgb4vf/csiostor: Cleanup PL, XGMAC, SF and MC related register defines This patch cleanups all PL, XGMAC and SF related macros/register defines that are defined in t4_regs.h and the affected files Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 56 +-- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 9 +- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 258 +++++----- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 538 +++++++++++---------- drivers/net/ethernet/chelsio/cxgb4/t4_values.h | 33 ++ .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 2 +- drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 6 +- 7 files changed, 493 insertions(+), 409 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 53ad8d3d9e4c..04e675b8218a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -834,11 +834,11 @@ static void disable_msi(struct adapter *adapter) static irqreturn_t t4_nondata_intr(int irq, void *cookie) { struct adapter *adap = cookie; + u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A)); - u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE)); - if (v & PFSW) { + if (v & PFSW_F) { adap->swintr = 1; - t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE), v); + t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A), v); } t4_slow_intr_handler(adap); return IRQ_HANDLED; @@ -3654,10 +3654,10 @@ void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, { struct adapter *adap = netdev2adap(dev); - t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK, tag_mask); - t4_write_reg(adap, ULP_RX_ISCSI_PSZ, HPZ0(pgsz_order[0]) | - HPZ1(pgsz_order[1]) | HPZ2(pgsz_order[2]) | - HPZ3(pgsz_order[3])); + t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK_A, tag_mask); + t4_write_reg(adap, ULP_RX_ISCSI_PSZ_A, HPZ0_V(pgsz_order[0]) | + HPZ1_V(pgsz_order[1]) | HPZ2_V(pgsz_order[2]) | + HPZ3_V(pgsz_order[3])); } EXPORT_SYMBOL(cxgb4_iscsi_init); @@ -4580,13 +4580,13 @@ int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid, f->fs.val.lip[i] = val[i]; f->fs.mask.lip[i] = ~0; } - if (adap->params.tp.vlan_pri_map & F_PORT) { + if (adap->params.tp.vlan_pri_map & PORT_F) { f->fs.val.iport = port; f->fs.mask.iport = mask; } } - if (adap->params.tp.vlan_pri_map & F_PROTOCOL) { + if (adap->params.tp.vlan_pri_map & PROTOCOL_F) { f->fs.val.proto = IPPROTO_TCP; f->fs.mask.proto = ~0; } @@ -4950,37 +4950,37 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) /* tweak some settings */ t4_write_reg(adap, TP_SHIFT_CNT_A, 0x64f8849); - t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12)); + t4_write_reg(adap, ULP_RX_TDDP_PSZ_A, HPZ0_V(PAGE_SHIFT - 12)); t4_write_reg(adap, TP_PIO_ADDR_A, TP_INGRESS_CONFIG_A); v = t4_read_reg(adap, TP_PIO_DATA_A); t4_write_reg(adap, TP_PIO_DATA_A, v & ~CSUM_HAS_PSEUDO_HDR_F); /* first 4 Tx modulation queues point to consecutive Tx channels */ adap->params.tp.tx_modq_map = 0xE4; - t4_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, - V_TX_MOD_QUEUE_REQ_MAP(adap->params.tp.tx_modq_map)); + t4_write_reg(adap, TP_TX_MOD_QUEUE_REQ_MAP_A, + TX_MOD_QUEUE_REQ_MAP_V(adap->params.tp.tx_modq_map)); /* associate each Tx modulation queue with consecutive Tx channels */ v = 0x84218421; t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, - &v, 1, A_TP_TX_SCHED_HDR); + &v, 1, TP_TX_SCHED_HDR_A); t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, - &v, 1, A_TP_TX_SCHED_FIFO); + &v, 1, TP_TX_SCHED_FIFO_A); t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, - &v, 1, A_TP_TX_SCHED_PCMD); + &v, 1, TP_TX_SCHED_PCMD_A); #define T4_TX_MODQ_10G_WEIGHT_DEFAULT 16 /* in KB units */ if (is_offload(adap)) { - t4_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, - V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); - t4_write_reg(adap, A_TP_TX_MOD_CHANNEL_WEIGHT, - V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); + t4_write_reg(adap, TP_TX_MOD_QUEUE_WEIGHT0_A, + TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); + t4_write_reg(adap, TP_TX_MOD_CHANNEL_WEIGHT_A, + TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); } /* get basic stuff going */ @@ -5059,7 +5059,7 @@ static int adap_init0_config(struct adapter *adapter, int reset) */ if (reset) { ret = t4_fw_reset(adapter, adapter->mbox, - PIORSTMODE | PIORST); + PIORSTMODE_F | PIORST_F); if (ret < 0) goto bye; } @@ -5264,7 +5264,7 @@ static int adap_init0_no_config(struct adapter *adapter, int reset) */ if (reset) { ret = t4_fw_reset(adapter, adapter->mbox, - PIORSTMODE | PIORST); + PIORSTMODE_F | PIORST_F); if (ret < 0) goto bye; } @@ -6413,7 +6413,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_unmap_bar0; /* We control everything through one PF */ - func = SOURCEPF_GET(readl(regs + PL_WHOAMI)); + func = SOURCEPF_G(readl(regs + PL_WHOAMI_A)); if (func != ent->driver_data) { iounmap(regs); pci_disable_device(pdev); diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index a047baa9fd04..5ae14451c3a4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -46,6 +46,7 @@ #include "t4_msg.h" #include "t4fw_api.h" #include "t4_regs.h" +#include "t4_values.h" #define VLAN_NONE 0xfff @@ -425,7 +426,7 @@ u64 cxgb4_select_ntuple(struct net_device *dev, * in the Compressed Filter Tuple. */ if (tp->vlan_shift >= 0 && l2t->vlan != VLAN_NONE) - ntuple |= (u64)(F_FT_VLAN_VLD | l2t->vlan) << tp->vlan_shift; + ntuple |= (u64)(FT_VLAN_VLD_F | l2t->vlan) << tp->vlan_shift; if (tp->port_shift >= 0) ntuple |= (u64)l2t->lport << tp->port_shift; @@ -439,9 +440,9 @@ u64 cxgb4_select_ntuple(struct net_device *dev, u32 pf = FW_VIID_PFN_G(viid); u32 vld = FW_VIID_VIVLD_G(viid); - ntuple |= (u64)(V_FT_VNID_ID_VF(vf) | - V_FT_VNID_ID_PF(pf) | - V_FT_VNID_ID_VLD(vld)) << tp->vnic_shift; + ntuple |= (u64)(FT_VNID_ID_VF_V(vf) | + FT_VNID_ID_PF_V(pf) | + FT_VNID_ID_VLD_V(vld)) << tp->vnic_shift; } return ntuple; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index cf0bf79a6193..3776279337c8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -761,14 +761,13 @@ static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, if (!byte_cnt || byte_cnt > 4) return -EINVAL; - if (t4_read_reg(adapter, SF_OP) & SF_BUSY) + if (t4_read_reg(adapter, SF_OP_A) & SF_BUSY_F) return -EBUSY; - cont = cont ? SF_CONT : 0; - lock = lock ? SF_LOCK : 0; - t4_write_reg(adapter, SF_OP, lock | cont | BYTECNT(byte_cnt - 1)); - ret = t4_wait_op_done(adapter, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 5); + t4_write_reg(adapter, SF_OP_A, SF_LOCK_V(lock) | + SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1)); + ret = t4_wait_op_done(adapter, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 5); if (!ret) - *valp = t4_read_reg(adapter, SF_DATA); + *valp = t4_read_reg(adapter, SF_DATA_A); return ret; } @@ -789,14 +788,12 @@ static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, { if (!byte_cnt || byte_cnt > 4) return -EINVAL; - if (t4_read_reg(adapter, SF_OP) & SF_BUSY) + if (t4_read_reg(adapter, SF_OP_A) & SF_BUSY_F) return -EBUSY; - cont = cont ? SF_CONT : 0; - lock = lock ? SF_LOCK : 0; - t4_write_reg(adapter, SF_DATA, val); - t4_write_reg(adapter, SF_OP, lock | - cont | BYTECNT(byte_cnt - 1) | OP_WR); - return t4_wait_op_done(adapter, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 5); + t4_write_reg(adapter, SF_DATA_A, val); + t4_write_reg(adapter, SF_OP_A, SF_LOCK_V(lock) | + SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1) | OP_V(1)); + return t4_wait_op_done(adapter, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 5); } /** @@ -855,7 +852,7 @@ static int t4_read_flash(struct adapter *adapter, unsigned int addr, for ( ; nwords; nwords--, data++) { ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data); if (nwords == 1) - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ if (ret) return ret; if (byte_oriented) @@ -903,7 +900,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr, if (ret) goto unlock; - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ /* Read the page to verify the write succeeded */ ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); @@ -919,7 +916,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr, return 0; unlock: - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ return ret; } @@ -1114,7 +1111,7 @@ static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) } start++; } - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ return ret; } @@ -1619,7 +1616,7 @@ static void ulprx_intr_handler(struct adapter *adapter) { 0 } }; - if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE, ulprx_intr_info)) + if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE_A, ulprx_intr_info)) t4_fatal_err(adapter); } @@ -1694,16 +1691,16 @@ static void pmrx_intr_handler(struct adapter *adapter) static void cplsw_intr_handler(struct adapter *adapter) { static const struct intr_info cplsw_intr_info[] = { - { CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 }, - { CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 }, - { TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 }, - { SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 }, - { CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 }, - { ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 }, + { CIM_OP_MAP_PERR_F, "CPLSW CIM op_map parity error", -1, 1 }, + { CIM_OVFL_ERROR_F, "CPLSW CIM overflow", -1, 1 }, + { TP_FRAMING_ERROR_F, "CPLSW TP framing error", -1, 1 }, + { SGE_FRAMING_ERROR_F, "CPLSW SGE framing error", -1, 1 }, + { CIM_FRAMING_ERROR_F, "CPLSW CIM framing error", -1, 1 }, + { ZERO_SWITCH_ERROR_F, "CPLSW no-switch error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE, cplsw_intr_info)) + if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE_A, cplsw_intr_info)) t4_fatal_err(adapter); } @@ -1713,15 +1710,15 @@ static void cplsw_intr_handler(struct adapter *adapter) static void le_intr_handler(struct adapter *adap) { static const struct intr_info le_intr_info[] = { - { LIPMISS, "LE LIP miss", -1, 0 }, - { LIP0, "LE 0 LIP error", -1, 0 }, - { PARITYERR, "LE parity error", -1, 1 }, - { UNKNOWNCMD, "LE unknown command", -1, 1 }, - { REQQPARERR, "LE request queue parity error", -1, 1 }, + { LIPMISS_F, "LE LIP miss", -1, 0 }, + { LIP0_F, "LE 0 LIP error", -1, 0 }, + { PARITYERR_F, "LE parity error", -1, 1 }, + { UNKNOWNCMD_F, "LE unknown command", -1, 1 }, + { REQQPARERR_F, "LE request queue parity error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE, le_intr_info)) + if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE_A, le_intr_info)) t4_fatal_err(adap); } @@ -1879,13 +1876,13 @@ static void ma_intr_handler(struct adapter *adap) static void smb_intr_handler(struct adapter *adap) { static const struct intr_info smb_intr_info[] = { - { MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 }, - { MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 }, - { SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 }, + { MSTTXFIFOPARINT_F, "SMB master Tx FIFO parity error", -1, 1 }, + { MSTRXFIFOPARINT_F, "SMB master Rx FIFO parity error", -1, 1 }, + { SLVFIFOPARINT_F, "SMB slave FIFO parity error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adap, SMB_INT_CAUSE, smb_intr_info)) + if (t4_handle_intr_status(adap, SMB_INT_CAUSE_A, smb_intr_info)) t4_fatal_err(adap); } @@ -1895,14 +1892,14 @@ static void smb_intr_handler(struct adapter *adap) static void ncsi_intr_handler(struct adapter *adap) { static const struct intr_info ncsi_intr_info[] = { - { CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 }, - { MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 }, - { TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 }, - { RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 }, + { CIM_DM_PRTY_ERR_F, "NC-SI CIM parity error", -1, 1 }, + { MPS_DM_PRTY_ERR_F, "NC-SI MPS parity error", -1, 1 }, + { TXFIFO_PRTY_ERR_F, "NC-SI Tx FIFO parity error", -1, 1 }, + { RXFIFO_PRTY_ERR_F, "NC-SI Rx FIFO parity error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adap, NCSI_INT_CAUSE, ncsi_intr_info)) + if (t4_handle_intr_status(adap, NCSI_INT_CAUSE_A, ncsi_intr_info)) t4_fatal_err(adap); } @@ -1914,23 +1911,23 @@ static void xgmac_intr_handler(struct adapter *adap, int port) u32 v, int_cause_reg; if (is_t4(adap->params.chip)) - int_cause_reg = PORT_REG(port, XGMAC_PORT_INT_CAUSE); + int_cause_reg = PORT_REG(port, XGMAC_PORT_INT_CAUSE_A); else - int_cause_reg = T5_PORT_REG(port, MAC_PORT_INT_CAUSE); + int_cause_reg = T5_PORT_REG(port, MAC_PORT_INT_CAUSE_A); v = t4_read_reg(adap, int_cause_reg); - v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR; + v &= TXFIFO_PRTY_ERR_F | RXFIFO_PRTY_ERR_F; if (!v) return; - if (v & TXFIFO_PRTY_ERR) + if (v & TXFIFO_PRTY_ERR_F) dev_alert(adap->pdev_dev, "XGMAC %d Tx FIFO parity error\n", port); - if (v & RXFIFO_PRTY_ERR) + if (v & RXFIFO_PRTY_ERR_F) dev_alert(adap->pdev_dev, "XGMAC %d Rx FIFO parity error\n", port); - t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE), v); + t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE_A), v); t4_fatal_err(adap); } @@ -1940,19 +1937,19 @@ static void xgmac_intr_handler(struct adapter *adap, int port) static void pl_intr_handler(struct adapter *adap) { static const struct intr_info pl_intr_info[] = { - { FATALPERR, "T4 fatal parity error", -1, 1 }, - { PERRVFID, "PL VFID_MAP parity error", -1, 1 }, + { FATALPERR_F, "T4 fatal parity error", -1, 1 }, + { PERRVFID_F, "PL VFID_MAP parity error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE, pl_intr_info)) + if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE_A, pl_intr_info)) t4_fatal_err(adap); } -#define PF_INTR_MASK (PFSW) -#define GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \ - EDC1 | LE | TP | MA | PM_TX | PM_RX | ULP_RX | \ - CPL_SWITCH | SGE | ULP_TX) +#define PF_INTR_MASK (PFSW_F) +#define GLBL_INTR_MASK (CIM_F | MPS_F | PL_F | PCIE_F | MC_F | EDC0_F | \ + EDC1_F | LE_F | TP_F | MA_F | PM_TX_F | PM_RX_F | ULP_RX_F | \ + CPL_SWITCH_F | SGE_F | ULP_TX_F) /** * t4_slow_intr_handler - control path interrupt handler @@ -1964,60 +1961,60 @@ static void pl_intr_handler(struct adapter *adap) */ int t4_slow_intr_handler(struct adapter *adapter) { - u32 cause = t4_read_reg(adapter, PL_INT_CAUSE); + u32 cause = t4_read_reg(adapter, PL_INT_CAUSE_A); if (!(cause & GLBL_INTR_MASK)) return 0; - if (cause & CIM) + if (cause & CIM_F) cim_intr_handler(adapter); - if (cause & MPS) + if (cause & MPS_F) mps_intr_handler(adapter); - if (cause & NCSI) + if (cause & NCSI_F) ncsi_intr_handler(adapter); - if (cause & PL) + if (cause & PL_F) pl_intr_handler(adapter); - if (cause & SMB) + if (cause & SMB_F) smb_intr_handler(adapter); - if (cause & XGMAC0) + if (cause & XGMAC0_F) xgmac_intr_handler(adapter, 0); - if (cause & XGMAC1) + if (cause & XGMAC1_F) xgmac_intr_handler(adapter, 1); - if (cause & XGMAC_KR0) + if (cause & XGMAC_KR0_F) xgmac_intr_handler(adapter, 2); - if (cause & XGMAC_KR1) + if (cause & XGMAC_KR1_F) xgmac_intr_handler(adapter, 3); - if (cause & PCIE) + if (cause & PCIE_F) pcie_intr_handler(adapter); - if (cause & MC) + if (cause & MC_F) mem_intr_handler(adapter, MEM_MC); - if (!is_t4(adapter->params.chip) && (cause & MC1)) + if (!is_t4(adapter->params.chip) && (cause & MC1_S)) mem_intr_handler(adapter, MEM_MC1); - if (cause & EDC0) + if (cause & EDC0_F) mem_intr_handler(adapter, MEM_EDC0); - if (cause & EDC1) + if (cause & EDC1_F) mem_intr_handler(adapter, MEM_EDC1); - if (cause & LE) + if (cause & LE_F) le_intr_handler(adapter); - if (cause & TP) + if (cause & TP_F) tp_intr_handler(adapter); - if (cause & MA) + if (cause & MA_F) ma_intr_handler(adapter); - if (cause & PM_TX) + if (cause & PM_TX_F) pmtx_intr_handler(adapter); - if (cause & PM_RX) + if (cause & PM_RX_F) pmrx_intr_handler(adapter); - if (cause & ULP_RX) + if (cause & ULP_RX_F) ulprx_intr_handler(adapter); - if (cause & CPL_SWITCH) + if (cause & CPL_SWITCH_F) cplsw_intr_handler(adapter); - if (cause & SGE) + if (cause & SGE_F) sge_intr_handler(adapter); - if (cause & ULP_TX) + if (cause & ULP_TX_F) ulptx_intr_handler(adapter); /* Clear the interrupts just processed for which we are the master. */ - t4_write_reg(adapter, PL_INT_CAUSE, cause & GLBL_INTR_MASK); - (void) t4_read_reg(adapter, PL_INT_CAUSE); /* flush */ + t4_write_reg(adapter, PL_INT_CAUSE_A, cause & GLBL_INTR_MASK); + (void)t4_read_reg(adapter, PL_INT_CAUSE_A); /* flush */ return 1; } @@ -2036,7 +2033,7 @@ int t4_slow_intr_handler(struct adapter *adapter) */ void t4_intr_enable(struct adapter *adapter) { - u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); + u32 pf = SOURCEPF_G(t4_read_reg(adapter, PL_WHOAMI_A)); t4_write_reg(adapter, SGE_INT_ENABLE3_A, ERR_CPL_EXCEED_IQE_SIZE_F | ERR_INVALID_CIDX_INC_F | ERR_CPL_OPCODE_0_F | @@ -2047,8 +2044,8 @@ void t4_intr_enable(struct adapter *adapter) ERR_EGR_CTXT_PRIO_F | INGRESS_SIZE_ERR_F | DBFIFO_HP_INT_F | DBFIFO_LP_INT_F | EGRESS_SIZE_ERR_F); - t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK); - t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf); + t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), PF_INTR_MASK); + t4_set_reg_field(adapter, PL_INT_MAP0_A, 0, 1 << pf); } /** @@ -2061,10 +2058,10 @@ void t4_intr_enable(struct adapter *adapter) */ void t4_intr_disable(struct adapter *adapter) { - u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); + u32 pf = SOURCEPF_G(t4_read_reg(adapter, PL_WHOAMI_A)); - t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), 0); - t4_set_reg_field(adapter, PL_INT_MAP0, 1 << pf, 0); + t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), 0); + t4_set_reg_field(adapter, PL_INT_MAP0_A, 1 << pf, 0); } /** @@ -2498,7 +2495,7 @@ void t4_wol_magic_enable(struct adapter *adap, unsigned int port, if (is_t4(adap->params.chip)) { mag_id_reg_l = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO); mag_id_reg_h = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI); - port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2); + port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2_A); } else { mag_id_reg_l = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_LO); mag_id_reg_h = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_HI); @@ -2512,8 +2509,8 @@ void t4_wol_magic_enable(struct adapter *adap, unsigned int port, t4_write_reg(adap, mag_id_reg_h, (addr[0] << 8) | addr[1]); } - t4_set_reg_field(adap, port_cfg_reg, MAGICEN, - addr ? MAGICEN : 0); + t4_set_reg_field(adap, port_cfg_reg, MAGICEN_F, + addr ? MAGICEN_F : 0); } /** @@ -2538,20 +2535,21 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, u32 port_cfg_reg; if (is_t4(adap->params.chip)) - port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2); + port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2_A); else port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A); if (!enable) { - t4_set_reg_field(adap, port_cfg_reg, PATEN, 0); + t4_set_reg_field(adap, port_cfg_reg, PATEN_F, 0); return 0; } if (map > 0xff) return -EINVAL; #define EPIO_REG(name) \ - (is_t4(adap->params.chip) ? PORT_REG(port, XGMAC_PORT_EPIO_##name) : \ - T5_PORT_REG(port, MAC_PORT_EPIO_##name##_A)) + (is_t4(adap->params.chip) ? \ + PORT_REG(port, XGMAC_PORT_EPIO_##name##_A) : \ + T5_PORT_REG(port, MAC_PORT_EPIO_##name##_A)) t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32); t4_write_reg(adap, EPIO_REG(DATA2), mask1); @@ -2563,21 +2561,21 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, /* write byte masks */ t4_write_reg(adap, EPIO_REG(DATA0), mask0); - t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i) | EPIOWR); + t4_write_reg(adap, EPIO_REG(OP), ADDRESS_V(i) | EPIOWR_F); t4_read_reg(adap, EPIO_REG(OP)); /* flush */ - if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY) + if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY_F) return -ETIMEDOUT; /* write CRC */ t4_write_reg(adap, EPIO_REG(DATA0), crc); - t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i + 32) | EPIOWR); + t4_write_reg(adap, EPIO_REG(OP), ADDRESS_V(i + 32) | EPIOWR_F); t4_read_reg(adap, EPIO_REG(OP)); /* flush */ - if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY) + if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY_F) return -ETIMEDOUT; } #undef EPIO_REG - t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), 0, PATEN); + t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2_A), 0, PATEN_F); return 0; } @@ -2998,7 +2996,7 @@ static int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force) memset(&c, 0, sizeof(c)); INIT_CMD(c, RESET, WRITE); - c.val = htonl(PIORST | PIORSTMODE); + c.val = htonl(PIORST_F | PIORSTMODE_F); c.halt_pkd = htonl(FW_RESET_CMD_HALT_F); ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -3071,11 +3069,11 @@ static int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset) t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0); msleep(100); if (t4_fw_reset(adap, mbox, - PIORST | PIORSTMODE) == 0) + PIORST_F | PIORSTMODE_F) == 0) return 0; } - t4_write_reg(adap, PL_RST, PIORST | PIORSTMODE); + t4_write_reg(adap, PL_RST_A, PIORST_F | PIORSTMODE_F); msleep(2000); } else { int ms; @@ -3246,7 +3244,7 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size, (t4_read_reg(adap, SGE_FL_BUFFER_SIZE3_A) + fl_align-1) & ~(fl_align-1)); - t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(page_shift - 12)); + t4_write_reg(adap, ULP_RX_TDDP_PSZ_A, HPZ0_V(page_shift - 12)); return 0; } @@ -3931,12 +3929,12 @@ int t4_wait_dev_ready(void __iomem *regs) { u32 whoami; - whoami = readl(regs + PL_WHOAMI); + whoami = readl(regs + PL_WHOAMI_A); if (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS) return 0; msleep(500); - whoami = readl(regs + PL_WHOAMI); + whoami = readl(regs + PL_WHOAMI_A); return (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS ? 0 : -EIO); } @@ -3960,7 +3958,7 @@ static int get_flash_params(struct adapter *adap) ret = sf1_write(adap, 1, 1, 0, SF_RD_ID); if (!ret) ret = sf1_read(adap, 3, 0, 1, &info); - t4_write_reg(adap, SF_OP, 0); /* unlock SF */ + t4_write_reg(adap, SF_OP_A, 0); /* unlock SF */ if (ret) return ret; @@ -4007,7 +4005,7 @@ int t4_prep_adapter(struct adapter *adapter) u32 pl_rev; get_pci_mode(adapter, &adapter->params.pci); - pl_rev = G_REV(t4_read_reg(adapter, PL_REV)); + pl_rev = REV_G(t4_read_reg(adapter, PL_REV_A)); ret = get_flash_params(adapter); if (ret < 0) { @@ -4197,16 +4195,16 @@ int t4_init_tp_params(struct adapter *adap) * shift positions of several elements of the Compressed Filter Tuple * for this adapter which we need frequently ... */ - adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN); - adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID); - adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT); + adap->params.tp.vlan_shift = t4_filter_field_shift(adap, VLAN_F); + adap->params.tp.vnic_shift = t4_filter_field_shift(adap, VNIC_ID_F); + adap->params.tp.port_shift = t4_filter_field_shift(adap, PORT_F); adap->params.tp.protocol_shift = t4_filter_field_shift(adap, - F_PROTOCOL); + PROTOCOL_F); /* If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID * represents the presense of an Outer VLAN instead of a VNIC ID. */ - if ((adap->params.tp.ingress_config & F_VNIC) == 0) + if ((adap->params.tp.ingress_config & VNIC_F) == 0) adap->params.tp.vnic_shift = -1; return 0; @@ -4232,35 +4230,35 @@ int t4_filter_field_shift(const struct adapter *adap, int filter_sel) for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) { switch (filter_mode & sel) { - case F_FCOE: - field_shift += W_FT_FCOE; + case FCOE_F: + field_shift += FT_FCOE_W; break; - case F_PORT: - field_shift += W_FT_PORT; + case PORT_F: + field_shift += FT_PORT_W; break; - case F_VNIC_ID: - field_shift += W_FT_VNIC_ID; + case VNIC_ID_F: + field_shift += FT_VNIC_ID_W; break; - case F_VLAN: - field_shift += W_FT_VLAN; + case VLAN_F: + field_shift += FT_VLAN_W; break; - case F_TOS: - field_shift += W_FT_TOS; + case TOS_F: + field_shift += FT_TOS_W; break; - case F_PROTOCOL: - field_shift += W_FT_PROTOCOL; + case PROTOCOL_F: + field_shift += FT_PROTOCOL_W; break; - case F_ETHERTYPE: - field_shift += W_FT_ETHERTYPE; + case ETHERTYPE_F: + field_shift += FT_ETHERTYPE_W; break; - case F_MACMATCH: - field_shift += W_FT_MACMATCH; + case MACMATCH_F: + field_shift += FT_MACMATCH_W; break; - case F_MPSHITTYPE: - field_shift += W_FT_MPSHITTYPE; + case MPSHITTYPE_F: + field_shift += FT_MPSHITTYPE_W; break; - case F_FRAGMENTATION: - field_shift += W_FT_FRAGMENTATION; + case FRAGMENTATION_F: + field_shift += FT_FRAGMENTATION_W; break; } } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index ec0addc85bb6..4077227b5cea 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1708,233 +1708,323 @@ #define MPS_RX_PERR_INT_CAUSE_A 0x11074 -#define CPL_INTR_CAUSE 0x19054 -#define CIM_OP_MAP_PERR 0x00000020U -#define CIM_OVFL_ERROR 0x00000010U -#define TP_FRAMING_ERROR 0x00000008U -#define SGE_FRAMING_ERROR 0x00000004U -#define CIM_FRAMING_ERROR 0x00000002U -#define ZERO_SWITCH_ERROR 0x00000001U - -#define SMB_INT_CAUSE 0x19090 -#define MSTTXFIFOPARINT 0x00200000U -#define MSTRXFIFOPARINT 0x00100000U -#define SLVFIFOPARINT 0x00080000U - -#define ULP_RX_INT_CAUSE 0x19158 -#define ULP_RX_ISCSI_TAGMASK 0x19164 -#define ULP_RX_ISCSI_PSZ 0x19168 -#define HPZ3_MASK 0x0f000000U -#define HPZ3_SHIFT 24 -#define HPZ3(x) ((x) << HPZ3_SHIFT) -#define HPZ2_MASK 0x000f0000U -#define HPZ2_SHIFT 16 -#define HPZ2(x) ((x) << HPZ2_SHIFT) -#define HPZ1_MASK 0x00000f00U -#define HPZ1_SHIFT 8 -#define HPZ1(x) ((x) << HPZ1_SHIFT) -#define HPZ0_MASK 0x0000000fU -#define HPZ0_SHIFT 0 -#define HPZ0(x) ((x) << HPZ0_SHIFT) - -#define ULP_RX_TDDP_PSZ 0x19178 - -#define SF_DATA 0x193f8 -#define SF_OP 0x193fc -#define SF_BUSY 0x80000000U -#define SF_LOCK 0x00000010U -#define SF_CONT 0x00000008U -#define BYTECNT_MASK 0x00000006U -#define BYTECNT_SHIFT 1 -#define BYTECNT(x) ((x) << BYTECNT_SHIFT) -#define OP_WR 0x00000001U - -#define PL_PF_INT_CAUSE 0x3c0 -#define PFSW 0x00000008U -#define PFSGE 0x00000004U -#define PFCIM 0x00000002U -#define PFMPS 0x00000001U - -#define PL_PF_INT_ENABLE 0x3c4 -#define PL_PF_CTL 0x3c8 -#define SWINT 0x00000001U - -#define PL_WHOAMI 0x19400 -#define SOURCEPF_MASK 0x00000700U -#define SOURCEPF_SHIFT 8 -#define SOURCEPF(x) ((x) << SOURCEPF_SHIFT) -#define SOURCEPF_GET(x) (((x) & SOURCEPF_MASK) >> SOURCEPF_SHIFT) -#define ISVF 0x00000080U -#define VFID_MASK 0x0000007fU -#define VFID_SHIFT 0 -#define VFID(x) ((x) << VFID_SHIFT) -#define VFID_GET(x) (((x) & VFID_MASK) >> VFID_SHIFT) - -#define PL_INT_CAUSE 0x1940c -#define ULP_TX 0x08000000U -#define SGE 0x04000000U -#define HMA 0x02000000U -#define CPL_SWITCH 0x01000000U -#define ULP_RX 0x00800000U -#define PM_RX 0x00400000U -#define PM_TX 0x00200000U -#define MA 0x00100000U -#define TP 0x00080000U -#define LE 0x00040000U -#define EDC1 0x00020000U -#define EDC0 0x00010000U -#define MC 0x00008000U -#define PCIE 0x00004000U -#define PMU 0x00002000U -#define XGMAC_KR1 0x00001000U -#define XGMAC_KR0 0x00000800U -#define XGMAC1 0x00000400U -#define XGMAC0 0x00000200U -#define SMB 0x00000100U -#define SF 0x00000080U -#define PL 0x00000040U -#define NCSI 0x00000020U -#define MPS 0x00000010U -#define MI 0x00000008U -#define DBG 0x00000004U -#define I2CM 0x00000002U -#define CIM 0x00000001U - -#define MC1 0x31 -#define PL_INT_ENABLE 0x19410 -#define PL_INT_MAP0 0x19414 -#define PL_RST 0x19428 -#define PIORST 0x00000002U -#define PIORSTMODE 0x00000001U - -#define PL_PL_INT_CAUSE 0x19430 -#define FATALPERR 0x00000010U -#define PERRVFID 0x00000001U - -#define PL_REV 0x1943c - -#define S_REV 0 -#define M_REV 0xfU -#define V_REV(x) ((x) << S_REV) -#define G_REV(x) (((x) >> S_REV) & M_REV) - -#define LE_DB_CONFIG 0x19c04 -#define HASHEN 0x00100000U - -#define LE_DB_SERVER_INDEX 0x19c18 -#define LE_DB_ACT_CNT_IPV4 0x19c20 -#define LE_DB_ACT_CNT_IPV6 0x19c24 - -#define LE_DB_INT_CAUSE 0x19c3c -#define REQQPARERR 0x00010000U -#define UNKNOWNCMD 0x00008000U -#define PARITYERR 0x00000040U -#define LIPMISS 0x00000020U -#define LIP0 0x00000010U - -#define LE_DB_TID_HASHBASE 0x19df8 - -#define NCSI_INT_CAUSE 0x1a0d8 -#define CIM_DM_PRTY_ERR 0x00000100U -#define MPS_DM_PRTY_ERR 0x00000080U -#define TXFIFO_PRTY_ERR 0x00000002U -#define RXFIFO_PRTY_ERR 0x00000001U - -#define XGMAC_PORT_CFG2 0x1018 -#define PATEN 0x00040000U -#define MAGICEN 0x00020000U +#define CPL_INTR_CAUSE_A 0x19054 -#define XGMAC_PORT_MAGIC_MACID_LO 0x1024 -#define XGMAC_PORT_MAGIC_MACID_HI 0x1028 +#define CIM_OP_MAP_PERR_S 5 +#define CIM_OP_MAP_PERR_V(x) ((x) << CIM_OP_MAP_PERR_S) +#define CIM_OP_MAP_PERR_F CIM_OP_MAP_PERR_V(1U) + +#define CIM_OVFL_ERROR_S 4 +#define CIM_OVFL_ERROR_V(x) ((x) << CIM_OVFL_ERROR_S) +#define CIM_OVFL_ERROR_F CIM_OVFL_ERROR_V(1U) + +#define TP_FRAMING_ERROR_S 3 +#define TP_FRAMING_ERROR_V(x) ((x) << TP_FRAMING_ERROR_S) +#define TP_FRAMING_ERROR_F TP_FRAMING_ERROR_V(1U) + +#define SGE_FRAMING_ERROR_S 2 +#define SGE_FRAMING_ERROR_V(x) ((x) << SGE_FRAMING_ERROR_S) +#define SGE_FRAMING_ERROR_F SGE_FRAMING_ERROR_V(1U) + +#define CIM_FRAMING_ERROR_S 1 +#define CIM_FRAMING_ERROR_V(x) ((x) << CIM_FRAMING_ERROR_S) +#define CIM_FRAMING_ERROR_F CIM_FRAMING_ERROR_V(1U) + +#define ZERO_SWITCH_ERROR_S 0 +#define ZERO_SWITCH_ERROR_V(x) ((x) << ZERO_SWITCH_ERROR_S) +#define ZERO_SWITCH_ERROR_F ZERO_SWITCH_ERROR_V(1U) + +#define SMB_INT_CAUSE_A 0x19090 + +#define MSTTXFIFOPARINT_S 21 +#define MSTTXFIFOPARINT_V(x) ((x) << MSTTXFIFOPARINT_S) +#define MSTTXFIFOPARINT_F MSTTXFIFOPARINT_V(1U) + +#define MSTRXFIFOPARINT_S 20 +#define MSTRXFIFOPARINT_V(x) ((x) << MSTRXFIFOPARINT_S) +#define MSTRXFIFOPARINT_F MSTRXFIFOPARINT_V(1U) + +#define SLVFIFOPARINT_S 19 +#define SLVFIFOPARINT_V(x) ((x) << SLVFIFOPARINT_S) +#define SLVFIFOPARINT_F SLVFIFOPARINT_V(1U) + +#define ULP_RX_INT_CAUSE_A 0x19158 +#define ULP_RX_ISCSI_TAGMASK_A 0x19164 +#define ULP_RX_ISCSI_PSZ_A 0x19168 + +#define HPZ3_S 24 +#define HPZ3_V(x) ((x) << HPZ3_S) + +#define HPZ2_S 16 +#define HPZ2_V(x) ((x) << HPZ2_S) + +#define HPZ1_S 8 +#define HPZ1_V(x) ((x) << HPZ1_S) + +#define HPZ0_S 0 +#define HPZ0_V(x) ((x) << HPZ0_S) + +#define ULP_RX_TDDP_PSZ_A 0x19178 + +/* registers for module SF */ +#define SF_DATA_A 0x193f8 +#define SF_OP_A 0x193fc + +#define SF_BUSY_S 31 +#define SF_BUSY_V(x) ((x) << SF_BUSY_S) +#define SF_BUSY_F SF_BUSY_V(1U) + +#define SF_LOCK_S 4 +#define SF_LOCK_V(x) ((x) << SF_LOCK_S) +#define SF_LOCK_F SF_LOCK_V(1U) + +#define SF_CONT_S 3 +#define SF_CONT_V(x) ((x) << SF_CONT_S) +#define SF_CONT_F SF_CONT_V(1U) + +#define BYTECNT_S 1 +#define BYTECNT_V(x) ((x) << BYTECNT_S) + +#define OP_S 0 +#define OP_V(x) ((x) << OP_S) +#define OP_F OP_V(1U) + +#define PL_PF_INT_CAUSE_A 0x3c0 + +#define PFSW_S 3 +#define PFSW_V(x) ((x) << PFSW_S) +#define PFSW_F PFSW_V(1U) + +#define PFCIM_S 1 +#define PFCIM_V(x) ((x) << PFCIM_S) +#define PFCIM_F PFCIM_V(1U) + +#define PL_PF_INT_ENABLE_A 0x3c4 +#define PL_PF_CTL_A 0x3c8 + +#define PL_WHOAMI_A 0x19400 + +#define SOURCEPF_S 8 +#define SOURCEPF_M 0x7U +#define SOURCEPF_G(x) (((x) >> SOURCEPF_S) & SOURCEPF_M) + +#define PL_INT_CAUSE_A 0x1940c + +#define ULP_TX_S 27 +#define ULP_TX_V(x) ((x) << ULP_TX_S) +#define ULP_TX_F ULP_TX_V(1U) + +#define SGE_S 26 +#define SGE_V(x) ((x) << SGE_S) +#define SGE_F SGE_V(1U) + +#define CPL_SWITCH_S 24 +#define CPL_SWITCH_V(x) ((x) << CPL_SWITCH_S) +#define CPL_SWITCH_F CPL_SWITCH_V(1U) + +#define ULP_RX_S 23 +#define ULP_RX_V(x) ((x) << ULP_RX_S) +#define ULP_RX_F ULP_RX_V(1U) + +#define PM_RX_S 22 +#define PM_RX_V(x) ((x) << PM_RX_S) +#define PM_RX_F PM_RX_V(1U) + +#define PM_TX_S 21 +#define PM_TX_V(x) ((x) << PM_TX_S) +#define PM_TX_F PM_TX_V(1U) + +#define MA_S 20 +#define MA_V(x) ((x) << MA_S) +#define MA_F MA_V(1U) -#define XGMAC_PORT_EPIO_DATA0 0x10c0 -#define XGMAC_PORT_EPIO_DATA1 0x10c4 -#define XGMAC_PORT_EPIO_DATA2 0x10c8 -#define XGMAC_PORT_EPIO_DATA3 0x10cc -#define XGMAC_PORT_EPIO_OP 0x10d0 -#define EPIOWR 0x00000100U -#define ADDRESS_MASK 0x000000ffU -#define ADDRESS_SHIFT 0 -#define ADDRESS(x) ((x) << ADDRESS_SHIFT) +#define TP_S 19 +#define TP_V(x) ((x) << TP_S) +#define TP_F TP_V(1U) -#define MAC_PORT_INT_CAUSE 0x8dc -#define XGMAC_PORT_INT_CAUSE 0x10dc +#define LE_S 18 +#define LE_V(x) ((x) << LE_S) +#define LE_F LE_V(1U) -#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x7e28 +#define EDC1_S 17 +#define EDC1_V(x) ((x) << EDC1_S) +#define EDC1_F EDC1_V(1U) -#define A_TP_TX_MOD_CHANNEL_WEIGHT 0x7e34 +#define EDC0_S 16 +#define EDC0_V(x) ((x) << EDC0_S) +#define EDC0_F EDC0_V(1U) -#define S_TX_MOD_QUEUE_REQ_MAP 0 -#define M_TX_MOD_QUEUE_REQ_MAP 0xffffU -#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP) +#define MC_S 15 +#define MC_V(x) ((x) << MC_S) +#define MC_F MC_V(1U) -#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x7e30 +#define PCIE_S 14 +#define PCIE_V(x) ((x) << PCIE_S) +#define PCIE_F PCIE_V(1U) -#define S_TX_MODQ_WEIGHT3 24 -#define M_TX_MODQ_WEIGHT3 0xffU -#define V_TX_MODQ_WEIGHT3(x) ((x) << S_TX_MODQ_WEIGHT3) +#define XGMAC_KR1_S 12 +#define XGMAC_KR1_V(x) ((x) << XGMAC_KR1_S) +#define XGMAC_KR1_F XGMAC_KR1_V(1U) -#define S_TX_MODQ_WEIGHT2 16 -#define M_TX_MODQ_WEIGHT2 0xffU -#define V_TX_MODQ_WEIGHT2(x) ((x) << S_TX_MODQ_WEIGHT2) +#define XGMAC_KR0_S 11 +#define XGMAC_KR0_V(x) ((x) << XGMAC_KR0_S) +#define XGMAC_KR0_F XGMAC_KR0_V(1U) -#define S_TX_MODQ_WEIGHT1 8 -#define M_TX_MODQ_WEIGHT1 0xffU -#define V_TX_MODQ_WEIGHT1(x) ((x) << S_TX_MODQ_WEIGHT1) +#define XGMAC1_S 10 +#define XGMAC1_V(x) ((x) << XGMAC1_S) +#define XGMAC1_F XGMAC1_V(1U) -#define S_TX_MODQ_WEIGHT0 0 -#define M_TX_MODQ_WEIGHT0 0xffU -#define V_TX_MODQ_WEIGHT0(x) ((x) << S_TX_MODQ_WEIGHT0) +#define XGMAC0_S 9 +#define XGMAC0_V(x) ((x) << XGMAC0_S) +#define XGMAC0_F XGMAC0_V(1U) -#define A_TP_TX_SCHED_HDR 0x23 +#define SMB_S 8 +#define SMB_V(x) ((x) << SMB_S) +#define SMB_F SMB_V(1U) -#define A_TP_TX_SCHED_FIFO 0x24 +#define SF_S 7 +#define SF_V(x) ((x) << SF_S) +#define SF_F SF_V(1U) -#define A_TP_TX_SCHED_PCMD 0x25 +#define PL_S 6 +#define PL_V(x) ((x) << PL_S) +#define PL_F PL_V(1U) -#define S_VNIC 11 -#define V_VNIC(x) ((x) << S_VNIC) -#define F_VNIC V_VNIC(1U) +#define NCSI_S 5 +#define NCSI_V(x) ((x) << NCSI_S) +#define NCSI_F NCSI_V(1U) -#define S_FRAGMENTATION 9 -#define V_FRAGMENTATION(x) ((x) << S_FRAGMENTATION) -#define F_FRAGMENTATION V_FRAGMENTATION(1U) +#define MPS_S 4 +#define MPS_V(x) ((x) << MPS_S) +#define MPS_F MPS_V(1U) -#define S_MPSHITTYPE 8 -#define V_MPSHITTYPE(x) ((x) << S_MPSHITTYPE) -#define F_MPSHITTYPE V_MPSHITTYPE(1U) +#define CIM_S 0 +#define CIM_V(x) ((x) << CIM_S) +#define CIM_F CIM_V(1U) -#define S_MACMATCH 7 -#define V_MACMATCH(x) ((x) << S_MACMATCH) -#define F_MACMATCH V_MACMATCH(1U) +#define MC1_S 31 -#define S_ETHERTYPE 6 -#define V_ETHERTYPE(x) ((x) << S_ETHERTYPE) -#define F_ETHERTYPE V_ETHERTYPE(1U) +#define PL_INT_ENABLE_A 0x19410 +#define PL_INT_MAP0_A 0x19414 +#define PL_RST_A 0x19428 -#define S_PROTOCOL 5 -#define V_PROTOCOL(x) ((x) << S_PROTOCOL) -#define F_PROTOCOL V_PROTOCOL(1U) +#define PIORST_S 1 +#define PIORST_V(x) ((x) << PIORST_S) +#define PIORST_F PIORST_V(1U) -#define S_TOS 4 -#define V_TOS(x) ((x) << S_TOS) -#define F_TOS V_TOS(1U) +#define PIORSTMODE_S 0 +#define PIORSTMODE_V(x) ((x) << PIORSTMODE_S) +#define PIORSTMODE_F PIORSTMODE_V(1U) -#define S_VLAN 3 -#define V_VLAN(x) ((x) << S_VLAN) -#define F_VLAN V_VLAN(1U) +#define PL_PL_INT_CAUSE_A 0x19430 -#define S_VNIC_ID 2 -#define V_VNIC_ID(x) ((x) << S_VNIC_ID) -#define F_VNIC_ID V_VNIC_ID(1U) +#define FATALPERR_S 4 +#define FATALPERR_V(x) ((x) << FATALPERR_S) +#define FATALPERR_F FATALPERR_V(1U) -#define S_PORT 1 -#define V_PORT(x) ((x) << S_PORT) -#define F_PORT V_PORT(1U) +#define PERRVFID_S 0 +#define PERRVFID_V(x) ((x) << PERRVFID_S) +#define PERRVFID_F PERRVFID_V(1U) -#define S_FCOE 0 -#define V_FCOE(x) ((x) << S_FCOE) -#define F_FCOE V_FCOE(1U) +#define PL_REV_A 0x1943c + +#define REV_S 0 +#define REV_M 0xfU +#define REV_V(x) ((x) << REV_S) +#define REV_G(x) (((x) >> REV_S) & REV_M) + +#define LE_DB_INT_CAUSE_A 0x19c3c + +#define REQQPARERR_S 16 +#define REQQPARERR_V(x) ((x) << REQQPARERR_S) +#define REQQPARERR_F REQQPARERR_V(1U) + +#define UNKNOWNCMD_S 15 +#define UNKNOWNCMD_V(x) ((x) << UNKNOWNCMD_S) +#define UNKNOWNCMD_F UNKNOWNCMD_V(1U) + +#define PARITYERR_S 6 +#define PARITYERR_V(x) ((x) << PARITYERR_S) +#define PARITYERR_F PARITYERR_V(1U) + +#define LIPMISS_S 5 +#define LIPMISS_V(x) ((x) << LIPMISS_S) +#define LIPMISS_F LIPMISS_V(1U) + +#define LIP0_S 4 +#define LIP0_V(x) ((x) << LIP0_S) +#define LIP0_F LIP0_V(1U) + +#define NCSI_INT_CAUSE_A 0x1a0d8 + +#define CIM_DM_PRTY_ERR_S 8 +#define CIM_DM_PRTY_ERR_V(x) ((x) << CIM_DM_PRTY_ERR_S) +#define CIM_DM_PRTY_ERR_F CIM_DM_PRTY_ERR_V(1U) + +#define MPS_DM_PRTY_ERR_S 7 +#define MPS_DM_PRTY_ERR_V(x) ((x) << MPS_DM_PRTY_ERR_S) +#define MPS_DM_PRTY_ERR_F MPS_DM_PRTY_ERR_V(1U) + +#define TXFIFO_PRTY_ERR_S 1 +#define TXFIFO_PRTY_ERR_V(x) ((x) << TXFIFO_PRTY_ERR_S) +#define TXFIFO_PRTY_ERR_F TXFIFO_PRTY_ERR_V(1U) + +#define RXFIFO_PRTY_ERR_S 0 +#define RXFIFO_PRTY_ERR_V(x) ((x) << RXFIFO_PRTY_ERR_S) +#define RXFIFO_PRTY_ERR_F RXFIFO_PRTY_ERR_V(1U) + +#define XGMAC_PORT_CFG2_A 0x1018 + +#define PATEN_S 18 +#define PATEN_V(x) ((x) << PATEN_S) +#define PATEN_F PATEN_V(1U) + +#define MAGICEN_S 17 +#define MAGICEN_V(x) ((x) << MAGICEN_S) +#define MAGICEN_F MAGICEN_V(1U) + +#define XGMAC_PORT_MAGIC_MACID_LO 0x1024 +#define XGMAC_PORT_MAGIC_MACID_HI 0x1028 + +#define XGMAC_PORT_EPIO_DATA0_A 0x10c0 +#define XGMAC_PORT_EPIO_DATA1_A 0x10c4 +#define XGMAC_PORT_EPIO_DATA2_A 0x10c8 +#define XGMAC_PORT_EPIO_DATA3_A 0x10cc +#define XGMAC_PORT_EPIO_OP_A 0x10d0 + +#define EPIOWR_S 8 +#define EPIOWR_V(x) ((x) << EPIOWR_S) +#define EPIOWR_F EPIOWR_V(1U) + +#define ADDRESS_S 0 +#define ADDRESS_V(x) ((x) << ADDRESS_S) + +#define MAC_PORT_INT_CAUSE_A 0x8dc +#define XGMAC_PORT_INT_CAUSE_A 0x10dc + +#define TP_TX_MOD_QUEUE_REQ_MAP_A 0x7e28 + +#define TP_TX_MOD_QUEUE_WEIGHT0_A 0x7e30 +#define TP_TX_MOD_CHANNEL_WEIGHT_A 0x7e34 + +#define TX_MOD_QUEUE_REQ_MAP_S 0 +#define TX_MOD_QUEUE_REQ_MAP_V(x) ((x) << TX_MOD_QUEUE_REQ_MAP_S) + +#define TX_MODQ_WEIGHT3_S 24 +#define TX_MODQ_WEIGHT3_V(x) ((x) << TX_MODQ_WEIGHT3_S) + +#define TX_MODQ_WEIGHT2_S 16 +#define TX_MODQ_WEIGHT2_V(x) ((x) << TX_MODQ_WEIGHT2_S) + +#define TX_MODQ_WEIGHT1_S 8 +#define TX_MODQ_WEIGHT1_V(x) ((x) << TX_MODQ_WEIGHT1_S) + +#define TX_MODQ_WEIGHT0_S 0 +#define TX_MODQ_WEIGHT0_V(x) ((x) << TX_MODQ_WEIGHT0_S) + +#define TP_TX_SCHED_HDR_A 0x23 +#define TP_TX_SCHED_FIFO_A 0x24 +#define TP_TX_SCHED_PCMD_A 0x25 #define NUM_MPS_CLS_SRAM_L_INSTANCES 336 #define NUM_MPS_T5_CLS_SRAM_L_INSTANCES 512 @@ -1968,46 +2058,8 @@ #define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR) #define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx) -#define A_PL_VF_REV 0x4 -#define A_PL_VF_WHOAMI 0x0 -#define A_PL_VF_REVISION 0x8 - -#define S_CHIPID 4 -#define M_CHIPID 0xfU -#define V_CHIPID(x) ((x) << S_CHIPID) -#define G_CHIPID(x) (((x) >> S_CHIPID) & M_CHIPID) - -/* TP_VLAN_PRI_MAP controls which subset of fields will be present in the - * Compressed Filter Tuple for LE filters. Each bit set in TP_VLAN_PRI_MAP - * selects for a particular field being present. These fields, when present - * in the Compressed Filter Tuple, have the following widths in bits. - */ -#define W_FT_FCOE 1 -#define W_FT_PORT 3 -#define W_FT_VNIC_ID 17 -#define W_FT_VLAN 17 -#define W_FT_TOS 8 -#define W_FT_PROTOCOL 8 -#define W_FT_ETHERTYPE 16 -#define W_FT_MACMATCH 9 -#define W_FT_MPSHITTYPE 3 -#define W_FT_FRAGMENTATION 1 - -/* Some of the Compressed Filter Tuple fields have internal structure. These - * bit shifts/masks describe those structures. All shifts are relative to the - * base position of the fields within the Compressed Filter Tuple - */ -#define S_FT_VLAN_VLD 16 -#define V_FT_VLAN_VLD(x) ((x) << S_FT_VLAN_VLD) -#define F_FT_VLAN_VLD V_FT_VLAN_VLD(1U) - -#define S_FT_VNID_ID_VF 0 -#define V_FT_VNID_ID_VF(x) ((x) << S_FT_VNID_ID_VF) - -#define S_FT_VNID_ID_PF 7 -#define V_FT_VNID_ID_PF(x) ((x) << S_FT_VNID_ID_PF) - -#define S_FT_VNID_ID_VLD 16 -#define V_FT_VNID_ID_VLD(x) ((x) << S_FT_VNID_ID_VLD) +#define PL_VF_REV_A 0x4 +#define PL_VF_WHOAMI_A 0x0 +#define PL_VF_REVISION_A 0x8 #endif /* __T4_REGS_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h index ecf7459f8217..a40484432ebf 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h @@ -82,4 +82,37 @@ #define WINDOW_SHIFT_X 10 #define PCIEOFST_SHIFT_X 10 +/* TP_VLAN_PRI_MAP controls which subset of fields will be present in the + * Compressed Filter Tuple for LE filters. Each bit set in TP_VLAN_PRI_MAP + * selects for a particular field being present. These fields, when present + * in the Compressed Filter Tuple, have the following widths in bits. + */ +#define FT_FCOE_W 1 +#define FT_PORT_W 3 +#define FT_VNIC_ID_W 17 +#define FT_VLAN_W 17 +#define FT_TOS_W 8 +#define FT_PROTOCOL_W 8 +#define FT_ETHERTYPE_W 16 +#define FT_MACMATCH_W 9 +#define FT_MPSHITTYPE_W 3 +#define FT_FRAGMENTATION_W 1 + +/* Some of the Compressed Filter Tuple fields have internal structure. These + * bit shifts/masks describe those structures. All shifts are relative to the + * base position of the fields within the Compressed Filter Tuple + */ +#define FT_VLAN_VLD_S 16 +#define FT_VLAN_VLD_V(x) ((x) << FT_VLAN_VLD_S) +#define FT_VLAN_VLD_F FT_VLAN_VLD_V(1U) + +#define FT_VNID_ID_VF_S 0 +#define FT_VNID_ID_VF_V(x) ((x) << FT_VNID_ID_VF_S) + +#define FT_VNID_ID_PF_S 7 +#define FT_VNID_ID_PF_V(x) ((x) << FT_VNID_ID_PF_S) + +#define FT_VNID_ID_VLD_S 16 +#define FT_VNID_ID_VLD_V(x) ((x) << FT_VNID_ID_VLD_S) + #endif /* __T4_VALUES_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index aa9f9cd7a3c7..7bfbacd63f7a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -1673,7 +1673,7 @@ static void cxgb4vf_get_regs(struct net_device *dev, reg_block_dump(adapter, regbuf, T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_FIRST, T4VF_PL_BASE_ADDR + (is_t4(adapter->params.chip) - ? A_PL_VF_WHOAMI : A_PL_VF_REVISION)); + ? PL_VF_WHOAMI_A : PL_VF_REVISION_A)); reg_block_dump(adapter, regbuf, T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_FIRST, T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_LAST); diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 5e83c183faa1..fcc610813856 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -616,8 +616,8 @@ int t4vf_get_sge_params(struct adapter *adapter) * the driver can just use it. */ whoami = t4_read_reg(adapter, - T4VF_PL_BASE_ADDR + A_PL_VF_WHOAMI); - pf = SOURCEPF_GET(whoami); + T4VF_PL_BASE_ADDR + PL_VF_WHOAMI_A); + pf = SOURCEPF_G(whoami); s_hps = (HOSTPAGESIZEPF0_S + (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * pf); @@ -1591,7 +1591,7 @@ int t4vf_prep_adapter(struct adapter *adapter) break; case CHELSIO_T5: - chipid = G_REV(t4_read_reg(adapter, A_PL_VF_REV)); + chipid = REV_G(t4_read_reg(adapter, PL_VF_REV_A)); adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T5, chipid); break; } -- cgit v1.2.1 From 678109ea0908a643e0338e20714aae9e07ffe02a Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 6 Jan 2015 17:31:46 +0530 Subject: cxgb4: Add PCI device ID for new T5 adapter Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h index 9e4f95a91fb4..ddfb5b846045 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h @@ -153,6 +153,7 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x5086), /* Custom 2x T580-CR */ CH_PCI_ID_TABLE_FENTRY(0x5087), /* Custom T580-CR */ CH_PCI_ID_TABLE_FENTRY(0x5088), /* Custom T570-CR */ + CH_PCI_ID_TABLE_FENTRY(0x5089), /* Custom T520-CR */ CH_PCI_DEVICE_ID_TABLE_DEFINE_END; #endif /* CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN */ -- cgit v1.2.1 From 83297aaa8fde85154c91a59e522c3d042c1084ec Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sun, 21 Dec 2014 12:43:44 +0100 Subject: brcmfmac: Fix incorrect casting of 64 bit physical address. The physical addresses being used by pcie and msgbuf were using a cast to long, which incorrectly caused it to limit the address to 32bit. Now explicit u64 is used where needed. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | 22 +++++++++++----------- drivers/net/wireless/brcm80211/brcmfmac/pcie.c | 10 +++++----- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index 456944a6a2db..3ff6acfd82a7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -583,7 +583,7 @@ brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf, u32 flowid; void *dma_buf; u32 dma_sz; - long long address; + u64 address; int err; flowid = work->flowid; @@ -620,7 +620,7 @@ brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf, BRCMF_NROF_H2D_COMMON_MSGRINGS); memcpy(create->sa, work->sa, ETH_ALEN); memcpy(create->da, work->da, ETH_ALEN); - address = (long long)(long)msgbuf->flowring_dma_handle[flowid]; + address = (u64)msgbuf->flowring_dma_handle[flowid]; create->flow_ring_addr.high_addr = cpu_to_le32(address >> 32); create->flow_ring_addr.low_addr = cpu_to_le32(address & 0xffffffff); create->max_items = cpu_to_le16(BRCMF_H2D_TXFLOWRING_MAX_ITEM); @@ -698,7 +698,7 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid) dma_addr_t physaddr; u32 pktid; struct msgbuf_tx_msghdr *tx_msghdr; - long long address; + u64 address; commonring = msgbuf->flowrings[flowid]; if (!brcmf_commonring_write_available(commonring)) @@ -742,7 +742,7 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid) tx_msghdr->seg_cnt = 1; memcpy(tx_msghdr->txhdr, skb->data, ETH_HLEN); tx_msghdr->data_len = cpu_to_le16(skb->len - ETH_HLEN); - address = (long long)(long)physaddr; + address = (u64)physaddr; tx_msghdr->data_buf_addr.high_addr = cpu_to_le32(address >> 32); tx_msghdr->data_buf_addr.low_addr = cpu_to_le32(address & 0xffffffff); @@ -885,7 +885,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count) u32 pktlen; dma_addr_t physaddr; struct msgbuf_rx_bufpost *rx_bufpost; - long long address; + u64 address; u32 pktid; u32 i; @@ -921,7 +921,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count) } if (msgbuf->rx_metadata_offset) { - address = (long long)(long)physaddr; + address = (u64)physaddr; rx_bufpost->metadata_buf_len = cpu_to_le16(msgbuf->rx_metadata_offset); rx_bufpost->metadata_buf_addr.high_addr = @@ -936,7 +936,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count) rx_bufpost->msg.msgtype = MSGBUF_TYPE_RXBUF_POST; rx_bufpost->msg.request_id = cpu_to_le32(pktid); - address = (long long)(long)physaddr; + address = (u64)physaddr; rx_bufpost->data_buf_len = cpu_to_le16((u16)pktlen); rx_bufpost->data_buf_addr.high_addr = cpu_to_le32(address >> 32); @@ -992,7 +992,7 @@ brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf, u32 pktlen; dma_addr_t physaddr; struct msgbuf_rx_ioctl_resp_or_event *rx_bufpost; - long long address; + u64 address; u32 pktid; u32 i; @@ -1035,7 +1035,7 @@ brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf, MSGBUF_TYPE_IOCTLRESP_BUF_POST; rx_bufpost->msg.request_id = cpu_to_le32(pktid); - address = (long long)(long)physaddr; + address = (u64)physaddr; rx_bufpost->host_buf_len = cpu_to_le16((u16)pktlen); rx_bufpost->host_buf_addr.high_addr = cpu_to_le32(address >> 32); @@ -1348,7 +1348,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) { struct brcmf_bus_msgbuf *if_msgbuf; struct brcmf_msgbuf *msgbuf; - long long address; + u64 address; u32 count; if_msgbuf = drvr->bus_if->msgbuf; @@ -1379,7 +1379,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) GFP_KERNEL); if (!msgbuf->ioctbuf) goto fail; - address = (long long)(long)msgbuf->ioctbuf_handle; + address = (u64)msgbuf->ioctbuf_handle; msgbuf->ioctbuf_phys_hi = address >> 32; msgbuf->ioctbuf_phys_lo = address & 0xffffffff; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index 905991fdb7b1..e91fa9a2c885 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -959,14 +959,14 @@ brcmf_pcie_init_dmabuffer_for_device(struct brcmf_pciedev_info *devinfo, dma_addr_t *dma_handle) { void *ring; - long long address; + u64 address; ring = dma_alloc_coherent(&devinfo->pdev->dev, size, dma_handle, GFP_KERNEL); if (!ring) return NULL; - address = (long long)(long)*dma_handle; + address = (u64)*dma_handle; brcmf_pcie_write_tcm32(devinfo, tcm_dma_phys_addr, address & 0xffffffff); brcmf_pcie_write_tcm32(devinfo, tcm_dma_phys_addr + 4, address >> 32); @@ -1166,7 +1166,7 @@ brcmf_pcie_release_scratchbuffers(struct brcmf_pciedev_info *devinfo) static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) { - long long address; + u64 address; u32 addr; devinfo->shared.scratch = dma_alloc_coherent(&devinfo->pdev->dev, @@ -1180,7 +1180,7 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) addr = devinfo->shared.tcm_base_address + BRCMF_SHARED_DMA_SCRATCH_ADDR_OFFSET; - address = (long long)(long)devinfo->shared.scratch_dmahandle; + address = (u64)devinfo->shared.scratch_dmahandle; brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); addr = devinfo->shared.tcm_base_address + @@ -1198,7 +1198,7 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) addr = devinfo->shared.tcm_base_address + BRCMF_SHARED_DMA_RINGUPD_ADDR_OFFSET; - address = (long long)(long)devinfo->shared.ringupd_dmahandle; + address = (u64)devinfo->shared.ringupd_dmahandle; brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); addr = devinfo->shared.tcm_base_address + -- cgit v1.2.1 From f714e58e19a567cc2659ea4645748ba06e3849a7 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 21 Dec 2014 12:43:48 +0100 Subject: brcmfmac: remove unused/duplicate defines in chip.c The source file chip.c contained some duplicate defines and some unused ones. Removing them. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/chip.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index ddae0b5e56ec..519b79ebaabd 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -101,14 +101,7 @@ /* ARM Cortex M3 core, ID 0x82a */ #define BCM4329_CORE_ARM_BASE 0x18002000 #define BCM4329_RAMSIZE 0x48000 - /* bcm43143 */ -/* SDIO device core */ -#define BCM43143_CORE_BUS_BASE 0x18002000 -/* internal memory core */ -#define BCM43143_CORE_SOCRAM_BASE 0x18004000 -/* ARM Cortex M3 core, ID 0x82a */ -#define BCM43143_CORE_ARM_BASE 0x18003000 #define BCM43143_RAMSIZE 0x70000 #define CORE_SB(base, field) \ @@ -164,13 +157,6 @@ struct brcmf_core_priv { struct brcmf_chip_priv *chip; }; -/* ARM CR4 core specific control flag bits */ -#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020 - -/* D11 core specific control flag bits */ -#define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004 -#define D11_BCMA_IOCTL_PHYRESET 0x0008 - struct brcmf_chip_priv { struct brcmf_chip pub; const struct brcmf_buscore_ops *ops; -- cgit v1.2.1 From 118eb304d0554fbeab8567410bbece5bae533c23 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sun, 21 Dec 2014 12:43:49 +0100 Subject: brcmfmac: Fix WEP configuration for AP mode. When a device is configured for AP mode and it is configured for WEP then the keys are plumbed first, followed by AP configuration. During configuration a down command is given to the firmware which will clear the configured keys. This patch reprograms the WEP keys after AP has been brought up. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 95 ++++++++++++++++------ drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h | 4 + drivers/net/wireless/brcm80211/brcmfmac/core.c | 3 +- drivers/net/wireless/brcm80211/brcmfmac/core.h | 4 +- 4 files changed, 76 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 3aecc5f48719..11725518d19a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -452,16 +452,16 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key, } static int -send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key) +send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key) { int err; struct brcmf_wsec_key_le key_le; convert_key_from_CPU(key, &key_le); - brcmf_netdev_wait_pend8021x(ndev); + brcmf_netdev_wait_pend8021x(ifp); - err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le, + err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le, sizeof(key_le)); if (err) @@ -1670,7 +1670,7 @@ brcmf_set_sharedkey(struct net_device *ndev, brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n", key.len, key.index, key.algo); brcmf_dbg(CONN, "key \"%s\"\n", key.data); - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(netdev_priv(ndev), &key); if (err) return err; @@ -2052,7 +2052,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, /* check for key index change */ if (key.len == 0) { /* key delete */ - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(ifp, &key); if (err) brcmf_err("key delete error (%d)\n", err); } else { @@ -2108,7 +2108,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("Invalid cipher (0x%x)\n", params->cipher); return -EINVAL; } - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(ifp, &key); if (err) brcmf_err("wsec_key error (%d)\n", err); } @@ -2121,7 +2121,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, struct key_params *params) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_wsec_key key; + struct brcmf_wsec_key *key; s32 val; s32 wsec; s32 err = 0; @@ -2132,54 +2132,62 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, if (!check_vif_up(ifp->vif)) return -EIO; + if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { + /* we ignore this key index in this case */ + brcmf_err("invalid key index (%d)\n", key_idx); + return -EINVAL; + } + if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) && (params->cipher != WLAN_CIPHER_SUITE_WEP104)) { brcmf_dbg(TRACE, "Exit"); return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); } - memset(&key, 0, sizeof(key)); - key.len = (u32) params->key_len; - key.index = (u32) key_idx; + key = &ifp->vif->profile.key[key_idx]; + memset(key, 0, sizeof(*key)); - if (key.len > sizeof(key.data)) { - brcmf_err("Too long key length (%u)\n", key.len); + if (params->key_len > sizeof(key->data)) { + brcmf_err("Too long key length (%u)\n", params->key_len); err = -EINVAL; goto done; } - memcpy(key.data, params->key, key.len); + key->len = params->key_len; + key->index = key_idx; - key.flags = BRCMF_PRIMARY_KEY; + memcpy(key->data, params->key, key->len); + + key->flags = BRCMF_PRIMARY_KEY; switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: - key.algo = CRYPTO_ALGO_WEP1; + key->algo = CRYPTO_ALGO_WEP1; val = WEP_ENABLED; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n"); break; case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; + key->algo = CRYPTO_ALGO_WEP128; val = WEP_ENABLED; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); break; case WLAN_CIPHER_SUITE_TKIP: if (!brcmf_is_apmode(ifp->vif)) { brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); - memcpy(keybuf, &key.data[24], sizeof(keybuf)); - memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); - memcpy(&key.data[16], keybuf, sizeof(keybuf)); + memcpy(keybuf, &key->data[24], sizeof(keybuf)); + memcpy(&key->data[24], &key->data[16], sizeof(keybuf)); + memcpy(&key->data[16], keybuf, sizeof(keybuf)); } - key.algo = CRYPTO_ALGO_TKIP; + key->algo = CRYPTO_ALGO_TKIP; val = TKIP_ENABLED; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); break; case WLAN_CIPHER_SUITE_AES_CMAC: - key.algo = CRYPTO_ALGO_AES_CCM; + key->algo = CRYPTO_ALGO_AES_CCM; val = AES_ENABLED; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); break; case WLAN_CIPHER_SUITE_CCMP: - key.algo = CRYPTO_ALGO_AES_CCM; + key->algo = CRYPTO_ALGO_AES_CCM; val = AES_ENABLED; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n"); break; @@ -2189,7 +2197,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, goto done; } - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(ifp, key); if (err) goto done; @@ -2222,7 +2230,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, if (!check_vif_up(ifp->vif)) return -EIO; - if (key_idx >= DOT11_MAX_DEFAULT_KEYS) { + if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { /* we ignore this key index in this case */ brcmf_err("invalid key index (%d)\n", key_idx); return -EINVAL; @@ -2237,7 +2245,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(CONN, "key index (%d)\n", key_idx); /* Set the new key/index */ - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(ifp, &key); brcmf_dbg(TRACE, "Exit\n"); return err; @@ -2305,6 +2313,39 @@ brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, return -EOPNOTSUPP; } +static void +brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp) +{ + s32 err; + u8 key_idx; + struct brcmf_wsec_key *key; + s32 wsec; + + for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) { + key = &ifp->vif->profile.key[key_idx]; + if ((key->algo == CRYPTO_ALGO_WEP1) || + (key->algo == CRYPTO_ALGO_WEP128)) + break; + } + if (key_idx == BRCMF_MAX_DEFAULT_KEYS) + return; + + err = send_key_to_dongle(ifp, key); + if (err) { + brcmf_err("Setting WEP key failed (%d)\n", err); + return; + } + err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); + if (err) { + brcmf_err("get wsec error (%d)\n", err); + return; + } + wsec |= WEP_ENABLED; + err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec); + if (err) + brcmf_err("set wsec error (%d)\n", err); +} + static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo) @@ -4057,6 +4098,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("BRCMF_C_UP error (%d)\n", err); goto exit; } + /* On DOWN the firmware removes the WEP keys, reconfigure + * them if they were set. + */ + brcmf_cfg80211_reconfigure_wep(ifp); memset(&join_params, 0, sizeof(join_params)); /* join parameters starts with ssid */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h index 9e98b8d52757..a5242af9da4c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h @@ -75,6 +75,8 @@ #define BRCMF_VNDR_IE_P2PAF_SHIFT 12 +#define BRCMF_MAX_DEFAULT_KEYS 4 + /** * enum brcmf_scan_status - scan engine status @@ -125,11 +127,13 @@ struct brcmf_cfg80211_security { * @ssid: ssid of associated/associating ap. * @bssid: bssid of joined/joining ibss. * @sec: security information. + * @key: key information */ struct brcmf_cfg80211_profile { struct brcmf_ssid ssid; u8 bssid[ETH_ALEN]; struct brcmf_cfg80211_security sec; + struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS]; }; /** diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index effe6d7831d9..e2a9e33f71ab 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c @@ -1093,9 +1093,8 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp) return atomic_read(&ifp->pend_8021x_cnt); } -int brcmf_netdev_wait_pend8021x(struct net_device *ndev) +int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp) { - struct brcmf_if *ifp = netdev_priv(ndev); int err; err = wait_event_timeout(ifp->pend_8021x_wait, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index 23f74b139cc8..f2f7d3d1a8ef 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h @@ -29,8 +29,6 @@ /* For supporting multiple interfaces */ #define BRCMF_MAX_IFS 16 -#define DOT11_MAX_DEFAULT_KEYS 4 - /* Small, medium and maximum buffer size for dcmd */ #define BRCMF_DCMD_SMLEN 256 @@ -167,7 +165,7 @@ struct brcmf_skb_reorder_data { u8 *reorder; }; -int brcmf_netdev_wait_pend8021x(struct net_device *ndev); +int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp); /* Return pointer to interface name */ char *brcmf_ifname(struct brcmf_pub *drvr, int idx); -- cgit v1.2.1 From d2e2472cd197e32f2c90beb016066b521ce68049 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sun, 21 Dec 2014 12:43:50 +0100 Subject: brcmfmac: Change error log in standard log for rxbufpost. When there is no room in the ring for rxbufpost an error is logged, however this happens quite frequently and can be considered normal and is certainly recoverable. This patch changes the erorr into a normal msgbuf log. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index 3ff6acfd82a7..ee147f5c706a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -894,7 +894,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count) count, &alloced); if (!ret_ptr) { - brcmf_err("Failed to reserve space in commonring\n"); + brcmf_dbg(MSGBUF, "Failed to reserve space in commonring\n"); return 0; } -- cgit v1.2.1 From 63db1a499cee154826d63a7d0eb096fa666ab9fb Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 21 Dec 2014 12:43:51 +0100 Subject: brcmfmac: follow user-space regulatory domain selection When user-space uses a valid ISO-3166-1 country code for its regulatory domain selection, the driver will try to configure the firmware to use the same. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 25 +++++++++++++++++++++- .../net/wireless/brcm80211/brcmfmac/fwil_types.h | 14 ++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 11725518d19a..2471dd58f17f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -3982,7 +3982,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n", settings->ssid, settings->ssid_len, settings->auth_type, settings->inactivity_timeout); - dev_role = ifp->vif->wdev.iftype; mbss = ifp->vif->mbss; @@ -5921,6 +5920,29 @@ int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, vif_event_equals(event, action), timeout); } +static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *req) +{ + struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct brcmf_fil_country_le ccreq; + int i; + + brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator, + req->alpha2[0], req->alpha2[1]); + + /* ignore non-ISO3166 country codes */ + for (i = 0; i < sizeof(req->alpha2); i++) + if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { + brcmf_err("not a ISO3166 code\n"); + return; + } + memset(&ccreq, 0, sizeof(ccreq)); + ccreq.rev = cpu_to_le32(-1); + memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2)); + brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq)); +} + static void brcmf_free_wiphy(struct wiphy *wiphy) { kfree(wiphy->iface_combinations); @@ -5997,6 +6019,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, goto priv_out; brcmf_dbg(INFO, "Registering custom regulatory\n"); + wiphy->reg_notifier = brcmf_cfg80211_reg_notifier; wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index 50891c02c4c1..619669bbdb83 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h @@ -112,6 +112,7 @@ #define BRCMF_WOWL_MAXPATTERNS 8 #define BRCMF_WOWL_MAXPATTERNSIZE 128 +#define BRCMF_COUNTRY_BUF_SZ 4 /* join preference types for join_pref iovar */ enum brcmf_join_pref_types { @@ -525,4 +526,17 @@ struct brcmf_mbss_ssid_le { unsigned char SSID[32]; }; +/** + * struct brcmf_fil_country_le - country configuration structure. + * + * @country_abbrev: null-terminated country code used in the country IE. + * @rev: revision specifier for ccode. on set, -1 indicates unspecified. + * @ccode: null-terminated built-in country code. + */ +struct brcmf_fil_country_le { + char country_abbrev[BRCMF_COUNTRY_BUF_SZ]; + __le32 rev; + char ccode[BRCMF_COUNTRY_BUF_SZ]; +}; + #endif /* FWIL_TYPES_H_ */ -- cgit v1.2.1 From 6b89dcb35bfc787ce21401417f7170997d8490ed Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sun, 21 Dec 2014 12:43:52 +0100 Subject: brcmfmac: signal completion of 802.1x. Use cfg80211 change_station to signal the completion of 802.1x to firmware. This allows FW to take appropriate actions. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 30 ++++++++++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/common.c | 3 +++ drivers/net/wireless/brcm80211/brcmfmac/common.h | 20 +++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/flowring.c | 6 ++--- drivers/net/wireless/brcm80211/brcmfmac/fwil.h | 2 ++ 5 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/common.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 2471dd58f17f..c896fe27a626 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -38,6 +38,7 @@ #include "proto.h" #include "vendor.h" #include "bus.h" +#include "common.h" #define BRCMF_SCAN_IE_LEN_MAX 2048 #define BRCMF_PNO_VERSION 2 @@ -4241,6 +4242,34 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, return err; } +static int +brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_parameters *params) +{ + struct brcmf_if *ifp = netdev_priv(ndev); + s32 err; + + brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac, + params->sta_flags_mask, params->sta_flags_set); + + /* Ignore all 00 MAC */ + if (is_zero_ether_addr(mac)) + return 0; + + if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) + return 0; + + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE, + (void *)mac, ETH_ALEN); + else + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE, + (void *)mac, ETH_ALEN); + if (err < 0) + brcmf_err("Setting SCB (de-)authorize failed, %d\n", err); + + return err; +} static void brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, @@ -4515,6 +4544,7 @@ static struct cfg80211_ops wl_cfg80211_ops = { .stop_ap = brcmf_cfg80211_stop_ap, .change_beacon = brcmf_cfg80211_change_beacon, .del_station = brcmf_cfg80211_del_station, + .change_station = brcmf_cfg80211_change_station, .sched_scan_start = brcmf_cfg80211_sched_scan_start, .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/common.c b/drivers/net/wireless/brcm80211/brcmfmac/common.c index 1861a13e8d03..ddf05af13d44 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/common.c @@ -25,6 +25,9 @@ #include "fwil.h" #include "fwil_types.h" #include "tracepoint.h" +#include "common.h" + +const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; #define BRCMF_DEFAULT_BCN_TIMEOUT 3 #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40 diff --git a/drivers/net/wireless/brcm80211/brcmfmac/common.h b/drivers/net/wireless/brcm80211/brcmfmac/common.h new file mode 100644 index 000000000000..0d39d80cee28 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/common.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef BRCMFMAC_COMMON_H +#define BRCMFMAC_COMMON_H + +extern const u8 ALLFFMAC[ETH_ALEN]; + +#endif /* BRCMFMAC_COMMON_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c index 44f3a84d1999..910fbb561469 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c @@ -25,6 +25,7 @@ #include "proto.h" #include "flowring.h" #include "msgbuf.h" +#include "common.h" #define BRCMF_FLOWRING_HIGH 1024 @@ -34,9 +35,6 @@ #define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16) #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16) -static const u8 ALLZEROMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; -static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - static const u8 brcmf_flowring_prio2fifo[] = { 1, 0, @@ -137,7 +135,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], hash = flow->hash; for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { if ((hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX) && - (memcmp(hash[hash_idx].mac, ALLZEROMAC, ETH_ALEN) == 0)) { + (is_zero_ether_addr(hash[hash_idx].mac))) { found = true; break; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h index a30be683f4a1..3ede91d11ad2 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h @@ -60,6 +60,8 @@ #define BRCMF_C_GET_CURR_RATESET 114 #define BRCMF_C_GET_AP 117 #define BRCMF_C_SET_AP 118 +#define BRCMF_C_SET_SCB_AUTHORIZE 121 +#define BRCMF_C_SET_SCB_DEAUTHORIZE 122 #define BRCMF_C_GET_RSSI 127 #define BRCMF_C_GET_WSEC 133 #define BRCMF_C_SET_WSEC 134 -- cgit v1.2.1 From 98027769828f772c7ce69b6e58d37b78ebe8ab28 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 21 Dec 2014 12:43:53 +0100 Subject: brcmfmac: enable 802.11d support in firmware When the driver gets beacon info containing a country IE from user-space upon .start_ap() callback, it will enable regulatory 802.11d support. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 26 ++++++++++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h | 1 + drivers/net/wireless/brcm80211/brcmfmac/fwil.h | 2 ++ 3 files changed, 29 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index c896fe27a626..1783c0350e1f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -3966,6 +3966,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); const struct brcmf_tlv *ssid_ie; + const struct brcmf_tlv *country_ie; struct brcmf_ssid_le ssid_le; s32 err = -EPERM; const struct brcmf_tlv *rsn_ie; @@ -3975,6 +3976,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_fil_bss_enable_le bss_enable; u16 chanspec; bool mbss; + int is_11d; brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n", settings->chandef.chan->hw_value, @@ -3986,6 +3988,13 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, dev_role = ifp->vif->wdev.iftype; mbss = ifp->vif->mbss; + /* store current 11d setting */ + brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d); + country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, + settings->beacon.tail_len, + WLAN_EID_COUNTRY); + is_11d = country_ie ? 1 : 0; + memset(&ssid_le, 0, sizeof(ssid_le)); if (settings->ssid == NULL || settings->ssid_len == 0) { ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; @@ -4051,6 +4060,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, goto exit; } + if (is_11d != ifp->vif->is_11d) { + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, + is_11d); + if (err < 0) { + brcmf_err("Regulatory Set Error, %d\n", err); + goto exit; + } + } if (settings->beacon_interval) { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, settings->beacon_interval); @@ -4083,6 +4100,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("SET INFRA error %d\n", err); goto exit; } + } else if (WARN_ON(is_11d != ifp->vif->is_11d)) { + /* Multiple-BSS should use same 11d configuration */ + err = -EINVAL; + goto exit; } if (dev_role == NL80211_IFTYPE_AP) { if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss)) @@ -4178,6 +4199,11 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) brcmf_err("setting INFRA mode failed %d\n", err); if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) brcmf_fil_iovar_int_set(ifp, "mbss", 0); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, + ifp->vif->is_11d); + if (err < 0) + brcmf_err("restoring REGULATORY setting failed %d\n", + err); /* Bring device back up so it can be used again */ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); if (err < 0) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h index a5242af9da4c..d9e6d01b2b69 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h @@ -200,6 +200,7 @@ struct brcmf_cfg80211_vif { struct list_head list; u16 mgmt_rx_reg; bool mbss; + int is_11d; }; /* association inform */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h index 3ede91d11ad2..37345e7b873d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h @@ -43,6 +43,8 @@ #define BRCMF_C_SET_RADIO 38 #define BRCMF_C_GET_PHYTYPE 39 #define BRCMF_C_SET_KEY 45 +#define BRCMF_C_GET_REGULATORY 46 +#define BRCMF_C_SET_REGULATORY 47 #define BRCMF_C_SET_PASSIVE_SCAN 49 #define BRCMF_C_SCAN 50 #define BRCMF_C_SCAN_RESULTS 51 -- cgit v1.2.1 From c0c3163a7213107478804ad92ee3da69f12fe346 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Dec 2014 22:14:32 +0100 Subject: ath5k: drop owner assignment from platform_drivers This platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Wolfram Sang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath5k/ahb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 8f387cf67340..2ca88b593e4c 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -227,7 +227,6 @@ static struct platform_driver ath_ahb_driver = { .remove = ath_ahb_remove, .driver = { .name = "ar231x-wmac", - .owner = THIS_MODULE, }, }; -- cgit v1.2.1 From 72df63100d54bc801700de2c6f525d0fd8bfd799 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 Dec 2014 19:14:05 +0530 Subject: mwifiex: report tdls peers in debugfs This patch add provision to show TDLS peer table in debugfs file. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/debugfs.c | 9 +++++++++ drivers/net/wireless/mwifiex/decl.h | 1 + drivers/net/wireless/mwifiex/ioctl.h | 9 ++++++++- drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/tdls.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/util.c | 2 ++ 6 files changed, 52 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 2713f7acd35e..b50603276ecb 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -493,6 +493,15 @@ mwifiex_debug_read(struct file *file, char __user *ubuf, } } + if (info.tdls_peer_num) { + p += sprintf(p, "TDLS peer table:\n"); + for (i = 0; i < info.tdls_peer_num; i++) { + p += sprintf(p, "peer = %pM", + info.tdls_list[i].peer_addr); + p += sprintf(p, "\n"); + } + } + ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, (unsigned long) p - page); diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 2269acf41ad8..21b5130c264e 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -41,6 +41,7 @@ #define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 #define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 +#define MWIFIEX_MAX_TDLS_PEER_SUPPORTED 8 #define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 64 #define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 64 diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 0847f3e07ab7..dcf4bdbd7505 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -180,7 +180,11 @@ struct mwifiex_ds_tx_ba_stream_tbl { u8 amsdu; }; -#define DBG_CMD_NUM 5 +#define DBG_CMD_NUM 5 + +struct tdls_peer_info { + u8 peer_addr[ETH_ALEN]; +}; struct mwifiex_debug_info { u32 int_counter; @@ -193,6 +197,9 @@ struct mwifiex_debug_info { u32 rx_tbl_num; struct mwifiex_ds_rx_reorder_tbl rx_tbl [MWIFIEX_MAX_RX_BASTREAM_SUPPORTED]; + u32 tdls_peer_num; + struct tdls_peer_info tdls_list + [MWIFIEX_MAX_TDLS_PEER_SUPPORTED]; u16 ps_mode; u32 ps_state; u8 is_deep_sleep; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index e66993cb5daf..b3e23f625e1a 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1324,6 +1324,8 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, u8 *buf, int len); int mwifiex_tdls_oper(struct mwifiex_private *priv, const u8 *peer, u8 action); int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac); +int mwifiex_get_tdls_list(struct mwifiex_private *priv, + struct tdls_peer_info *buf); void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv); bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private *priv); u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band, diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 22884b429be7..efa81d8f2597 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -1123,6 +1123,36 @@ int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac) return TDLS_NOT_SETUP; } +int mwifiex_get_tdls_list(struct mwifiex_private *priv, + struct tdls_peer_info *buf) +{ + struct mwifiex_sta_node *sta_ptr; + struct tdls_peer_info *peer = buf; + int count = 0; + unsigned long flags; + + if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return 0; + + /* make sure we are in station mode and connected */ + if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) + return 0; + + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + list_for_each_entry(sta_ptr, &priv->sta_list, list) { + if (sta_ptr->tdls_status == TDLS_SETUP_COMPLETE) { + ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr); + peer++; + count++; + if (count >= MWIFIEX_MAX_TDLS_PEER_SUPPORTED) + break; + } + } + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + return count; +} + void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv) { struct mwifiex_sta_node *sta_ptr; diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index b1768fbf98f2..3bd917975e5b 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -97,6 +97,8 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, info->rx_tbl); info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(priv, info->tx_tbl); + info->tdls_peer_num = mwifiex_get_tdls_list(priv, + info->tdls_list); info->ps_mode = adapter->ps_mode; info->ps_state = adapter->ps_state; info->is_deep_sleep = adapter->is_deep_sleep; -- cgit v1.2.1 From d35b6392281f3368c8d31be7ce4356ecf6580605 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 Dec 2014 19:14:06 +0530 Subject: mwifiex: add bcn_rcv_cnt and bcn_miss_cnt in getlog debugfs This patch add receive beacon count and miss beacon count statistics in debugfs getlog item. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/debugfs.c | 10 ++++++++-- drivers/net/wireless/mwifiex/fw.h | 2 ++ drivers/net/wireless/mwifiex/ioctl.h | 2 ++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index b50603276ecb..3d2fb9af2069 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -297,6 +297,8 @@ mwifiex_fw_dump_read(struct file *file, char __user *ubuf, * - Number of FCS errors * - Number of Tx frames * - WEP ICV error counts + * - Number of received beacons + * - Number of missed beacons */ static ssize_t mwifiex_getlog_read(struct file *file, char __user *ubuf, @@ -333,7 +335,9 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf, "wepicverrcnt-1 %u\n" "wepicverrcnt-2 %u\n" "wepicverrcnt-3 %u\n" - "wepicverrcnt-4 %u\n", + "wepicverrcnt-4 %u\n" + "bcn_rcv_cnt %u\n" + "bcn_miss_cnt %u\n", stats.mcast_tx_frame, stats.failed, stats.retry, @@ -349,7 +353,9 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf, stats.wep_icv_error[0], stats.wep_icv_error[1], stats.wep_icv_error[2], - stats.wep_icv_error[3]); + stats.wep_icv_error[3], + stats.bcn_rcv_cnt, + stats.bcn_miss_cnt); ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index fb5936eb82e3..a1b8d5319562 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -1076,6 +1076,8 @@ struct host_cmd_ds_802_11_get_log { __le32 tx_frame; __le32 reserved; __le32 wep_icv_err_cnt[4]; + __le32 bcn_rcv_cnt; + __le32 bcn_miss_cnt; }; /* Enumeration for rate format */ diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index dcf4bdbd7505..d2b05c3a96da 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -137,6 +137,8 @@ struct mwifiex_ds_get_stats { u32 fcs_error; u32 tx_frame; u32 wep_icv_error[4]; + u32 bcn_rcv_cnt; + u32 bcn_miss_cnt; }; #define MWIFIEX_MAX_VER_STR_LEN 128 diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index b65e1014b0fc..65d10a33eab5 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -248,6 +248,8 @@ static int mwifiex_ret_get_log(struct mwifiex_private *priv, le32_to_cpu(get_log->wep_icv_err_cnt[2]); stats->wep_icv_error[3] = le32_to_cpu(get_log->wep_icv_err_cnt[3]); + stats->bcn_rcv_cnt = le32_to_cpu(get_log->bcn_rcv_cnt); + stats->bcn_miss_cnt = le32_to_cpu(get_log->bcn_miss_cnt); } return 0; -- cgit v1.2.1 From cbf6e05527a7654ac1c4f4787dfd7a182fcc0c73 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 Dec 2014 19:14:07 +0530 Subject: mwifiex: add rx histogram statistics support This patch add a new debugfs item histogram used for reporting rx data packet statitics(rx rate, snr, noise floor, signal strenth) to userspace. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 4 ++ drivers/net/wireless/mwifiex/cfp.c | 18 ++++++ drivers/net/wireless/mwifiex/debugfs.c | 99 ++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/decl.h | 24 ++++++++ drivers/net/wireless/mwifiex/main.c | 8 +++ drivers/net/wireless/mwifiex/main.h | 10 ++++ drivers/net/wireless/mwifiex/sta_event.c | 4 ++ drivers/net/wireless/mwifiex/sta_rx.c | 9 +++ drivers/net/wireless/mwifiex/uap_event.c | 2 + drivers/net/wireless/mwifiex/util.c | 41 +++++++++++++ 10 files changed, 219 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 4a66a6555366..f8b1ce0a0fd6 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2386,6 +2386,10 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || + GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) + kfree(priv->hist_data); + return 0; } EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index b8242eb2be6f..f494fc7eeb62 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -509,3 +509,21 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) return k; } + +u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, + u8 rx_rate, u8 rate_info) +{ + u8 rate_index = 0; + + /* HT40 */ + if ((rate_info & BIT(0)) && (rate_info & BIT(1))) + rate_index = MWIFIEX_RATE_INDEX_MCS0 + + MWIFIEX_BW20_MCS_NUM + rx_rate; + else if (rate_info & BIT(0)) /* HT20 */ + rate_index = MWIFIEX_RATE_INDEX_MCS0 + rx_rate; + else + rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ? + rx_rate - 1 : rx_rate; + + return rate_index; +} diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 3d2fb9af2069..fe1eb74d6703 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -366,6 +366,103 @@ free_and_exit: return ret; } +/* Sysfs histogram file read handler. + * + * This function is called when the 'histogram' file is opened for reading + * It prints the following histogram information - + * - Number of histogram samples + * - Receive packet number of each rx_rate + * - Receive packet number of each snr + * - Receive packet number of each nosie_flr + * - Receive packet number of each signal streath + */ +static ssize_t +mwifiex_histogram_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *)file->private_data; + ssize_t ret; + struct mwifiex_histogram_data *phist_data; + int i, value; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *)page; + + if (!p) + return -ENOMEM; + + if (!priv || !priv->hist_data) + return -EFAULT; + phist_data = priv->hist_data; + + p += sprintf(p, "\n" + "total samples = %d\n", + atomic_read(&phist_data->num_samples)); + + p += sprintf(p, "rx rates (in Mbps): 0=1M 1=2M"); + p += sprintf(p, "2=5.5M 3=11M 4=6M 5=9M 6=12M\n"); + p += sprintf(p, "7=18M 8=24M 9=36M 10=48M 11=54M"); + p += sprintf(p, "12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n"); + + if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { + p += sprintf(p, "44-53=MCS0-9(VHT:BW20)"); + p += sprintf(p, "54-63=MCS0-9(VHT:BW40)"); + p += sprintf(p, "64-73=MCS0-9(VHT:BW80)\n\n"); + } else { + p += sprintf(p, "\n"); + } + + for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) { + value = atomic_read(&phist_data->rx_rate[i]); + if (value) + p += sprintf(p, "rx_rate[%02d] = %d\n", i, value); + } + + if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { + for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES; + i++) { + value = atomic_read(&phist_data->rx_rate[i]); + if (value) + p += sprintf(p, "rx_rate[%02d] = %d\n", + i, value); + } + } + + for (i = 0; i < MWIFIEX_MAX_SNR; i++) { + value = atomic_read(&phist_data->snr[i]); + if (value) + p += sprintf(p, "snr[%02ddB] = %d\n", i, value); + } + for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) { + value = atomic_read(&phist_data->noise_flr[i]); + if (value) + p += sprintf(p, "noise_flr[-%02ddBm] = %d\n", + (int)(i-128), value); + } + for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) { + value = atomic_read(&phist_data->sig_str[i]); + if (value) + p += sprintf(p, "sig_strength[-%02ddBm] = %d\n", + i, value); + } + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, + (unsigned long)p - page); + + return ret; +} + +static ssize_t +mwifiex_histogram_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = (void *)file->private_data; + + if (priv && priv->hist_data) + mwifiex_hist_data_reset(priv); + return 0; +} + static struct mwifiex_debug_info info; /* @@ -832,6 +929,7 @@ MWIFIEX_DFS_FILE_READ_OPS(fw_dump); MWIFIEX_DFS_FILE_OPS(regrdwr); MWIFIEX_DFS_FILE_OPS(rdeeprom); MWIFIEX_DFS_FILE_OPS(hscfg); +MWIFIEX_DFS_FILE_OPS(histogram); /* * This function creates the debug FS directory structure and the files. @@ -855,6 +953,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) MWIFIEX_DFS_ADD_FILE(rdeeprom); MWIFIEX_DFS_ADD_FILE(fw_dump); MWIFIEX_DFS_ADD_FILE(hscfg); + MWIFIEX_DFS_ADD_FILE(histogram); } /* diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 21b5130c264e..cdca8ed7b3b1 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -93,6 +93,14 @@ #define MWIFIEX_TDLS_MAX_FAIL_COUNT 4 #define MWIFIEX_AUTO_TDLS_IDLE_TIME 10 +/* 54M rates, index from 0 to 11 */ +#define MWIFIEX_RATE_INDEX_MCS0 12 +/* 12-27=MCS0-15(BW20) */ +#define MWIFIEX_BW20_MCS_NUM 15 + +/* Rate index for OFDM 0 */ +#define MWIFIEX_RATE_INDEX_OFDM0 4 + enum mwifiex_bss_type { MWIFIEX_BSS_TYPE_STA = 0, MWIFIEX_BSS_TYPE_UAP = 1, @@ -205,4 +213,20 @@ struct mwifiex_chan_stats { u16 cca_scan_dur; u16 cca_busy_dur; } __packed; + +#define MWIFIEX_HIST_MAX_SAMPLES 1048576 +#define MWIFIEX_MAX_RX_RATES 44 +#define MWIFIEX_MAX_AC_RX_RATES 74 +#define MWIFIEX_MAX_SNR 256 +#define MWIFIEX_MAX_NOISE_FLR 256 +#define MWIFIEX_MAX_SIG_STRENGTH 256 + +struct mwifiex_histogram_data { + atomic_t rx_rate[MWIFIEX_MAX_AC_RX_RATES]; + atomic_t snr[MWIFIEX_MAX_SNR]; + atomic_t noise_flr[MWIFIEX_MAX_NOISE_FLR]; + atomic_t sig_str[MWIFIEX_MAX_SIG_STRENGTH]; + atomic_t num_samples; +}; + #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index d4d2223d1f31..0c44c5ee0a70 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -847,6 +847,7 @@ static const struct net_device_ops mwifiex_netdev_ops = { * - Nick name : Set to null * - Number of Tx timeout : Set to 0 * - Device address : Set to current address + * - Rx histogram statistc : Set to 0 * * In addition, the CFG80211 work queue is also created. */ @@ -867,6 +868,13 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; priv->num_tx_timeout = 0; memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); + + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || + GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + priv->hist_data = kmalloc(sizeof(*priv->hist_data), GFP_KERNEL); + if (priv->hist_data) + mwifiex_hist_data_reset(priv); + } } /* diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index b3e23f625e1a..6f7e0601f804 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -582,6 +582,8 @@ struct mwifiex_private { struct idr ack_status_frames; /* spin lock for ack status */ spinlock_t ack_status_lock; + /** rx histogram data */ + struct mwifiex_histogram_data *hist_data; }; enum mwifiex_ba_status { @@ -1350,6 +1352,14 @@ struct sk_buff * mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, struct sk_buff *skb, u8 flag, u64 *cookie); +void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, + s8 nflr); +void mwifiex_hist_data_reset(struct mwifiex_private *priv); +void mwifiex_hist_data_add(struct mwifiex_private *priv, + u8 rx_rate, s8 snr, s8 nflr); +u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, + u8 rx_rate, u8 ht_info); + #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); void mwifiex_debugfs_remove(void); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index b8c171df6223..fbec95bbc10f 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -90,6 +90,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) priv->is_data_rate_auto = true; priv->data_rate = 0; + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || + GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data) + mwifiex_hist_data_reset(priv); + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { priv->adhoc_state = ADHOC_IDLE; priv->adhoc_is_link_sensed = false; diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index c2ad3b63ae70..b8729c9394e9 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -90,6 +90,7 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, struct ethhdr *eth; u16 rx_pkt_off, rx_pkt_len; u8 *offset; + u8 adj_rx_rate = 0; local_rx_pd = (struct rxpd *) (skb->data); @@ -155,6 +156,14 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, priv->rxpd_htinfo = local_rx_pd->ht_info; + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || + GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + adj_rx_rate = mwifiex_adjust_data_rate(priv, priv->rxpd_rate, + priv->rxpd_htinfo); + mwifiex_hist_data_add(priv, adj_rx_rate, local_rx_pd->snr, + local_rx_pd->nf); + } + ret = mwifiex_recv_packet(priv, skb); if (ret == -1) dev_err(priv->adapter->dev, "recv packet failed\n"); diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index c54a537e31fb..f31086cdf937 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -132,6 +132,8 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause); memcpy(priv->netdev->dev_addr, adapter->event_body + 2, ETH_ALEN); + if (priv->hist_data) + mwifiex_hist_data_reset(priv); break; case EVENT_UAP_MIC_COUNTERMEASURES: /* For future development */ diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 3bd917975e5b..6a83c04cf307 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -406,3 +406,44 @@ void mwifiex_del_all_sta_list(struct mwifiex_private *priv) spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); return; } + +/* This function adds histogram data to histogram array*/ +void mwifiex_hist_data_add(struct mwifiex_private *priv, + u8 rx_rate, s8 snr, s8 nflr) +{ + struct mwifiex_histogram_data *phist_data = priv->hist_data; + + if (atomic_read(&phist_data->num_samples) > MWIFIEX_HIST_MAX_SAMPLES) + mwifiex_hist_data_reset(priv); + mwifiex_hist_data_set(priv, rx_rate, snr, nflr); +} + +/* function to add histogram record */ +void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, + s8 nflr) +{ + struct mwifiex_histogram_data *phist_data = priv->hist_data; + + atomic_inc(&phist_data->num_samples); + atomic_inc(&phist_data->rx_rate[rx_rate]); + atomic_inc(&phist_data->snr[snr]); + atomic_inc(&phist_data->noise_flr[128 + nflr]); + atomic_inc(&phist_data->sig_str[nflr - snr]); +} + +/* function to reset histogram data during init/reset */ +void mwifiex_hist_data_reset(struct mwifiex_private *priv) +{ + int ix; + struct mwifiex_histogram_data *phist_data = priv->hist_data; + + atomic_set(&phist_data->num_samples, 0); + for (ix = 0; ix < MWIFIEX_MAX_AC_RX_RATES; ix++) + atomic_set(&phist_data->rx_rate[ix], 0); + for (ix = 0; ix < MWIFIEX_MAX_SNR; ix++) + atomic_set(&phist_data->snr[ix], 0); + for (ix = 0; ix < MWIFIEX_MAX_NOISE_FLR; ix++) + atomic_set(&phist_data->noise_flr[ix], 0); + for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++) + atomic_set(&phist_data->sig_str[ix], 0); +} -- cgit v1.2.1 From 617543033ed77a4d144555202b4d8e43fcd6ba1b Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 Dec 2014 19:14:08 +0530 Subject: mwifiex: move pm_wakeup_card_complete definition to usb.c Move mwifiex_pm_wakeup_card_complete handler to source file. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/usb.c | 7 +++++++ drivers/net/wireless/mwifiex/usb.h | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 1b56495ec872..8ae7a8586811 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -1010,6 +1010,13 @@ static void mwifiex_usb_submit_rem_rx_urbs(struct mwifiex_adapter *adapter) } } +/* This function is called after the card has woken up. */ +static inline int +mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) +{ + return 0; +} + static struct mwifiex_if_ops usb_ops = { .register_dev = mwifiex_register_dev, .unregister_dev = mwifiex_unregister_dev, diff --git a/drivers/net/wireless/mwifiex/usb.h b/drivers/net/wireless/mwifiex/usb.h index a7cbba1355af..0ad1bebc3f93 100644 --- a/drivers/net/wireless/mwifiex/usb.h +++ b/drivers/net/wireless/mwifiex/usb.h @@ -96,11 +96,4 @@ struct fw_data { u8 data[1]; }; -/* This function is called after the card has woken up. */ -static inline int -mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) -{ - return 0; -} - #endif /*_MWIFIEX_USB_H */ -- cgit v1.2.1 From bb5097fec91efd3253d2b769ba2ccd9f8d67a5d6 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 Dec 2014 19:14:09 +0530 Subject: mwifiex: move debug_data dump function to common utililty file mwifiex_debug_info also need be save to file when firmware dump happens. Move its dump implementation function to commmon utilility file, thus it can be reused in firmware dump function. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/debugfs.c | 181 +-------------------------------- drivers/net/wireless/mwifiex/util.c | 177 ++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/util.h | 20 ++++ 3 files changed, 198 insertions(+), 180 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index fe1eb74d6703..1fb329dc6744 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -39,111 +39,6 @@ static char *bss_modes[] = { "P2P_DEVICE", }; -/* size/addr for mwifiex_debug_info */ -#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n)) -#define item_addr(n) (offsetof(struct mwifiex_debug_info, n)) - -/* size/addr for struct mwifiex_adapter */ -#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n)) -#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n)) - -struct mwifiex_debug_data { - char name[32]; /* variable/array name */ - u32 size; /* size of the variable/array */ - size_t addr; /* address of the variable/array */ - int num; /* number of variables in an array */ -}; - -static struct mwifiex_debug_data items[] = { - {"int_counter", item_size(int_counter), - item_addr(int_counter), 1}, - {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]), - item_addr(packets_out[WMM_AC_VO]), 1}, - {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]), - item_addr(packets_out[WMM_AC_VI]), 1}, - {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]), - item_addr(packets_out[WMM_AC_BE]), 1}, - {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), - item_addr(packets_out[WMM_AC_BK]), 1}, - {"tx_buf_size", item_size(tx_buf_size), - item_addr(tx_buf_size), 1}, - {"curr_tx_buf_size", item_size(curr_tx_buf_size), - item_addr(curr_tx_buf_size), 1}, - {"ps_mode", item_size(ps_mode), - item_addr(ps_mode), 1}, - {"ps_state", item_size(ps_state), - item_addr(ps_state), 1}, - {"is_deep_sleep", item_size(is_deep_sleep), - item_addr(is_deep_sleep), 1}, - {"wakeup_dev_req", item_size(pm_wakeup_card_req), - item_addr(pm_wakeup_card_req), 1}, - {"wakeup_tries", item_size(pm_wakeup_fw_try), - item_addr(pm_wakeup_fw_try), 1}, - {"hs_configured", item_size(is_hs_configured), - item_addr(is_hs_configured), 1}, - {"hs_activated", item_size(hs_activated), - item_addr(hs_activated), 1}, - {"num_tx_timeout", item_size(num_tx_timeout), - item_addr(num_tx_timeout), 1}, - {"is_cmd_timedout", item_size(is_cmd_timedout), - item_addr(is_cmd_timedout), 1}, - {"timeout_cmd_id", item_size(timeout_cmd_id), - item_addr(timeout_cmd_id), 1}, - {"timeout_cmd_act", item_size(timeout_cmd_act), - item_addr(timeout_cmd_act), 1}, - {"last_cmd_id", item_size(last_cmd_id), - item_addr(last_cmd_id), DBG_CMD_NUM}, - {"last_cmd_act", item_size(last_cmd_act), - item_addr(last_cmd_act), DBG_CMD_NUM}, - {"last_cmd_index", item_size(last_cmd_index), - item_addr(last_cmd_index), 1}, - {"last_cmd_resp_id", item_size(last_cmd_resp_id), - item_addr(last_cmd_resp_id), DBG_CMD_NUM}, - {"last_cmd_resp_index", item_size(last_cmd_resp_index), - item_addr(last_cmd_resp_index), 1}, - {"last_event", item_size(last_event), - item_addr(last_event), DBG_CMD_NUM}, - {"last_event_index", item_size(last_event_index), - item_addr(last_event_index), 1}, - {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), - item_addr(num_cmd_host_to_card_failure), 1}, - {"num_cmd_sleep_cfm_fail", - item_size(num_cmd_sleep_cfm_host_to_card_failure), - item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1}, - {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), - item_addr(num_tx_host_to_card_failure), 1}, - {"num_evt_deauth", item_size(num_event_deauth), - item_addr(num_event_deauth), 1}, - {"num_evt_disassoc", item_size(num_event_disassoc), - item_addr(num_event_disassoc), 1}, - {"num_evt_link_lost", item_size(num_event_link_lost), - item_addr(num_event_link_lost), 1}, - {"num_cmd_deauth", item_size(num_cmd_deauth), - item_addr(num_cmd_deauth), 1}, - {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), - item_addr(num_cmd_assoc_success), 1}, - {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), - item_addr(num_cmd_assoc_failure), 1}, - {"cmd_sent", item_size(cmd_sent), - item_addr(cmd_sent), 1}, - {"data_sent", item_size(data_sent), - item_addr(data_sent), 1}, - {"cmd_resp_received", item_size(cmd_resp_received), - item_addr(cmd_resp_received), 1}, - {"event_received", item_size(event_received), - item_addr(event_received), 1}, - - /* variables defined in struct mwifiex_adapter */ - {"cmd_pending", adapter_item_size(cmd_pending), - adapter_item_addr(cmd_pending), 1}, - {"tx_pending", adapter_item_size(tx_pending), - adapter_item_addr(tx_pending), 1}, - {"rx_pending", adapter_item_size(rx_pending), - adapter_item_addr(rx_pending), 1}, -}; - -static int num_of_items = ARRAY_SIZE(items); - /* * Proc info file read handler. * @@ -518,13 +413,9 @@ mwifiex_debug_read(struct file *file, char __user *ubuf, { struct mwifiex_private *priv = (struct mwifiex_private *) file->private_data; - struct mwifiex_debug_data *d = &items[0]; unsigned long page = get_zeroed_page(GFP_KERNEL); char *p = (char *) page; ssize_t ret; - size_t size, addr; - long val; - int i, j; if (!p) return -ENOMEM; @@ -533,77 +424,7 @@ mwifiex_debug_read(struct file *file, char __user *ubuf, if (ret) goto free_and_exit; - for (i = 0; i < num_of_items; i++) { - p += sprintf(p, "%s=", d[i].name); - - size = d[i].size / d[i].num; - - if (i < (num_of_items - 3)) - addr = d[i].addr + (size_t) &info; - else /* The last 3 items are struct mwifiex_adapter variables */ - addr = d[i].addr + (size_t) priv->adapter; - - for (j = 0; j < d[i].num; j++) { - switch (size) { - case 1: - val = *((u8 *) addr); - break; - case 2: - val = *((u16 *) addr); - break; - case 4: - val = *((u32 *) addr); - break; - case 8: - val = *((long long *) addr); - break; - default: - val = -1; - break; - } - - p += sprintf(p, "%#lx ", val); - addr += size; - } - - p += sprintf(p, "\n"); - } - - if (info.tx_tbl_num) { - p += sprintf(p, "Tx BA stream table:\n"); - for (i = 0; i < info.tx_tbl_num; i++) - p += sprintf(p, "tid = %d, ra = %pM\n", - info.tx_tbl[i].tid, info.tx_tbl[i].ra); - } - - if (info.rx_tbl_num) { - p += sprintf(p, "Rx reorder table:\n"); - for (i = 0; i < info.rx_tbl_num; i++) { - p += sprintf(p, "tid = %d, ta = %pM, " - "start_win = %d, " - "win_size = %d, buffer: ", - info.rx_tbl[i].tid, - info.rx_tbl[i].ta, - info.rx_tbl[i].start_win, - info.rx_tbl[i].win_size); - - for (j = 0; j < info.rx_tbl[i].win_size; j++) - p += sprintf(p, "%c ", - info.rx_tbl[i].buffer[j] ? - '1' : '0'); - - p += sprintf(p, "\n"); - } - } - - if (info.tdls_peer_num) { - p += sprintf(p, "TDLS peer table:\n"); - for (i = 0; i < info.tdls_peer_num; i++) { - p += sprintf(p, "peer = %pM", - info.tdls_list[i].peer_addr); - p += sprintf(p, "\n"); - } - } + p += mwifiex_debug_info_to_buffer(priv, p, &info); ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, (unsigned long) p - page); diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 6a83c04cf307..707319799942 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -25,6 +25,96 @@ #include "wmm.h" #include "11n.h" +static struct mwifiex_debug_data items[] = { + {"int_counter", item_size(int_counter), + item_addr(int_counter), 1}, + {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]), + item_addr(packets_out[WMM_AC_VO]), 1}, + {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]), + item_addr(packets_out[WMM_AC_VI]), 1}, + {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]), + item_addr(packets_out[WMM_AC_BE]), 1}, + {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), + item_addr(packets_out[WMM_AC_BK]), 1}, + {"tx_buf_size", item_size(tx_buf_size), + item_addr(tx_buf_size), 1}, + {"curr_tx_buf_size", item_size(curr_tx_buf_size), + item_addr(curr_tx_buf_size), 1}, + {"ps_mode", item_size(ps_mode), + item_addr(ps_mode), 1}, + {"ps_state", item_size(ps_state), + item_addr(ps_state), 1}, + {"is_deep_sleep", item_size(is_deep_sleep), + item_addr(is_deep_sleep), 1}, + {"wakeup_dev_req", item_size(pm_wakeup_card_req), + item_addr(pm_wakeup_card_req), 1}, + {"wakeup_tries", item_size(pm_wakeup_fw_try), + item_addr(pm_wakeup_fw_try), 1}, + {"hs_configured", item_size(is_hs_configured), + item_addr(is_hs_configured), 1}, + {"hs_activated", item_size(hs_activated), + item_addr(hs_activated), 1}, + {"num_tx_timeout", item_size(num_tx_timeout), + item_addr(num_tx_timeout), 1}, + {"is_cmd_timedout", item_size(is_cmd_timedout), + item_addr(is_cmd_timedout), 1}, + {"timeout_cmd_id", item_size(timeout_cmd_id), + item_addr(timeout_cmd_id), 1}, + {"timeout_cmd_act", item_size(timeout_cmd_act), + item_addr(timeout_cmd_act), 1}, + {"last_cmd_id", item_size(last_cmd_id), + item_addr(last_cmd_id), DBG_CMD_NUM}, + {"last_cmd_act", item_size(last_cmd_act), + item_addr(last_cmd_act), DBG_CMD_NUM}, + {"last_cmd_index", item_size(last_cmd_index), + item_addr(last_cmd_index), 1}, + {"last_cmd_resp_id", item_size(last_cmd_resp_id), + item_addr(last_cmd_resp_id), DBG_CMD_NUM}, + {"last_cmd_resp_index", item_size(last_cmd_resp_index), + item_addr(last_cmd_resp_index), 1}, + {"last_event", item_size(last_event), + item_addr(last_event), DBG_CMD_NUM}, + {"last_event_index", item_size(last_event_index), + item_addr(last_event_index), 1}, + {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), + item_addr(num_cmd_host_to_card_failure), 1}, + {"num_cmd_sleep_cfm_fail", + item_size(num_cmd_sleep_cfm_host_to_card_failure), + item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1}, + {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), + item_addr(num_tx_host_to_card_failure), 1}, + {"num_evt_deauth", item_size(num_event_deauth), + item_addr(num_event_deauth), 1}, + {"num_evt_disassoc", item_size(num_event_disassoc), + item_addr(num_event_disassoc), 1}, + {"num_evt_link_lost", item_size(num_event_link_lost), + item_addr(num_event_link_lost), 1}, + {"num_cmd_deauth", item_size(num_cmd_deauth), + item_addr(num_cmd_deauth), 1}, + {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), + item_addr(num_cmd_assoc_success), 1}, + {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), + item_addr(num_cmd_assoc_failure), 1}, + {"cmd_sent", item_size(cmd_sent), + item_addr(cmd_sent), 1}, + {"data_sent", item_size(data_sent), + item_addr(data_sent), 1}, + {"cmd_resp_received", item_size(cmd_resp_received), + item_addr(cmd_resp_received), 1}, + {"event_received", item_size(event_received), + item_addr(event_received), 1}, + + /* variables defined in struct mwifiex_adapter */ + {"cmd_pending", adapter_item_size(cmd_pending), + adapter_item_addr(cmd_pending), 1}, + {"tx_pending", adapter_item_size(tx_pending), + adapter_item_addr(tx_pending), 1}, + {"rx_pending", adapter_item_size(rx_pending), + adapter_item_addr(rx_pending), 1}, +}; + +static int num_of_items = ARRAY_SIZE(items); + /* * Firmware initialization complete callback handler. * @@ -143,6 +233,93 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, return 0; } +int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf, + struct mwifiex_debug_info *info) +{ + char *p = buf; + struct mwifiex_debug_data *d = &items[0]; + size_t size, addr; + long val; + int i, j; + + if (!info) + return 0; + + for (i = 0; i < num_of_items; i++) { + p += sprintf(p, "%s=", d[i].name); + + size = d[i].size / d[i].num; + + if (i < (num_of_items - 3)) + addr = d[i].addr + (size_t)info; + else /* The last 3 items are struct mwifiex_adapter variables */ + addr = d[i].addr + (size_t)priv->adapter; + + for (j = 0; j < d[i].num; j++) { + switch (size) { + case 1: + val = *((u8 *)addr); + break; + case 2: + val = *((u16 *)addr); + break; + case 4: + val = *((u32 *)addr); + break; + case 8: + val = *((long long *)addr); + break; + default: + val = -1; + break; + } + + p += sprintf(p, "%#lx ", val); + addr += size; + } + + p += sprintf(p, "\n"); + } + + if (info->tx_tbl_num) { + p += sprintf(p, "Tx BA stream table:\n"); + for (i = 0; i < info->tx_tbl_num; i++) + p += sprintf(p, "tid = %d, ra = %pM\n", + info->tx_tbl[i].tid, info->tx_tbl[i].ra); + } + + if (info->rx_tbl_num) { + p += sprintf(p, "Rx reorder table:\n"); + for (i = 0; i < info->rx_tbl_num; i++) { + p += sprintf(p, "tid = %d, ta = %pM, ", + info->rx_tbl[i].tid, + info->rx_tbl[i].ta); + p += sprintf(p, "start_win = %d, ", + info->rx_tbl[i].start_win); + p += sprintf(p, "win_size = %d, buffer: ", + info->rx_tbl[i].win_size); + + for (j = 0; j < info->rx_tbl[i].win_size; j++) + p += sprintf(p, "%c ", + info->rx_tbl[i].buffer[j] ? + '1' : '0'); + + p += sprintf(p, "\n"); + } + } + + if (info->tdls_peer_num) { + p += sprintf(p, "TDLS peer table:\n"); + for (i = 0; i < info->tdls_peer_num; i++) { + p += sprintf(p, "peer = %pM", + info->tdls_list[i].peer_addr); + p += sprintf(p, "\n"); + } + } + + return p - buf; +} + static int mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len, struct rxpd *rx_pd) diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h index 40296cb4a3f1..b541d66c01eb 100644 --- a/drivers/net/wireless/mwifiex/util.h +++ b/drivers/net/wireless/mwifiex/util.h @@ -20,6 +20,8 @@ #ifndef _MWIFIEX_UTIL_H_ #define _MWIFIEX_UTIL_H_ +struct mwifiex_private; + struct mwifiex_dma_mapping { dma_addr_t addr; size_t len; @@ -33,6 +35,21 @@ struct mwifiex_cb { }; }; +/* size/addr for mwifiex_debug_info */ +#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n)) +#define item_addr(n) (offsetof(struct mwifiex_debug_info, n)) + +/* size/addr for struct mwifiex_adapter */ +#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n)) +#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n)) + +struct mwifiex_debug_data { + char name[32]; /* variable/array name */ + u32 size; /* size of the variable/array */ + size_t addr; /* address of the variable/array */ + int num; /* number of variables in an array */ +}; + static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) { struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb; @@ -73,4 +90,7 @@ static inline dma_addr_t MWIFIEX_SKB_DMA_ADDR(struct sk_buff *skb) return mapping.addr; } +int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf, + struct mwifiex_debug_info *info); + #endif /* !_MWIFIEX_UTIL_H_ */ -- cgit v1.2.1 From 11cd07a9694cbd4d06361d6f46b735a47daa9a77 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 Dec 2014 19:14:10 +0530 Subject: mwifiex: save driver information to file when firmware dump This patch adds support to dump driver information to a file when firmware dump happens. This information can be used to root casue FW crash. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/ethtool.c | 16 +++++- drivers/net/wireless/mwifiex/init.c | 5 ++ drivers/net/wireless/mwifiex/main.c | 102 +++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/main.h | 9 +++ drivers/net/wireless/mwifiex/sdio.c | 2 + 5 files changed, 133 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c index 04e56b5fc535..65d8d6d4b6ba 100644 --- a/drivers/net/wireless/mwifiex/ethtool.c +++ b/drivers/net/wireless/mwifiex/ethtool.c @@ -76,7 +76,9 @@ mwifiex_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) dump->flag = adapter->curr_mem_idx; dump->version = 1; - if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) { + if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) { + dump->len = adapter->drv_info_size; + } else if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) { entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx]; dump->len = entry->mem_size; } else { @@ -98,6 +100,13 @@ mwifiex_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, if (!adapter->if_ops.fw_dump) return -ENOTSUPP; + if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) { + if (!adapter->drv_info_dump) + return -EFAULT; + memcpy(p, adapter->drv_info_dump, adapter->drv_info_size); + return 0; + } + if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) { dev_err(adapter->dev, "firmware dump in progress!!\n"); return -EBUSY; @@ -125,6 +134,11 @@ static int mwifiex_set_dump(struct net_device *dev, struct ethtool_dump *val) if (!adapter->if_ops.fw_dump) return -ENOTSUPP; + if (val->flag == MWIFIEX_DRV_INFO_IDX) { + adapter->curr_mem_idx = MWIFIEX_DRV_INFO_IDX; + return 0; + } + if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) { dev_err(adapter->dev, "firmware dump in progress!!\n"); return -EBUSY; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 520ad4a3018b..a3dd601a495a 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -411,6 +411,11 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) entry->mem_size = 0; } + if (adapter->drv_info_dump) { + vfree(adapter->drv_info_dump); + adapter->drv_info_size = 0; + } + if (adapter->sleep_cfm) dev_kfree_skb_any(adapter->sleep_cfm); } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 0c44c5ee0a70..4edaaf48259b 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -801,6 +801,108 @@ mwifiex_tx_timeout(struct net_device *dev) } } +void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter) +{ + void *p; + char drv_version[64]; + struct usb_card_rec *cardp; + struct sdio_mmc_card *sdio_card; + struct mwifiex_private *priv; + int i, idx; + struct netdev_queue *txq; + struct mwifiex_debug_info *debug_info; + + if (adapter->drv_info_dump) { + vfree(adapter->drv_info_dump); + adapter->drv_info_size = 0; + } + + dev_info(adapter->dev, "=== DRIVER INFO DUMP START===\n"); + + adapter->drv_info_dump = vzalloc(MWIFIEX_DRV_INFO_SIZE_MAX); + + if (!adapter->drv_info_dump) + return; + + p = (char *)(adapter->drv_info_dump); + p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); + + mwifiex_drv_get_driver_version(adapter, drv_version, + sizeof(drv_version) - 1); + p += sprintf(p, "driver_version = %s\n", drv_version); + + if (adapter->iface_type == MWIFIEX_USB) { + cardp = (struct usb_card_rec *)adapter->card; + p += sprintf(p, "tx_cmd_urb_pending = %d\n", + atomic_read(&cardp->tx_cmd_urb_pending)); + p += sprintf(p, "tx_data_urb_pending = %d\n", + atomic_read(&cardp->tx_data_urb_pending)); + p += sprintf(p, "rx_cmd_urb_pending = %d\n", + atomic_read(&cardp->rx_cmd_urb_pending)); + p += sprintf(p, "rx_data_urb_pending = %d\n", + atomic_read(&cardp->rx_data_urb_pending)); + } + + p += sprintf(p, "tx_pending = %d\n", + atomic_read(&adapter->tx_pending)); + p += sprintf(p, "rx_pending = %d\n", + atomic_read(&adapter->rx_pending)); + + if (adapter->iface_type == MWIFIEX_SDIO) { + sdio_card = (struct sdio_mmc_card *)adapter->card; + p += sprintf(p, "\nmp_rd_bitmap=0x%x curr_rd_port=0x%x\n", + sdio_card->mp_rd_bitmap, sdio_card->curr_rd_port); + p += sprintf(p, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n", + sdio_card->mp_wr_bitmap, sdio_card->curr_wr_port); + } + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i] || !adapter->priv[i]->netdev) + continue; + priv = adapter->priv[i]; + p += sprintf(p, "\n[interface : \"%s\"]\n", + priv->netdev->name); + p += sprintf(p, "wmm_tx_pending[0] = %d\n", + atomic_read(&priv->wmm_tx_pending[0])); + p += sprintf(p, "wmm_tx_pending[1] = %d\n", + atomic_read(&priv->wmm_tx_pending[1])); + p += sprintf(p, "wmm_tx_pending[2] = %d\n", + atomic_read(&priv->wmm_tx_pending[2])); + p += sprintf(p, "wmm_tx_pending[3] = %d\n", + atomic_read(&priv->wmm_tx_pending[3])); + p += sprintf(p, "media_state=\"%s\"\n", !priv->media_connected ? + "Disconnected" : "Connected"); + p += sprintf(p, "carrier %s\n", (netif_carrier_ok(priv->netdev) + ? "on" : "off")); + for (idx = 0; idx < priv->netdev->num_tx_queues; idx++) { + txq = netdev_get_tx_queue(priv->netdev, idx); + p += sprintf(p, "tx queue %d:%s ", idx, + netif_tx_queue_stopped(txq) ? + "stopped" : "started"); + } + p += sprintf(p, "\n%s: num_tx_timeout = %d\n", + priv->netdev->name, priv->num_tx_timeout); + } + + p += sprintf(p, "\n=== MORE DEBUG INFORMATION\n"); + debug_info = kzalloc(sizeof(*debug_info), GFP_KERNEL); + if (debug_info) { + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i] || !adapter->priv[i]->netdev) + continue; + priv = adapter->priv[i]; + mwifiex_get_debug_info(priv, debug_info); + p += mwifiex_debug_info_to_buffer(priv, p, debug_info); + break; + } + kfree(debug_info); + } + + adapter->drv_info_size = p - adapter->drv_info_dump; + dev_info(adapter->dev, "=== DRIVER INFO DUMP END===\n"); +} +EXPORT_SYMBOL_GPL(mwifiex_dump_drv_info); + /* * CFG802.11 network device handler for statistics retrieval. */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 6f7e0601f804..2f085de1ff63 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -41,6 +41,8 @@ #include "util.h" #include "fw.h" #include "pcie.h" +#include "usb.h" +#include "sdio.h" extern const char driver_version[]; @@ -136,6 +138,8 @@ enum { /* Threshold for tx_timeout_cnt before we trigger a card reset */ #define TX_TIMEOUT_THRESHOLD 6 +#define MWIFIEX_DRV_INFO_SIZE_MAX 0x40000 + struct mwifiex_dbg { u32 num_cmd_host_to_card_failure; u32 num_cmd_sleep_cfm_host_to_card_failure; @@ -413,6 +417,7 @@ struct mwifiex_roc_cfg { }; #define MWIFIEX_FW_DUMP_IDX 0xff +#define MWIFIEX_DRV_INFO_IDX 20 #define FW_DUMP_MAX_NAME_LEN 8 #define FW_DUMP_HOST_READY 0xEE #define FW_DUMP_DONE 0xFF @@ -867,6 +872,8 @@ struct mwifiex_adapter { struct memory_type_mapping *mem_type_mapping_tbl; u8 num_mem_types; u8 curr_mem_idx; + void *drv_info_dump; + u32 drv_info_size; bool scan_chan_gap_enabled; struct sk_buff_head rx_data_q; struct mwifiex_chan_stats *chan_stats; @@ -1360,6 +1367,8 @@ void mwifiex_hist_data_add(struct mwifiex_private *priv, u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, u8 rx_rate, u8 ht_info); +void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter); + #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); void mwifiex_debugfs_remove(void); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 933dae137850..6bdfe67eabab 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -2023,6 +2023,8 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work) u32 memory_size; static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL }; + mwifiex_dump_drv_info(adapter); + if (!card->supports_fw_dump) return; -- cgit v1.2.1 From 809c6ea8abe9f18b74253e6c8c7b23dd73f74b7a Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 Dec 2014 19:14:11 +0530 Subject: mwifiex: save sdio register values before firmware dump This patch saves sdio registers value before firmware dump, this can be used to find out reason for FW dump. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.c | 6 +++ drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/sdio.c | 94 +++++++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/sdio.h | 26 ++++++++++ 4 files changed, 127 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 4edaaf48259b..6125d1c8ae3a 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -884,6 +884,12 @@ void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter) priv->netdev->name, priv->num_tx_timeout); } + if (adapter->iface_type == MWIFIEX_SDIO) { + p += sprintf(p, "\n=== SDIO register DUMP===\n"); + if (adapter->if_ops.reg_dump) + p += adapter->if_ops.reg_dump(adapter, p); + } + p += sprintf(p, "\n=== MORE DEBUG INFORMATION\n"); debug_info = kzalloc(sizeof(*debug_info), GFP_KERNEL); if (debug_info) { diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 2f085de1ff63..dd55bc16aeab 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -724,6 +724,7 @@ struct mwifiex_if_ops { int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); void (*card_reset) (struct mwifiex_adapter *); void (*fw_dump)(struct mwifiex_adapter *); + int (*reg_dump)(struct mwifiex_adapter *, char *); int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); void (*iface_work)(struct work_struct *work); void (*submit_rem_rx_urbs)(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 6bdfe67eabab..274a1b2b0365 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -2168,6 +2168,99 @@ static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter) schedule_work(&adapter->iface_work); } +/* Function to dump SDIO function registers and SDIO scratch registers in case + * of FW crash + */ +static int +mwifiex_sdio_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf) +{ + char *p = drv_buf; + struct sdio_mmc_card *cardp = adapter->card; + int ret = 0; + u8 count, func, data, index = 0, size = 0; + u8 reg, reg_start, reg_end; + char buf[256], *ptr; + + if (!p) + return 0; + + dev_info(adapter->dev, "SDIO register DUMP START\n"); + + mwifiex_pm_wakeup_card(adapter); + + sdio_claim_host(cardp->func); + + for (count = 0; count < 5; count++) { + memset(buf, 0, sizeof(buf)); + ptr = buf; + + switch (count) { + case 0: + /* Read the registers of SDIO function0 */ + func = count; + reg_start = 0; + reg_end = 9; + break; + case 1: + /* Read the registers of SDIO function1 */ + func = count; + reg_start = cardp->reg->func1_dump_reg_start; + reg_end = cardp->reg->func1_dump_reg_end; + break; + case 2: + index = 0; + func = 1; + reg_start = cardp->reg->func1_spec_reg_table[index++]; + size = cardp->reg->func1_spec_reg_num; + reg_end = cardp->reg->func1_spec_reg_table[size-1]; + break; + default: + /* Read the scratch registers of SDIO function1 */ + if (count == 4) + mdelay(100); + func = 1; + reg_start = cardp->reg->func1_scratch_reg; + reg_end = reg_start + MWIFIEX_SDIO_SCRATCH_SIZE; + } + + if (count != 2) + ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", + func, reg_start, reg_end); + else + ptr += sprintf(ptr, "SDIO Func%d: ", func); + + for (reg = reg_start; reg <= reg_end;) { + if (func == 0) + data = sdio_f0_readb(cardp->func, reg, &ret); + else + data = sdio_readb(cardp->func, reg, &ret); + + if (count == 2) + ptr += sprintf(ptr, "(%#x) ", reg); + if (!ret) { + ptr += sprintf(ptr, "%02x ", data); + } else { + ptr += sprintf(ptr, "ERR"); + break; + } + + if (count == 2 && reg < reg_end) + reg = cardp->reg->func1_spec_reg_table[index++]; + else + reg++; + } + + dev_info(adapter->dev, "%s\n", buf); + p += sprintf(p, "%s\n", buf); + } + + sdio_release_host(cardp->func); + + dev_info(adapter->dev, "SDIO register DUMP END\n"); + + return p - drv_buf; +} + static struct mwifiex_if_ops sdio_ops = { .init_if = mwifiex_init_sdio, .cleanup_if = mwifiex_cleanup_sdio, @@ -2190,6 +2283,7 @@ static struct mwifiex_if_ops sdio_ops = { .card_reset = mwifiex_sdio_card_reset, .iface_work = mwifiex_sdio_work, .fw_dump = mwifiex_sdio_fw_dump, + .reg_dump = mwifiex_sdio_reg_dump, }; /* diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 54c07156dd78..895eea054c9e 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -44,6 +44,9 @@ #define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000 +#define MWIFIEX_MAX_FUNC2_REG_NUM 13 +#define MWIFIEX_SDIO_SCRATCH_SIZE 10 + #define SDIO_MPA_ADDR_BASE 0x1000 #define CTRL_PORT 0 #define CTRL_PORT_MASK 0x0001 @@ -219,6 +222,11 @@ struct mwifiex_sdio_card_reg { u8 fw_dump_ctrl; u8 fw_dump_start; u8 fw_dump_end; + u8 func1_dump_reg_start; + u8 func1_dump_reg_end; + u8 func1_scratch_reg; + u8 func1_spec_reg_num; + u8 func1_spec_reg_table[MWIFIEX_MAX_FUNC2_REG_NUM]; }; struct sdio_mmc_card { @@ -291,6 +299,11 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = { .rd_len_p0_l = 0x08, .rd_len_p0_u = 0x09, .card_misc_cfg_reg = 0x6c, + .func1_dump_reg_start = 0x0, + .func1_dump_reg_end = 0x9, + .func1_scratch_reg = 0x60, + .func1_spec_reg_num = 5, + .func1_spec_reg_table = {0x28, 0x30, 0x34, 0x38, 0x3c}, }; static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = { @@ -335,6 +348,12 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = { .fw_dump_ctrl = 0xe2, .fw_dump_start = 0xe3, .fw_dump_end = 0xea, + .func1_dump_reg_start = 0x0, + .func1_dump_reg_end = 0xb, + .func1_scratch_reg = 0xc0, + .func1_spec_reg_num = 8, + .func1_spec_reg_table = {0x4C, 0x50, 0x54, 0x55, 0x58, + 0x59, 0x5c, 0x5d}, }; static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8887 = { @@ -376,6 +395,13 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8887 = { .cmd_cfg_1 = 0xc5, .cmd_cfg_2 = 0xc6, .cmd_cfg_3 = 0xc7, + .func1_dump_reg_start = 0x10, + .func1_dump_reg_end = 0x17, + .func1_scratch_reg = 0x90, + .func1_spec_reg_num = 13, + .func1_spec_reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, + 0x61, 0x62, 0x64, 0x65, 0x66, + 0x68, 0x69, 0x6a}, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { -- cgit v1.2.1 From 0b4155d1cc8e7562f490124c081e710c36cb2cf8 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Tue, 23 Dec 2014 19:14:12 +0530 Subject: mwifiex: module parameter for deep sleep configuration This patch adds module parameter for auto deepsleep configuration. By default, module_param is 0 and auto deep sleep is enabled. If mwifiex driver is loaded with disable_auto_ds=1, deep sleep configuration would not be downloaded to FW and FW would not enter deepsleep upon initializing. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sta_cmd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 1c2ca291d1f5..f7b920d7a95a 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -26,6 +26,10 @@ #include "11n.h" #include "11ac.h" +static bool disable_auto_ds; +module_param(disable_auto_ds, bool, 0); +MODULE_PARM_DESC(disable_auto_ds, + "deepsleep enabled=0(default), deepsleep disabled=1"); /* * This function prepares command to set/get RSSI information. * @@ -2031,7 +2035,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) if (ret) return -1; - if (first_sta && priv->adapter->iface_type != MWIFIEX_USB && + if (!disable_auto_ds && + first_sta && priv->adapter->iface_type != MWIFIEX_USB && priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { /* Enable auto deep sleep */ auto_ds.auto_ds = DEEP_SLEEP_ON; -- cgit v1.2.1 From 8b3a38daff6f50027039d6979b9eb026907508eb Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 23 Dec 2014 19:04:23 +0100 Subject: brcmfmac: Add support for bcm43340/1 wireless chipsets This patch adds support for the bcm43340 and bcm43341 wireless chipsets. These two chipsets are identical from wireless parts perspective. As such they use the same firmware image. Cc: Samuel Ortiz Cc: Rob Herring Signed-off-by: John Stultz [arend@broadcom.com: squash to single commit, remove 43341 chipid] Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 2 ++ drivers/net/wireless/brcm80211/brcmfmac/chip.c | 1 + drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 5 +++++ drivers/net/wireless/brcm80211/include/brcm_hw_ids.h | 3 +++ 4 files changed, 11 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 9880dae2a569..dffd9e44f5b6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -1005,6 +1005,8 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(BRCM_SDIO_4329_DEVICE_ID), BRCMF_SDIO_DEVICE(BRCM_SDIO_4330_DEVICE_ID), BRCMF_SDIO_DEVICE(BRCM_SDIO_4334_DEVICE_ID), + BRCMF_SDIO_DEVICE(BRCM_SDIO_43340_DEVICE_ID), + BRCMF_SDIO_DEVICE(BRCM_SDIO_43341_DEVICE_ID), BRCMF_SDIO_DEVICE(BRCM_SDIO_43362_DEVICE_ID), BRCMF_SDIO_DEVICE(BRCM_SDIO_4335_4339_DEVICE_ID), BRCMF_SDIO_DEVICE(BRCM_SDIO_4354_DEVICE_ID), diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index 519b79ebaabd..04d2ca0d87d6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -481,6 +481,7 @@ static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) ci->pub.ramsize = 0x48000; break; case BRCM_CC_4334_CHIP_ID: + case BRCM_CC_43340_CHIP_ID: ci->pub.ramsize = 0x80000; break; case BRCM_CC_4335_CHIP_ID: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 0b0d51a61060..551da356a5bd 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -608,6 +608,8 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { #define BCM4330_NVRAM_NAME "brcm/brcmfmac4330-sdio.txt" #define BCM4334_FIRMWARE_NAME "brcm/brcmfmac4334-sdio.bin" #define BCM4334_NVRAM_NAME "brcm/brcmfmac4334-sdio.txt" +#define BCM43340_FIRMWARE_NAME "brcm/brcmfmac43340-sdio.bin" +#define BCM43340_NVRAM_NAME "brcm/brcmfmac43340-sdio.txt" #define BCM4335_FIRMWARE_NAME "brcm/brcmfmac4335-sdio.bin" #define BCM4335_NVRAM_NAME "brcm/brcmfmac4335-sdio.txt" #define BCM43362_FIRMWARE_NAME "brcm/brcmfmac43362-sdio.bin" @@ -629,6 +631,8 @@ MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4330_NVRAM_NAME); MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4334_NVRAM_NAME); +MODULE_FIRMWARE(BCM43340_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM43340_NVRAM_NAME); MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4335_NVRAM_NAME); MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME); @@ -660,6 +664,7 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = { { BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) }, { BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) }, { BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, + { BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43340) }, { BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, { BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, { BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }, diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 6996fcc144cf..00215efbc13b 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -34,6 +34,7 @@ #define BRCM_CC_4329_CHIP_ID 0x4329 #define BRCM_CC_4330_CHIP_ID 0x4330 #define BRCM_CC_4334_CHIP_ID 0x4334 +#define BRCM_CC_43340_CHIP_ID 43340 #define BRCM_CC_43362_CHIP_ID 43362 #define BRCM_CC_4335_CHIP_ID 0x4335 #define BRCM_CC_4339_CHIP_ID 0x4339 @@ -51,6 +52,8 @@ #define BRCM_SDIO_4329_DEVICE_ID BRCM_CC_4329_CHIP_ID #define BRCM_SDIO_4330_DEVICE_ID BRCM_CC_4330_CHIP_ID #define BRCM_SDIO_4334_DEVICE_ID BRCM_CC_4334_CHIP_ID +#define BRCM_SDIO_43340_DEVICE_ID BRCM_CC_43340_CHIP_ID +#define BRCM_SDIO_43341_DEVICE_ID 43341 #define BRCM_SDIO_43362_DEVICE_ID BRCM_CC_43362_CHIP_ID #define BRCM_SDIO_4335_4339_DEVICE_ID BRCM_CC_4335_CHIP_ID #define BRCM_SDIO_4354_DEVICE_ID BRCM_CC_4354_CHIP_ID -- cgit v1.2.1 From bd7d0d103ae8c841c0e2b9fd6c5e591b2fae3bb5 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 26 Dec 2014 03:02:31 -0800 Subject: mwifiex: enable -D__CHECK_ENDIAN__ for sparse by default Enable the endian checks by default. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/Makefile | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile index 9487d728ac20..fdfd9bf15ed4 100644 --- a/drivers/net/wireless/mwifiex/Makefile +++ b/drivers/net/wireless/mwifiex/Makefile @@ -53,3 +53,5 @@ obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o mwifiex_usb-y += usb.o obj-$(CONFIG_MWIFIEX_USB) += mwifiex_usb.o + +ccflags-y += -D__CHECK_ENDIAN -- cgit v1.2.1 From 2ab87d5d670d6946cae03b519ab9ef76c932d1a3 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Fri, 26 Dec 2014 03:02:32 -0800 Subject: mwifiex: do not send key material cmd when delete wep key This patch fixes memory corruption reported by community developer. "Memory corruption occurs in mwifiex_ret_802_11_key_material_v1() when a short command response is received without a key length causing non initialised memory to be interpreted as the key length resulting in a memcpy() overwriting the part of the driver's private data structure beyond the key area." For v1 key material API firmwares, there is no need to send command to delete WEP key. WEP encryption/decryption is controlled by mac_control command. This patch avoids sending key material command in del_key case. Reported-by: Martin Fuzzey Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sta_ioctl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 1626868a4b5c..fb9c5fc83e5d 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -902,9 +902,12 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, if (wep_key->key_length) { void *enc_key; - if (encrypt_key->key_disable) + if (encrypt_key->key_disable) { memset(&priv->wep_key[index], 0, sizeof(struct mwifiex_wep_key)); + if (wep_key->key_length) + goto done; + } if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) enc_key = encrypt_key; @@ -918,6 +921,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, return ret; } +done: if (priv->sec_info.wep_enabled) priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; else -- cgit v1.2.1 From 84b313b35f8158d7ff35d649d18428a7740db49e Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Fri, 26 Dec 2014 03:02:33 -0800 Subject: mwifiex: make tx packet 64 byte DMA aligned This patch adds support for DMA alignment of 64 bytes for TX packets. Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11n_aggr.c | 15 ++++++++++++--- drivers/net/wireless/mwifiex/decl.h | 9 ++++++--- drivers/net/wireless/mwifiex/sta_tx.c | 19 ++++++++++--------- drivers/net/wireless/mwifiex/uap_txrx.c | 28 +++++++++++++++------------- 4 files changed, 43 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 8720a3d3c755..9b983b5cebbd 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -101,6 +101,13 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, { struct txpd *local_tx_pd; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + unsigned int pad; + int headroom = (priv->adapter->iface_type == + MWIFIEX_USB) ? 0 : INTF_HEADER_LEN; + + pad = ((void *)skb->data - sizeof(*local_tx_pd) - + headroom - NULL) & (MWIFIEX_DMA_ALIGN_SZ - 1); + skb_push(skb, pad); skb_push(skb, sizeof(*local_tx_pd)); @@ -114,10 +121,12 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, local_tx_pd->bss_num = priv->bss_num; local_tx_pd->bss_type = priv->bss_type; /* Always zero as the data is followed by struct txpd */ - local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) + + pad); local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU); local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len - - sizeof(*local_tx_pd)); + sizeof(*local_tx_pd) - + pad); if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT) local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET; @@ -182,7 +191,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, ra_list_flags); return -1; } - skb_reserve(skb_aggr, headroom + sizeof(struct txpd)); + skb_reserve(skb_aggr, MWIFIEX_MIN_DATA_HEADER_LEN); tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr); memset(tx_info_aggr, 0, sizeof(*tx_info_aggr)); diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index cdca8ed7b3b1..7aa988e1dc7a 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -32,9 +32,12 @@ #define MWIFIEX_MAX_BSS_NUM (3) -#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd) - * + 4 byte alignment - */ +#define MWIFIEX_DMA_ALIGN_SZ 64 +#define MAX_TXPD_SZ 32 +#define INTF_HDR_ALIGN 4 + +#define MWIFIEX_MIN_DATA_HEADER_LEN (MWIFIEX_DMA_ALIGN_SZ + INTF_HDR_ALIGN + \ + MAX_TXPD_SZ) #define MWIFIEX_MGMT_FRAME_HEADER_SIZE 8 /* sizeof(pkt_type) * + sizeof(tx_control) */ diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index b896d7375b52..1debe76017b1 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -47,8 +47,10 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct txpd *local_tx_pd; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); - u8 pad; + unsigned int pad; u16 pkt_type, pkt_offset; + int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 : + INTF_HEADER_LEN; if (!skb->len) { dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len); @@ -56,13 +58,12 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, return skb->data; } - pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0; + BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN); - /* If skb->data is not aligned; add padding */ - pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4; + pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0; - BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN - + pad)); + pad = ((void *)skb->data - (sizeof(*local_tx_pd) + hroom)- + NULL) & (MWIFIEX_DMA_ALIGN_SZ - 1); skb_push(skb, sizeof(*local_tx_pd) + pad); local_tx_pd = (struct txpd *) skb->data; @@ -70,8 +71,8 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, local_tx_pd->bss_num = priv->bss_num; local_tx_pd->bss_type = priv->bss_type; local_tx_pd->tx_pkt_length = cpu_to_le16((u16)(skb->len - - (sizeof(struct txpd) - + pad))); + (sizeof(struct txpd) + + pad))); local_tx_pd->priority = (u8) skb->priority; local_tx_pd->pkt_delay_2ms = @@ -115,7 +116,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset); /* make space for INTF_HEADER_LEN */ - skb_push(skb, INTF_HEADER_LEN); + skb_push(skb, hroom); if (!local_tx_pd->tx_control) /* TxCtrl set by user or default */ diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index be3a203a529b..38ac4d74c486 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -348,8 +348,10 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct uap_txpd *txpd; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); - int pad, len; - u16 pkt_type; + int pad; + u16 pkt_type, pkt_offset; + int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 : + INTF_HEADER_LEN; if (!skb->len) { dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len); @@ -357,22 +359,21 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, return skb->data; } - pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0; - - /* If skb->data is not aligned, add padding */ - pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4; + BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN); - len = sizeof(*txpd) + pad; + pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0; - BUG_ON(skb_headroom(skb) < len + INTF_HEADER_LEN); + pad = ((void *)skb->data - (sizeof(*txpd) + hroom) - NULL) & + (MWIFIEX_DMA_ALIGN_SZ - 1); - skb_push(skb, len); + skb_push(skb, sizeof(*txpd) + pad); txpd = (struct uap_txpd *)skb->data; memset(txpd, 0, sizeof(*txpd)); txpd->bss_num = priv->bss_num; txpd->bss_type = priv->bss_type; - txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - len)); + txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - (sizeof(*txpd) + + pad))); txpd->priority = (u8)skb->priority; txpd->pkt_delay_2ms = mwifiex_wmm_compute_drv_pkt_delay(priv, skb); @@ -392,16 +393,17 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[txpd->priority]); /* Offset of actual data */ + pkt_offset = sizeof(*txpd) + pad; if (pkt_type == PKT_TYPE_MGMT) { /* Set the packet type and add header for management frame */ txpd->tx_pkt_type = cpu_to_le16(pkt_type); - len += MWIFIEX_MGMT_FRAME_HEADER_SIZE; + pkt_offset += MWIFIEX_MGMT_FRAME_HEADER_SIZE; } - txpd->tx_pkt_offset = cpu_to_le16(len); + txpd->tx_pkt_offset = cpu_to_le16(pkt_offset); /* make space for INTF_HEADER_LEN */ - skb_push(skb, INTF_HEADER_LEN); + skb_push(skb, hroom); if (!txpd->tx_control) /* TxCtrl set by user or default */ -- cgit v1.2.1 From 4f3dfdfb4cbf1771f2e0e17d0dcb2cd1852fd392 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 26 Dec 2014 03:02:34 -0800 Subject: mwifiex: get supported BA stream info from FW This patch adds support to get number of BA streams supported information from FW. Some newer chips(e.g. 8897 series) support 4 BA streams for TX; so driver should not disallow BA stream setup just after 2 streams have been established. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11n.h | 14 +++++++++++--- drivers/net/wireless/mwifiex/fw.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index f275675cdbd3..8e2e39422ad8 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -130,7 +130,9 @@ static inline u8 mwifiex_space_avail_for_new_ba_stream( { struct mwifiex_private *priv; u8 i; - u32 ba_stream_num = 0; + u32 ba_stream_num = 0, ba_stream_max; + + ba_stream_max = MWIFIEX_MAX_TX_BASTREAM_SUPPORTED; for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; @@ -139,8 +141,14 @@ static inline u8 mwifiex_space_avail_for_new_ba_stream( &priv->tx_ba_stream_tbl_ptr); } - return ((ba_stream_num < - MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false); + if (adapter->fw_api_ver == MWIFIEX_FW_V15) { + ba_stream_max = + GETSUPP_TXBASTREAMS(adapter->hw_dot_11n_dev_cap); + if (!ba_stream_max) + ba_stream_max = MWIFIEX_MAX_TX_BASTREAM_SUPPORTED; + } + + return ((ba_stream_num < ba_stream_max) ? true : false); } /* diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index a1b8d5319562..15ad776ae08e 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -233,6 +233,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22)) #define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & BIT(30)) #define ISALLOWED_CHANWIDTH40(ht_param) (ht_param & BIT(2)) +#define GETSUPP_TXBASTREAMS(Dot11nDevCap) ((Dot11nDevCap >> 18) & 0xF) /* httxcfg bitmap * 0 reserved -- cgit v1.2.1 From 53831aa12538f8753fb77b7ab6408cce54973b30 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Tue, 6 Jan 2015 09:20:15 -0800 Subject: Driver: Vmxnet3: Make Rx ring 2 size configurable Rx ring 2 size can be configured by adjusting rx-jumbo parameter of ethtool -G. Signed-off-by: Ramya Bolla Signed-off-by: Shreyas Bhatewara Signed-off-by: Shrikrishna Khare Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_defs.h | 1 + drivers/net/vmxnet3/vmxnet3_drv.c | 6 +++++- drivers/net/vmxnet3/vmxnet3_ethtool.c | 27 ++++++++++++++++++++------- drivers/net/vmxnet3/vmxnet3_int.h | 6 ++++-- 4 files changed, 30 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h index 4d84912c99ba..25b6fa4810b5 100644 --- a/drivers/net/vmxnet3/vmxnet3_defs.h +++ b/drivers/net/vmxnet3/vmxnet3_defs.h @@ -342,6 +342,7 @@ union Vmxnet3_GenericDesc { #define VMXNET3_TX_RING_MAX_SIZE 4096 #define VMXNET3_TC_RING_MAX_SIZE 4096 #define VMXNET3_RX_RING_MAX_SIZE 4096 +#define VMXNET3_RX_RING2_MAX_SIZE 2048 #define VMXNET3_RC_RING_MAX_SIZE 8192 /* a list of reasons for queue stop */ diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index afd295348ddb..7af1f5cfa87a 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2505,6 +2505,9 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter) ring0_size = min_t(u32, ring0_size, VMXNET3_RX_RING_MAX_SIZE / sz * sz); ring1_size = adapter->rx_queue[0].rx_ring[1].size; + ring1_size = (ring1_size + sz - 1) / sz * sz; + ring1_size = min_t(u32, ring1_size, VMXNET3_RX_RING2_MAX_SIZE / + sz * sz); comp_size = ring0_size + ring1_size; for (i = 0; i < adapter->num_rx_queues; i++) { @@ -2585,7 +2588,7 @@ vmxnet3_open(struct net_device *netdev) err = vmxnet3_create_queues(adapter, adapter->tx_ring_size, adapter->rx_ring_size, - VMXNET3_DEF_RX_RING_SIZE); + adapter->rx_ring2_size); if (err) goto queue_err; @@ -2964,6 +2967,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, adapter->tx_ring_size = VMXNET3_DEF_TX_RING_SIZE; adapter->rx_ring_size = VMXNET3_DEF_RX_RING_SIZE; + adapter->rx_ring2_size = VMXNET3_DEF_RX_RING2_SIZE; spin_lock_init(&adapter->cmd_lock); adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter, diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index b7b53329d575..8a5a90eeb4f9 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -447,12 +447,12 @@ vmxnet3_get_ringparam(struct net_device *netdev, param->rx_max_pending = VMXNET3_RX_RING_MAX_SIZE; param->tx_max_pending = VMXNET3_TX_RING_MAX_SIZE; param->rx_mini_max_pending = 0; - param->rx_jumbo_max_pending = 0; + param->rx_jumbo_max_pending = VMXNET3_RX_RING2_MAX_SIZE; param->rx_pending = adapter->rx_ring_size; param->tx_pending = adapter->tx_ring_size; param->rx_mini_pending = 0; - param->rx_jumbo_pending = 0; + param->rx_jumbo_pending = adapter->rx_ring2_size; } @@ -461,7 +461,7 @@ vmxnet3_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *param) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); - u32 new_tx_ring_size, new_rx_ring_size; + u32 new_tx_ring_size, new_rx_ring_size, new_rx_ring2_size; u32 sz; int err = 0; @@ -473,6 +473,10 @@ vmxnet3_set_ringparam(struct net_device *netdev, VMXNET3_RX_RING_MAX_SIZE) return -EINVAL; + if (param->rx_jumbo_pending == 0 || + param->rx_jumbo_pending > VMXNET3_RX_RING2_MAX_SIZE) + return -EINVAL; + /* if adapter not yet initialized, do nothing */ if (adapter->rx_buf_per_pkt == 0) { netdev_err(netdev, "adapter not completely initialized, " @@ -500,8 +504,15 @@ vmxnet3_set_ringparam(struct net_device *netdev, sz) != 0) return -EINVAL; - if (new_tx_ring_size == adapter->tx_queue[0].tx_ring.size && - new_rx_ring_size == adapter->rx_queue[0].rx_ring[0].size) { + /* ring2 has to be a multiple of VMXNET3_RING_SIZE_ALIGN */ + new_rx_ring2_size = (param->rx_jumbo_pending + VMXNET3_RING_SIZE_MASK) & + ~VMXNET3_RING_SIZE_MASK; + new_rx_ring2_size = min_t(u32, new_rx_ring2_size, + VMXNET3_RX_RING2_MAX_SIZE); + + if (new_tx_ring_size == adapter->tx_ring_size && + new_rx_ring_size == adapter->rx_ring_size && + new_rx_ring2_size == adapter->rx_ring2_size) { return 0; } @@ -522,7 +533,7 @@ vmxnet3_set_ringparam(struct net_device *netdev, vmxnet3_rq_destroy_all(adapter); err = vmxnet3_create_queues(adapter, new_tx_ring_size, - new_rx_ring_size, VMXNET3_DEF_RX_RING_SIZE); + new_rx_ring_size, new_rx_ring2_size); if (err) { /* failed, most likely because of OOM, try default @@ -530,11 +541,12 @@ vmxnet3_set_ringparam(struct net_device *netdev, netdev_err(netdev, "failed to apply new sizes, " "try the default ones\n"); new_rx_ring_size = VMXNET3_DEF_RX_RING_SIZE; + new_rx_ring2_size = VMXNET3_DEF_RX_RING2_SIZE; new_tx_ring_size = VMXNET3_DEF_TX_RING_SIZE; err = vmxnet3_create_queues(adapter, new_tx_ring_size, new_rx_ring_size, - VMXNET3_DEF_RX_RING_SIZE); + new_rx_ring2_size); if (err) { netdev_err(netdev, "failed to create queues " "with default sizes. Closing it\n"); @@ -549,6 +561,7 @@ vmxnet3_set_ringparam(struct net_device *netdev, } adapter->tx_ring_size = new_tx_ring_size; adapter->rx_ring_size = new_rx_ring_size; + adapter->rx_ring2_size = new_rx_ring2_size; out: clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state); diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 5f0199f6c31e..048f02058ec9 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -69,10 +69,10 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.2.1.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.3.1.0-k" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01020100 +#define VMXNET3_DRIVER_VERSION_NUM 0x01030100 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */ @@ -352,6 +352,7 @@ struct vmxnet3_adapter { /* Ring sizes */ u32 tx_ring_size; u32 rx_ring_size; + u32 rx_ring2_size; struct work_struct work; @@ -384,6 +385,7 @@ struct vmxnet3_adapter { /* must be a multiple of VMXNET3_RING_SIZE_ALIGN */ #define VMXNET3_DEF_TX_RING_SIZE 512 #define VMXNET3_DEF_RX_RING_SIZE 256 +#define VMXNET3_DEF_RX_RING2_SIZE 128 #define VMXNET3_MAX_ETH_HDR_SIZE 22 #define VMXNET3_MAX_SKB_BUF_SIZE (3*1024) -- cgit v1.2.1 From 7197325b17737144e2e7cb9f68d2ebd1a0696ee1 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 31 Dec 2014 02:36:38 -0800 Subject: mwifiex: remove redundant flag MWIFIEX_HW_STATUS_FW_READY This flag is never set but checked at two places. We will get rid of this code. Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.c | 6 ++---- drivers/net/wireless/mwifiex/main.h | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 6125d1c8ae3a..2568395f0276 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -511,8 +511,7 @@ err_dnld_fw: if (adapter->if_ops.unregister_dev) adapter->if_ops.unregister_dev(adapter); - if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || - (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { + if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) { pr_debug("info: %s: shutdown mwifiex\n", __func__); adapter->init_wait_q_woken = false; @@ -1116,8 +1115,7 @@ err_init_fw: pr_debug("info: %s: unregister device\n", __func__); if (adapter->if_ops.unregister_dev) adapter->if_ops.unregister_dev(adapter); - if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || - (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { + if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) { pr_debug("info: %s: shutdown mwifiex\n", __func__); adapter->init_wait_q_woken = false; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index dd55bc16aeab..f9279399226a 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -165,7 +165,6 @@ struct mwifiex_dbg { enum MWIFIEX_HARDWARE_STATUS { MWIFIEX_HW_STATUS_READY, MWIFIEX_HW_STATUS_INITIALIZING, - MWIFIEX_HW_STATUS_FW_READY, MWIFIEX_HW_STATUS_INIT_DONE, MWIFIEX_HW_STATUS_RESET, MWIFIEX_HW_STATUS_CLOSING, -- cgit v1.2.1 From 9d2e85e001c15789798a1550cce5e7cc3ffe4e9b Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Wed, 31 Dec 2014 02:36:39 -0800 Subject: mwifiex: Adjust calling place of mwifiex_terminate_workqueue Workqueue needs to be flushed early when removing card, otherwise soft lockup issue may happen because main_process is triggered by interrupt while card is being removed. Signed-off-by: Marc Yang Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 2568395f0276..2d4047f4be17 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -1166,6 +1166,8 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) adapter->surprise_removed = true; + mwifiex_terminate_workqueue(adapter); + /* Stop data */ for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; @@ -1208,8 +1210,6 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); - mwifiex_terminate_workqueue(adapter); - /* Unregister device */ dev_dbg(adapter->dev, "info: unregister device\n"); if (adapter->if_ops.unregister_dev) -- cgit v1.2.1 From b4f1b177be27103cd84a3692ae71bf857700e27f Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Wed, 31 Dec 2014 02:36:40 -0800 Subject: mwifiex: increase delay during card reset 200ms is the requirement to allow VDD1.1 and VDD1.8 to drop to have proper reset. Signed-off-by: Cathy Luo Signed-off-by: Marc Yang Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 274a1b2b0365..4e8aedd5c9f3 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1958,8 +1958,8 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) pr_err("Resetting card...\n"); mmc_remove_host(target); - /* 20ms delay is based on experiment with sdhci controller */ - mdelay(20); + /* 200ms delay is based on experiment with sdhci controller */ + mdelay(200); target->rescan_entered = 0; /* rescan non-removable cards */ mmc_add_host(target); } -- cgit v1.2.1 From 4636187da60b6e33526050235c610409d9cc00e8 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 31 Dec 2014 02:36:41 -0800 Subject: mwifiex: add wakeup timer based recovery mechanism If host fails to wakeup the firmware, we will trigger card reset after 3 second timeout. Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/init.c | 16 ++++++++++++++++ drivers/net/wireless/mwifiex/main.c | 2 ++ drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/pcie.c | 1 + drivers/net/wireless/mwifiex/sta_event.c | 3 +++ drivers/net/wireless/mwifiex/usb.c | 1 + 6 files changed, 24 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index a3dd601a495a..524692a59d4a 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -52,6 +52,18 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) return 0; } +static void wakeup_timer_fn(unsigned long data) +{ + struct mwifiex_adapter *adapter = (struct mwifiex_adapter *)data; + + dev_err(adapter->dev, "Firmware wakeup failed\n"); + adapter->hw_status = MWIFIEX_HW_STATUS_RESET; + mwifiex_cancel_all_pending_cmd(adapter); + + if (adapter->if_ops.card_reset) + adapter->if_ops.card_reset(adapter); +} + /* * This function initializes the private structure and sets default * values to the members. @@ -285,6 +297,9 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->ext_scan = true; adapter->key_api_major_ver = 0; adapter->key_api_minor_ver = 0; + + setup_timer(&adapter->wakeup_timer, wakeup_timer_fn, + (unsigned long)adapter); } /* @@ -391,6 +406,7 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) return; } + del_timer(&adapter->wakeup_timer); mwifiex_cancel_all_pending_cmd(adapter); /* Free lock variables */ diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 2d4047f4be17..119e87574e83 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -237,6 +237,7 @@ process_start: (is_command_pending(adapter) || !mwifiex_wmm_lists_empty(adapter))) { adapter->pm_wakeup_fw_try = true; + mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3)); adapter->if_ops.wakeup(adapter); continue; } @@ -244,6 +245,7 @@ process_start: if (IS_CARD_RX_RCVD(adapter)) { adapter->data_received = false; adapter->pm_wakeup_fw_try = false; + del_timer_sync(&adapter->wakeup_timer); if (adapter->ps_state == PS_STATE_SLEEP) adapter->ps_state = PS_STATE_AWAKE; } else { diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index f9279399226a..55273eefb785 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -830,6 +830,7 @@ struct mwifiex_adapter { u16 gen_null_pkt; u16 pps_uapsd_mode; u32 pm_wakeup_fw_try; + struct timer_list wakeup_timer; u8 is_hs_configured; struct mwifiex_hs_config_param hs_cfg; u8 hs_activated; diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index c3a20f94f3c9..10e4a93d3d56 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -2064,6 +2064,7 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) * state until cookie is set */ adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_fw_try = false; + del_timer(&adapter->wakeup_timer); } } } diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index fbec95bbc10f..419e35f1dbf3 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -312,6 +312,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; + mod_timer(&adapter->wakeup_timer, + jiffies + (HZ*3)); break; } if (!mwifiex_send_null_packet @@ -326,6 +328,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; + del_timer_sync(&adapter->wakeup_timer); break; diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 8ae7a8586811..199b43f89e01 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -990,6 +990,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) { /* Simulation of HS_AWAKE event */ adapter->pm_wakeup_fw_try = false; + del_timer_sync(&adapter->wakeup_timer); adapter->pm_wakeup_card_req = false; adapter->ps_state = PS_STATE_AWAKE; -- cgit v1.2.1 From fc647467c178936aad29a1e5332c05a23d6efb39 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 31 Dec 2014 02:36:42 -0800 Subject: mwifiex: wakeup pending wait queues Wakeup pending wait queues in unload path. This will help to avoid soft lockup issues in corner cases. Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/init.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 524692a59d4a..b115e0f94dd7 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -408,6 +408,8 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) del_timer(&adapter->wakeup_timer); mwifiex_cancel_all_pending_cmd(adapter); + wake_up_interruptible(&adapter->cmd_wait_q.wait); + wake_up_interruptible(&adapter->hs_activate_wait_q); /* Free lock variables */ mwifiex_free_lock_list(adapter); -- cgit v1.2.1 From b420166fa87a281a5476716982655009fd11e724 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 31 Dec 2014 02:36:43 -0800 Subject: mwifiex: do not release lock during list_for_each_entry_safe() As we are releasing the lock, during next iteration we may end up getting page fault if other thread has already deleted that node. Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 85597200badc..946a2f7a172f 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1008,11 +1008,9 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) list_for_each_entry_safe(cmd_node, tmp_node, &adapter->scan_pending_q, list) { list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); cmd_node->wait_q_enabled = false; mwifiex_insert_cmd_to_free_q(adapter, cmd_node); - spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); } spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); @@ -1070,12 +1068,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) list_for_each_entry_safe(cmd_node, tmp_node, &adapter->scan_pending_q, list) { list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - scan_pending_q_flags); cmd_node->wait_q_enabled = false; mwifiex_insert_cmd_to_free_q(adapter, cmd_node); - spin_lock_irqsave(&adapter->scan_pending_q_lock, - scan_pending_q_flags); } spin_unlock_irqrestore(&adapter->scan_pending_q_lock, scan_pending_q_flags); -- cgit v1.2.1 From ca5b20e6b4dfb1561cda8ef82dbe555aa26a036e Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 31 Dec 2014 02:36:44 -0800 Subject: mwifiex: Increase priority of firmware download message When driver is loaded, it is important to know if FW was already active or it is freshly downloaded. This patch increases the priority of these messages. Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/pcie.c | 4 ++-- drivers/net/wireless/mwifiex/sdio.c | 4 ++-- drivers/net/wireless/mwifiex/usb.c | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 10e4a93d3d56..a460b0e6a151 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1952,8 +1952,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, offset += txlen; } while (true); - dev_dbg(adapter->dev, "info:\nFW download over, size %d bytes\n", - offset); + dev_notice(adapter->dev, + "info: FW download over, size %d bytes\n", offset); ret = 0; diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 4e8aedd5c9f3..a70f103359ea 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -986,8 +986,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, offset += txlen; } while (true); - dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", - offset); + dev_notice(adapter->dev, + "info: FW download over, size %d bytes\n", offset); ret = 0; done: diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 199b43f89e01..6c62995028e6 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -930,7 +930,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, } while ((dnld_cmd != FW_HAS_LAST_BLOCK) && retries); cleanup: - dev_dbg(adapter->dev, "%s: %d bytes downloaded\n", __func__, tlen); + dev_notice(adapter->dev, + "info: FW download over, size %d bytes\n", tlen); kfree(recv_buff); kfree(fwdata); -- cgit v1.2.1 From 468133c54f4e5e194cb4bfd4e3bf640ae2304e97 Mon Sep 17 00:00:00 2001 From: Maithili Hinge Date: Wed, 31 Dec 2014 02:36:45 -0800 Subject: mwifiex: Move code for wowlan magic-packet and patterns to a function This patch moves code for wowlan magic-packet and patterns to a function mwifiex_set_mef_filter. Signed-off-by: Maithili Hinge Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 78 ++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index f8b1ce0a0fd6..2be2dc5f76bb 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2425,30 +2425,16 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, } #ifdef CONFIG_PM -static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, - struct cfg80211_wowlan *wowlan) +static int mwifiex_set_mef_filter(struct mwifiex_private *priv, + struct cfg80211_wowlan *wowlan) { - struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); - struct mwifiex_ds_mef_cfg mef_cfg; - struct mwifiex_mef_entry *mef_entry; - int i, filt_num = 0, ret; + int i, filt_num = 0, ret = 0; bool first_pat = true; u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1]; const u8 ipv4_mc_mac[] = {0x33, 0x33}; const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; - struct mwifiex_private *priv = - mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); - - if (!wowlan) { - dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n"); - return 0; - } - - if (!priv->media_connected) { - dev_warn(adapter->dev, - "Can not configure WOWLAN in disconnected state\n"); - return 0; - } + struct mwifiex_ds_mef_cfg mef_cfg; + struct mwifiex_mef_entry *mef_entry; mef_entry = kzalloc(sizeof(*mef_entry), GFP_KERNEL); if (!mef_entry) @@ -2463,9 +2449,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, for (i = 0; i < wowlan->n_patterns; i++) { memset(byte_seq, 0, sizeof(byte_seq)); if (!mwifiex_is_pattern_supported(&wowlan->patterns[i], - byte_seq, - MWIFIEX_MEF_MAX_BYTESEQ)) { - wiphy_err(wiphy, "Pattern not supported\n"); + byte_seq, + MWIFIEX_MEF_MAX_BYTESEQ)) { + dev_err(priv->adapter->dev, "Pattern not supported\n"); kfree(mef_entry); return -EOPNOTSUPP; } @@ -2489,9 +2475,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, mef_entry->filter[filt_num].repeat = 1; mef_entry->filter[filt_num].offset = - wowlan->patterns[i].pkt_offset; + wowlan->patterns[i].pkt_offset; memcpy(mef_entry->filter[filt_num].byte_seq, byte_seq, - sizeof(byte_seq)); + sizeof(byte_seq)); mef_entry->filter[filt_num].filt_type = TYPE_EQ; if (first_pat) @@ -2506,9 +2492,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; mef_entry->filter[filt_num].repeat = 16; memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, - ETH_ALEN); + ETH_ALEN); mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = - ETH_ALEN; + ETH_ALEN; mef_entry->filter[filt_num].offset = 28; mef_entry->filter[filt_num].filt_type = TYPE_EQ; if (filt_num) @@ -2517,9 +2503,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, filt_num++; mef_entry->filter[filt_num].repeat = 16; memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, - ETH_ALEN); + ETH_ALEN); mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = - ETH_ALEN; + ETH_ALEN; mef_entry->filter[filt_num].offset = 56; mef_entry->filter[filt_num].filt_type = TYPE_EQ; mef_entry->filter[filt_num].filt_action = TYPE_OR; @@ -2527,16 +2513,46 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, if (!mef_cfg.criteria) mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | - MWIFIEX_CRITERIA_UNICAST | - MWIFIEX_CRITERIA_MULTICAST; + MWIFIEX_CRITERIA_UNICAST | + MWIFIEX_CRITERIA_MULTICAST; ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, - HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); + HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); kfree(mef_entry); return ret; } +static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wowlan) +{ + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + int ret = 0; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + + if (!wowlan) { + dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n"); + return 0; + } + + if (!priv->media_connected) { + dev_warn(adapter->dev, + "Can not configure WOWLAN in disconnected state\n"); + return 0; + } + + if (wowlan->n_patterns || wowlan->magic_pkt) { + ret = mwifiex_set_mef_filter(priv, wowlan); + if (ret) { + dev_err(adapter->dev, "Failed to set MEF filter\n"); + return ret; + } + } + + return ret; +} + static int mwifiex_cfg80211_resume(struct wiphy *wiphy) { return 0; -- cgit v1.2.1 From 8a40084e7bb8f0fd32a301a64fd869726516a1df Mon Sep 17 00:00:00 2001 From: Maithili Hinge Date: Wed, 31 Dec 2014 02:36:46 -0800 Subject: mwifiex: Add support for wowlan disconnect This patch adds support for wowlan disconnect. Signed-off-by: Maithili Hinge Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 2be2dc5f76bb..93ab36fc9f93 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2527,6 +2527,7 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wowlan) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_ds_hs_cfg hs_cfg; int ret = 0; struct mwifiex_private *priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); @@ -2550,6 +2551,20 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, } } + if (wowlan->disconnect) { + memset(&hs_cfg, 0, sizeof(hs_cfg)); + hs_cfg.is_invoke_hostcmd = false; + hs_cfg.conditions = HS_CFG_COND_MAC_EVENT; + hs_cfg.gpio = HS_CFG_GPIO_DEF; + hs_cfg.gap = HS_CFG_GAP_DEF; + ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, + MWIFIEX_SYNC_CMD, &hs_cfg); + if (ret) { + dev_err(adapter->dev, "Failed to set HS params\n"); + return ret; + } + } + return ret; } @@ -2890,7 +2905,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { #ifdef CONFIG_PM static const struct wiphy_wowlan_support mwifiex_wowlan_support = { - .flags = WIPHY_WOWLAN_MAGIC_PKT, + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, .n_patterns = MWIFIEX_MEF_MAX_FILTERS, .pattern_min_len = 1, .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN, -- cgit v1.2.1 From 1fcf77c87ad659a92e1dcfb883388cb43baeaab6 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Sun, 4 Jan 2015 17:36:02 +0800 Subject: net/fsl: Add mEMAC MDIO support to XGMAC MDIO The Freescale mEMAC supports operating at 10/100/1000/10G, and its associated MDIO controller is likewise capable of operating both Clause 22 and Clause 45 MDIO buses. It is nearly identical to the MDIO controller on the XGMAC, so we just modify that driver. Portions of this driver developed by: Sandeep Singh Roy Zang Signed-off-by: Andy Fleming Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/Kconfig | 3 +- drivers/net/ethernet/freescale/xgmac_mdio.c | 64 ++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index 270308315d43..ba84c4a9ce32 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -69,7 +69,8 @@ config FSL_XGMAC_MDIO select PHYLIB select OF_MDIO ---help--- - This driver supports the MDIO bus on the Fman 10G Ethernet MACs. + This driver supports the MDIO bus on the Fman 10G Ethernet MACs, and + on the FMan mEMAC (which supports both Clauses 22 and 45) config UCC_GETH tristate "Freescale QE Gigabit Ethernet" diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index a35244586a63..e0fc3d1115ea 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -32,6 +32,7 @@ struct tgec_mdio_controller { __be32 mdio_addr; /* MDIO address */ } __packed; +#define MDIO_STAT_ENC BIT(6) #define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8) #define MDIO_STAT_BSY (1 << 0) #define MDIO_STAT_RD_ER (1 << 1) @@ -91,20 +92,40 @@ static int xgmac_wait_until_done(struct device *dev, static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) { struct tgec_mdio_controller __iomem *regs = bus->priv; - uint16_t dev_addr = regnum >> 16; + uint16_t dev_addr; + u32 mdio_ctl, mdio_stat; int ret; - /* Set the port and dev addr */ - out_be32(®s->mdio_ctl, - MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr)); + mdio_stat = in_be32(®s->mdio_stat); + if (regnum & MII_ADDR_C45) { + /* Clause 45 (ie 10G) */ + dev_addr = (regnum >> 16) & 0x1f; + mdio_stat |= MDIO_STAT_ENC; + } else { + /* Clause 22 (ie 1G) */ + dev_addr = regnum & 0x1f; + mdio_stat &= ~MDIO_STAT_ENC; + } - /* Set the register address */ - out_be32(®s->mdio_addr, regnum & 0xffff); + out_be32(®s->mdio_stat, mdio_stat); ret = xgmac_wait_until_free(&bus->dev, regs); if (ret) return ret; + /* Set the port and dev addr */ + mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); + out_be32(®s->mdio_ctl, mdio_ctl); + + /* Set the register address */ + if (regnum & MII_ADDR_C45) { + out_be32(®s->mdio_addr, regnum & 0xffff); + + ret = xgmac_wait_until_free(&bus->dev, regs); + if (ret) + return ret; + } + /* Write the value to the register */ out_be32(®s->mdio_data, MDIO_DATA(value)); @@ -123,21 +144,39 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 val static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) { struct tgec_mdio_controller __iomem *regs = bus->priv; - uint16_t dev_addr = regnum >> 16; + uint16_t dev_addr; + uint32_t mdio_stat; uint32_t mdio_ctl; uint16_t value; int ret; + mdio_stat = in_be32(®s->mdio_stat); + if (regnum & MII_ADDR_C45) { + dev_addr = (regnum >> 16) & 0x1f; + mdio_stat |= MDIO_STAT_ENC; + } else { + dev_addr = regnum & 0x1f; + mdio_stat = ~MDIO_STAT_ENC; + } + + out_be32(®s->mdio_stat, mdio_stat); + + ret = xgmac_wait_until_free(&bus->dev, regs); + if (ret) + return ret; + /* Set the Port and Device Addrs */ mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); out_be32(®s->mdio_ctl, mdio_ctl); /* Set the register address */ - out_be32(®s->mdio_addr, regnum & 0xffff); + if (regnum & MII_ADDR_C45) { + out_be32(®s->mdio_addr, regnum & 0xffff); - ret = xgmac_wait_until_free(&bus->dev, regs); - if (ret) - return ret; + ret = xgmac_wait_until_free(&bus->dev, regs); + if (ret) + return ret; + } /* Initiate the read */ out_be32(®s->mdio_ctl, mdio_ctl | MDIO_CTL_READ); @@ -224,6 +263,9 @@ static struct of_device_id xgmac_mdio_match[] = { { .compatible = "fsl,fman-xmdio", }, + { + .compatible = "fsl,fman-memac-mdio", + }, {}, }; MODULE_DEVICE_TABLE(of, xgmac_mdio_match); -- cgit v1.2.1 From de7b5b3d790a2524c3f992d357983600635c441b Mon Sep 17 00:00:00 2001 From: Feng Kan Date: Tue, 6 Jan 2015 15:41:33 -0700 Subject: net: eth: xgene: change APM X-Gene SoC platform ethernet to support ACPI This adds support for APM X-Gene ethernet driver to use ACPI table to derive ethernet driver parameter. Signed-off-by: Feng Kan Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 94 +++++++++++++++++------ drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 97 +++++++++++++++++++----- drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 3 + 3 files changed, 150 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 7ba83ffb08ac..869d97fcf781 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -593,10 +593,12 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata) if (!xgene_ring_mgr_init(pdata)) return -ENODEV; - clk_prepare_enable(pdata->clk); - clk_disable_unprepare(pdata->clk); - clk_prepare_enable(pdata->clk); - xgene_enet_ecc_init(pdata); + if (!efi_enabled(EFI_BOOT)) { + clk_prepare_enable(pdata->clk); + clk_disable_unprepare(pdata->clk); + clk_prepare_enable(pdata->clk); + xgene_enet_ecc_init(pdata); + } xgene_enet_config_ring_if_assoc(pdata); /* Enable auto-incr for scanning */ @@ -663,15 +665,20 @@ static int xgene_enet_phy_connect(struct net_device *ndev) struct phy_device *phy_dev; struct device *dev = &pdata->pdev->dev; - phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); - if (!phy_np) { - netdev_dbg(ndev, "No phy-handle found\n"); - return -ENODEV; + if (dev->of_node) { + phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); + if (!phy_np) { + netdev_dbg(ndev, "No phy-handle found in DT\n"); + return -ENODEV; + } + pdata->phy_dev = of_phy_find_device(phy_np); } - phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, - 0, pdata->phy_mode); - if (!phy_dev) { + phy_dev = pdata->phy_dev; + + if (!phy_dev || + phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link, + pdata->phy_mode)) { netdev_err(ndev, "Could not connect to PHY\n"); return -ENODEV; } @@ -681,32 +688,71 @@ static int xgene_enet_phy_connect(struct net_device *ndev) ~SUPPORTED_100baseT_Half & ~SUPPORTED_1000baseT_Half; phy_dev->advertising = phy_dev->supported; - pdata->phy_dev = phy_dev; return 0; } -int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) +static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, + struct mii_bus *mdio) { - struct net_device *ndev = pdata->ndev; struct device *dev = &pdata->pdev->dev; + struct net_device *ndev = pdata->ndev; + struct phy_device *phy; struct device_node *child_np; struct device_node *mdio_np = NULL; - struct mii_bus *mdio_bus; int ret; + u32 phy_id; + + if (dev->of_node) { + for_each_child_of_node(dev->of_node, child_np) { + if (of_device_is_compatible(child_np, + "apm,xgene-mdio")) { + mdio_np = child_np; + break; + } + } - for_each_child_of_node(dev->of_node, child_np) { - if (of_device_is_compatible(child_np, "apm,xgene-mdio")) { - mdio_np = child_np; - break; + if (!mdio_np) { + netdev_dbg(ndev, "No mdio node in the dts\n"); + return -ENXIO; } - } - if (!mdio_np) { - netdev_dbg(ndev, "No mdio node in the dts\n"); - return -ENXIO; + return of_mdiobus_register(mdio, mdio_np); } + /* Mask out all PHYs from auto probing. */ + mdio->phy_mask = ~0; + + /* Register the MDIO bus */ + ret = mdiobus_register(mdio); + if (ret) + return ret; + + ret = device_property_read_u32(dev, "phy-channel", &phy_id); + if (ret) + ret = device_property_read_u32(dev, "phy-addr", &phy_id); + if (ret) + return -EINVAL; + + phy = get_phy_device(mdio, phy_id, true); + if (!phy || IS_ERR(phy)) + return -EIO; + + ret = phy_device_register(phy); + if (ret) + phy_device_free(phy); + else + pdata->phy_dev = phy; + + return ret; +} + +int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) +{ + struct net_device *ndev = pdata->ndev; + struct mii_bus *mdio_bus; + int ret; + mdio_bus = mdiobus_alloc(); if (!mdio_bus) return -ENOMEM; @@ -720,7 +766,7 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) mdio_bus->priv = pdata; mdio_bus->parent = &ndev->dev; - ret = of_mdiobus_register(mdio_bus, mdio_np); + ret = xgene_mdiobus_register(pdata, mdio_bus); if (ret) { netdev_err(ndev, "Failed to register MDIO bus\n"); mdiobus_free(mdio_bus); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 83a50280bb70..1e56bf30366f 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -24,6 +24,10 @@ #include "xgene_enet_sgmac.h" #include "xgene_enet_xgmac.h" +#define RES_ENET_CSR 0 +#define RES_RING_CSR 1 +#define RES_RING_CMD 2 + static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) { struct xgene_enet_raw_desc16 *raw_desc; @@ -746,6 +750,41 @@ static const struct net_device_ops xgene_ndev_ops = { .ndo_set_mac_address = xgene_enet_set_mac_address, }; +static int xgene_get_mac_address(struct device *dev, + unsigned char *addr) +{ + int ret; + + ret = device_property_read_u8_array(dev, "local-mac-address", addr, 6); + if (ret) + ret = device_property_read_u8_array(dev, "mac-address", + addr, 6); + if (ret) + return -ENODEV; + + return ETH_ALEN; +} + +static int xgene_get_phy_mode(struct device *dev) +{ + int i, ret; + char *modestr; + + ret = device_property_read_string(dev, "phy-connection-type", + (const char **)&modestr); + if (ret) + ret = device_property_read_string(dev, "phy-mode", + (const char **)&modestr); + if (ret) + return -ENODEV; + + for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) { + if (!strcasecmp(modestr, phy_modes(i))) + return i; + } + return -ENODEV; +} + static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) { struct platform_device *pdev; @@ -753,29 +792,42 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) struct device *dev; struct resource *res; void __iomem *base_addr; - const char *mac; int ret; pdev = pdata->pdev; dev = &pdev->dev; ndev = pdata->ndev; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr"); - pdata->base_addr = devm_ioremap_resource(dev, res); + res = platform_get_resource(pdev, IORESOURCE_MEM, RES_ENET_CSR); + if (!res) { + dev_err(dev, "Resource enet_csr not defined\n"); + return -ENODEV; + } + pdata->base_addr = devm_ioremap(dev, res->start, resource_size(res)); if (IS_ERR(pdata->base_addr)) { dev_err(dev, "Unable to retrieve ENET Port CSR region\n"); return PTR_ERR(pdata->base_addr); } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr"); - pdata->ring_csr_addr = devm_ioremap_resource(dev, res); + res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CSR); + if (!res) { + dev_err(dev, "Resource ring_csr not defined\n"); + return -ENODEV; + } + pdata->ring_csr_addr = devm_ioremap(dev, res->start, + resource_size(res)); if (IS_ERR(pdata->ring_csr_addr)) { dev_err(dev, "Unable to retrieve ENET Ring CSR region\n"); return PTR_ERR(pdata->ring_csr_addr); } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd"); - pdata->ring_cmd_addr = devm_ioremap_resource(dev, res); + res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CMD); + if (!res) { + dev_err(dev, "Resource ring_cmd not defined\n"); + return -ENODEV; + } + pdata->ring_cmd_addr = devm_ioremap(dev, res->start, + resource_size(res)); if (IS_ERR(pdata->ring_cmd_addr)) { dev_err(dev, "Unable to retrieve ENET Ring command region\n"); return PTR_ERR(pdata->ring_cmd_addr); @@ -789,14 +841,12 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) } pdata->rx_irq = ret; - mac = of_get_mac_address(dev->of_node); - if (mac) - memcpy(ndev->dev_addr, mac, ndev->addr_len); - else + if (xgene_get_mac_address(dev, ndev->dev_addr) != ETH_ALEN) eth_hw_addr_random(ndev); + memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); - pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); + pdata->phy_mode = xgene_get_phy_mode(dev); if (pdata->phy_mode < 0) { dev_err(dev, "Unable to get phy-connection-type\n"); return pdata->phy_mode; @@ -809,11 +859,9 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) } pdata->clk = devm_clk_get(&pdev->dev, NULL); - ret = IS_ERR(pdata->clk); if (IS_ERR(pdata->clk)) { - dev_err(&pdev->dev, "can't get clock\n"); - ret = PTR_ERR(pdata->clk); - return ret; + /* Firmware may have set up the clock already. */ + pdata->clk = NULL; } base_addr = pdata->base_addr; @@ -924,7 +972,7 @@ static int xgene_enet_probe(struct platform_device *pdev) goto err; } - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (ret) { netdev_err(ndev, "No usable DMA configuration\n"); goto err; @@ -972,17 +1020,26 @@ static int xgene_enet_remove(struct platform_device *pdev) return 0; } -static struct of_device_id xgene_enet_match[] = { +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_enet_acpi_match[] = { + { "APMC0D05", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match); +#endif + +static struct of_device_id xgene_enet_of_match[] = { {.compatible = "apm,xgene-enet",}, {}, }; -MODULE_DEVICE_TABLE(of, xgene_enet_match); +MODULE_DEVICE_TABLE(of, xgene_enet_of_match); static struct platform_driver xgene_enet_driver = { .driver = { .name = "xgene-enet", - .of_match_table = xgene_enet_match, + .of_match_table = of_match_ptr(xgene_enet_of_match), + .acpi_match_table = ACPI_PTR(xgene_enet_acpi_match), }, .probe = xgene_enet_probe, .remove = xgene_enet_remove, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index f9958fae6ffd..c2d465c3db66 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -22,7 +22,10 @@ #ifndef __XGENE_ENET_MAIN_H__ #define __XGENE_ENET_MAIN_H__ +#include #include +#include +#include #include #include #include -- cgit v1.2.1 From c20e7789be9f64ed6000e3d985bc7203781a671c Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Wed, 24 Dec 2014 23:08:44 +0800 Subject: wil6210: use 'uint64_t' instead of 'cycles_t' to avoid warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit do_div() checks the type strictly. 'cycles_t' may be 32-bit under quite a few architectures (parisc, arm, avr32 ...). So use 'uint64_t' instead of, the related warning (with allmodconfig under parisc): CC [M] drivers/net/wireless/ath/wil6210/debugfs.o In file included from arch/parisc/include/generated/asm/div64.h:1:0, from include/linux/kernel.h:124, from include/linux/list.h:8, from include/linux/module.h:9, from drivers/net/wireless/ath/wil6210/debugfs.c:17: drivers/net/wireless/ath/wil6210/debugfs.c: In function ‘wil_vring_debugfs_show’: include/asm-generic/div64.h:43:28: warning: comparison of distinct pointer types lacks a cast (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ ^ drivers/net/wireless/ath/wil6210/debugfs.c:107:4: note: in expansion of macro ‘do_div’ do_div(idle, total); ^ In file included from include/uapi/linux/stddef.h:1:0, from include/linux/stddef.h:4, from ./include/uapi/linux/posix_types.h:4, from include/uapi/linux/types.h:13, from include/linux/types.h:5, from include/linux/list.h:4, from include/linux/module.h:9, from drivers/net/wireless/ath/wil6210/debugfs.c:17: include/asm-generic/div64.h:44:18: warning: right shift count >= width of type [-Wshift-count-overflow] if (likely(((n) >> 32) == 0)) { \ ^ include/linux/compiler.h:159:40: note: in definition of macro ‘likely’ # define likely(x) __builtin_expect(!!(x), 1) ^ drivers/net/wireless/ath/wil6210/debugfs.c:107:4: note: in expansion of macro ‘do_div’ do_div(idle, total); ^ In file included from arch/parisc/include/generated/asm/div64.h:1:0, from include/linux/kernel.h:124, from include/linux/list.h:8, from include/linux/module.h:9, from drivers/net/wireless/ath/wil6210/debugfs.c:17: include/asm-generic/div64.h:48:22: warning: passing argument 1 of ‘__div64_32’ from incompatible pointer type [-Wincompatible-pointer-types] __rem = __div64_32(&(n), __base); \ ^ drivers/net/wireless/ath/wil6210/debugfs.c:107:4: note: in expansion of macro ‘do_div’ do_div(idle, total); ^ include/asm-generic/div64.h:35:17: note: expected ‘uint64_t * {aka long long unsigned int *}’ but argument is of type ‘cycles_t * {aka long unsigned int *}’ extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); ^ Signed-off-by: Chen Gang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 4e6e14501c2f..cd991fa1cc3f 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -101,8 +101,8 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) char name[10]; /* performance monitoring */ cycles_t now = get_cycles(); - cycles_t idle = txdata->idle * 100; - cycles_t total = now - txdata->begin; + uint64_t idle = txdata->idle * 100; + uint64_t total = now - txdata->begin; do_div(idle, total); txdata->begin = now; -- cgit v1.2.1 From b9d305cc47407f6a615145ff69e89060e7def6c7 Mon Sep 17 00:00:00 2001 From: Fred Chou Date: Fri, 26 Dec 2014 16:19:18 +0800 Subject: rt2x00: use helper to check capability/requirement Use rt2x00_has_cap_flag macro to check rt2x00dev->cap_flags. Signed-off-by: Fred Chou Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/rt2x00/rt2x00config.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00dev.c | 18 +++++++++--------- drivers/net/wireless/rt2x00/rt2x00firmware.c | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 18 +++++++++--------- drivers/net/wireless/rt2x00/rt2x00usb.c | 8 ++++---- 6 files changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 1122dc44c9fd..48a2cad29477 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -240,7 +240,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, rt2x00dev->rf_channel = libconf.rf.channel; } - if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_PS_AUTOWAKE) && (ieee80211_flags & IEEE80211_CONF_CHANGE_PS)) cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); @@ -257,7 +257,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, rt2x00link_reset_tuner(rt2x00dev, false); if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && - test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + rt2x00_has_cap_flag(rt2x00dev, REQUIRE_PS_AUTOWAKE) && (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && (conf->flags & IEEE80211_CONF_PS)) { beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9967a1d9f0ec..5639ed816813 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -351,7 +351,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * Remove L2 padding which was added during */ - if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_L2PAD)) rt2x00queue_remove_l2pad(entry->skb, header_length); /* @@ -460,7 +460,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * send the status report back. */ if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) { - if (test_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TASKLET_CONTEXT)) ieee80211_tx_status(rt2x00dev->hw, entry->skb); else ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb); @@ -1056,9 +1056,9 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Take TX headroom required for alignment into account. */ - if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_L2PAD)) rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE; - else if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) + else if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA)) rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE; /* @@ -1069,7 +1069,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Allocate tx status FIFO for driver use. */ - if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) { + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TXSTATUS_FIFO)) { /* * Allocate the txstatus fifo. In the worst case the tx * status fifo has to hold the tx status of all entries @@ -1131,7 +1131,7 @@ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) /* * Stop rfkill polling. */ - if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL)) rt2x00rfkill_unregister(rt2x00dev); /* @@ -1173,7 +1173,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) /* * Start rfkill polling. */ - if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL)) rt2x00rfkill_register(rt2x00dev); return 0; @@ -1389,7 +1389,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) /* * Start rfkill polling. */ - if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags)) + if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL)) rt2x00rfkill_register(rt2x00dev); return 0; @@ -1408,7 +1408,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) /* * Stop rfkill polling. */ - if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags)) + if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL)) rt2x00rfkill_unregister(rt2x00dev); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index fbae2799e3ee..5813300f68a2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -96,7 +96,7 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) { int retval; - if (!test_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags)) + if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_FIRMWARE)) return 0; if (!rt2x00dev->fw) { diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index cb40245a0695..300876df056f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -119,7 +119,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, * Use the ATIM queue if appropriate and present. */ if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && - test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) + rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE)) qid = QID_ATIM; queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 66ff36447b94..68b620b2462f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -85,7 +85,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp) memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; - if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) { + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA)) { dma_addr_t skb_dma; skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, @@ -198,7 +198,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev, __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); - if (!test_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags)) { + if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_SW_SEQNO)) { /* * rt2800 has a H/W (or F/W) bug, device incorrectly increase * seqno on retransmited data (non-QOS) frames. To workaround @@ -484,7 +484,7 @@ static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, rt2x00crypto_create_tx_descriptor(rt2x00dev, skb, txdesc); rt2x00queue_create_tx_descriptor_seq(rt2x00dev, skb, txdesc); - if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_HT_TX_DESC)) rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc, sta, hwrate); else @@ -526,7 +526,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry, /* * Map the skb to DMA. */ - if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags) && + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA) && rt2x00queue_map_txskb(entry)) return -ENOMEM; @@ -646,7 +646,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { - if (test_bit(REQUIRE_COPY_IV, &queue->rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_COPY_IV)) rt2x00crypto_tx_copy_iv(skb, &txdesc); else rt2x00crypto_tx_remove_iv(skb, &txdesc); @@ -660,9 +660,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, * PCI and USB devices, while header alignment only is valid * for PCI devices. */ - if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_L2PAD)) rt2x00queue_insert_l2pad(skb, txdesc.header_length); - else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags)) + else if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_DMA)) rt2x00queue_align_frame(skb); /* @@ -1178,7 +1178,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev) if (status) goto exit; - if (test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) { + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE)) { status = rt2x00queue_alloc_entries(rt2x00dev->atim); if (status) goto exit; @@ -1234,7 +1234,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; enum data_queue_qid qid; unsigned int req_atim = - !!test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); + rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE); /* * We need the following queues: diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 892270dd3e7b..7627af6098eb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -274,7 +274,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * Schedule the delayed work for reading the TX status * from the device. */ - if (!test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags) || + if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TXSTATUS_FIFO) || !kfifo_is_empty(&rt2x00dev->txstatus_fifo)) queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } @@ -456,7 +456,7 @@ static bool rt2x00usb_flush_entry(struct queue_entry *entry, void *data) * Kill guardian urb (if required by driver). */ if ((entry->queue->qid == QID_BEACON) && - (test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))) + (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD))) usb_kill_urb(bcn_priv->guardian_urb); return false; @@ -655,7 +655,7 @@ static int rt2x00usb_alloc_entries(struct data_queue *queue) * then we are done. */ if (queue->qid != QID_BEACON || - !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)) + !rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD)) return 0; for (i = 0; i < queue->limit; i++) { @@ -690,7 +690,7 @@ static void rt2x00usb_free_entries(struct data_queue *queue) * then we are done. */ if (queue->qid != QID_BEACON || - !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)) + !rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD)) return; for (i = 0; i < queue->limit; i++) { -- cgit v1.2.1 From 983988ec0a2499a5d31fdc96a1d2d7af2b3609a6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:37 +0100 Subject: wireless: cw1200: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.data = d; -t.function = f; // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/cw1200/pm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/cw1200/pm.c b/drivers/net/wireless/cw1200/pm.c index 6907c8fd4578..d2202ae92bdd 100644 --- a/drivers/net/wireless/cw1200/pm.c +++ b/drivers/net/wireless/cw1200/pm.c @@ -101,9 +101,8 @@ int cw1200_pm_init(struct cw1200_pm_state *pm, { spin_lock_init(&pm->lock); - init_timer(&pm->stay_awake); - pm->stay_awake.data = (unsigned long)pm; - pm->stay_awake.function = cw1200_pm_stay_awake_tmo; + setup_timer(&pm->stay_awake, cw1200_pm_stay_awake_tmo, + (unsigned long)pm); return 0; } -- cgit v1.2.1 From dabefea6937dc0015624a43ec1b8764f5b3dcb68 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:38 +0100 Subject: cw1200: main: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.data = d; -t.function = f; // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/cw1200/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c index 3e78cc3ccb78..fa965ee9f56b 100644 --- a/drivers/net/wireless/cw1200/main.c +++ b/drivers/net/wireless/cw1200/main.c @@ -374,9 +374,8 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work); INIT_WORK(&priv->set_beacon_wakeup_period_work, cw1200_set_beacon_wakeup_period_work); - init_timer(&priv->mcast_timeout); - priv->mcast_timeout.data = (unsigned long)priv; - priv->mcast_timeout.function = cw1200_mcast_timeout; + setup_timer(&priv->mcast_timeout, cw1200_mcast_timeout, + (unsigned long)priv); if (cw1200_queue_stats_init(&priv->tx_queue_stats, CW1200_LINK_ID_MAX, -- cgit v1.2.1 From 0be01bf297215e36fbcbe07fc838792aa7c963e5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:39 +0100 Subject: cw1200: queue: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.data = d; -t.function = f; // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/cw1200/queue.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/cw1200/queue.c b/drivers/net/wireless/cw1200/queue.c index 9c3925f58d79..0ba5ef9b3e7b 100644 --- a/drivers/net/wireless/cw1200/queue.c +++ b/drivers/net/wireless/cw1200/queue.c @@ -179,9 +179,7 @@ int cw1200_queue_init(struct cw1200_queue *queue, INIT_LIST_HEAD(&queue->pending); INIT_LIST_HEAD(&queue->free_pool); spin_lock_init(&queue->lock); - init_timer(&queue->gc); - queue->gc.data = (unsigned long)queue; - queue->gc.function = cw1200_queue_gc; + setup_timer(&queue->gc, cw1200_queue_gc, (unsigned long)queue); queue->pool = kzalloc(sizeof(struct cw1200_queue_item) * capacity, GFP_KERNEL); -- cgit v1.2.1 From af68b87f721166a08f3cd3282a07e0cbce15ea80 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:48 +0100 Subject: iwl4965: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.data = d; -t.function = f; // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/iwlegacy/4965-mac.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 2748fde4b90c..976f65fe9c38 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -6247,13 +6247,10 @@ il4965_setup_deferred_work(struct il_priv *il) INIT_WORK(&il->txpower_work, il4965_bg_txpower_work); - init_timer(&il->stats_periodic); - il->stats_periodic.data = (unsigned long)il; - il->stats_periodic.function = il4965_bg_stats_periodic; + setup_timer(&il->stats_periodic, il4965_bg_stats_periodic, + (unsigned long)il); - init_timer(&il->watchdog); - il->watchdog.data = (unsigned long)il; - il->watchdog.function = il_bg_watchdog; + setup_timer(&il->watchdog, il_bg_watchdog, (unsigned long)il); tasklet_init(&il->irq_tasklet, (void (*)(unsigned long))il4965_irq_tasklet, -- cgit v1.2.1 From 1a94ace406ad6befab73ac62f254c39599617c90 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:49 +0100 Subject: iwl3945: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.data = d; -t.function = f; // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/iwlegacy/3945-mac.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index dc1d20cf64ee..e5665804d986 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3429,9 +3429,7 @@ il3945_setup_deferred_work(struct il_priv *il) il3945_hw_setup_deferred_work(il); - init_timer(&il->watchdog); - il->watchdog.data = (unsigned long)il; - il->watchdog.function = il_bg_watchdog; + setup_timer(&il->watchdog, il_bg_watchdog, (unsigned long)il); tasklet_init(&il->irq_tasklet, (void (*)(unsigned long))il3945_irq_tasklet, -- cgit v1.2.1 From 99a1b74395a51b5be91a92c23da47c0032ff7507 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:55 +0100 Subject: orinoco_usb: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.function = f; -t.data = d; // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/orinoco/orinoco_usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index 995846422dc0..91f05442de28 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c @@ -364,9 +364,7 @@ static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv, atomic_set(&ctx->refcount, 1); init_completion(&ctx->done); - init_timer(&ctx->timer); - ctx->timer.function = ezusb_request_timerfn; - ctx->timer.data = (u_long) ctx; + setup_timer(&ctx->timer, ezusb_request_timerfn, (u_long)ctx); return ctx; } -- cgit v1.2.1 From c6c33e772407031bc3b7482296e400a0ea6e7b32 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:56 +0100 Subject: mwifiex: main: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.function = f; -t.data = d; // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 119e87574e83..d235adb82c94 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -83,9 +83,8 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, } mwifiex_init_lock_list(adapter); - init_timer(&adapter->cmd_timer); - adapter->cmd_timer.function = mwifiex_cmd_timeout_func; - adapter->cmd_timer.data = (unsigned long) adapter; + setup_timer(&adapter->cmd_timer, mwifiex_cmd_timeout_func, + (unsigned long)adapter); return 0; -- cgit v1.2.1 From e4a1c3f88e6530b3128a361f8d869819e922c3a1 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:57 +0100 Subject: mwifiex: 11n_rxreorder: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.function = f; -t.data = d; // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11n_rxreorder.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index d73fda312c87..f33dc81c5228 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -391,10 +391,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, new_node->timer_context.priv = priv; new_node->timer_context.timer_is_set = false; - init_timer(&new_node->timer_context.timer); - new_node->timer_context.timer.function = mwifiex_flush_data; - new_node->timer_context.timer.data = - (unsigned long) &new_node->timer_context; + setup_timer(&new_node->timer_context.timer, mwifiex_flush_data, + (unsigned long)&new_node->timer_context); for (i = 0; i < win_size; ++i) new_node->rx_reorder_ptr[i] = NULL; -- cgit v1.2.1 From 6383539b973a22b4d066779b04de8e9937754e60 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Dec 2014 15:35:58 +0100 Subject: mwifiex: tdls: Use setup_timer Convert a call to init_timer and accompanying intializations of the timer's data and function fields to a call to setup_timer. A simplified version of the semantic match that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,f,d; @@ -init_timer(&t); +setup_timer(&t,f,d); -t.function = f; -t.data = d; // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/tdls.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index efa81d8f2597..087d84762cd3 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -1397,9 +1397,8 @@ void mwifiex_check_auto_tdls(unsigned long context) void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv) { - init_timer(&priv->auto_tdls_timer); - priv->auto_tdls_timer.function = mwifiex_check_auto_tdls; - priv->auto_tdls_timer.data = (unsigned long)priv; + setup_timer(&priv->auto_tdls_timer, mwifiex_check_auto_tdls, + (unsigned long)priv); priv->auto_tdls_timer_active = true; mod_timer(&priv->auto_tdls_timer, jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S)); -- cgit v1.2.1 From db12847ca84b7a315a3ba77c939c9d08df17d54f Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Tue, 6 Jan 2015 08:39:02 -0500 Subject: mac80211: Re-fix accounting of the tailroom-needed counter When hw acceleration is enabled, the GENERATE_IV or PUT_IV_SPACE flags only require headroom space. Therefore, the tailroom-needed counter can safely be decremented for most drivers. The older incarnation of this patch (ca34e3b5) assumed that the above holds true for all drivers. As reported by Christopher Chavez and researched by Christian Lamparter and Larry Finger, this isn't a valid assumption for p54 and cw1200. Drivers that still require tailroom for ICV/MIC even when HW encryption is enabled can use IEEE80211_KEY_FLAG_RESERVE_TAILROOM to indicate it. Signed-off-by: Ido Yariv Cc: Christopher Chavez Cc: Christian Lamparter Cc: Larry Finger Cc: Solomon Peachy Signed-off-by: Johannes Berg --- drivers/net/wireless/cw1200/sta.c | 3 ++- drivers/net/wireless/p54/main.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c index a1e3237c0be8..4a47c7f8a246 100644 --- a/drivers/net/wireless/cw1200/sta.c +++ b/drivers/net/wireless/cw1200/sta.c @@ -709,7 +709,8 @@ int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, if (sta) peer_addr = sta->addr; - key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | + IEEE80211_KEY_FLAG_RESERVE_TAILROOM; switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 97aeff0edb84..13a30c4a27f2 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -575,6 +575,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, key->hw_key_idx = 0xff; goto out_unlock; } + + key->flags |= IEEE80211_KEY_FLAG_RESERVE_TAILROOM; } else { slot = key->hw_key_idx; -- cgit v1.2.1 From 4ed20bebf51578229a1986efcf46344075ec8447 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Nov 2014 16:35:34 +0100 Subject: cfg80211: remove "channel" from survey names All of the survey data is (currently) per channel anyway, so having the word "channel" in the name does nothing. In the next patch I'll introduce global data to the survey, where the word "channel" is actually confusing. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/wmi.c | 8 ++++---- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 16 ++++++++-------- drivers/net/wireless/ath/ath9k/link.c | 16 ++++++++-------- drivers/net/wireless/ath/carl9170/cmd.c | 12 ++++++------ drivers/net/wireless/ath/carl9170/main.c | 6 +++--- drivers/net/wireless/mwifiex/cfg80211.c | 7 ++++--- drivers/net/wireless/mwl8k.c | 12 ++++++------ drivers/net/wireless/p54/eeprom.c | 6 +++--- drivers/net/wireless/p54/main.c | 8 ++++---- drivers/net/wireless/p54/txrx.c | 12 ++++++------ drivers/net/wireless/rt2x00/rt2800lib.c | 12 ++++++------ 11 files changed, 58 insertions(+), 57 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c0f3e4d09263..721631c3dd3e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1344,11 +1344,11 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) rx_clear_count -= ar->survey_last_rx_clear_count; survey = &ar->survey[idx]; - survey->channel_time = WMI_CHAN_INFO_MSEC(cycle_count); - survey->channel_time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count); + survey->time = WMI_CHAN_INFO_MSEC(cycle_count); + survey->time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count); survey->noise = noise_floor; - survey->filled = SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_RX | + survey->filled = SURVEY_INFO_TIME | + SURVEY_INFO_TIME_RX | SURVEY_INFO_NOISE_DBM; } diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 19eab2a69ad5..3b4a6463d87a 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -672,10 +672,10 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) spin_lock_bh(&common->cc_lock); ath_hw_cycle_counters_update(common); if (cc->cycles > 0) { - ah->survey.channel_time += cc->cycles / div; - ah->survey.channel_time_busy += cc->rx_busy / div; - ah->survey.channel_time_rx += cc->rx_frame / div; - ah->survey.channel_time_tx += cc->tx_frame / div; + ah->survey.time += cc->cycles / div; + ah->survey.time_busy += cc->rx_busy / div; + ah->survey.time_rx += cc->rx_frame / div; + ah->survey.time_tx += cc->tx_frame / div; } memset(cc, 0, sizeof(*cc)); spin_unlock_bh(&common->cc_lock); @@ -686,10 +686,10 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) survey->noise = ah->ah_noise_floor; survey->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_IN_USE | - SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_RX | - SURVEY_INFO_CHANNEL_TIME_TX; + SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_TX; return 0; } diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index b829263e3d0a..90631d768a60 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -516,14 +516,14 @@ int ath_update_survey_stats(struct ath_softc *sc) ath_hw_cycle_counters_update(common); if (cc->cycles > 0) { - survey->filled |= SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_RX | - SURVEY_INFO_CHANNEL_TIME_TX; - survey->channel_time += cc->cycles / div; - survey->channel_time_busy += cc->rx_busy / div; - survey->channel_time_rx += cc->rx_frame / div; - survey->channel_time_tx += cc->tx_frame / div; + survey->filled |= SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_TX; + survey->time += cc->cycles / div; + survey->time_busy += cc->rx_busy / div; + survey->time_rx += cc->rx_frame / div; + survey->time_tx += cc->tx_frame / div; } if (cc->cycles < div) diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c index 39a63874b275..f2b4f537e4c1 100644 --- a/drivers/net/wireless/ath/carl9170/cmd.c +++ b/drivers/net/wireless/ath/carl9170/cmd.c @@ -188,12 +188,12 @@ int carl9170_collect_tally(struct ar9170 *ar) if (ar->channel) { info = &ar->survey[ar->channel->hw_value]; - info->channel_time = ar->tally.active; - info->channel_time_busy = ar->tally.cca; - info->channel_time_tx = ar->tally.tx_time; - do_div(info->channel_time, 1000); - do_div(info->channel_time_busy, 1000); - do_div(info->channel_time_tx, 1000); + info->time = ar->tally.active; + info->time_busy = ar->tally.cca; + info->time_tx = ar->tally.tx_time; + do_div(info->time, 1000); + do_div(info->time_busy, 1000); + do_div(info->time_tx, 1000); } } return 0; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index ef5b6dc7b7f1..f1455a04cb62 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1690,9 +1690,9 @@ found: survey->filled |= SURVEY_INFO_IN_USE; if (ar->fw.hw_counters) { - survey->filled |= SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_TX; + survey->filled |= SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_TX; } return 0; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 4a66a6555366..8bd446b69658 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1037,10 +1037,11 @@ mwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev, survey->channel = ieee80211_get_channel(wiphy, ieee80211_channel_to_frequency(pchan_stats[idx].chan_num, band)); survey->filled = SURVEY_INFO_NOISE_DBM | - SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY; + SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY; survey->noise = pchan_stats[idx].noise; - survey->channel_time = pchan_stats[idx].cca_scan_dur; - survey->channel_time_busy = pchan_stats[idx].cca_busy_dur; + survey->time = pchan_stats[idx].cca_scan_dur; + survey->time_busy = pchan_stats[idx].cca_busy_dur; return 0; } diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b8d1e04aa9b9..f9b1218c761a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3098,14 +3098,14 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv, cca_cnt = ioread32(priv->regs + NOK_CCA_CNT_REG); cca_cnt /= 1000; /* uSecs to mSecs */ - survey->channel_time_busy = (u64) cca_cnt; + survey->time_busy = (u64) cca_cnt; rx_rdy = ioread32(priv->regs + BBU_RXRDY_CNT_REG); rx_rdy /= 1000; /* uSecs to mSecs */ - survey->channel_time_rx = (u64) rx_rdy; + survey->time_rx = (u64) rx_rdy; priv->channel_time = jiffies - priv->channel_time; - survey->channel_time = jiffies_to_msecs(priv->channel_time); + survey->time = jiffies_to_msecs(priv->channel_time); survey->channel = channel; @@ -3115,9 +3115,9 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv, survey->noise = nf * -1; survey->filled = SURVEY_INFO_NOISE_DBM | - SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_RX; + SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_RX; } /* diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 0fe67d2da208..2fe713eda7ad 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -196,9 +196,9 @@ static int p54_generate_band(struct ieee80211_hw *dev, dest->max_power = chan->max_power; priv->survey[*chan_num].channel = &tmp->channels[j]; priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM | - SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_TX; + SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_TX; dest->hw_value = (*chan_num); j++; (*chan_num)++; diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 13a30c4a27f2..b9250d75d253 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -305,9 +305,9 @@ static void p54_reset_stats(struct p54_common *priv) struct survey_info *info = &priv->survey[chan->hw_value]; /* only reset channel statistics, don't touch .filled, etc. */ - info->channel_time = 0; - info->channel_time_busy = 0; - info->channel_time_tx = 0; + info->time = 0; + info->time_busy = 0; + info->time_tx = 0; } priv->update_stats = true; @@ -636,7 +636,7 @@ static int p54_get_survey(struct ieee80211_hw *dev, int idx, if (in_use) { /* test if the reported statistics are valid. */ - if (survey->channel_time != 0) { + if (survey->time != 0) { survey->filled |= SURVEY_INFO_IN_USE; } else { /* diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 153c61539ec8..24e5ff9a9272 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -587,13 +587,13 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb) if (chan) { struct survey_info *survey = &priv->survey[chan->hw_value]; survey->noise = clamp(priv->noise, -128, 127); - survey->channel_time = priv->survey_raw.active; - survey->channel_time_tx = priv->survey_raw.tx; - survey->channel_time_busy = priv->survey_raw.tx + + survey->time = priv->survey_raw.active; + survey->time_tx = priv->survey_raw.tx; + survey->time_busy = priv->survey_raw.tx + priv->survey_raw.cca; - do_div(survey->channel_time, 1024); - do_div(survey->channel_time_tx, 1024); - do_div(survey->channel_time_busy, 1024); + do_div(survey->time, 1024); + do_div(survey->time_tx, 1024); + do_div(survey->time_busy, 1024); } tmp = p54_find_and_unlink_skb(priv, hdr->req_id); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 81ee481487cf..be2d54f257b1 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -8020,13 +8020,13 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx, rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext); if (idle || busy) { - survey->filled = SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_EXT_BUSY; + survey->filled = SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_EXT_BUSY; - survey->channel_time = (idle + busy) / 1000; - survey->channel_time_busy = busy / 1000; - survey->channel_time_ext_busy = busy_ext / 1000; + survey->time = (idle + busy) / 1000; + survey->time_busy = busy / 1000; + survey->time_ext_busy = busy_ext / 1000; } if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) -- cgit v1.2.1 From 2b9a7e1bac24df8ddb0713ad1e5807a7243bcab0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Nov 2014 11:35:23 +0100 Subject: mac80211: allow drivers to provide most station statistics In many cases, drivers can filter things like beacons that will skew statistics reported by mac80211. To get correct statistics in these cases, call drivers to obtain statistics and let them override all values, filling values from mac80211 if the driver didn't provide them. Not all of them make sense for the driver to fill, so some are still always done by mac80211. Note that this doesn't currently allow a driver to say "I know this value is wrong, don't report it at all", or to sum it up with a mac80211 value (as could be useful for "dropped misc"), that can be added if it turns out to be needed. This also gets rid of the get_rssi() method as is can now be implemented using sta_statistics(). Signed-off-by: Johannes Berg --- drivers/net/wireless/ti/wlcore/main.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 2a99456b6b8f..8d11b0ca412c 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5376,14 +5376,15 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw, wlcore_hw_sta_rc_update(wl, wlvif, sta, changed); } -static int wlcore_op_get_rssi(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - s8 *rssi_dbm) +static void wlcore_op_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret = 0; + s8 rssi_dbm; + int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi"); @@ -5396,17 +5397,18 @@ static int wlcore_op_get_rssi(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; - ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm); + ret = wlcore_acx_average_rssi(wl, wlvif, &rssi_dbm); if (ret < 0) goto out_sleep; + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = rssi_dbm; + out_sleep: wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); - - return ret; } static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) @@ -5606,7 +5608,7 @@ static const struct ieee80211_ops wl1271_ops = { .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, .sta_rc_update = wlcore_op_sta_rc_update, - .get_rssi = wlcore_op_get_rssi, + .sta_statistics = wlcore_op_sta_statistics, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; -- cgit v1.2.1 From 319090bf6c75e3ad42a8c74973be5e78ae4f948f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Nov 2014 14:08:11 +0100 Subject: cfg80211: remove enum station_info_flags This is really just duplicating the list of information that's already available in the nl80211 attribute, so remove the list. Two small changes are needed: * remove STATION_INFO_ASSOC_REQ_IES complete, but the length (assoc_req_ies_len) can be used instead * add NL80211_STA_INFO_RX_DROP_MISC which exists internally but not in nl80211 yet This gets rid of the duplicate maintenance of the two lists. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 14 +++++++------- drivers/net/wireless/ath/ath6kl/main.c | 1 - drivers/net/wireless/ath/wil6210/cfg80211.c | 18 +++++++++--------- drivers/net/wireless/ath/wil6210/wmi.c | 1 - drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 11 +++++------ drivers/net/wireless/libertas/cfg.c | 12 ++++++------ drivers/net/wireless/mwifiex/cfg80211.c | 10 +++++----- drivers/net/wireless/mwifiex/uap_event.c | 1 - drivers/net/wireless/rndis_wlan.c | 4 ++-- drivers/net/wireless/ti/wlcore/main.c | 2 +- 10 files changed, 35 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 7a5337877a0c..44dd6ef923cd 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1799,20 +1799,20 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, if (vif->target_stats.rx_byte) { sinfo->rx_bytes = vif->target_stats.rx_byte; - sinfo->filled |= STATION_INFO_RX_BYTES64; + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64); sinfo->rx_packets = vif->target_stats.rx_pkt; - sinfo->filled |= STATION_INFO_RX_PACKETS; + sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); } if (vif->target_stats.tx_byte) { sinfo->tx_bytes = vif->target_stats.tx_byte; - sinfo->filled |= STATION_INFO_TX_BYTES64; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64); sinfo->tx_packets = vif->target_stats.tx_pkt; - sinfo->filled |= STATION_INFO_TX_PACKETS; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); } sinfo->signal = vif->target_stats.cs_rssi; - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); rate = vif->target_stats.tx_ucast_rate; @@ -1844,12 +1844,12 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, return 0; } - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); if (test_bit(CONNECTED, &vif->flags) && test_bit(DTIM_PERIOD_AVAIL, &vif->flags) && vif->nw_type == INFRA_NETWORK) { - sinfo->filled |= STATION_INFO_BSS_PARAM; + sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); sinfo->bss_param.flags = 0; sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period; sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int; diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 933aef025698..b42ba46b5030 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -488,7 +488,6 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, sinfo.assoc_req_ies = ies; sinfo.assoc_req_ies_len = ies_len; - sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; cfg80211_new_sta(vif->ndev, mac_addr, &sinfo, GFP_KERNEL); diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 38332a6dfb3a..e72a95d1ced6 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -142,14 +142,14 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, sinfo->generation = wil->sinfo_gen; - sinfo->filled = STATION_INFO_RX_BYTES | - STATION_INFO_TX_BYTES | - STATION_INFO_RX_PACKETS | - STATION_INFO_TX_PACKETS | - STATION_INFO_RX_BITRATE | - STATION_INFO_TX_BITRATE | - STATION_INFO_RX_DROP_MISC | - STATION_INFO_TX_FAILED; + sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) | + BIT(NL80211_STA_INFO_TX_BYTES) | + BIT(NL80211_STA_INFO_RX_PACKETS) | + BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_RX_BITRATE) | + BIT(NL80211_STA_INFO_TX_BITRATE) | + BIT(NL80211_STA_INFO_RX_DROP_MISC) | + BIT(NL80211_STA_INFO_TX_FAILED); sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); @@ -163,7 +163,7 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, sinfo->tx_failed = stats->tx_errors; if (test_bit(wil_status_fwconnected, &wil->status)) { - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); sinfo->signal = reply.evt.sqi; } diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 63476c86cd0e..899754920955 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -457,7 +457,6 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) if (assoc_req_ie) { sinfo.assoc_req_ies = assoc_req_ie; sinfo.assoc_req_ies_len = assoc_req_ielen; - sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; } cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 3aecc5f48719..4a88b2381a68 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -2333,10 +2333,10 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("GET STA INFO failed, %d\n", err); goto done; } - sinfo->filled = STATION_INFO_INACTIVE_TIME; + sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME); sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000; if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) { - sinfo->filled |= STATION_INFO_CONNECTED_TIME; + sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME); sinfo->connected_time = le32_to_cpu(sta_info_le.in); } brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n", @@ -2354,7 +2354,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("Could not get rate (%d)\n", err); goto done; } else { - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); sinfo->txrate.legacy = rate * 5; brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2); } @@ -2369,7 +2369,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, goto done; } else { rssi = le32_to_cpu(scb_val.val); - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); sinfo->signal = rssi; brcmf_dbg(CONN, "RSSI %d dBm\n", rssi); } @@ -2396,7 +2396,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(CONN, "DTIM peroid %d\n", dtim_period); } - sinfo->filled |= STATION_INFO_BSS_PARAM; + sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); } } else err = -EPERM; @@ -4778,7 +4778,6 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && (reason == BRCMF_E_STATUS_SUCCESS)) { memset(&sinfo, 0, sizeof(sinfo)); - sinfo.filled = STATION_INFO_ASSOC_REQ_IES; if (!data) { brcmf_err("No IEs present in ASSOC/REASSOC_IND"); return -EINVAL; diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 34f09ef90bb3..a92985a6ea21 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -1616,10 +1616,10 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, lbs_deb_enter(LBS_DEB_CFG80211); - sinfo->filled |= STATION_INFO_TX_BYTES | - STATION_INFO_TX_PACKETS | - STATION_INFO_RX_BYTES | - STATION_INFO_RX_PACKETS; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) | + BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_RX_BYTES) | + BIT(NL80211_STA_INFO_RX_PACKETS); sinfo->tx_bytes = priv->dev->stats.tx_bytes; sinfo->tx_packets = priv->dev->stats.tx_packets; sinfo->rx_bytes = priv->dev->stats.rx_bytes; @@ -1629,14 +1629,14 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, ret = lbs_get_rssi(priv, &signal, &noise); if (ret == 0) { sinfo->signal = signal; - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); } /* Convert priv->cur_rate from hw_value to NL80211 value */ for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) { if (priv->cur_rate == lbs_rates[i].hw_value) { sinfo->txrate.legacy = lbs_rates[i].bitrate; - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); break; } } diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 8bd446b69658..71312ff52703 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -910,10 +910,10 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, { u32 rate; - sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | - STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS | - STATION_INFO_TX_BITRATE | - STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; + sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) | BIT(NL80211_STA_INFO_TX_BYTES) | + BIT(NL80211_STA_INFO_RX_PACKETS) | BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_TX_BITRATE) | + BIT(NL80211_STA_INFO_SIGNAL) | BIT(NL80211_STA_INFO_SIGNAL_AVG); /* Get signal information from the firmware */ if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO, @@ -944,7 +944,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, sinfo->txrate.legacy = rate * 5; if (priv->bss_mode == NL80211_IFTYPE_STATION) { - sinfo->filled |= STATION_INFO_BSS_PARAM; + sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); sinfo->bss_param.flags = 0; if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap & WLAN_CAPABILITY_SHORT_PREAMBLE) diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index c54a537e31fb..3b3a970e2086 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -68,7 +68,6 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) len = ETH_ALEN; if (len != -1) { - sinfo.filled = STATION_INFO_ASSOC_REQ_IES; sinfo.assoc_req_ies = &event->data[len]; len = (u8 *)sinfo.assoc_req_ies - (u8 *)&event->frame_control; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 1a4facd1fbf3..60d44ce9c017 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2478,7 +2478,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev, 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 |= STATION_INFO_TX_BITRATE; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); } len = sizeof(rssi); @@ -2486,7 +2486,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev, &rssi, &len); if (ret == 0) { sinfo->signal = level_to_qual(le32_to_cpu(rssi)); - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); } } diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 8d11b0ca412c..a2133b1fd631 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5401,7 +5401,7 @@ static void wlcore_op_sta_statistics(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); sinfo->signal = rssi_dbm; out_sleep: -- cgit v1.2.1 From 49aa284ffe64c4c13d63d315aa374e0f4bdd4b7c Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 7 Jan 2015 08:48:00 +0530 Subject: cxgb4: Add support for devlog Add support for device log entry in debugfs Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 8 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 198 +++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 26 +++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 12 ++ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 81 +++++++++ 5 files changed, 325 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 5ab5c3133acd..73b1f3aea092 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -290,11 +290,19 @@ enum chip_type { T5_LAST_REV = T5_A1, }; +struct devlog_params { + u32 memtype; /* which memory (EDC0, EDC1, MC) */ + u32 start; /* start of log in firmware memory */ + u32 size; /* size of log */ +}; + struct adapter_params { struct sge_params sge; struct tp_params tp; struct vpd_params vpd; struct pci_params pci; + struct devlog_params devlog; + enum pcie_memwin drv_memwin; unsigned int sf_size; /* serial flash size in bytes */ unsigned int sf_nsec; /* # of flash sectors */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index c98a350d857e..1d3d1c590808 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -43,6 +43,203 @@ #include "cxgb4_debugfs.h" #include "l2t.h" +/* Firmware Device Log dump. + */ +static const char * const devlog_level_strings[] = { + [FW_DEVLOG_LEVEL_EMERG] = "EMERG", + [FW_DEVLOG_LEVEL_CRIT] = "CRIT", + [FW_DEVLOG_LEVEL_ERR] = "ERR", + [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", + [FW_DEVLOG_LEVEL_INFO] = "INFO", + [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" +}; + +static const char * const devlog_facility_strings[] = { + [FW_DEVLOG_FACILITY_CORE] = "CORE", + [FW_DEVLOG_FACILITY_SCHED] = "SCHED", + [FW_DEVLOG_FACILITY_TIMER] = "TIMER", + [FW_DEVLOG_FACILITY_RES] = "RES", + [FW_DEVLOG_FACILITY_HW] = "HW", + [FW_DEVLOG_FACILITY_FLR] = "FLR", + [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", + [FW_DEVLOG_FACILITY_PHY] = "PHY", + [FW_DEVLOG_FACILITY_MAC] = "MAC", + [FW_DEVLOG_FACILITY_PORT] = "PORT", + [FW_DEVLOG_FACILITY_VI] = "VI", + [FW_DEVLOG_FACILITY_FILTER] = "FILTER", + [FW_DEVLOG_FACILITY_ACL] = "ACL", + [FW_DEVLOG_FACILITY_TM] = "TM", + [FW_DEVLOG_FACILITY_QFC] = "QFC", + [FW_DEVLOG_FACILITY_DCB] = "DCB", + [FW_DEVLOG_FACILITY_ETH] = "ETH", + [FW_DEVLOG_FACILITY_OFLD] = "OFLD", + [FW_DEVLOG_FACILITY_RI] = "RI", + [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", + [FW_DEVLOG_FACILITY_FCOE] = "FCOE", + [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", + [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" +}; + +/* Information gathered by Device Log Open routine for the display routine. + */ +struct devlog_info { + unsigned int nentries; /* number of entries in log[] */ + unsigned int first; /* first [temporal] entry in log[] */ + struct fw_devlog_e log[0]; /* Firmware Device Log */ +}; + +/* Dump a Firmaware Device Log entry. + */ +static int devlog_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, "%10s %15s %8s %8s %s\n", + "Seq#", "Tstamp", "Level", "Facility", "Message"); + else { + struct devlog_info *dinfo = seq->private; + int fidx = (uintptr_t)v - 2; + unsigned long index; + struct fw_devlog_e *e; + + /* Get a pointer to the log entry to display. Skip unused log + * entries. + */ + index = dinfo->first + fidx; + if (index >= dinfo->nentries) + index -= dinfo->nentries; + e = &dinfo->log[index]; + if (e->timestamp == 0) + return 0; + + /* Print the message. This depends on the firmware using + * exactly the same formating strings as the kernel so we may + * eventually have to put a format interpreter in here ... + */ + seq_printf(seq, "%10d %15llu %8s %8s ", + e->seqno, e->timestamp, + (e->level < ARRAY_SIZE(devlog_level_strings) + ? devlog_level_strings[e->level] + : "UNKNOWN"), + (e->facility < ARRAY_SIZE(devlog_facility_strings) + ? devlog_facility_strings[e->facility] + : "UNKNOWN")); + seq_printf(seq, e->fmt, e->params[0], e->params[1], + e->params[2], e->params[3], e->params[4], + e->params[5], e->params[6], e->params[7]); + } + return 0; +} + +/* Sequential File Operations for Device Log. + */ +static inline void *devlog_get_idx(struct devlog_info *dinfo, loff_t pos) +{ + if (pos > dinfo->nentries) + return NULL; + + return (void *)(uintptr_t)(pos + 1); +} + +static void *devlog_start(struct seq_file *seq, loff_t *pos) +{ + struct devlog_info *dinfo = seq->private; + + return (*pos + ? devlog_get_idx(dinfo, *pos) + : SEQ_START_TOKEN); +} + +static void *devlog_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct devlog_info *dinfo = seq->private; + + (*pos)++; + return devlog_get_idx(dinfo, *pos); +} + +static void devlog_stop(struct seq_file *seq, void *v) +{ +} + +static const struct seq_operations devlog_seq_ops = { + .start = devlog_start, + .next = devlog_next, + .stop = devlog_stop, + .show = devlog_show +}; + +/* Set up for reading the firmware's device log. We read the entire log here + * and then display it incrementally in devlog_show(). + */ +static int devlog_open(struct inode *inode, struct file *file) +{ + struct adapter *adap = inode->i_private; + struct devlog_params *dparams = &adap->params.devlog; + struct devlog_info *dinfo; + unsigned int index; + u32 fseqno; + int ret; + + /* If we don't know where the log is we can't do anything. + */ + if (dparams->start == 0) + return -ENXIO; + + /* Allocate the space to read in the firmware's device log and set up + * for the iterated call to our display function. + */ + dinfo = __seq_open_private(file, &devlog_seq_ops, + sizeof(*dinfo) + dparams->size); + if (!dinfo) + return -ENOMEM; + + /* Record the basic log buffer information and read in the raw log. + */ + dinfo->nentries = (dparams->size / sizeof(struct fw_devlog_e)); + dinfo->first = 0; + spin_lock(&adap->win0_lock); + ret = t4_memory_rw(adap, adap->params.drv_memwin, dparams->memtype, + dparams->start, dparams->size, (__be32 *)dinfo->log, + T4_MEMORY_READ); + spin_unlock(&adap->win0_lock); + if (ret) { + seq_release_private(inode, file); + return ret; + } + + /* Translate log multi-byte integral elements into host native format + * and determine where the first entry in the log is. + */ + for (fseqno = ~((u32)0), index = 0; index < dinfo->nentries; index++) { + struct fw_devlog_e *e = &dinfo->log[index]; + int i; + __u32 seqno; + + if (e->timestamp == 0) + continue; + + e->timestamp = (__force __be64)be64_to_cpu(e->timestamp); + seqno = be32_to_cpu(e->seqno); + for (i = 0; i < 8; i++) + e->params[i] = + (__force __be32)be32_to_cpu(e->params[i]); + + if (seqno < fseqno) { + fseqno = seqno; + dinfo->first = index; + } + } + return 0; +} + +static const struct file_operations devlog_fops = { + .owner = THIS_MODULE, + .open = devlog_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + static ssize_t mem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -121,6 +318,7 @@ int t4_setup_debugfs(struct adapter *adap) u32 size; static struct t4_debugfs_entry t4_debugfs_files[] = { + { "devlog", &devlog_fops, S_IRUSR, 0 }, { "l2t", &t4_l2t_fops, S_IRUSR, 0}, }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 04e675b8218a..6de41cc6687e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -5541,6 +5541,8 @@ static int adap_init0(struct adapter *adap) enum dev_state state; u32 params[7], val[7]; struct fw_caps_config_cmd caps_cmd; + struct fw_devlog_cmd devlog_cmd; + u32 devlog_meminfo; int reset = 1; /* Contact FW, advertising Master capability */ @@ -5621,6 +5623,30 @@ static int adap_init0(struct adapter *adap) if (ret < 0) goto bye; + /* Read firmware device log parameters. We really need to find a way + * to get these parameters initialized with some default values (which + * are likely to be correct) for the case where we either don't + * attache to the firmware or it's crashed when we probe the adapter. + * That way we'll still be able to perform early firmware startup + * debugging ... If the request to get the Firmware's Device Log + * parameters fails, we'll live so we don't make that a fatal error. + */ + memset(&devlog_cmd, 0, sizeof(devlog_cmd)); + devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) | + FW_CMD_REQUEST_F | FW_CMD_READ_F); + devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd)); + ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd), + &devlog_cmd); + if (ret == 0) { + devlog_meminfo = + ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog); + adap->params.devlog.memtype = + FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo); + adap->params.devlog.start = + FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4; + adap->params.devlog.size = ntohl(devlog_cmd.memsize_devlog); + } + /* * Find out what ports are available to us. Note that we need to do * this before calling adap_init0_no_config() since it needs nports diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index c19a90e7f7d1..5e5eee6c6b5e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -110,6 +110,18 @@ enum { SGE_INGPADBOUNDARY_SHIFT = 5,/* ingress queue pad boundary */ }; +/* PCI-e memory window access */ +enum pcie_memwin { + MEMWIN_NIC = 0, + MEMWIN_RSVD1 = 1, + MEMWIN_RSVD2 = 2, + MEMWIN_RDMA = 3, + MEMWIN_RSVD4 = 4, + MEMWIN_FOISCSI = 5, + MEMWIN_CSIOSTOR = 6, + MEMWIN_RSVD7 = 7, +}; + struct sge_qstat { /* data written to SGE queue status entries */ __be32 qid; __be16 cidx; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 7c0aec85137a..de8283324f1f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -673,6 +673,7 @@ enum fw_cmd_opcodes { FW_RSS_IND_TBL_CMD = 0x20, FW_RSS_GLB_CONFIG_CMD = 0x22, FW_RSS_VI_CONFIG_CMD = 0x23, + FW_DEVLOG_CMD = 0x25, FW_CLIP_CMD = 0x28, FW_LASTC2E_CMD = 0x40, FW_ERROR_CMD = 0x80, @@ -3038,4 +3039,84 @@ enum fw_hdr_flags { FW_HDR_FLAGS_RESET_HALT = 0x00000001, }; +/* length of the formatting string */ +#define FW_DEVLOG_FMT_LEN 192 + +/* maximum number of the formatting string parameters */ +#define FW_DEVLOG_FMT_PARAMS_NUM 8 + +/* priority levels */ +enum fw_devlog_level { + FW_DEVLOG_LEVEL_EMERG = 0x0, + FW_DEVLOG_LEVEL_CRIT = 0x1, + FW_DEVLOG_LEVEL_ERR = 0x2, + FW_DEVLOG_LEVEL_NOTICE = 0x3, + FW_DEVLOG_LEVEL_INFO = 0x4, + FW_DEVLOG_LEVEL_DEBUG = 0x5, + FW_DEVLOG_LEVEL_MAX = 0x5, +}; + +/* facilities that may send a log message */ +enum fw_devlog_facility { + FW_DEVLOG_FACILITY_CORE = 0x00, + FW_DEVLOG_FACILITY_CF = 0x01, + FW_DEVLOG_FACILITY_SCHED = 0x02, + FW_DEVLOG_FACILITY_TIMER = 0x04, + FW_DEVLOG_FACILITY_RES = 0x06, + FW_DEVLOG_FACILITY_HW = 0x08, + FW_DEVLOG_FACILITY_FLR = 0x10, + FW_DEVLOG_FACILITY_DMAQ = 0x12, + FW_DEVLOG_FACILITY_PHY = 0x14, + FW_DEVLOG_FACILITY_MAC = 0x16, + FW_DEVLOG_FACILITY_PORT = 0x18, + FW_DEVLOG_FACILITY_VI = 0x1A, + FW_DEVLOG_FACILITY_FILTER = 0x1C, + FW_DEVLOG_FACILITY_ACL = 0x1E, + FW_DEVLOG_FACILITY_TM = 0x20, + FW_DEVLOG_FACILITY_QFC = 0x22, + FW_DEVLOG_FACILITY_DCB = 0x24, + FW_DEVLOG_FACILITY_ETH = 0x26, + FW_DEVLOG_FACILITY_OFLD = 0x28, + FW_DEVLOG_FACILITY_RI = 0x2A, + FW_DEVLOG_FACILITY_ISCSI = 0x2C, + FW_DEVLOG_FACILITY_FCOE = 0x2E, + FW_DEVLOG_FACILITY_FOISCSI = 0x30, + FW_DEVLOG_FACILITY_FOFCOE = 0x32, + FW_DEVLOG_FACILITY_MAX = 0x32, +}; + +/* log message format */ +struct fw_devlog_e { + __be64 timestamp; + __be32 seqno; + __be16 reserved1; + __u8 level; + __u8 facility; + __u8 fmt[FW_DEVLOG_FMT_LEN]; + __be32 params[FW_DEVLOG_FMT_PARAMS_NUM]; + __be32 reserved3[4]; +}; + +struct fw_devlog_cmd { + __be32 op_to_write; + __be32 retval_len16; + __u8 level; + __u8 r2[7]; + __be32 memtype_devlog_memaddr16_devlog; + __be32 memsize_devlog; + __be32 r3[2]; +}; + +#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_S 28 +#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_M 0xf +#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(x) \ + (((x) >> FW_DEVLOG_CMD_MEMTYPE_DEVLOG_S) & \ + FW_DEVLOG_CMD_MEMTYPE_DEVLOG_M) + +#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S 0 +#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M 0xfffffff +#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(x) \ + (((x) >> FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S) & \ + FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M) + #endif /* _T4FW_INTERFACE_H_ */ -- cgit v1.2.1 From f1ff24aa95f5612c7744d1ff9b8394a9e09bc6c9 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 7 Jan 2015 08:48:01 +0530 Subject: cxgb4: Add support for cim_la entry in debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CIM LA captures the embedded processor’s internal state. Optionally, it can also trace the flow of data in and out of the embedded processor. Therefore, the CIM LA output contains detailed information of what code the embedded processor executed prior to the CIM LA capture. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 7 ++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 129 ++++++++++++++++++++- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h | 12 ++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 120 +++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 4 + drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 34 ++++++ 6 files changed, 304 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 73b1f3aea092..46cd506120d3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -304,6 +304,8 @@ struct adapter_params { struct devlog_params devlog; enum pcie_memwin drv_memwin; + unsigned int cim_la_size; + unsigned int sf_size; /* serial flash size in bytes */ unsigned int sf_nsec; /* # of flash sectors */ unsigned int sf_fw_start; /* start of FW image in flash */ @@ -1034,6 +1036,11 @@ int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); +int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, + unsigned int *valp); +int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, + const unsigned int *valp); +int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr); const char *t4_get_port_type_description(enum fw_port_type port_type); void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p); void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 1d3d1c590808..0f7b23f15810 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -43,8 +43,132 @@ #include "cxgb4_debugfs.h" #include "l2t.h" -/* Firmware Device Log dump. - */ +/* generic seq_file support for showing a table of size rows x width. */ +static void *seq_tab_get_idx(struct seq_tab *tb, loff_t pos) +{ + pos -= tb->skip_first; + return pos >= tb->rows ? NULL : &tb->data[pos * tb->width]; +} + +static void *seq_tab_start(struct seq_file *seq, loff_t *pos) +{ + struct seq_tab *tb = seq->private; + + if (tb->skip_first && *pos == 0) + return SEQ_START_TOKEN; + + return seq_tab_get_idx(tb, *pos); +} + +static void *seq_tab_next(struct seq_file *seq, void *v, loff_t *pos) +{ + v = seq_tab_get_idx(seq->private, *pos + 1); + if (v) + ++*pos; + return v; +} + +static void seq_tab_stop(struct seq_file *seq, void *v) +{ +} + +static int seq_tab_show(struct seq_file *seq, void *v) +{ + const struct seq_tab *tb = seq->private; + + return tb->show(seq, v, ((char *)v - tb->data) / tb->width); +} + +static const struct seq_operations seq_tab_ops = { + .start = seq_tab_start, + .next = seq_tab_next, + .stop = seq_tab_stop, + .show = seq_tab_show +}; + +struct seq_tab *seq_open_tab(struct file *f, unsigned int rows, + unsigned int width, unsigned int have_header, + int (*show)(struct seq_file *seq, void *v, int i)) +{ + struct seq_tab *p; + + p = __seq_open_private(f, &seq_tab_ops, sizeof(*p) + rows * width); + if (p) { + p->show = show; + p->rows = rows; + p->width = width; + p->skip_first = have_header != 0; + } + return p; +} + +static int cim_la_show(struct seq_file *seq, void *v, int idx) +{ + if (v == SEQ_START_TOKEN) + seq_puts(seq, "Status Data PC LS0Stat LS0Addr " + " LS0Data\n"); + else { + const u32 *p = v; + + seq_printf(seq, + " %02x %x%07x %x%07x %08x %08x %08x%08x%08x%08x\n", + (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, + p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5], + p[6], p[7]); + } + return 0; +} + +static int cim_la_show_3in1(struct seq_file *seq, void *v, int idx) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "Status Data PC\n"); + } else { + const u32 *p = v; + + seq_printf(seq, " %02x %08x %08x\n", p[5] & 0xff, p[6], + p[7]); + seq_printf(seq, " %02x %02x%06x %02x%06x\n", + (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8, + p[4] & 0xff, p[5] >> 8); + seq_printf(seq, " %02x %x%07x %x%07x\n", (p[0] >> 4) & 0xff, + p[0] & 0xf, p[1] >> 4, p[1] & 0xf, p[2] >> 4); + } + return 0; +} + +static int cim_la_open(struct inode *inode, struct file *file) +{ + int ret; + unsigned int cfg; + struct seq_tab *p; + struct adapter *adap = inode->i_private; + + ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &cfg); + if (ret) + return ret; + + p = seq_open_tab(file, adap->params.cim_la_size / 8, 8 * sizeof(u32), 1, + cfg & UPDBGLACAPTPCONLY_F ? + cim_la_show_3in1 : cim_la_show); + if (!p) + return -ENOMEM; + + ret = t4_cim_read_la(adap, (u32 *)p->data, NULL); + if (ret) + seq_release_private(inode, file); + return ret; +} + +static const struct file_operations cim_la_fops = { + .owner = THIS_MODULE, + .open = cim_la_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +/* Firmware Device Log dump. */ static const char * const devlog_level_strings[] = { [FW_DEVLOG_LEVEL_EMERG] = "EMERG", [FW_DEVLOG_LEVEL_CRIT] = "CRIT", @@ -318,6 +442,7 @@ int t4_setup_debugfs(struct adapter *adap) u32 size; static struct t4_debugfs_entry t4_debugfs_files[] = { + { "cim_la", &cim_la_fops, S_IRUSR, 0 }, { "devlog", &devlog_fops, S_IRUSR, 0 }, { "l2t", &t4_l2t_fops, S_IRUSR, 0}, }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h index a3d8867efd3d..70fcbc930826 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h @@ -44,6 +44,18 @@ struct t4_debugfs_entry { unsigned char data; }; +struct seq_tab { + int (*show)(struct seq_file *seq, void *v, int idx); + unsigned int rows; /* # of entries */ + unsigned char width; /* size in bytes of each entry */ + unsigned char skip_first; /* whether the first line is a header */ + char data[0]; /* the table data */ +}; + +struct seq_tab *seq_open_tab(struct file *f, unsigned int rows, + unsigned int width, unsigned int have_header, + int (*show)(struct seq_file *seq, void *v, int i)); + int t4_setup_debugfs(struct adapter *adap); void add_debugfs_files(struct adapter *adap, struct t4_debugfs_entry *files, diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 3776279337c8..1e30554f2699 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -4031,6 +4031,7 @@ int t4_prep_adapter(struct adapter *adapter) return -EINVAL; } + adapter->params.cim_la_size = CIMLA_SIZE; init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); /* @@ -4323,3 +4324,122 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf) } return 0; } + +/** + * t4_cim_read - read a block from CIM internal address space + * @adap: the adapter + * @addr: the start address within the CIM address space + * @n: number of words to read + * @valp: where to store the result + * + * Reads a block of 4-byte words from the CIM intenal address space. + */ +int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, + unsigned int *valp) +{ + int ret = 0; + + if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F) + return -EBUSY; + + for ( ; !ret && n--; addr += 4) { + t4_write_reg(adap, CIM_HOST_ACC_CTRL_A, addr); + ret = t4_wait_op_done(adap, CIM_HOST_ACC_CTRL_A, HOSTBUSY_F, + 0, 5, 2); + if (!ret) + *valp++ = t4_read_reg(adap, CIM_HOST_ACC_DATA_A); + } + return ret; +} + +/** + * t4_cim_write - write a block into CIM internal address space + * @adap: the adapter + * @addr: the start address within the CIM address space + * @n: number of words to write + * @valp: set of values to write + * + * Writes a block of 4-byte words into the CIM intenal address space. + */ +int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, + const unsigned int *valp) +{ + int ret = 0; + + if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F) + return -EBUSY; + + for ( ; !ret && n--; addr += 4) { + t4_write_reg(adap, CIM_HOST_ACC_DATA_A, *valp++); + t4_write_reg(adap, CIM_HOST_ACC_CTRL_A, addr | HOSTWRITE_F); + ret = t4_wait_op_done(adap, CIM_HOST_ACC_CTRL_A, HOSTBUSY_F, + 0, 5, 2); + } + return ret; +} + +static int t4_cim_write1(struct adapter *adap, unsigned int addr, + unsigned int val) +{ + return t4_cim_write(adap, addr, 1, &val); +} + +/** + * t4_cim_read_la - read CIM LA capture buffer + * @adap: the adapter + * @la_buf: where to store the LA data + * @wrptr: the HW write pointer within the capture buffer + * + * Reads the contents of the CIM LA buffer with the most recent entry at + * the end of the returned data and with the entry at @wrptr first. + * We try to leave the LA in the running state we find it in. + */ +int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) +{ + int i, ret; + unsigned int cfg, val, idx; + + ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &cfg); + if (ret) + return ret; + + if (cfg & UPDBGLAEN_F) { /* LA is running, freeze it */ + ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, 0); + if (ret) + return ret; + } + + ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val); + if (ret) + goto restart; + + idx = UPDBGLAWRPTR_G(val); + if (wrptr) + *wrptr = idx; + + for (i = 0; i < adap->params.cim_la_size; i++) { + ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, + UPDBGLARDPTR_V(idx) | UPDBGLARDEN_F); + if (ret) + break; + ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val); + if (ret) + break; + if (val & UPDBGLARDEN_F) { + ret = -ETIMEDOUT; + break; + } + ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]); + if (ret) + break; + idx = (idx + 1) & UPDBGLARDPTR_M; + } +restart: + if (cfg & UPDBGLAEN_F) { + int r = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, + cfg & ~UPDBGLARDEN_F); + if (!ret) + ret = r; + } + return ret; +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index 5e5eee6c6b5e..bcc925b20088 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -55,6 +55,10 @@ enum { WOL_PAT_LEN = 128, /* length of WoL patterns */ }; +enum { + CIMLA_SIZE = 2048, /* # of 32-bit words in CIM LA */ +}; + enum { SF_PAGE_SIZE = 256, /* serial flash page size */ SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 4077227b5cea..3fe6eeb3a55e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -2062,4 +2062,38 @@ #define PL_VF_WHOAMI_A 0x0 #define PL_VF_REVISION_A 0x8 +/* registers for module CIM */ +#define CIM_HOST_ACC_CTRL_A 0x7b50 +#define CIM_HOST_ACC_DATA_A 0x7b54 +#define UP_UP_DBG_LA_CFG_A 0x140 +#define UP_UP_DBG_LA_DATA_A 0x144 + +#define HOSTBUSY_S 17 +#define HOSTBUSY_V(x) ((x) << HOSTBUSY_S) +#define HOSTBUSY_F HOSTBUSY_V(1U) + +#define HOSTWRITE_S 16 +#define HOSTWRITE_V(x) ((x) << HOSTWRITE_S) +#define HOSTWRITE_F HOSTWRITE_V(1U) + +#define UPDBGLARDEN_S 1 +#define UPDBGLARDEN_V(x) ((x) << UPDBGLARDEN_S) +#define UPDBGLARDEN_F UPDBGLARDEN_V(1U) + +#define UPDBGLAEN_S 0 +#define UPDBGLAEN_V(x) ((x) << UPDBGLAEN_S) +#define UPDBGLAEN_F UPDBGLAEN_V(1U) + +#define UPDBGLARDPTR_S 2 +#define UPDBGLARDPTR_M 0xfffU +#define UPDBGLARDPTR_V(x) ((x) << UPDBGLARDPTR_S) + +#define UPDBGLAWRPTR_S 16 +#define UPDBGLAWRPTR_M 0xfffU +#define UPDBGLAWRPTR_G(x) (((x) >> UPDBGLAWRPTR_S) & UPDBGLAWRPTR_M) + +#define UPDBGLACAPTPCONLY_S 30 +#define UPDBGLACAPTPCONLY_V(x) ((x) << UPDBGLACAPTPCONLY_S) +#define UPDBGLACAPTPCONLY_F UPDBGLACAPTPCONLY_V(1U) + #endif /* __T4_REGS_H */ -- cgit v1.2.1 From 74b3092c45c3101bd110013ac7fb693b3c9231f3 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 7 Jan 2015 08:48:02 +0530 Subject: cxgb4: Add support for cim_qcfg entry in debugfs Adds debug log to get cim queue config Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 70 ++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 35 +++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 3 + drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 55 +++++++++++++++++ 5 files changed, 164 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 46cd506120d3..7c785b5e7757 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1041,6 +1041,7 @@ int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, const unsigned int *valp); int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr); +void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres); const char *t4_get_port_type_description(enum fw_port_type port_type); void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p); void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 0f7b23f15810..a8b02232c086 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -168,6 +168,75 @@ static const struct file_operations cim_la_fops = { .release = seq_release_private }; +static int cim_qcfg_show(struct seq_file *seq, void *v) +{ + static const char * const qname[] = { + "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI", + "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI", + "SGE0-RX", "SGE1-RX" + }; + + int i; + struct adapter *adap = seq->private; + u16 base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; + u16 size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; + u32 stat[(4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5))]; + u16 thres[CIM_NUM_IBQ]; + u32 obq_wr_t4[2 * CIM_NUM_OBQ], *wr; + u32 obq_wr_t5[2 * CIM_NUM_OBQ_T5]; + u32 *p = stat; + int cim_num_obq = is_t4(adap->params.chip) ? + CIM_NUM_OBQ : CIM_NUM_OBQ_T5; + + i = t4_cim_read(adap, is_t4(adap->params.chip) ? UP_IBQ_0_RDADDR_A : + UP_IBQ_0_SHADOW_RDADDR_A, + ARRAY_SIZE(stat), stat); + if (!i) { + if (is_t4(adap->params.chip)) { + i = t4_cim_read(adap, UP_OBQ_0_REALADDR_A, + ARRAY_SIZE(obq_wr_t4), obq_wr_t4); + wr = obq_wr_t4; + } else { + i = t4_cim_read(adap, UP_OBQ_0_SHADOW_REALADDR_A, + ARRAY_SIZE(obq_wr_t5), obq_wr_t5); + wr = obq_wr_t5; + } + } + if (i) + return i; + + t4_read_cimq_cfg(adap, base, size, thres); + + seq_printf(seq, + " Queue Base Size Thres RdPtr WrPtr SOP EOP Avail\n"); + for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) + seq_printf(seq, "%7s %5x %5u %5u %6x %4x %4u %4u %5u\n", + qname[i], base[i], size[i], thres[i], + IBQRDADDR_G(p[0]), IBQWRADDR_G(p[1]), + QUESOPCNT_G(p[3]), QUEEOPCNT_G(p[3]), + QUEREMFLITS_G(p[2]) * 16); + for ( ; i < CIM_NUM_IBQ + cim_num_obq; i++, p += 4, wr += 2) + seq_printf(seq, "%7s %5x %5u %12x %4x %4u %4u %5u\n", + qname[i], base[i], size[i], + QUERDADDR_G(p[0]) & 0x3fff, wr[0] - base[i], + QUESOPCNT_G(p[3]), QUEEOPCNT_G(p[3]), + QUEREMFLITS_G(p[2]) * 16); + return 0; +} + +static int cim_qcfg_open(struct inode *inode, struct file *file) +{ + return single_open(file, cim_qcfg_show, inode->i_private); +} + +static const struct file_operations cim_qcfg_fops = { + .owner = THIS_MODULE, + .open = cim_qcfg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* Firmware Device Log dump. */ static const char * const devlog_level_strings[] = { [FW_DEVLOG_LEVEL_EMERG] = "EMERG", @@ -443,6 +512,7 @@ int t4_setup_debugfs(struct adapter *adap) static struct t4_debugfs_entry t4_debugfs_files[] = { { "cim_la", &cim_la_fops, S_IRUSR, 0 }, + { "cim_qcfg", &cim_qcfg_fops, S_IRUSR, 0 }, { "devlog", &devlog_fops, S_IRUSR, 0 }, { "l2t", &t4_l2t_fops, S_IRUSR, 0}, }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 1e30554f2699..734d33e3f53b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -4325,6 +4325,41 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf) return 0; } +/** + * t4_read_cimq_cfg - read CIM queue configuration + * @adap: the adapter + * @base: holds the queue base addresses in bytes + * @size: holds the queue sizes in bytes + * @thres: holds the queue full thresholds in bytes + * + * Returns the current configuration of the CIM queues, starting with + * the IBQs, then the OBQs. + */ +void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres) +{ + unsigned int i, v; + int cim_num_obq = is_t4(adap->params.chip) ? + CIM_NUM_OBQ : CIM_NUM_OBQ_T5; + + for (i = 0; i < CIM_NUM_IBQ; i++) { + t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, IBQSELECT_F | + QUENUMSELECT_V(i)); + v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); + /* value is in 256-byte units */ + *base++ = CIMQBASE_G(v) * 256; + *size++ = CIMQSIZE_G(v) * 256; + *thres++ = QUEFULLTHRSH_G(v) * 8; /* 8-byte unit */ + } + for (i = 0; i < cim_num_obq; i++) { + t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F | + QUENUMSELECT_V(i)); + v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); + /* value is in 256-byte units */ + *base++ = CIMQBASE_G(v) * 256; + *size++ = CIMQSIZE_G(v) * 256; + } +} + /** * t4_cim_read - read a block from CIM internal address space * @adap: the adapter diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index bcc925b20088..f6b82da350e2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -56,6 +56,9 @@ enum { }; enum { + CIM_NUM_IBQ = 6, /* # of CIM IBQs */ + CIM_NUM_OBQ = 6, /* # of CIM OBQs */ + CIM_NUM_OBQ_T5 = 8, /* # of CIM OBQs for T5 adapter */ CIMLA_SIZE = 2048, /* # of 32-bit words in CIM LA */ }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 3fe6eeb3a55e..a2cae0e82a53 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -2096,4 +2096,59 @@ #define UPDBGLACAPTPCONLY_V(x) ((x) << UPDBGLACAPTPCONLY_S) #define UPDBGLACAPTPCONLY_F UPDBGLACAPTPCONLY_V(1U) +#define CIM_QUEUE_CONFIG_REF_A 0x7b48 +#define CIM_QUEUE_CONFIG_CTRL_A 0x7b4c + +#define CIMQSIZE_S 24 +#define CIMQSIZE_M 0x3fU +#define CIMQSIZE_G(x) (((x) >> CIMQSIZE_S) & CIMQSIZE_M) + +#define CIMQBASE_S 16 +#define CIMQBASE_M 0x3fU +#define CIMQBASE_G(x) (((x) >> CIMQBASE_S) & CIMQBASE_M) + +#define QUEFULLTHRSH_S 0 +#define QUEFULLTHRSH_M 0x1ffU +#define QUEFULLTHRSH_G(x) (((x) >> QUEFULLTHRSH_S) & QUEFULLTHRSH_M) + +#define UP_IBQ_0_RDADDR_A 0x10 +#define UP_IBQ_0_SHADOW_RDADDR_A 0x280 +#define UP_OBQ_0_REALADDR_A 0x104 +#define UP_OBQ_0_SHADOW_REALADDR_A 0x394 + +#define IBQRDADDR_S 0 +#define IBQRDADDR_M 0x1fffU +#define IBQRDADDR_G(x) (((x) >> IBQRDADDR_S) & IBQRDADDR_M) + +#define IBQWRADDR_S 0 +#define IBQWRADDR_M 0x1fffU +#define IBQWRADDR_G(x) (((x) >> IBQWRADDR_S) & IBQWRADDR_M) + +#define QUERDADDR_S 0 +#define QUERDADDR_M 0x7fffU +#define QUERDADDR_G(x) (((x) >> QUERDADDR_S) & QUERDADDR_M) + +#define QUEREMFLITS_S 0 +#define QUEREMFLITS_M 0x7ffU +#define QUEREMFLITS_G(x) (((x) >> QUEREMFLITS_S) & QUEREMFLITS_M) + +#define QUEEOPCNT_S 16 +#define QUEEOPCNT_M 0xfffU +#define QUEEOPCNT_G(x) (((x) >> QUEEOPCNT_S) & QUEEOPCNT_M) + +#define QUESOPCNT_S 0 +#define QUESOPCNT_M 0xfffU +#define QUESOPCNT_G(x) (((x) >> QUESOPCNT_S) & QUESOPCNT_M) + +#define OBQSELECT_S 4 +#define OBQSELECT_V(x) ((x) << OBQSELECT_S) +#define OBQSELECT_F OBQSELECT_V(1U) + +#define IBQSELECT_S 3 +#define IBQSELECT_V(x) ((x) << IBQSELECT_S) +#define IBQSELECT_F IBQSELECT_V(1U) + +#define QUENUMSELECT_S 0 +#define QUENUMSELECT_V(x) ((x) << QUENUMSELECT_S) + #endif /* __T4_REGS_H */ -- cgit v1.2.1 From ef82f662ba9454e1ccc193cd9d9b8a8a09ec2a43 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 7 Jan 2015 08:48:03 +0530 Subject: cxgb4: Add support for mps_tcam debugfs Debug log to get the MPS TCAM table Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 131 +++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 60 ++++++++++ 2 files changed, 191 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index a8b02232c086..e9f348942eb0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -433,6 +433,136 @@ static const struct file_operations devlog_fops = { .release = seq_release_private }; +static inline void tcamxy2valmask(u64 x, u64 y, u8 *addr, u64 *mask) +{ + *mask = x | y; + y = (__force u64)cpu_to_be64(y); + memcpy(addr, (char *)&y + 2, ETH_ALEN); +} + +static int mps_tcam_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_puts(seq, "Idx Ethernet address Mask Vld Ports PF" + " VF Replication " + "P0 P1 P2 P3 ML\n"); + else { + u64 mask; + u8 addr[ETH_ALEN]; + struct adapter *adap = seq->private; + unsigned int idx = (uintptr_t)v - 2; + u64 tcamy = t4_read_reg64(adap, MPS_CLS_TCAM_Y_L(idx)); + u64 tcamx = t4_read_reg64(adap, MPS_CLS_TCAM_X_L(idx)); + u32 cls_lo = t4_read_reg(adap, MPS_CLS_SRAM_L(idx)); + u32 cls_hi = t4_read_reg(adap, MPS_CLS_SRAM_H(idx)); + u32 rplc[4] = {0, 0, 0, 0}; + + if (tcamx & tcamy) { + seq_printf(seq, "%3u -\n", idx); + goto out; + } + + if (cls_lo & REPLICATE_F) { + struct fw_ldst_cmd ldst_cmd; + int ret; + + memset(&ldst_cmd, 0, sizeof(ldst_cmd)); + ldst_cmd.op_to_addrspace = + htonl(FW_CMD_OP_V(FW_LDST_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_READ_F | + FW_LDST_CMD_ADDRSPACE_V( + FW_LDST_ADDRSPC_MPS)); + ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd)); + ldst_cmd.u.mps.fid_ctl = + htons(FW_LDST_CMD_FID_V(FW_LDST_MPS_RPLC) | + FW_LDST_CMD_CTL_V(idx)); + ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd, + sizeof(ldst_cmd), &ldst_cmd); + if (ret) + dev_warn(adap->pdev_dev, "Can't read MPS " + "replication map for idx %d: %d\n", + idx, -ret); + else { + rplc[0] = ntohl(ldst_cmd.u.mps.rplc31_0); + rplc[1] = ntohl(ldst_cmd.u.mps.rplc63_32); + rplc[2] = ntohl(ldst_cmd.u.mps.rplc95_64); + rplc[3] = ntohl(ldst_cmd.u.mps.rplc127_96); + } + } + + tcamxy2valmask(tcamx, tcamy, addr, &mask); + seq_printf(seq, "%3u %02x:%02x:%02x:%02x:%02x:%02x %012llx" + "%3c %#x%4u%4d", + idx, addr[0], addr[1], addr[2], addr[3], addr[4], + addr[5], (unsigned long long)mask, + (cls_lo & SRAM_VLD_F) ? 'Y' : 'N', PORTMAP_G(cls_hi), + PF_G(cls_lo), + (cls_lo & VF_VALID_F) ? VF_G(cls_lo) : -1); + if (cls_lo & REPLICATE_F) + seq_printf(seq, " %08x %08x %08x %08x", + rplc[3], rplc[2], rplc[1], rplc[0]); + else + seq_printf(seq, "%36c", ' '); + seq_printf(seq, "%4u%3u%3u%3u %#x\n", + SRAM_PRIO0_G(cls_lo), SRAM_PRIO1_G(cls_lo), + SRAM_PRIO2_G(cls_lo), SRAM_PRIO3_G(cls_lo), + (cls_lo >> MULTILISTEN0_S) & 0xf); + } +out: return 0; +} + +static inline void *mps_tcam_get_idx(struct seq_file *seq, loff_t pos) +{ + struct adapter *adap = seq->private; + int max_mac_addr = is_t4(adap->params.chip) ? + NUM_MPS_CLS_SRAM_L_INSTANCES : + NUM_MPS_T5_CLS_SRAM_L_INSTANCES; + return ((pos <= max_mac_addr) ? (void *)(uintptr_t)(pos + 1) : NULL); +} + +static void *mps_tcam_start(struct seq_file *seq, loff_t *pos) +{ + return *pos ? mps_tcam_get_idx(seq, *pos) : SEQ_START_TOKEN; +} + +static void *mps_tcam_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return mps_tcam_get_idx(seq, *pos); +} + +static void mps_tcam_stop(struct seq_file *seq, void *v) +{ +} + +static const struct seq_operations mps_tcam_seq_ops = { + .start = mps_tcam_start, + .next = mps_tcam_next, + .stop = mps_tcam_stop, + .show = mps_tcam_show +}; + +static int mps_tcam_open(struct inode *inode, struct file *file) +{ + int res = seq_open(file, &mps_tcam_seq_ops); + + if (!res) { + struct seq_file *seq = file->private_data; + + seq->private = inode->i_private; + } + return res; +} + +static const struct file_operations mps_tcam_debugfs_fops = { + .owner = THIS_MODULE, + .open = mps_tcam_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static ssize_t mem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -515,6 +645,7 @@ int t4_setup_debugfs(struct adapter *adap) { "cim_qcfg", &cim_qcfg_fops, S_IRUSR, 0 }, { "devlog", &devlog_fops, S_IRUSR, 0 }, { "l2t", &t4_l2t_fops, S_IRUSR, 0}, + { "mps_tcam", &mps_tcam_debugfs_fops, S_IRUSR, 0 }, }; add_debugfs_files(adap, diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index a2cae0e82a53..7ce55f9be9d4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1708,6 +1708,66 @@ #define MPS_RX_PERR_INT_CAUSE_A 0x11074 +#define MPS_CLS_TCAM_Y_L_A 0xf000 +#define MPS_CLS_TCAM_X_L_A 0xf008 + +#define MPS_CLS_TCAM_Y_L(idx) (MPS_CLS_TCAM_Y_L_A + (idx) * 16) +#define NUM_MPS_CLS_TCAM_Y_L_INSTANCES 512 + +#define MPS_CLS_TCAM_X_L(idx) (MPS_CLS_TCAM_X_L_A + (idx) * 16) +#define NUM_MPS_CLS_TCAM_X_L_INSTANCES 512 + +#define MPS_CLS_SRAM_L_A 0xe000 +#define MPS_CLS_SRAM_H_A 0xe004 + +#define MPS_CLS_SRAM_L(idx) (MPS_CLS_SRAM_L_A + (idx) * 8) +#define NUM_MPS_CLS_SRAM_L_INSTANCES 336 + +#define MPS_CLS_SRAM_H(idx) (MPS_CLS_SRAM_H_A + (idx) * 8) +#define NUM_MPS_CLS_SRAM_H_INSTANCES 336 + +#define MULTILISTEN0_S 25 + +#define REPLICATE_S 11 +#define REPLICATE_V(x) ((x) << REPLICATE_S) +#define REPLICATE_F REPLICATE_V(1U) + +#define PF_S 8 +#define PF_M 0x7U +#define PF_G(x) (((x) >> PF_S) & PF_M) + +#define VF_VALID_S 7 +#define VF_VALID_V(x) ((x) << VF_VALID_S) +#define VF_VALID_F VF_VALID_V(1U) + +#define VF_S 0 +#define VF_M 0x7fU +#define VF_G(x) (((x) >> VF_S) & VF_M) + +#define SRAM_PRIO3_S 22 +#define SRAM_PRIO3_M 0x7U +#define SRAM_PRIO3_G(x) (((x) >> SRAM_PRIO3_S) & SRAM_PRIO3_M) + +#define SRAM_PRIO2_S 19 +#define SRAM_PRIO2_M 0x7U +#define SRAM_PRIO2_G(x) (((x) >> SRAM_PRIO2_S) & SRAM_PRIO2_M) + +#define SRAM_PRIO1_S 16 +#define SRAM_PRIO1_M 0x7U +#define SRAM_PRIO1_G(x) (((x) >> SRAM_PRIO1_S) & SRAM_PRIO1_M) + +#define SRAM_PRIO0_S 13 +#define SRAM_PRIO0_M 0x7U +#define SRAM_PRIO0_G(x) (((x) >> SRAM_PRIO0_S) & SRAM_PRIO0_M) + +#define SRAM_VLD_S 12 +#define SRAM_VLD_V(x) ((x) << SRAM_VLD_S) +#define SRAM_VLD_F SRAM_VLD_V(1U) + +#define PORTMAP_S 0 +#define PORTMAP_M 0xfU +#define PORTMAP_G(x) (((x) >> PORTMAP_S) & PORTMAP_M) + #define CPL_INTR_CAUSE_A 0x19054 #define CIM_OP_MAP_PERR_S 5 -- cgit v1.2.1 From 0bec3b700d106a8b0a34227b2976d1a582f1aab7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 7 Jan 2015 10:49:49 +0100 Subject: r8169: add support for xmit_more Delay update of hw tail descriptor if we know that another skb is going to be sent. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 14a1c5cec3a5..3a280598a15a 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -7049,6 +7049,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, u32 status, len; u32 opts[2]; int frags; + bool stop_queue; if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) { netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n"); @@ -7105,11 +7106,16 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, tp->cur_tx += frags + 1; - RTL_W8(TxPoll, NPQ); + stop_queue = !TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS); - mmiowb(); + if (!skb->xmit_more || stop_queue || + netif_xmit_stopped(netdev_get_tx_queue(dev, 0))) { + RTL_W8(TxPoll, NPQ); + + mmiowb(); + } - if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) { + if (stop_queue) { /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must * not miss a ring update when it notices a stopped queue. */ -- cgit v1.2.1 From a809ca5e03c6dd3b324d148564715ca5ea2b8103 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 9 Jan 2015 11:29:50 +0100 Subject: mac80211_hwsim: fix PS debugfs file locking The functions called within the iterators must be called with tasklets disabled, so use atomic iteration like the rest of the code and disable tasklets around the whole operation. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 057a99e01637..74f4e1c18322 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -626,22 +626,22 @@ static int hwsim_fops_ps_write(void *dat, u64 val) old_ps = data->ps; data->ps = val; + local_bh_disable(); if (val == PS_MANUAL_POLL) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_ps_poll, data); + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_ps_poll, data); data->ps_poll_pending = true; } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_nullfunc_ps, - data); + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_nullfunc_ps, data); } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_nullfunc_no_ps, - data); + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_nullfunc_no_ps, data); } + local_bh_enable(); return 0; } -- cgit v1.2.1 From d6b984816b902c73b2273c6088f52660a54c2034 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 29 Dec 2014 08:24:01 +0200 Subject: wlcore: fix WLCORE_VENDOR_ATTR_GROUP_KEY policy The attribute type is binary data (with max length). Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/vendor_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c index ad86a48dcfcb..fd4e9ba176c9 100644 --- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c @@ -21,7 +21,7 @@ static const struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = { [WLCORE_VENDOR_ATTR_FREQ] = { .type = NLA_U32 }, [WLCORE_VENDOR_ATTR_GROUP_ID] = { .type = NLA_U32 }, - [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_U32, + [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, }; -- cgit v1.2.1 From 16129d1d59be0f330f80b33fef8a7a7d7b18394d Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 29 Dec 2014 08:24:02 +0200 Subject: wlcore: fix sparse warning Use kstrtoul_from_user() for reading the user value, and fix the following sparse warning: drivers/net/wireless/ti/wlcore/debugfs.c:937:15: error: incompatible types in comparison expression (different type sizes) Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/debugfs.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index 0be21f62fcb0..68f3bf229b5a 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -929,17 +929,10 @@ static ssize_t beacon_filtering_write(struct file *file, { struct wl1271 *wl = file->private_data; struct wl12xx_vif *wlvif; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 0, &value); if (ret < 0) { wl1271_warning("illegal value for beacon_filtering!"); return -EINVAL; -- cgit v1.2.1 From 7d3b29e5c86e0da38052d33fdd1f195d4591c6b2 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 29 Dec 2014 08:24:03 +0200 Subject: wlcore/wl18xx: handle rc updates in a separate work sta_rc_update runs in atomic context. thus, a new work should be scheduled in order to configure the fw with the required configuration. Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/main.c | 18 ++++------------ drivers/net/wireless/ti/wlcore/hw_ops.h | 5 ++--- drivers/net/wireless/ti/wlcore/main.c | 35 +++++++++++++++++++++++++++++-- drivers/net/wireless/ti/wlcore/wlcore.h | 3 +-- drivers/net/wireless/ti/wlcore/wlcore_i.h | 4 ++++ 5 files changed, 44 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 8e562610bf16..96dbe71662c1 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1559,26 +1559,19 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl, } static void wl18xx_sta_rc_update(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, - u32 changed) + struct wl12xx_vif *wlvif) { - bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40; + bool wide = wlvif->rc_update_bw >= IEEE80211_STA_RX_BW_40; wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); - if (!(changed & IEEE80211_RC_BW_CHANGED)) - return; - - mutex_lock(&wl->mutex); - /* sanity */ if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS)) - goto out; + return; /* ignore the change before association */ if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - goto out; + return; /* * If we started out as wide, we can change the operation mode. If we @@ -1589,9 +1582,6 @@ static void wl18xx_sta_rc_update(struct wl1271 *wl, wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide); else ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif)); - -out: - mutex_unlock(&wl->mutex); } static int wl18xx_set_peer_cap(struct wl1271 *wl, diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index aa9f82c72296..29ce55ff8823 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -211,11 +211,10 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len) } static inline void -wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, u32 changed) +wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif) { if (wl->ops->sta_rc_update) - wl->ops->sta_rc_update(wl, wlvif, sta, changed); + wl->ops->sta_rc_update(wl, wlvif); } static inline int diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 6ad3fcedab9b..7b32b4536fff 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -226,6 +226,29 @@ void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl) msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout)); } +static void wlcore_rc_update_work(struct work_struct *work) +{ + int ret; + struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, + rc_update_work); + struct wl1271 *wl = wlvif->wl; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wlcore_hw_sta_rc_update(wl, wlvif); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + static void wl12xx_tx_watchdog_work(struct work_struct *work) { struct delayed_work *dwork; @@ -2279,6 +2302,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) wl1271_rx_streaming_enable_work); INIT_WORK(&wlvif->rx_streaming_disable_work, wl1271_rx_streaming_disable_work); + INIT_WORK(&wlvif->rc_update_work, wlcore_rc_update_work); INIT_DELAYED_WORK(&wlvif->channel_switch_work, wlcore_channel_switch_work); INIT_DELAYED_WORK(&wlvif->connection_loss_work, @@ -2723,6 +2747,7 @@ unlock: del_timer_sync(&wlvif->rx_streaming_timer); cancel_work_sync(&wlvif->rx_streaming_enable_work); cancel_work_sync(&wlvif->rx_streaming_disable_work); + cancel_work_sync(&wlvif->rc_update_work); cancel_delayed_work_sync(&wlvif->connection_loss_work); cancel_delayed_work_sync(&wlvif->channel_switch_work); cancel_delayed_work_sync(&wlvif->pending_auth_complete_work); @@ -5370,9 +5395,15 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw, u32 changed) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct wl1271 *wl = hw->priv; - wlcore_hw_sta_rc_update(wl, wlvif, sta, changed); + wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update"); + + if (!(changed & IEEE80211_RC_BW_CHANGED)) + return; + + /* this callback is atomic, so schedule a new work */ + wlvif->rc_update_bw = sta->bandwidth; + ieee80211_queue_work(hw, &wlvif->rc_update_work); } static int wlcore_op_get_rssi(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index df78cf12ef15..2440ebe8a8d6 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -106,8 +106,7 @@ struct wlcore_ops { struct wl12xx_vif *wlvif, struct ieee80211_channel_switch *ch_switch); u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len); - void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, u32 changed); + void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif); int (*set_peer_cap)(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, bool allow_ht_operation, diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 0e52556044d9..811851d00b33 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -463,6 +463,10 @@ struct wl12xx_vif { /* work for canceling ROC after pending auth reply */ struct delayed_work pending_auth_complete_work; + /* update rate conrol */ + enum ieee80211_sta_rx_bandwidth rc_update_bw; + struct work_struct rc_update_work; + /* * total freed FW packets on the link. * For STA this holds the PN of the link to the AP. -- cgit v1.2.1 From 6d5a748d4836ddd0ca626fe4870942a0e90a5c3d Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Mon, 29 Dec 2014 08:24:04 +0200 Subject: wlcore: add ability to reduce FW interrupts during suspend Add the ability to mask FW interrupts on RX BA activity, PSM entry/exit and fast-link notifications. This is used when the host is suspended in order to decrease redundant wake ups. Signed-off-by: Ram Amrani Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl12xx/main.c | 3 ++ drivers/net/wireless/ti/wl18xx/acx.c | 56 +++++++++++++++++++++++++++ drivers/net/wireless/ti/wl18xx/acx.h | 25 +++++++++++- drivers/net/wireless/ti/wl18xx/main.c | 3 ++ drivers/net/wireless/ti/wlcore/conf.h | 7 +++- drivers/net/wireless/ti/wlcore/hw_ops.h | 16 ++++++++ drivers/net/wireless/ti/wlcore/main.c | 68 ++++++++++++++++++++++----------- drivers/net/wireless/ti/wlcore/wlcore.h | 2 + 8 files changed, 155 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index d6d0d6d9c7a8..f3cee5ad7026 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -250,6 +250,7 @@ static struct wlcore_conf wl12xx_conf = { .keep_alive_interval = 55000, .max_listen_interval = 20, .sta_sleep_auth = WL1271_PSM_ILLEGAL, + .suspend_rx_ba_activity = 0, }, .itrim = { .enable = false, @@ -1728,6 +1729,8 @@ static struct wlcore_ops wl12xx_ops = { .convert_hwaddr = wl12xx_convert_hwaddr, .lnk_high_prio = wl12xx_lnk_high_prio, .lnk_low_prio = wl12xx_lnk_low_prio, + .interrupt_notify = NULL, + .rx_ba_filter = NULL, }; static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c index a169bb5a5dbf..9d4b9aacd037 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.c +++ b/drivers/net/wireless/ti/wl18xx/acx.c @@ -194,3 +194,59 @@ out: kfree(acx); return ret; } + +/* + * When the host is suspended, we don't want to get any fast-link/PSM + * notifications + */ +int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, + bool action) +{ + struct wl18xx_acx_interrupt_notify *acx; + int ret = 0; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->enable = action; + ret = wl1271_cmd_configure(wl, ACX_INTERRUPT_NOTIFY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx interrupt notify setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +/* + * When the host is suspended, we can configure the FW to disable RX BA + * notifications. + */ +int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action) +{ + struct wl18xx_acx_rx_ba_filter *acx; + int ret = 0; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->enable = (u32)action; + ret = wl1271_cmd_configure(wl, ACX_RX_BA_FILTER, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx rx ba activity filter setting failed: %d", + ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index 0e636def1217..1234bdc6d1b9 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h @@ -32,7 +32,10 @@ enum { ACX_SIM_CONFIG = 0x0053, ACX_CLEAR_STATISTICS = 0x0054, ACX_AUTO_RX_STREAMING = 0x0055, - ACX_PEER_CAP = 0x0056 + ACX_PEER_CAP = 0x0056, + ACX_INTERRUPT_NOTIFY = 0x0057, + ACX_RX_BA_FILTER = 0x0058 + }; /* numbers of bits the length field takes (add 1 for the actual number) */ @@ -326,6 +329,24 @@ struct wlcore_acx_peer_cap { u8 padding; } __packed; +/* + * ACX_INTERRUPT_NOTIFY + * enable/disable fast-link/PSM notification from FW + */ +struct wl18xx_acx_interrupt_notify { + struct acx_header header; + u32 enable; +}; + +/* + * ACX_RX_BA_FILTER + * enable/disable RX BA filtering in FW + */ +struct wl18xx_acx_rx_ba_filter { + struct acx_header header; + u32 enable; +}; + int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, u32 sdio_blk_size, u32 extra_mem_blks, u32 len_field_size); @@ -336,5 +357,7 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, bool allow_ht_operation, u32 rate_set, u8 hlid); +int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action); +int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action); #endif /* __WL18XX_ACX_H__ */ diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 96dbe71662c1..6c1000d1735b 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -378,6 +378,7 @@ static struct wlcore_conf wl18xx_conf = { .keep_alive_interval = 55000, .max_listen_interval = 20, .sta_sleep_auth = WL1271_PSM_ILLEGAL, + .suspend_rx_ba_activity = 0, }, .itrim = { .enable = false, @@ -1693,6 +1694,8 @@ static struct wlcore_ops wl18xx_ops = { .smart_config_start = wl18xx_cmd_smart_config_start, .smart_config_stop = wl18xx_cmd_smart_config_stop, .smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key, + .interrupt_notify = wl18xx_acx_interrupt_notify_config, + .rx_ba_filter = wl18xx_acx_rx_ba_filter, }; /* HT cap appropriate for wide channels in 2Ghz */ diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h index 40995c42bef8..166add00b50f 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h @@ -997,6 +997,11 @@ struct conf_conn_settings { * whether we can go to ELP. */ u8 sta_sleep_auth; + + /* + * Default RX BA Activity filter configuration + */ + u8 suspend_rx_ba_activity; } __packed; enum { @@ -1347,7 +1352,7 @@ struct conf_recovery_settings { * version, the two LSB are the lower driver's private conf * version. */ -#define WLCORE_CONF_VERSION (0x0005 << 16) +#define WLCORE_CONF_VERSION (0x0006 << 16) #define WLCORE_CONF_MASK 0xffff0000 #define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \ sizeof(struct wlcore_conf)) diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index 29ce55ff8823..c2545ce6b2db 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -217,6 +217,22 @@ wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif) wl->ops->sta_rc_update(wl, wlvif); } +static inline int +wlcore_hw_interrupt_notify(struct wl1271 *wl, bool action) +{ + if (wl->ops->interrupt_notify) + return wl->ops->interrupt_notify(wl, action); + return 0; +} + +static inline int +wlcore_hw_rx_ba_filter(struct wl1271 *wl, bool action) +{ + if (wl->ops->rx_ba_filter) + return wl->ops->rx_ba_filter(wl, action); + return 0; +} + static inline int wlcore_hw_set_peer_cap(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 7b32b4536fff..de3bf781be6e 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1685,19 +1685,15 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - ret = wl1271_configure_wowlan(wl, wow); if (ret < 0) - goto out_sleep; + goto out; if ((wl->conf.conn.suspend_wake_up_event == wl->conf.conn.wake_up_event) && (wl->conf.conn.suspend_listen_interval == wl->conf.conn.listen_interval)) - goto out_sleep; + goto out; ret = wl1271_acx_wake_up_conditions(wl, wlvif, wl->conf.conn.suspend_wake_up_event, @@ -1705,9 +1701,6 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, if (ret < 0) wl1271_error("suspend: set wake up conditions failed: %d", ret); - -out_sleep: - wl1271_ps_elp_sleep(wl); out: return ret; @@ -1721,13 +1714,8 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl, if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); - wl1271_ps_elp_sleep(wl); out: return ret; @@ -1756,10 +1744,6 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif) if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) return; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - return; - if (is_sta) { wl1271_configure_wowlan(wl, NULL); @@ -1767,7 +1751,7 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif) wl->conf.conn.wake_up_event) && (wl->conf.conn.suspend_listen_interval == wl->conf.conn.listen_interval)) - goto out_sleep; + return; ret = wl1271_acx_wake_up_conditions(wl, wlvif, wl->conf.conn.wake_up_event, @@ -1780,9 +1764,6 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif) } else if (is_ap) { ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); } - -out_sleep: - wl1271_ps_elp_sleep(wl); } static int wl1271_op_suspend(struct ieee80211_hw *hw, @@ -1804,6 +1785,11 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, wl1271_tx_flush(wl); mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + return ret; + wl->wow_enabled = true; wl12xx_for_each_wlvif(wl, wlvif) { ret = wl1271_configure_suspend(wl, wlvif, wow); @@ -1813,7 +1799,27 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, return ret; } } + + /* disable fast link flow control notifications from FW */ + ret = wlcore_hw_interrupt_notify(wl, false); + if (ret < 0) + goto out_sleep; + + /* if filtering is enabled, configure the FW to drop all RX BA frames */ + ret = wlcore_hw_rx_ba_filter(wl, + !!wl->conf.conn.suspend_rx_ba_activity); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl1271_warning("couldn't prepare device to suspend"); + return ret; + } + /* flush any remaining work */ wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); @@ -1887,13 +1893,29 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) if (pending_recovery) { wl1271_warning("queuing forgotten recovery on resume"); ieee80211_queue_work(wl->hw, &wl->recovery_work); - goto out; + goto out_sleep; } + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + wl12xx_for_each_wlvif(wl, wlvif) { wl1271_configure_resume(wl, wlvif); } + ret = wlcore_hw_interrupt_notify(wl, true); + if (ret < 0) + goto out_sleep; + + /* if filtering is enabled, configure the FW to drop all RX BA frames */ + ret = wlcore_hw_rx_ba_filter(wl, false); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + out: wl->wow_enabled = false; diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 2440ebe8a8d6..7860a4e1d791 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -116,6 +116,8 @@ struct wlcore_ops { struct wl1271_link *lnk); bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid, struct wl1271_link *lnk); + int (*interrupt_notify)(struct wl1271 *wl, bool action); + int (*rx_ba_filter)(struct wl1271 *wl, bool action); int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap); int (*smart_config_stop)(struct wl1271 *wl); int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id, -- cgit v1.2.1 From b8714d1b6a7ee4c4e4730203a90e1db6485d9343 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 29 Dec 2014 08:24:05 +0200 Subject: wlcore: enable AP wowlan configure wowlan when host is suspended in AP mode, since the FW can now wake the host up on Rx. Signed-off-by: Kobi Leibovitch Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/main.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index de3bf781be6e..caff69966ce1 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1707,7 +1707,8 @@ out: } static int wl1271_configure_suspend_ap(struct wl1271 *wl, - struct wl12xx_vif *wlvif) + struct wl12xx_vif *wlvif, + struct cfg80211_wowlan *wow) { int ret = 0; @@ -1715,6 +1716,12 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl, goto out; ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); + if (ret < 0) + goto out; + + ret = wl1271_configure_wowlan(wl, wow); + if (ret < 0) + goto out; out: return ret; @@ -1728,7 +1735,7 @@ static int wl1271_configure_suspend(struct wl1271 *wl, if (wlvif->bss_type == BSS_TYPE_STA_BSS) return wl1271_configure_suspend_sta(wl, wlvif, wow); if (wlvif->bss_type == BSS_TYPE_AP_BSS) - return wl1271_configure_suspend_ap(wl, wlvif); + return wl1271_configure_suspend_ap(wl, wlvif, wow); return 0; } @@ -1741,12 +1748,13 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif) if ((!is_ap) && (!is_sta)) return; - if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + if ((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) || + (is_ap && !test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))) return; - if (is_sta) { - wl1271_configure_wowlan(wl, NULL); + wl1271_configure_wowlan(wl, NULL); + if (is_sta) { if ((wl->conf.conn.suspend_wake_up_event == wl->conf.conn.wake_up_event) && (wl->conf.conn.suspend_listen_interval == -- cgit v1.2.1 From e2f1e50f62ae70c7ddde8420ed586c6a1aa1e28c Mon Sep 17 00:00:00 2001 From: Kobi L Date: Mon, 29 Dec 2014 08:24:06 +0200 Subject: wlcore: enable sleep during AP mode operation Enable ELP authorization in AP mode and enable the use of the wakeup bit in the ELP register. Introduce AP role sleep configuration which is disabled by default. When configured, it allows the AP to sleep when ELP is authorized for it. Signed-off-by: Kobi Leibovitch Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl12xx/main.c | 1 + drivers/net/wireless/ti/wl18xx/acx.c | 32 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ti/wl18xx/acx.h | 25 +++++++++++++++++++++++-- drivers/net/wireless/ti/wl18xx/conf.h | 23 ++++++++++++++++++++++- drivers/net/wireless/ti/wl18xx/main.c | 7 +++++++ drivers/net/wireless/ti/wlcore/hw_ops.h | 9 +++++++++ drivers/net/wireless/ti/wlcore/init.c | 8 ++++++-- drivers/net/wireless/ti/wlcore/ps.c | 6 ------ drivers/net/wireless/ti/wlcore/wlcore.h | 1 + 9 files changed, 101 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index f3cee5ad7026..144d1f8ba473 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -1731,6 +1731,7 @@ static struct wlcore_ops wl12xx_ops = { .lnk_low_prio = wl12xx_lnk_low_prio, .interrupt_notify = NULL, .rx_ba_filter = NULL, + .ap_sleep = NULL, }; static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c index 9d4b9aacd037..67f2a0eec854 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.c +++ b/drivers/net/wireless/ti/wl18xx/acx.c @@ -24,6 +24,7 @@ #include "../wlcore/acx.h" #include "acx.h" +#include "wl18xx.h" int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, u32 sdio_blk_size, u32 extra_mem_blks, @@ -250,3 +251,34 @@ out: kfree(acx); return ret; } + +int wl18xx_acx_ap_sleep(struct wl1271 *wl) +{ + struct wl18xx_priv *priv = wl->priv; + struct acx_ap_sleep_cfg *acx; + struct conf_ap_sleep_settings *conf = &priv->conf.ap_sleep; + int ret; + + wl1271_debug(DEBUG_ACX, "acx config ap sleep"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->idle_duty_cycle = conf->idle_duty_cycle; + acx->connected_duty_cycle = conf->connected_duty_cycle; + acx->max_stations_thresh = conf->max_stations_thresh; + acx->idle_conn_thresh = conf->idle_conn_thresh; + + ret = wl1271_cmd_configure(wl, ACX_AP_SLEEP_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx config ap-sleep failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index 1234bdc6d1b9..4afccd4b9467 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h @@ -34,8 +34,8 @@ enum { ACX_AUTO_RX_STREAMING = 0x0055, ACX_PEER_CAP = 0x0056, ACX_INTERRUPT_NOTIFY = 0x0057, - ACX_RX_BA_FILTER = 0x0058 - + ACX_RX_BA_FILTER = 0x0058, + ACX_AP_SLEEP_CFG = 0x0059 }; /* numbers of bits the length field takes (add 1 for the actual number) */ @@ -347,6 +347,26 @@ struct wl18xx_acx_rx_ba_filter { u32 enable; }; +struct acx_ap_sleep_cfg { + struct acx_header header; + /* Duty Cycle (20-80% of staying Awake) for IDLE AP + * (0: disable) + */ + u8 idle_duty_cycle; + /* Duty Cycle (20-80% of staying Awake) for Connected AP + * (0: disable) + */ + u8 connected_duty_cycle; + /* Maximum stations that are allowed to be connected to AP + * (255: no limit) + */ + u8 max_stations_thresh; + /* Timeout till enabling the Sleep Mechanism after data stops + * [unit: 100 msec] + */ + u8 idle_conn_thresh; +} __packed; + int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, u32 sdio_blk_size, u32 extra_mem_blks, u32 len_field_size); @@ -359,5 +379,6 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl, u32 rate_set, u8 hlid); int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action); int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action); +int wl18xx_acx_ap_sleep(struct wl1271 *wl); #endif /* __WL18XX_ACX_H__ */ diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h index e34302e3b51d..71f1ec448ba5 100644 --- a/drivers/net/wireless/ti/wl18xx/conf.h +++ b/drivers/net/wireless/ti/wl18xx/conf.h @@ -23,7 +23,7 @@ #define __WL18XX_CONF_H__ #define WL18XX_CONF_MAGIC 0x10e100ca -#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0006) +#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0007) #define WL18XX_CONF_MASK 0x0000ffff #define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \ sizeof(struct wl18xx_priv_conf)) @@ -110,12 +110,33 @@ struct wl18xx_ht_settings { u8 mode; } __packed; +struct conf_ap_sleep_settings { + /* Duty Cycle (20-80% of staying Awake) for IDLE AP + * (0: disable) + */ + u8 idle_duty_cycle; + /* Duty Cycle (20-80% of staying Awake) for Connected AP + * (0: disable) + */ + u8 connected_duty_cycle; + /* Maximum stations that are allowed to be connected to AP + * (255: no limit) + */ + u8 max_stations_thresh; + /* Timeout till enabling the Sleep Mechanism after data stops + * [unit: 100 msec] + */ + u8 idle_conn_thresh; +} __packed; + struct wl18xx_priv_conf { /* Module params structures */ struct wl18xx_ht_settings ht; /* this structure is copied wholesale to FW */ struct wl18xx_mac_and_phy_params phy; + + struct conf_ap_sleep_settings ap_sleep; } __packed; #endif /* __WL18XX_CONF_H__ */ diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 6c1000d1735b..04db941e1913 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -568,6 +568,12 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = { .high_power_val_2nd = 0xff, .tx_rf_margin = 1, }, + .ap_sleep = { /* disabled by default */ + .idle_duty_cycle = 0, + .connected_duty_cycle = 0, + .max_stations_thresh = 0, + .idle_conn_thresh = 0, + }, }; static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = { @@ -1696,6 +1702,7 @@ static struct wlcore_ops wl18xx_ops = { .smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key, .interrupt_notify = wl18xx_acx_interrupt_notify_config, .rx_ba_filter = wl18xx_acx_rx_ba_filter, + .ap_sleep = wl18xx_acx_ap_sleep, }; /* HT cap appropriate for wide channels in 2Ghz */ diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index c2545ce6b2db..449050b5c750 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -233,6 +233,15 @@ wlcore_hw_rx_ba_filter(struct wl1271 *wl, bool action) return 0; } +static inline int +wlcore_hw_ap_sleep(struct wl1271 *wl) +{ + if (wl->ops->ap_sleep) + return wl->ops->ap_sleep(wl); + + return 0; +} + static inline int wlcore_hw_set_peer_cap(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index 199e94120864..5ca1fb161a50 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c @@ -392,6 +392,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) if (ret < 0) return ret; + /* configure AP sleep, if enabled */ + ret = wlcore_hw_ap_sleep(wl); + if (ret < 0) + return ret; + return 0; } @@ -567,8 +572,7 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) /* consider all existing roles before configuring psm. */ if (wl->ap_count == 0 && is_ap) { /* first AP */ - /* Configure for power always on */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); if (ret < 0) return ret; diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c index b52516eed7b2..f3ed543bfe73 100644 --- a/drivers/net/wireless/ti/wlcore/ps.c +++ b/drivers/net/wireless/ti/wlcore/ps.c @@ -56,9 +56,6 @@ void wl1271_elp_work(struct work_struct *work) goto out; wl12xx_for_each_wlvif(wl, wlvif) { - if (wlvif->bss_type == BSS_TYPE_AP_BSS) - goto out; - if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) goto out; @@ -95,9 +92,6 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) return; wl12xx_for_each_wlvif(wl, wlvif) { - if (wlvif->bss_type == BSS_TYPE_AP_BSS) - return; - if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) return; diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 7860a4e1d791..c8fe2ae272ac 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -118,6 +118,7 @@ struct wlcore_ops { struct wl1271_link *lnk); int (*interrupt_notify)(struct wl1271 *wl, bool action); int (*rx_ba_filter)(struct wl1271 *wl, bool action); + int (*ap_sleep)(struct wl1271 *wl); int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap); int (*smart_config_stop)(struct wl1271 *wl); int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id, -- cgit v1.2.1 From 750e9d15e2fe93fec696893be7b120b2940378d0 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 29 Dec 2014 08:24:07 +0200 Subject: wl18xx: add radar detection implementation Add support for CAC start/stop commands, and pass radar detection events from the fw to mac80211. Bump fw name (to wl18xx-fw-4.bin) and min fw version (to 8.9.*.*.11), and align event mailbox accordingly. Signed-off-by: Guy Mishol Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/cmd.c | 31 ++++++ drivers/net/wireless/ti/wl18xx/cmd.h | 11 +++ drivers/net/wireless/ti/wl18xx/event.c | 21 ++++ drivers/net/wireless/ti/wl18xx/event.h | 14 ++- drivers/net/wireless/ti/wl18xx/main.c | 4 +- drivers/net/wireless/ti/wl18xx/wl18xx.h | 4 +- drivers/net/wireless/ti/wlcore/cmd.c | 3 +- drivers/net/wireless/ti/wlcore/cmd.h | 6 ++ drivers/net/wireless/ti/wlcore/hw_ops.h | 9 ++ drivers/net/wireless/ti/wlcore/main.c | 159 +++++++++++++++++++++++++++++- drivers/net/wireless/ti/wlcore/wlcore.h | 2 + drivers/net/wireless/ti/wlcore/wlcore_i.h | 2 + 12 files changed, 257 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c index 44f0b205b065..10f9d1c064ba 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.c +++ b/drivers/net/wireless/ti/wl18xx/cmd.c @@ -167,3 +167,34 @@ out_free: out: return ret; } + +int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start) +{ + struct wlcore_cmd_cac_start *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd cac (channel %d) %s", + wlvif->channel, start ? "start" : "stop"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->role_id = wlvif->role_id; + cmd->channel = wlvif->channel; + if (wlvif->band == IEEE80211_BAND_5GHZ) + cmd->band = WLCORE_BAND_5GHZ; + cmd->bandwidth = wlcore_get_native_channel_type(wlvif->channel_type); + + ret = wl1271_cmd_send(wl, + start ? CMD_CAC_START : CMD_CAC_STOP, + cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send cac command"); + goto out_free; + } + +out_free: + kfree(cmd); + return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h index 92499e2dfa83..91b3e2fe77cd 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.h +++ b/drivers/net/wireless/ti/wl18xx/cmd.h @@ -59,6 +59,16 @@ struct wl18xx_cmd_smart_config_set_group_key { u8 key[16]; } __packed; +/* cac_start and cac_stop share the same params */ +struct wlcore_cmd_cac_start { + struct wl1271_cmd_header header; + + u8 role_id; + u8 channel; + u8 band; + u8 bandwidth; +} __packed; + int wl18xx_cmd_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_channel_switch *ch_switch); @@ -66,4 +76,5 @@ int wl18xx_cmd_smart_config_start(struct wl1271 *wl, u32 group_bitmap); int wl18xx_cmd_smart_config_stop(struct wl1271 *wl); int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, u8 key_len, u8 *key); +int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start); #endif diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c index eb1848e08424..c28f06854195 100644 --- a/drivers/net/wireless/ti/wl18xx/event.c +++ b/drivers/net/wireless/ti/wl18xx/event.c @@ -47,6 +47,19 @@ int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout); } +static const char *wl18xx_radar_type_decode(u8 radar_type) +{ + switch (radar_type) { + case RADAR_TYPE_REGULAR: + return "REGULAR"; + case RADAR_TYPE_CHIRP: + return "CHIRP"; + case RADAR_TYPE_NONE: + default: + return "N/A"; + } +} + static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel, u8 sync_band) { @@ -115,6 +128,14 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl) wl18xx_scan_completed(wl, wl->scan_wlvif); } + if (vector & RADAR_DETECTED_EVENT_ID) { + wl1271_info("radar event: channel %d type %s", + mbox->radar_channel, + wl18xx_radar_type_decode(mbox->radar_type)); + + ieee80211_radar_detected(wl->hw); + } + if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT (results %d)", diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h index 0680312d4943..266ee87834e4 100644 --- a/drivers/net/wireless/ti/wl18xx/event.h +++ b/drivers/net/wireless/ti/wl18xx/event.h @@ -42,6 +42,12 @@ enum { SMART_CONFIG_DECODE_EVENT_ID = BIT(23), }; +enum wl18xx_radar_types { + RADAR_TYPE_NONE, + RADAR_TYPE_REGULAR, + RADAR_TYPE_CHIRP +}; + struct wl18xx_event_mailbox { __le32 events_vector; @@ -83,13 +89,19 @@ struct wl18xx_event_mailbox { u8 sc_token_len; u8 padding1; u8 sc_ssid[32]; - u8 sc_pwd[32]; + u8 sc_pwd[64]; u8 sc_token[32]; /* smart config sync channel */ u8 sc_sync_channel; u8 sc_sync_band; u8 padding2[2]; + + /* radar detect */ + u8 radar_channel; + u8 radar_type; + + u8 padding3[2]; } __packed; int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 04db941e1913..c36b1afc3891 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -655,7 +655,7 @@ static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = { }; /* TODO: maybe move to a new header file? */ -#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-3.bin" +#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-4.bin" static int wl18xx_identify_chip(struct wl1271 *wl) { @@ -990,6 +990,7 @@ static int wl18xx_boot(struct wl1271 *wl) wl->event_mask = BSS_LOSS_EVENT_ID | SCAN_COMPLETE_EVENT_ID | + RADAR_DETECTED_EVENT_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PERIODIC_SCAN_COMPLETE_EVENT_ID | PERIODIC_SCAN_REPORT_EVENT_ID | @@ -1703,6 +1704,7 @@ static struct wlcore_ops wl18xx_ops = { .interrupt_notify = wl18xx_acx_interrupt_notify_config, .rx_ba_filter = wl18xx_acx_rx_ba_filter, .ap_sleep = wl18xx_acx_ap_sleep, + .set_cac = wl18xx_cmd_set_cac, }; /* HT cap appropriate for wide channels in 2Ghz */ diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h index 6a2b88030c1d..71e9e382ce80 100644 --- a/drivers/net/wireless/ti/wl18xx/wl18xx.h +++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h @@ -26,10 +26,10 @@ /* minimum FW required for driver */ #define WL18XX_CHIP_VER 8 -#define WL18XX_IFTYPE_VER 8 +#define WL18XX_IFTYPE_VER 9 #define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE #define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE -#define WL18XX_MINOR_VER 13 +#define WL18XX_MINOR_VER 11 #define WL18XX_CMD_MAX_SIZE 740 diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index b82661962d33..aacad4eee070 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -403,7 +403,7 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) WARN_ON_ONCE(wl->active_link_count < 0); } -static u8 wlcore_get_native_channel_type(u8 nl_channel_type) +u8 wlcore_get_native_channel_type(u8 nl_channel_type) { switch (nl_channel_type) { case NL80211_CHAN_NO_HT: @@ -419,6 +419,7 @@ static u8 wlcore_get_native_channel_type(u8 nl_channel_type) return WLCORE_CHAN_NO_HT; } } +EXPORT_SYMBOL_GPL(wlcore_get_native_channel_type); static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index 453684a71d30..06bdee2a78d8 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -105,6 +105,7 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask, bool *timeout); +u8 wlcore_get_native_channel_type(u8 nl_channel_type); enum wl1271_commands { CMD_INTERROGATE = 1, /* use this to read information elements */ @@ -172,6 +173,11 @@ enum wl1271_commands { CMD_SMART_CONFIG_STOP = 62, CMD_SMART_CONFIG_SET_GROUP_KEY = 63, + CMD_CAC_START = 64, + CMD_CAC_STOP = 65, + CMD_DFS_MASTER_RESTART = 66, + CMD_DFS_RADAR_DETECTION_DEBUG = 67, + MAX_COMMAND_ID = 0xFFFF, }; diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index 449050b5c750..42fef847dc5c 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -311,4 +311,13 @@ wlcore_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, return wl->ops->smart_config_set_group_key(wl, group_id, key_len, key); } + +static inline int +wlcore_hw_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start) +{ + if (!wl->ops->set_cac) + return -EINVAL; + + return wl->ops->set_cac(wl, wlvif, start); +} #endif diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index caff69966ce1..f46c91965301 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4629,10 +4629,46 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed) { + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + int ret; + int channel = ieee80211_frequency_to_channel( + ctx->def.chan->center_freq); + wl1271_debug(DEBUG_MAC80211, "mac80211 change chanctx %d (type %d) changed 0x%x", - ieee80211_frequency_to_channel(ctx->def.chan->center_freq), - cfg80211_get_chandef_type(&ctx->def), changed); + channel, cfg80211_get_chandef_type(&ctx->def), changed); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl12xx_for_each_wlvif(wl, wlvif) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + + rcu_read_lock(); + if (rcu_access_pointer(vif->chanctx_conf) != ctx) { + rcu_read_unlock(); + continue; + } + rcu_read_unlock(); + + /* start radar if needed */ + if (changed & IEEE80211_CHANCTX_CHANGE_RADAR && + wlvif->bss_type == BSS_TYPE_AP_BSS && + ctx->radar_enabled && !wlvif->radar_enabled && + ctx->def.chan->dfs_state == NL80211_DFS_USABLE) { + wl1271_debug(DEBUG_MAC80211, "Start radar detection"); + wlcore_hw_set_cac(wl, wlvif, true); + wlvif->radar_enabled = true; + } + } + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); } static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, @@ -4643,13 +4679,26 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int channel = ieee80211_frequency_to_channel( ctx->def.chan->center_freq); + int ret = -EINVAL; wl1271_debug(DEBUG_MAC80211, - "mac80211 assign chanctx (role %d) %d (type %d)", - wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def)); + "mac80211 assign chanctx (role %d) %d (type %d) (radar %d dfs_state %d)", + wlvif->role_id, channel, + cfg80211_get_chandef_type(&ctx->def), + ctx->radar_enabled, ctx->def.chan->dfs_state); mutex_lock(&wl->mutex); + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + wlvif->band = ctx->def.chan->band; wlvif->channel = channel; wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def); @@ -4657,6 +4706,15 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, /* update default rates according to the band */ wl1271_set_band_rate(wl, wlvif); + if (ctx->radar_enabled && + ctx->def.chan->dfs_state == NL80211_DFS_USABLE) { + wl1271_debug(DEBUG_MAC80211, "Start radar detection"); + wlcore_hw_set_cac(wl, wlvif, true); + wlvif->radar_enabled = true; + } + + wl1271_ps_elp_sleep(wl); +out: mutex_unlock(&wl->mutex); return 0; @@ -4668,6 +4726,7 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 unassign chanctx (role %d) %d (type %d)", @@ -4676,6 +4735,97 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, cfg80211_get_chandef_type(&ctx->def)); wl1271_tx_flush(wl); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (wlvif->radar_enabled) { + wl1271_debug(DEBUG_MAC80211, "Stop radar detection"); + wlcore_hw_set_cac(wl, wlvif, false); + wlvif->radar_enabled = false; + } + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + +static int __wlcore_switch_vif_chan(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct ieee80211_chanctx_conf *new_ctx) +{ + int channel = ieee80211_frequency_to_channel( + new_ctx->def.chan->center_freq); + + wl1271_debug(DEBUG_MAC80211, + "switch vif (role %d) %d -> %d chan_type: %d", + wlvif->role_id, wlvif->channel, channel, + cfg80211_get_chandef_type(&new_ctx->def)); + + if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS)) + return 0; + + if (wlvif->radar_enabled) { + wl1271_debug(DEBUG_MAC80211, "Stop radar detection"); + wlcore_hw_set_cac(wl, wlvif, false); + wlvif->radar_enabled = false; + } + + wlvif->band = new_ctx->def.chan->band; + wlvif->channel = channel; + wlvif->channel_type = cfg80211_get_chandef_type(&new_ctx->def); + + /* start radar if needed */ + if (new_ctx->radar_enabled) { + wl1271_debug(DEBUG_MAC80211, "Start radar detection"); + wlcore_hw_set_cac(wl, wlvif, true); + wlvif->radar_enabled = true; + } + + return 0; +} + +static int +wlcore_op_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + struct wl1271 *wl = hw->priv; + int i, ret; + + wl1271_debug(DEBUG_MAC80211, + "mac80211 switch chanctx n_vifs %d mode %d", + n_vifs, mode); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + for (i = 0; i < n_vifs; i++) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vifs[i].vif); + + ret = __wlcore_switch_vif_chan(wl, wlvif, vifs[i].new_ctx); + if (ret) + goto out_sleep; + } +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + return 0; } static int wl1271_op_conf_tx(struct ieee80211_hw *hw, @@ -5665,6 +5815,7 @@ static const struct ieee80211_ops wl1271_ops = { .change_chanctx = wlcore_op_change_chanctx, .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, + .switch_vif_chanctx = wlcore_op_switch_vif_chanctx, .sta_rc_update = wlcore_op_sta_rc_update, .get_rssi = wlcore_op_get_rssi, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index c8fe2ae272ac..caee58f72a05 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -123,6 +123,8 @@ struct wlcore_ops { int (*smart_config_stop)(struct wl1271 *wl); int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id, u8 key_len, u8 *key); + int (*set_cac)(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool start); }; enum wlcore_partitions { diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 811851d00b33..b2bdb139c020 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -434,6 +434,8 @@ struct wl12xx_vif { bool wmm_enabled; + bool radar_enabled; + /* Rx Streaming */ struct work_struct rx_streaming_enable_work; struct work_struct rx_streaming_disable_work; -- cgit v1.2.1 From e7d323243f567b8f3ff1324dc8a6f17dd36b4106 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 29 Dec 2014 08:24:08 +0200 Subject: wl18xx: add debugfs file to emulate radar event Add debugfs file to emulate radar detection through a special fw cmd (which in turn will generate radar event) Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/cmd.c | 26 +++++++++++++++++++ drivers/net/wireless/ti/wl18xx/cmd.h | 8 ++++++ drivers/net/wireless/ti/wl18xx/debugfs.c | 43 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ti/wlcore/ps.c | 2 ++ 4 files changed, 79 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c index 10f9d1c064ba..68e12e54aeed 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.c +++ b/drivers/net/wireless/ti/wl18xx/cmd.c @@ -198,3 +198,29 @@ out_free: kfree(cmd); return ret; } + +int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel) +{ + struct wl18xx_cmd_dfs_radar_debug *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd radar detection debug (chan %d)", + channel); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->channel = channel; + + ret = wl1271_cmd_send(wl, CMD_DFS_RADAR_DETECTION_DEBUG, + cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send radar detection debug command"); + goto out_free; + } + +out_free: + kfree(cmd); + return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h index 91b3e2fe77cd..0809b92c23db 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.h +++ b/drivers/net/wireless/ti/wl18xx/cmd.h @@ -59,6 +59,13 @@ struct wl18xx_cmd_smart_config_set_group_key { u8 key[16]; } __packed; +struct wl18xx_cmd_dfs_radar_debug { + struct wl1271_cmd_header header; + + u8 channel; + u8 padding[3]; +} __packed; + /* cac_start and cac_stop share the same params */ struct wlcore_cmd_cac_start { struct wl1271_cmd_header header; @@ -77,4 +84,5 @@ int wl18xx_cmd_smart_config_stop(struct wl1271 *wl); int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, u8 key_len, u8 *key); int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start); +int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel); #endif diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index 7f1669cdea09..c93fae95baac 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -22,9 +22,12 @@ #include "../wlcore/debugfs.h" #include "../wlcore/wlcore.h" +#include "../wlcore/debug.h" +#include "../wlcore/ps.h" #include "wl18xx.h" #include "acx.h" +#include "cmd.h" #include "debugfs.h" #define WL18XX_DEBUGFS_FWSTATS_FILE(a, b, c) \ @@ -239,6 +242,45 @@ static const struct file_operations clear_fw_stats_ops = { .llseek = default_llseek, }; +static ssize_t radar_detection_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + int ret; + u8 channel; + + ret = kstrtou8_from_user(user_buf, count, 10, &channel); + if (ret < 0) { + wl1271_warning("illegal channel"); + return -EINVAL; + } + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl18xx_cmd_radar_detection_debug(wl, channel); + if (ret < 0) + count = ret; + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations radar_detection_ops = { + .write = radar_detection_write, + .open = simple_open, + .llseek = default_llseek, +}; + int wl18xx_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -390,6 +432,7 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(mem, fw_gen_free_mem_blks); DEBUGFS_ADD(conf, moddir); + DEBUGFS_ADD(radar_detection, moddir); return 0; diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c index f3ed543bfe73..4cd316e61466 100644 --- a/drivers/net/wireless/ti/wlcore/ps.c +++ b/drivers/net/wireless/ti/wlcore/ps.c @@ -102,6 +102,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, msecs_to_jiffies(timeout)); } +EXPORT_SYMBOL_GPL(wl1271_ps_elp_sleep); int wl1271_ps_elp_wakeup(struct wl1271 *wl) { @@ -169,6 +170,7 @@ err: out: return 0; } +EXPORT_SYMBOL_GPL(wl1271_ps_elp_wakeup); int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, enum wl1271_cmd_ps_mode mode) -- cgit v1.2.1 From 534719f445c6f8bf5218adaf4bec36f118ccc1e9 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 29 Dec 2014 08:24:09 +0200 Subject: wlcore: add support for ap csa Support ap csa support by implementing the channel_switch_beacon() mac80211 op. Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/cmd.c | 11 +++-- drivers/net/wireless/ti/wlcore/event.c | 10 +++-- drivers/net/wireless/ti/wlcore/main.c | 81 +++++++++++++++++++++++++++++++++- 3 files changed, 95 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c index 68e12e54aeed..5731950d671e 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.c +++ b/drivers/net/wireless/ti/wl18xx/cmd.c @@ -33,7 +33,8 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl, u32 supported_rates; int ret; - wl1271_debug(DEBUG_ACX, "cmd channel switch"); + wl1271_debug(DEBUG_ACX, "cmd channel switch (count=%d)", + ch_switch->count); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -60,8 +61,12 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl, goto out_free; } - supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | - wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); + supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES; + if (wlvif->bss_type == BSS_TYPE_STA_BSS) + supported_rates |= wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); + else + supported_rates |= + wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif); if (wlvif->p2p) supported_rates &= ~CONF_TX_CCK_RATES; cmd->local_supported_rates = cpu_to_le32(supported_rates); diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 5153640f4532..69a266121bf4 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -139,7 +139,7 @@ void wlcore_event_channel_switch(struct wl1271 *wl, wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx success=%d", __func__, roles_bitmap, success); - wl12xx_for_each_wlvif_sta(wl, wlvif) { + wl12xx_for_each_wlvif(wl, wlvif) { if (wlvif->role_id == WL12XX_INVALID_ROLE_ID || !test_bit(wlvif->role_id , &roles_bitmap)) continue; @@ -150,8 +150,12 @@ void wlcore_event_channel_switch(struct wl1271 *wl, vif = wl12xx_wlvif_to_vif(wlvif); - ieee80211_chswitch_done(vif, success); - cancel_delayed_work(&wlvif->channel_switch_work); + if (wlvif->bss_type == BSS_TYPE_STA_BSS) { + ieee80211_chswitch_done(vif, success); + cancel_delayed_work(&wlvif->channel_switch_work); + } else { + ieee80211_csa_finish(vif); + } } } EXPORT_SYMBOL_GPL(wlcore_event_channel_switch); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index f46c91965301..68da50efb164 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5433,6 +5433,83 @@ out: mutex_unlock(&wl->mutex); } +static const void *wlcore_get_beacon_ie(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u8 eid) +{ + int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); + struct sk_buff *beacon = + ieee80211_beacon_get(wl->hw, wl12xx_wlvif_to_vif(wlvif)); + + if (!beacon) + return NULL; + + return cfg80211_find_ie(eid, + beacon->data + ieoffset, + beacon->len - ieoffset); +} + +static int wlcore_get_csa_count(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 *csa_count) +{ + const u8 *ie; + const struct ieee80211_channel_sw_ie *ie_csa; + + ie = wlcore_get_beacon_ie(wl, wlvif, WLAN_EID_CHANNEL_SWITCH); + if (!ie) + return -EINVAL; + + ie_csa = (struct ieee80211_channel_sw_ie *)&ie[2]; + *csa_count = ie_csa->count; + + return 0; +} + +static void wlcore_op_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct ieee80211_channel_switch ch_switch = { + .block_tx = true, + .chandef = *chandef, + }; + int ret; + + wl1271_debug(DEBUG_MAC80211, + "mac80211 channel switch beacon (role %d)", + wlvif->role_id); + + ret = wlcore_get_csa_count(wl, wlvif, &ch_switch.count); + if (ret < 0) { + wl1271_error("error getting beacon (for CSA counter)"); + return; + } + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) { + ret = -EBUSY; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl->ops->channel_switch(wl, wlvif, &ch_switch); + if (ret) + goto out_sleep; + + set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + static void wlcore_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { @@ -5807,6 +5884,7 @@ static const struct ieee80211_ops wl1271_ops = { .set_bitrate_mask = wl12xx_set_bitrate_mask, .set_default_unicast_key = wl1271_op_set_default_key_idx, .channel_switch = wl12xx_op_channel_switch, + .channel_switch_beacon = wlcore_op_channel_switch_beacon, .flush = wlcore_op_flush, .remain_on_channel = wlcore_op_remain_on_channel, .cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel, @@ -6023,7 +6101,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + WIPHY_FLAG_SUPPORTS_SCHED_SCAN | + WIPHY_FLAG_HAS_CHANNEL_SWITCH; /* make sure all our channels fit in the scanned_ch bitmask */ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + -- cgit v1.2.1 From 830513abc6ea2b1828b83b37300711984bae89f6 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 29 Dec 2014 08:24:10 +0200 Subject: wlcore: add dfs master restart calls call wlcore_cmd_dfs_master_restart when starting the ap on a new channel (after csa is done). Add a new WLVIF_FLAG_BEACON_DISABLED flag to indicate that dfs_master_restart command is required. Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/cmd.c | 25 +++++++++++++++++++++++++ drivers/net/wireless/ti/wl18xx/cmd.h | 8 ++++++++ drivers/net/wireless/ti/wl18xx/main.c | 1 + drivers/net/wireless/ti/wlcore/event.c | 1 + drivers/net/wireless/ti/wlcore/hw_ops.h | 9 +++++++++ drivers/net/wireless/ti/wlcore/main.c | 10 +++++++++- drivers/net/wireless/ti/wlcore/wlcore.h | 1 + drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 + 8 files changed, 55 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c index 5731950d671e..a8d176ddc73c 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.c +++ b/drivers/net/wireless/ti/wl18xx/cmd.c @@ -229,3 +229,28 @@ out_free: kfree(cmd); return ret; } + +int wl18xx_cmd_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct wl18xx_cmd_dfs_master_restart *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd dfs master restart (role %d)", + wlvif->role_id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->role_id = wlvif->role_id; + + ret = wl1271_cmd_send(wl, CMD_DFS_MASTER_RESTART, + cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send dfs master restart command"); + goto out_free; + } +out_free: + kfree(cmd); + return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h index 0809b92c23db..7f9440a2bff8 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.h +++ b/drivers/net/wireless/ti/wl18xx/cmd.h @@ -66,6 +66,13 @@ struct wl18xx_cmd_dfs_radar_debug { u8 padding[3]; } __packed; +struct wl18xx_cmd_dfs_master_restart { + struct wl1271_cmd_header header; + + u8 role_id; + u8 padding[3]; +} __packed; + /* cac_start and cac_stop share the same params */ struct wlcore_cmd_cac_start { struct wl1271_cmd_header header; @@ -85,4 +92,5 @@ int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, u8 key_len, u8 *key); int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start); int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel); +int wl18xx_cmd_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif); #endif diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index c36b1afc3891..0e96b38a612f 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1705,6 +1705,7 @@ static struct wlcore_ops wl18xx_ops = { .rx_ba_filter = wl18xx_acx_rx_ba_filter, .ap_sleep = wl18xx_acx_ap_sleep, .set_cac = wl18xx_cmd_set_cac, + .dfs_master_restart = wl18xx_cmd_dfs_master_restart, }; /* HT cap appropriate for wide channels in 2Ghz */ diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 69a266121bf4..c42e78955e7b 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -154,6 +154,7 @@ void wlcore_event_channel_switch(struct wl1271 *wl, ieee80211_chswitch_done(vif, success); cancel_delayed_work(&wlvif->channel_switch_work); } else { + set_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags); ieee80211_csa_finish(vif); } } diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index 42fef847dc5c..eec56935b1b6 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -320,4 +320,13 @@ wlcore_hw_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start) return wl->ops->set_cac(wl, wlvif, start); } + +static inline int +wlcore_hw_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + if (!wl->ops->dfs_master_restart) + return -EINVAL; + + return wl->ops->dfs_master_restart(wl, wlvif); +} #endif diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 68da50efb164..2cbec03049e6 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4127,8 +4127,14 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, ret = wlcore_set_beacon_template(wl, vif, is_ap); if (ret < 0) goto out; - } + if (test_and_clear_bit(WLVIF_FLAG_BEACON_DISABLED, + &wlvif->flags)) { + ret = wlcore_hw_dfs_master_restart(wl, wlvif); + if (ret < 0) + goto out; + } + } out: if (ret != 0) wl1271_error("beacon info change failed: %d", ret); @@ -4774,6 +4780,8 @@ static int __wlcore_switch_vif_chan(struct wl1271 *wl, if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS)) return 0; + WARN_ON(!test_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags)); + if (wlvif->radar_enabled) { wl1271_debug(DEBUG_MAC80211, "Stop radar detection"); wlcore_hw_set_cac(wl, wlvif, false); diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index caee58f72a05..581c47913cec 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -125,6 +125,7 @@ struct wlcore_ops { u8 key_len, u8 *key); int (*set_cac)(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start); + int (*dfs_master_restart)(struct wl1271 *wl, struct wl12xx_vif *wlvif); }; enum wlcore_partitions { diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index b2bdb139c020..3396ce5a934d 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -251,6 +251,7 @@ enum wl12xx_vif_flags { WLVIF_FLAG_AP_PROBE_RESP_SET, WLVIF_FLAG_IN_USE, WLVIF_FLAG_ACTIVE, + WLVIF_FLAG_BEACON_DISABLED, }; struct wl12xx_vif; -- cgit v1.2.1 From 4ce9fad35a4ae21c393a89001b8ef33fa8c2033b Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 29 Dec 2014 08:24:11 +0200 Subject: wlcore: allow using dfs channels Since we are going to support dfs channels, there is no reason to mark them as NO_IR (having the DFS flag is enough anyway). Additionally, when setting the regdomain configuration, enable usable dfs channels. Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/cmd.c | 16 +++++++++------- drivers/net/wireless/ti/wlcore/main.c | 14 -------------- 2 files changed, 9 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index aacad4eee070..50ca10c95a18 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1687,9 +1687,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl) { struct wl12xx_cmd_regdomain_dfs_config *cmd = NULL; int ret = 0, i, b, ch_bit_idx; - struct ieee80211_channel *channel; u32 tmp_ch_bitmap[2]; - u16 ch; struct wiphy *wiphy = wl->hw->wiphy; struct ieee80211_supported_band *band; bool timeout = false; @@ -1704,12 +1702,16 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl) for (b = IEEE80211_BAND_2GHZ; b <= IEEE80211_BAND_5GHZ; b++) { band = wiphy->bands[b]; for (i = 0; i < band->n_channels; i++) { - channel = &band->channels[i]; - ch = channel->hw_value; + struct ieee80211_channel *channel = &band->channels[i]; + u16 ch = channel->hw_value; + u32 flags = channel->flags; - if (channel->flags & (IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IR)) + if (flags & (IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_IR)) + continue; + + if ((flags & IEEE80211_CHAN_RADAR) && + channel->dfs_state != NL80211_DFS_AVAILABLE) continue; ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 2cbec03049e6..a393ae8fa81b 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -79,23 +79,9 @@ static int wl12xx_set_authorized(struct wl1271 *wl, struct wl12xx_vif *wlvif) static void wl1271_reg_notify(struct wiphy *wiphy, struct regulatory_request *request) { - struct ieee80211_supported_band *band; - struct ieee80211_channel *ch; - int i; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct wl1271 *wl = hw->priv; - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - for (i = 0; i < band->n_channels; i++) { - ch = &band->channels[i]; - if (ch->flags & IEEE80211_CHAN_DISABLED) - continue; - - if (ch->flags & IEEE80211_CHAN_RADAR) - ch->flags |= IEEE80211_CHAN_NO_IR; - - } - wlcore_regdomain_config(wl); } -- cgit v1.2.1 From 1cd91b2c4d8a5ebe9ba7874fcd45ee2b9b444b04 Mon Sep 17 00:00:00 2001 From: Guy Mishol Date: Mon, 29 Dec 2014 08:24:12 +0200 Subject: wlcore: add dfs region to reg domain update cmd Add dfs region to the reg domain channel update command. Signed-off-by: Guy Mishol Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/cmd.c | 1 + drivers/net/wireless/ti/wlcore/cmd.h | 2 ++ drivers/net/wireless/ti/wlcore/main.c | 4 ++++ drivers/net/wireless/ti/wlcore/wlcore.h | 3 +++ 4 files changed, 10 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 50ca10c95a18..c26fc2106e5b 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1736,6 +1736,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl) cmd->ch_bit_map1 = cpu_to_le32(tmp_ch_bitmap[0]); cmd->ch_bit_map2 = cpu_to_le32(tmp_ch_bitmap[1]); + cmd->dfs_region = wl->dfs_region; wl1271_debug(DEBUG_CMD, "cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x", diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index 06bdee2a78d8..e14cd407a6ae 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -648,6 +648,8 @@ struct wl12xx_cmd_regdomain_dfs_config { __le32 ch_bit_map1; __le32 ch_bit_map2; + u8 dfs_region; + u8 padding[3]; } __packed; struct wl12xx_cmd_config_fwlog { diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index a393ae8fa81b..e90fb781a6a1 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -82,6 +82,10 @@ static void wl1271_reg_notify(struct wiphy *wiphy, struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct wl1271 *wl = hw->priv; + /* copy the current dfs region */ + if (request) + wl->dfs_region = request->dfs_region; + wlcore_regdomain_config(wl); } diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 581c47913cec..d599c869e6e8 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -465,6 +465,9 @@ struct wl1271 { /* HW HT (11n) capabilities */ struct ieee80211_sta_ht_cap ht_cap[WLCORE_NUM_BANDS]; + /* the current dfs region */ + enum nl80211_dfs_regions dfs_region; + /* size of the private FW status data */ size_t fw_status_len; size_t fw_status_priv_len; -- cgit v1.2.1 From 86f2db86d410f5dc3e89cc7d9c31607f0c7763bd Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 29 Dec 2014 08:24:13 +0200 Subject: wl18xx: declare radar_detect_widths support for ap interfaces After having all the dfs infrastructure in place, declare radar_detect_widths support for the ap interfaces combination. Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 0e96b38a612f..717c4f5a02c2 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1799,6 +1799,10 @@ wl18xx_iface_combinations[] = { .limits = wl18xx_iface_ap_limits, .n_limits = ARRAY_SIZE(wl18xx_iface_ap_limits), .num_different_channels = 1, + .radar_detect_widths = BIT(NL80211_CHAN_NO_HT) | + BIT(NL80211_CHAN_HT20) | + BIT(NL80211_CHAN_HT40MINUS) | + BIT(NL80211_CHAN_HT40PLUS), } }; -- cgit v1.2.1 From 8bd61f8d8790c5502f7fdbf49861bbea1339054f Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 6 Jan 2015 23:02:54 +0100 Subject: brcmfmac: get rid of duplicate SDIO device identifiers Instead of defining SDIO device identifier in brcm80211 code use the defintions in linux/mmc/sdio_ids.h directly. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 22 +++++++++++----------- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 2 +- .../net/wireless/brcm80211/include/brcm_hw_ids.h | 13 ------------- 3 files changed, 12 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index dffd9e44f5b6..00ba90b89455 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -996,20 +996,20 @@ out: } #define BRCMF_SDIO_DEVICE(dev_id) \ - {SDIO_DEVICE(BRCM_SDIO_VENDOR_ID_BROADCOM, dev_id)} + {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id)} /* devices we support, null terminated */ static const struct sdio_device_id brcmf_sdmmc_ids[] = { - BRCMF_SDIO_DEVICE(BRCM_SDIO_43143_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_43241_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_4329_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_4330_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_4334_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_43340_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_43341_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_43362_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_4335_4339_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_4354_DEVICE_ID), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43241), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4329), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4330), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4334), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354), { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 551da356a5bd..99a37765888d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -3816,7 +3816,7 @@ static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr) u32 val, rev; val = brcmf_sdiod_regrl(sdiodev, addr, NULL); - if (sdiodev->func[0]->device == BRCM_SDIO_4335_4339_DEVICE_ID && + if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 && addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) { rev = (val & CID_REV_MASK) >> CID_REV_SHIFT; if (rev >= 2) { diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 00215efbc13b..2124a17d0bfd 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -22,7 +22,6 @@ #define BRCM_USB_VENDOR_ID_BROADCOM 0x0a5c #define BRCM_PCIE_VENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM -#define BRCM_SDIO_VENDOR_ID_BROADCOM SDIO_VENDOR_ID_BROADCOM /* Chipcommon Core Chip IDs */ #define BRCM_CC_43143_CHIP_ID 43143 @@ -46,18 +45,6 @@ #define BRCM_CC_43570_CHIP_ID 43570 #define BRCM_CC_43602_CHIP_ID 43602 -/* SDIO Device IDs */ -#define BRCM_SDIO_43143_DEVICE_ID BRCM_CC_43143_CHIP_ID -#define BRCM_SDIO_43241_DEVICE_ID BRCM_CC_43241_CHIP_ID -#define BRCM_SDIO_4329_DEVICE_ID BRCM_CC_4329_CHIP_ID -#define BRCM_SDIO_4330_DEVICE_ID BRCM_CC_4330_CHIP_ID -#define BRCM_SDIO_4334_DEVICE_ID BRCM_CC_4334_CHIP_ID -#define BRCM_SDIO_43340_DEVICE_ID BRCM_CC_43340_CHIP_ID -#define BRCM_SDIO_43341_DEVICE_ID 43341 -#define BRCM_SDIO_43362_DEVICE_ID BRCM_CC_43362_CHIP_ID -#define BRCM_SDIO_4335_4339_DEVICE_ID BRCM_CC_4335_CHIP_ID -#define BRCM_SDIO_4354_DEVICE_ID BRCM_CC_4354_CHIP_ID - /* USB Device IDs */ #define BRCM_USB_43143_DEVICE_ID 0xbd1e #define BRCM_USB_43236_DEVICE_ID 0xbd17 -- cgit v1.2.1 From 1f6969fb230b79debcdf8ec3614162b553664396 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:02 -0600 Subject: rtlwifi: Unify variable naming for all drivers Some drivers refer to a particular quantity in the driver's private are by one name, while others use a different name. These differences are removed. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192ee/dm.c | 26 ++++++++++---------- drivers/net/wireless/rtlwifi/rtl8723be/dm.c | 26 ++++++++++---------- drivers/net/wireless/rtlwifi/rtl8821ae/dm.c | 30 +++++++++++------------ drivers/net/wireless/rtlwifi/wifi.h | 2 -- 5 files changed, 42 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index f6cb5aedfdd1..c3aad76fb473 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -221,7 +221,7 @@ static void rtl92c_dm_diginit(struct ieee80211_hw *hw) dm_digtable->forbidden_igi = DM_DIG_MIN; dm_digtable->large_fa_hit = 0; dm_digtable->recover_cnt = 0; - dm_digtable->dig_dynamic_min = 0x25; + dm_digtable->dig_min_0 = 0x25; } static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c index 77deedf79d1d..2fa4c4551afb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c @@ -172,8 +172,8 @@ static void rtl92ee_dm_diginit(struct ieee80211_hw *hw) dm_dig->forbidden_igi = DM_DIG_MIN; dm_dig->large_fa_hit = 0; dm_dig->recover_cnt = 0; - dm_dig->dig_dynamic_min = DM_DIG_MIN; - dm_dig->dig_dynamic_min_1 = DM_DIG_MIN; + dm_dig->dig_min_0 = DM_DIG_MIN; + dm_dig->dig_min_1 = DM_DIG_MIN; dm_dig->media_connect_0 = false; dm_dig->media_connect_1 = false; rtlpriv->dm.dm_initialgain_enable = true; @@ -298,7 +298,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct dig_t *dm_dig = &rtlpriv->dm_digtable; - u8 dig_dynamic_min , dig_maxofmin; + u8 dig_min_0, dig_maxofmin; bool bfirstconnect , bfirstdisconnect; u8 dm_dig_max, dm_dig_min; u8 current_igi = dm_dig->cur_igvalue; @@ -308,7 +308,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) if (mac->act_scanning) return; - dig_dynamic_min = dm_dig->dig_dynamic_min; + dig_min_0 = dm_dig->dig_min_0; bfirstconnect = (mac->link_state >= MAC80211_LINKED) && !dm_dig->media_connect_0; bfirstdisconnect = (mac->link_state < MAC80211_LINKED) && @@ -329,19 +329,19 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) if (rtlpriv->dm.one_entry_only) { offset = 0; if (dm_dig->rssi_val_min - offset < dm_dig_min) - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; else if (dm_dig->rssi_val_min - offset > dig_maxofmin) - dig_dynamic_min = dig_maxofmin; + dig_min_0 = dig_maxofmin; else - dig_dynamic_min = dm_dig->rssi_val_min - offset; + dig_min_0 = dm_dig->rssi_val_min - offset; } else { - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; } } else { dm_dig->rx_gain_max = dm_dig_max; - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n"); } @@ -368,10 +368,10 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) } else { if (dm_dig->large_fa_hit < 3) { if ((dm_dig->forbidden_igi - 1) < - dig_dynamic_min) { - dm_dig->forbidden_igi = dig_dynamic_min; + dig_min_0) { + dm_dig->forbidden_igi = dig_min_0; dm_dig->rx_gain_min = - dig_dynamic_min; + dig_min_0; } else { dm_dig->forbidden_igi--; dm_dig->rx_gain_min = @@ -430,7 +430,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) rtl92ee_dm_write_dig(hw , current_igi); dm_dig->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ? true : false); - dm_dig->dig_dynamic_min = dig_dynamic_min; + dm_dig->dig_min_0 = dig_min_0; } void rtl92ee_dm_write_cck_cca_thres(struct ieee80211_hw *hw, u8 cur_thres) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c index dd7eb4371f49..b92c521e8c63 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c @@ -232,8 +232,8 @@ static void rtl8723be_dm_diginit(struct ieee80211_hw *hw) dm_digtable->forbidden_igi = DM_DIG_MIN; dm_digtable->large_fa_hit = 0; dm_digtable->recover_cnt = 0; - dm_digtable->dig_dynamic_min = DM_DIG_MIN; - dm_digtable->dig_dynamic_min_1 = DM_DIG_MIN; + dm_digtable->dig_min_0 = DM_DIG_MIN; + dm_digtable->dig_min_1 = DM_DIG_MIN; dm_digtable->media_connect_0 = false; dm_digtable->media_connect_1 = false; rtlpriv->dm.dm_initialgain_enable = true; @@ -424,7 +424,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct dig_t *dm_digtable = &rtlpriv->dm_digtable; struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u8 dig_dynamic_min, dig_maxofmin; + u8 dig_min_0, dig_maxofmin; bool bfirstconnect, bfirstdisconnect; u8 dm_dig_max, dm_dig_min; u8 current_igi = dm_digtable->cur_igvalue; @@ -434,7 +434,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) if (mac->act_scanning) return; - dig_dynamic_min = dm_digtable->dig_dynamic_min; + dig_min_0 = dm_digtable->dig_min_0; bfirstconnect = (mac->link_state >= MAC80211_LINKED) && !dm_digtable->media_connect_0; bfirstdisconnect = (mac->link_state < MAC80211_LINKED) && @@ -456,20 +456,20 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) if (rtlpriv->dm.one_entry_only) { offset = 12; if (dm_digtable->rssi_val_min - offset < dm_dig_min) - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; else if (dm_digtable->rssi_val_min - offset > dig_maxofmin) - dig_dynamic_min = dig_maxofmin; + dig_min_0 = dig_maxofmin; else - dig_dynamic_min = + dig_min_0 = dm_digtable->rssi_val_min - offset; } else { - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; } } else { dm_digtable->rx_gain_max = dm_dig_max; - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n"); } @@ -497,11 +497,11 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) } else { if (dm_digtable->large_fa_hit < 3) { if ((dm_digtable->forbidden_igi - 1) < - dig_dynamic_min) { + dig_min_0) { dm_digtable->forbidden_igi = - dig_dynamic_min; + dig_min_0; dm_digtable->rx_gain_min = - dig_dynamic_min; + dig_min_0; } else { dm_digtable->forbidden_igi--; dm_digtable->rx_gain_min = @@ -552,7 +552,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) rtl8723be_dm_write_dig(hw, current_igi); dm_digtable->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ? true : false); - dm_digtable->dig_dynamic_min = dig_dynamic_min; + dm_digtable->dig_min_0 = dig_min_0; } static void rtl8723be_dm_false_alarm_counter_statistics( diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c index ba30b0d250fd..8b0bfb2bd8f7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c @@ -539,8 +539,8 @@ static void rtl8821ae_dm_diginit(struct ieee80211_hw *hw) dm_digtable->forbidden_igi = DM_DIG_MIN; dm_digtable->large_fa_hit = 0; dm_digtable->recover_cnt = 0; - dm_digtable->dig_dynamic_min = DM_DIG_MIN; - dm_digtable->dig_dynamic_min_1 = DM_DIG_MIN; + dm_digtable->dig_min_0 = DM_DIG_MIN; + dm_digtable->dig_min_1 = DM_DIG_MIN; dm_digtable->media_connect_0 = false; dm_digtable->media_connect_1 = false; rtlpriv->dm.dm_initialgain_enable = true; @@ -822,7 +822,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) struct dig_t *dm_digtable = &rtlpriv->dm_digtable; struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u8 dig_dynamic_min; + u8 dig_min_0; u8 dig_max_of_min; bool first_connect, first_disconnect; u8 dm_dig_max, dm_dig_min, offset; @@ -837,7 +837,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) } /*add by Neil Chen to avoid PSD is processing*/ - dig_dynamic_min = dm_digtable->dig_dynamic_min; + dig_min_0 = dm_digtable->dig_min_0; first_connect = (mac->link_state >= MAC80211_LINKED) && (!dm_digtable->media_connect_0); first_disconnect = (mac->link_state < MAC80211_LINKED) && @@ -876,23 +876,23 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) offset = 0; if (dm_digtable->rssi_val_min - offset < dm_dig_min) - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; else if (dm_digtable->rssi_val_min - offset > dig_max_of_min) - dig_dynamic_min = dig_max_of_min; + dig_min_0 = dig_max_of_min; else - dig_dynamic_min = + dig_min_0 = dm_digtable->rssi_val_min - offset; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, - "bOneEntryOnly=TRUE, dig_dynamic_min=0x%x\n", - dig_dynamic_min); + "bOneEntryOnly=TRUE, dig_min_0=0x%x\n", + dig_min_0); } else { - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; } } else { dm_digtable->rx_gain_max = dm_dig_max; - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "No Link\n"); } @@ -925,11 +925,11 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) } else { if (dm_digtable->large_fa_hit < 3) { if ((dm_digtable->forbidden_igi - 1) < - dig_dynamic_min) { + dig_min_0) { dm_digtable->forbidden_igi = - dig_dynamic_min; + dig_min_0; dm_digtable->rx_gain_min = - dig_dynamic_min; + dig_min_0; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "Normal Case: At Lower Bound\n"); } else { @@ -1024,7 +1024,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) rtl8821ae_dm_write_dig(hw, current_igi); dm_digtable->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ? true : false); - dm_digtable->dig_dynamic_min = dig_dynamic_min; + dm_digtable->dig_min_0 = dig_min_0; } static void rtl8821ae_dm_common_info_self_update(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 7a718fdb82cd..b53d9dd7a595 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -2412,8 +2412,6 @@ struct dig_t { u8 pre_ccastate; u8 cur_ccasate; u8 large_fa_hit; - u8 dig_dynamic_min; - u8 dig_dynamic_min_1; u8 forbidden_igi; u8 dig_state; u8 dig_highpwrstate; -- cgit v1.2.1 From 3f0c1cfa735a12dbe24c583d2ab833d348745856 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:03 -0600 Subject: rtlwifi: rtl8723be: Improve modinfo output The description of the power-save variables for this driver is not as clear as for the others. The wording is changed to match the others. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8723be/sw.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index 223eb42992bd..1017f02d7bf7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -387,12 +387,14 @@ module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444); module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog, bool, 0444); -MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); -MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); -MODULE_PARM_DESC(fwlps, "using linked fw control power save (default 1 is open)\n"); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 0)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n"); +MODULE_PARM_DESC(disable_watchdog, + "Set to 1 to disable the watchdog (default 0)\n"); static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); -- cgit v1.2.1 From 6f8214b6905741ac5c58958a35257e8103645c90 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:04 -0600 Subject: rtlwifi: Create new routine to initialize the DM tables Each of the drivers contains a routine that initializes the dm_digtable member of the driver's private area. As a first step toward reducing the size of the drivers, a copy of this driver is created in rtlwifi, and the definitions of the parameters are moved there. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/core.c | 34 +++++++++++++++++++++++ drivers/net/wireless/rtlwifi/core.h | 24 ++++++++++++++++ drivers/net/wireless/rtlwifi/rtl8188ee/dm.c | 1 + drivers/net/wireless/rtlwifi/rtl8188ee/dm.h | 22 --------------- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 1 + drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h | 22 --------------- drivers/net/wireless/rtlwifi/rtl8192ce/dm.c | 1 + drivers/net/wireless/rtlwifi/rtl8192ce/dm.h | 13 --------- drivers/net/wireless/rtlwifi/rtl8192de/dm.c | 1 + drivers/net/wireless/rtlwifi/rtl8192de/dm.h | 22 --------------- drivers/net/wireless/rtlwifi/rtl8192ee/dm.c | 1 + drivers/net/wireless/rtlwifi/rtl8192ee/dm.h | 13 --------- drivers/net/wireless/rtlwifi/rtl8192se/dm.c | 1 + drivers/net/wireless/rtlwifi/rtl8192se/dm.h | 19 ------------- drivers/net/wireless/rtlwifi/rtl8723ae/dm.c | 1 + drivers/net/wireless/rtlwifi/rtl8723ae/dm.h | 22 --------------- drivers/net/wireless/rtlwifi/rtl8723be/dm.c | 1 + drivers/net/wireless/rtlwifi/rtl8723be/dm.h | 22 --------------- drivers/net/wireless/rtlwifi/rtl8821ae/dm.c | 1 + drivers/net/wireless/rtlwifi/rtl8821ae/dm.h | 16 ----------- 20 files changed, 67 insertions(+), 171 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index deab85236bfd..5aa3ab3fff35 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -1871,3 +1871,37 @@ bool rtl_btc_status_false(void) return false; } EXPORT_SYMBOL_GPL(rtl_btc_status_false); + +void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igvalue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + + dm_digtable->dig_enable_flag = true; + dm_digtable->cur_igvalue = cur_igvalue; + dm_digtable->pre_igvalue = 0; + dm_digtable->cur_sta_cstate = DIG_STA_DISCONNECT; + dm_digtable->presta_cstate = DIG_STA_DISCONNECT; + dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; + dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; + dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; + dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + dm_digtable->rx_gain_max = DM_DIG_MAX; + dm_digtable->rx_gain_min = DM_DIG_MIN; + dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; + dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; + dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; + dm_digtable->pre_cck_cca_thres = 0xff; + dm_digtable->cur_cck_cca_thres = 0x83; + dm_digtable->forbidden_igi = DM_DIG_MIN; + dm_digtable->large_fa_hit = 0; + dm_digtable->recover_cnt = 0; + dm_digtable->dig_min_0 = 0x25; + dm_digtable->dig_min_1 = 0x25; + dm_digtable->media_connect_0 = false; + dm_digtable->media_connect_1 = false; + rtlpriv->dm.dm_initialgain_enable = true; + dm_digtable->bt30_cur_igi = 0x32; +} +EXPORT_SYMBOL(rtl_dm_diginit); diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index 8c87eb54be66..c0a03174b666 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h @@ -35,6 +35,29 @@ #define RTL_SUPPORTED_CTRL_FILTER 0xFF +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 +#define DM_FALSEALARM_THRESH_LOW 400 +#define DM_FALSEALARM_THRESH_HIGH 1000 + +#define DM_DIG_MAX 0x3e +#define DM_DIG_MIN 0x1e +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 +#define DM_DIG_BACKOFF_DEFAULT 10 + +enum dm_dig_connect_e { + DIG_STA_DISCONNECT, + DIG_STA_CONNECT, + DIG_STA_BEFORE_CONNECT, + DIG_MULTISTA_DISCONNECT, + DIG_MULTISTA_CONNECT, + DIG_AP_DISCONNECT, + DIG_AP_CONNECT, + DIG_AP_ADD_STATION, + DIG_CONNECT_MAX +}; + extern const struct ieee80211_ops rtl_ops; void rtl_fw_cb(const struct firmware *firmware, void *context); void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context); @@ -44,5 +67,6 @@ void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data); bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); bool rtl_btc_status_false(void); +void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igval); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c index 2aa34d9055f0..7ebf6e06871f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h index 64f1f3ea9807..6217b7c2842a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h @@ -186,15 +186,6 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - #define DM_DIG_MAX_AP 0x32 #define DM_DIG_MIN_AP 0x20 @@ -204,10 +195,6 @@ #define DM_DIG_FA_TH1 0x300 #define DM_DIG_FA_TH2 0x400 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_W 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -296,15 +283,6 @@ enum dm_dig_ext_port_alg_e { DIG_EXT_PORT_STAGE_MAX = 4, }; -enum dm_dig_connect_e { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - enum pwr_track_control_method { BBSWING, TXAGC diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index c3aad76fb473..dabe18f168e0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -32,6 +32,7 @@ #include "phy_common.h" #include "../pci.h" #include "../base.h" +#include "../core.h" #define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1) #define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1) diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h index 4f232a063636..55ebffd91428 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h @@ -47,25 +47,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - #define DM_DIG_FA_UPPER 0x32 #define DM_DIG_FA_LOWER 0x20 #define DM_DIG_FA_TH0 0x20 #define DM_DIG_FA_TH1 0x100 #define DM_DIG_FA_TH2 0x200 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_lOW 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -157,15 +144,6 @@ enum dm_dig_ext_port_alg_e { DIG_EXT_PORT_STAGE_MAX = 4, }; -enum dm_dig_connect_e { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - void rtl92c_dm_init(struct ieee80211_hw *hw); void rtl92c_dm_watchdog(struct ieee80211_hw *hw); void rtl92c_dm_write_dig(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c index 74f9c083b80d..09898cf2e07a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h index 9c5311c299fd..38ba707015f5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h @@ -42,25 +42,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - #define DM_DIG_FA_UPPER 0x32 #define DM_DIG_FA_LOWER 0x20 #define DM_DIG_FA_TH0 0x20 #define DM_DIG_FA_TH1 0x100 #define DM_DIG_FA_TH2 0x200 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_lOW 30 #define RXPATHSELECTION_DIFF_TH 18 diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index 304c443b89b2..75643abe0571 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -29,6 +29,7 @@ #include "../wifi.h" #include "../base.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.h b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h index 3fea0c11c24a..d21b3bceab62 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h @@ -42,25 +42,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1c - #define DM_DIG_FA_UPPER 0x32 #define DM_DIG_FA_LOWER 0x20 #define DM_DIG_FA_TH0 0x100 #define DM_DIG_FA_TH1 0x400 #define DM_DIG_FA_TH2 0x600 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_lOW 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -142,15 +129,6 @@ enum dm_dig_ext_port_alg { DIG_EXT_PORT_STAGE_MAX = 4, }; -enum dm_dig_connect { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - void rtl92d_dm_init(struct ieee80211_hw *hw); void rtl92d_dm_watchdog(struct ieee80211_hw *hw); void rtl92d_dm_init_edca_turbo(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c index 2fa4c4551afb..70e58d102d1e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h index 881db7d6fef7..4880e191e02a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h @@ -189,15 +189,6 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - #define DM_DIG_MAX_AP 0x32 #define DM_DIG_MIN_AP 0x20 @@ -207,10 +198,6 @@ #define DM_DIG_FA_TH1 0x300 #define DM_DIG_FA_TH2 0x400 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_LOW 30 #define RXPATHSELECTION_DIFF_TH 18 diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c index b3a2d5ec59e6..6cac70b77539 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -29,6 +29,7 @@ #include "../wifi.h" #include "../base.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h index 2e9052c8fe4b..7d778d384fde 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h @@ -54,16 +54,6 @@ enum dm_dig_sta { DM_STA_DIG_MAX }; -enum dm_dig_connect { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_AP_DISCONNECT = 3, - DIG_AP_CONNECT = 4, - DIG_AP_ADD_STATION = 5, - DIG_CONNECT_MAX -}; - enum dm_dig_ext_port_alg { DIG_EXT_PORT_STAGE_0 = 0, DIG_EXT_PORT_STAGE_1 = 1, @@ -99,22 +89,13 @@ enum dm_ratr_sta { #define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 #define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 -#define DM_FALSEALARM_THRESH_LOW 40 -#define DM_FALSEALARM_THRESH_HIGH 1000 #define DM_DIG_HIGH_PWR_THRESH_HIGH 75 #define DM_DIG_HIGH_PWR_THRESH_LOW 70 #define DM_DIG_BACKOFF 12 -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1c #define DM_DIG_MIN_Netcore 0x12 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 void rtl92s_dm_watchdog(struct ieee80211_hw *hw); void rtl92s_dm_init(struct ieee80211_hw *hw); void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw); #endif - diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c index a0e86922780a..80f4c5410a13 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h index 6fa0feb05f6d..c54024e05489 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h @@ -42,25 +42,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - #define DM_DIG_FA_UPPER 0x32 #define DM_DIG_FA_LOWER 0x20 #define DM_DIG_FA_TH0 0x20 #define DM_DIG_FA_TH1 0x100 #define DM_DIG_FA_TH2 0x200 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_LOW 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -142,15 +129,6 @@ enum dm_dig_ext_port_alg_e { DIG_EXT_PORT_STAGE_MAX = 4, }; -enum dm_dig_connect_e { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - #define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1) #define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1) #define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c index b92c521e8c63..ddf45d9fd6ea 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h index e4c0e8ae6f47..f3e47abe0baf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h @@ -180,15 +180,6 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - #define DM_DIG_MAX_AP 0x32 #define DM_DIG_MIN_AP 0x20 @@ -198,10 +189,6 @@ #define DM_DIG_FA_TH1 0x300 #define DM_DIG_FA_TH2 0x400 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_LOW 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -260,15 +247,6 @@ enum dm_dig_ext_port_alg_e { DIG_EXT_PORT_STAGE_MAX = 4, }; -enum dm_dig_connect_e { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - enum pwr_track_control_method { BBSWING, TXAGC diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c index 8b0bfb2bd8f7..4af4613cf7e3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h index 9dd40dd316c1..f3118879cbdf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h @@ -187,9 +187,6 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - #define DM_FALSEALARM_THRESH_LOW 400 #define DM_FALSEALARM_THRESH_HIGH 1000 @@ -205,10 +202,6 @@ #define DM_DIG_FA_TH1 0x300 #define DM_DIG_FA_TH2 0x400 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_LOW 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -296,15 +289,6 @@ enum dm_dig_ext_port_alg_e { DIG_EXT_PORT_STAGE_MAX = 4, }; -enum dm_dig_connect_e { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - enum pwr_track_control_method { BBSWING, TXAGC, -- cgit v1.2.1 From b5d4478dc35e0cd9ef482d22aba069a19fe04a04 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:05 -0600 Subject: rtlwifi: rtl8188ee: Convert driver to use the common DM table init routine The previous patch created a routine in rtlwifi to initialize dm_digtable. Driver rtl8188ee is converted to use that routine. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8188ee/dm.c | 35 ++--------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c index 7ebf6e06871f..d930c1f78721 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c @@ -342,38 +342,6 @@ static void dm_tx_pwr_track_set_pwr(struct ieee80211_hw *hw, } } -static void rtl88e_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_dig = &rtlpriv->dm_digtable; - - dm_dig->dig_enable_flag = true; - dm_dig->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); - dm_dig->pre_igvalue = 0; - dm_dig->cur_sta_cstate = DIG_STA_DISCONNECT; - dm_dig->presta_cstate = DIG_STA_DISCONNECT; - dm_dig->curmultista_cstate = DIG_MULTISTA_DISCONNECT; - dm_dig->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_dig->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_dig->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_dig->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_dig->rx_gain_max = DM_DIG_MAX; - dm_dig->rx_gain_min = DM_DIG_MIN; - dm_dig->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_dig->back_range_max = DM_DIG_BACKOFF_MAX; - dm_dig->back_range_min = DM_DIG_BACKOFF_MIN; - dm_dig->pre_cck_cca_thres = 0xff; - dm_dig->cur_cck_cca_thres = 0x83; - dm_dig->forbidden_igi = DM_DIG_MIN; - dm_dig->large_fa_hit = 0; - dm_dig->recover_cnt = 0; - dm_dig->dig_min_0 = 0x25; - dm_dig->dig_min_1 = 0x25; - dm_dig->media_connect_0 = false; - dm_dig->media_connect_1 = false; - rtlpriv->dm.dm_initialgain_enable = true; -} - static u8 rtl88e_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1797,9 +1765,10 @@ static void rtl88e_dm_antenna_diversity(struct ieee80211_hw *hw) void rtl88e_dm_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; - rtl88e_dm_diginit(hw); + rtl_dm_diginit(hw, cur_igvalue); rtl88e_dm_init_dynamic_txpower(hw); rtl88e_dm_init_edca_turbo(hw); rtl88e_dm_init_rate_adaptive_mask(hw); -- cgit v1.2.1 From 3424a00fd559debf402559c226d9b1d895b94a5f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:06 -0600 Subject: rtlwifi: rtl8192c-common: Convert driver to use common DM table initialization These changes convert both rtl8192ce and rtl8192cu to use the new routine. Some additional definitions are needed in the core, thus several of the headers for other drivers are affected, but no other executable code is changed. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/core.c | 3 ++ drivers/net/wireless/rtlwifi/core.h | 16 +++++++++ drivers/net/wireless/rtlwifi/rtl8188ee/dm.h | 16 --------- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 44 ++++------------------- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h | 16 --------- drivers/net/wireless/rtlwifi/rtl8192de/dm.h | 16 --------- drivers/net/wireless/rtlwifi/rtl8192se/dm.h | 8 ----- drivers/net/wireless/rtlwifi/rtl8723ae/dm.c | 14 ++++---- drivers/net/wireless/rtlwifi/rtl8723ae/dm.h | 16 --------- drivers/net/wireless/rtlwifi/rtl8723be/dm.h | 8 ----- drivers/net/wireless/rtlwifi/rtl8821ae/dm.h | 16 --------- 11 files changed, 33 insertions(+), 140 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 5aa3ab3fff35..eb203163ed05 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -1878,6 +1878,7 @@ void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igvalue) struct dig_t *dm_digtable = &rtlpriv->dm_digtable; dm_digtable->dig_enable_flag = true; + dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; dm_digtable->cur_igvalue = cur_igvalue; dm_digtable->pre_igvalue = 0; dm_digtable->cur_sta_cstate = DIG_STA_DISCONNECT; @@ -1903,5 +1904,7 @@ void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igvalue) dm_digtable->media_connect_1 = false; rtlpriv->dm.dm_initialgain_enable = true; dm_digtable->bt30_cur_igi = 0x32; + dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LOWRSSI; } EXPORT_SYMBOL(rtl_dm_diginit); diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index c0a03174b666..1cde35694605 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h @@ -46,6 +46,22 @@ #define DM_DIG_BACKOFF_MIN -4 #define DM_DIG_BACKOFF_DEFAULT 10 +enum cck_packet_detection_threshold { + CCK_PD_STAGE_LOWRSSI = 0, + CCK_PD_STAGE_HIGHRSSI = 1, + CCK_FA_STAGE_LOW = 2, + CCK_FA_STAGE_HIGH = 3, + CCK_PD_STAGE_MAX = 4, +}; + +enum dm_dig_ext_port_alg_e { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + enum dm_dig_connect_e { DIG_STA_DISCONNECT, DIG_STA_CONNECT, diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h index 6217b7c2842a..51ad3f9b81c3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h @@ -249,14 +249,6 @@ enum tag_dynamic_init_gain_operation_type_definition { DIG_OP_TYPE_MAX }; -enum tag_cck_packet_detection_threshold_type_definition { - CCK_PD_STAGE_LOWRSSI = 0, - CCK_PD_STAGE_HIGHRSSI = 1, - CCK_FA_STAGE_LOW = 2, - CCK_FA_STAGE_HIGH = 3, - CCK_PD_STAGE_MAX = 4, -}; - enum dm_1r_cca_e { CCA_1R = 0, CCA_2R = 1, @@ -275,14 +267,6 @@ enum dm_sw_ant_switch_e { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg_e { - DIG_EXT_PORT_STAGE_0 = 0, - DIG_EXT_PORT_STAGE_1 = 1, - DIG_EXT_PORT_STAGE_2 = 2, - DIG_EXT_PORT_STAGE_3 = 3, - DIG_EXT_PORT_STAGE_MAX = 4, -}; - enum pwr_track_control_method { BBSWING, TXAGC diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index dabe18f168e0..f5ee67cda73a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -195,36 +195,6 @@ void dm_savepowerindex(struct ieee80211_hw *hw) } EXPORT_SYMBOL_GPL(dm_savepowerindex); -static void rtl92c_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_digtable = &rtlpriv->dm_digtable; - - dm_digtable->dig_enable_flag = true; - dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; - dm_digtable->cur_igvalue = 0x20; - dm_digtable->pre_igvalue = 0x0; - dm_digtable->cursta_cstate = DIG_STA_DISCONNECT; - dm_digtable->presta_cstate = DIG_STA_DISCONNECT; - dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; - dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_digtable->rx_gain_max = DM_DIG_MAX; - dm_digtable->rx_gain_min = DM_DIG_MIN; - dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; - dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; - dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; - dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LowRssi; - - dm_digtable->forbidden_igi = DM_DIG_MIN; - dm_digtable->large_fa_hit = 0; - dm_digtable->recover_cnt = 0; - dm_digtable->dig_min_0 = 0x25; -} - static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -508,27 +478,27 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) if (dm_digtable->rssi_val_min > 100) dm_digtable->rssi_val_min = 100; - if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { + if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { if (dm_digtable->rssi_val_min <= 25) dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_LowRssi; + CCK_PD_STAGE_LOWRSSI; else dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_HighRssi; + CCK_PD_STAGE_HIGHRSSI; } else { if (dm_digtable->rssi_val_min <= 20) dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_LowRssi; + CCK_PD_STAGE_LOWRSSI; else dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_HighRssi; + CCK_PD_STAGE_HIGHRSSI; } } else { dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; } if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) { - if ((dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) || + if ((dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) || (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_MAX)) rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83); else @@ -1375,7 +1345,7 @@ void rtl92c_dm_init(struct ieee80211_hw *hw) rtlpriv->dm.undec_sm_pwdb = -1; rtlpriv->dm.undec_sm_cck = -1; rtlpriv->dm.dm_initialgain_enable = true; - rtl92c_dm_diginit(hw); + rtl_dm_diginit(hw, 0x20); rtlpriv->dm.dm_flag |= HAL_DM_HIPWR_DISABLE; rtl92c_dm_init_dynamic_txpower(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h index 55ebffd91428..4422e31fedd9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h @@ -110,14 +110,6 @@ enum tag_dynamic_init_gain_operation_type_definition { DIG_OP_TYPE_MAX }; -enum tag_cck_packet_detection_threshold_type_definition { - CCK_PD_STAGE_LowRssi = 0, - CCK_PD_STAGE_HighRssi = 1, - CCK_FA_STAGE_Low = 2, - CCK_FA_STAGE_High = 3, - CCK_PD_STAGE_MAX = 4, -}; - enum dm_1r_cca_e { CCA_1R = 0, CCA_2R = 1, @@ -136,14 +128,6 @@ enum dm_sw_ant_switch_e { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg_e { - DIG_EXT_PORT_STAGE_0 = 0, - DIG_EXT_PORT_STAGE_1 = 1, - DIG_EXT_PORT_STAGE_2 = 2, - DIG_EXT_PORT_STAGE_3 = 3, - DIG_EXT_PORT_STAGE_MAX = 4, -}; - void rtl92c_dm_init(struct ieee80211_hw *hw); void rtl92c_dm_watchdog(struct ieee80211_hw *hw); void rtl92c_dm_write_dig(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.h b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h index d21b3bceab62..f2d318ceeb28 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h @@ -95,14 +95,6 @@ enum tag_dynamic_init_gain_operation_type_definition { DIG_OP_TYPE_MAX }; -enum tag_cck_packet_detection_threshold_type_definition { - CCK_PD_STAGE_LOWRSSI = 0, - CCK_PD_STAGE_HIGHRSSI = 1, - CCK_FA_STAGE_LOW = 2, - CCK_FA_STAGE_HIGH = 3, - CCK_PD_STAGE_MAX = 4, -}; - enum dm_1r_cca { CCA_1R = 0, CCA_2R = 1, @@ -121,14 +113,6 @@ enum dm_sw_ant_switch { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg { - DIG_EXT_PORT_STAGE_0 = 0, - DIG_EXT_PORT_STAGE_1 = 1, - DIG_EXT_PORT_STAGE_2 = 2, - DIG_EXT_PORT_STAGE_3 = 3, - DIG_EXT_PORT_STAGE_MAX = 4, -}; - void rtl92d_dm_init(struct ieee80211_hw *hw); void rtl92d_dm_watchdog(struct ieee80211_hw *hw); void rtl92d_dm_init_edca_turbo(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h index 7d778d384fde..be07d816acea 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h @@ -54,14 +54,6 @@ enum dm_dig_sta { DM_STA_DIG_MAX }; -enum dm_dig_ext_port_alg { - DIG_EXT_PORT_STAGE_0 = 0, - DIG_EXT_PORT_STAGE_1 = 1, - DIG_EXT_PORT_STAGE_2 = 2, - DIG_EXT_PORT_STAGE_3 = 3, - DIG_EXT_PORT_STAGE_MAX = 4, -}; - enum dm_ratr_sta { DM_RATR_STA_HIGH = 0, DM_RATR_STA_MIDDLEHIGH = 1, diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c index 80f4c5410a13..8bd124c40937 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c @@ -396,30 +396,30 @@ static void rtl8723e_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) { dm_digtable->rssi_val_min = rtl8723e_dm_initial_gain_min_pwdb(hw); - if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { + if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { if (dm_digtable->rssi_val_min <= 25) dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_LowRssi; + CCK_PD_STAGE_LOWRSSI; else dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_HighRssi; + CCK_PD_STAGE_HIGHRSSI; } else { if (dm_digtable->rssi_val_min <= 20) dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_LowRssi; + CCK_PD_STAGE_LOWRSSI; else dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_HighRssi; + CCK_PD_STAGE_HIGHRSSI; } } else { dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; } if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) { - if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) { + if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800) dm_digtable->cur_cck_fa_state = - CCK_FA_STAGE_High; + CCK_FA_STAGE_HIGH; else dm_digtable->cur_cck_fa_state = CCK_FA_STAGE_LOW; diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h index c54024e05489..57111052e86b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h @@ -95,14 +95,6 @@ enum tag_dynamic_init_gain_operation_type_definition { DIG_OP_TYPE_MAX }; -enum tag_cck_packet_detection_threshold_type_definition { - CCK_PD_STAGE_LowRssi = 0, - CCK_PD_STAGE_HighRssi = 1, - CCK_FA_STAGE_LOW = 2, - CCK_FA_STAGE_High = 3, - CCK_PD_STAGE_MAX = 4, -}; - enum dm_1r_cca_e { CCA_1R = 0, CCA_2R = 1, @@ -121,14 +113,6 @@ enum dm_sw_ant_switch_e { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg_e { - DIG_EXT_PORT_STAGE_0 = 0, - DIG_EXT_PORT_STAGE_1 = 1, - DIG_EXT_PORT_STAGE_2 = 2, - DIG_EXT_PORT_STAGE_3 = 3, - DIG_EXT_PORT_STAGE_MAX = 4, -}; - #define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1) #define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1) #define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h index f3e47abe0baf..533b4f2ec3ee 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h @@ -239,14 +239,6 @@ enum dm_sw_ant_switch_e { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg_e { - DIG_EXT_PORT_STAGE_0 = 0, - DIG_EXT_PORT_STAGE_1 = 1, - DIG_EXT_PORT_STAGE_2 = 2, - DIG_EXT_PORT_STAGE_3 = 3, - DIG_EXT_PORT_STAGE_MAX = 4, -}; - enum pwr_track_control_method { BBSWING, TXAGC diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h index f3118879cbdf..5516557f8b57 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h @@ -255,14 +255,6 @@ enum tag_dynamic_init_gain_operation_type_definition { DIG_OP_TYPE_MAX }; -enum tag_cck_packet_detection_threshold_type_definition { - CCK_PD_STAGE_LOWRSSI = 0, - CCK_PD_STAGE_HIGHRSSI = 1, - CCK_FA_STAGE_LOW = 2, - CCK_FA_STAGE_HIGH = 3, - CCK_PD_STAGE_MAX = 4, -}; - enum dm_1r_cca_e { CCA_1R = 0, CCA_2R = 1, @@ -281,14 +273,6 @@ enum dm_sw_ant_switch_e { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg_e { - DIG_EXT_PORT_STAGE_0 = 0, - DIG_EXT_PORT_STAGE_1 = 1, - DIG_EXT_PORT_STAGE_2 = 2, - DIG_EXT_PORT_STAGE_3 = 3, - DIG_EXT_PORT_STAGE_MAX = 4, -}; - enum pwr_track_control_method { BBSWING, TXAGC, -- cgit v1.2.1 From 8b17c1f3a5e058952177339d0310f27a4fb42c13 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:07 -0600 Subject: rtlwifi: rtl8192de: Convert driver to use common DM table initialization This patch converts driver rtl8192de to use the common routine to initialize dm_digtable. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192de/dm.c | 32 +++-------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index 75643abe0571..a1be5a68edfb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -156,34 +156,6 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */ }; -static void rtl92d_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *de_digtable = &rtlpriv->dm_digtable; - - de_digtable->dig_enable_flag = true; - de_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; - de_digtable->cur_igvalue = 0x20; - de_digtable->pre_igvalue = 0x0; - de_digtable->cursta_cstate = DIG_STA_DISCONNECT; - de_digtable->presta_cstate = DIG_STA_DISCONNECT; - de_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; - de_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; - de_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - de_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - de_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - de_digtable->rx_gain_max = DM_DIG_FA_UPPER; - de_digtable->rx_gain_min = DM_DIG_FA_LOWER; - de_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; - de_digtable->back_range_max = DM_DIG_BACKOFF_MAX; - de_digtable->back_range_min = DM_DIG_BACKOFF_MIN; - de_digtable->pre_cck_pd_state = CCK_PD_STAGE_LOWRSSI; - de_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; - de_digtable->large_fa_hit = 0; - de_digtable->recover_cnt = 0; - de_digtable->forbidden_igi = DM_DIG_FA_LOWER; -} - static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) { u32 ret_value; @@ -1306,7 +1278,9 @@ void rtl92d_dm_init(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; - rtl92d_dm_diginit(hw); + rtl_dm_diginit(hw, 0x20); + rtlpriv->dm_digtable.rx_gain_max = DM_DIG_FA_UPPER; + rtlpriv->dm_digtable.rx_gain_min = DM_DIG_FA_LOWER; rtl92d_dm_init_dynamic_txpower(hw); rtl92d_dm_init_edca_turbo(hw); rtl92d_dm_init_rate_adaptive_mask(hw); -- cgit v1.2.1 From 153cb55731b68ddf7b0ebaa55536b56d766b47e6 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:08 -0600 Subject: rtlwifi: rtl8192ee: Convert driver to use common DM table initialization Convert driver rtl8192ee to use the common routine to initialize dm_digtable. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ee/dm.c | 32 ++--------------------------- 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c index 70e58d102d1e..459f3d0efa2f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c @@ -152,35 +152,6 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */ }; -static void rtl92ee_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_dig = &rtlpriv->dm_digtable; - - dm_dig->cur_igvalue = rtl_get_bbreg(hw, DM_REG_IGI_A_11N, - DM_BIT_IGI_11N); - dm_dig->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_dig->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_dig->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_dig->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_dig->rx_gain_max = DM_DIG_MAX; - dm_dig->rx_gain_min = DM_DIG_MIN; - dm_dig->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_dig->back_range_max = DM_DIG_BACKOFF_MAX; - dm_dig->back_range_min = DM_DIG_BACKOFF_MIN; - dm_dig->pre_cck_cca_thres = 0xff; - dm_dig->cur_cck_cca_thres = 0x83; - dm_dig->forbidden_igi = DM_DIG_MIN; - dm_dig->large_fa_hit = 0; - dm_dig->recover_cnt = 0; - dm_dig->dig_min_0 = DM_DIG_MIN; - dm_dig->dig_min_1 = DM_DIG_MIN; - dm_dig->media_connect_0 = false; - dm_dig->media_connect_1 = false; - rtlpriv->dm.dm_initialgain_enable = true; - dm_dig->bt30_cur_igi = 0x32; -} - static void rtl92ee_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) { u32 ret_value; @@ -1089,10 +1060,11 @@ static void rtl92ee_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw) void rtl92ee_dm_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 cur_igvalue = rtl_get_bbreg(hw, DM_REG_IGI_A_11N, DM_BIT_IGI_11N); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; - rtl92ee_dm_diginit(hw); + rtl_dm_diginit(hw, cur_igvalue); rtl92ee_dm_init_rate_adaptive_mask(hw); rtl92ee_dm_init_primary_cca_check(hw); rtl92ee_dm_init_edca_turbo(hw); -- cgit v1.2.1 From 3592c54b6c8e85a1713515f463379c6a97bf8009 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:09 -0600 Subject: rtlwifi: rtl8723ae: Convert driver to use common DM table initialization Convert driver rtl8723ae to use common routine rtl_dm_diginit(). Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8723ae/dm.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c index 8bd124c40937..4c1c96c96a5a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c @@ -147,31 +147,6 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} }; -static void rtl8723e_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_digtable = &rtlpriv->dm_digtable; - - dm_digtable->dig_enable_flag = true; - dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; - dm_digtable->cur_igvalue = 0x20; - dm_digtable->pre_igvalue = 0x0; - dm_digtable->cursta_cstate = DIG_STA_DISCONNECT; - dm_digtable->presta_cstate = DIG_STA_DISCONNECT; - dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; - dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_digtable->rx_gain_max = DM_DIG_MAX; - dm_digtable->rx_gain_min = DM_DIG_MIN; - dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; - dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; - dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; - dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; -} - static u8 rtl8723e_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -819,7 +794,7 @@ void rtl8723e_dm_init(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; - rtl8723e_dm_diginit(hw); + rtl_dm_diginit(hw, 0x20); rtl8723_dm_init_dynamic_txpower(hw); rtl8723_dm_init_edca_turbo(hw); rtl8723e_dm_init_rate_adaptive_mask(hw); -- cgit v1.2.1 From ac2f0baefab920a3f9117993eb1455b40b265ab5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:10 -0600 Subject: rtlwifi: rtl8723be: Convert driver to use common DM table initialization Convert driver rtl8723be to use routine rtl_dm_diginit(). Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8723be/dm.c | 32 ++--------------------------- 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c index ddf45d9fd6ea..2367e8f47a5b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c @@ -212,35 +212,6 @@ void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type, (pwr_val << 16) | (pwr_val << 24); } -static void rtl8723be_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_digtable = &rtlpriv->dm_digtable; - - dm_digtable->dig_enable_flag = true; - dm_digtable->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); - dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_digtable->rx_gain_max = DM_DIG_MAX; - dm_digtable->rx_gain_min = DM_DIG_MIN; - dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; - dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; - dm_digtable->pre_cck_cca_thres = 0xff; - dm_digtable->cur_cck_cca_thres = 0x83; - dm_digtable->forbidden_igi = DM_DIG_MIN; - dm_digtable->large_fa_hit = 0; - dm_digtable->recover_cnt = 0; - dm_digtable->dig_min_0 = DM_DIG_MIN; - dm_digtable->dig_min_1 = DM_DIG_MIN; - dm_digtable->media_connect_0 = false; - dm_digtable->media_connect_1 = false; - rtlpriv->dm.dm_initialgain_enable = true; - dm_digtable->bt30_cur_igi = 0x32; -} - void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -294,9 +265,10 @@ static void rtl8723be_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw) void rtl8723be_dm_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; - rtl8723be_dm_diginit(hw); + rtl_dm_diginit(hw, cur_igvalue); rtl8723be_dm_init_rate_adaptive_mask(hw); rtl8723_dm_init_edca_turbo(hw); rtl8723_dm_init_dynamic_bb_powersaving(hw); -- cgit v1.2.1 From 9259ee79208a95aa20a9824717a9f22b0a52cccd Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:11 -0600 Subject: rtlwifi: rtl8821ae: Convert driver to use common DM table initialization Convert driver to use routine rtl_dm_diginit(). Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8821ae/dm.c | 31 ++--------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c index 4af4613cf7e3..0b2082dc48f1 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c @@ -520,34 +520,6 @@ void rtl8821ae_dm_initialize_txpower_tracking_thermalmeter( } } -static void rtl8821ae_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_digtable = &rtlpriv->dm_digtable; - - dm_digtable->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); - dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_digtable->rx_gain_max = DM_DIG_MAX; - dm_digtable->rx_gain_min = DM_DIG_MIN; - dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; - dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; - dm_digtable->pre_cck_cca_thres = 0xff; - dm_digtable->cur_cck_cca_thres = 0x83; - dm_digtable->forbidden_igi = DM_DIG_MIN; - dm_digtable->large_fa_hit = 0; - dm_digtable->recover_cnt = 0; - dm_digtable->dig_min_0 = DM_DIG_MIN; - dm_digtable->dig_min_1 = DM_DIG_MIN; - dm_digtable->media_connect_0 = false; - dm_digtable->media_connect_1 = false; - rtlpriv->dm.dm_initialgain_enable = true; - dm_digtable->bt30_cur_igi = 0x32; -} - void rtl8821ae_dm_init_edca_turbo(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -607,6 +579,7 @@ void rtl8821ae_dm_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &rtlpriv->phy; + u32 cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); spin_lock(&rtlpriv->locks.iqk_lock); rtlphy->lck_inprogress = false; @@ -614,7 +587,7 @@ void rtl8821ae_dm_init(struct ieee80211_hw *hw) rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; rtl8821ae_dm_common_info_self_init(hw); - rtl8821ae_dm_diginit(hw); + rtl_dm_diginit(hw, cur_igvalue); rtl8821ae_dm_init_rate_adaptive_mask(hw); rtl8821ae_dm_init_edca_turbo(hw); rtl8821ae_dm_initialize_txpower_tracking_thermalmeter(hw); -- cgit v1.2.1 From ed0fb7eb2b2d27a07610b75d1f3a68cc22716347 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 6 Jan 2015 09:58:12 -0600 Subject: rtlwifi: Move macro definitions to core Several of the drivers still were defining their own copies of various macros. These are all moved into the core. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/core.h | 1 + drivers/net/wireless/rtlwifi/rtl8188ee/dm.h | 3 --- drivers/net/wireless/rtlwifi/rtl8192ee/dm.h | 3 --- drivers/net/wireless/rtlwifi/rtl8192se/dm.c | 6 +++--- drivers/net/wireless/rtlwifi/rtl8192se/dm.h | 1 - drivers/net/wireless/rtlwifi/rtl8723be/dm.h | 3 --- drivers/net/wireless/rtlwifi/rtl8821ae/dm.h | 9 --------- 7 files changed, 4 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index 1cde35694605..7b64e34f421e 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h @@ -42,6 +42,7 @@ #define DM_DIG_MAX 0x3e #define DM_DIG_MIN 0x1e +#define DM_DIG_MAX_AP 0x32 #define DM_DIG_BACKOFF_MAX 12 #define DM_DIG_BACKOFF_MIN -4 #define DM_DIG_BACKOFF_DEFAULT 10 diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h index 51ad3f9b81c3..071ccee69eae 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h @@ -186,9 +186,6 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_MAX_AP 0x32 -#define DM_DIG_MIN_AP 0x20 - #define DM_DIG_FA_UPPER 0x3e #define DM_DIG_FA_LOWER 0x1e #define DM_DIG_FA_TH0 0x200 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h index 4880e191e02a..107d5a488fa8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h @@ -189,9 +189,6 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_MAX_AP 0x32 -#define DM_DIG_MIN_AP 0x20 - #define DM_DIG_FA_UPPER 0x3e #define DM_DIG_FA_LOWER 0x1e #define DM_DIG_FA_TH0 0x200 diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c index 6cac70b77539..575980b88658 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -470,7 +470,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) if (digtable->backoff_enable_flag) rtl92s_backoff_enable_flag(hw); else - digtable->back_val = DM_DIG_BACKOFF; + digtable->back_val = DM_DIG_BACKOFF_MAX; if ((digtable->rssi_val + 10 - digtable->back_val) > digtable->rx_gain_max) @@ -504,7 +504,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE); - digtable->back_val = DM_DIG_BACKOFF; + digtable->back_val = DM_DIG_BACKOFF_MAX; digtable->cur_igvalue = rtlpriv->phy.default_initialgain[0]; digtable->pre_igvalue = 0; return; @@ -692,7 +692,7 @@ static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw) /* for dig debug rssi value */ digtable->rssi_val = 50; - digtable->back_val = DM_DIG_BACKOFF; + digtable->back_val = DM_DIG_BACKOFF_MAX; digtable->rx_gain_max = DM_DIG_MAX; digtable->rx_gain_min = DM_DIG_MIN; diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h index be07d816acea..de6ac796c74d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h @@ -83,7 +83,6 @@ enum dm_ratr_sta { #define DM_DIG_HIGH_PWR_THRESH_HIGH 75 #define DM_DIG_HIGH_PWR_THRESH_LOW 70 -#define DM_DIG_BACKOFF 12 #define DM_DIG_MIN_Netcore 0x12 void rtl92s_dm_watchdog(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h index 533b4f2ec3ee..f752a2cad63d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h @@ -180,9 +180,6 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_MAX_AP 0x32 -#define DM_DIG_MIN_AP 0x20 - #define DM_DIG_FA_UPPER 0x3e #define DM_DIG_FA_LOWER 0x1e #define DM_DIG_FA_TH0 0x200 diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h index 5516557f8b57..625a6bbb21fc 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h @@ -187,15 +187,6 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - -#define DM_DIG_MAX_AP 0x32 -#define DM_DIG_MIN_AP 0x20 - #define DM_DIG_FA_UPPER 0x3e #define DM_DIG_FA_LOWER 0x1e #define DM_DIG_FA_TH0 200 -- cgit v1.2.1 From 96bba98393f97e4c4bfe29341b3ad2adef32bde2 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 7 Jan 2015 17:04:10 +0200 Subject: ath10k: fix build error when hwmon is off kbuild reported a linking error: ERROR: "devm_hwmon_device_register_with_groups" [drivers/net/wireless/ath/ath10k/ath10k_core.ko] undefined! Fix it by returning early and letting the compiler to optimise out the function call. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/thermal.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index d93913538d18..b14ae8d135f6 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -213,6 +213,11 @@ int ath10k_thermal_register(struct ath10k *ar) if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4) return 0; + /* Avoid linking error on devm_hwmon_device_register_with_groups, I + * guess linux/hwmon.h is missing proper stubs. */ + if (!config_enabled(HWMON)) + return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev, "ath10k_hwmon", ar, ath10k_hwmon_groups); -- cgit v1.2.1 From 9b1a6d36c38d236b42d912fce852f37d2367b593 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Wed, 7 Jan 2015 15:04:12 +0000 Subject: stmmac: dwmac-sti: Pass sysconfig register offset via syscon dt property. Based on Arnds review comments here https://lkml.org/lkml/2014/11/13/161, we should not be mixing address spaces in the reg property like this driver currently does. This patch updates the driver, dt docs and also the existing dt nodes to pass the sysconfig offset in the syscon dt property. This patch breaks DT compatibility! But this platform is considered WIP, and is only used by a few developers who are upstreaming support for it. This change has been done as a single atomic commit to ensure it is bisectable. Signed-off-by: Peter Griffin Reviewed-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index 056b358b4a72..bb6e2dc61bec 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -122,7 +122,7 @@ struct sti_dwmac { bool ext_phyclk; /* Clock from external PHY */ u32 tx_retime_src; /* TXCLK Retiming*/ struct clk *clk; /* PHY clock */ - int ctrl_reg; /* GMAC glue-logic control register */ + u32 ctrl_reg; /* GMAC glue-logic control register */ int clk_sel_reg; /* GMAC ext clk selection register */ struct device *dev; struct regmap *regmap; @@ -285,11 +285,6 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, if (!np) return -EINVAL; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf"); - if (!res) - return -ENODATA; - dwmac->ctrl_reg = res->start; - /* clk selection from extra syscfg register */ dwmac->clk_sel_reg = -ENXIO; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-clkconf"); @@ -300,6 +295,12 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, if (IS_ERR(regmap)) return PTR_ERR(regmap); + err = of_property_read_u32_index(np, "st,syscon", 1, &dwmac->ctrl_reg); + if (err) { + dev_err(dev, "Can't get sysconfig ctrl offset (%d)\n", err); + return err; + } + dwmac->dev = dev; dwmac->interface = of_get_phy_mode(np); dwmac->regmap = regmap; -- cgit v1.2.1 From 270d73c1c32c71e215f1c64e70be82063ec65005 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Thu, 8 Jan 2015 12:01:27 +0800 Subject: irda: Removed all unused timeval variables In the file au1k_ir.c & via-ircc.h, there were two unused definitions of the timeval type members, this commit therefore removes this unneeded code. In other three files, the same problem is the rx_time member is only ever written, never read, so removed it entirely. Signed-off-by: Chunyan Zhang Reviewed-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/irda/au1k_ir.c | 3 --- drivers/net/irda/kingsun-sir.c | 3 --- drivers/net/irda/ks959-sir.c | 3 --- drivers/net/irda/mcs7780.c | 2 -- drivers/net/irda/mcs7780.h | 1 - drivers/net/irda/via-ircc.h | 4 ---- 6 files changed, 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index e151205281e2..44e4f386a5dc 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -163,8 +162,6 @@ struct au1k_private { iobuff_t rx_buff; struct net_device *netdev; - struct timeval stamp; - struct timeval now; struct qos_info qos; struct irlap_cb *irlap; diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index e638893e98a9..fb5d162ec7d2 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -114,7 +114,6 @@ struct kingsun_cb { (usually 8) */ iobuff_t rx_buff; /* receive unwrap state machine */ - struct timeval rx_time; spinlock_t lock; int receiving; @@ -235,7 +234,6 @@ static void kingsun_rcv_irq(struct urb *urb) &kingsun->netdev->stats, &kingsun->rx_buff, bytes[i]); } - do_gettimeofday(&kingsun->rx_time); kingsun->receiving = (kingsun->rx_buff.state != OUTSIDE_FRAME) ? 1 : 0; @@ -273,7 +271,6 @@ static int kingsun_net_open(struct net_device *netdev) skb_reserve(kingsun->rx_buff.skb, 1); kingsun->rx_buff.head = kingsun->rx_buff.skb->data; - do_gettimeofday(&kingsun->rx_time); kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!kingsun->rx_urb) diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index e6b3804edacd..8e6e0edf2440 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -187,7 +187,6 @@ struct ks959_cb { __u8 *rx_buf; __u8 rx_variable_xormask; iobuff_t rx_unwrap_buff; - struct timeval rx_time; struct usb_ctrlrequest *speed_setuprequest; struct urb *speed_urb; @@ -476,7 +475,6 @@ static void ks959_rcv_irq(struct urb *urb) bytes[i]); } } - do_gettimeofday(&kingsun->rx_time); kingsun->receiving = (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; } @@ -514,7 +512,6 @@ static int ks959_net_open(struct net_device *netdev) skb_reserve(kingsun->rx_unwrap_buff.skb, 1); kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data; - do_gettimeofday(&kingsun->rx_time); kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!kingsun->rx_urb) diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index e4d678fbeb2f..bca6a1e72d1d 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -722,7 +722,6 @@ static int mcs_net_open(struct net_device *netdev) skb_reserve(mcs->rx_buff.skb, 1); mcs->rx_buff.head = mcs->rx_buff.skb->data; - do_gettimeofday(&mcs->rx_time); /* * Now that everything should be initialized properly, @@ -799,7 +798,6 @@ static void mcs_receive_irq(struct urb *urb) mcs_unwrap_fir(mcs, urb->transfer_buffer, urb->actual_length); } - do_gettimeofday(&mcs->rx_time); } ret = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h index b10689b2887c..a6e8f7dbafc9 100644 --- a/drivers/net/irda/mcs7780.h +++ b/drivers/net/irda/mcs7780.h @@ -116,7 +116,6 @@ struct mcs_cb { __u8 *fifo_status; iobuff_t rx_buff; /* receive unwrap state machine */ - struct timeval rx_time; spinlock_t lock; int receiving; diff --git a/drivers/net/irda/via-ircc.h b/drivers/net/irda/via-ircc.h index 7ce820ecc361..ac1525573398 100644 --- a/drivers/net/irda/via-ircc.h +++ b/drivers/net/irda/via-ircc.h @@ -29,7 +29,6 @@ this program; if not, see . ********************************************************************/ #ifndef via_IRCC_H #define via_IRCC_H -#include #include #include #include @@ -106,9 +105,6 @@ struct via_ircc_cb { __u8 ier; /* Interrupt enable register */ - struct timeval stamp; - struct timeval now; - spinlock_t lock; /* For serializing operations */ __u32 flags; /* Interface flags */ -- cgit v1.2.1 From 9f61e309c54ac7f906422abd4ccebe10bee9debd Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Thu, 8 Jan 2015 12:01:28 +0800 Subject: irda: ali-ircc: Replace timeval with ktime_t The ali ircc driver uses 'timeval', which we try to remove in the kernel because all 32-bit time types will break in the year 2038. This patch also changes do_gettimeofday() to ktime_get() accordingly, since ktime_get returns a ktime_t, but do_gettimeofday returns a struct timeval, and the other reason is that ktime_get() uses the monotonic clock. This patch uses ktime_us_delta to get the elapsed time, and in this way it no longer needs to check for the overflow, because ktime_us_delta returns time difference of microsecond. Signed-off-by: Chunyan Zhang Reviewed-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/irda/ali-ircc.c | 11 +++-------- drivers/net/irda/ali-ircc.h | 5 ++--- 2 files changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 58f98f4de773..58ae11a14bb6 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -1462,17 +1462,12 @@ static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb, if (mtt) { /* Check how much time we have used already */ - do_gettimeofday(&self->now); - - diff = self->now.tv_usec - self->stamp.tv_usec; + diff = ktime_us_delta(ktime_get(), self->stamp); /* self->stamp is set from ali_ircc_dma_receive_complete() */ pr_debug("%s(), ******* diff = %d *******\n", __func__, diff); - - if (diff < 0) - diff += 1000000; - + /* Check if the mtt is larger than the time we have * already used by all the protocol processing */ @@ -1884,7 +1879,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) * reduce the min turn time a bit since we will know * how much time we have used for protocol processing */ - do_gettimeofday(&self->stamp); + self->stamp = ktime_get(); skb = dev_alloc_skb(len+1); if (skb == NULL) diff --git a/drivers/net/irda/ali-ircc.h b/drivers/net/irda/ali-ircc.h index 0c8edb41bd0a..c2d9747a5108 100644 --- a/drivers/net/irda/ali-ircc.h +++ b/drivers/net/irda/ali-ircc.h @@ -22,7 +22,7 @@ #ifndef ALI_IRCC_H #define ALI_IRCC_H -#include +#include #include #include @@ -209,8 +209,7 @@ struct ali_ircc_cb { unsigned char rcvFramesOverflow; - struct timeval stamp; - struct timeval now; + ktime_t stamp; spinlock_t lock; /* For serializing operations */ -- cgit v1.2.1 From ca98278a14b76916cd09c2c899c21c29a0748d15 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Thu, 8 Jan 2015 12:01:29 +0800 Subject: irda: irda-usb: Replace timeval with ktime_t The irda usb driver uses 'timeval', which we try to remove in the kernel because all 32-bit time types will break in the year 2038. This patch also changes do_gettimeofday() to ktime_get() accordingly, since ktime_get returns a ktime_t, but do_gettimeofday returns a struct timeval, and the other reason is that ktime_get() uses the monotonic clock. This patch uses ktime_us_delta to get the elapsed time, and in this way it no longer needs to check for the overflow, because ktime_us_delta returns time difference of microsecond. Signed-off-by: Chunyan Zhang Reviewed-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/irda/irda-usb.c | 10 ++-------- drivers/net/irda/irda-usb.h | 5 ++--- 2 files changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 48b2f9a321b7..f6c916312577 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -495,18 +495,12 @@ static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb, mtt = irda_get_mtt(skb); if (mtt) { int diff; - do_gettimeofday(&self->now); - diff = self->now.tv_usec - self->stamp.tv_usec; + diff = ktime_us_delta(ktime_get(), self->stamp); #ifdef IU_USB_MIN_RTT /* Factor in USB delays -> Get rid of udelay() that * would be lost in the noise - Jean II */ diff += IU_USB_MIN_RTT; #endif /* IU_USB_MIN_RTT */ - /* If the usec counter did wraparound, the diff will - * go negative (tv_usec is a long), so we need to - * correct it by one second. Jean II */ - if (diff < 0) - diff += 1000000; /* Check if the mtt is larger than the time we have * already used by all the protocol processing @@ -869,7 +863,7 @@ static void irda_usb_receive(struct urb *urb) * reduce the min turn time a bit since we will know * how much time we have used for protocol processing */ - do_gettimeofday(&self->stamp); + self->stamp = ktime_get(); /* Check if we need to copy the data to a new skb or not. * For most frames, we use ZeroCopy and pass the already diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h index 58ddb5214916..8ac389fa9348 100644 --- a/drivers/net/irda/irda-usb.h +++ b/drivers/net/irda/irda-usb.h @@ -29,7 +29,7 @@ * *****************************************************************************/ -#include +#include #include #include /* struct irlap_cb */ @@ -157,8 +157,7 @@ struct irda_usb_cb { char *speed_buff; /* Buffer for speed changes */ char *tx_buff; - struct timeval stamp; - struct timeval now; + ktime_t stamp; spinlock_t lock; /* For serializing Tx operations */ -- cgit v1.2.1 From 4c3bd197a0f9b98343c5a6533e76a259271855b4 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Thu, 8 Jan 2015 12:01:30 +0800 Subject: irda: nsc-ircc: Replace timeval with ktime_t The nsc ircc driver uses 'timeval', which we try to remove in the kernel because all 32-bit time types will break in the year 2038. This patch also changes do_gettimeofday() to ktime_get() accordingly, since ktime_get returns a ktime_t, but do_gettimeofday returns a struct timeval, and the other reason is that ktime_get() uses the monotonic clock. This patch uses ktime_us_delta to get the elapsed time, and in this way it no longer needs to check for the overflow, because ktime_us_delta returns time difference of microsecond. Signed-off-by: Chunyan Zhang Reviewed-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/irda/nsc-ircc.c | 7 ++----- drivers/net/irda/nsc-ircc.h | 5 ++--- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index e7317b104bfb..dc0dbd8dd0b5 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1501,10 +1501,7 @@ static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb, mtt = irda_get_mtt(skb); if (mtt) { /* Check how much time we have used already */ - do_gettimeofday(&self->now); - diff = self->now.tv_usec - self->stamp.tv_usec; - if (diff < 0) - diff += 1000000; + diff = ktime_us_delta(ktime_get(), self->stamp); /* Check if the mtt is larger than the time we have * already used by all the protocol processing @@ -1867,7 +1864,7 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) * reduce the min turn time a bit since we will know * how much time we have used for protocol processing */ - do_gettimeofday(&self->stamp); + self->stamp = ktime_get(); skb = dev_alloc_skb(len+1); if (skb == NULL) { diff --git a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h index 32fa58211fad..7be5acb56532 100644 --- a/drivers/net/irda/nsc-ircc.h +++ b/drivers/net/irda/nsc-ircc.h @@ -28,7 +28,7 @@ #ifndef NSC_IRCC_H #define NSC_IRCC_H -#include +#include #include #include @@ -263,8 +263,7 @@ struct nsc_ircc_cb { __u8 ier; /* Interrupt enable register */ - struct timeval stamp; - struct timeval now; + ktime_t stamp; spinlock_t lock; /* For serializing operations */ -- cgit v1.2.1 From 89a07e1726534957fc987b39742048d592ec9aae Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Thu, 8 Jan 2015 12:01:31 +0800 Subject: irda: stir4200: Replace timeval with ktime_t The stir4200 driver uses 'timeval', which we try to remove in the kernel because all 32-bit time types will break in the year 2038. This patch also changes do_gettimeofday() to ktime_get() accordingly, since ktime_get returns a ktime_t, but do_gettimeofday returns a struct timeval, and the other reason is that ktime_get() uses the monotonic clock. This patch uses ktime_us_delta to get the elapsed time of microsecond. Signed-off-by: Chunyan Zhang Reviewed-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/irda/stir4200.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index dd1bd1060ec9..83cc48a01802 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -174,7 +175,7 @@ struct stir_cb { __u8 *fifo_status; iobuff_t rx_buff; /* receive unwrap state machine */ - struct timeval rx_time; + ktime_t rx_time; int receiving; struct urb *rx_urb; }; @@ -650,15 +651,12 @@ static int fifo_txwait(struct stir_cb *stir, int space) static void turnaround_delay(const struct stir_cb *stir, long us) { long ticks; - struct timeval now; if (us <= 0) return; - do_gettimeofday(&now); - if (now.tv_sec - stir->rx_time.tv_sec > 0) - us -= USEC_PER_SEC; - us -= now.tv_usec - stir->rx_time.tv_usec; + us -= ktime_us_delta(ktime_get(), stir->rx_time); + if (us < 10) return; @@ -823,8 +821,8 @@ static void stir_rcv_irq(struct urb *urb) pr_debug("receive %d\n", urb->actual_length); unwrap_chars(stir, urb->transfer_buffer, urb->actual_length); - - do_gettimeofday(&stir->rx_time); + + stir->rx_time = ktime_get(); } /* kernel thread is stopping receiver don't resubmit */ @@ -876,7 +874,7 @@ static int stir_net_open(struct net_device *netdev) skb_reserve(stir->rx_buff.skb, 1); stir->rx_buff.head = stir->rx_buff.skb->data; - do_gettimeofday(&stir->rx_time); + stir->rx_time = ktime_get(); stir->rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!stir->rx_urb) -- cgit v1.2.1 From 497ec1f2a086878d6a42334eda72bfef079dd484 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Thu, 8 Jan 2015 12:01:32 +0800 Subject: irda: vlsi_ir: Replace timeval with ktime_t The vlsi ir driver uses 'timeval', which we try to remove in the kernel because all 32-bit time types will break in the year 2038. This patch also changes do_gettimeofday() to ktime_get() accordingly, since ktime_get returns a ktime_t, but do_gettimeofday returns a struct timeval, and the other reason is that ktime_get() uses the monotonic clock. This patch uses ktime_us_delta to get the elapsed time of microsecond, and uses div_s64_rem to get what seconds & microseconds time elapsed for printing. This patch also changes the function 'vlsi_hard_start_xmit' to do the same things as the others drivers, that is passing the remaining time into udelay() instead of looping until enough time has passed. Signed-off-by: Chunyan Zhang Reviewed-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/irda/vlsi_ir.c | 46 +++++++++++++--------------------------------- drivers/net/irda/vlsi_ir.h | 2 +- 2 files changed, 14 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index ac39d9f33d5f..a0849f49bbec 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -33,6 +33,7 @@ MODULE_LICENSE("GPL"); /********************************************************/ #include +#include #include #include #include @@ -40,9 +41,9 @@ MODULE_LICENSE("GPL"); #include #include #include -#include #include #include +#include #include #include #include @@ -180,8 +181,7 @@ static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev) vlsi_irda_dev_t *idev = netdev_priv(ndev); u8 byte; u16 word; - unsigned delta1, delta2; - struct timeval now; + s32 sec, usec; unsigned iobase = ndev->base_addr; seq_printf(seq, "\n%s link state: %s / %s / %s / %s\n", ndev->name, @@ -277,17 +277,9 @@ static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev) seq_printf(seq, "\nsw-state:\n"); seq_printf(seq, "IrPHY setup: %d baud - %s encoding\n", idev->baud, (idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR")); - do_gettimeofday(&now); - if (now.tv_usec >= idev->last_rx.tv_usec) { - delta2 = now.tv_usec - idev->last_rx.tv_usec; - delta1 = 0; - } - else { - delta2 = 1000000 + now.tv_usec - idev->last_rx.tv_usec; - delta1 = 1; - } - seq_printf(seq, "last rx: %lu.%06u sec\n", - now.tv_sec - idev->last_rx.tv_sec - delta1, delta2); + sec = div_s64_rem(ktime_us_delta(ktime_get(), idev->last_rx), + USEC_PER_SEC, &usec); + seq_printf(seq, "last rx: %ul.%06u sec\n", sec, usec); seq_printf(seq, "RX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu", ndev->stats.rx_packets, ndev->stats.rx_bytes, ndev->stats.rx_errors, @@ -661,7 +653,7 @@ static void vlsi_rx_interrupt(struct net_device *ndev) } } - do_gettimeofday(&idev->last_rx); /* remember "now" for later mtt delay */ + idev->last_rx = ktime_get(); /* remember "now" for later mtt delay */ vlsi_fill_rx(r); @@ -858,9 +850,8 @@ static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb, unsigned iobase = ndev->base_addr; u8 status; u16 config; - int mtt; + int mtt, diff; int len, speed; - struct timeval now, ready; char *msg = NULL; speed = irda_get_next_speed(skb); @@ -940,21 +931,10 @@ static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb, spin_unlock_irqrestore(&idev->lock, flags); if ((mtt = irda_get_mtt(skb)) > 0) { - - ready.tv_usec = idev->last_rx.tv_usec + mtt; - ready.tv_sec = idev->last_rx.tv_sec; - if (ready.tv_usec >= 1000000) { - ready.tv_usec -= 1000000; - ready.tv_sec++; /* IrLAP 1.1: mtt always < 1 sec */ - } - for(;;) { - do_gettimeofday(&now); - if (now.tv_sec > ready.tv_sec || - (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec)) - break; - udelay(100); + diff = ktime_us_delta(ktime_get(), idev->last_rx); + if (mtt > diff) + udelay(mtt - diff); /* must not sleep here - called under netif_tx_lock! */ - } } /* tx buffer already owned by CPU due to pci_dma_sync_single_for_cpu() @@ -1333,7 +1313,7 @@ static int vlsi_start_hw(vlsi_irda_dev_t *idev) vlsi_fill_rx(idev->rx_ring); - do_gettimeofday(&idev->last_rx); /* first mtt may start from now on */ + idev->last_rx = ktime_get(); /* first mtt may start from now on */ outw(0, iobase+VLSI_PIO_PROMPT); /* kick hw state machine */ @@ -1520,7 +1500,7 @@ static int vlsi_open(struct net_device *ndev) if (!idev->irlap) goto errout_free_ring; - do_gettimeofday(&idev->last_rx); /* first mtt may start from now on */ + idev->last_rx = ktime_get(); /* first mtt may start from now on */ idev->new_baud = 9600; /* start with IrPHY using 9600(SIR) mode */ diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index f9119c6d2a09..f9db2ce4c5c6 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -723,7 +723,7 @@ typedef struct vlsi_irda_dev { void *virtaddr; struct vlsi_ring *tx_ring, *rx_ring; - struct timeval last_rx; + ktime_t last_rx; spinlock_t lock; struct mutex mtx; -- cgit v1.2.1 From f6603ff2b7a8e02b748dd1acf00fcde78eb5dbcb Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 12 Jan 2015 12:30:02 +0200 Subject: ath10k: Fix DMA burst size A value of zero indicates that 128B is the maximum DMA request size for read/writes. But PCI cards based on AR9880 can support 256B, so enable this for the 10.2 firmware. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 3 +++ drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 5729901923ac..7b771ae7789f 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -183,6 +183,9 @@ struct ath10k_pktlog_hdr { #define TARGET_10X_NUM_MSDU_DESC (1024 + 400) #define TARGET_10X_MAX_FRAG_ENTRIES 0 +/* 10.2 parameters */ +#define TARGET_10_2_DMA_BURST_SIZE 1 + /* Target specific defines for WMI-TLV firmware */ #define TARGET_TLV_NUM_VDEVS 3 #define TARGET_TLV_NUM_STATIONS 32 diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index ac742905331b..b103122c5874 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3744,7 +3744,7 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE); config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE); config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES); - config.dma_burst_size = __cpu_to_le32(TARGET_10X_DMA_BURST_SIZE); + config.dma_burst_size = __cpu_to_le32(TARGET_10_2_DMA_BURST_SIZE); config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM); val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK; -- cgit v1.2.1 From b6c8e287f6089559146e2a388a63fbe5460d7f44 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 12 Jan 2015 12:30:02 +0200 Subject: ath10k: Enable RX batching This feature allows the FW to batch RX indications, reducing the rate of host interrupt generation, which in turn reduces CPU load. Currently, this is enabled only for the 10.2 firmware. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b103122c5874..c56d2fa5edb8 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3710,7 +3710,7 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) struct wmi_init_cmd_10_2 *cmd; struct sk_buff *buf; struct wmi_resource_config_10x config = {}; - u32 len, val; + u32 len, val, features; config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); @@ -3764,6 +3764,9 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) cmd = (struct wmi_init_cmd_10_2 *)buf->data; + features = WMI_10_2_RX_BATCH_MODE; + cmd->resource_config.feature_mask = __cpu_to_le32(features); + memcpy(&cmd->resource_config.common, &config, sizeof(config)); ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); -- cgit v1.2.1 From 3ec7a176fa81107c20f1693c64873c11a6cd8fa4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 8 Jan 2015 13:52:12 +0300 Subject: net: eth: xgene: devm_ioremap() returns NULL on error devm_ioremap() returns NULL on failure, it doesn't return an ERR_PTR. Fixes: de7b5b3d790a ('net: eth: xgene: change APM X-Gene SoC platform ethernet to support ACPI') Signed-off-by: Dan Carpenter Acked-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 1e56bf30366f..02add385a33d 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -804,9 +804,9 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) return -ENODEV; } pdata->base_addr = devm_ioremap(dev, res->start, resource_size(res)); - if (IS_ERR(pdata->base_addr)) { + if (!pdata->base_addr) { dev_err(dev, "Unable to retrieve ENET Port CSR region\n"); - return PTR_ERR(pdata->base_addr); + return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CSR); @@ -816,9 +816,9 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) } pdata->ring_csr_addr = devm_ioremap(dev, res->start, resource_size(res)); - if (IS_ERR(pdata->ring_csr_addr)) { + if (!pdata->ring_csr_addr) { dev_err(dev, "Unable to retrieve ENET Ring CSR region\n"); - return PTR_ERR(pdata->ring_csr_addr); + return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CMD); @@ -828,9 +828,9 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) } pdata->ring_cmd_addr = devm_ioremap(dev, res->start, resource_size(res)); - if (IS_ERR(pdata->ring_cmd_addr)) { + if (!pdata->ring_cmd_addr) { dev_err(dev, "Unable to retrieve ENET Ring command region\n"); - return PTR_ERR(pdata->ring_cmd_addr); + return -ENOMEM; } ret = platform_get_irq(pdev, 0); -- cgit v1.2.1 From 20d14a5d377a6265c2e89986d052f79dff922217 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Thu, 8 Jan 2015 16:13:07 +0100 Subject: tg3: move init/deinit from open/close to probe/remove Move init and deinit of PTP support from open/close functions to probe/remove funcs to avoid removing/re-adding of associated PTP device(s) during ifup/ifdown. v2: tg3_ptp_init call moved to correct place (thx. Prashant) Signed-off-by: Ivan Vecera Acked-by: Prashant Sreedharan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 553dcd8a9df2..356bd5b022a5 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -11556,11 +11556,7 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq, tg3_flag_set(tp, INIT_COMPLETE); tg3_enable_ints(tp); - if (init) - tg3_ptp_init(tp); - else - tg3_ptp_resume(tp); - + tg3_ptp_resume(tp); tg3_full_unlock(tp); @@ -11681,13 +11677,6 @@ static int tg3_open(struct net_device *dev) pci_set_power_state(tp->pdev, PCI_D3hot); } - if (tg3_flag(tp, PTP_CAPABLE)) { - tp->ptp_clock = ptp_clock_register(&tp->ptp_info, - &tp->pdev->dev); - if (IS_ERR(tp->ptp_clock)) - tp->ptp_clock = NULL; - } - return err; } @@ -11701,8 +11690,6 @@ static int tg3_close(struct net_device *dev) return -EAGAIN; } - tg3_ptp_fini(tp); - tg3_stop(tp); /* Clear stats across close / open calls */ @@ -17880,6 +17867,14 @@ static int tg3_init_one(struct pci_dev *pdev, goto err_out_apeunmap; } + if (tg3_flag(tp, PTP_CAPABLE)) { + tg3_ptp_init(tp); + tp->ptp_clock = ptp_clock_register(&tp->ptp_info, + &tp->pdev->dev); + if (IS_ERR(tp->ptp_clock)) + tp->ptp_clock = NULL; + } + netdev_info(dev, "Tigon3 [partno(%s) rev %04x] (%s) MAC address %pM\n", tp->board_part_number, tg3_chip_rev_id(tp), @@ -17955,6 +17950,8 @@ static void tg3_remove_one(struct pci_dev *pdev) if (dev) { struct tg3 *tp = netdev_priv(dev); + tg3_ptp_fini(tp); + release_firmware(tp->fw); tg3_reset_task_cancel(tp); -- cgit v1.2.1 From 3bf3947526c1053ddf2523f261395d682718f56c Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 8 Jan 2015 12:31:18 -0800 Subject: vxlan: Improve support for header flags This patch cleans up the header flags of VXLAN in anticipation of defining some new ones: - Move header related definitions from vxlan.c to vxlan.h - Change VXLAN_FLAGS to be VXLAN_HF_VNI (only currently defined flag) - Move check for unknown flags to after we find vxlan_sock, this assumes that some flags may be processed based on tunnel configuration - Add a comment about why the stack treating unknown set flags as an error instead of ignoring them Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 2ab0922af0b4..3a18d8ed89ca 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -61,12 +61,6 @@ #define FDB_AGE_DEFAULT 300 /* 5 min */ #define FDB_AGE_INTERVAL (10 * HZ) /* rescan interval */ -#define VXLAN_N_VID (1u << 24) -#define VXLAN_VID_MASK (VXLAN_N_VID - 1) -#define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr)) - -#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */ - /* UDP port for VXLAN traffic. * The IANA assigned port is 4789, but the Linux default is 8472 * for compatibility with early adopters. @@ -1095,18 +1089,21 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { struct vxlan_sock *vs; struct vxlanhdr *vxh; + u32 flags, vni; /* Need Vxlan and inner Ethernet header to be present */ if (!pskb_may_pull(skb, VXLAN_HLEN)) goto error; - /* Return packets with reserved bits set */ vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1); - if (vxh->vx_flags != htonl(VXLAN_FLAGS) || - (vxh->vx_vni & htonl(0xff))) { - netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n", - ntohl(vxh->vx_flags), ntohl(vxh->vx_vni)); - goto error; + flags = ntohl(vxh->vx_flags); + vni = ntohl(vxh->vx_vni); + + if (flags & VXLAN_HF_VNI) { + flags &= ~VXLAN_HF_VNI; + } else { + /* VNI flag always required to be set */ + goto bad_flags; } if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB))) @@ -1116,6 +1113,19 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) if (!vs) goto drop; + if (flags || (vni & 0xff)) { + /* If there are any unprocessed flags remaining treat + * this as a malformed packet. This behavior diverges from + * VXLAN RFC (RFC7348) which stipulates that bits in reserved + * in reserved fields are to be ignored. The approach here + * maintains compatbility with previous stack code, and also + * is more robust and provides a little more security in + * adding extensions to VXLAN. + */ + + goto bad_flags; + } + vs->rcv(vs, skb, vxh->vx_vni); return 0; @@ -1124,6 +1134,10 @@ drop: kfree_skb(skb); return 0; +bad_flags: + netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n", + ntohl(vxh->vx_flags), ntohl(vxh->vx_vni)); + error: /* Return non vxlan pkt */ return 1; @@ -1563,7 +1577,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, } vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); - vxh->vx_flags = htonl(VXLAN_FLAGS); + vxh->vx_flags = htonl(VXLAN_HF_VNI); vxh->vx_vni = vni; skb_set_inner_protocol(skb, htons(ETH_P_TEB)); @@ -1607,7 +1621,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, return -ENOMEM; vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); - vxh->vx_flags = htonl(VXLAN_FLAGS); + vxh->vx_flags = htonl(VXLAN_HF_VNI); vxh->vx_vni = vni; skb_set_inner_protocol(skb, htons(ETH_P_TEB)); -- cgit v1.2.1 From aa2e092671c84b149ba0f9ad7185ace357fb4a33 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jan 2015 10:26:35 +0800 Subject: r8152: call rtl_start_rx after netif_carrier_on Remove rtl_start_rx() from rtl_enable() and put it after calling netif_carrier_on(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 57ec23e8ccfa..cd9338837ce6 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2059,7 +2059,7 @@ static int rtl_enable(struct r8152 *tp) rxdy_gated_en(tp, false); - return rtl_start_rx(tp); + return 0; } static int rtl8152_enable(struct r8152 *tp) @@ -2874,6 +2874,7 @@ static void set_carrier(struct r8152 *tp) tp->rtl_ops.enable(tp); set_bit(RTL8152_SET_RX_MODE, &tp->flags); netif_carrier_on(netdev); + rtl_start_rx(tp); } } else { if (tp->speed & LINK_STATUS) { -- cgit v1.2.1 From ef827a5b578c4255043a0c0032c88799fb4a774b Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jan 2015 10:26:36 +0800 Subject: r8152: check the status before submitting rx Don't submit the rx if the device is unplugged, stopped, or linking down. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index cd9338837ce6..b23426e4952c 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1789,6 +1789,11 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) { int ret; + /* The rx would be stopped, so skip submitting */ + if (test_bit(RTL8152_UNPLUG, &tp->flags) || + !test_bit(WORK_ENABLE, &tp->flags) || !netif_carrier_ok(tp->netdev)) + return 0; + usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1), agg->head, agg_buf_sz, (usb_complete_t)read_bulk_callback, agg); -- cgit v1.2.1 From 6c53e938a81c0b31f9f6a31690c3be601aa8fa60 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 8 Jan 2015 21:38:15 -0800 Subject: iw_cxgb4/cxgb4/cxgb4i: Cleanup register defines/MACROS related to CM CPL messages This patch cleanups all macros/register define related to connection management CPL messages that are defined in t4_msg.h and the affected files Signed-off-by: Anish Bhatt Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 8 +- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 168 ++++++++++++++++----- .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 2 +- 4 files changed, 138 insertions(+), 42 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 6de41cc6687e..2897f956bb21 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3416,8 +3416,8 @@ int cxgb4_create_server(const struct net_device *dev, unsigned int stid, req->peer_ip = htonl(0); chan = rxq_to_chan(&adap->sge, queue); req->opt0 = cpu_to_be64(TX_CHAN_V(chan)); - req->opt1 = cpu_to_be64(CONN_POLICY_ASK | - SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue)); + req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) | + SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue)); ret = t4_mgmt_tx(adap, skb); return net_xmit_eval(ret); } @@ -3459,8 +3459,8 @@ int cxgb4_create_server6(const struct net_device *dev, unsigned int stid, req->peer_ip_lo = cpu_to_be64(0); chan = rxq_to_chan(&adap->sge, queue); req->opt0 = cpu_to_be64(TX_CHAN_V(chan)); - req->opt1 = cpu_to_be64(CONN_POLICY_ASK | - SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue)); + req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) | + SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue)); ret = t4_mgmt_tx(adap, skb); return net_xmit_eval(ret); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 5ae14451c3a4..dea984bbdb99 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -151,7 +151,7 @@ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx | (sync ? F_SYNC_WR : 0) | - TID_QID(adap->sge.fw_evtq.abs_id))); + TID_QID_V(adap->sge.fw_evtq.abs_id))); req->params = htons(L2T_W_PORT(e->lport) | L2T_W_NOREPLY(!sync)); req->l2t_idx = htons(e->idx); req->vlan = htons(e->vlan); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 0f89f68948ab..15e72063fc95 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -123,6 +123,13 @@ enum CPL_error { CPL_ERR_IWARP_FLM = 50, }; +enum { + CPL_CONN_POLICY_AUTO = 0, + CPL_CONN_POLICY_ASK = 1, + CPL_CONN_POLICY_FILTER = 2, + CPL_CONN_POLICY_DENY = 3 +}; + enum { ULP_MODE_NONE = 0, ULP_MODE_ISCSI = 2, @@ -160,16 +167,28 @@ union opcode_tid { u8 opcode; }; -#define CPL_OPCODE(x) ((x) << 24) -#define G_CPL_OPCODE(x) (((x) >> 24) & 0xFF) -#define MK_OPCODE_TID(opcode, tid) (CPL_OPCODE(opcode) | (tid)) +#define CPL_OPCODE_S 24 +#define CPL_OPCODE_V(x) ((x) << CPL_OPCODE_S) +#define CPL_OPCODE_G(x) (((x) >> CPL_OPCODE_S) & 0xFF) +#define TID_G(x) ((x) & 0xFFFFFF) + +/* tid is assumed to be 24-bits */ +#define MK_OPCODE_TID(opcode, tid) (CPL_OPCODE_V(opcode) | (tid)) + #define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) -#define GET_TID(cmd) (ntohl(OPCODE_TID(cmd)) & 0xFFFFFF) + +/* extract the TID from a CPL command */ +#define GET_TID(cmd) (TID_G(be32_to_cpu(OPCODE_TID(cmd)))) /* partitioning of TID fields that also carry a queue id */ -#define GET_TID_TID(x) ((x) & 0x3fff) -#define GET_TID_QID(x) (((x) >> 14) & 0x3ff) -#define TID_QID(x) ((x) << 14) +#define TID_TID_S 0 +#define TID_TID_M 0x3fff +#define TID_TID_G(x) (((x) >> TID_TID_S) & TID_TID_M) + +#define TID_QID_S 14 +#define TID_QID_M 0x3ff +#define TID_QID_V(x) ((x) << TID_QID_S) +#define TID_QID_G(x) (((x) >> TID_QID_S) & TID_QID_M) struct rss_header { u8 opcode; @@ -199,8 +218,8 @@ struct work_request_hdr { }; /* wr_hi fields */ -#define S_WR_OP 24 -#define V_WR_OP(x) ((__u64)(x) << S_WR_OP) +#define WR_OP_S 24 +#define WR_OP_V(x) ((__u64)(x) << WR_OP_S) #define WR_HDR struct work_request_hdr wr @@ -270,17 +289,42 @@ struct cpl_pass_open_req { __be32 local_ip; __be32 peer_ip; __be64 opt0; -#define NO_CONG(x) ((x) << 4) -#define DELACK(x) ((x) << 5) -#define DSCP(x) ((x) << 22) -#define TCAM_BYPASS(x) ((u64)(x) << 48) -#define NAGLE(x) ((u64)(x) << 49) __be64 opt1; -#define SYN_RSS_ENABLE (1 << 0) -#define SYN_RSS_QUEUE(x) ((x) << 2) -#define CONN_POLICY_ASK (1 << 22) }; +/* option 0 fields */ +#define NO_CONG_S 4 +#define NO_CONG_V(x) ((x) << NO_CONG_S) +#define NO_CONG_F NO_CONG_V(1U) + +#define DELACK_S 5 +#define DELACK_V(x) ((x) << DELACK_S) +#define DELACK_F DELACK_V(1U) + +#define DSCP_S 22 +#define DSCP_M 0x3F +#define DSCP_V(x) ((x) << DSCP_S) +#define DSCP_G(x) (((x) >> DSCP_S) & DSCP_M) + +#define TCAM_BYPASS_S 48 +#define TCAM_BYPASS_V(x) ((__u64)(x) << TCAM_BYPASS_S) +#define TCAM_BYPASS_F TCAM_BYPASS_V(1ULL) + +#define NAGLE_S 49 +#define NAGLE_V(x) ((__u64)(x) << NAGLE_S) +#define NAGLE_F NAGLE_V(1ULL) + +/* option 1 fields */ +#define SYN_RSS_ENABLE_S 0 +#define SYN_RSS_ENABLE_V(x) ((x) << SYN_RSS_ENABLE_S) +#define SYN_RSS_ENABLE_F SYN_RSS_ENABLE_V(1U) + +#define SYN_RSS_QUEUE_S 2 +#define SYN_RSS_QUEUE_V(x) ((x) << SYN_RSS_QUEUE_S) + +#define CONN_POLICY_S 22 +#define CONN_POLICY_V(x) ((x) << CONN_POLICY_S) + struct cpl_pass_open_req6 { WR_HDR; union opcode_tid ot; @@ -304,16 +348,37 @@ struct cpl_pass_accept_rpl { WR_HDR; union opcode_tid ot; __be32 opt2; -#define RX_COALESCE_VALID(x) ((x) << 11) -#define RX_COALESCE(x) ((x) << 12) -#define PACE(x) ((x) << 16) -#define TX_QUEUE(x) ((x) << 23) -#define CCTRL_ECN(x) ((x) << 27) -#define TSTAMPS_EN(x) ((x) << 29) -#define SACK_EN(x) ((x) << 30) __be64 opt0; }; +/* option 2 fields */ +#define RX_COALESCE_VALID_S 11 +#define RX_COALESCE_VALID_V(x) ((x) << RX_COALESCE_VALID_S) +#define RX_COALESCE_VALID_F RX_COALESCE_VALID_V(1U) + +#define RX_COALESCE_S 12 +#define RX_COALESCE_V(x) ((x) << RX_COALESCE_S) + +#define PACE_S 16 +#define PACE_V(x) ((x) << PACE_S) + +#define TX_QUEUE_S 23 +#define TX_QUEUE_M 0x7 +#define TX_QUEUE_V(x) ((x) << TX_QUEUE_S) +#define TX_QUEUE_G(x) (((x) >> TX_QUEUE_S) & TX_QUEUE_M) + +#define CCTRL_ECN_S 27 +#define CCTRL_ECN_V(x) ((x) << CCTRL_ECN_S) +#define CCTRL_ECN_F CCTRL_ECN_V(1U) + +#define TSTAMPS_EN_S 29 +#define TSTAMPS_EN_V(x) ((x) << TSTAMPS_EN_S) +#define TSTAMPS_EN_F TSTAMPS_EN_V(1U) + +#define SACK_EN_S 30 +#define SACK_EN_V(x) ((x) << SACK_EN_S) +#define SACK_EN_F SACK_EN_V(1U) + struct cpl_t5_pass_accept_rpl { WR_HDR; union opcode_tid ot; @@ -384,30 +449,61 @@ struct cpl_t5_act_open_req6 { struct cpl_act_open_rpl { union opcode_tid ot; __be32 atid_status; -#define GET_AOPEN_STATUS(x) ((x) & 0xff) -#define GET_AOPEN_ATID(x) (((x) >> 8) & 0xffffff) }; +/* cpl_act_open_rpl.atid_status fields */ +#define AOPEN_STATUS_S 0 +#define AOPEN_STATUS_M 0xFF +#define AOPEN_STATUS_G(x) (((x) >> AOPEN_STATUS_S) & AOPEN_STATUS_M) + +#define AOPEN_ATID_S 8 +#define AOPEN_ATID_M 0xFFFFFF +#define AOPEN_ATID_G(x) (((x) >> AOPEN_ATID_S) & AOPEN_ATID_M) + struct cpl_pass_establish { union opcode_tid ot; __be32 rsvd; __be32 tos_stid; -#define PASS_OPEN_TID(x) ((x) << 0) -#define PASS_OPEN_TOS(x) ((x) << 24) -#define GET_PASS_OPEN_TID(x) (((x) >> 0) & 0xFFFFFF) -#define GET_POPEN_TID(x) ((x) & 0xffffff) -#define GET_POPEN_TOS(x) (((x) >> 24) & 0xff) __be16 mac_idx; __be16 tcp_opt; -#define GET_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1) -#define GET_TCPOPT_SACK(x) (((x) >> 6) & 1) -#define GET_TCPOPT_TSTAMP(x) (((x) >> 7) & 1) -#define GET_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf) -#define GET_TCPOPT_MSS(x) (((x) >> 12) & 0xf) __be32 snd_isn; __be32 rcv_isn; }; +/* cpl_pass_establish.tos_stid fields */ +#define PASS_OPEN_TID_S 0 +#define PASS_OPEN_TID_M 0xFFFFFF +#define PASS_OPEN_TID_V(x) ((x) << PASS_OPEN_TID_S) +#define PASS_OPEN_TID_G(x) (((x) >> PASS_OPEN_TID_S) & PASS_OPEN_TID_M) + +#define PASS_OPEN_TOS_S 24 +#define PASS_OPEN_TOS_M 0xFF +#define PASS_OPEN_TOS_V(x) ((x) << PASS_OPEN_TOS_S) +#define PASS_OPEN_TOS_G(x) (((x) >> PASS_OPEN_TOS_S) & PASS_OPEN_TOS_M) + +/* cpl_pass_establish.tcp_opt fields (also applies to act_open_establish) */ +#define TCPOPT_WSCALE_OK_S 5 +#define TCPOPT_WSCALE_OK_M 0x1 +#define TCPOPT_WSCALE_OK_G(x) \ + (((x) >> TCPOPT_WSCALE_OK_S) & TCPOPT_WSCALE_OK_M) + +#define TCPOPT_SACK_S 6 +#define TCPOPT_SACK_M 0x1 +#define TCPOPT_SACK_G(x) (((x) >> TCPOPT_SACK_S) & TCPOPT_SACK_M) + +#define TCPOPT_TSTAMP_S 7 +#define TCPOPT_TSTAMP_M 0x1 +#define TCPOPT_TSTAMP_G(x) (((x) >> TCPOPT_TSTAMP_S) & TCPOPT_TSTAMP_M) + +#define TCPOPT_SND_WSCALE_S 8 +#define TCPOPT_SND_WSCALE_M 0xF +#define TCPOPT_SND_WSCALE_G(x) \ + (((x) >> TCPOPT_SND_WSCALE_S) & TCPOPT_SND_WSCALE_M) + +#define TCPOPT_MSS_S 12 +#define TCPOPT_MSS_M 0xF +#define TCPOPT_MSS_G(x) (((x) >> TCPOPT_MSS_S) & TCPOPT_MSS_M) + struct cpl_act_establish { union opcode_tid ot; __be32 rsvd; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index 7bfbacd63f7a..4591d934e221 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -450,7 +450,7 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp, /* FW can send EGR_UPDATEs encapsulated in a CPL_FW4_MSG. */ const struct cpl_sge_egr_update *p = (void *)(rsp + 3); - opcode = G_CPL_OPCODE(ntohl(p->opcode_qid)); + opcode = CPL_OPCODE_G(ntohl(p->opcode_qid)); if (opcode != CPL_SGE_EGR_UPDATE) { dev_err(adapter->pdev_dev, "unexpected FW4/CPL %#x on FW event queue\n" , opcode); -- cgit v1.2.1 From bdc590b99f6002faeb12c1c810cbbf8ac4481f70 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 8 Jan 2015 21:38:16 -0800 Subject: iw_cxgb4/cxgb4/cxgb4vf/cxgb4i/csiostor: Cleanup register defines/macros related to all other cpl messages This patch cleanups all other macros/register define related to CPL messages that are defined in t4_msg.h and the affected files Signed-off-by: Anish Bhatt Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 8 +- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/sge.c | 9 +- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 199 +++++++++++++++------ .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 2 +- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 6 +- 6 files changed, 155 insertions(+), 71 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 2897f956bb21..23ae0b7a9019 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -672,7 +672,7 @@ static void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl) if (idx >= adap->tids.ftid_base && nidx < (adap->tids.nftids + adap->tids.nsftids)) { idx = nidx; - ret = GET_TCB_COOKIE(rpl->cookie); + ret = TCB_COOKIE_G(rpl->cookie); f = &adap->tids.ftid_tab[idx]; if (ret == FW_FILTER_WR_FLT_DELETED) { @@ -724,7 +724,7 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp, if (likely(opcode == CPL_SGE_EGR_UPDATE)) { const struct cpl_sge_egr_update *p = (void *)rsp; - unsigned int qid = EGR_QID(ntohl(p->opcode_qid)); + unsigned int qid = EGR_QID_G(ntohl(p->opcode_qid)); struct sge_txq *txq; txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start]; @@ -3483,8 +3483,8 @@ int cxgb4_remove_server(const struct net_device *dev, unsigned int stid, req = (struct cpl_close_listsvr_req *)__skb_put(skb, sizeof(*req)); INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, stid)); - req->reply_ctrl = htons(NO_REPLY(0) | (ipv6 ? LISTSVR_IPV6(1) : - LISTSVR_IPV6(0)) | QUEUENO(queue)); + req->reply_ctrl = htons(NO_REPLY_V(0) | (ipv6 ? LISTSVR_IPV6_V(1) : + LISTSVR_IPV6_V(0)) | QUEUENO_V(queue)); ret = t4_mgmt_tx(adap, skb); return net_xmit_eval(ret); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index dea984bbdb99..252efc29321f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -152,7 +152,7 @@ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx | (sync ? F_SYNC_WR : 0) | TID_QID_V(adap->sge.fw_evtq.abs_id))); - req->params = htons(L2T_W_PORT(e->lport) | L2T_W_NOREPLY(!sync)); + req->params = htons(L2T_W_PORT_V(e->lport) | L2T_W_NOREPLY_V(!sync)); req->l2t_idx = htons(e->idx); req->vlan = htons(e->vlan); if (e->neigh && !(e->neigh->dev->flags & IFF_LOOPBACK)) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index d7c301c77060..a79fa6a0f5c5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -821,7 +821,8 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *q, sgl->addr0 = cpu_to_be64(addr[1]); } - sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | ULPTX_NSGE(nfrags)); + sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | + ULPTX_NSGE_V(nfrags)); if (likely(--nfrags == 0)) return; /* @@ -1761,7 +1762,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, pkt = (const struct cpl_rx_pkt *)rsp; csum_ok = pkt->csum_calc && !pkt->err_vec && (q->netdev->features & NETIF_F_RXCSUM); - if ((pkt->l2info & htonl(RXF_TCP)) && + if ((pkt->l2info & htonl(RXF_TCP_F)) && (q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) { do_gro(rxq, si, pkt); return 0; @@ -1783,11 +1784,11 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, rxq->stats.pkts++; - if (csum_ok && (pkt->l2info & htonl(RXF_UDP | RXF_TCP))) { + if (csum_ok && (pkt->l2info & htonl(RXF_UDP_F | RXF_TCP_F))) { if (!pkt->ip_frag) { skb->ip_summed = CHECKSUM_UNNECESSARY; rxq->stats.rx_cso++; - } else if (pkt->l2info & htonl(RXF_IP)) { + } else if (pkt->l2info & htonl(RXF_IP_F)) { __sum16 c = (__force __sum16)pkt->csum; skb->csum = csum_unfold(c); skb->ip_summed = CHECKSUM_COMPLETE; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 15e72063fc95..0fb975e258b3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -518,24 +518,39 @@ struct cpl_get_tcb { WR_HDR; union opcode_tid ot; __be16 reply_ctrl; -#define QUEUENO(x) ((x) << 0) -#define REPLY_CHAN(x) ((x) << 14) -#define NO_REPLY(x) ((x) << 15) __be16 cookie; }; +/* cpl_get_tcb.reply_ctrl fields */ +#define QUEUENO_S 0 +#define QUEUENO_V(x) ((x) << QUEUENO_S) + +#define REPLY_CHAN_S 14 +#define REPLY_CHAN_V(x) ((x) << REPLY_CHAN_S) +#define REPLY_CHAN_F REPLY_CHAN_V(1U) + +#define NO_REPLY_S 15 +#define NO_REPLY_V(x) ((x) << NO_REPLY_S) +#define NO_REPLY_F NO_REPLY_V(1U) + struct cpl_set_tcb_field { WR_HDR; union opcode_tid ot; __be16 reply_ctrl; __be16 word_cookie; -#define TCB_WORD(x) ((x) << 0) -#define TCB_COOKIE(x) ((x) << 5) -#define GET_TCB_COOKIE(x) (((x) >> 5) & 7) __be64 mask; __be64 val; }; +/* cpl_set_tcb_field.word_cookie fields */ +#define TCB_WORD_S 0 +#define TCB_WORD(x) ((x) << TCB_WORD_S) + +#define TCB_COOKIE_S 5 +#define TCB_COOKIE_M 0x7 +#define TCB_COOKIE_V(x) ((x) << TCB_COOKIE_S) +#define TCB_COOKIE_G(x) (((x) >> TCB_COOKIE_S) & TCB_COOKIE_M) + struct cpl_set_tcb_rpl { union opcode_tid ot; __be16 rsvd; @@ -562,10 +577,14 @@ struct cpl_close_listsvr_req { WR_HDR; union opcode_tid ot; __be16 reply_ctrl; -#define LISTSVR_IPV6(x) ((x) << 14) __be16 rsvd; }; +/* additional cpl_close_listsvr_req.reply_ctrl field */ +#define LISTSVR_IPV6_S 14 +#define LISTSVR_IPV6_V(x) ((x) << LISTSVR_IPV6_S) +#define LISTSVR_IPV6_F LISTSVR_IPV6_V(1U) + struct cpl_close_listsvr_rpl { union opcode_tid ot; u8 rsvd[3]; @@ -661,6 +680,34 @@ struct cpl_tx_pkt_lso_core { /* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */ }; +/* cpl_tx_pkt_lso_core.lso_ctrl fields */ +#define LSO_TCPHDR_LEN_S 0 +#define LSO_TCPHDR_LEN_V(x) ((x) << LSO_TCPHDR_LEN_S) + +#define LSO_IPHDR_LEN_S 4 +#define LSO_IPHDR_LEN_V(x) ((x) << LSO_IPHDR_LEN_S) + +#define LSO_ETHHDR_LEN_S 16 +#define LSO_ETHHDR_LEN_V(x) ((x) << LSO_ETHHDR_LEN_S) + +#define LSO_IPV6_S 20 +#define LSO_IPV6_V(x) ((x) << LSO_IPV6_S) +#define LSO_IPV6_F LSO_IPV6_V(1U) + +#define LSO_LAST_SLICE_S 22 +#define LSO_LAST_SLICE_V(x) ((x) << LSO_LAST_SLICE_S) +#define LSO_LAST_SLICE_F LSO_LAST_SLICE_V(1U) + +#define LSO_FIRST_SLICE_S 23 +#define LSO_FIRST_SLICE_V(x) ((x) << LSO_FIRST_SLICE_S) +#define LSO_FIRST_SLICE_F LSO_FIRST_SLICE_V(1U) + +#define LSO_OPCODE_S 24 +#define LSO_OPCODE_V(x) ((x) << LSO_OPCODE_S) + +#define LSO_T5_XFER_SIZE_S 0 +#define LSO_T5_XFER_SIZE_V(x) ((x) << LSO_T5_XFER_SIZE_S) + struct cpl_tx_pkt_lso { WR_HDR; struct cpl_tx_pkt_lso_core c; @@ -670,8 +717,6 @@ struct cpl_tx_pkt_lso { struct cpl_iscsi_hdr { union opcode_tid ot; __be16 pdu_len_ddp; -#define ISCSI_PDU_LEN(x) ((x) & 0x7FFF) -#define ISCSI_DDP (1 << 15) __be16 len; __be32 seq; __be16 urg; @@ -679,6 +724,16 @@ struct cpl_iscsi_hdr { u8 status; }; +/* cpl_iscsi_hdr.pdu_len_ddp fields */ +#define ISCSI_PDU_LEN_S 0 +#define ISCSI_PDU_LEN_M 0x7FFF +#define ISCSI_PDU_LEN_V(x) ((x) << ISCSI_PDU_LEN_S) +#define ISCSI_PDU_LEN_G(x) (((x) >> ISCSI_PDU_LEN_S) & ISCSI_PDU_LEN_M) + +#define ISCSI_DDP_S 15 +#define ISCSI_DDP_V(x) ((x) << ISCSI_DDP_S) +#define ISCSI_DDP_F ISCSI_DDP_V(1U) + struct cpl_rx_data { union opcode_tid ot; __be16 rsvd; @@ -735,49 +790,61 @@ struct cpl_rx_pkt { __be16 vlan; __be16 len; __be32 l2info; -#define RXF_UDP (1 << 22) -#define RXF_TCP (1 << 23) -#define RXF_IP (1 << 24) -#define RXF_IP6 (1 << 25) __be16 hdr_len; __be16 err_vec; }; +#define RXF_UDP_S 22 +#define RXF_UDP_V(x) ((x) << RXF_UDP_S) +#define RXF_UDP_F RXF_UDP_V(1U) + +#define RXF_TCP_S 23 +#define RXF_TCP_V(x) ((x) << RXF_TCP_S) +#define RXF_TCP_F RXF_TCP_V(1U) + +#define RXF_IP_S 24 +#define RXF_IP_V(x) ((x) << RXF_IP_S) +#define RXF_IP_F RXF_IP_V(1U) + +#define RXF_IP6_S 25 +#define RXF_IP6_V(x) ((x) << RXF_IP6_S) +#define RXF_IP6_F RXF_IP6_V(1U) + /* rx_pkt.l2info fields */ -#define S_RX_ETHHDR_LEN 0 -#define M_RX_ETHHDR_LEN 0x1F -#define V_RX_ETHHDR_LEN(x) ((x) << S_RX_ETHHDR_LEN) -#define G_RX_ETHHDR_LEN(x) (((x) >> S_RX_ETHHDR_LEN) & M_RX_ETHHDR_LEN) - -#define S_RX_T5_ETHHDR_LEN 0 -#define M_RX_T5_ETHHDR_LEN 0x3F -#define V_RX_T5_ETHHDR_LEN(x) ((x) << S_RX_T5_ETHHDR_LEN) -#define G_RX_T5_ETHHDR_LEN(x) (((x) >> S_RX_T5_ETHHDR_LEN) & M_RX_T5_ETHHDR_LEN) - -#define S_RX_MACIDX 8 -#define M_RX_MACIDX 0x1FF -#define V_RX_MACIDX(x) ((x) << S_RX_MACIDX) -#define G_RX_MACIDX(x) (((x) >> S_RX_MACIDX) & M_RX_MACIDX) - -#define S_RXF_SYN 21 -#define V_RXF_SYN(x) ((x) << S_RXF_SYN) -#define F_RXF_SYN V_RXF_SYN(1U) - -#define S_RX_CHAN 28 -#define M_RX_CHAN 0xF -#define V_RX_CHAN(x) ((x) << S_RX_CHAN) -#define G_RX_CHAN(x) (((x) >> S_RX_CHAN) & M_RX_CHAN) +#define RX_ETHHDR_LEN_S 0 +#define RX_ETHHDR_LEN_M 0x1F +#define RX_ETHHDR_LEN_V(x) ((x) << RX_ETHHDR_LEN_S) +#define RX_ETHHDR_LEN_G(x) (((x) >> RX_ETHHDR_LEN_S) & RX_ETHHDR_LEN_M) + +#define RX_T5_ETHHDR_LEN_S 0 +#define RX_T5_ETHHDR_LEN_M 0x3F +#define RX_T5_ETHHDR_LEN_V(x) ((x) << RX_T5_ETHHDR_LEN_S) +#define RX_T5_ETHHDR_LEN_G(x) (((x) >> RX_T5_ETHHDR_LEN_S) & RX_T5_ETHHDR_LEN_M) + +#define RX_MACIDX_S 8 +#define RX_MACIDX_M 0x1FF +#define RX_MACIDX_V(x) ((x) << RX_MACIDX_S) +#define RX_MACIDX_G(x) (((x) >> RX_MACIDX_S) & RX_MACIDX_M) + +#define RXF_SYN_S 21 +#define RXF_SYN_V(x) ((x) << RXF_SYN_S) +#define RXF_SYN_F RXF_SYN_V(1U) + +#define RX_CHAN_S 28 +#define RX_CHAN_M 0xF +#define RX_CHAN_V(x) ((x) << RX_CHAN_S) +#define RX_CHAN_G(x) (((x) >> RX_CHAN_S) & RX_CHAN_M) /* rx_pkt.hdr_len fields */ -#define S_RX_TCPHDR_LEN 0 -#define M_RX_TCPHDR_LEN 0x3F -#define V_RX_TCPHDR_LEN(x) ((x) << S_RX_TCPHDR_LEN) -#define G_RX_TCPHDR_LEN(x) (((x) >> S_RX_TCPHDR_LEN) & M_RX_TCPHDR_LEN) +#define RX_TCPHDR_LEN_S 0 +#define RX_TCPHDR_LEN_M 0x3F +#define RX_TCPHDR_LEN_V(x) ((x) << RX_TCPHDR_LEN_S) +#define RX_TCPHDR_LEN_G(x) (((x) >> RX_TCPHDR_LEN_S) & RX_TCPHDR_LEN_M) -#define S_RX_IPHDR_LEN 6 -#define M_RX_IPHDR_LEN 0x3FF -#define V_RX_IPHDR_LEN(x) ((x) << S_RX_IPHDR_LEN) -#define G_RX_IPHDR_LEN(x) (((x) >> S_RX_IPHDR_LEN) & M_RX_IPHDR_LEN) +#define RX_IPHDR_LEN_S 6 +#define RX_IPHDR_LEN_M 0x3FF +#define RX_IPHDR_LEN_V(x) ((x) << RX_IPHDR_LEN_S) +#define RX_IPHDR_LEN_G(x) (((x) >> RX_IPHDR_LEN_S) & RX_IPHDR_LEN_M) struct cpl_trace_pkt { u8 opcode; @@ -826,14 +893,22 @@ struct cpl_l2t_write_req { WR_HDR; union opcode_tid ot; __be16 params; -#define L2T_W_INFO(x) ((x) << 2) -#define L2T_W_PORT(x) ((x) << 8) -#define L2T_W_NOREPLY(x) ((x) << 15) __be16 l2t_idx; __be16 vlan; u8 dst_mac[6]; }; +/* cpl_l2t_write_req.params fields */ +#define L2T_W_INFO_S 2 +#define L2T_W_INFO_V(x) ((x) << L2T_W_INFO_S) + +#define L2T_W_PORT_S 8 +#define L2T_W_PORT_V(x) ((x) << L2T_W_PORT_S) + +#define L2T_W_NOREPLY_S 15 +#define L2T_W_NOREPLY_V(x) ((x) << L2T_W_NOREPLY_S) +#define L2T_W_NOREPLY_F L2T_W_NOREPLY_V(1U) + struct cpl_l2t_write_rpl { union opcode_tid ot; u8 status; @@ -848,11 +923,15 @@ struct cpl_rdma_terminate { struct cpl_sge_egr_update { __be32 opcode_qid; -#define EGR_QID(x) ((x) & 0x1FFFF) __be16 cidx; __be16 pidx; }; +/* cpl_sge_egr_update.ot fields */ +#define EGR_QID_S 0 +#define EGR_QID_M 0x1FFFF +#define EGR_QID_G(x) (((x) >> EGR_QID_S) & EGR_QID_M) + /* cpl_fw*.type values */ enum { FW_TYPE_CMD_RPL = 0, @@ -945,22 +1024,30 @@ struct ulptx_sge_pair { struct ulptx_sgl { __be32 cmd_nsge; -#define ULPTX_NSGE(x) ((x) << 0) -#define ULPTX_MORE (1U << 23) __be32 len0; __be64 addr0; struct ulptx_sge_pair sge[0]; }; +#define ULPTX_NSGE_S 0 +#define ULPTX_NSGE_V(x) ((x) << ULPTX_NSGE_S) + +#define ULPTX_MORE_S 23 +#define ULPTX_MORE_V(x) ((x) << ULPTX_MORE_S) +#define ULPTX_MORE_F ULPTX_MORE_V(1U) + struct ulp_mem_io { WR_HDR; __be32 cmd; __be32 len16; /* command length */ __be32 dlen; /* data length in 32-byte units */ __be32 lock_addr; -#define ULP_MEMIO_LOCK(x) ((x) << 31) }; +#define ULP_MEMIO_LOCK_S 31 +#define ULP_MEMIO_LOCK_V(x) ((x) << ULP_MEMIO_LOCK_S) +#define ULP_MEMIO_LOCK_F ULP_MEMIO_LOCK_V(1U) + /* additional ulp_mem_io.cmd fields */ #define ULP_MEMIO_ORDER_S 23 #define ULP_MEMIO_ORDER_V(x) ((x) << ULP_MEMIO_ORDER_S) @@ -970,13 +1057,9 @@ struct ulp_mem_io { #define T5_ULP_MEMIO_IMM_V(x) ((x) << T5_ULP_MEMIO_IMM_S) #define T5_ULP_MEMIO_IMM_F T5_ULP_MEMIO_IMM_V(1U) -#define S_T5_ULP_MEMIO_IMM 23 -#define V_T5_ULP_MEMIO_IMM(x) ((x) << S_T5_ULP_MEMIO_IMM) -#define F_T5_ULP_MEMIO_IMM V_T5_ULP_MEMIO_IMM(1U) - -#define S_T5_ULP_MEMIO_ORDER 22 -#define V_T5_ULP_MEMIO_ORDER(x) ((x) << S_T5_ULP_MEMIO_ORDER) -#define F_T5_ULP_MEMIO_ORDER V_T5_ULP_MEMIO_ORDER(1U) +#define T5_ULP_MEMIO_ORDER_S 22 +#define T5_ULP_MEMIO_ORDER_V(x) ((x) << T5_ULP_MEMIO_ORDER_S) +#define T5_ULP_MEMIO_ORDER_F T5_ULP_MEMIO_ORDER_V(1U) /* ulp_mem_io.lock_addr fields */ #define ULP_MEMIO_ADDR_S 0 diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index 4591d934e221..710e5e2bac9f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -471,7 +471,7 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp, * free TX Queue Descriptors ... */ const struct cpl_sge_egr_update *p = cpl; - unsigned int qid = EGR_QID(be32_to_cpu(p->opcode_qid)); + unsigned int qid = EGR_QID_G(be32_to_cpu(p->opcode_qid)); struct sge *s = &adapter->sge; struct sge_txq *tq; struct sge_eth_txq *txq; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index ef4da3e1829b..4424277a7e4d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -926,7 +926,7 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq, } sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | - ULPTX_NSGE(nfrags)); + ULPTX_NSGE_V(nfrags)); if (likely(--nfrags == 0)) return; /* @@ -1604,7 +1604,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, * If this is a good TCP packet and we have Generic Receive Offload * enabled, handle the packet in the GRO path. */ - if ((pkt->l2info & cpu_to_be32(RXF_TCP)) && + if ((pkt->l2info & cpu_to_be32(RXF_TCP_F)) && (rspq->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) { do_gro(rxq, gl, pkt); @@ -1626,7 +1626,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, rxq->stats.pkts++; if (csum_ok && !pkt->err_vec && - (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) { + (be32_to_cpu(pkt->l2info) & (RXF_UDP_F | RXF_TCP_F))) { if (!pkt->ip_frag) skb->ip_summed = CHECKSUM_UNNECESSARY; else { -- cgit v1.2.1 From 7bfa014500ceffa8b787ffc3a6e00252443631d0 Mon Sep 17 00:00:00 2001 From: Jonathan Toppins Date: Fri, 9 Jan 2015 13:31:08 -0500 Subject: bonding: cleanup bond_opts array Remove the empty array element initializer and size the array with BOND_OPT_LAST so the compiler will complain if more elements are in there than should be. An interesting unwanted side effect of this initializer is that if one inserts new options into the middle of the array then this initializer will zero out the option that equals BOND_OPT_TLB_DYNAMIC_LB+1. Example: Extend the OPTS enum: enum { ... BOND_OPT_TLB_DYNAMIC_LB, BOND_OPT_LACP_NEW1, BOND_OPT_LAST }; Now insert into bond_opts array: static const struct bond_option bond_opts[] = { ... [BOND_OPT_LACP_RATE] = { .... unchanged stuff .... }, [BOND_OPT_LACP_NEW1] = { ... new stuff ... }, ... [BOND_OPT_TLB_DYNAMIC_LB] = { .... unchanged stuff ....}, { } // MARK A }; Since BOND_OPT_LACP_NEW1 = BOND_OPT_TLB_DYNAMIC_LB+1, the last initializer (MARK A) will overwrite the contents of BOND_OPT_LACP_NEW1 and can be easily viewed with the crash utility. Signed-off-by: Jonathan Toppins Cc: Andy Gospodarek Cc: Nikolay Aleksandrov Signed-off-by: Andy Gospodarek Acked-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_options.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 1a61cc9b3402..9bd538d4474b 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -186,7 +186,7 @@ static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = { { NULL, -1, 0} }; -static const struct bond_option bond_opts[] = { +static const struct bond_option bond_opts[BOND_OPT_LAST] = { [BOND_OPT_MODE] = { .id = BOND_OPT_MODE, .name = "mode", @@ -379,8 +379,7 @@ static const struct bond_option bond_opts[] = { .values = bond_tlb_dynamic_lb_tbl, .flags = BOND_OPTFLAG_IFDOWN, .set = bond_option_tlb_dynamic_lb_set, - }, - { } + } }; /* Searches for an option by name */ -- cgit v1.2.1 From 5ec82c1e4c86cf2fa115a2ae6d3576a100b47c42 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Fri, 9 Jan 2015 15:19:14 -0800 Subject: Driver: Vmxnet3: Reinitialize vmxnet3 backend on wakeup from hibernate Failing to reinitialize on wakeup results in loss of network connectivity for vmxnet3 interface. Signed-off-by: Srividya Murali Signed-off-by: Shrikrishna Khare Reviewed-by: Shreyas N Bhatewara Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_drv.c | 44 ++++++++++++++++++++++----------------- drivers/net/vmxnet3/vmxnet3_int.h | 4 ++-- 2 files changed, 27 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 7af1f5cfa87a..31439818c27e 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -3290,27 +3290,15 @@ skip_arp: static int vmxnet3_resume(struct device *device) { - int err, i = 0; + int err; unsigned long flags; struct pci_dev *pdev = to_pci_dev(device); struct net_device *netdev = pci_get_drvdata(pdev); struct vmxnet3_adapter *adapter = netdev_priv(netdev); - struct Vmxnet3_PMConf *pmConf; if (!netif_running(netdev)) return 0; - /* Destroy wake-up filters. */ - pmConf = adapter->pm_conf; - memset(pmConf, 0, sizeof(*pmConf)); - - adapter->shared->devRead.pmConfDesc.confVer = cpu_to_le32(1); - adapter->shared->devRead.pmConfDesc.confLen = cpu_to_le32(sizeof( - *pmConf)); - adapter->shared->devRead.pmConfDesc.confPA = - cpu_to_le64(adapter->pm_conf_pa); - - netif_device_attach(netdev); pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); err = pci_enable_device_mem(pdev); @@ -3319,15 +3307,31 @@ vmxnet3_resume(struct device *device) pci_enable_wake(pdev, PCI_D0, 0); + vmxnet3_alloc_intr_resources(adapter); + + /* During hibernate and suspend, device has to be reinitialized as the + * device state need not be preserved. + */ + + /* Need not check adapter state as other reset tasks cannot run during + * device resume. + */ spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, - VMXNET3_CMD_UPDATE_PMCFG); + VMXNET3_CMD_QUIESCE_DEV); spin_unlock_irqrestore(&adapter->cmd_lock, flags); - vmxnet3_alloc_intr_resources(adapter); - vmxnet3_request_irqs(adapter); - for (i = 0; i < adapter->num_rx_queues; i++) - napi_enable(&adapter->rx_queue[i].napi); - vmxnet3_enable_all_intrs(adapter); + vmxnet3_tq_cleanup_all(adapter); + vmxnet3_rq_cleanup_all(adapter); + + vmxnet3_reset_dev(adapter); + err = vmxnet3_activate_dev(adapter); + if (err != 0) { + netdev_err(netdev, + "failed to re-activate on resume, error: %d", err); + vmxnet3_force_close(adapter); + return err; + } + netif_device_attach(netdev); return 0; } @@ -3335,6 +3339,8 @@ vmxnet3_resume(struct device *device) static const struct dev_pm_ops vmxnet3_pm_ops = { .suspend = vmxnet3_suspend, .resume = vmxnet3_resume, + .freeze = vmxnet3_suspend, + .restore = vmxnet3_resume, }; #endif diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 048f02058ec9..6297d9fb0ae5 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -69,10 +69,10 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.3.1.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.3.2.0-k" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01030100 +#define VMXNET3_DRIVER_VERSION_NUM 0x01030200 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */ -- cgit v1.2.1 From dd2e8bf586a69b824e50d50a5bbc16ed38f50986 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jan 2015 10:20:25 +0100 Subject: drivers: net: xen-netfront: remove residual dead code This patch removes some unused arrays from the netfront private data structures. These arrays were used in "flip" receive mode. Signed-off-by: Vincenzo Maffione Reviewed-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 22bcb4e12e2a..a4e50482a230 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -144,10 +144,6 @@ struct netfront_queue { struct sk_buff *rx_skbs[NET_RX_RING_SIZE]; grant_ref_t gref_rx_head; grant_ref_t grant_rx_ref[NET_RX_RING_SIZE]; - - unsigned long rx_pfn_array[NET_RX_RING_SIZE]; - struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1]; - struct mmu_update rx_mmu[NET_RX_RING_SIZE]; }; struct netfront_info { -- cgit v1.2.1 From b1e8bc617d30fc9360a58889f21a0d0ce982cf04 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Sun, 11 Jan 2015 11:42:37 -0800 Subject: net: bnx2x: avoid macro redefinition Signed-off-by: David Decotigny Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 792ba72fb5c8..756053c028be 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1138,12 +1138,8 @@ struct bnx2x_port { u32 link_config[LINK_CONFIG_SIZE]; u32 supported[LINK_CONFIG_SIZE]; -/* link settings - missing defines */ -#define SUPPORTED_2500baseX_Full (1 << 15) u32 advertising[LINK_CONFIG_SIZE]; -/* link settings - missing defines */ -#define ADVERTISED_2500baseX_Full (1 << 15) u32 phy_addr; -- cgit v1.2.1 From e350a96ec9e6c74f06235ded93ef3155f71c6c6b Mon Sep 17 00:00:00 2001 From: Kenneth Williams Date: Sun, 11 Jan 2015 16:43:54 -0800 Subject: team: Remove dead code The deleted lines are called from a function which is called: 1) Only through __team_options_register via team_options_register and 2) Only during initialization / mode initialization when there are no ports attached. Therefore the ports list is guarenteed to be empty and this code will never be executed. Signed-off-by: Kenneth Williams Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/team/team.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 93e224217e24..43bcfff71d95 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -176,7 +176,6 @@ static int __team_option_inst_add(struct team *team, struct team_option *option, static int __team_option_inst_add_option(struct team *team, struct team_option *option) { - struct team_port *port; int err; if (!option->per_port) { @@ -184,12 +183,6 @@ static int __team_option_inst_add_option(struct team *team, if (err) goto inst_del_option; } - - list_for_each_entry(port, &team->port_list, list) { - err = __team_option_inst_add(team, option, port); - if (err) - goto inst_del_option; - } return 0; inst_del_option: -- cgit v1.2.1 From baf71c5c1f80d82e92924050a60b5baaf97e3094 Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Mon, 12 Jan 2015 11:41:29 +0530 Subject: tuntap: Increase the number of queues in tun. Networking under kvm works best if we allocate a per-vCPU RX and TX queue in a virtual NIC. This requires a per-vCPU queue on the host side. It is now safe to increase the maximum number of queues. Preceding patch: 'net: allow large number of rx queues' made sure this won't cause failures due to high order memory allocations. Increase it to 256: this is the max number of vCPUs KVM supports. Size of tun_struct changes from 8512 to 10496 after this patch. This keeps pages allocated for tun_struct before and after the patch to 3. Signed-off-by: Pankaj Gupta Reviewed-by: David Gibson Signed-off-by: David S. Miller --- drivers/net/tun.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index c0df872f5b8c..74fdf1158448 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -124,10 +124,9 @@ struct tap_filter { unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; }; -/* DEFAULT_MAX_NUM_RSS_QUEUES were chosen to let the rx/tx queues allocated for - * the netdevice to be fit in one page. So we can make sure the success of - * memory allocation. TODO: increase the limit. */ -#define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES +/* MAX_TAP_QUEUES 256 is chosen to allow rx/tx queues to be equal + * to max number of VCPUs in guest. */ +#define MAX_TAP_QUEUES 256 #define MAX_TAP_FLOWS 4096 #define TUN_FLOW_EXPIRE (3 * HZ) -- cgit v1.2.1 From dc8ab27861b2c1277bd9603a85f317708149d844 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 12 Jan 2015 14:07:25 +0200 Subject: ath10k: add wmi support for addba_clear_resp Add WMI support for clearing addba response before switching aggregation mode (auto/manual) for debugging purpose. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 18 ++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 20e2c3002bb5..b161043c7740 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -119,6 +119,8 @@ struct wmi_ops { u32 next_offset, u32 enabled); struct sk_buff *(*gen_pdev_get_temperature)(struct ath10k *ar); + struct sk_buff *(*gen_addba_clear_resp)(struct ath10k *ar, u32 vdev_id, + const u8 *mac); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -857,4 +859,20 @@ ath10k_wmi_pdev_get_temperature(struct ath10k *ar) ar->wmi.cmd->pdev_get_temperature_cmdid); } +static inline int +ath10k_wmi_addba_clear_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_addba_clear_resp) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_addba_clear_resp(ar, vdev_id, mac); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->addba_clear_resp_cmdid); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 4c050cec3966..499a7797b4de 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2207,6 +2207,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, /* .gen_pdev_set_quiet_mode not implemented */ /* .gen_pdev_get_temperature not implemented */ + /* .gen_addba_clear_resp not implemented */ }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c56d2fa5edb8..47ef1a9ada21 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4880,6 +4880,30 @@ ath10k_wmi_op_gen_pdev_set_quiet_mode(struct ath10k *ar, u32 period, return skb; } +static struct sk_buff * +ath10k_wmi_op_gen_addba_clear_resp(struct ath10k *ar, u32 vdev_id, + const u8 *mac) +{ + struct wmi_addba_clear_resp_cmd *cmd; + struct sk_buff *skb; + + if (!mac) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_addba_clear_resp_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, mac); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi addba clear resp vdev_id 0x%X mac_addr %pM\n", + vdev_id, mac); + return skb; +} + static const struct wmi_ops wmi_ops = { .rx = ath10k_wmi_op_rx, .map_svc = wmi_main_svc_map, @@ -4931,6 +4955,7 @@ static const struct wmi_ops wmi_ops = { .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, /* .gen_pdev_get_temperature not implemented */ + .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, }; static const struct wmi_ops wmi_10_1_ops = { @@ -4985,6 +5010,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, }; static const struct wmi_ops wmi_10_2_ops = { @@ -5040,6 +5066,7 @@ static const struct wmi_ops wmi_10_2_ops = { .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, }; static const struct wmi_ops wmi_10_2_4_ops = { @@ -5095,6 +5122,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, }; int ath10k_wmi_attach(struct ath10k *ar) -- cgit v1.2.1 From 65c0893d91b33018e8eaacc6aeb777c5faf6a094 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 12 Jan 2015 14:07:26 +0200 Subject: ath10k: add wmi support for addba_send Add WMI support for sending addba request. This command is meant for debugging purpose. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 19 +++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index b161043c7740..badf4223335c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -121,6 +121,8 @@ struct wmi_ops { struct sk_buff *(*gen_pdev_get_temperature)(struct ath10k *ar); struct sk_buff *(*gen_addba_clear_resp)(struct ath10k *ar, u32 vdev_id, const u8 *mac); + struct sk_buff *(*gen_addba_send)(struct ath10k *ar, u32 vdev_id, + const u8 *mac, u32 tid, u32 buf_size); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -875,4 +877,21 @@ ath10k_wmi_addba_clear_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac) ar->wmi.cmd->addba_clear_resp_cmdid); } +static inline int +ath10k_wmi_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 buf_size) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_addba_send) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_addba_send(ar, vdev_id, mac, tid, buf_size); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->addba_send_cmdid); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 499a7797b4de..74a0598634ed 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2208,6 +2208,7 @@ static const struct wmi_ops wmi_tlv_ops = { /* .gen_pdev_set_quiet_mode not implemented */ /* .gen_pdev_get_temperature not implemented */ /* .gen_addba_clear_resp not implemented */ + /* .gen_addba_send not implemented */ }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 47ef1a9ada21..980d6ee82cc6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4904,6 +4904,32 @@ ath10k_wmi_op_gen_addba_clear_resp(struct ath10k *ar, u32 vdev_id, return skb; } +static struct sk_buff * +ath10k_wmi_op_gen_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 buf_size) +{ + struct wmi_addba_send_cmd *cmd; + struct sk_buff *skb; + + if (!mac) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_addba_send_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, mac); + cmd->tid = __cpu_to_le32(tid); + cmd->buffersize = __cpu_to_le32(buf_size); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n", + vdev_id, mac, tid, buf_size); + return skb; +} + static const struct wmi_ops wmi_ops = { .rx = ath10k_wmi_op_rx, .map_svc = wmi_main_svc_map, @@ -4956,6 +4982,7 @@ static const struct wmi_ops wmi_ops = { .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, /* .gen_pdev_get_temperature not implemented */ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, + .gen_addba_send = ath10k_wmi_op_gen_addba_send, }; static const struct wmi_ops wmi_10_1_ops = { @@ -5011,6 +5038,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, + .gen_addba_send = ath10k_wmi_op_gen_addba_send, }; static const struct wmi_ops wmi_10_2_ops = { @@ -5067,6 +5095,7 @@ static const struct wmi_ops wmi_10_2_ops = { .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, + .gen_addba_send = ath10k_wmi_op_gen_addba_send, }; static const struct wmi_ops wmi_10_2_4_ops = { @@ -5123,6 +5152,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, + .gen_addba_send = ath10k_wmi_op_gen_addba_send, }; int ath10k_wmi_attach(struct ath10k *ar) -- cgit v1.2.1 From 11597413b22d1a2ee02501d4167ae712a2b7929e Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 12 Jan 2015 14:07:26 +0200 Subject: ath10k: add wmi support for addba_set_resp Add WMI support for sending addba response manually. This command is used for debugging purpose. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 20 ++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index badf4223335c..e8f49de18369 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -123,6 +123,9 @@ struct wmi_ops { const u8 *mac); struct sk_buff *(*gen_addba_send)(struct ath10k *ar, u32 vdev_id, const u8 *mac, u32 tid, u32 buf_size); + struct sk_buff *(*gen_addba_set_resp)(struct ath10k *ar, u32 vdev_id, + const u8 *mac, u32 tid, + u32 status); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -894,4 +897,21 @@ ath10k_wmi_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, ar->wmi.cmd->addba_send_cmdid); } +static inline int +ath10k_wmi_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 status) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_addba_set_resp) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_addba_set_resp(ar, vdev_id, mac, tid, status); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->addba_set_resp_cmdid); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 74a0598634ed..63f98600cc05 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2209,6 +2209,7 @@ static const struct wmi_ops wmi_tlv_ops = { /* .gen_pdev_get_temperature not implemented */ /* .gen_addba_clear_resp not implemented */ /* .gen_addba_send not implemented */ + /* .gen_addba_set_resp not implemented */ }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 980d6ee82cc6..9872181d33aa 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4930,6 +4930,32 @@ ath10k_wmi_op_gen_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, return skb; } +static struct sk_buff * +ath10k_wmi_op_gen_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 status) +{ + struct wmi_addba_setresponse_cmd *cmd; + struct sk_buff *skb; + + if (!mac) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_addba_setresponse_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, mac); + cmd->tid = __cpu_to_le32(tid); + cmd->statuscode = __cpu_to_le32(status); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n", + vdev_id, mac, tid, status); + return skb; +} + static const struct wmi_ops wmi_ops = { .rx = ath10k_wmi_op_rx, .map_svc = wmi_main_svc_map, @@ -4983,6 +5009,7 @@ static const struct wmi_ops wmi_ops = { /* .gen_pdev_get_temperature not implemented */ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, .gen_addba_send = ath10k_wmi_op_gen_addba_send, + .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, }; static const struct wmi_ops wmi_10_1_ops = { @@ -5039,6 +5066,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, .gen_addba_send = ath10k_wmi_op_gen_addba_send, + .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, }; static const struct wmi_ops wmi_10_2_ops = { @@ -5096,6 +5124,7 @@ static const struct wmi_ops wmi_10_2_ops = { .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, .gen_addba_send = ath10k_wmi_op_gen_addba_send, + .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, }; static const struct wmi_ops wmi_10_2_4_ops = { @@ -5153,6 +5182,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, .gen_addba_send = ath10k_wmi_op_gen_addba_send, + .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, }; int ath10k_wmi_attach(struct ath10k *ar) -- cgit v1.2.1 From 50abef85e7cc7576b37ba8dbe480f0537fe74d6d Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 12 Jan 2015 14:07:26 +0200 Subject: ath10k: add wmi support for delba_send Add WMI support for sending delba request. This command is used for debugging purpose. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 21 +++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index e8f49de18369..3a3d15e65e0a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -126,6 +126,9 @@ struct wmi_ops { struct sk_buff *(*gen_addba_set_resp)(struct ath10k *ar, u32 vdev_id, const u8 *mac, u32 tid, u32 status); + struct sk_buff *(*gen_delba_send)(struct ath10k *ar, u32 vdev_id, + const u8 *mac, u32 tid, u32 initiator, + u32 reason); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -914,4 +917,22 @@ ath10k_wmi_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac, ar->wmi.cmd->addba_set_resp_cmdid); } +static inline int +ath10k_wmi_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 initiator, u32 reason) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_delba_send) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_delba_send(ar, vdev_id, mac, tid, initiator, + reason); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->delba_send_cmdid); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 63f98600cc05..57d2b50c1f00 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2210,6 +2210,7 @@ static const struct wmi_ops wmi_tlv_ops = { /* .gen_addba_clear_resp not implemented */ /* .gen_addba_send not implemented */ /* .gen_addba_set_resp not implemented */ + /* .gen_delba_send not implemented */ }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 9872181d33aa..2d3c700e2cbb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4956,6 +4956,33 @@ ath10k_wmi_op_gen_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac, return skb; } +static struct sk_buff * +ath10k_wmi_op_gen_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 initiator, u32 reason) +{ + struct wmi_delba_send_cmd *cmd; + struct sk_buff *skb; + + if (!mac) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_delba_send_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, mac); + cmd->tid = __cpu_to_le32(tid); + cmd->initiator = __cpu_to_le32(initiator); + cmd->reasoncode = __cpu_to_le32(reason); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n", + vdev_id, mac, tid, initiator, reason); + return skb; +} + static const struct wmi_ops wmi_ops = { .rx = ath10k_wmi_op_rx, .map_svc = wmi_main_svc_map, @@ -5010,6 +5037,7 @@ static const struct wmi_ops wmi_ops = { .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, .gen_addba_send = ath10k_wmi_op_gen_addba_send, .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, + .gen_delba_send = ath10k_wmi_op_gen_delba_send, }; static const struct wmi_ops wmi_10_1_ops = { @@ -5067,6 +5095,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, .gen_addba_send = ath10k_wmi_op_gen_addba_send, .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, + .gen_delba_send = ath10k_wmi_op_gen_delba_send, }; static const struct wmi_ops wmi_10_2_ops = { @@ -5125,6 +5154,7 @@ static const struct wmi_ops wmi_10_2_ops = { .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, .gen_addba_send = ath10k_wmi_op_gen_addba_send, .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, + .gen_delba_send = ath10k_wmi_op_gen_delba_send, }; static const struct wmi_ops wmi_10_2_4_ops = { @@ -5183,6 +5213,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, .gen_addba_send = ath10k_wmi_op_gen_addba_send, .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, + .gen_delba_send = ath10k_wmi_op_gen_delba_send, }; int ath10k_wmi_attach(struct ath10k *ar) -- cgit v1.2.1 From f5045988b937e4801e3185f9d95c34a7c050b681 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 12 Jan 2015 14:07:27 +0200 Subject: ath10k: Implement sta_add_debugfs Add per station debugfs files when a station is added to mac80211's station list. This helps to group peer specific debugfs entries altogether. Right now this callback adds support to test aggregation procedures (addba/addba_resp/delba) manually. To enable automatic aggregation in target, echo 0 >/sys/kernel/debug/ieee80211/phyX/netdev:wlanX/ stations/XX:XX:XX:XX:XX:XX/aggr_mode For manual mode, echo 1 >/sys/kernel/debug/ieee80211/phyX/netdev:wlanX/ stations/XX:XX:XX:XX:XX:XX/aggr_mode Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Makefile | 1 + drivers/net/wireless/ath/ath10k/core.h | 5 ++ drivers/net/wireless/ath/ath10k/debug.h | 11 +++- drivers/net/wireless/ath/ath10k/debugfs_sta.c | 88 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/mac.c | 3 + 5 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath10k/debugfs_sta.c (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index ffa3b1a8745f..6c0c23e79bda 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -15,6 +15,7 @@ ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o ath10k_core-$(CONFIG_THERMAL) += thermal.o +ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o ath10k_pci-y += pci.o \ diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 7b6d9e4567a3..c5686122b140 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -239,6 +239,11 @@ struct ath10k_sta { u32 smps; struct work_struct update_wk; + +#ifdef CONFIG_MAC80211_DEBUGFS + /* protected by conf_mutex */ + bool aggr_mode; +#endif }; #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 1b87a5dbec53..a12b8323f9f1 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -48,6 +48,12 @@ enum ath10k_pktlog_filter { ATH10K_PKTLOG_ANY = 0x00000001f, }; +enum ath10k_dbg_aggr_mode { + ATH10K_DBG_AGGR_MODE_AUTO, + ATH10K_DBG_AGGR_MODE_MANUAL, + ATH10K_DBG_AGGR_MODE_MAX, +}; + extern unsigned int ath10k_debug_mask; __printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...); @@ -77,7 +83,6 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw, void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ethtool_stats *stats, u64 *data); - #else static inline int ath10k_debug_start(struct ath10k *ar) { @@ -129,6 +134,10 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) #define ath10k_debug_get_et_stats NULL #endif /* CONFIG_ATH10K_DEBUGFS */ +#ifdef CONFIG_MAC80211_DEBUGFS +void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct dentry *dir); +#endif /* CONFIG_MAC80211_DEBUGFS */ #ifdef CONFIG_ATH10K_DEBUG __printf(3, 4) void ath10k_dbg(struct ath10k *ar, diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c new file mode 100644 index 000000000000..5df967387532 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "wmi-ops.h" +#include "debug.h" + +static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + char buf[32]; + int len = 0; + + mutex_lock(&ar->conf_mutex); + len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n", + (arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ? + "auto" : "manual"); + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + u32 aggr_mode; + int ret; + + if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode)) + return -EINVAL; + + if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + if ((ar->state != ATH10K_STATE_ON) || + (aggr_mode == arsta->aggr_mode)) { + ret = count; + goto out; + } + + ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr); + if (ret) { + ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret); + goto out; + } + + arsta->aggr_mode = aggr_mode; +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_aggr_mode = { + .read = ath10k_dbg_sta_read_aggr_mode, + .write = ath10k_dbg_sta_write_aggr_mode, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct dentry *dir) +{ + debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta, + &fops_aggr_mode); +} diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 5085f558d010..c7febfc9c68f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4746,6 +4746,9 @@ static const struct ieee80211_ops ath10k_ops = { .suspend = ath10k_suspend, .resume = ath10k_resume, #endif +#ifdef CONFIG_MAC80211_DEBUGFS + .sta_add_debugfs = ath10k_sta_add_debugfs, +#endif }; #define RATETAB_ENT(_rate, _rateid, _flags) { \ -- cgit v1.2.1 From 8bf8f190febcd2b4544d5fa13ed0809e2e92f53b Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 12 Jan 2015 14:07:27 +0200 Subject: ath10k: add support to send addba request This per-station debugfs entry helps to send addba request in manual mode. Need to pass two configuration parameters (tid, buffer size) as input. To send addba, echo 1 32 >/sys/kernel/debug/ieee80211/phyX/netdev:wlanX/ stations/XX:XX:XX:XX:XX:XX/addba Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debugfs_sta.c | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 5df967387532..23d81a244201 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -80,9 +80,61 @@ static const struct file_operations fops_aggr_mode = { .llseek = default_llseek, }; +static ssize_t ath10k_dbg_sta_write_addba(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + u32 tid, buf_size; + int ret; + char buf[64]; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = '\0'; + + ret = sscanf(buf, "%u %u", &tid, &buf_size); + if (ret != 2) + return -EINVAL; + + /* Valid TID values are 0 through 15 */ + if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + if ((ar->state != ATH10K_STATE_ON) || + (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { + ret = count; + goto out; + } + + ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr, + tid, buf_size); + if (ret) { + ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n", + arsta->arvif->vdev_id, sta->addr, tid, buf_size); + } + + ret = count; +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_addba = { + .write = ath10k_dbg_sta_write_addba, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta, &fops_aggr_mode); + debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba); } -- cgit v1.2.1 From 8e68d55f5e4a0444a569ecf605f482b9af0b9264 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 12 Jan 2015 14:07:27 +0200 Subject: ath10k: add support to send addba response This per-station debugfs entry helps to send addba response in manual mode for debugging purpose. It accepts tid and status code as input arguments. To send addba response, echo 0 25 >/sys/kernel/debug/ieee80211/phyX/netdev:wlanX/ stations/XX:XX:XX:XX:XX:XX/addba_resp Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debugfs_sta.c | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 23d81a244201..31a72d41addd 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -131,10 +131,61 @@ static const struct file_operations fops_addba = { .llseek = default_llseek, }; +static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + u32 tid, status; + int ret; + char buf[64]; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = '\0'; + + ret = sscanf(buf, "%u %u", &tid, &status); + if (ret != 2) + return -EINVAL; + + /* Valid TID values are 0 through 15 */ + if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + if ((ar->state != ATH10K_STATE_ON) || + (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { + ret = count; + goto out; + } + + ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr, + tid, status); + if (ret) { + ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n", + arsta->arvif->vdev_id, sta->addr, tid, status); + } + ret = count; +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_addba_resp = { + .write = ath10k_dbg_sta_write_addba_resp, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta, &fops_aggr_mode); debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba); + debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp); } -- cgit v1.2.1 From da2aedcadbe2e03db78b30adccbdba77e25f406b Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 12 Jan 2015 14:07:28 +0200 Subject: ath10k: add support to send delba This per-station debugfs entry helps to send delba in manual mode for debugging purpose. It accepts tid, initiator and reason code as inputs. To send delba, echo 0 1 37 >/sys/kernel/debug/ieee80211/phyX/netdev:wlanX/ stations/XX:XX:XX:XX:XX:XX/delba Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debugfs_sta.c | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 31a72d41addd..95b5c49374e0 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -181,6 +181,57 @@ static const struct file_operations fops_addba_resp = { .llseek = default_llseek, }; +static ssize_t ath10k_dbg_sta_write_delba(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + u32 tid, initiator, reason; + int ret; + char buf[64]; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = '\0'; + + ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason); + if (ret != 3) + return -EINVAL; + + /* Valid TID values are 0 through 15 */ + if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + if ((ar->state != ATH10K_STATE_ON) || + (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { + ret = count; + goto out; + } + + ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr, + tid, initiator, reason); + if (ret) { + ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n", + arsta->arvif->vdev_id, sta->addr, tid, initiator, + reason); + } + ret = count; +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_delba = { + .write = ath10k_dbg_sta_write_delba, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { @@ -188,4 +239,5 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, &fops_aggr_mode); debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba); debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp); + debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba); } -- cgit v1.2.1 From 8be3b69259ce2b9efc9a822ff3bf48a42460f133 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 29 Dec 2014 18:04:43 +0100 Subject: ath10k: fix error return code Return a negative error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_tx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index a1bda41fb543..5c64139161fc 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -475,8 +475,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC, &paddr); - if (!skb_cb->htt.txbuf) + if (!skb_cb->htt.txbuf) { + res = -ENOMEM; goto err_free_msdu_id; + } skb_cb->htt.txbuf_paddr = paddr; skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, -- cgit v1.2.1 From c3ebfede463ca071ae42d5b5aa3b6cb89c592951 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 5 Jan 2015 10:10:22 +0530 Subject: ath10k: Remove unused htt->max_throughput_mbps htt->max_throughput_mbps is not used anywhere. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.c | 1 - drivers/net/wireless/ath/ath10k/htt.h | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 56cb4aceb383..ceec76426070 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -53,7 +53,6 @@ int ath10k_htt_init(struct ath10k *ar) struct ath10k_htt *htt = &ar->htt; htt->ar = ar; - htt->max_throughput_mbps = 800; /* * Prefetch enough data to satisfy target diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 1bd5545af903..8809b37e1912 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1182,7 +1182,6 @@ struct ath10k_htt { struct ath10k *ar; enum ath10k_htc_ep_id eid; - int max_throughput_mbps; u8 target_version_major; u8 target_version_minor; struct completion target_version_received; -- cgit v1.2.1 From 49274332a43a70b3a3f40ba6db14d9c0677e8e02 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 8 Jan 2015 11:36:56 +0100 Subject: ath10k: fill max_num_vdevs for wmi-tlv Recent commit 30c78167bc6536d9074aa79385a575596343bf69 ("ath10k: set max_num_vdevs based on wmi op version") skipped wmi-tlv case and left max_num_vdevs reset. Make sure it is properly set. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 2d0671ebcf2b..a5465752a3ff 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -927,6 +927,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_TLV: ar->max_num_peers = TARGET_TLV_NUM_PEERS; ar->max_num_stations = TARGET_TLV_NUM_STATIONS; + ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS; ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC; break; case ATH10K_FW_WMI_OP_VERSION_UNSET: -- cgit v1.2.1 From 38e2a644174e74f948ec4415ae5b5c76f1412b0e Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Thu, 8 Jan 2015 13:27:34 +0100 Subject: ath10k: fixup wait_for_completion_timeout return handling wait_for_completion_timeout does not return negative values so the tests for <= 0 are not needed and the case differentiation in the error handling path unnecessary. Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 2 +- drivers/net/wireless/ath/ath10k/htc.c | 6 ++---- drivers/net/wireless/ath/ath10k/htt.c | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 6ca24427e184..42b2e49b2836 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -371,7 +371,7 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar) ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete, 1*HZ); - if (ret <= 0) + if (ret == 0) return -ETIMEDOUT; spin_lock_bh(&ar->data_lock); diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index f1946a6be442..2fd9e180272b 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -703,11 +703,9 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, /* wait for response */ status = wait_for_completion_timeout(&htc->ctl_resp, ATH10K_HTC_CONN_SVC_TIMEOUT_HZ); - if (status <= 0) { - if (status == 0) - status = -ETIMEDOUT; + if (status == 0) { ath10k_err(ar, "Service connect timeout: %d\n", status); - return status; + return -ETIMEDOUT; } /* we controlled the buffer creation, it's aligned */ diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index ceec76426070..4f59ab923e48 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -101,7 +101,7 @@ int ath10k_htt_setup(struct ath10k_htt *htt) status = wait_for_completion_timeout(&htt->target_version_received, HTT_TARGET_VERSION_TIMEOUT_HZ); - if (status <= 0) { + if (status == 0) { ath10k_warn(ar, "htt version request timed out\n"); return -ETIMEDOUT; } diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c7febfc9c68f..b403cba0afc1 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2228,7 +2228,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) ret = wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ); - if (ret <= 0) + if (ret == 0) ath10k_warn(ar, "timed out waiting for offchannel skb %p\n", skb); -- cgit v1.2.1 From 5de6dfc82f715b9fe9cf5c0cccce4384a82279ef Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 9 Jan 2015 22:49:46 +0530 Subject: ath10k: Fix potential Rx ring corruption When replenishing Rx buffers driver updates the address of the buffer and the index of rx buffer in rx ring to the firmware. Change in order by CPU can cause rx ring corruption. Add memory barrier before updating rx buffer index to guarantee the order. This could fix some instances of rx ring corruption due to done bit in rx attention flag not set. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 9c782a42665e..baa1c447a3b8 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -97,6 +97,11 @@ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) } fail: + /* + * Make sure the rx buffer is updated before available buffer + * index to avoid any potential rx ring corruption. + */ + mb(); *htt->rx_ring.alloc_idx.vaddr = __cpu_to_le32(idx); return ret; } -- cgit v1.2.1 From a4031afbdc7bfdf26b98b160a5fca05b9cf38140 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 13 Jan 2015 14:21:45 +0530 Subject: ath10k: fix config_enabled check for hwmon Because of wrong macro check in commit 96bba98393f9 ("ath10k: fix build error when hwmon is off"), hwmon never be enabled. Fix that. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index b14ae8d135f6..c384c79975ba 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -215,7 +215,7 @@ int ath10k_thermal_register(struct ath10k *ar) /* Avoid linking error on devm_hwmon_device_register_with_groups, I * guess linux/hwmon.h is missing proper stubs. */ - if (!config_enabled(HWMON)) + if (!config_enabled(CONFIG_HWMON)) return 0; hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev, -- cgit v1.2.1 From 6a9ddb36eeb897807341fc92d35b71b2d5d6d67d Mon Sep 17 00:00:00 2001 From: Mitch A Williams Date: Tue, 9 Dec 2014 08:53:01 +0000 Subject: i40e: disable IOV before freeing resources If VF drivers are loaded in the host OS, the call to pci_disable_sriov() will cause these drivers' remove routines to be called. If the PF driver has already freed VF resources before this happens, then the VF remove routine can't properly communicate with the PF driver causing all sorts of mayhem and error messages and hurt feelings. To fix this, we move the call to pci_disable_sriov() up to the top of the function and let it complete before freeing any VF resources. Change-ID: I397c3997a00f6408e32b7735273911e499600236 Signed-off-by: Mitch Williams Acked-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 5bae89550657..044019b9d406 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -791,10 +791,18 @@ void i40e_free_vfs(struct i40e_pf *pf) if (!pf->vf) return; + /* Disable IOV before freeing resources. This lets any VF drivers + * running in the host get themselves cleaned up before we yank + * the carpet out from underneath their feet. + */ + if (!pci_vfs_assigned(pf->pdev)) + pci_disable_sriov(pf->pdev); + + msleep(20); /* let any messages in transit get finished up */ + /* Disable interrupt 0 so we don't try to handle the VFLR. */ i40e_irq_dynamic_disable_icr0(pf); - mdelay(10); /* let any messages in transit get finished up */ /* free up vf resources */ tmp = pf->num_alloc_vfs; pf->num_alloc_vfs = 0; @@ -813,7 +821,6 @@ void i40e_free_vfs(struct i40e_pf *pf) * before this function ever gets called. */ if (!pci_vfs_assigned(pf->pdev)) { - pci_disable_sriov(pf->pdev); /* Acknowledge VFLR for all VFS. Without this, VFs will fail to * work correctly when SR-IOV gets re-enabled. */ -- cgit v1.2.1 From ff30cb6b59f429c0d9e398d2af045af0d6960676 Mon Sep 17 00:00:00 2001 From: Mitch A Williams Date: Tue, 9 Dec 2014 08:53:02 +0000 Subject: i40evf: remove redundant code These functions are redundant and duplicate functionality found in i40evf_free_all_[tx|rx]_resources. Change-ID: Ia199908926d7a1a4b8247f75f89b5da24c9b149c Signed-off-by: Mitch Williams Acked-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 27 ------------------------- 1 file changed, 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index cabaf599f562..ee0db5900d52 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -946,30 +946,6 @@ static int i40evf_up_complete(struct i40evf_adapter *adapter) return 0; } -/** - * i40evf_clean_all_rx_rings - Free Rx Buffers for all queues - * @adapter: board private structure - **/ -static void i40evf_clean_all_rx_rings(struct i40evf_adapter *adapter) -{ - int i; - - for (i = 0; i < adapter->num_active_queues; i++) - i40evf_clean_rx_ring(adapter->rx_rings[i]); -} - -/** - * i40evf_clean_all_tx_rings - Free Tx Buffers for all queues - * @adapter: board private structure - **/ -static void i40evf_clean_all_tx_rings(struct i40evf_adapter *adapter) -{ - int i; - - for (i = 0; i < adapter->num_active_queues; i++) - i40evf_clean_tx_ring(adapter->tx_rings[i]); -} - /** * i40e_down - Shutdown the connection processing * @adapter: board private structure @@ -1008,9 +984,6 @@ void i40evf_down(struct i40evf_adapter *adapter) i40evf_napi_disable_all(adapter); netif_carrier_off(netdev); - - i40evf_clean_all_tx_rings(adapter); - i40evf_clean_all_rx_rings(adapter); } /** -- cgit v1.2.1 From d4f82fd36836f6c90771cd0ceb4dfe191569e2c6 Mon Sep 17 00:00:00 2001 From: Mitch A Williams Date: Tue, 9 Dec 2014 08:53:03 +0000 Subject: i40evf: Remove some scary log messages These messages may be triggered during normal init of the driver if the PF or FW take a long time to respond. There's nothing really wrong, so don't freak people out logging messages. If the communication channel really is dead, then we'll retry a few times and give up. This will log a different more scary message that should cause consternation. This allows the user to more easily detect a genuine failure. Change-ID: I6e2b758d4234a3a09c1015c82c8f2442a697cbdb Signed-off-by: Mitch Williams Acked-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 7 +------ drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 3 --- 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index ee0db5900d52..6c73acf7d2d9 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2026,12 +2026,8 @@ static void i40evf_init_task(struct work_struct *work) /* aq msg sent, awaiting reply */ err = i40evf_verify_api_ver(adapter); if (err) { - dev_info(&pdev->dev, "Unable to verify API version (%d), retrying\n", - err); - if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) { - dev_info(&pdev->dev, "Resending request\n"); + if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) err = i40evf_send_api_ver(adapter); - } goto err; } err = i40evf_send_vf_config_msg(adapter); @@ -2054,7 +2050,6 @@ static void i40evf_init_task(struct work_struct *work) } err = i40evf_get_vf_config(adapter); if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) { - dev_info(&pdev->dev, "Resending VF config request\n"); err = i40evf_send_vf_config_msg(adapter); goto err; } diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 5fde5a7f4591..3aeb633e6bc2 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -715,9 +715,6 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, } return; } - if (v_opcode != adapter->current_op) - dev_info(&adapter->pdev->dev, "Pending op is %d, received %d\n", - adapter->current_op, v_opcode); if (v_retval) { dev_err(&adapter->pdev->dev, "%s: PF returned error %d to our request %d\n", __func__, v_retval, v_opcode); -- cgit v1.2.1 From 53d0b3ae2590bbd15620ce905c05320ed9cfed1a Mon Sep 17 00:00:00 2001 From: Mitch A Williams Date: Tue, 9 Dec 2014 08:53:04 +0000 Subject: i40evf: refactor shutdown code If the VF driver is running in the host, the shutdown code is completely broken. We cannot wait in our down routine for the PF to respond to our requests, as its admin queue task will never run while we hold the lock. Instead, we schedule operations, then let the watchdog take care of shutting things down. If the driver is being removed, then wait in the remove routine until the watchdog is done before continuing. Change-ID: I93a58d17389e8d6b58f21e430b56ed7b4590b2c5 Signed-off-by: Mitch Williams Acked-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 29 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 6c73acf7d2d9..d3392569485c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -958,6 +958,12 @@ void i40evf_down(struct i40evf_adapter *adapter) if (adapter->state == __I40EVF_DOWN) return; + while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, + &adapter->crit_section)) + usleep_range(500, 1000); + + i40evf_irq_disable(adapter); + /* remove all MAC filters */ list_for_each_entry(f, &adapter->mac_filter_list, list) { f->remove = true; @@ -968,22 +974,27 @@ void i40evf_down(struct i40evf_adapter *adapter) } if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) && adapter->state != __I40EVF_RESETTING) { - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; + /* cancel any current operation */ + adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->aq_pending = 0; + /* Schedule operations to close down the HW. Don't wait + * here for this to complete. The watchdog is still running + * and it will take care of this. + */ + adapter->aq_required = I40EVF_FLAG_AQ_DEL_MAC_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; - /* disable receives */ adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES; - mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); - msleep(20); } netif_tx_disable(netdev); netif_tx_stop_all_queues(netdev); - i40evf_irq_disable(adapter); - i40evf_napi_disable_all(adapter); + msleep(20); + netif_carrier_off(netdev); + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); } /** @@ -2408,6 +2419,7 @@ static void i40evf_remove(struct pci_dev *pdev) struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40evf_mac_filter *f, *ftmp; struct i40e_hw *hw = &adapter->hw; + int count = 50; cancel_delayed_work_sync(&adapter->init_task); cancel_work_sync(&adapter->reset_task); @@ -2416,6 +2428,11 @@ static void i40evf_remove(struct pci_dev *pdev) unregister_netdev(netdev); adapter->netdev_registered = false; } + while (count-- && adapter->aq_required) + msleep(50); + + if (count < 0) + dev_err(&pdev->dev, "Timed out waiting for PF driver.\n"); adapter->state = __I40EVF_REMOVE; if (adapter->msix_entries) { -- cgit v1.2.1 From 37dfdf373ce98a7b9fe99478bc40ffaef2ea5eee Mon Sep 17 00:00:00 2001 From: Mitch A Williams Date: Tue, 9 Dec 2014 08:53:05 +0000 Subject: i40evf: remove leftover VLAN filters If we're using VLANs and communications with the PF fail during shutdown, we will leak memory because not all of the VLAN filters will be removed. To eliminate this possibility, go through the list again right before the module is removed and delete any leftover entries. Change-ID: Id3b5315c47ca0a61ae123a96ff345d010bc41aed Signed-off-by: Mitch Williams Acked-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index d3392569485c..994ae4e782d4 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2462,6 +2462,10 @@ static void i40evf_remove(struct pci_dev *pdev) list_del(&f->list); kfree(f); } + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { + list_del(&f->list); + kfree(f); + } free_netdev(netdev); -- cgit v1.2.1 From 4870e176aada5c214d2224a8596465a0f7fbab3d Mon Sep 17 00:00:00 2001 From: Mitch A Williams Date: Tue, 9 Dec 2014 08:53:06 +0000 Subject: i40evf: don't fire traffic IRQs when the interface is down There is always a possibility that MSI-X interrupts can get lost. To keep this problem from stalling the driver, we fire all of our MSI-X vectors during the watchdog routine. However, we should not fire the traffic vectors when the interface is closed. In this case, just fire vector 0, which is used for admin queue events. As a result, we do not enable the interrupt cause for vector 0. This can cause the admin queue handler to be called reentrantly, which causes a scary "critical section violation" message to be logged, even though no real damage is done. Change-ID: Ic43a5184708ab2cb9a23fca7dedd808a46717795 Signed-off-by: Mitch Williams Acked-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 994ae4e782d4..c960ef5007cf 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1385,11 +1385,14 @@ static void i40evf_watchdog_task(struct work_struct *work) if (adapter->state == __I40EVF_RUNNING) i40evf_request_stats(adapter); - - i40evf_irq_enable(adapter, true); - i40evf_fire_sw_int(adapter, 0xFF); - watchdog_done: + if (adapter->state == __I40EVF_RUNNING) { + i40evf_irq_enable_queues(adapter, ~0); + i40evf_fire_sw_int(adapter, 0xFF); + } else { + i40evf_fire_sw_int(adapter, 0x1); + } + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); restart_watchdog: if (adapter->state == __I40EVF_REMOVE) -- cgit v1.2.1 From 7235448c9d90ca221587178e9b468839b2724440 Mon Sep 17 00:00:00 2001 From: Mitch A Williams Date: Tue, 9 Dec 2014 08:53:07 +0000 Subject: i40evf: enable interrupt 0 appropriately Don't enable vector 0 in the ISR, just schedule the adminq task and let it enable the vector. This prevents the task from being called reentrantly. Make sure that the vector is enabled on all exit paths of the adminq task, including error exits. Change-ID: I53f3d14f91ed7a9e90291ea41c681122a5eca5b5 Signed-off-by: Mitch Williams Acked-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index c960ef5007cf..e2311affdfe2 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -313,10 +313,6 @@ static irqreturn_t i40evf_msix_aq(int irq, void *data) val = val | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTL01, val); - /* re-enable interrupt causes */ - wr32(hw, I40E_VFINT_ICR0_ENA1, ena_mask); - wr32(hw, I40E_VFINT_DYN_CTL01, I40E_VFINT_DYN_CTL01_INTENA_MASK); - /* schedule work on the private workqueue */ schedule_work(&adapter->adminq_task); @@ -1620,12 +1616,12 @@ static void i40evf_adminq_task(struct work_struct *work) u16 pending; if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) - return; + goto out; event.buf_len = I40EVF_MAX_AQ_BUF_SIZE; event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); if (!event.msg_buf) - return; + goto out; v_msg = (struct i40e_virtchnl_msg *)&event.desc; do { @@ -1675,10 +1671,10 @@ static void i40evf_adminq_task(struct work_struct *work) if (oldval != val) wr32(hw, hw->aq.asq.len, val); + kfree(event.msg_buf); +out: /* re-enable Admin queue interrupt cause */ i40evf_misc_irq_enable(adapter); - - kfree(event.msg_buf); } /** -- cgit v1.2.1 From 0758e7cb5f61a61dffe814bc91ebb4ea8e5cc534 Mon Sep 17 00:00:00 2001 From: Mitch A Williams Date: Tue, 9 Dec 2014 08:53:08 +0000 Subject: i40evf: kick a stalled admin queue On some versions of the firmware, the VF admin send queue may become stalled. In this case, the easiest solution is to just place another descriptor on the queue; the firmware will then process both requests. The early init code already accounts for this, but the runtime code does not. In the watchdog task, check for the stall condition, and if it's found, send our API version to the PF. When the PF replies, just ignore the reply. Change-ID: I380d78185a4f284d649c44d263e648afc9b4d50c Signed-off-by: Mitch Williams Acked-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 7 ++++++- drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index e2311affdfe2..21ccbe8b6d13 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1336,8 +1336,13 @@ static void i40evf_watchdog_task(struct work_struct *work) /* Process admin queue tasks. After init, everything gets done * here so we don't race on the admin queue. */ - if (adapter->aq_pending) + if (adapter->aq_pending) { + if (!i40evf_asq_done(hw)) { + dev_dbg(&adapter->pdev->dev, "Admin queue timeout\n"); + i40evf_send_api_ver(adapter); + } goto watchdog_done; + } if (adapter->aq_required & I40EVF_FLAG_AQ_MAP_VECTORS) { i40evf_map_queues(adapter); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 3aeb633e6bc2..3f0c85ecbca6 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -720,6 +720,9 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, __func__, v_retval, v_opcode); } switch (v_opcode) { + case I40E_VIRTCHNL_OP_VERSION: + /* no action, but also not an error */ + break; case I40E_VIRTCHNL_OP_GET_STATS: { struct i40e_eth_stats *stats = (struct i40e_eth_stats *)msg; -- cgit v1.2.1 From 148c2d80d548a111d48b3c37a794ca5e0eb703c5 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Thu, 11 Dec 2014 07:06:27 +0000 Subject: i40e: Add warning for NPAR partitions with link speed less than 10Gbps NPAR enabled partitions should warn the user when detected link speed is less than 10Gpbs. Change-ID: I7728bb8ce279bf0f4f755d78d7071074a4eb5f69 Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index a5f2660d552d..7c1497330138 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4557,6 +4557,15 @@ static void i40e_print_link_message(struct i40e_vsi *vsi, bool isup) return; } + /* Warn user if link speed on NPAR enabled partition is not at + * least 10GB + */ + if (vsi->back->hw.func_caps.npar_enable && + (vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_1GB || + vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_100MB)) + netdev_warn(vsi->netdev, + "The partition detected link speed that is less than 10Gbps\n"); + switch (vsi->back->hw.phy.link_info.link_speed) { case I40E_LINK_SPEED_40GB: strlcpy(speed, "40 Gbps", SPEED_SIZE); -- cgit v1.2.1 From b2d4d9059ec65e10cde070148207d3b70a596394 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Thu, 11 Dec 2014 07:06:28 +0000 Subject: i40e: remove VN2VN related mac filters These mac address already added by FCoE stack above netdev, therefore adding them here is redundant. Change-ID: Ia5b59f426f57efd20f8945f7c6cc5d741fbe06e5 Signed-off-by: Vasu Dev Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c index a8b8bd95108d..2cd841b29059 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -1515,8 +1515,6 @@ void i40e_fcoe_config_netdev(struct net_device *netdev, struct i40e_vsi *vsi) i40e_add_filter(vsi, (u8[6]) FC_FCOE_FLOGI_MAC, 0, false, false); i40e_add_filter(vsi, FIP_ALL_FCOE_MACS, 0, false, false); i40e_add_filter(vsi, FIP_ALL_ENODE_MACS, 0, false, false); - i40e_add_filter(vsi, FIP_ALL_VN2VN_MACS, 0, false, false); - i40e_add_filter(vsi, FIP_ALL_P2P_MACS, 0, false, false); /* use san mac */ ether_addr_copy(netdev->dev_addr, hw->mac.san_addr); -- cgit v1.2.1 From 9fee9db5fb6a62ab1340a1dca43aa8e352cf49e2 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Thu, 11 Dec 2014 07:06:30 +0000 Subject: i40e/i40evf: find partition_id in npar mode When in NPAR mode the driver instance might be controlling the base partition or one of the other "fake" PFs. There are some things that can only be done by the base partition, aka partition_id 1. This code does a bit of work to find how many partitions are there per port and what is the current partition_id. Change-ID: Iba427f020a1983d02147d86f121b3627e20ee21d Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 66 ++++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_prototype.h | 3 ++ drivers/net/ethernet/intel/i40e/i40e_type.h | 7 ++- drivers/net/ethernet/intel/i40evf/i40e_type.h | 7 ++- 4 files changed, 81 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 3d741ee99a2c..b16fc03ab00c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -2034,6 +2034,43 @@ i40e_status i40e_aq_send_msg_to_vf(struct i40e_hw *hw, u16 vfid, return status; } +/** + * i40e_aq_debug_read_register + * @hw: pointer to the hw struct + * @reg_addr: register address + * @reg_val: register value + * @cmd_details: pointer to command details structure or NULL + * + * Read the register using the admin queue commands + **/ +i40e_status i40e_aq_debug_read_register(struct i40e_hw *hw, + u32 reg_addr, u64 *reg_val, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_debug_reg_read_write *cmd_resp = + (struct i40e_aqc_debug_reg_read_write *)&desc.params.raw; + i40e_status status; + + if (reg_val == NULL) + return I40E_ERR_PARAM; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_debug_read_reg); + + cmd_resp->address = cpu_to_le32(reg_addr); + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + + if (!status) { + *reg_val = ((u64)cmd_resp->value_high << 32) | + (u64)cmd_resp->value_low; + *reg_val = le64_to_cpu(*reg_val); + } + + return status; +} + /** * i40e_aq_debug_write_register * @hw: pointer to the hw struct @@ -2292,6 +2329,7 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, enum i40e_admin_queue_opc list_type_opc) { struct i40e_aqc_list_capabilities_element_resp *cap; + u32 valid_functions, num_functions; u32 number, logical_id, phys_id; struct i40e_hw_capabilities *p; u32 i = 0; @@ -2427,6 +2465,34 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, if (p->npar_enable || p->mfp_mode_1) p->fcoe = false; + /* count the enabled ports (aka the "not disabled" ports) */ + hw->num_ports = 0; + for (i = 0; i < 4; i++) { + u32 port_cfg_reg = I40E_PRTGEN_CNF + (4 * i); + u64 port_cfg = 0; + + /* use AQ read to get the physical register offset instead + * of the port relative offset + */ + i40e_aq_debug_read_register(hw, port_cfg_reg, &port_cfg, NULL); + if (!(port_cfg & I40E_PRTGEN_CNF_PORT_DIS_MASK)) + hw->num_ports++; + } + + valid_functions = p->valid_functions; + num_functions = 0; + while (valid_functions) { + if (valid_functions & 1) + num_functions++; + valid_functions >>= 1; + } + + /* partition id is 1-based, and functions are evenly spread + * across the ports as partitions + */ + hw->partition_id = (hw->pf_id / hw->num_ports) + 1; + hw->num_partitions = num_functions / hw->num_ports; + /* additional HW specific goodies that might * someday be HW version specific */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 2fb4306597e8..d1c7d6332c0f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -71,6 +71,9 @@ i40e_status i40e_aq_get_firmware_version(struct i40e_hw *hw, i40e_status i40e_aq_debug_write_register(struct i40e_hw *hw, u32 reg_addr, u64 reg_val, struct i40e_asq_cmd_details *cmd_details); +i40e_status i40e_aq_debug_read_register(struct i40e_hw *hw, + u32 reg_addr, u64 *reg_val, + struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_default_vsi(struct i40e_hw *hw, u16 vsi_id, diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index c1f2eb963357..611de3e409bc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -431,7 +431,7 @@ struct i40e_hw { u8 __iomem *hw_addr; void *back; - /* function pointer structs */ + /* subsystem structs */ struct i40e_phy_info phy; struct i40e_mac_info mac; struct i40e_bus_info bus; @@ -458,6 +458,11 @@ struct i40e_hw { u8 pf_id; u16 main_vsi_seid; + /* for multi-function MACs */ + u16 partition_id; + u16 num_partitions; + u16 num_ports; + /* Closest numa node to the device */ u16 numa_node; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 68aec11f6523..d1c2b5a6e648 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -425,7 +425,7 @@ struct i40e_hw { u8 __iomem *hw_addr; void *back; - /* function pointer structs */ + /* subsystem structs */ struct i40e_phy_info phy; struct i40e_mac_info mac; struct i40e_bus_info bus; @@ -452,6 +452,11 @@ struct i40e_hw { u8 pf_id; u16 main_vsi_seid; + /* for multi-function MACs */ + u16 partition_id; + u16 num_partitions; + u16 num_ports; + /* Closest numa node to the device */ u16 numa_node; -- cgit v1.2.1 From 18f680c6969b6f0554e7ec5775f7a312b9f76692 Mon Sep 17 00:00:00 2001 From: Kamil Krawczyk Date: Thu, 11 Dec 2014 07:06:31 +0000 Subject: i40e: Adding function for reading PBA String Function will read PBA Block from Shadow RAM and return it in a string format. Change-ID: I4ee7059f6e21bd0eba38687da15e772e0b4ab36e Signed-off-by: Kamil Krawczyk Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 59 ++++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_prototype.h | 2 + drivers/net/ethernet/intel/i40e/i40e_type.h | 2 + 3 files changed, 63 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index b16fc03ab00c..4f4d9d16bddb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -741,6 +741,65 @@ i40e_status i40e_get_san_mac_addr(struct i40e_hw *hw, u8 *mac_addr) } #endif +/** + * i40e_read_pba_string - Reads part number string from EEPROM + * @hw: pointer to hardware structure + * @pba_num: stores the part number string from the EEPROM + * @pba_num_size: part number string buffer length + * + * Reads the part number string from the EEPROM. + **/ +i40e_status i40e_read_pba_string(struct i40e_hw *hw, u8 *pba_num, + u32 pba_num_size) +{ + i40e_status status = 0; + u16 pba_word = 0; + u16 pba_size = 0; + u16 pba_ptr = 0; + u16 i = 0; + + status = i40e_read_nvm_word(hw, I40E_SR_PBA_FLAGS, &pba_word); + if (status || (pba_word != 0xFAFA)) { + hw_dbg(hw, "Failed to read PBA flags or flag is invalid.\n"); + return status; + } + + status = i40e_read_nvm_word(hw, I40E_SR_PBA_BLOCK_PTR, &pba_ptr); + if (status) { + hw_dbg(hw, "Failed to read PBA Block pointer.\n"); + return status; + } + + status = i40e_read_nvm_word(hw, pba_ptr, &pba_size); + if (status) { + hw_dbg(hw, "Failed to read PBA Block size.\n"); + return status; + } + + /* Subtract one to get PBA word count (PBA Size word is included in + * total size) + */ + pba_size--; + if (pba_num_size < (((u32)pba_size * 2) + 1)) { + hw_dbg(hw, "Buffer to small for PBA data.\n"); + return I40E_ERR_PARAM; + } + + for (i = 0; i < pba_size; i++) { + status = i40e_read_nvm_word(hw, (pba_ptr + 1) + i, &pba_word); + if (status) { + hw_dbg(hw, "Failed to read PBA Block word %d.\n", i); + return status; + } + + pba_num[(i * 2)] = (pba_word >> 8) & 0xFF; + pba_num[(i * 2) + 1] = pba_word & 0xFF; + } + pba_num[(pba_size * 2)] = '\0'; + + return status; +} + /** * i40e_get_media_type - Gets media type * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index d1c7d6332c0f..68e852a96680 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -248,6 +248,8 @@ void i40e_clear_pxe_mode(struct i40e_hw *hw); bool i40e_get_link_status(struct i40e_hw *hw); i40e_status i40e_get_mac_addr(struct i40e_hw *hw, u8 *mac_addr); i40e_status i40e_get_port_mac_addr(struct i40e_hw *hw, u8 *mac_addr); +i40e_status i40e_read_pba_string(struct i40e_hw *hw, u8 *pba_num, + u32 pba_num_size); i40e_status i40e_validate_mac_addr(u8 *mac_addr); void i40e_pre_tx_queue_cfg(struct i40e_hw *hw, u32 queue, bool enable); #ifdef I40E_FCOE diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 611de3e409bc..ff121fe98dd4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -1140,6 +1140,8 @@ struct i40e_hw_port_stats { /* Checksum and Shadow RAM pointers */ #define I40E_SR_NVM_CONTROL_WORD 0x00 #define I40E_SR_EMP_MODULE_PTR 0x0F +#define I40E_SR_PBA_FLAGS 0x15 +#define I40E_SR_PBA_BLOCK_PTR 0x16 #define I40E_SR_NVM_IMAGE_VERSION 0x18 #define I40E_SR_NVM_WAKE_ON_LAN 0x19 #define I40E_SR_ALTERNATE_SAN_MAC_ADDRESS_PTR 0x27 -- cgit v1.2.1 From f0d8c73396a8abbb20dd5b73560ac6159ddf3c3d Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Thu, 11 Dec 2014 07:06:32 +0000 Subject: i40e: limit WoL and link settings to partition 1 When in multi-function mode, e.g. Dell's NPAR, only partition 1 of each MAC is allowed to set WoL, speed, and flow control. Change-ID: I87a9debc7479361c55a71f0120294ea319f23588 Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 43 +++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 951e8767fc50..b8230dc205ec 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -218,6 +218,16 @@ static const char i40e_gstrings_test[][ETH_GSTRING_LEN] = { #define I40E_TEST_LEN (sizeof(i40e_gstrings_test) / ETH_GSTRING_LEN) +/** + * i40e_partition_setting_complaint - generic complaint for MFP restriction + * @pf: the PF struct + **/ +static void i40e_partition_setting_complaint(struct i40e_pf *pf) +{ + dev_info(&pf->pdev->dev, + "The link settings are allowed to be changed only from the first partition of a given port. Please switch to the first partition in order to change the setting.\n"); +} + /** * i40e_get_settings - Get Link Speed and Duplex settings * @netdev: network interface device structure @@ -485,6 +495,14 @@ static int i40e_set_settings(struct net_device *netdev, u8 autoneg; u32 advertise; + /* Changing port settings is not supported if this isn't the + * port's controlling PF + */ + if (hw->partition_id != 1) { + i40e_partition_setting_complaint(pf); + return -EOPNOTSUPP; + } + if (vsi != pf->vsi[pf->lan_vsi]) return -EOPNOTSUPP; @@ -687,6 +705,14 @@ static int i40e_set_pauseparam(struct net_device *netdev, u8 aq_failures; int err = 0; + /* Changing the port's flow control is not supported if this isn't the + * port's controlling PF + */ + if (hw->partition_id != 1) { + i40e_partition_setting_complaint(pf); + return -EOPNOTSUPP; + } + if (vsi != pf->vsi[pf->lan_vsi]) return -EOPNOTSUPP; @@ -1503,7 +1529,7 @@ static void i40e_get_wol(struct net_device *netdev, /* NVM bit on means WoL disabled for the port */ i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits); - if ((1 << hw->port) & wol_nvm_bits) { + if ((1 << hw->port) & wol_nvm_bits || hw->partition_id != 1) { wol->supported = 0; wol->wolopts = 0; } else { @@ -1512,13 +1538,28 @@ static void i40e_get_wol(struct net_device *netdev, } } +/** + * i40e_set_wol - set the WakeOnLAN configuration + * @netdev: the netdev in question + * @wol: the ethtool WoL setting data + **/ static int i40e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; + struct i40e_vsi *vsi = np->vsi; struct i40e_hw *hw = &pf->hw; u16 wol_nvm_bits; + /* WoL not supported if this isn't the controlling PF on the port */ + if (hw->partition_id != 1) { + i40e_partition_setting_complaint(pf); + return -EOPNOTSUPP; + } + + if (vsi != pf->vsi[pf->lan_vsi]) + return -EOPNOTSUPP; + /* NVM bit on means WoL disabled for the port */ i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits); if (((1 << hw->port) & wol_nvm_bits)) -- cgit v1.2.1 From fef59ddfe8ab1302b0c999840f5d238c1dcd2497 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Thu, 11 Dec 2014 07:06:33 +0000 Subject: i40e: Don't exit link event early if link speed has changed Previously we were only checking if the link up state had changed, and if it hadn't exiting the link event routine early. We should also check if speed has changed, and if it has, stay and finish processing the link event. Change-ID: I9c8e0991b3f0279108a7858898c3c5ce0a9856b8 Signed-off-by: Catherine Sullivan Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7c1497330138..80430b0cfeb7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5503,14 +5503,18 @@ static void i40e_link_event(struct i40e_pf *pf) { bool new_link, old_link; struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; + u8 new_link_speed, old_link_speed; /* set this to force the get_link_status call to refresh state */ pf->hw.phy.get_link_info = true; old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP); new_link = i40e_get_link_status(&pf->hw); + old_link_speed = pf->hw.phy.link_info_old.link_speed; + new_link_speed = pf->hw.phy.link_info.link_speed; if (new_link == old_link && + new_link_speed == old_link_speed && (test_bit(__I40E_DOWN, &vsi->state) || new_link == netif_carrier_ok(vsi->netdev))) return; -- cgit v1.2.1 From ba252f1378f189040286f432f28eb8163567fa03 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Thu, 11 Dec 2014 07:06:34 +0000 Subject: i40e: limit sriov to partition 1 of NPAR configurations Make sure we only allow SR/IOV on the master PF of a port in multifunction mode. This should be the case anyway based on the num_vfs configured in the NVM, but this will help make sure there's no question. If we're not in multifunction mode the partition_id will always be 1. Change-ID: I8b2592366fe6782f15301bde2ebd1d4da240109d Signed-off-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 80430b0cfeb7..f3b036d19b6b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7319,7 +7319,7 @@ static int i40e_sw_init(struct i40e_pf *pf) #endif /* I40E_FCOE */ #ifdef CONFIG_PCI_IOV - if (pf->hw.func_caps.num_vfs) { + if (pf->hw.func_caps.num_vfs && pf->hw.partition_id == 1) { pf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF; pf->flags |= I40E_FLAG_SRIOV_ENABLED; pf->num_req_vfs = min_t(int, -- cgit v1.2.1 From e54bfe9d7e5823f8b460e8de371f695ada41a0c1 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Tue, 13 Jan 2015 10:30:31 +0800 Subject: net/fsl: fix a bug in xgmac_mdio There is a bug in xgmac_mdio_read when clear the bit MDIO_STAT_ENC, which '&' is missed in 'mdio_stat &= ~MDIO_STAT_ENC'. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/xgmac_mdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index e0fc3d1115ea..a492e5006756 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -156,7 +156,7 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) mdio_stat |= MDIO_STAT_ENC; } else { dev_addr = regnum & 0x1f; - mdio_stat = ~MDIO_STAT_ENC; + mdio_stat &= ~MDIO_STAT_ENC; } out_be32(®s->mdio_stat, mdio_stat); -- cgit v1.2.1 From 49ff2d3f040c133a9caeb862c9c2cd58a561d2c3 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Tue, 13 Jan 2015 10:30:59 +0800 Subject: net/fsl: replace (1 << x) with BIT(x) for bit definitions in xgmac_mdio Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/xgmac_mdio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index a492e5006756..3a76e235fff6 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -34,17 +34,17 @@ struct tgec_mdio_controller { #define MDIO_STAT_ENC BIT(6) #define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8) -#define MDIO_STAT_BSY (1 << 0) -#define MDIO_STAT_RD_ER (1 << 1) +#define MDIO_STAT_BSY BIT(0) +#define MDIO_STAT_RD_ER BIT(1) #define MDIO_CTL_DEV_ADDR(x) (x & 0x1f) #define MDIO_CTL_PORT_ADDR(x) ((x & 0x1f) << 5) -#define MDIO_CTL_PRE_DIS (1 << 10) -#define MDIO_CTL_SCAN_EN (1 << 11) -#define MDIO_CTL_POST_INC (1 << 14) -#define MDIO_CTL_READ (1 << 15) +#define MDIO_CTL_PRE_DIS BIT(10) +#define MDIO_CTL_SCAN_EN BIT(11) +#define MDIO_CTL_POST_INC BIT(14) +#define MDIO_CTL_READ BIT(15) #define MDIO_DATA(x) (x & 0xffff) -#define MDIO_DATA_BSY (1 << 31) +#define MDIO_DATA_BSY BIT(31) /* * Wait until the MDIO bus is free -- cgit v1.2.1 From 06640310b43c9b3185629e2b919c0800486b0d8e Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 13 Jan 2015 15:19:25 +0530 Subject: cxgb4: Ripping out old hard-wired initialization code in driver Removing old hard-wired initialization code in the driver, which is no longer used. Also deprecating few module parameters. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 480 +++--------------------- drivers/net/ethernet/chelsio/cxgb4/sge.c | 98 +---- 2 files changed, 58 insertions(+), 520 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 23ae0b7a9019..082a596a4264 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -79,99 +79,6 @@ #define DRV_VERSION "2.0.0-ko" #define DRV_DESC "Chelsio T4/T5 Network Driver" -/* - * Max interrupt hold-off timer value in us. Queues fall back to this value - * under extreme memory pressure so it's largish to give the system time to - * recover. - */ -#define MAX_SGE_TIMERVAL 200U - -enum { - /* - * Physical Function provisioning constants. - */ - PFRES_NVI = 4, /* # of Virtual Interfaces */ - PFRES_NETHCTRL = 128, /* # of EQs used for ETH or CTRL Qs */ - PFRES_NIQFLINT = 128, /* # of ingress Qs/w Free List(s)/intr - */ - PFRES_NEQ = 256, /* # of egress queues */ - PFRES_NIQ = 0, /* # of ingress queues */ - PFRES_TC = 0, /* PCI-E traffic class */ - PFRES_NEXACTF = 128, /* # of exact MPS filters */ - - PFRES_R_CAPS = FW_CMD_CAP_PF, - PFRES_WX_CAPS = FW_CMD_CAP_PF, - -#ifdef CONFIG_PCI_IOV - /* - * Virtual Function provisioning constants. We need two extra Ingress - * Queues with Interrupt capability to serve as the VF's Firmware - * Event Queue and Forwarded Interrupt Queue (when using MSI mode) -- - * neither will have Free Lists associated with them). For each - * Ethernet/Control Egress Queue and for each Free List, we need an - * Egress Context. - */ - VFRES_NPORTS = 1, /* # of "ports" per VF */ - VFRES_NQSETS = 2, /* # of "Queue Sets" per VF */ - - VFRES_NVI = VFRES_NPORTS, /* # of Virtual Interfaces */ - VFRES_NETHCTRL = VFRES_NQSETS, /* # of EQs used for ETH or CTRL Qs */ - VFRES_NIQFLINT = VFRES_NQSETS+2,/* # of ingress Qs/w Free List(s)/intr */ - VFRES_NEQ = VFRES_NQSETS*2, /* # of egress queues */ - VFRES_NIQ = 0, /* # of non-fl/int ingress queues */ - VFRES_TC = 0, /* PCI-E traffic class */ - VFRES_NEXACTF = 16, /* # of exact MPS filters */ - - VFRES_R_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF|FW_CMD_CAP_PORT, - VFRES_WX_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF, -#endif -}; - -/* - * Provide a Port Access Rights Mask for the specified PF/VF. This is very - * static and likely not to be useful in the long run. We really need to - * implement some form of persistent configuration which the firmware - * controls. - */ -static unsigned int pfvfres_pmask(struct adapter *adapter, - unsigned int pf, unsigned int vf) -{ - unsigned int portn, portvec; - - /* - * Give PF's access to all of the ports. - */ - if (vf == 0) - return FW_PFVF_CMD_PMASK_M; - - /* - * For VFs, we'll assign them access to the ports based purely on the - * PF. We assign active ports in order, wrapping around if there are - * fewer active ports than PFs: e.g. active port[pf % nports]. - * Unfortunately the adapter's port_info structs haven't been - * initialized yet so we have to compute this. - */ - if (adapter->params.nports == 0) - return 0; - - portn = pf % adapter->params.nports; - portvec = adapter->params.portvec; - for (;;) { - /* - * Isolate the lowest set bit in the port vector. If we're at - * the port number that we want, return that as the pmask. - * otherwise mask that bit out of the port vector and - * decrement our port number ... - */ - unsigned int pmask = portvec ^ (portvec & (portvec-1)); - if (portn == 0) - return pmask; - portn--; - portvec &= ~pmask; - } - /*NOTREACHED*/ -} - enum { MAX_TXQ_ENTRIES = 16384, MAX_CTRL_TXQ_ENTRIES = 1024, @@ -264,7 +171,8 @@ MODULE_PARM_DESC(force_init, "Forcibly become Master PF and initialize adapter") static uint force_old_init; module_param(force_old_init, uint, 0644); -MODULE_PARM_DESC(force_old_init, "Force old initialization sequence"); +MODULE_PARM_DESC(force_old_init, "Force old initialization sequence, deprecated" + " parameter"); static int dflt_msg_enable = DFLT_MSG_ENABLE; @@ -293,13 +201,14 @@ static unsigned int intr_holdoff[SGE_NTIMERS - 1] = { 5, 10, 20, 50, 100 }; module_param_array(intr_holdoff, uint, NULL, 0644); MODULE_PARM_DESC(intr_holdoff, "values for queue interrupt hold-off timers " - "0..4 in microseconds"); + "0..4 in microseconds, deprecated parameter"); static unsigned int intr_cnt[SGE_NCOUNTERS - 1] = { 4, 8, 16 }; module_param_array(intr_cnt, uint, NULL, 0644); MODULE_PARM_DESC(intr_cnt, - "thresholds 1..3 for queue interrupt packet counters"); + "thresholds 1..3 for queue interrupt packet counters, " + "deprecated parameter"); /* * Normally we tell the chip to deliver Ingress Packets into our DMA buffers @@ -319,7 +228,8 @@ static bool vf_acls; #ifdef CONFIG_PCI_IOV module_param(vf_acls, bool, 0644); -MODULE_PARM_DESC(vf_acls, "if set enable virtualization L2 ACL enforcement"); +MODULE_PARM_DESC(vf_acls, "if set enable virtualization L2 ACL enforcement, " + "deprecated parameter"); /* Configure the number of PCI-E Virtual Function which are to be instantiated * on SR-IOV Capable Physical Functions. @@ -341,32 +251,11 @@ module_param(select_queue, int, 0644); MODULE_PARM_DESC(select_queue, "Select between kernel provided method of selecting or driver method of selecting TX queue. Default is kernel method."); -/* - * The filter TCAM has a fixed portion and a variable portion. The fixed - * portion can match on source/destination IP IPv4/IPv6 addresses and TCP/UDP - * ports. The variable portion is 36 bits which can include things like Exact - * Match MAC Index (9 bits), Ether Type (16 bits), IP Protocol (8 bits), - * [Inner] VLAN Tag (17 bits), etc. which, if all were somehow selected, would - * far exceed the 36-bit budget for this "compressed" header portion of the - * filter. Thus, we have a scarce resource which must be carefully managed. - * - * By default we set this up to mostly match the set of filter matching - * capabilities of T3 but with accommodations for some of T4's more - * interesting features: - * - * { IP Fragment (1), MPS Match Type (3), IP Protocol (8), - * [Inner] VLAN (17), Port (3), FCoE (1) } - */ -enum { - TP_VLAN_PRI_MAP_DEFAULT = HW_TPL_FR_MT_PR_IV_P_FC, - TP_VLAN_PRI_MAP_FIRST = FCOE_S, - TP_VLAN_PRI_MAP_LAST = FRAGMENTATION_S, -}; - -static unsigned int tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT; +static unsigned int tp_vlan_pri_map = HW_TPL_FR_MT_PR_IV_P_FC; module_param(tp_vlan_pri_map, uint, 0644); -MODULE_PARM_DESC(tp_vlan_pri_map, "global compressed filter configuration"); +MODULE_PARM_DESC(tp_vlan_pri_map, "global compressed filter configuration, " + "deprecated parameter"); static struct dentry *cxgb4_debugfs_root; @@ -5225,12 +5114,9 @@ static int adap_init0_config(struct adapter *adapter, int reset) if (ret < 0) goto bye; - /* - * Return successfully and note that we're operating with parameters - * not supplied by the driver, rather than from hard-wired - * initialization constants burried in the driver. + /* Emit Firmware Configuration File information and return + * successfully. */ - adapter->flags |= USING_SOFT_PARAMS; dev_info(adapter->pdev_dev, "Successfully configured using Firmware "\ "Configuration File \"%s\", version %#x, computed checksum %#x\n", config_name, finiver, cfcsum); @@ -5248,248 +5134,6 @@ bye: return ret; } -/* - * Attempt to initialize the adapter via hard-coded, driver supplied - * parameters ... - */ -static int adap_init0_no_config(struct adapter *adapter, int reset) -{ - struct sge *s = &adapter->sge; - struct fw_caps_config_cmd caps_cmd; - u32 v; - int i, ret; - - /* - * Reset device if necessary - */ - if (reset) { - ret = t4_fw_reset(adapter, adapter->mbox, - PIORSTMODE_F | PIORST_F); - if (ret < 0) - goto bye; - } - - /* - * Get device capabilities and select which we'll be using. - */ - memset(&caps_cmd, 0, sizeof(caps_cmd)); - caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | - FW_CMD_REQUEST_F | FW_CMD_READ_F); - caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd)); - ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd), - &caps_cmd); - if (ret < 0) - goto bye; - - if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) { - if (!vf_acls) - caps_cmd.niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM); - else - caps_cmd.niccaps = htons(FW_CAPS_CONFIG_NIC_VM); - } else if (vf_acls) { - dev_err(adapter->pdev_dev, "virtualization ACLs not supported"); - goto bye; - } - caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | - FW_CMD_REQUEST_F | FW_CMD_WRITE_F); - ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd), - NULL); - if (ret < 0) - goto bye; - - /* - * Tweak configuration based on system architecture, module - * parameters, etc. - */ - ret = adap_init0_tweaks(adapter); - if (ret < 0) - goto bye; - - /* - * Select RSS Global Mode we want to use. We use "Basic Virtual" - * mode which maps each Virtual Interface to its own section of - * the RSS Table and we turn on all map and hash enables ... - */ - adapter->flags |= RSS_TNLALLLOOKUP; - ret = t4_config_glbl_rss(adapter, adapter->mbox, - FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL, - FW_RSS_GLB_CONFIG_CMD_TNLMAPEN_F | - FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ_F | - ((adapter->flags & RSS_TNLALLLOOKUP) ? - FW_RSS_GLB_CONFIG_CMD_TNLALLLKP_F : 0)); - if (ret < 0) - goto bye; - - /* - * Set up our own fundamental resource provisioning ... - */ - ret = t4_cfg_pfvf(adapter, adapter->mbox, adapter->fn, 0, - PFRES_NEQ, PFRES_NETHCTRL, - PFRES_NIQFLINT, PFRES_NIQ, - PFRES_TC, PFRES_NVI, - FW_PFVF_CMD_CMASK_M, - pfvfres_pmask(adapter, adapter->fn, 0), - PFRES_NEXACTF, - PFRES_R_CAPS, PFRES_WX_CAPS); - if (ret < 0) - goto bye; - - /* - * Perform low level SGE initialization. We need to do this before we - * send the firmware the INITIALIZE command because that will cause - * any other PF Drivers which are waiting for the Master - * Initialization to proceed forward. - */ - for (i = 0; i < SGE_NTIMERS - 1; i++) - s->timer_val[i] = min(intr_holdoff[i], MAX_SGE_TIMERVAL); - s->timer_val[SGE_NTIMERS - 1] = MAX_SGE_TIMERVAL; - s->counter_val[0] = 1; - for (i = 1; i < SGE_NCOUNTERS; i++) - s->counter_val[i] = min(intr_cnt[i - 1], THRESHOLD_0_M); - t4_sge_init(adapter); - -#ifdef CONFIG_PCI_IOV - /* - * Provision resource limits for Virtual Functions. We currently - * grant them all the same static resource limits except for the Port - * Access Rights Mask which we're assigning based on the PF. All of - * the static provisioning stuff for both the PF and VF really needs - * to be managed in a persistent manner for each device which the - * firmware controls. - */ - { - int pf, vf; - - for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) { - if (num_vf[pf] <= 0) - continue; - - /* VF numbering starts at 1! */ - for (vf = 1; vf <= num_vf[pf]; vf++) { - ret = t4_cfg_pfvf(adapter, adapter->mbox, - pf, vf, - VFRES_NEQ, VFRES_NETHCTRL, - VFRES_NIQFLINT, VFRES_NIQ, - VFRES_TC, VFRES_NVI, - FW_PFVF_CMD_CMASK_M, - pfvfres_pmask( - adapter, pf, vf), - VFRES_NEXACTF, - VFRES_R_CAPS, VFRES_WX_CAPS); - if (ret < 0) - dev_warn(adapter->pdev_dev, - "failed to "\ - "provision pf/vf=%d/%d; " - "err=%d\n", pf, vf, ret); - } - } - } -#endif - - /* - * Set up the default filter mode. Later we'll want to implement this - * via a firmware command, etc. ... This needs to be done before the - * firmare initialization command ... If the selected set of fields - * isn't equal to the default value, we'll need to make sure that the - * field selections will fit in the 36-bit budget. - */ - if (tp_vlan_pri_map != TP_VLAN_PRI_MAP_DEFAULT) { - int j, bits = 0; - - for (j = TP_VLAN_PRI_MAP_FIRST; j <= TP_VLAN_PRI_MAP_LAST; j++) - switch (tp_vlan_pri_map & (1 << j)) { - case 0: - /* compressed filter field not enabled */ - break; - case FCOE_F: - bits += 1; - break; - case PORT_F: - bits += 3; - break; - case VNIC_F: - bits += 17; - break; - case VLAN_F: - bits += 17; - break; - case TOS_F: - bits += 8; - break; - case PROTOCOL_F: - bits += 8; - break; - case ETHERTYPE_F: - bits += 16; - break; - case MACMATCH_F: - bits += 9; - break; - case MPSHITTYPE_F: - bits += 3; - break; - case FRAGMENTATION_F: - bits += 1; - break; - } - - if (bits > 36) { - dev_err(adapter->pdev_dev, - "tp_vlan_pri_map=%#x needs %d bits > 36;"\ - " using %#x\n", tp_vlan_pri_map, bits, - TP_VLAN_PRI_MAP_DEFAULT); - tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT; - } - } - v = tp_vlan_pri_map; - t4_write_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, - &v, 1, TP_VLAN_PRI_MAP_A); - - /* - * We need Five Tuple Lookup mode to be set in TP_GLOBAL_CONFIG order - * to support any of the compressed filter fields above. Newer - * versions of the firmware do this automatically but it doesn't hurt - * to set it here. Meanwhile, we do _not_ need to set Lookup Every - * Packet in TP_INGRESS_CONFIG to support matching non-TCP packets - * since the firmware automatically turns this on and off when we have - * a non-zero number of filters active (since it does have a - * performance impact). - */ - if (tp_vlan_pri_map) - t4_set_reg_field(adapter, TP_GLOBAL_CONFIG_A, - FIVETUPLELOOKUP_V(FIVETUPLELOOKUP_M), - FIVETUPLELOOKUP_V(FIVETUPLELOOKUP_M)); - - /* - * Tweak some settings. - */ - t4_write_reg(adapter, TP_SHIFT_CNT_A, SYNSHIFTMAX_V(6) | - RXTSHIFTMAXR1_V(4) | RXTSHIFTMAXR2_V(15) | - PERSHIFTBACKOFFMAX_V(8) | PERSHIFTMAX_V(8) | - KEEPALIVEMAXR1_V(4) | KEEPALIVEMAXR2_V(9)); - - /* - * Get basic stuff going by issuing the Firmware Initialize command. - * Note that this _must_ be after all PFVF commands ... - */ - ret = t4_fw_initialize(adapter, adapter->mbox); - if (ret < 0) - goto bye; - - /* - * Return successfully! - */ - dev_info(adapter->pdev_dev, "Successfully configured using built-in "\ - "driver parameters\n"); - return 0; - - /* - * Something bad happened. Return the error ... - */ -bye: - return ret; -} - static struct fw_info fw_info_array[] = { { .chip = CHELSIO_T4, @@ -5662,88 +5306,58 @@ static int adap_init0(struct adapter *adap) adap->params.nports = hweight32(port_vec); adap->params.portvec = port_vec; - /* - * If the firmware is initialized already (and we're not forcing a - * master initialization), note that we're living with existing - * adapter parameters. Otherwise, it's time to try initializing the - * adapter ... + /* If the firmware is initialized already, emit a simply note to that + * effect. Otherwise, it's time to try initializing the adapter. */ if (state == DEV_STATE_INIT) { dev_info(adap->pdev_dev, "Coming up as %s: "\ "Adapter already initialized\n", adap->flags & MASTER_PF ? "MASTER" : "SLAVE"); - adap->flags |= USING_SOFT_PARAMS; } else { dev_info(adap->pdev_dev, "Coming up as MASTER: "\ "Initializing adapter\n"); - /* - * If the firmware doesn't support Configuration - * Files warn user and exit, + + /* Find out whether we're dealing with a version of the + * firmware which has configuration file support. */ - if (ret < 0) - dev_warn(adap->pdev_dev, "Firmware doesn't support " - "configuration file.\n"); - if (force_old_init) - ret = adap_init0_no_config(adap, reset); - else { - /* - * Find out whether we're dealing with a version of - * the firmware which has configuration file support. - */ - params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | - FW_PARAMS_PARAM_X_V( - FW_PARAMS_PARAM_DEV_CF)); - ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1, - params, val); - - /* - * If the firmware doesn't support Configuration - * Files, use the old Driver-based, hard-wired - * initialization. Otherwise, try using the - * Configuration File support and fall back to the - * Driver-based initialization if there's no - * Configuration File found. - */ - if (ret < 0) - ret = adap_init0_no_config(adap, reset); - else { - /* - * The firmware provides us with a memory - * buffer where we can load a Configuration - * File from the host if we want to override - * the Configuration File in flash. - */ + params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF)); + ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1, + params, val); - ret = adap_init0_config(adap, reset); - if (ret == -ENOENT) { - dev_info(adap->pdev_dev, - "No Configuration File present " - "on adapter. Using hard-wired " - "configuration parameters.\n"); - ret = adap_init0_no_config(adap, reset); - } - } + /* If the firmware doesn't support Configuration Files, + * return an error. + */ + if (ret < 0) { + dev_err(adap->pdev_dev, "firmware doesn't support " + "Firmware Configuration Files\n"); + goto bye; + } + + /* The firmware provides us with a memory buffer where we can + * load a Configuration File from the host if we want to + * override the Configuration File in flash. + */ + ret = adap_init0_config(adap, reset); + if (ret == -ENOENT) { + dev_err(adap->pdev_dev, "no Configuration File " + "present on adapter.\n"); + goto bye; } if (ret < 0) { - dev_err(adap->pdev_dev, - "could not initialize adapter, error %d\n", - -ret); + dev_err(adap->pdev_dev, "could not initialize " + "adapter, error %d\n", -ret); goto bye; } } - /* - * If we're living with non-hard-coded parameters (either from a - * Firmware Configuration File or values programmed by a different PF - * Driver), give the SGE code a chance to pull in anything that it - * needs ... Note that this must be called after we retrieve our VPD - * parameters in order to know how to convert core ticks to seconds. + /* Give the SGE code a chance to pull in anything that it needs ... + * Note that this must be called after we retrieve our VPD parameters + * in order to know how to convert core ticks to seconds, etc. */ - if (adap->flags & USING_SOFT_PARAMS) { - ret = t4_sge_init(adap); - if (ret < 0) - goto bye; - } + ret = t4_sge_init(adap); + if (ret < 0) + goto bye; if (is_bypass_device(adap->pdev->device)) adap->params.bypass = 1; diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index a79fa6a0f5c5..ca42e2e9dec9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2742,24 +2742,11 @@ void t4_sge_stop(struct adapter *adap) } /** - * t4_sge_init - initialize SGE + * t4_sge_init_soft - grab core SGE values needed by SGE code * @adap: the adapter * - * Performs SGE initialization needed every time after a chip reset. - * We do not initialize any of the queues here, instead the driver - * top-level must request them individually. - * - * Called in two different modes: - * - * 1. Perform actual hardware initialization and record hard-coded - * parameters which were used. This gets used when we're the - * Master PF and the Firmware Configuration File support didn't - * work for some reason. - * - * 2. We're not the Master PF or initialization was performed with - * a Firmware Configuration File. In this case we need to grab - * any of the SGE operating parameters that we need to have in - * order to do our job and make sure we can live with them ... + * We need to grab the SGE operating parameters that we need to have + * in order to do our job and make sure we can live with them. */ static int t4_sge_init_soft(struct adapter *adap) @@ -2852,73 +2839,13 @@ static int t4_sge_init_soft(struct adapter *adap) return 0; } -static int t4_sge_init_hard(struct adapter *adap) -{ - struct sge *s = &adap->sge; - - /* - * Set up our basic SGE mode to deliver CPL messages to our Ingress - * Queue and Packet Date to the Free List. - */ - t4_set_reg_field(adap, SGE_CONTROL_A, RXPKTCPLMODE_F, RXPKTCPLMODE_F); - - /* - * Set up to drop DOORBELL writes when the DOORBELL FIFO overflows - * and generate an interrupt when this occurs so we can recover. - */ - if (is_t4(adap->params.chip)) { - t4_set_reg_field(adap, SGE_DBFIFO_STATUS_A, - HP_INT_THRESH_V(HP_INT_THRESH_M) | - LP_INT_THRESH_V(LP_INT_THRESH_M), - HP_INT_THRESH_V(dbfifo_int_thresh) | - LP_INT_THRESH_V(dbfifo_int_thresh)); - } else { - t4_set_reg_field(adap, SGE_DBFIFO_STATUS_A, - LP_INT_THRESH_T5_V(LP_INT_THRESH_T5_M), - LP_INT_THRESH_T5_V(dbfifo_int_thresh)); - t4_set_reg_field(adap, SGE_DBFIFO_STATUS2_A, - HP_INT_THRESH_T5_V(HP_INT_THRESH_T5_M), - HP_INT_THRESH_T5_V(dbfifo_int_thresh)); - } - t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, ENABLE_DROP_F, - ENABLE_DROP_F); - - /* - * SGE_FL_BUFFER_SIZE0 (RX_SMALL_PG_BUF) is set up by - * t4_fixup_host_params(). - */ - s->fl_pg_order = FL_PG_ORDER; - if (s->fl_pg_order) - t4_write_reg(adap, - SGE_FL_BUFFER_SIZE0_A+RX_LARGE_PG_BUF*sizeof(u32), - PAGE_SIZE << FL_PG_ORDER); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE0_A+RX_SMALL_MTU_BUF*sizeof(u32), - FL_MTU_SMALL_BUFSIZE(adap)); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE0_A+RX_LARGE_MTU_BUF*sizeof(u32), - FL_MTU_LARGE_BUFSIZE(adap)); - - /* - * Note that the SGE Ingress Packet Count Interrupt Threshold and - * Timer Holdoff values must be supplied by our caller. - */ - t4_write_reg(adap, SGE_INGRESS_RX_THRESHOLD_A, - THRESHOLD_0_V(s->counter_val[0]) | - THRESHOLD_1_V(s->counter_val[1]) | - THRESHOLD_2_V(s->counter_val[2]) | - THRESHOLD_3_V(s->counter_val[3])); - t4_write_reg(adap, SGE_TIMER_VALUE_0_AND_1_A, - TIMERVALUE0_V(us_to_core_ticks(adap, s->timer_val[0])) | - TIMERVALUE1_V(us_to_core_ticks(adap, s->timer_val[1]))); - t4_write_reg(adap, SGE_TIMER_VALUE_2_AND_3_A, - TIMERVALUE2_V(us_to_core_ticks(adap, s->timer_val[2])) | - TIMERVALUE3_V(us_to_core_ticks(adap, s->timer_val[3]))); - t4_write_reg(adap, SGE_TIMER_VALUE_4_AND_5_A, - TIMERVALUE4_V(us_to_core_ticks(adap, s->timer_val[4])) | - TIMERVALUE5_V(us_to_core_ticks(adap, s->timer_val[5]))); - - return 0; -} - +/** + * t4_sge_init - initialize SGE + * @adap: the adapter + * + * Perform low-level SGE code initialization needed every time after a + * chip reset. + */ int t4_sge_init(struct adapter *adap) { struct sge *s = &adap->sge; @@ -2959,10 +2886,7 @@ int t4_sge_init(struct adapter *adap) s->fl_align = max(ingpadboundary, ingpackboundary); } - if (adap->flags & USING_SOFT_PARAMS) - ret = t4_sge_init_soft(adap); - else - ret = t4_sge_init_hard(adap); + ret = t4_sge_init_soft(adap); if (ret < 0) return ret; -- cgit v1.2.1 From adedf37b5908de05256913875f1041e838994b49 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Jan 2015 15:23:52 +0100 Subject: rocker: fix harmless warning on 32-bit machines The rocker driver tries to assign a pointer to a 64-bit integer and then back to a pointer. This is safe on all architectures, but causes a compiler warning when pointers are shorter than 64-bit: rocker/rocker.c: In function 'rocker_desc_cookie_ptr_get': rocker/rocker.c:809:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] return (void *) desc_info->desc->cookie; ^ This adds another cast to uintptr_t to tell the compiler that it's safe. Signed-off-by: Arnd Bergmann Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 2f398fa4b9e6..cad8cf962cdf 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -806,13 +806,13 @@ static bool rocker_desc_gen(struct rocker_desc_info *desc_info) static void *rocker_desc_cookie_ptr_get(struct rocker_desc_info *desc_info) { - return (void *) desc_info->desc->cookie; + return (void *)(uintptr_t)desc_info->desc->cookie; } static void rocker_desc_cookie_ptr_set(struct rocker_desc_info *desc_info, void *ptr) { - desc_info->desc->cookie = (long) ptr; + desc_info->desc->cookie = (uintptr_t) ptr; } static struct rocker_desc_info * -- cgit v1.2.1 From 065bd8c28ba37d04c9a5b732173c1508954b1f58 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Jan 2015 17:08:06 +0100 Subject: mlx5: avoid build warnings on 32-bit The mlx5 driver passes a string pointer in through a 'u64' variable, which on 32-bit machines causes a build warning: drivers/net/ethernet/mellanox/mlx5/core/debugfs.c: In function 'qp_read_field': drivers/net/ethernet/mellanox/mlx5/core/debugfs.c:303:11: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] The code is in fact safe, so we can shut up the warning by adding extra type casts. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c index 10e1f1a18255..4878025e231c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c @@ -300,11 +300,11 @@ static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, param = qp->pid; break; case QP_STATE: - param = (u64)mlx5_qp_state_str(be32_to_cpu(ctx->flags) >> 28); + param = (unsigned long)mlx5_qp_state_str(be32_to_cpu(ctx->flags) >> 28); *is_str = 1; break; case QP_XPORT: - param = (u64)mlx5_qp_type_str((be32_to_cpu(ctx->flags) >> 16) & 0xff); + param = (unsigned long)mlx5_qp_type_str((be32_to_cpu(ctx->flags) >> 16) & 0xff); *is_str = 1; break; case QP_MTU: @@ -464,7 +464,7 @@ static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count, if (is_str) - ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)field); + ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field); else ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field); -- cgit v1.2.1 From 86cfeab6b510a2fe94683bf71f9b96b686e2e0ce Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Tue, 13 Jan 2015 12:45:05 -0500 Subject: sunvnet: fix rx packet length check to allow for TSO This patch fixes the rx packet length check in the sunvnet driver to allow for a TSO max packet length greater than the LDC channel negotiated MTU. These are negotiated separately and there is no requirement that port->tsolen be less than port->rmtu, but if it isn't, it'll drop packets with rx length errors. Signed-off-by: David L Stevens Acked-by: Sowmini Varadhan Signed-off-by: David S. Miller --- drivers/net/ethernet/sun/sunvnet.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index d2835bf7b4fb..b5a1d3d7b0bf 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -351,10 +351,15 @@ static int vnet_rx_one(struct vnet_port *port, struct vio_net_desc *desc) unsigned int len = desc->size; unsigned int copy_len; struct sk_buff *skb; + int maxlen; int err; err = -EMSGSIZE; - if (unlikely(len < ETH_ZLEN || len > port->rmtu)) { + if (port->tso && port->tsolen > port->rmtu) + maxlen = port->tsolen; + else + maxlen = port->rmtu; + if (unlikely(len < ETH_ZLEN || len > maxlen)) { dev->stats.rx_length_errors++; goto out_dropped; } -- cgit v1.2.1 From df8a39defad46b83694ea6dd868d332976d62cc0 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 13 Jan 2015 17:13:44 +0100 Subject: net: rename vlan_tx_* helpers since "tx" is misleading there The same macros are used for rx as well. So rename it. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/3com/typhoon.c | 4 ++-- drivers/net/ethernet/alteon/acenic.c | 8 ++++---- drivers/net/ethernet/amd/amd8111e.c | 4 ++-- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 8 ++++---- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 4 ++-- drivers/net/ethernet/atheros/atl1e/atl1e_main.c | 4 ++-- drivers/net/ethernet/atheros/atlx/atl1.c | 4 ++-- drivers/net/ethernet/atheros/atlx/atl2.c | 4 ++-- drivers/net/ethernet/broadcom/bnx2.c | 4 ++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 4 ++-- drivers/net/ethernet/broadcom/tg3.c | 4 ++-- drivers/net/ethernet/brocade/bna/bnad.c | 4 ++-- drivers/net/ethernet/chelsio/cxgb/sge.c | 4 ++-- drivers/net/ethernet/chelsio/cxgb3/sge.c | 6 +++--- drivers/net/ethernet/chelsio/cxgb4/sge.c | 4 ++-- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 4 ++-- drivers/net/ethernet/cisco/enic/enic_main.c | 4 ++-- drivers/net/ethernet/emulex/benet/be_main.c | 12 ++++++------ drivers/net/ethernet/freescale/gianfar.c | 4 ++-- drivers/net/ethernet/ibm/ehea/ehea_main.c | 4 ++-- drivers/net/ethernet/intel/e1000/e1000_main.c | 5 +++-- drivers/net/ethernet/intel/e1000e/netdev.c | 9 +++++---- drivers/net/ethernet/intel/fm10k/fm10k_main.c | 4 ++-- drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 4 ++-- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 4 ++-- drivers/net/ethernet/intel/igb/igb_main.c | 4 ++-- drivers/net/ethernet/intel/igbvf/netdev.c | 5 +++-- drivers/net/ethernet/intel/ixgb/ixgb_main.c | 4 ++-- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 ++-- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 4 ++-- drivers/net/ethernet/jme.c | 4 ++-- drivers/net/ethernet/marvell/sky2.c | 6 +++--- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 12 ++++++------ drivers/net/ethernet/natsemi/ns83820.c | 4 ++-- drivers/net/ethernet/neterion/s2io.c | 4 ++-- drivers/net/ethernet/neterion/vxge/vxge-main.c | 4 ++-- drivers/net/ethernet/nvidia/forcedeth.c | 4 ++-- drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | 4 ++-- drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 8 ++++---- drivers/net/ethernet/qlogic/qlge/qlge_main.c | 6 +++--- drivers/net/ethernet/realtek/8139cp.c | 4 ++-- drivers/net/ethernet/realtek/r8169.c | 4 ++-- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 2 +- drivers/net/ethernet/tehuti/tehuti.c | 4 ++-- drivers/net/ethernet/via/via-rhine.c | 6 +++--- drivers/net/ethernet/via/via-velocity.c | 4 ++-- drivers/net/macvtap.c | 6 +++--- drivers/net/tun.c | 4 ++-- drivers/net/usb/r8152.c | 4 ++-- drivers/net/vmxnet3/vmxnet3_drv.c | 4 ++-- drivers/net/vxlan.c | 4 ++-- 52 files changed, 126 insertions(+), 123 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c index dede43f4ce09..8f8418d2ac4a 100644 --- a/drivers/net/ethernet/3com/typhoon.c +++ b/drivers/net/ethernet/3com/typhoon.c @@ -769,11 +769,11 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) first_txd->processFlags |= TYPHOON_TX_PF_IP_CHKSUM; } - if(vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { first_txd->processFlags |= TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY; first_txd->processFlags |= - cpu_to_le32(htons(vlan_tx_tag_get(skb)) << + cpu_to_le32(htons(skb_vlan_tag_get(skb)) << TYPHOON_TX_PF_VLAN_TAG_SHIFT); } diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c index b68074803de3..b90a26b13fdf 100644 --- a/drivers/net/ethernet/alteon/acenic.c +++ b/drivers/net/ethernet/alteon/acenic.c @@ -2429,9 +2429,9 @@ restart: flagsize = (skb->len << 16) | (BD_FLG_END); if (skb->ip_summed == CHECKSUM_PARTIAL) flagsize |= BD_FLG_TCP_UDP_SUM; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { flagsize |= BD_FLG_VLAN_TAG; - vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = skb_vlan_tag_get(skb); } desc = ap->tx_ring + idx; idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap); @@ -2450,9 +2450,9 @@ restart: flagsize = (skb_headlen(skb) << 16); if (skb->ip_summed == CHECKSUM_PARTIAL) flagsize |= BD_FLG_TCP_UDP_SUM; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { flagsize |= BD_FLG_VLAN_TAG; - vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = skb_vlan_tag_get(skb); } ace_load_tx_bd(ap, ap->tx_ring + idx, mapping, flagsize, vlan_tag); diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index 841e6558db68..4c2ae2221780 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -1299,11 +1299,11 @@ static netdev_tx_t amd8111e_start_xmit(struct sk_buff *skb, lp->tx_ring[tx_index].tx_flags = 0; #if AMD8111E_VLAN_TAG_USED - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { lp->tx_ring[tx_index].tag_ctrl_cmd |= cpu_to_le16(TCC_VLAN_INSERT); lp->tx_ring[tx_index].tag_ctrl_info = - cpu_to_le16(vlan_tx_tag_get(skb)); + cpu_to_le16(skb_vlan_tag_get(skb)); } #endif diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 7bb5f07dbeef..2ba1dd22ad64 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1165,8 +1165,8 @@ static void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata, static void xgbe_prep_vlan(struct sk_buff *skb, struct xgbe_packet_data *packet) { - if (vlan_tx_tag_present(skb)) - packet->vlan_ctag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) + packet->vlan_ctag = skb_vlan_tag_get(skb); } static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet) @@ -1247,9 +1247,9 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata, XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, CSUM_ENABLE, 1); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { /* VLAN requires an extra descriptor if tag is different */ - if (vlan_tx_tag_get(skb) != ring->tx.cur_vlan_ctag) + if (skb_vlan_tag_get(skb) != ring->tx.cur_vlan_ctag) /* We can share with the TSO context descriptor */ if (!context_desc) { context_desc = 1; diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index c9946c6c119e..587f63e87588 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -2235,8 +2235,8 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, return NETDEV_TX_OK; } - if (unlikely(vlan_tx_tag_present(skb))) { - u16 vlan = vlan_tx_tag_get(skb); + if (unlikely(skb_vlan_tag_present(skb))) { + u16 vlan = skb_vlan_tag_get(skb); __le16 tag; vlan = cpu_to_le16(vlan); diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c index c88abf5b6415..59a03a193e83 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c @@ -1892,8 +1892,8 @@ static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb, tpd = atl1e_get_tpd(adapter); - if (vlan_tx_tag_present(skb)) { - u16 vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + u16 vlan_tag = skb_vlan_tag_get(skb); u16 atl1e_vlan_tag; tpd->word3 |= 1 << TPD_INS_VL_TAG_SHIFT; diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c index 2c8f398aeda9..eca1d113fee1 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.c +++ b/drivers/net/ethernet/atheros/atlx/atl1.c @@ -2415,8 +2415,8 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb, (u16) atomic_read(&tpd_ring->next_to_use)); memset(ptpd, 0, sizeof(struct tx_packet_desc)); - if (vlan_tx_tag_present(skb)) { - vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + vlan_tag = skb_vlan_tag_get(skb); vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) | ((vlan_tag >> 9) & 0x8); ptpd->word3 |= 1 << TPD_INS_VL_TAG_SHIFT; diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index 482a7cabb0a1..46a535318c7a 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -887,8 +887,8 @@ static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb, offset = ((u32)(skb->len-copy_len + 3) & ~3); } #ifdef NETIF_F_HW_VLAN_CTAG_TX - if (vlan_tx_tag_present(skb)) { - u16 vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + u16 vlan_tag = skb_vlan_tag_get(skb); vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) | ((vlan_tag >> 9) & 0x8); diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 823d01c5684c..02bf0b86995b 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -6597,9 +6597,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { vlan_tag_flags |= - (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16)); + (TX_BD_FLAGS_VLAN_TAG | (skb_vlan_tag_get(skb) << 16)); } if ((mss = skb_shinfo(skb)->gso_size)) { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 1d1147c93d59..b51a18a09d4d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3865,9 +3865,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) "sending pkt %u @%p next_idx %u bd %u @%p\n", pkt_prod, tx_buf, txdata->tx_pkt_prod, bd_prod, tx_start_bd); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_start_bd->vlan_or_ethertype = - cpu_to_le16(vlan_tx_tag_get(skb)); + cpu_to_le16(skb_vlan_tag_get(skb)); tx_start_bd->bd_flags.as_bitfield |= (X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT); } else { diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 356bd5b022a5..4cf43bfbc955 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8002,9 +8002,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) !mss && skb->len > VLAN_ETH_FRAME_LEN) base_flags |= TXD_FLAG_JMB_PKT; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { base_flags |= TXD_FLAG_VLAN; - vlan = vlan_tx_tag_get(skb); + vlan = skb_vlan_tag_get(skb); } if ((unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) && diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 323721838cf9..7714d7790089 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -2824,8 +2824,8 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb, u32 gso_size; u16 vlan_tag = 0; - if (vlan_tx_tag_present(skb)) { - vlan_tag = (u16)vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + vlan_tag = (u16)skb_vlan_tag_get(skb); flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN); } if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) { diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c index babe2a915b00..526ea74e82d9 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb/sge.c @@ -1860,9 +1860,9 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) } cpl->iff = dev->if_port; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { cpl->vlan_valid = 1; - cpl->vlan = htons(vlan_tx_tag_get(skb)); + cpl->vlan = htons(skb_vlan_tag_get(skb)); st->vlan_insert++; } else cpl->vlan_valid = 0; diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c index 3dfcf600fcc6..d6aa602f168d 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -1148,8 +1148,8 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, cpl->len = htonl(skb->len); cntrl = V_TXPKT_INTF(pi->port_id); - if (vlan_tx_tag_present(skb)) - cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb)); + if (skb_vlan_tag_present(skb)) + cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(skb_vlan_tag_get(skb)); tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size); if (tso_info) { @@ -1282,7 +1282,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) qs->port_stats[SGE_PSTAT_TX_CSUM]++; if (skb_shinfo(skb)->gso_size) qs->port_stats[SGE_PSTAT_TSO]++; - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) qs->port_stats[SGE_PSTAT_VLANINS]++; /* diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index ca42e2e9dec9..619156112b21 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -1154,9 +1154,9 @@ out_free: dev_kfree_skb_any(skb); cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS; } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { q->vlan_ins++; - cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb)); + cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(skb_vlan_tag_get(skb)); } cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) | diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index 4424277a7e4d..0545f0de1c52 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -1326,9 +1326,9 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev) * If there's a VLAN tag present, add that to the list of things to * do in this Work Request. */ - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { txq->vlan_ins++; - cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb)); + cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(skb_vlan_tag_get(skb)); } /* diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 9a952df6606e..0535f6fbdc71 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -520,10 +520,10 @@ static inline void enic_queue_wq_skb(struct enic *enic, int loopback = 0; int err; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { /* VLAN tag from trunking driver */ vlan_tag_insert = 1; - vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = skb_vlan_tag_get(skb); } else if (enic->loop_enable) { vlan_tag = enic->loop_tag; loopback = 1; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 37a26b0b7e33..ed46610e5453 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -694,7 +694,7 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, u8 vlan_prio; u16 vlan_tag; - vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = skb_vlan_tag_get(skb); vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; /* If vlan priority provided by OS is NOT in available bmap */ if (!(adapter->vlan_prio_bmap & (1 << vlan_prio))) @@ -745,7 +745,7 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, SET_TX_WRB_HDR_BITS(udpcs, hdr, 1); } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { SET_TX_WRB_HDR_BITS(vlan, hdr, 1); vlan_tag = be_get_tx_vlan_tag(adapter, skb); SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag); @@ -864,7 +864,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, if (unlikely(!skb)) return skb; - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) vlan_tag = be_get_tx_vlan_tag(adapter, skb); if (qnq_async_evt_rcvd(adapter) && adapter->pvid) { @@ -923,7 +923,7 @@ static bool be_ipv6_exthdr_check(struct sk_buff *skb) static int be_vlan_tag_tx_chk(struct be_adapter *adapter, struct sk_buff *skb) { - return vlan_tx_tag_present(skb) || adapter->pvid || adapter->qnq_vid; + return skb_vlan_tag_present(skb) || adapter->pvid || adapter->qnq_vid; } static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb) @@ -946,7 +946,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? VLAN_ETH_HLEN : ETH_HLEN; if (skb->len <= 60 && - (lancer_chip(adapter) || vlan_tx_tag_present(skb)) && + (lancer_chip(adapter) || skb_vlan_tag_present(skb)) && is_ipv4_pkt(skb)) { ip = (struct iphdr *)ip_hdr(skb); pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len)); @@ -964,7 +964,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, * Manually insert VLAN in pkt. */ if (skb->ip_summed != CHECKSUM_PARTIAL && - vlan_tx_tag_present(skb)) { + skb_vlan_tag_present(skb)) { skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan); if (unlikely(!skb)) goto err; diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index e54b1e39f9b4..93ff846e96f1 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2170,7 +2170,7 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb, void inline gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb) { fcb->flags |= TXFCB_VLN; - fcb->vlctl = vlan_tx_tag_get(skb); + fcb->vlctl = skb_vlan_tag_get(skb); } static inline struct txbd8 *skip_txbd(struct txbd8 *bdp, int stride, @@ -2230,7 +2230,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) regs = tx_queue->grp->regs; do_csum = (CHECKSUM_PARTIAL == skb->ip_summed); - do_vlan = vlan_tx_tag_present(skb); + do_vlan = skb_vlan_tag_present(skb); do_tstamp = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en; diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index 566b17db135a..e8a1adb7a962 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -2064,9 +2064,9 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) memset(swqe, 0, SWQE_HEADER_SIZE); atomic_dec(&pr->swqe_avail); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { swqe->tx_control |= EHEA_SWQE_VLAN_INSERT; - swqe->vlan_tag = vlan_tx_tag_get(skb); + swqe->vlan_tag = skb_vlan_tag_get(skb); } pr->tx_packets++; diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 83140cbb5f01..9242982db3e0 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -3226,9 +3226,10 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, return NETDEV_TX_BUSY; } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_flags |= E1000_TX_FLAGS_VLAN; - tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); + tx_flags |= (skb_vlan_tag_get(skb) << + E1000_TX_FLAGS_VLAN_SHIFT); } first = tx_ring->next_to_use; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 332a298e95b5..38cb586b1bf4 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5463,8 +5463,8 @@ static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct e1000_hw *hw = &adapter->hw; u16 length, offset; - if (vlan_tx_tag_present(skb) && - !((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) && + if (skb_vlan_tag_present(skb) && + !((skb_vlan_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) && (adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN))) return 0; @@ -5603,9 +5603,10 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, if (e1000_maybe_stop_tx(tx_ring, count + 2)) return NETDEV_TX_BUSY; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_flags |= E1000_TX_FLAGS_VLAN; - tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); + tx_flags |= (skb_vlan_tag_get(skb) << + E1000_TX_FLAGS_VLAN_SHIFT); } first = tx_ring->next_to_use; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index eb088b129bc7..caa43f7c2931 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -965,8 +965,8 @@ static void fm10k_tx_map(struct fm10k_ring *tx_ring, tx_desc = FM10K_TX_DESC(tx_ring, i); /* add HW VLAN tag */ - if (vlan_tx_tag_present(skb)) - tx_desc->vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + if (skb_vlan_tag_present(skb)) + tx_desc->vlan = cpu_to_le16(skb_vlan_tag_get(skb)); else tx_desc->vlan = 0; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 8811364b91cb..945b35d31c71 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -609,7 +609,7 @@ static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev) int err; if ((skb->protocol == htons(ETH_P_8021Q)) && - !vlan_tx_tag_present(skb)) { + !skb_vlan_tag_present(skb)) { /* FM10K only supports hardware tagging, any tags in frame * are considered 2nd level or "outer" tags */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 04b441460bbd..9f536dd8e1ec 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1772,8 +1772,8 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, u32 tx_flags = 0; /* if we have a HW VLAN tag being added, default to the HW one */ - if (vlan_tx_tag_present(skb)) { - tx_flags |= vlan_tx_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; + if (skb_vlan_tag_present(skb)) { + tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; tx_flags |= I40E_TX_FLAGS_HW_VLAN; /* else if it is a SW VLAN, check the next protocol and store the tag */ } else if (protocol == htons(ETH_P_8021Q)) { diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 04c7c1557a0c..82c3798fdd36 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1122,8 +1122,8 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, u32 tx_flags = 0; /* if we have a HW VLAN tag being added, default to the HW one */ - if (vlan_tx_tag_present(skb)) { - tx_flags |= vlan_tx_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; + if (skb_vlan_tag_present(skb)) { + tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; tx_flags |= I40E_TX_FLAGS_HW_VLAN; /* else if it is a SW VLAN, check the next protocol and store the tag */ } else if (protocol == htons(ETH_P_8021Q)) { diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ff59897a9463..6c25ec314183 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -5035,9 +5035,9 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, skb_tx_timestamp(skb); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_flags |= IGB_TX_FLAGS_VLAN; - tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT); + tx_flags |= (skb_vlan_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT); } /* record initial flags and protocol */ diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index 63c807c9b21c..ad2b4897b392 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -2234,9 +2234,10 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb, return NETDEV_TX_BUSY; } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_flags |= IGBVF_TX_FLAGS_VLAN; - tx_flags |= (vlan_tx_tag_get(skb) << IGBVF_TX_FLAGS_VLAN_SHIFT); + tx_flags |= (skb_vlan_tag_get(skb) << + IGBVF_TX_FLAGS_VLAN_SHIFT); } if (skb->protocol == htons(ETH_P_IP)) diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index aa87605b144a..11a1bdbe3fd9 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -1532,9 +1532,9 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) DESC_NEEDED))) return NETDEV_TX_BUSY; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_flags |= IXGB_TX_FLAGS_VLAN; - vlan_id = vlan_tx_tag_get(skb); + vlan_id = skb_vlan_tag_get(skb); } first = adapter->tx_ring.next_to_use; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 2ed2c7de2304..7bb421bfd84e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7217,8 +7217,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, first->gso_segs = 1; /* if we have a HW VLAN tag being added default to the HW one */ - if (vlan_tx_tag_present(skb)) { - tx_flags |= vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT; + if (skb_vlan_tag_present(skb)) { + tx_flags |= skb_vlan_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_HW_VLAN; /* else if it is a SW VLAN check the next protocol and store the tag */ } else if (protocol == htons(ETH_P_8021Q)) { diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 62a0d8e0f17d..c9b49bfb51bb 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3452,8 +3452,8 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) first->bytecount = skb->len; first->gso_segs = 1; - if (vlan_tx_tag_present(skb)) { - tx_flags |= vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + tx_flags |= skb_vlan_tag_get(skb); tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_VLAN; } diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 44ce7d88f554..6e9a792097d3 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -2154,9 +2154,9 @@ jme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags) static inline void jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags) { - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { *flags |= TXFLAG_TAGON; - *vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + *vlan = cpu_to_le16(skb_vlan_tag_get(skb)); } } diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 867a6a3ef81f..d9f4498832a1 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -1895,14 +1895,14 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb, ctrl = 0; /* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */ - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { if (!le) { le = get_tx_le(sky2, &slot); le->addr = 0; le->opcode = OP_VLAN|HW_OWNER; } else le->opcode |= OP_VLAN; - le->length = cpu_to_be16(vlan_tx_tag_get(skb)); + le->length = cpu_to_be16(skb_vlan_tag_get(skb)); ctrl |= INS_VLAN; } @@ -2594,7 +2594,7 @@ static struct sk_buff *sky2_receive(struct net_device *dev, sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending; prefetch(sky2->rx_ring + sky2->rx_next); - if (vlan_tx_tag_present(re->skb)) + if (skb_vlan_tag_present(re->skb)) count -= VLAN_HLEN; /* Account for vlan tag */ /* This chip has hardware problems that generates bogus status. diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index e3357bf523df..359bb1286eb5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -682,8 +682,8 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb, if (dev->num_tc) return skb_tx_hash(dev, skb); - if (vlan_tx_tag_present(skb)) - up = vlan_tx_tag_get(skb) >> VLAN_PRIO_SHIFT; + if (skb_vlan_tag_present(skb)) + up = skb_vlan_tag_get(skb) >> VLAN_PRIO_SHIFT; return fallback(dev, skb) % rings_p_up + up * rings_p_up; } @@ -742,8 +742,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_drop; } - if (vlan_tx_tag_present(skb)) - vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) + vlan_tag = skb_vlan_tag_get(skb); netdev_txq_bql_enqueue_prefetchw(ring->tx_queue); @@ -930,7 +930,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) real_size = (real_size / 16) & 0x3f; if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && - !vlan_tx_tag_present(skb) && send_doorbell) { + !skb_vlan_tag_present(skb) && send_doorbell) { tx_desc->ctrl.bf_qpn = ring->doorbell_qpn | cpu_to_be32(real_size); @@ -952,7 +952,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) } else { tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag); tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN * - !!vlan_tx_tag_present(skb); + !!skb_vlan_tag_present(skb); tx_desc->ctrl.fence_size = real_size; /* Ensure new descriptor hits memory diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c index 2552e550a78c..eb807b0dc72a 100644 --- a/drivers/net/ethernet/natsemi/ns83820.c +++ b/drivers/net/ethernet/natsemi/ns83820.c @@ -1122,12 +1122,12 @@ again: } #ifdef NS83820_VLAN_ACCEL_SUPPORT - if(vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { /* fetch the vlan tag info out of the * ancillary data if the vlan code * is using hw vlan acceleration */ - short tag = vlan_tx_tag_get(skb); + short tag = skb_vlan_tag_get(skb); extsts |= (EXTSTS_VPKT | htons(tag)); } #endif diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index f5e4b820128b..0529cad75b10 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -4045,8 +4045,8 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev) } queue = 0; - if (vlan_tx_tag_present(skb)) - vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) + vlan_tag = skb_vlan_tag_get(skb); if (sp->config.tx_steering_type == TX_DEFAULT_STEERING) { if (skb->protocol == htons(ETH_P_IP)) { struct iphdr *ip; diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index cc0485e3c621..50d5604833ed 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -890,8 +890,8 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, __func__, __LINE__, fifo_hw, dtr, dtr_priv); - if (vlan_tx_tag_present(skb)) { - u16 vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + u16 vlan_tag = skb_vlan_tag_get(skb); vxge_hw_fifo_txdl_vlan_set(dtr, vlan_tag); } diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index f39cae620f61..a41bb5e6b954 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -2462,9 +2462,9 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0; /* vlan tag */ - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | - vlan_tx_tag_get(skb)); + skb_vlan_tag_get(skb)); else start_tx->txvlan = 0; diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 613037584d08..a47fe67fdf58 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -1893,9 +1893,9 @@ netxen_tso_check(struct net_device *netdev, protocol = vh->h_vlan_encapsulated_proto; flags = FLAGS_VLAN_TAGGED; - } else if (vlan_tx_tag_present(skb)) { + } else if (skb_vlan_tag_present(skb)) { flags = FLAGS_VLAN_OOB; - vid = vlan_tx_tag_get(skb); + vid = skb_vlan_tag_get(skb); netxen_set_tx_vlan_tci(first_desc, vid); vlan_oob = 1; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index d166e534925d..4d2496f28b85 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -321,8 +321,8 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, if (protocol == ETH_P_8021Q) { vh = (struct vlan_ethhdr *)skb->data; vlan_id = ntohs(vh->h_vlan_TCI); - } else if (vlan_tx_tag_present(skb)) { - vlan_id = vlan_tx_tag_get(skb); + } else if (skb_vlan_tag_present(skb)) { + vlan_id = skb_vlan_tag_get(skb); } } @@ -473,9 +473,9 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter, flags = QLCNIC_FLAGS_VLAN_TAGGED; vlan_tci = ntohs(vh->h_vlan_TCI); protocol = ntohs(vh->h_vlan_encapsulated_proto); - } else if (vlan_tx_tag_present(skb)) { + } else if (skb_vlan_tag_present(skb)) { flags = QLCNIC_FLAGS_VLAN_OOB; - vlan_tci = vlan_tx_tag_get(skb); + vlan_tci = skb_vlan_tag_get(skb); } if (unlikely(adapter->tx_pvid)) { if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED)) diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 6c904a6cad2a..dc0058f90370 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -2660,11 +2660,11 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev) mac_iocb_ptr->frame_len = cpu_to_le16((u16) skb->len); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { netif_printk(qdev, tx_queued, KERN_DEBUG, qdev->ndev, - "Adding a vlan tag %d.\n", vlan_tx_tag_get(skb)); + "Adding a vlan tag %d.\n", skb_vlan_tag_get(skb)); mac_iocb_ptr->flags3 |= OB_MAC_IOCB_V; - mac_iocb_ptr->vlan_tci = cpu_to_le16(vlan_tx_tag_get(skb)); + mac_iocb_ptr->vlan_tci = cpu_to_le16(skb_vlan_tag_get(skb)); } tso = ql_tso(skb, (struct ob_mac_tso_iocb_req *)mac_iocb_ptr); if (tso < 0) { diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 9c31e46d1eee..d79e33b3c191 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -708,8 +708,8 @@ static void cp_tx (struct cp_private *cp) static inline u32 cp_tx_vlan_tag(struct sk_buff *skb) { - return vlan_tx_tag_present(skb) ? - TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; + return skb_vlan_tag_present(skb) ? + TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00; } static void unwind_tx_frag_mapping(struct cp_private *cp, struct sk_buff *skb, diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 3a280598a15a..cd286b0356ab 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -2073,8 +2073,8 @@ static int rtl8169_set_features(struct net_device *dev, static inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb) { - return (vlan_tx_tag_present(skb)) ? - TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; + return (skb_vlan_tag_present(skb)) ? + TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00; } static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb) diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index b6612d6090ac..23545e1e605a 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -1272,7 +1272,7 @@ static netdev_tx_t sxgbe_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb_is_gso(skb) && tqueue->prev_mss != cur_mss)) ctxt_desc_req = 1; - if (unlikely(vlan_tx_tag_present(skb) || + if (unlikely(skb_vlan_tag_present(skb) || ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && tqueue->hwts_tx_en))) ctxt_desc_req = 1; diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c index 6ab36d9ff2ab..a9cac8413e49 100644 --- a/drivers/net/ethernet/tehuti/tehuti.c +++ b/drivers/net/ethernet/tehuti/tehuti.c @@ -1650,9 +1650,9 @@ static netdev_tx_t bdx_tx_transmit(struct sk_buff *skb, txd_mss); } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { /*Cut VLAN ID to 12 bits */ - txd_vlan_id = vlan_tx_tag_get(skb) & BITS_MASK(12); + txd_vlan_id = skb_vlan_tag_get(skb) & BITS_MASK(12); txd_vtag = 1; } diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index a191afc23b56..0ac76102b33d 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -1781,8 +1781,8 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, rp->tx_ring[entry].desc_length = cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); - if (unlikely(vlan_tx_tag_present(skb))) { - u16 vid_pcp = vlan_tx_tag_get(skb); + if (unlikely(skb_vlan_tag_present(skb))) { + u16 vid_pcp = skb_vlan_tag_get(skb); /* drop CFI/DEI bit, register needs VID and PCP */ vid_pcp = (vid_pcp & VLAN_VID_MASK) | @@ -1803,7 +1803,7 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, /* Non-x86 Todo: explicitly flush cache lines here. */ - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) /* Tx queues are bits 7-0 (first Tx queue: bit 7) */ BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake); diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c index 282f83a63b67..c20206f83cc1 100644 --- a/drivers/net/ethernet/via/via-velocity.c +++ b/drivers/net/ethernet/via/via-velocity.c @@ -2611,8 +2611,8 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; - if (vlan_tx_tag_present(skb)) { - td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + if (skb_vlan_tag_present(skb)) { + td_ptr->tdesc1.vlan = cpu_to_le16(skb_vlan_tag_get(skb)); td_ptr->tdesc1.TCR |= TCR0_VETAG; } diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 7df221788cd4..d0ed5694dd7d 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -645,7 +645,7 @@ static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q, if (skb->ip_summed == CHECKSUM_PARTIAL) { vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) vnet_hdr->csum_start = cpu_to_macvtap16(q, skb_checksum_start_offset(skb) + VLAN_HLEN); else @@ -821,13 +821,13 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, total = vnet_hdr_len; total += skb->len; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { struct { __be16 h_vlan_proto; __be16 h_vlan_TCI; } veth; veth.h_vlan_proto = skb->vlan_proto; - veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); + veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb)); vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); total += VLAN_HLEN; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 74fdf1158448..be196e89ab6c 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1260,7 +1260,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, int vlan_hlen = 0; int vnet_hdr_sz = 0; - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) vlan_hlen = VLAN_HLEN; if (tun->flags & IFF_VNET_HDR) @@ -1337,7 +1337,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, } veth; veth.h_vlan_proto = skb->vlan_proto; - veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); + veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb)); vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index b23426e4952c..e519e6a269b9 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1421,10 +1421,10 @@ static int msdn_giant_send_check(struct sk_buff *skb) static inline void rtl_tx_vlan_tag(struct tx_desc *desc, struct sk_buff *skb) { - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { u32 opts2; - opts2 = TX_VLAN_TAG | swab16(vlan_tx_tag_get(skb)); + opts2 = TX_VLAN_TAG | swab16(skb_vlan_tag_get(skb)); desc->opts2 |= cpu_to_le32(opts2); } } diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 31439818c27e..294214c15292 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1038,9 +1038,9 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, le32_add_cpu(&tq->shared->txNumDeferred, 1); } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { gdesc->txd.ti = 1; - gdesc->txd.tci = vlan_tx_tag_get(skb); + gdesc->txd.tci = skb_vlan_tag_get(skb); } /* finally flips the GEN bit of the SOP desc. */ diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 3a18d8ed89ca..985359dd6033 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1561,7 +1561,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len + VXLAN_HLEN + sizeof(struct ipv6hdr) - + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); + + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); /* Need space for new headers (invalidates iph ptr) */ err = skb_cow_head(skb, min_headroom); @@ -1607,7 +1607,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len + VXLAN_HLEN + sizeof(struct iphdr) - + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); + + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); /* Need space for new headers (invalidates iph ptr) */ err = skb_cow_head(skb, min_headroom); -- cgit v1.2.1 From e84448d52190413400663736067f826f28a04ad6 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Tue, 13 Jan 2015 17:16:43 +0000 Subject: xen-netfront: refactor skb slot counting A function to count the number of slots an skb needs is more useful than one that counts the slots needed for only the frags. Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index a4e50482a230..803ff5356faa 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -517,13 +517,15 @@ static void xennet_make_frags(struct sk_buff *skb, struct netfront_queue *queue, } /* - * Count how many ring slots are required to send the frags of this - * skb. Each frag might be a compound page. + * Count how many ring slots are required to send this skb. Each frag + * might be a compound page. */ -static int xennet_count_skb_frag_slots(struct sk_buff *skb) +static int xennet_count_skb_slots(struct sk_buff *skb) { int i, frags = skb_shinfo(skb)->nr_frags; - int pages = 0; + int pages; + + pages = PFN_UP(offset_in_page(skb->data) + skb_headlen(skb)); for (i = 0; i < frags; i++) { skb_frag_t *frag = skb_shinfo(skb)->frags + i; @@ -593,8 +595,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) goto drop; } - slots = DIV_ROUND_UP(offset + len, PAGE_SIZE) + - xennet_count_skb_frag_slots(skb); + slots = xennet_count_skb_slots(skb); if (unlikely(slots > MAX_SKB_FRAGS + 1)) { net_dbg_ratelimited("xennet: skb rides the rocket: %d slots, %d bytes\n", slots, skb->len); -- cgit v1.2.1 From a55e8bb8fb89c90b33791861e59859a39e57ba30 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Tue, 13 Jan 2015 17:16:44 +0000 Subject: xen-netfront: refactor making Tx requests Eliminate all the duplicate code for making Tx requests by consolidating them into a single xennet_make_one_txreq() function. xennet_make_one_txreq() and xennet_make_txreqs() work with pages and offsets so it will be easier to make netfront handle highmem frags in the future. Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 181 +++++++++++++++++---------------------------- 1 file changed, 67 insertions(+), 114 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 803ff5356faa..01a4350eb313 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -421,99 +421,56 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue) xennet_maybe_wake_tx(queue); } -static void xennet_make_frags(struct sk_buff *skb, struct netfront_queue *queue, - struct xen_netif_tx_request *tx) -{ - char *data = skb->data; - unsigned long mfn; - RING_IDX prod = queue->tx.req_prod_pvt; - int frags = skb_shinfo(skb)->nr_frags; - unsigned int offset = offset_in_page(data); - unsigned int len = skb_headlen(skb); +static struct xen_netif_tx_request *xennet_make_one_txreq( + struct netfront_queue *queue, struct sk_buff *skb, + struct page *page, unsigned int offset, unsigned int len) +{ unsigned int id; + struct xen_netif_tx_request *tx; grant_ref_t ref; - int i; - /* While the header overlaps a page boundary (including being - larger than a page), split it it into page-sized chunks. */ - while (len > PAGE_SIZE - offset) { - tx->size = PAGE_SIZE - offset; - tx->flags |= XEN_NETTXF_more_data; - len -= tx->size; - data += tx->size; - offset = 0; + len = min_t(unsigned int, PAGE_SIZE - offset, len); - id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs); - queue->tx_skbs[id].skb = skb_get(skb); - tx = RING_GET_REQUEST(&queue->tx, prod++); - tx->id = id; - ref = gnttab_claim_grant_reference(&queue->gref_tx_head); - BUG_ON((signed short)ref < 0); + id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs); + tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++); + ref = gnttab_claim_grant_reference(&queue->gref_tx_head); + BUG_ON((signed short)ref < 0); - mfn = virt_to_mfn(data); - gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id, - mfn, GNTMAP_readonly); + gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id, + page_to_mfn(page), GNTMAP_readonly); - queue->grant_tx_page[id] = virt_to_page(data); - tx->gref = queue->grant_tx_ref[id] = ref; - tx->offset = offset; - tx->size = len; - tx->flags = 0; - } + queue->tx_skbs[id].skb = skb; + queue->grant_tx_page[id] = page; + queue->grant_tx_ref[id] = ref; - /* Grant backend access to each skb fragment page. */ - for (i = 0; i < frags; i++) { - skb_frag_t *frag = skb_shinfo(skb)->frags + i; - struct page *page = skb_frag_page(frag); + tx->id = id; + tx->gref = ref; + tx->offset = offset; + tx->size = len; + tx->flags = 0; - len = skb_frag_size(frag); - offset = frag->page_offset; + return tx; +} - /* Skip unused frames from start of page */ - page += offset >> PAGE_SHIFT; - offset &= ~PAGE_MASK; +static struct xen_netif_tx_request *xennet_make_txreqs( + struct netfront_queue *queue, struct xen_netif_tx_request *tx, + struct sk_buff *skb, struct page *page, + unsigned int offset, unsigned int len) +{ + /* Skip unused frames from start of page */ + page += offset >> PAGE_SHIFT; + offset &= ~PAGE_MASK; - while (len > 0) { - unsigned long bytes; - - bytes = PAGE_SIZE - offset; - if (bytes > len) - bytes = len; - - tx->flags |= XEN_NETTXF_more_data; - - id = get_id_from_freelist(&queue->tx_skb_freelist, - queue->tx_skbs); - queue->tx_skbs[id].skb = skb_get(skb); - tx = RING_GET_REQUEST(&queue->tx, prod++); - tx->id = id; - ref = gnttab_claim_grant_reference(&queue->gref_tx_head); - BUG_ON((signed short)ref < 0); - - mfn = pfn_to_mfn(page_to_pfn(page)); - gnttab_grant_foreign_access_ref(ref, - queue->info->xbdev->otherend_id, - mfn, GNTMAP_readonly); - - queue->grant_tx_page[id] = page; - tx->gref = queue->grant_tx_ref[id] = ref; - tx->offset = offset; - tx->size = bytes; - tx->flags = 0; - - offset += bytes; - len -= bytes; - - /* Next frame */ - if (offset == PAGE_SIZE && len) { - BUG_ON(!PageCompound(page)); - page++; - offset = 0; - } - } + while (len) { + tx->flags |= XEN_NETTXF_more_data; + tx = xennet_make_one_txreq(queue, skb_get(skb), + page, offset, len); + page++; + offset = 0; + len -= tx->size; } - queue->tx.req_prod_pvt = prod; + return tx; } /* @@ -561,18 +518,15 @@ static u16 xennet_select_queue(struct net_device *dev, struct sk_buff *skb, static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) { - unsigned short id; struct netfront_info *np = netdev_priv(dev); struct netfront_stats *stats = this_cpu_ptr(np->stats); - struct xen_netif_tx_request *tx; - char *data = skb->data; - RING_IDX i; - grant_ref_t ref; - unsigned long mfn; + struct xen_netif_tx_request *tx, *first_tx; + unsigned int i; int notify; int slots; - unsigned int offset = offset_in_page(data); - unsigned int len = skb_headlen(skb); + struct page *page; + unsigned int offset; + unsigned int len; unsigned long flags; struct netfront_queue *queue = NULL; unsigned int num_queues = dev->real_num_tx_queues; @@ -601,11 +555,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) slots, skb->len); if (skb_linearize(skb)) goto drop; - data = skb->data; - offset = offset_in_page(data); - len = skb_headlen(skb); } + page = virt_to_page(skb->data); + offset = offset_in_page(skb->data); + len = skb_headlen(skb); + spin_lock_irqsave(&queue->tx_lock, flags); if (unlikely(!netif_carrier_ok(dev) || @@ -615,25 +570,13 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) goto drop; } - i = queue->tx.req_prod_pvt; - - id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs); - queue->tx_skbs[id].skb = skb; - - tx = RING_GET_REQUEST(&queue->tx, i); + /* First request for the linear area. */ + first_tx = tx = xennet_make_one_txreq(queue, skb, + page, offset, len); + page++; + offset = 0; + len -= tx->size; - tx->id = id; - ref = gnttab_claim_grant_reference(&queue->gref_tx_head); - BUG_ON((signed short)ref < 0); - mfn = virt_to_mfn(data); - gnttab_grant_foreign_access_ref( - ref, queue->info->xbdev->otherend_id, mfn, GNTMAP_readonly); - queue->grant_tx_page[id] = virt_to_page(data); - tx->gref = queue->grant_tx_ref[id] = ref; - tx->offset = offset; - tx->size = len; - - tx->flags = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */ tx->flags |= XEN_NETTXF_csum_blank | XEN_NETTXF_data_validated; @@ -641,11 +584,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) /* remote but checksummed. */ tx->flags |= XEN_NETTXF_data_validated; + /* Optional extra info after the first request. */ if (skb_shinfo(skb)->gso_size) { struct xen_netif_extra_info *gso; gso = (struct xen_netif_extra_info *) - RING_GET_REQUEST(&queue->tx, ++i); + RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++); tx->flags |= XEN_NETTXF_extra_info; @@ -660,10 +604,19 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) gso->flags = 0; } - queue->tx.req_prod_pvt = i + 1; + /* Requests for the rest of the linear area. */ + tx = xennet_make_txreqs(queue, tx, skb, page, offset, len); + + /* Requests for all the frags. */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + tx = xennet_make_txreqs(queue, tx, skb, + skb_frag_page(frag), frag->page_offset, + skb_frag_size(frag)); + } - xennet_make_frags(skb, queue, tx); - tx->size = skb->len; + /* First request has the packet length. */ + first_tx->size = skb->len; RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&queue->tx, notify); if (notify) -- cgit v1.2.1 From 5c2fa0f6d0b1c7be183b0f3907ccd7dd8746b22a Mon Sep 17 00:00:00 2001 From: Xander Huff Date: Tue, 13 Jan 2015 16:15:50 -0600 Subject: net/macb: Adding comments to various #defs to make interpretation easier This change is to help improve at-a-glace knowledge of the purpose of the various Cadence MACB/GEM registers. Comments are more helpful for human readability than short acronyms. Describe various #define varibles Cadence MACB/GEM registers as documented in Xilinix's "Zynq-7000 All Programmable SoC TechnicalReference Manual, v1.9.1 (UG-585)" Signed-off-by: Xander Huff Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.h | 269 ++++++++++++++++++++++-------------- 1 file changed, 162 insertions(+), 107 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 084191b6fad2..8e8c3c9fda3b 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -15,20 +15,20 @@ #define MACB_MAX_QUEUES 8 /* MACB register offsets */ -#define MACB_NCR 0x0000 -#define MACB_NCFGR 0x0004 -#define MACB_NSR 0x0008 +#define MACB_NCR 0x0000 /* Network Control */ +#define MACB_NCFGR 0x0004 /* Network Config */ +#define MACB_NSR 0x0008 /* Network Status */ #define MACB_TAR 0x000c /* AT91RM9200 only */ #define MACB_TCR 0x0010 /* AT91RM9200 only */ -#define MACB_TSR 0x0014 -#define MACB_RBQP 0x0018 -#define MACB_TBQP 0x001c -#define MACB_RSR 0x0020 -#define MACB_ISR 0x0024 -#define MACB_IER 0x0028 -#define MACB_IDR 0x002c -#define MACB_IMR 0x0030 -#define MACB_MAN 0x0034 +#define MACB_TSR 0x0014 /* Transmit Status */ +#define MACB_RBQP 0x0018 /* RX Q Base Address */ +#define MACB_TBQP 0x001c /* TX Q Base Address */ +#define MACB_RSR 0x0020 /* Receive Status */ +#define MACB_ISR 0x0024 /* Interrupt Status */ +#define MACB_IER 0x0028 /* Interrupt Enable */ +#define MACB_IDR 0x002c /* Interrupt Disable */ +#define MACB_IMR 0x0030 /* Interrupt Mask */ +#define MACB_MAN 0x0034 /* PHY Maintenance */ #define MACB_PTR 0x0038 #define MACB_PFR 0x003c #define MACB_FTO 0x0040 @@ -68,27 +68,27 @@ #define MACB_MID 0x00fc /* GEM register offsets. */ -#define GEM_NCFGR 0x0004 -#define GEM_USRIO 0x000c -#define GEM_DMACFG 0x0010 -#define GEM_HRB 0x0080 -#define GEM_HRT 0x0084 -#define GEM_SA1B 0x0088 -#define GEM_SA1T 0x008C -#define GEM_SA2B 0x0090 -#define GEM_SA2T 0x0094 -#define GEM_SA3B 0x0098 -#define GEM_SA3T 0x009C -#define GEM_SA4B 0x00A0 -#define GEM_SA4T 0x00A4 -#define GEM_OTX 0x0100 -#define GEM_DCFG1 0x0280 -#define GEM_DCFG2 0x0284 -#define GEM_DCFG3 0x0288 -#define GEM_DCFG4 0x028c -#define GEM_DCFG5 0x0290 -#define GEM_DCFG6 0x0294 -#define GEM_DCFG7 0x0298 +#define GEM_NCFGR 0x0004 /* Network Config */ +#define GEM_USRIO 0x000c /* User IO */ +#define GEM_DMACFG 0x0010 /* DMA Configuration */ +#define GEM_HRB 0x0080 /* Hash Bottom */ +#define GEM_HRT 0x0084 /* Hash Top */ +#define GEM_SA1B 0x0088 /* Specific1 Bottom */ +#define GEM_SA1T 0x008C /* Specific1 Top */ +#define GEM_SA2B 0x0090 /* Specific2 Bottom */ +#define GEM_SA2T 0x0094 /* Specific2 Top */ +#define GEM_SA3B 0x0098 /* Specific3 Bottom */ +#define GEM_SA3T 0x009C /* Specific3 Top */ +#define GEM_SA4B 0x00A0 /* Specific4 Bottom */ +#define GEM_SA4T 0x00A4 /* Specific4 Top */ +#define GEM_OTX 0x0100 /* Octets transmitted */ +#define GEM_DCFG1 0x0280 /* Design Config 1 */ +#define GEM_DCFG2 0x0284 /* Design Config 2 */ +#define GEM_DCFG3 0x0288 /* Design Config 3 */ +#define GEM_DCFG4 0x028c /* Design Config 4 */ +#define GEM_DCFG5 0x0290 /* Design Config 5 */ +#define GEM_DCFG6 0x0294 /* Design Config 6 */ +#define GEM_DCFG7 0x0298 /* Design Config 7 */ #define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2)) #define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2)) @@ -98,67 +98,73 @@ #define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2)) /* Bitfields in NCR */ -#define MACB_LB_OFFSET 0 +#define MACB_LB_OFFSET 0 /* reserved */ #define MACB_LB_SIZE 1 -#define MACB_LLB_OFFSET 1 +#define MACB_LLB_OFFSET 1 /* Loop back local */ #define MACB_LLB_SIZE 1 -#define MACB_RE_OFFSET 2 +#define MACB_RE_OFFSET 2 /* Receive enable */ #define MACB_RE_SIZE 1 -#define MACB_TE_OFFSET 3 +#define MACB_TE_OFFSET 3 /* Transmit enable */ #define MACB_TE_SIZE 1 -#define MACB_MPE_OFFSET 4 +#define MACB_MPE_OFFSET 4 /* Management port enable */ #define MACB_MPE_SIZE 1 -#define MACB_CLRSTAT_OFFSET 5 +#define MACB_CLRSTAT_OFFSET 5 /* Clear stats regs */ #define MACB_CLRSTAT_SIZE 1 -#define MACB_INCSTAT_OFFSET 6 +#define MACB_INCSTAT_OFFSET 6 /* Incremental stats regs */ #define MACB_INCSTAT_SIZE 1 -#define MACB_WESTAT_OFFSET 7 +#define MACB_WESTAT_OFFSET 7 /* Write enable stats regs */ #define MACB_WESTAT_SIZE 1 -#define MACB_BP_OFFSET 8 +#define MACB_BP_OFFSET 8 /* Back pressure */ #define MACB_BP_SIZE 1 -#define MACB_TSTART_OFFSET 9 +#define MACB_TSTART_OFFSET 9 /* Start transmission */ #define MACB_TSTART_SIZE 1 -#define MACB_THALT_OFFSET 10 +#define MACB_THALT_OFFSET 10 /* Transmit halt */ #define MACB_THALT_SIZE 1 -#define MACB_NCR_TPF_OFFSET 11 +#define MACB_NCR_TPF_OFFSET 11 /* Transmit pause frame */ #define MACB_NCR_TPF_SIZE 1 -#define MACB_TZQ_OFFSET 12 +#define MACB_TZQ_OFFSET 12 /* Transmit zero quantum + * pause frame + */ #define MACB_TZQ_SIZE 1 /* Bitfields in NCFGR */ -#define MACB_SPD_OFFSET 0 +#define MACB_SPD_OFFSET 0 /* Speed */ #define MACB_SPD_SIZE 1 -#define MACB_FD_OFFSET 1 +#define MACB_FD_OFFSET 1 /* Full duplex */ #define MACB_FD_SIZE 1 -#define MACB_BIT_RATE_OFFSET 2 +#define MACB_BIT_RATE_OFFSET 2 /* Discard non-VLAN frames */ #define MACB_BIT_RATE_SIZE 1 -#define MACB_JFRAME_OFFSET 3 +#define MACB_JFRAME_OFFSET 3 /* reserved */ #define MACB_JFRAME_SIZE 1 -#define MACB_CAF_OFFSET 4 +#define MACB_CAF_OFFSET 4 /* Copy all frames */ #define MACB_CAF_SIZE 1 -#define MACB_NBC_OFFSET 5 +#define MACB_NBC_OFFSET 5 /* No broadcast */ #define MACB_NBC_SIZE 1 -#define MACB_NCFGR_MTI_OFFSET 6 +#define MACB_NCFGR_MTI_OFFSET 6 /* Multicast hash enable */ #define MACB_NCFGR_MTI_SIZE 1 -#define MACB_UNI_OFFSET 7 +#define MACB_UNI_OFFSET 7 /* Unicast hash enable */ #define MACB_UNI_SIZE 1 -#define MACB_BIG_OFFSET 8 +#define MACB_BIG_OFFSET 8 /* Receive 1536 byte frames */ #define MACB_BIG_SIZE 1 -#define MACB_EAE_OFFSET 9 +#define MACB_EAE_OFFSET 9 /* External address match + * enable + */ #define MACB_EAE_SIZE 1 #define MACB_CLK_OFFSET 10 #define MACB_CLK_SIZE 2 -#define MACB_RTY_OFFSET 12 +#define MACB_RTY_OFFSET 12 /* Retry test */ #define MACB_RTY_SIZE 1 -#define MACB_PAE_OFFSET 13 +#define MACB_PAE_OFFSET 13 /* Pause enable */ #define MACB_PAE_SIZE 1 #define MACB_RM9200_RMII_OFFSET 13 /* AT91RM9200 only */ #define MACB_RM9200_RMII_SIZE 1 /* AT91RM9200 only */ -#define MACB_RBOF_OFFSET 14 +#define MACB_RBOF_OFFSET 14 /* Receive buffer offset */ #define MACB_RBOF_SIZE 2 -#define MACB_RLCE_OFFSET 16 +#define MACB_RLCE_OFFSET 16 /* Length field error frame + * discard + */ #define MACB_RLCE_SIZE 1 -#define MACB_DRFCS_OFFSET 17 +#define MACB_DRFCS_OFFSET 17 /* FCS remove */ #define MACB_DRFCS_SIZE 1 #define MACB_EFRHD_OFFSET 18 #define MACB_EFRHD_SIZE 1 @@ -166,111 +172,160 @@ #define MACB_IRXFCS_SIZE 1 /* GEM specific NCFGR bitfields. */ -#define GEM_GBE_OFFSET 10 +#define GEM_GBE_OFFSET 10 /* Gigabit mode enable */ #define GEM_GBE_SIZE 1 -#define GEM_CLK_OFFSET 18 +#define GEM_CLK_OFFSET 18 /* MDC clock division */ #define GEM_CLK_SIZE 3 -#define GEM_DBW_OFFSET 21 +#define GEM_DBW_OFFSET 21 /* Data bus width */ #define GEM_DBW_SIZE 2 #define GEM_RXCOEN_OFFSET 24 #define GEM_RXCOEN_SIZE 1 /* Constants for data bus width. */ -#define GEM_DBW32 0 -#define GEM_DBW64 1 -#define GEM_DBW128 2 +#define GEM_DBW32 0 /* 32 bit AMBA AHB data bus + * width + */ +#define GEM_DBW64 1 /* 64 bit AMBA AHB data bus + * width + */ +#define GEM_DBW128 2 /* 128 bit AMBA AHB data bus + * width + */ /* Bitfields in DMACFG. */ -#define GEM_FBLDO_OFFSET 0 +#define GEM_FBLDO_OFFSET 0 /* AHB fixed burst length for + * DMA data operations + */ #define GEM_FBLDO_SIZE 5 -#define GEM_ENDIA_OFFSET 7 +#define GEM_ENDIA_OFFSET 7 /* AHB endian swap mode enable + * for packet data accesses + */ #define GEM_ENDIA_SIZE 1 -#define GEM_RXBMS_OFFSET 8 +#define GEM_RXBMS_OFFSET 8 /* Receiver packet buffer + * memory size select + */ #define GEM_RXBMS_SIZE 2 -#define GEM_TXPBMS_OFFSET 10 +#define GEM_TXPBMS_OFFSET 10 /* Transmitter packet buffer + * memory size select + */ #define GEM_TXPBMS_SIZE 1 -#define GEM_TXCOEN_OFFSET 11 +#define GEM_TXCOEN_OFFSET 11 /* Transmitter IP, TCP and + * UDP checksum generation + * offload enable + */ #define GEM_TXCOEN_SIZE 1 -#define GEM_RXBS_OFFSET 16 +#define GEM_RXBS_OFFSET 16 /* DMA receive buffer size in + * AHB system memory + */ #define GEM_RXBS_SIZE 8 -#define GEM_DDRP_OFFSET 24 +#define GEM_DDRP_OFFSET 24 /* disc_when_no_ahb */ #define GEM_DDRP_SIZE 1 /* Bitfields in NSR */ -#define MACB_NSR_LINK_OFFSET 0 +#define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */ #define MACB_NSR_LINK_SIZE 1 -#define MACB_MDIO_OFFSET 1 +#define MACB_MDIO_OFFSET 1 /* status of the mdio_in + * pin + */ #define MACB_MDIO_SIZE 1 -#define MACB_IDLE_OFFSET 2 +#define MACB_IDLE_OFFSET 2 /* The PHY management logic is + * idle (i.e. has completed) + */ #define MACB_IDLE_SIZE 1 /* Bitfields in TSR */ -#define MACB_UBR_OFFSET 0 +#define MACB_UBR_OFFSET 0 /* Used bit read */ #define MACB_UBR_SIZE 1 -#define MACB_COL_OFFSET 1 +#define MACB_COL_OFFSET 1 /* Collision occurred */ #define MACB_COL_SIZE 1 -#define MACB_TSR_RLE_OFFSET 2 +#define MACB_TSR_RLE_OFFSET 2 /* Retry limit exceeded */ #define MACB_TSR_RLE_SIZE 1 -#define MACB_TGO_OFFSET 3 +#define MACB_TGO_OFFSET 3 /* Transmit go */ #define MACB_TGO_SIZE 1 -#define MACB_BEX_OFFSET 4 +#define MACB_BEX_OFFSET 4 /* Transmit frame corruption + * due to AHB error + */ #define MACB_BEX_SIZE 1 #define MACB_RM9200_BNQ_OFFSET 4 /* AT91RM9200 only */ #define MACB_RM9200_BNQ_SIZE 1 /* AT91RM9200 only */ -#define MACB_COMP_OFFSET 5 +#define MACB_COMP_OFFSET 5 /* Trnasmit complete */ #define MACB_COMP_SIZE 1 -#define MACB_UND_OFFSET 6 +#define MACB_UND_OFFSET 6 /* Trnasmit under run */ #define MACB_UND_SIZE 1 /* Bitfields in RSR */ -#define MACB_BNA_OFFSET 0 +#define MACB_BNA_OFFSET 0 /* Buffer not available */ #define MACB_BNA_SIZE 1 -#define MACB_REC_OFFSET 1 +#define MACB_REC_OFFSET 1 /* Frame received */ #define MACB_REC_SIZE 1 -#define MACB_OVR_OFFSET 2 +#define MACB_OVR_OFFSET 2 /* Receive overrun */ #define MACB_OVR_SIZE 1 /* Bitfields in ISR/IER/IDR/IMR */ -#define MACB_MFD_OFFSET 0 +#define MACB_MFD_OFFSET 0 /* Management frame sent */ #define MACB_MFD_SIZE 1 -#define MACB_RCOMP_OFFSET 1 +#define MACB_RCOMP_OFFSET 1 /* Receive complete */ #define MACB_RCOMP_SIZE 1 -#define MACB_RXUBR_OFFSET 2 +#define MACB_RXUBR_OFFSET 2 /* RX used bit read */ #define MACB_RXUBR_SIZE 1 -#define MACB_TXUBR_OFFSET 3 +#define MACB_TXUBR_OFFSET 3 /* TX used bit read */ #define MACB_TXUBR_SIZE 1 -#define MACB_ISR_TUND_OFFSET 4 +#define MACB_ISR_TUND_OFFSET 4 /* Enable trnasmit buffer + * under run interrupt + */ #define MACB_ISR_TUND_SIZE 1 -#define MACB_ISR_RLE_OFFSET 5 +#define MACB_ISR_RLE_OFFSET 5 /* Enable retry limit exceeded + * or late collision interrupt + */ #define MACB_ISR_RLE_SIZE 1 -#define MACB_TXERR_OFFSET 6 +#define MACB_TXERR_OFFSET 6 /* Enable transmit frame + * corruption due to AHB error + * interrupt + */ #define MACB_TXERR_SIZE 1 -#define MACB_TCOMP_OFFSET 7 +#define MACB_TCOMP_OFFSET 7 /* Enable transmit complete + * interrupt + */ #define MACB_TCOMP_SIZE 1 -#define MACB_ISR_LINK_OFFSET 9 +#define MACB_ISR_LINK_OFFSET 9 /* Enable link change + * interrupt + */ #define MACB_ISR_LINK_SIZE 1 -#define MACB_ISR_ROVR_OFFSET 10 +#define MACB_ISR_ROVR_OFFSET 10 /* Enable receive overrun + * interrupt + */ #define MACB_ISR_ROVR_SIZE 1 -#define MACB_HRESP_OFFSET 11 +#define MACB_HRESP_OFFSET 11 /* Enable hrsep not OK + * interrupt + */ #define MACB_HRESP_SIZE 1 -#define MACB_PFR_OFFSET 12 +#define MACB_PFR_OFFSET 12 /* Enable pause frame with + * non-zero pause quantum + * interrupt + */ #define MACB_PFR_SIZE 1 -#define MACB_PTZ_OFFSET 13 +#define MACB_PTZ_OFFSET 13 /* Enable pause time zero + * interrupt + */ #define MACB_PTZ_SIZE 1 /* Bitfields in MAN */ -#define MACB_DATA_OFFSET 0 +#define MACB_DATA_OFFSET 0 /* data */ #define MACB_DATA_SIZE 16 -#define MACB_CODE_OFFSET 16 +#define MACB_CODE_OFFSET 16 /* Must be written to 10 */ #define MACB_CODE_SIZE 2 -#define MACB_REGA_OFFSET 18 +#define MACB_REGA_OFFSET 18 /* Register address */ #define MACB_REGA_SIZE 5 -#define MACB_PHYA_OFFSET 23 +#define MACB_PHYA_OFFSET 23 /* PHY address */ #define MACB_PHYA_SIZE 5 -#define MACB_RW_OFFSET 28 +#define MACB_RW_OFFSET 28 /* Operation. 10 is read. 01 + * is write. + */ #define MACB_RW_SIZE 2 -#define MACB_SOF_OFFSET 30 +#define MACB_SOF_OFFSET 30 /* Must be written to 1 for + * Clause 22 operation + */ #define MACB_SOF_SIZE 2 /* Bitfields in USRIO (AVR32) */ @@ -286,7 +341,7 @@ /* Bitfields in USRIO (AT91) */ #define MACB_RMII_OFFSET 0 #define MACB_RMII_SIZE 1 -#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */ +#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */ #define GEM_RGMII_SIZE 1 #define MACB_CLKEN_OFFSET 1 #define MACB_CLKEN_SIZE 1 -- cgit v1.2.1 From 3ff13f1c620e4387e1a9b9bc5d95d67052615037 Mon Sep 17 00:00:00 2001 From: Xander Huff Date: Tue, 13 Jan 2015 16:15:51 -0600 Subject: net/macb: improved ethtool statistics support Currently `ethtool -S` simply returns "no stats available". It would be more useful to see what the various ethtool statistics registers' values are. This change implements get_ethtool_stats, get_strings, and get_sset_count functions to accomplish this. Read all GEM statistics registers and sum them into macb.ethtool_stats. Add the necessary infrastructure to make this accessible via `ethtool -S`. Update gem_update_stats to utilize ethtool_stats. Signed-off-by: Xander Huff Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 55 +++++++- drivers/net/ethernet/cadence/macb.h | 256 ++++++++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 3767271c7667..dd8c202c0708 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1827,12 +1827,23 @@ static int macb_close(struct net_device *dev) static void gem_update_stats(struct macb *bp) { - u32 __iomem *reg = bp->regs + GEM_OTX; + int i; u32 *p = &bp->hw_stats.gem.tx_octets_31_0; - u32 *end = &bp->hw_stats.gem.rx_udp_checksum_errors + 1; - for (; p < end; p++, reg++) - *p += __raw_readl(reg); + for (i = 0; i < GEM_STATS_LEN; ++i, ++p) { + u32 offset = gem_statistics[i].offset; + u64 val = __raw_readl(bp->regs+offset); + + bp->ethtool_stats[i] += val; + *p += val; + + if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) { + /* Add GEM_OCTTXH, GEM_OCTRXH */ + val = __raw_readl(bp->regs+offset+4); + bp->ethtool_stats[i] += ((u64)val)<<32; + *(++p) += val; + } + } } static struct net_device_stats *gem_get_stats(struct macb *bp) @@ -1873,6 +1884,39 @@ static struct net_device_stats *gem_get_stats(struct macb *bp) return nstat; } +static void gem_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct macb *bp; + + bp = netdev_priv(dev); + gem_update_stats(bp); + memcpy(data, &bp->ethtool_stats, sizeof(u64)*GEM_STATS_LEN); +} + +static int gem_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return GEM_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p) +{ + int i; + + switch (sset) { + case ETH_SS_STATS: + for (i = 0; i < GEM_STATS_LEN; i++, p += ETH_GSTRING_LEN) + memcpy(p, gem_statistics[i].stat_string, + ETH_GSTRING_LEN); + break; + } +} + struct net_device_stats *macb_get_stats(struct net_device *dev) { struct macb *bp = netdev_priv(dev); @@ -1988,6 +2032,9 @@ const struct ethtool_ops macb_ethtool_ops = { .get_regs = macb_get_regs, .get_link = ethtool_op_get_link, .get_ts_info = ethtool_op_get_ts_info, + .get_ethtool_stats = gem_get_ethtool_stats, + .get_strings = gem_get_ethtool_strings, + .get_sset_count = gem_get_sset_count, }; EXPORT_SYMBOL_GPL(macb_ethtool_ops); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 8e8c3c9fda3b..378b2183ab8d 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -82,6 +82,159 @@ #define GEM_SA4B 0x00A0 /* Specific4 Bottom */ #define GEM_SA4T 0x00A4 /* Specific4 Top */ #define GEM_OTX 0x0100 /* Octets transmitted */ +#define GEM_OCTTXL 0x0100 /* Octets transmitted + * [31:0] + */ +#define GEM_OCTTXH 0x0104 /* Octets transmitted + * [47:32] + */ +#define GEM_TXCNT 0x0108 /* Error-free Frames + * Transmitted counter + */ +#define GEM_TXBCCNT 0x010c /* Error-free Broadcast + * Frames counter + */ +#define GEM_TXMCCNT 0x0110 /* Error-free Multicast + * Frames counter + */ +#define GEM_TXPAUSECNT 0x0114 /* Pause Frames + * Transmitted Counter + */ +#define GEM_TX64CNT 0x0118 /* Error-free 64 byte + * Frames Transmitted + * counter + */ +#define GEM_TX65CNT 0x011c /* Error-free 65-127 byte + * Frames Transmitted + * counter + */ +#define GEM_TX128CNT 0x0120 /* Error-free 128-255 + * byte Frames + * Transmitted counter + */ +#define GEM_TX256CNT 0x0124 /* Error-free 256-511 + * byte Frames + * transmitted counter + */ +#define GEM_TX512CNT 0x0128 /* Error-free 512-1023 + * byte Frames + * transmitted counter + */ +#define GEM_TX1024CNT 0x012c /* Error-free 1024-1518 + * byte Frames + * transmitted counter + */ +#define GEM_TX1519CNT 0x0130 /* Error-free larger than + * 1519 byte Frames + * tranmitted counter + */ +#define GEM_TXURUNCNT 0x0134 /* TX under run error + * counter + */ +#define GEM_SNGLCOLLCNT 0x0138 /* Single Collision Frame + * Counter + */ +#define GEM_MULTICOLLCNT 0x013c /* Multiple Collision + * Frame Counter + */ +#define GEM_EXCESSCOLLCNT 0x0140 /* Excessive Collision + * Frame Counter + */ +#define GEM_LATECOLLCNT 0x0144 /* Late Collision Frame + * Counter + */ +#define GEM_TXDEFERCNT 0x0148 /* Deferred Transmission + * Frame Counter + */ +#define GEM_TXCSENSECNT 0x014c /* Carrier Sense Error + * Counter + */ +#define GEM_ORX 0x0150 /* Octets received */ +#define GEM_OCTRXL 0x0150 /* Octets received + * [31:0] + */ +#define GEM_OCTRXH 0x0154 /* Octets received + * [47:32] + */ +#define GEM_RXCNT 0x0158 /* Error-free Frames + * Received Counter + */ +#define GEM_RXBROADCNT 0x015c /* Error-free Broadcast + * Frames Received + * Counter + */ +#define GEM_RXMULTICNT 0x0160 /* Error-free Multicast + * Frames Received + * Counter + */ +#define GEM_RXPAUSECNT 0x0164 /* Error-free Pause + * Frames Received + * Counter + */ +#define GEM_RX64CNT 0x0168 /* Error-free 64 byte + * Frames Received + * Counter + */ +#define GEM_RX65CNT 0x016c /* Error-free 65-127 byte + * Frames Received + * Counter + */ +#define GEM_RX128CNT 0x0170 /* Error-free 128-255 + * byte Frames Received + * Counter + */ +#define GEM_RX256CNT 0x0174 /* Error-free 256-511 + * byte Frames Received + * Counter + */ +#define GEM_RX512CNT 0x0178 /* Error-free 512-1023 + * byte Frames Received + * Counter + */ +#define GEM_RX1024CNT 0x017c /* Error-free 1024-1518 + * byte Frames Received + * Counter + */ +#define GEM_RX1519CNT 0x0180 /* Error-free larger than + * 1519 Frames Received + * Counter + */ +#define GEM_RXUNDRCNT 0x0184 /* Undersize Frames + * Received Counter + */ +#define GEM_RXOVRCNT 0x0188 /* Oversize Frames + * Received Counter + */ +#define GEM_RXJABCNT 0x018c /* Jabbers Received + * Counter + */ +#define GEM_RXFCSCNT 0x0190 /* Frame Check Sequence + * Error Counter + */ +#define GEM_RXLENGTHCNT 0x0194 /* Length Field Error + * Counter + */ +#define GEM_RXSYMBCNT 0x0198 /* Symbol Error + * Counter + */ +#define GEM_RXALIGNCNT 0x019c /* Alignment Error + * Counter + */ +#define GEM_RXRESERRCNT 0x01a0 /* Receive Resource Error + * Counter + */ +#define GEM_RXORCNT 0x01a4 /* Receive Overrun + * Counter + */ +#define GEM_RXIPCCNT 0x01a8 /* IP header Checksum + * Error Counter + */ +#define GEM_RXTCPCCNT 0x01ac /* TCP Checksum Error + * Counter + */ +#define GEM_RXUDPCCNT 0x01b0 /* UDP Checksum Error + * Counter + */ #define GEM_DCFG1 0x0280 /* Design Config 1 */ #define GEM_DCFG2 0x0284 /* Design Config 2 */ #define GEM_DCFG3 0x0288 /* Design Config 3 */ @@ -650,6 +803,107 @@ struct gem_stats { u32 rx_udp_checksum_errors; }; +/* Describes the name and offset of an individual statistic register, as + * returned by `ethtool -S`. Also describes which net_device_stats statistics + * this register should contribute to. + */ +struct gem_statistic { + char stat_string[ETH_GSTRING_LEN]; + int offset; + u32 stat_bits; +}; + +/* Bitfield defs for net_device_stat statistics */ +#define GEM_NDS_RXERR_OFFSET 0 +#define GEM_NDS_RXLENERR_OFFSET 1 +#define GEM_NDS_RXOVERERR_OFFSET 2 +#define GEM_NDS_RXCRCERR_OFFSET 3 +#define GEM_NDS_RXFRAMEERR_OFFSET 4 +#define GEM_NDS_RXFIFOERR_OFFSET 5 +#define GEM_NDS_TXERR_OFFSET 6 +#define GEM_NDS_TXABORTEDERR_OFFSET 7 +#define GEM_NDS_TXCARRIERERR_OFFSET 8 +#define GEM_NDS_TXFIFOERR_OFFSET 9 +#define GEM_NDS_COLLISIONS_OFFSET 10 + +#define GEM_STAT_TITLE(name, title) GEM_STAT_TITLE_BITS(name, title, 0) +#define GEM_STAT_TITLE_BITS(name, title, bits) { \ + .stat_string = title, \ + .offset = GEM_##name, \ + .stat_bits = bits \ +} + +/* list of gem statistic registers. The names MUST match the + * corresponding GEM_* definitions. + */ +static const struct gem_statistic gem_statistics[] = { + GEM_STAT_TITLE(OCTTXL, "tx_octets"), /* OCTTXH combined with OCTTXL */ + GEM_STAT_TITLE(TXCNT, "tx_frames"), + GEM_STAT_TITLE(TXBCCNT, "tx_broadcast_frames"), + GEM_STAT_TITLE(TXMCCNT, "tx_multicast_frames"), + GEM_STAT_TITLE(TXPAUSECNT, "tx_pause_frames"), + GEM_STAT_TITLE(TX64CNT, "tx_64_byte_frames"), + GEM_STAT_TITLE(TX65CNT, "tx_65_127_byte_frames"), + GEM_STAT_TITLE(TX128CNT, "tx_128_255_byte_frames"), + GEM_STAT_TITLE(TX256CNT, "tx_256_511_byte_frames"), + GEM_STAT_TITLE(TX512CNT, "tx_512_1023_byte_frames"), + GEM_STAT_TITLE(TX1024CNT, "tx_1024_1518_byte_frames"), + GEM_STAT_TITLE(TX1519CNT, "tx_greater_than_1518_byte_frames"), + GEM_STAT_TITLE_BITS(TXURUNCNT, "tx_underrun", + GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_TXFIFOERR)), + GEM_STAT_TITLE_BITS(SNGLCOLLCNT, "tx_single_collision_frames", + GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)), + GEM_STAT_TITLE_BITS(MULTICOLLCNT, "tx_multiple_collision_frames", + GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)), + GEM_STAT_TITLE_BITS(EXCESSCOLLCNT, "tx_excessive_collisions", + GEM_BIT(NDS_TXERR)| + GEM_BIT(NDS_TXABORTEDERR)| + GEM_BIT(NDS_COLLISIONS)), + GEM_STAT_TITLE_BITS(LATECOLLCNT, "tx_late_collisions", + GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)), + GEM_STAT_TITLE(TXDEFERCNT, "tx_deferred_frames"), + GEM_STAT_TITLE_BITS(TXCSENSECNT, "tx_carrier_sense_errors", + GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)), + GEM_STAT_TITLE(OCTRXL, "rx_octets"), /* OCTRXH combined with OCTRXL */ + GEM_STAT_TITLE(RXCNT, "rx_frames"), + GEM_STAT_TITLE(RXBROADCNT, "rx_broadcast_frames"), + GEM_STAT_TITLE(RXMULTICNT, "rx_multicast_frames"), + GEM_STAT_TITLE(RXPAUSECNT, "rx_pause_frames"), + GEM_STAT_TITLE(RX64CNT, "rx_64_byte_frames"), + GEM_STAT_TITLE(RX65CNT, "rx_65_127_byte_frames"), + GEM_STAT_TITLE(RX128CNT, "rx_128_255_byte_frames"), + GEM_STAT_TITLE(RX256CNT, "rx_256_511_byte_frames"), + GEM_STAT_TITLE(RX512CNT, "rx_512_1023_byte_frames"), + GEM_STAT_TITLE(RX1024CNT, "rx_1024_1518_byte_frames"), + GEM_STAT_TITLE(RX1519CNT, "rx_greater_than_1518_byte_frames"), + GEM_STAT_TITLE_BITS(RXUNDRCNT, "rx_undersized_frames", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXLENERR)), + GEM_STAT_TITLE_BITS(RXOVRCNT, "rx_oversize_frames", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXLENERR)), + GEM_STAT_TITLE_BITS(RXJABCNT, "rx_jabbers", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXLENERR)), + GEM_STAT_TITLE_BITS(RXFCSCNT, "rx_frame_check_sequence_errors", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXCRCERR)), + GEM_STAT_TITLE_BITS(RXLENGTHCNT, "rx_length_field_frame_errors", + GEM_BIT(NDS_RXERR)), + GEM_STAT_TITLE_BITS(RXSYMBCNT, "rx_symbol_errors", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXFRAMEERR)), + GEM_STAT_TITLE_BITS(RXALIGNCNT, "rx_alignment_errors", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXOVERERR)), + GEM_STAT_TITLE_BITS(RXRESERRCNT, "rx_resource_errors", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXOVERERR)), + GEM_STAT_TITLE_BITS(RXORCNT, "rx_overruns", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXFIFOERR)), + GEM_STAT_TITLE_BITS(RXIPCCNT, "rx_ip_header_checksum_errors", + GEM_BIT(NDS_RXERR)), + GEM_STAT_TITLE_BITS(RXTCPCCNT, "rx_tcp_checksum_errors", + GEM_BIT(NDS_RXERR)), + GEM_STAT_TITLE_BITS(RXUDPCCNT, "rx_udp_checksum_errors", + GEM_BIT(NDS_RXERR)), +}; + +#define GEM_STATS_LEN ARRAY_SIZE(gem_statistics) + struct macb; struct macb_or_gem_ops { @@ -728,6 +982,8 @@ struct macb { dma_addr_t skb_physaddr; /* phys addr from pci_map_single */ int skb_length; /* saved skb length for pci_unmap_single */ unsigned int max_tx_length; + + u64 ethtool_stats[GEM_STATS_LEN]; }; extern const struct ethtool_ops macb_ethtool_ops; -- cgit v1.2.1 From 4a841ee928f430e466cf8e7ea8ad08eb13b1377c Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Wed, 14 Jan 2015 14:34:13 +0800 Subject: net: hisilicon: new hip04 MDIO driver Hisilicon hip04 platform mdio driver Reuse Marvell phy drivers/net/phy/marvell.c Signed-off-by: Zhangfei Gao Signed-off-by: Ding Tianhong Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/Kconfig | 9 ++ drivers/net/ethernet/hisilicon/Makefile | 1 + drivers/net/ethernet/hisilicon/hip04_mdio.c | 186 ++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 drivers/net/ethernet/hisilicon/hip04_mdio.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index e9421731b05e..a54d89791311 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -24,4 +24,13 @@ config HIX5HD2_GMAC help This selects the hix5hd2 mac family network device. +config HIP04_ETH + tristate "HISILICON P04 Ethernet support" + select PHYLIB + select MARVELL_PHY + select MFD_SYSCON + ---help--- + If you wish to compile a kernel for a hardware with hisilicon p04 SoC and + want to use the internal ethernet then you should answer Y to this. + endif # NET_VENDOR_HISILICON diff --git a/drivers/net/ethernet/hisilicon/Makefile b/drivers/net/ethernet/hisilicon/Makefile index 9175e84622d4..40115a7e2ed5 100644 --- a/drivers/net/ethernet/hisilicon/Makefile +++ b/drivers/net/ethernet/hisilicon/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_HIX5HD2_GMAC) += hix5hd2_gmac.o +obj-$(CONFIG_HIP04_ETH) += hip04_mdio.o diff --git a/drivers/net/ethernet/hisilicon/hip04_mdio.c b/drivers/net/ethernet/hisilicon/hip04_mdio.c new file mode 100644 index 000000000000..b3bac25db99c --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hip04_mdio.c @@ -0,0 +1,186 @@ +/* Copyright (c) 2014 Linaro Ltd. + * Copyright (c) 2014 Hisilicon Limited. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#define MDIO_CMD_REG 0x0 +#define MDIO_ADDR_REG 0x4 +#define MDIO_WDATA_REG 0x8 +#define MDIO_RDATA_REG 0xc +#define MDIO_STA_REG 0x10 + +#define MDIO_START BIT(14) +#define MDIO_R_VALID BIT(1) +#define MDIO_READ (BIT(12) | BIT(11) | MDIO_START) +#define MDIO_WRITE (BIT(12) | BIT(10) | MDIO_START) + +struct hip04_mdio_priv { + void __iomem *base; +}; + +#define WAIT_TIMEOUT 10 +static int hip04_mdio_wait_ready(struct mii_bus *bus) +{ + struct hip04_mdio_priv *priv = bus->priv; + int i; + + for (i = 0; readl_relaxed(priv->base + MDIO_CMD_REG) & MDIO_START; i++) { + if (i == WAIT_TIMEOUT) + return -ETIMEDOUT; + msleep(20); + } + + return 0; +} + +static int hip04_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct hip04_mdio_priv *priv = bus->priv; + u32 val; + int ret; + + ret = hip04_mdio_wait_ready(bus); + if (ret < 0) + goto out; + + val = regnum | (mii_id << 5) | MDIO_READ; + writel_relaxed(val, priv->base + MDIO_CMD_REG); + + ret = hip04_mdio_wait_ready(bus); + if (ret < 0) + goto out; + + val = readl_relaxed(priv->base + MDIO_STA_REG); + if (val & MDIO_R_VALID) { + dev_err(bus->parent, "SMI bus read not valid\n"); + ret = -ENODEV; + goto out; + } + + val = readl_relaxed(priv->base + MDIO_RDATA_REG); + ret = val & 0xFFFF; +out: + return ret; +} + +static int hip04_mdio_write(struct mii_bus *bus, int mii_id, + int regnum, u16 value) +{ + struct hip04_mdio_priv *priv = bus->priv; + u32 val; + int ret; + + ret = hip04_mdio_wait_ready(bus); + if (ret < 0) + goto out; + + writel_relaxed(value, priv->base + MDIO_WDATA_REG); + val = regnum | (mii_id << 5) | MDIO_WRITE; + writel_relaxed(val, priv->base + MDIO_CMD_REG); +out: + return ret; +} + +static int hip04_mdio_reset(struct mii_bus *bus) +{ + int temp, i; + + for (i = 0; i < PHY_MAX_ADDR; i++) { + hip04_mdio_write(bus, i, 22, 0); + temp = hip04_mdio_read(bus, i, MII_BMCR); + if (temp < 0) + continue; + + temp |= BMCR_RESET; + if (hip04_mdio_write(bus, i, MII_BMCR, temp) < 0) + continue; + } + + mdelay(500); + return 0; +} + +static int hip04_mdio_probe(struct platform_device *pdev) +{ + struct resource *r; + struct mii_bus *bus; + struct hip04_mdio_priv *priv; + int ret; + + bus = mdiobus_alloc_size(sizeof(struct hip04_mdio_priv)); + if (!bus) { + dev_err(&pdev->dev, "Cannot allocate MDIO bus\n"); + return -ENOMEM; + } + + bus->name = "hip04_mdio_bus"; + bus->read = hip04_mdio_read; + bus->write = hip04_mdio_write; + bus->reset = hip04_mdio_reset; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); + bus->parent = &pdev->dev; + priv = bus->priv; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(priv->base)) { + ret = PTR_ERR(priv->base); + goto out_mdio; + } + + ret = of_mdiobus_register(bus, pdev->dev.of_node); + if (ret < 0) { + dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret); + goto out_mdio; + } + + platform_set_drvdata(pdev, bus); + + return 0; + +out_mdio: + mdiobus_free(bus); + return ret; +} + +static int hip04_mdio_remove(struct platform_device *pdev) +{ + struct mii_bus *bus = platform_get_drvdata(pdev); + + mdiobus_unregister(bus); + mdiobus_free(bus); + + return 0; +} + +static const struct of_device_id hip04_mdio_match[] = { + { .compatible = "hisilicon,hip04-mdio" }, + { } +}; +MODULE_DEVICE_TABLE(of, hip04_mdio_match); + +static struct platform_driver hip04_mdio_driver = { + .probe = hip04_mdio_probe, + .remove = hip04_mdio_remove, + .driver = { + .name = "hip04-mdio", + .owner = THIS_MODULE, + .of_match_table = hip04_mdio_match, + }, +}; + +module_platform_driver(hip04_mdio_driver); + +MODULE_DESCRIPTION("HISILICON P04 MDIO interface driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:hip04-mdio"); -- cgit v1.2.1 From a41ea46a9a128abe5210381ba7902f5208096d53 Mon Sep 17 00:00:00 2001 From: dingtianhong Date: Wed, 14 Jan 2015 14:34:14 +0800 Subject: net: hisilicon: new hip04 ethernet driver Support Hisilicon hip04 ethernet driver, including 100M / 1000M controller. The controller has no tx done interrupt, reclaim xmitted buffer in the poll. v13: Fix the problem of alignment parameters for function and checkpatch warming. v12: According Alex's suggestion, modify the changelog and add MODULE_DEVICE_TABLE for hip04 ethernet. v11: Add ethtool support for tx coalecse getting and setting, the xmit_more is not supported for this patch, but I think it could work for hip04, will support it later after some tests for performance better. Here are some performance test results by ping and iperf(add tx_coalesce_frames/users), it looks that the performance and latency is more better by tx_coalesce_frames/usecs. - Before: $ ping 192.168.1.1 ... === 192.168.1.1 ping statistics === 24 packets transmitted, 24 received, 0% packet loss, time 22999ms rtt min/avg/max/mdev = 0.180/0.202/0.403/0.043 ms $ iperf -c 192.168.1.1 ... [ ID] Interval Transfer Bandwidth [ 3] 0.0- 1.0 sec 115 MBytes 945 Mbits/sec - After: $ ping 192.168.1.1 ... === 192.168.1.1 ping statistics === 24 packets transmitted, 24 received, 0% packet loss, time 22999ms rtt min/avg/max/mdev = 0.178/0.190/0.380/0.041 ms $ iperf -c 192.168.1.1 ... [ ID] Interval Transfer Bandwidth [ 3] 0.0- 1.0 sec 115 MBytes 965 Mbits/sec v10: According David Miller and Arnd Bergmann's suggestion, add some modification for v9 version - drop the workqueue - batch cleanup based on tx_coalesce_frames/usecs for better throughput - use a reasonable default tx timeout (200us, could be shorted based on measurements) with a range timer - fix napi poll function return value - use a lockless queue for cleanup Signed-off-by: Zhangfei Gao Signed-off-by: Arnd Bergmann Signed-off-by: Ding Tianhong Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/Makefile | 2 +- drivers/net/ethernet/hisilicon/hip04_eth.c | 969 +++++++++++++++++++++++++++++ 2 files changed, 970 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/hisilicon/hip04_eth.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/Makefile b/drivers/net/ethernet/hisilicon/Makefile index 40115a7e2ed5..6c14540a4dc5 100644 --- a/drivers/net/ethernet/hisilicon/Makefile +++ b/drivers/net/ethernet/hisilicon/Makefile @@ -3,4 +3,4 @@ # obj-$(CONFIG_HIX5HD2_GMAC) += hix5hd2_gmac.o -obj-$(CONFIG_HIP04_ETH) += hip04_mdio.o +obj-$(CONFIG_HIP04_ETH) += hip04_mdio.o hip04_eth.o diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c new file mode 100644 index 000000000000..525214ef5984 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -0,0 +1,969 @@ + +/* Copyright (c) 2014 Linaro Ltd. + * Copyright (c) 2014 Hisilicon Limited. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PPE_CFG_RX_ADDR 0x100 +#define PPE_CFG_POOL_GRP 0x300 +#define PPE_CFG_RX_BUF_SIZE 0x400 +#define PPE_CFG_RX_FIFO_SIZE 0x500 +#define PPE_CURR_BUF_CNT 0xa200 + +#define GE_DUPLEX_TYPE 0x08 +#define GE_MAX_FRM_SIZE_REG 0x3c +#define GE_PORT_MODE 0x40 +#define GE_PORT_EN 0x44 +#define GE_SHORT_RUNTS_THR_REG 0x50 +#define GE_TX_LOCAL_PAGE_REG 0x5c +#define GE_TRANSMIT_CONTROL_REG 0x60 +#define GE_CF_CRC_STRIP_REG 0x1b0 +#define GE_MODE_CHANGE_REG 0x1b4 +#define GE_RECV_CONTROL_REG 0x1e0 +#define GE_STATION_MAC_ADDRESS 0x210 +#define PPE_CFG_CPU_ADD_ADDR 0x580 +#define PPE_CFG_MAX_FRAME_LEN_REG 0x408 +#define PPE_CFG_BUS_CTRL_REG 0x424 +#define PPE_CFG_RX_CTRL_REG 0x428 +#define PPE_CFG_RX_PKT_MODE_REG 0x438 +#define PPE_CFG_QOS_VMID_GEN 0x500 +#define PPE_CFG_RX_PKT_INT 0x538 +#define PPE_INTEN 0x600 +#define PPE_INTSTS 0x608 +#define PPE_RINT 0x604 +#define PPE_CFG_STS_MODE 0x700 +#define PPE_HIS_RX_PKT_CNT 0x804 + +/* REG_INTERRUPT */ +#define RCV_INT BIT(10) +#define RCV_NOBUF BIT(8) +#define RCV_DROP BIT(7) +#define TX_DROP BIT(6) +#define DEF_INT_ERR (RCV_NOBUF | RCV_DROP | TX_DROP) +#define DEF_INT_MASK (RCV_INT | DEF_INT_ERR) + +/* TX descriptor config */ +#define TX_FREE_MEM BIT(0) +#define TX_READ_ALLOC_L3 BIT(1) +#define TX_FINISH_CACHE_INV BIT(2) +#define TX_CLEAR_WB BIT(4) +#define TX_L3_CHECKSUM BIT(5) +#define TX_LOOP_BACK BIT(11) + +/* RX error */ +#define RX_PKT_DROP BIT(0) +#define RX_L2_ERR BIT(1) +#define RX_PKT_ERR (RX_PKT_DROP | RX_L2_ERR) + +#define SGMII_SPEED_1000 0x08 +#define SGMII_SPEED_100 0x07 +#define SGMII_SPEED_10 0x06 +#define MII_SPEED_100 0x01 +#define MII_SPEED_10 0x00 + +#define GE_DUPLEX_FULL BIT(0) +#define GE_DUPLEX_HALF 0x00 +#define GE_MODE_CHANGE_EN BIT(0) + +#define GE_TX_AUTO_NEG BIT(5) +#define GE_TX_ADD_CRC BIT(6) +#define GE_TX_SHORT_PAD_THROUGH BIT(7) + +#define GE_RX_STRIP_CRC BIT(0) +#define GE_RX_STRIP_PAD BIT(3) +#define GE_RX_PAD_EN BIT(4) + +#define GE_AUTO_NEG_CTL BIT(0) + +#define GE_RX_INT_THRESHOLD BIT(6) +#define GE_RX_TIMEOUT 0x04 + +#define GE_RX_PORT_EN BIT(1) +#define GE_TX_PORT_EN BIT(2) + +#define PPE_CFG_STS_RX_PKT_CNT_RC BIT(12) + +#define PPE_CFG_RX_PKT_ALIGN BIT(18) +#define PPE_CFG_QOS_VMID_MODE BIT(14) +#define PPE_CFG_QOS_VMID_GRP_SHIFT 8 + +#define PPE_CFG_RX_FIFO_FSFU BIT(11) +#define PPE_CFG_RX_DEPTH_SHIFT 16 +#define PPE_CFG_RX_START_SHIFT 0 +#define PPE_CFG_RX_CTRL_ALIGN_SHIFT 11 + +#define PPE_CFG_BUS_LOCAL_REL BIT(14) +#define PPE_CFG_BUS_BIG_ENDIEN BIT(0) + +#define RX_DESC_NUM 128 +#define TX_DESC_NUM 256 +#define TX_NEXT(N) (((N) + 1) & (TX_DESC_NUM-1)) +#define RX_NEXT(N) (((N) + 1) & (RX_DESC_NUM-1)) + +#define GMAC_PPE_RX_PKT_MAX_LEN 379 +#define GMAC_MAX_PKT_LEN 1516 +#define GMAC_MIN_PKT_LEN 31 +#define RX_BUF_SIZE 1600 +#define RESET_TIMEOUT 1000 +#define TX_TIMEOUT (6 * HZ) + +#define DRV_NAME "hip04-ether" +#define DRV_VERSION "v1.0" + +#define HIP04_MAX_TX_COALESCE_USECS 200 +#define HIP04_MIN_TX_COALESCE_USECS 100 +#define HIP04_MAX_TX_COALESCE_FRAMES 200 +#define HIP04_MIN_TX_COALESCE_FRAMES 100 + +struct tx_desc { + u32 send_addr; + u32 send_size; + u32 next_addr; + u32 cfg; + u32 wb_addr; +} __aligned(64); + +struct rx_desc { + u16 reserved_16; + u16 pkt_len; + u32 reserve1[3]; + u32 pkt_err; + u32 reserve2[4]; +}; + +struct hip04_priv { + void __iomem *base; + int phy_mode; + int chan; + unsigned int port; + unsigned int speed; + unsigned int duplex; + unsigned int reg_inten; + + struct napi_struct napi; + struct net_device *ndev; + + struct tx_desc *tx_desc; + dma_addr_t tx_desc_dma; + struct sk_buff *tx_skb[TX_DESC_NUM]; + dma_addr_t tx_phys[TX_DESC_NUM]; + unsigned int tx_head; + + int tx_coalesce_frames; + int tx_coalesce_usecs; + struct hrtimer tx_coalesce_timer; + + unsigned char *rx_buf[RX_DESC_NUM]; + dma_addr_t rx_phys[RX_DESC_NUM]; + unsigned int rx_head; + unsigned int rx_buf_size; + + struct device_node *phy_node; + struct phy_device *phy; + struct regmap *map; + struct work_struct tx_timeout_task; + + /* written only by tx cleanup */ + unsigned int tx_tail ____cacheline_aligned_in_smp; +}; + +static inline unsigned int tx_count(unsigned int head, unsigned int tail) +{ + return (head - tail) % (TX_DESC_NUM - 1); +} + +static void hip04_config_port(struct net_device *ndev, u32 speed, u32 duplex) +{ + struct hip04_priv *priv = netdev_priv(ndev); + u32 val; + + priv->speed = speed; + priv->duplex = duplex; + + switch (priv->phy_mode) { + case PHY_INTERFACE_MODE_SGMII: + if (speed == SPEED_1000) + val = SGMII_SPEED_1000; + else if (speed == SPEED_100) + val = SGMII_SPEED_100; + else + val = SGMII_SPEED_10; + break; + case PHY_INTERFACE_MODE_MII: + if (speed == SPEED_100) + val = MII_SPEED_100; + else + val = MII_SPEED_10; + break; + default: + netdev_warn(ndev, "not supported mode\n"); + val = MII_SPEED_10; + break; + } + writel_relaxed(val, priv->base + GE_PORT_MODE); + + val = duplex ? GE_DUPLEX_FULL : GE_DUPLEX_HALF; + writel_relaxed(val, priv->base + GE_DUPLEX_TYPE); + + val = GE_MODE_CHANGE_EN; + writel_relaxed(val, priv->base + GE_MODE_CHANGE_REG); +} + +static void hip04_reset_ppe(struct hip04_priv *priv) +{ + u32 val, tmp, timeout = 0; + + do { + regmap_read(priv->map, priv->port * 4 + PPE_CURR_BUF_CNT, &val); + regmap_read(priv->map, priv->port * 4 + PPE_CFG_RX_ADDR, &tmp); + if (timeout++ > RESET_TIMEOUT) + break; + } while (val & 0xfff); +} + +static void hip04_config_fifo(struct hip04_priv *priv) +{ + u32 val; + + val = readl_relaxed(priv->base + PPE_CFG_STS_MODE); + val |= PPE_CFG_STS_RX_PKT_CNT_RC; + writel_relaxed(val, priv->base + PPE_CFG_STS_MODE); + + val = BIT(priv->port); + regmap_write(priv->map, priv->port * 4 + PPE_CFG_POOL_GRP, val); + + val = priv->port << PPE_CFG_QOS_VMID_GRP_SHIFT; + val |= PPE_CFG_QOS_VMID_MODE; + writel_relaxed(val, priv->base + PPE_CFG_QOS_VMID_GEN); + + val = RX_BUF_SIZE; + regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_BUF_SIZE, val); + + val = RX_DESC_NUM << PPE_CFG_RX_DEPTH_SHIFT; + val |= PPE_CFG_RX_FIFO_FSFU; + val |= priv->chan << PPE_CFG_RX_START_SHIFT; + regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_FIFO_SIZE, val); + + val = NET_IP_ALIGN << PPE_CFG_RX_CTRL_ALIGN_SHIFT; + writel_relaxed(val, priv->base + PPE_CFG_RX_CTRL_REG); + + val = PPE_CFG_RX_PKT_ALIGN; + writel_relaxed(val, priv->base + PPE_CFG_RX_PKT_MODE_REG); + + val = PPE_CFG_BUS_LOCAL_REL | PPE_CFG_BUS_BIG_ENDIEN; + writel_relaxed(val, priv->base + PPE_CFG_BUS_CTRL_REG); + + val = GMAC_PPE_RX_PKT_MAX_LEN; + writel_relaxed(val, priv->base + PPE_CFG_MAX_FRAME_LEN_REG); + + val = GMAC_MAX_PKT_LEN; + writel_relaxed(val, priv->base + GE_MAX_FRM_SIZE_REG); + + val = GMAC_MIN_PKT_LEN; + writel_relaxed(val, priv->base + GE_SHORT_RUNTS_THR_REG); + + val = readl_relaxed(priv->base + GE_TRANSMIT_CONTROL_REG); + val |= GE_TX_AUTO_NEG | GE_TX_ADD_CRC | GE_TX_SHORT_PAD_THROUGH; + writel_relaxed(val, priv->base + GE_TRANSMIT_CONTROL_REG); + + val = GE_RX_STRIP_CRC; + writel_relaxed(val, priv->base + GE_CF_CRC_STRIP_REG); + + val = readl_relaxed(priv->base + GE_RECV_CONTROL_REG); + val |= GE_RX_STRIP_PAD | GE_RX_PAD_EN; + writel_relaxed(val, priv->base + GE_RECV_CONTROL_REG); + + val = GE_AUTO_NEG_CTL; + writel_relaxed(val, priv->base + GE_TX_LOCAL_PAGE_REG); +} + +static void hip04_mac_enable(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + u32 val; + + /* enable tx & rx */ + val = readl_relaxed(priv->base + GE_PORT_EN); + val |= GE_RX_PORT_EN | GE_TX_PORT_EN; + writel_relaxed(val, priv->base + GE_PORT_EN); + + /* clear rx int */ + val = RCV_INT; + writel_relaxed(val, priv->base + PPE_RINT); + + /* config recv int */ + val = GE_RX_INT_THRESHOLD | GE_RX_TIMEOUT; + writel_relaxed(val, priv->base + PPE_CFG_RX_PKT_INT); + + /* enable interrupt */ + priv->reg_inten = DEF_INT_MASK; + writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); +} + +static void hip04_mac_disable(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + u32 val; + + /* disable int */ + priv->reg_inten &= ~(DEF_INT_MASK); + writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); + + /* disable tx & rx */ + val = readl_relaxed(priv->base + GE_PORT_EN); + val &= ~(GE_RX_PORT_EN | GE_TX_PORT_EN); + writel_relaxed(val, priv->base + GE_PORT_EN); +} + +static void hip04_set_xmit_desc(struct hip04_priv *priv, dma_addr_t phys) +{ + writel(phys, priv->base + PPE_CFG_CPU_ADD_ADDR); +} + +static void hip04_set_recv_desc(struct hip04_priv *priv, dma_addr_t phys) +{ + regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_ADDR, phys); +} + +static u32 hip04_recv_cnt(struct hip04_priv *priv) +{ + return readl(priv->base + PPE_HIS_RX_PKT_CNT); +} + +static void hip04_update_mac_address(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + + writel_relaxed(((ndev->dev_addr[0] << 8) | (ndev->dev_addr[1])), + priv->base + GE_STATION_MAC_ADDRESS); + writel_relaxed(((ndev->dev_addr[2] << 24) | (ndev->dev_addr[3] << 16) | + (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5])), + priv->base + GE_STATION_MAC_ADDRESS + 4); +} + +static int hip04_set_mac_address(struct net_device *ndev, void *addr) +{ + eth_mac_addr(ndev, addr); + hip04_update_mac_address(ndev); + return 0; +} + +static int hip04_tx_reclaim(struct net_device *ndev, bool force) +{ + struct hip04_priv *priv = netdev_priv(ndev); + unsigned tx_tail = priv->tx_tail; + struct tx_desc *desc; + unsigned int bytes_compl = 0, pkts_compl = 0; + unsigned int count; + + smp_rmb(); + count = tx_count(ACCESS_ONCE(priv->tx_head), tx_tail); + if (count == 0) + goto out; + + while (count) { + desc = &priv->tx_desc[tx_tail]; + if (desc->send_addr != 0) { + if (force) + desc->send_addr = 0; + else + break; + } + + if (priv->tx_phys[tx_tail]) { + dma_unmap_single(&ndev->dev, priv->tx_phys[tx_tail], + priv->tx_skb[tx_tail]->len, + DMA_TO_DEVICE); + priv->tx_phys[tx_tail] = 0; + } + pkts_compl++; + bytes_compl += priv->tx_skb[tx_tail]->len; + dev_kfree_skb(priv->tx_skb[tx_tail]); + priv->tx_skb[tx_tail] = NULL; + tx_tail = TX_NEXT(tx_tail); + count--; + } + + priv->tx_tail = tx_tail; + smp_wmb(); /* Ensure tx_tail visible to xmit */ + +out: + if (pkts_compl || bytes_compl) + netdev_completed_queue(ndev, pkts_compl, bytes_compl); + + if (unlikely(netif_queue_stopped(ndev)) && (count < (TX_DESC_NUM - 1))) + netif_wake_queue(ndev); + + return count; +} + +static int hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + unsigned int tx_head = priv->tx_head, count; + struct tx_desc *desc = &priv->tx_desc[tx_head]; + dma_addr_t phys; + + smp_rmb(); + count = tx_count(tx_head, ACCESS_ONCE(priv->tx_tail)); + if (count == (TX_DESC_NUM - 1)) { + netif_stop_queue(ndev); + return NETDEV_TX_BUSY; + } + + phys = dma_map_single(&ndev->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(&ndev->dev, phys)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + priv->tx_skb[tx_head] = skb; + priv->tx_phys[tx_head] = phys; + desc->send_addr = cpu_to_be32(phys); + desc->send_size = cpu_to_be32(skb->len); + desc->cfg = cpu_to_be32(TX_CLEAR_WB | TX_FINISH_CACHE_INV); + phys = priv->tx_desc_dma + tx_head * sizeof(struct tx_desc); + desc->wb_addr = cpu_to_be32(phys); + skb_tx_timestamp(skb); + + hip04_set_xmit_desc(priv, phys); + priv->tx_head = TX_NEXT(tx_head); + count++; + netdev_sent_queue(ndev, skb->len); + + stats->tx_bytes += skb->len; + stats->tx_packets++; + + /* Ensure tx_head update visible to tx reclaim */ + smp_wmb(); + + /* queue is getting full, better start cleaning up now */ + if (count >= priv->tx_coalesce_frames) { + if (napi_schedule_prep(&priv->napi)) { + /* disable rx interrupt and timer */ + priv->reg_inten &= ~(RCV_INT); + writel_relaxed(DEF_INT_MASK & ~RCV_INT, + priv->base + PPE_INTEN); + hrtimer_cancel(&priv->tx_coalesce_timer); + __napi_schedule(&priv->napi); + } + } else if (!hrtimer_is_queued(&priv->tx_coalesce_timer)) { + /* cleanup not pending yet, start a new timer */ + hrtimer_start_expires(&priv->tx_coalesce_timer, + HRTIMER_MODE_REL); + } + + return NETDEV_TX_OK; +} + +static int hip04_rx_poll(struct napi_struct *napi, int budget) +{ + struct hip04_priv *priv = container_of(napi, struct hip04_priv, napi); + struct net_device *ndev = priv->ndev; + struct net_device_stats *stats = &ndev->stats; + unsigned int cnt = hip04_recv_cnt(priv); + struct rx_desc *desc; + struct sk_buff *skb; + unsigned char *buf; + bool last = false; + dma_addr_t phys; + int rx = 0; + int tx_remaining; + u16 len; + u32 err; + + while (cnt && !last) { + buf = priv->rx_buf[priv->rx_head]; + skb = build_skb(buf, priv->rx_buf_size); + if (unlikely(!skb)) + net_dbg_ratelimited("build_skb failed\n"); + + dma_unmap_single(&ndev->dev, priv->rx_phys[priv->rx_head], + RX_BUF_SIZE, DMA_FROM_DEVICE); + priv->rx_phys[priv->rx_head] = 0; + + desc = (struct rx_desc *)skb->data; + len = be16_to_cpu(desc->pkt_len); + err = be32_to_cpu(desc->pkt_err); + + if (0 == len) { + dev_kfree_skb_any(skb); + last = true; + } else if ((err & RX_PKT_ERR) || (len >= GMAC_MAX_PKT_LEN)) { + dev_kfree_skb_any(skb); + stats->rx_dropped++; + stats->rx_errors++; + } else { + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, ndev); + napi_gro_receive(&priv->napi, skb); + stats->rx_packets++; + stats->rx_bytes += len; + rx++; + } + + buf = netdev_alloc_frag(priv->rx_buf_size); + if (!buf) + goto done; + phys = dma_map_single(&ndev->dev, buf, + RX_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&ndev->dev, phys)) + goto done; + priv->rx_buf[priv->rx_head] = buf; + priv->rx_phys[priv->rx_head] = phys; + hip04_set_recv_desc(priv, phys); + + priv->rx_head = RX_NEXT(priv->rx_head); + if (rx >= budget) + goto done; + + if (--cnt == 0) + cnt = hip04_recv_cnt(priv); + } + + if (!(priv->reg_inten & RCV_INT)) { + /* enable rx interrupt */ + priv->reg_inten |= RCV_INT; + writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); + } + napi_complete(napi); +done: + /* clean up tx descriptors and start a new timer if necessary */ + tx_remaining = hip04_tx_reclaim(ndev, false); + if (rx < budget && tx_remaining) + hrtimer_start_expires(&priv->tx_coalesce_timer, HRTIMER_MODE_REL); + + return rx; +} + +static irqreturn_t hip04_mac_interrupt(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct hip04_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + u32 ists = readl_relaxed(priv->base + PPE_INTSTS); + + if (!ists) + return IRQ_NONE; + + writel_relaxed(DEF_INT_MASK, priv->base + PPE_RINT); + + if (unlikely(ists & DEF_INT_ERR)) { + if (ists & (RCV_NOBUF | RCV_DROP)) + stats->rx_errors++; + stats->rx_dropped++; + netdev_err(ndev, "rx drop\n"); + if (ists & TX_DROP) { + stats->tx_dropped++; + netdev_err(ndev, "tx drop\n"); + } + } + + if (ists & RCV_INT && napi_schedule_prep(&priv->napi)) { + /* disable rx interrupt */ + priv->reg_inten &= ~(RCV_INT); + writel_relaxed(DEF_INT_MASK & ~RCV_INT, priv->base + PPE_INTEN); + hrtimer_cancel(&priv->tx_coalesce_timer); + __napi_schedule(&priv->napi); + } + + return IRQ_HANDLED; +} + +enum hrtimer_restart tx_done(struct hrtimer *hrtimer) +{ + struct hip04_priv *priv; + + priv = container_of(hrtimer, struct hip04_priv, tx_coalesce_timer); + + if (napi_schedule_prep(&priv->napi)) { + /* disable rx interrupt */ + priv->reg_inten &= ~(RCV_INT); + writel_relaxed(DEF_INT_MASK & ~RCV_INT, priv->base + PPE_INTEN); + __napi_schedule(&priv->napi); + } + + return HRTIMER_NORESTART; +} + +static void hip04_adjust_link(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + struct phy_device *phy = priv->phy; + + if ((priv->speed != phy->speed) || (priv->duplex != phy->duplex)) { + hip04_config_port(ndev, phy->speed, phy->duplex); + phy_print_status(phy); + } +} + +static int hip04_mac_open(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + int i; + + priv->rx_head = 0; + priv->tx_head = 0; + priv->tx_tail = 0; + hip04_reset_ppe(priv); + + for (i = 0; i < RX_DESC_NUM; i++) { + dma_addr_t phys; + + phys = dma_map_single(&ndev->dev, priv->rx_buf[i], + RX_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&ndev->dev, phys)) + return -EIO; + + priv->rx_phys[i] = phys; + hip04_set_recv_desc(priv, phys); + } + + if (priv->phy) + phy_start(priv->phy); + + netdev_reset_queue(ndev); + netif_start_queue(ndev); + hip04_mac_enable(ndev); + napi_enable(&priv->napi); + + return 0; +} + +static int hip04_mac_stop(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + int i; + + napi_disable(&priv->napi); + netif_stop_queue(ndev); + hip04_mac_disable(ndev); + hip04_tx_reclaim(ndev, true); + hip04_reset_ppe(priv); + + if (priv->phy) + phy_stop(priv->phy); + + for (i = 0; i < RX_DESC_NUM; i++) { + if (priv->rx_phys[i]) { + dma_unmap_single(&ndev->dev, priv->rx_phys[i], + RX_BUF_SIZE, DMA_FROM_DEVICE); + priv->rx_phys[i] = 0; + } + } + + return 0; +} + +static void hip04_timeout(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + + schedule_work(&priv->tx_timeout_task); +} + +static void hip04_tx_timeout_task(struct work_struct *work) +{ + struct hip04_priv *priv; + + priv = container_of(work, struct hip04_priv, tx_timeout_task); + hip04_mac_stop(priv->ndev); + hip04_mac_open(priv->ndev); +} + +static struct net_device_stats *hip04_get_stats(struct net_device *ndev) +{ + return &ndev->stats; +} + +static int hip04_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct hip04_priv *priv = netdev_priv(netdev); + + ec->tx_coalesce_usecs = priv->tx_coalesce_usecs; + ec->tx_max_coalesced_frames = priv->tx_coalesce_frames; + + return 0; +} + +static int hip04_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct hip04_priv *priv = netdev_priv(netdev); + + /* Check not supported parameters */ + if ((ec->rx_max_coalesced_frames) || (ec->rx_coalesce_usecs_irq) || + (ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) || + (ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) || + (ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) || + (ec->rx_max_coalesced_frames_low) || (ec->tx_coalesce_usecs_high) || + (ec->tx_max_coalesced_frames_low) || (ec->pkt_rate_high) || + (ec->tx_coalesce_usecs_low) || (ec->rx_coalesce_usecs_high) || + (ec->rx_max_coalesced_frames_high) || (ec->rx_coalesce_usecs) || + (ec->tx_max_coalesced_frames_irq) || + (ec->stats_block_coalesce_usecs) || + (ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval)) + return -EOPNOTSUPP; + + if ((ec->tx_coalesce_usecs > HIP04_MAX_TX_COALESCE_USECS || + ec->tx_coalesce_usecs < HIP04_MIN_TX_COALESCE_USECS) || + (ec->tx_max_coalesced_frames > HIP04_MAX_TX_COALESCE_FRAMES || + ec->tx_max_coalesced_frames < HIP04_MIN_TX_COALESCE_FRAMES)) + return -EINVAL; + + priv->tx_coalesce_usecs = ec->tx_coalesce_usecs; + priv->tx_coalesce_frames = ec->tx_max_coalesced_frames; + + return 0; +} + +static void hip04_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); +} + +static struct ethtool_ops hip04_ethtool_ops = { + .get_coalesce = hip04_get_coalesce, + .set_coalesce = hip04_set_coalesce, + .get_drvinfo = hip04_get_drvinfo, +}; + +static struct net_device_ops hip04_netdev_ops = { + .ndo_open = hip04_mac_open, + .ndo_stop = hip04_mac_stop, + .ndo_get_stats = hip04_get_stats, + .ndo_start_xmit = hip04_mac_start_xmit, + .ndo_set_mac_address = hip04_set_mac_address, + .ndo_tx_timeout = hip04_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + +static int hip04_alloc_ring(struct net_device *ndev, struct device *d) +{ + struct hip04_priv *priv = netdev_priv(ndev); + int i; + + priv->tx_desc = dma_alloc_coherent(d, + TX_DESC_NUM * sizeof(struct tx_desc), + &priv->tx_desc_dma, GFP_KERNEL); + if (!priv->tx_desc) + return -ENOMEM; + + priv->rx_buf_size = RX_BUF_SIZE + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + for (i = 0; i < RX_DESC_NUM; i++) { + priv->rx_buf[i] = netdev_alloc_frag(priv->rx_buf_size); + if (!priv->rx_buf[i]) + return -ENOMEM; + } + + return 0; +} + +static void hip04_free_ring(struct net_device *ndev, struct device *d) +{ + struct hip04_priv *priv = netdev_priv(ndev); + int i; + + for (i = 0; i < RX_DESC_NUM; i++) + if (priv->rx_buf[i]) + put_page(virt_to_head_page(priv->rx_buf[i])); + + for (i = 0; i < TX_DESC_NUM; i++) + if (priv->tx_skb[i]) + dev_kfree_skb_any(priv->tx_skb[i]); + + dma_free_coherent(d, TX_DESC_NUM * sizeof(struct tx_desc), + priv->tx_desc, priv->tx_desc_dma); +} + +static int hip04_mac_probe(struct platform_device *pdev) +{ + struct device *d = &pdev->dev; + struct device_node *node = d->of_node; + struct of_phandle_args arg; + struct net_device *ndev; + struct hip04_priv *priv; + struct resource *res; + unsigned int irq; + ktime_t txtime; + int ret; + + ndev = alloc_etherdev(sizeof(struct hip04_priv)); + if (!ndev) + return -ENOMEM; + + priv = netdev_priv(ndev); + priv->ndev = ndev; + platform_set_drvdata(pdev, ndev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(d, res); + if (IS_ERR(priv->base)) { + ret = PTR_ERR(priv->base); + goto init_fail; + } + + ret = of_parse_phandle_with_fixed_args(node, "port-handle", 2, 0, &arg); + if (ret < 0) { + dev_warn(d, "no port-handle\n"); + goto init_fail; + } + + priv->port = arg.args[0]; + priv->chan = arg.args[1] * RX_DESC_NUM; + + hrtimer_init(&priv->tx_coalesce_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + + /* BQL will try to keep the TX queue as short as possible, but it can't + * be faster than tx_coalesce_usecs, so we need a fast timeout here, + * but also long enough to gather up enough frames to ensure we don't + * get more interrupts than necessary. + * 200us is enough for 16 frames of 1500 bytes at gigabit ethernet rate + */ + priv->tx_coalesce_frames = TX_DESC_NUM * 3 / 4; + priv->tx_coalesce_usecs = 200; + /* allow timer to fire after half the time at the earliest */ + txtime = ktime_set(0, priv->tx_coalesce_usecs * NSEC_PER_USEC / 2); + hrtimer_set_expires_range(&priv->tx_coalesce_timer, txtime, txtime); + priv->tx_coalesce_timer.function = tx_done; + + priv->map = syscon_node_to_regmap(arg.np); + if (IS_ERR(priv->map)) { + dev_warn(d, "no syscon hisilicon,hip04-ppe\n"); + ret = PTR_ERR(priv->map); + goto init_fail; + } + + priv->phy_mode = of_get_phy_mode(node); + if (priv->phy_mode < 0) { + dev_warn(d, "not find phy-mode\n"); + ret = -EINVAL; + goto init_fail; + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + ret = -EINVAL; + goto init_fail; + } + + ret = devm_request_irq(d, irq, hip04_mac_interrupt, + 0, pdev->name, ndev); + if (ret) { + netdev_err(ndev, "devm_request_irq failed\n"); + goto init_fail; + } + + priv->phy_node = of_parse_phandle(node, "phy-handle", 0); + if (priv->phy_node) { + priv->phy = of_phy_connect(ndev, priv->phy_node, + &hip04_adjust_link, + 0, priv->phy_mode); + if (!priv->phy) { + ret = -EPROBE_DEFER; + goto init_fail; + } + } + + INIT_WORK(&priv->tx_timeout_task, hip04_tx_timeout_task); + + ether_setup(ndev); + ndev->netdev_ops = &hip04_netdev_ops; + ndev->ethtool_ops = &hip04_ethtool_ops; + ndev->watchdog_timeo = TX_TIMEOUT; + ndev->priv_flags |= IFF_UNICAST_FLT; + ndev->irq = irq; + netif_napi_add(ndev, &priv->napi, hip04_rx_poll, NAPI_POLL_WEIGHT); + SET_NETDEV_DEV(ndev, &pdev->dev); + + hip04_reset_ppe(priv); + if (priv->phy_mode == PHY_INTERFACE_MODE_MII) + hip04_config_port(ndev, SPEED_100, DUPLEX_FULL); + + hip04_config_fifo(priv); + random_ether_addr(ndev->dev_addr); + hip04_update_mac_address(ndev); + + ret = hip04_alloc_ring(ndev, d); + if (ret) { + netdev_err(ndev, "alloc ring fail\n"); + goto alloc_fail; + } + + ret = register_netdev(ndev); + if (ret) { + free_netdev(ndev); + goto alloc_fail; + } + + return 0; + +alloc_fail: + hip04_free_ring(ndev, d); +init_fail: + of_node_put(priv->phy_node); + free_netdev(ndev); + return ret; +} + +static int hip04_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct hip04_priv *priv = netdev_priv(ndev); + struct device *d = &pdev->dev; + + if (priv->phy) + phy_disconnect(priv->phy); + + hip04_free_ring(ndev, d); + unregister_netdev(ndev); + free_irq(ndev->irq, ndev); + of_node_put(priv->phy_node); + cancel_work_sync(&priv->tx_timeout_task); + free_netdev(ndev); + + return 0; +} + +static const struct of_device_id hip04_mac_match[] = { + { .compatible = "hisilicon,hip04-mac" }, + { } +}; + +MODULE_DEVICE_TABLE(of, hip04_mac_match); + +static struct platform_driver hip04_mac_driver = { + .probe = hip04_mac_probe, + .remove = hip04_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = hip04_mac_match, + }, +}; +module_platform_driver(hip04_mac_driver); + +MODULE_DESCRIPTION("HISILICON P04 Ethernet driver"); -- cgit v1.2.1 From d823ab68fbb0fa504a2490bd499ac921bdf497d8 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Mon, 12 Jan 2015 12:06:23 +0800 Subject: r8152: replace tasklet with NAPI Replace tasklet with NAPI. Add rx_queue to queue the remaining rx packets if the number of the rx packets is more than the request from poll(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 120 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index e519e6a269b9..2e2244221cbe 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -27,7 +27,7 @@ #include /* Version Information */ -#define DRIVER_VERSION "v1.07.0 (2014/10/09)" +#define DRIVER_VERSION "v1.08.0 (2015/01/13)" #define DRIVER_AUTHOR "Realtek linux nic maintainers " #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" @@ -448,6 +448,7 @@ enum rtl_register_content { #define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN) #define RTL8153_RMS RTL8153_MAX_PACKET #define RTL8152_TX_TIMEOUT (5 * HZ) +#define RTL8152_NAPI_WEIGHT 64 /* rtl8152 flags */ enum rtl8152_flags { @@ -457,7 +458,7 @@ enum rtl8152_flags { RTL8152_LINK_CHG, SELECTIVE_SUSPEND, PHY_RESET, - SCHEDULE_TASKLET, + SCHEDULE_NAPI, }; /* Define these values to match your device */ @@ -549,14 +550,14 @@ struct tx_agg { struct r8152 { unsigned long flags; struct usb_device *udev; - struct tasklet_struct tl; + struct napi_struct napi; struct usb_interface *intf; struct net_device *netdev; struct urb *intr_urb; struct tx_agg tx_info[RTL8152_MAX_TX]; struct rx_agg rx_info[RTL8152_MAX_RX]; struct list_head rx_done, tx_free; - struct sk_buff_head tx_queue; + struct sk_buff_head tx_queue, rx_queue; spinlock_t rx_lock, tx_lock; struct delayed_work schedule; struct mii_if_info mii; @@ -1062,7 +1063,7 @@ static void read_bulk_callback(struct urb *urb) spin_lock(&tp->rx_lock); list_add_tail(&agg->list, &tp->rx_done); spin_unlock(&tp->rx_lock); - tasklet_schedule(&tp->tl); + napi_schedule(&tp->napi); return; case -ESHUTDOWN: set_bit(RTL8152_UNPLUG, &tp->flags); @@ -1126,7 +1127,7 @@ static void write_bulk_callback(struct urb *urb) return; if (!skb_queue_empty(&tp->tx_queue)) - tasklet_schedule(&tp->tl); + napi_schedule(&tp->napi); } static void intr_callback(struct urb *urb) @@ -1245,6 +1246,7 @@ static int alloc_all_mem(struct r8152 *tp) spin_lock_init(&tp->tx_lock); INIT_LIST_HEAD(&tp->tx_free); skb_queue_head_init(&tp->tx_queue); + skb_queue_head_init(&tp->rx_queue); for (i = 0; i < RTL8152_MAX_RX; i++) { buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node); @@ -1649,13 +1651,32 @@ return_result: return checksum; } -static void rx_bottom(struct r8152 *tp) +static int rx_bottom(struct r8152 *tp, int budget) { unsigned long flags; struct list_head *cursor, *next, rx_queue; + int work_done = 0; + + if (!skb_queue_empty(&tp->rx_queue)) { + while (work_done < budget) { + struct sk_buff *skb = __skb_dequeue(&tp->rx_queue); + struct net_device *netdev = tp->netdev; + struct net_device_stats *stats = &netdev->stats; + unsigned int pkt_len; + + if (!skb) + break; + + pkt_len = skb->len; + napi_gro_receive(&tp->napi, skb); + work_done++; + stats->rx_packets++; + stats->rx_bytes += pkt_len; + } + } if (list_empty(&tp->rx_done)) - return; + goto out1; INIT_LIST_HEAD(&rx_queue); spin_lock_irqsave(&tp->rx_lock, flags); @@ -1708,9 +1729,14 @@ static void rx_bottom(struct r8152 *tp) skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, netdev); rtl_rx_vlan_tag(rx_desc, skb); - netif_receive_skb(skb); - stats->rx_packets++; - stats->rx_bytes += pkt_len; + if (work_done < budget) { + napi_gro_receive(&tp->napi, skb); + work_done++; + stats->rx_packets++; + stats->rx_bytes += pkt_len; + } else { + __skb_queue_tail(&tp->rx_queue, skb); + } find_next_rx: rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); @@ -1722,6 +1748,9 @@ find_next_rx: submit: r8152_submit_rx(tp, agg, GFP_ATOMIC); } + +out1: + return work_done; } static void tx_bottom(struct r8152 *tp) @@ -1761,12 +1790,8 @@ static void tx_bottom(struct r8152 *tp) } while (res == 0); } -static void bottom_half(unsigned long data) +static void bottom_half(struct r8152 *tp) { - struct r8152 *tp; - - tp = (struct r8152 *)data; - if (test_bit(RTL8152_UNPLUG, &tp->flags)) return; @@ -1778,12 +1803,28 @@ static void bottom_half(unsigned long data) if (!netif_carrier_ok(tp->netdev)) return; - clear_bit(SCHEDULE_TASKLET, &tp->flags); + clear_bit(SCHEDULE_NAPI, &tp->flags); - rx_bottom(tp); tx_bottom(tp); } +static int r8152_poll(struct napi_struct *napi, int budget) +{ + struct r8152 *tp = container_of(napi, struct r8152, napi); + int work_done; + + work_done = rx_bottom(tp, budget); + bottom_half(tp); + + if (work_done < budget) { + napi_complete(napi); + if (!list_empty(&tp->rx_done)) + napi_schedule(napi); + } + + return work_done; +} + static int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) { @@ -1810,7 +1851,11 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) spin_lock_irqsave(&tp->rx_lock, flags); list_add_tail(&agg->list, &tp->rx_done); spin_unlock_irqrestore(&tp->rx_lock, flags); - tasklet_schedule(&tp->tl); + + netif_err(tp, rx_err, tp->netdev, + "Couldn't submit rx[%p], ret = %d\n", agg, ret); + + napi_schedule(&tp->napi); } return ret; @@ -1929,11 +1974,11 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, if (!list_empty(&tp->tx_free)) { if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - set_bit(SCHEDULE_TASKLET, &tp->flags); + set_bit(SCHEDULE_NAPI, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } else { usb_mark_last_busy(tp->udev); - tasklet_schedule(&tp->tl); + napi_schedule(&tp->napi); } } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) { netif_stop_queue(netdev); @@ -2012,6 +2057,7 @@ static int rtl_start_rx(struct r8152 *tp) { int i, ret = 0; + napi_disable(&tp->napi); INIT_LIST_HEAD(&tp->rx_done); for (i = 0; i < RTL8152_MAX_RX; i++) { INIT_LIST_HEAD(&tp->rx_info[i].list); @@ -2019,6 +2065,7 @@ static int rtl_start_rx(struct r8152 *tp) if (ret) break; } + napi_enable(&tp->napi); if (ret && ++i < RTL8152_MAX_RX) { struct list_head rx_queue; @@ -2049,6 +2096,9 @@ static int rtl_stop_rx(struct r8152 *tp) for (i = 0; i < RTL8152_MAX_RX; i++) usb_kill_urb(tp->rx_info[i].urb); + while (!skb_queue_empty(&tp->rx_queue)) + dev_kfree_skb(__skb_dequeue(&tp->rx_queue)); + return 0; } @@ -2884,9 +2934,9 @@ static void set_carrier(struct r8152 *tp) } else { if (tp->speed & LINK_STATUS) { netif_carrier_off(netdev); - tasklet_disable(&tp->tl); + napi_disable(&tp->napi); tp->rtl_ops.disable(tp); - tasklet_enable(&tp->tl); + napi_enable(&tp->napi); } } tp->speed = speed; @@ -2919,10 +2969,11 @@ static void rtl_work_func_t(struct work_struct *work) if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) _rtl8152_set_rx_mode(tp->netdev); - if (test_bit(SCHEDULE_TASKLET, &tp->flags) && + /* don't schedule napi before linking */ + if (test_bit(SCHEDULE_NAPI, &tp->flags) && (tp->speed & LINK_STATUS)) { - clear_bit(SCHEDULE_TASKLET, &tp->flags); - tasklet_schedule(&tp->tl); + clear_bit(SCHEDULE_NAPI, &tp->flags); + napi_schedule(&tp->napi); } if (test_bit(PHY_RESET, &tp->flags)) @@ -2983,7 +3034,7 @@ static int rtl8152_open(struct net_device *netdev) res); free_all_mem(tp); } else { - tasklet_enable(&tp->tl); + napi_enable(&tp->napi); } mutex_unlock(&tp->control); @@ -2999,7 +3050,7 @@ static int rtl8152_close(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int res = 0; - tasklet_disable(&tp->tl); + napi_disable(&tp->napi); clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); @@ -3008,6 +3059,7 @@ static int rtl8152_close(struct net_device *netdev) res = usb_autopm_get_interface(tp->intf); if (res < 0) { rtl_drop_queued_tx(tp); + rtl_stop_rx(tp); } else { mutex_lock(&tp->control); @@ -3263,7 +3315,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); - tasklet_disable(&tp->tl); + napi_disable(&tp->napi); if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { rtl_stop_rx(tp); rtl_runtime_suspend_enable(tp, true); @@ -3271,7 +3323,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) cancel_delayed_work_sync(&tp->schedule); tp->rtl_ops.down(tp); } - tasklet_enable(&tp->tl); + napi_enable(&tp->napi); } out1: mutex_unlock(&tp->control); @@ -3855,7 +3907,6 @@ static int rtl8152_probe(struct usb_interface *intf, if (ret) goto out; - tasklet_init(&tp->tl, bottom_half, (unsigned long)tp); mutex_init(&tp->control); INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); @@ -3891,6 +3942,7 @@ static int rtl8152_probe(struct usb_interface *intf, set_ethernet_addr(tp); usb_set_intfdata(intf, tp); + netif_napi_add(netdev, &tp->napi, r8152_poll, RTL8152_NAPI_WEIGHT); ret = register_netdev(netdev); if (ret != 0) { @@ -3904,15 +3956,13 @@ static int rtl8152_probe(struct usb_interface *intf, else device_set_wakeup_enable(&udev->dev, false); - tasklet_disable(&tp->tl); - netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); return 0; out1: + netif_napi_del(&tp->napi); usb_set_intfdata(intf, NULL); - tasklet_kill(&tp->tl); out: free_netdev(netdev); return ret; @@ -3929,7 +3979,7 @@ static void rtl8152_disconnect(struct usb_interface *intf) if (udev->state == USB_STATE_NOTATTACHED) set_bit(RTL8152_UNPLUG, &tp->flags); - tasklet_kill(&tp->tl); + netif_napi_del(&tp->napi); unregister_netdev(tp->netdev); tp->rtl_ops.unload(tp); free_netdev(tp->netdev); -- cgit v1.2.1 From a2b12f3c7ac1ea43ae646db74faf0b56c2bba563 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Mon, 12 Jan 2015 17:00:37 -0800 Subject: udp: pass udp_offload struct to UDP gro callbacks This patch introduces udp_offload_callbacks which has the same GRO functions (but not a GSO function) as offload_callbacks, except there is an argument to a udp_offload struct passed to gro_receive and gro_complete functions. This additional argument can be used to retrieve the per port structure of the encapsulation for use in gro processing (mostly by doing container_of on the structure). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 985359dd6033..5c56a3ff25aa 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -539,7 +539,9 @@ static int vxlan_fdb_append(struct vxlan_fdb *f, return 1; } -static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff *skb) +static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, + struct sk_buff *skb, + struct udp_offload *uoff) { struct sk_buff *p, **pp = NULL; struct vxlanhdr *vh, *vh2; @@ -578,7 +580,8 @@ out: return pp; } -static int vxlan_gro_complete(struct sk_buff *skb, int nhoff) +static int vxlan_gro_complete(struct sk_buff *skb, int nhoff, + struct udp_offload *uoff) { udp_tunnel_gro_complete(skb, nhoff); -- cgit v1.2.1 From dfd8645ea1bd91277f841e74c33e1f4dbbede808 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Mon, 12 Jan 2015 17:00:38 -0800 Subject: vxlan: Remote checksum offload Add support for remote checksum offload in VXLAN. This uses a reserved bit to indicate that RCO is being done, and uses the low order reserved eight bits of the VNI to hold the start and offset values in a compressed manner. Start is encoded in the low order seven bits of VNI. This is start >> 1 so that the checksum start offset is 0-254 using even values only. Checksum offset (transport checksum field) is indicated in the high order bit in the low order byte of the VNI. If the bit is set, the checksum field is for UDP (so offset = start + 6), else checksum field is for TCP (so offset = start + 16). Only TCP and UDP are supported in this implementation. Remote checksum offload for VXLAN is described in: https://tools.ietf.org/html/draft-herbert-vxlan-rco-00 Tested by running 200 TCP_STREAM connections with VXLAN (over IPv4). With UDP checksums and Remote Checksum Offload IPv4 Client 11.84% CPU utilization Server 12.96% CPU utilization 9197 Mbps IPv6 Client 12.46% CPU utilization Server 14.48% CPU utilization 8963 Mbps With UDP checksums, no remote checksum offload IPv4 Client 15.67% CPU utilization Server 14.83% CPU utilization 9094 Mbps IPv6 Client 16.21% CPU utilization Server 14.32% CPU utilization 9058 Mbps No UDP checksums IPv4 Client 15.03% CPU utilization Server 23.09% CPU utilization 9089 Mbps IPv6 Client 16.18% CPU utilization Server 26.57% CPU utilization 8954 Mbps Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 185 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 5c56a3ff25aa..99df0d76157c 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -539,6 +539,46 @@ static int vxlan_fdb_append(struct vxlan_fdb *f, return 1; } +static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, + unsigned int off, + struct vxlanhdr *vh, size_t hdrlen, + u32 data) +{ + size_t start, offset, plen; + __wsum delta; + + if (skb->remcsum_offload) + return vh; + + if (!NAPI_GRO_CB(skb)->csum_valid) + return NULL; + + start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT; + offset = start + ((data & VXLAN_RCO_UDP) ? + offsetof(struct udphdr, check) : + offsetof(struct tcphdr, check)); + + plen = hdrlen + offset + sizeof(u16); + + /* Pull checksum that will be written */ + if (skb_gro_header_hard(skb, off + plen)) { + vh = skb_gro_header_slow(skb, off + plen, off); + if (!vh) + return NULL; + } + + delta = remcsum_adjust((void *)vh + hdrlen, + NAPI_GRO_CB(skb)->csum, start, offset); + + /* Adjust skb->csum since we changed the packet */ + skb->csum = csum_add(skb->csum, delta); + NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta); + + skb->remcsum_offload = 1; + + return vh; +} + static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff *skb, struct udp_offload *uoff) @@ -547,6 +587,9 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct vxlanhdr *vh, *vh2; unsigned int hlen, off_vx; int flush = 1; + struct vxlan_sock *vs = container_of(uoff, struct vxlan_sock, + udp_offloads); + u32 flags; off_vx = skb_gro_offset(skb); hlen = off_vx + sizeof(*vh); @@ -557,6 +600,19 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, goto out; } + skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */ + skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr)); + + flags = ntohl(vh->vx_flags); + + if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) { + vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr), + ntohl(vh->vx_vni)); + + if (!vh) + goto out; + } + flush = 0; for (p = *head; p; p = p->next) { @@ -570,8 +626,6 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, } } - skb_gro_pull(skb, sizeof(struct vxlanhdr)); - skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr)); pp = eth_gro_receive(head, skb); out: @@ -1087,6 +1141,42 @@ static void vxlan_igmp_leave(struct work_struct *work) dev_put(vxlan->dev); } +static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, + size_t hdrlen, u32 data) +{ + size_t start, offset, plen; + __wsum delta; + + if (skb->remcsum_offload) { + /* Already processed in GRO path */ + skb->remcsum_offload = 0; + return vh; + } + + start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT; + offset = start + ((data & VXLAN_RCO_UDP) ? + offsetof(struct udphdr, check) : + offsetof(struct tcphdr, check)); + + plen = hdrlen + offset + sizeof(u16); + + if (!pskb_may_pull(skb, plen)) + return NULL; + + vh = (struct vxlanhdr *)(udp_hdr(skb) + 1); + + if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE)) + __skb_checksum_complete(skb); + + delta = remcsum_adjust((void *)vh + hdrlen, + skb->csum, start, offset); + + /* Adjust skb->csum since we changed the packet */ + skb->csum = csum_add(skb->csum, delta); + + return vh; +} + /* Callback from net/ipv4/udp.c to receive packets */ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { @@ -1111,12 +1201,22 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB))) goto drop; + vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1); vs = rcu_dereference_sk_user_data(sk); if (!vs) goto drop; - if (flags || (vni & 0xff)) { + if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) { + vxh = vxlan_remcsum(skb, vxh, sizeof(struct vxlanhdr), vni); + if (!vxh) + goto drop; + + flags &= ~VXLAN_HF_RCO; + vni &= VXLAN_VID_MASK; + } + + if (flags || (vni & ~VXLAN_VID_MASK)) { /* If there are any unprocessed flags remaining treat * this as a malformed packet. This behavior diverges from * VXLAN RFC (RFC7348) which stipulates that bits in reserved @@ -1553,8 +1653,23 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, int min_headroom; int err; bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk); + int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; + u16 hdrlen = sizeof(struct vxlanhdr); + + if ((vs->flags & VXLAN_F_REMCSUM_TX) && + skb->ip_summed == CHECKSUM_PARTIAL) { + int csum_start = skb_checksum_start_offset(skb); + + if (csum_start <= VXLAN_MAX_REMCSUM_START && + !(csum_start & VXLAN_RCO_SHIFT_MASK) && + (skb->csum_offset == offsetof(struct udphdr, check) || + skb->csum_offset == offsetof(struct tcphdr, check))) { + udp_sum = false; + type |= SKB_GSO_TUNNEL_REMCSUM; + } + } - skb = udp_tunnel_handle_offloads(skb, udp_sum); + skb = iptunnel_handle_offloads(skb, udp_sum, type); if (IS_ERR(skb)) { err = -EINVAL; goto err; @@ -1583,6 +1698,22 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, vxh->vx_flags = htonl(VXLAN_HF_VNI); vxh->vx_vni = vni; + if (type & SKB_GSO_TUNNEL_REMCSUM) { + u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> + VXLAN_RCO_SHIFT; + + if (skb->csum_offset == offsetof(struct udphdr, check)) + data |= VXLAN_RCO_UDP; + + vxh->vx_vni |= htonl(data); + vxh->vx_flags |= htonl(VXLAN_HF_RCO); + + if (!skb_is_gso(skb)) { + skb->ip_summed = CHECKSUM_NONE; + skb->encapsulation = 0; + } + } + skb_set_inner_protocol(skb, htons(ETH_P_TEB)); udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio, @@ -1603,8 +1734,23 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, int min_headroom; int err; bool udp_sum = !vs->sock->sk->sk_no_check_tx; + int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; + u16 hdrlen = sizeof(struct vxlanhdr); + + if ((vs->flags & VXLAN_F_REMCSUM_TX) && + skb->ip_summed == CHECKSUM_PARTIAL) { + int csum_start = skb_checksum_start_offset(skb); + + if (csum_start <= VXLAN_MAX_REMCSUM_START && + !(csum_start & VXLAN_RCO_SHIFT_MASK) && + (skb->csum_offset == offsetof(struct udphdr, check) || + skb->csum_offset == offsetof(struct tcphdr, check))) { + udp_sum = false; + type |= SKB_GSO_TUNNEL_REMCSUM; + } + } - skb = udp_tunnel_handle_offloads(skb, udp_sum); + skb = iptunnel_handle_offloads(skb, udp_sum, type); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1627,6 +1773,22 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, vxh->vx_flags = htonl(VXLAN_HF_VNI); vxh->vx_vni = vni; + if (type & SKB_GSO_TUNNEL_REMCSUM) { + u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> + VXLAN_RCO_SHIFT; + + if (skb->csum_offset == offsetof(struct udphdr, check)) + data |= VXLAN_RCO_UDP; + + vxh->vx_vni |= htonl(data); + vxh->vx_flags |= htonl(VXLAN_HF_RCO); + + if (!skb_is_gso(skb)) { + skb->ip_summed = CHECKSUM_NONE; + skb->encapsulation = 0; + } + } + skb_set_inner_protocol(skb, htons(ETH_P_TEB)); return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos, @@ -2218,6 +2380,8 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 }, [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 }, [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 }, + [IFLA_VXLAN_REMCSUM_TX] = { .type = NLA_U8 }, + [IFLA_VXLAN_REMCSUM_RX] = { .type = NLA_U8 }, }; static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -2339,6 +2503,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, atomic_set(&vs->refcnt, 1); vs->rcv = rcv; vs->data = data; + vs->flags = flags; /* Initialize the vxlan udp offloads structure */ vs->udp_offloads.port = port; @@ -2533,6 +2698,14 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])) vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_RX; + if (data[IFLA_VXLAN_REMCSUM_TX] && + nla_get_u8(data[IFLA_VXLAN_REMCSUM_TX])) + vxlan->flags |= VXLAN_F_REMCSUM_TX; + + if (data[IFLA_VXLAN_REMCSUM_RX] && + nla_get_u8(data[IFLA_VXLAN_REMCSUM_RX])) + vxlan->flags |= VXLAN_F_REMCSUM_RX; + if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET, vxlan->dst_port)) { pr_info("duplicate VNI %u\n", vni); @@ -2601,6 +2774,8 @@ static size_t vxlan_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_CSUM */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_TX */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */ 0; } @@ -2666,7 +2841,11 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) || nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, - !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX))) + !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) || + nla_put_u8(skb, IFLA_VXLAN_REMCSUM_TX, + !!(vxlan->flags & VXLAN_F_REMCSUM_TX)) || + nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX, + !!(vxlan->flags & VXLAN_F_REMCSUM_RX))) goto nla_put_failure; if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) -- cgit v1.2.1 From 3511494ce2f3d3b77544c79b87511a4ddb61dc89 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 15 Jan 2015 03:53:55 +0100 Subject: vxlan: Group Policy extension Implements supports for the Group Policy VXLAN extension [0] to provide a lightweight and simple security label mechanism across network peers based on VXLAN. The security context and associated metadata is mapped to/from skb->mark. This allows further mapping to a SELinux context using SECMARK, to implement ACLs directly with nftables, iptables, OVS, tc, etc. The group membership is defined by the lower 16 bits of skb->mark, the upper 16 bits are used for flags. SELinux allows to manage label to secure local resources. However, distributed applications require ACLs to implemented across hosts. This is typically achieved by matching on L2-L4 fields to identify the original sending host and process on the receiver. On top of that, netlabel and specifically CIPSO [1] allow to map security contexts to universal labels. However, netlabel and CIPSO are relatively complex. This patch provides a lightweight alternative for overlay network environments with a trusted underlay. No additional control protocol is required. Host 1: Host 2: Group A Group B Group B Group A +-----+ +-------------+ +-------+ +-----+ | lxc | | SELinux CTX | | httpd | | VM | +--+--+ +--+----------+ +---+---+ +--+--+ \---+---/ \----+---/ | | +---+---+ +---+---+ | vxlan | | vxlan | +---+---+ +---+---+ +------------------------------+ Backwards compatibility: A VXLAN-GBP socket can receive standard VXLAN frames and will assign the default group 0x0000 to such frames. A Linux VXLAN socket will drop VXLAN-GBP frames. The extension is therefore disabled by default and needs to be specifically enabled: ip link add [...] type vxlan [...] gbp In a mixed environment with VXLAN and VXLAN-GBP sockets, the GBP socket must run on a separate port number. Examples: iptables: host1# iptables -I OUTPUT -m owner --uid-owner 101 -j MARK --set-mark 0x200 host2# iptables -I INPUT -m mark --mark 0x200 -j DROP OVS: # ovs-ofctl add-flow br0 'in_port=1,actions=load:0x200->NXM_NX_TUN_GBP_ID[],NORMAL' # ovs-ofctl add-flow br0 'in_port=2,tun_gbp_id=0x200,actions=drop' [0] https://tools.ietf.org/html/draft-smith-vxlan-group-policy [1] http://lwn.net/Articles/204905/ Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 84 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 99df0d76157c..6dbf8e041922 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -620,7 +620,8 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, continue; vh2 = (struct vxlanhdr *)(p->data + off_vx); - if (vh->vx_vni != vh2->vx_vni) { + if (vh->vx_flags != vh2->vx_flags || + vh->vx_vni != vh2->vx_vni) { NAPI_GRO_CB(p)->same_flow = 0; continue; } @@ -1183,6 +1184,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) struct vxlan_sock *vs; struct vxlanhdr *vxh; u32 flags, vni; + struct vxlan_metadata md = {0}; /* Need Vxlan and inner Ethernet header to be present */ if (!pskb_may_pull(skb, VXLAN_HLEN)) @@ -1216,6 +1218,24 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) vni &= VXLAN_VID_MASK; } + /* For backwards compatibility, only allow reserved fields to be + * used by VXLAN extensions if explicitly requested. + */ + if ((flags & VXLAN_HF_GBP) && (vs->flags & VXLAN_F_GBP)) { + struct vxlanhdr_gbp *gbp; + + gbp = (struct vxlanhdr_gbp *)vxh; + md.gbp = ntohs(gbp->policy_id); + + if (gbp->dont_learn) + md.gbp |= VXLAN_GBP_DONT_LEARN; + + if (gbp->policy_applied) + md.gbp |= VXLAN_GBP_POLICY_APPLIED; + + flags &= ~VXLAN_GBP_USED_BITS; + } + if (flags || (vni & ~VXLAN_VID_MASK)) { /* If there are any unprocessed flags remaining treat * this as a malformed packet. This behavior diverges from @@ -1229,7 +1249,8 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) goto bad_flags; } - vs->rcv(vs, skb, vxh->vx_vni); + md.vni = vxh->vx_vni; + vs->rcv(vs, skb, &md); return 0; drop: @@ -1246,8 +1267,8 @@ error: return 1; } -static void vxlan_rcv(struct vxlan_sock *vs, - struct sk_buff *skb, __be32 vx_vni) +static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, + struct vxlan_metadata *md) { struct iphdr *oip = NULL; struct ipv6hdr *oip6 = NULL; @@ -1258,7 +1279,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, int err = 0; union vxlan_addr *remote_ip; - vni = ntohl(vx_vni) >> 8; + vni = ntohl(md->vni) >> 8; /* Is this VNI defined? */ vxlan = vxlan_vs_find_vni(vs, vni); if (!vxlan) @@ -1292,6 +1313,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, goto drop; skb_reset_network_header(skb); + skb->mark = md->gbp; if (oip6) err = IP6_ECN_decapsulate(oip6, skb); @@ -1641,13 +1663,30 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) return false; } +static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, struct vxlan_sock *vs, + struct vxlan_metadata *md) +{ + struct vxlanhdr_gbp *gbp; + + gbp = (struct vxlanhdr_gbp *)vxh; + vxh->vx_flags |= htonl(VXLAN_HF_GBP); + + if (md->gbp & VXLAN_GBP_DONT_LEARN) + gbp->dont_learn = 1; + + if (md->gbp & VXLAN_GBP_POLICY_APPLIED) + gbp->policy_applied = 1; + + gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK); +} + #if IS_ENABLED(CONFIG_IPV6) static int vxlan6_xmit_skb(struct vxlan_sock *vs, struct dst_entry *dst, struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, - __be16 src_port, __be16 dst_port, __be32 vni, - bool xnet) + __be16 src_port, __be16 dst_port, + struct vxlan_metadata *md, bool xnet) { struct vxlanhdr *vxh; int min_headroom; @@ -1696,7 +1735,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_HF_VNI); - vxh->vx_vni = vni; + vxh->vx_vni = md->vni; if (type & SKB_GSO_TUNNEL_REMCSUM) { u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> @@ -1714,6 +1753,9 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, } } + if (vs->flags & VXLAN_F_GBP) + vxlan_build_gbp_hdr(vxh, vs, md); + skb_set_inner_protocol(skb, htons(ETH_P_TEB)); udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio, @@ -1728,7 +1770,8 @@ err: int vxlan_xmit_skb(struct vxlan_sock *vs, struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, - __be16 src_port, __be16 dst_port, __be32 vni, bool xnet) + __be16 src_port, __be16 dst_port, + struct vxlan_metadata *md, bool xnet) { struct vxlanhdr *vxh; int min_headroom; @@ -1771,7 +1814,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_HF_VNI); - vxh->vx_vni = vni; + vxh->vx_vni = md->vni; if (type & SKB_GSO_TUNNEL_REMCSUM) { u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> @@ -1789,6 +1832,9 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, } } + if (vs->flags & VXLAN_F_GBP) + vxlan_build_gbp_hdr(vxh, vs, md); + skb_set_inner_protocol(skb, htons(ETH_P_TEB)); return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos, @@ -1849,6 +1895,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, const struct iphdr *old_iph; struct flowi4 fl4; union vxlan_addr *dst; + struct vxlan_metadata md; __be16 src_port = 0, dst_port; u32 vni; __be16 df = 0; @@ -1919,11 +1966,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + md.vni = htonl(vni << 8); + md.gbp = skb->mark; err = vxlan_xmit_skb(vxlan->vn_sock, rt, skb, fl4.saddr, dst->sin.sin_addr.s_addr, - tos, ttl, df, src_port, dst_port, - htonl(vni << 8), + tos, ttl, df, src_port, dst_port, &md, !net_eq(vxlan->net, dev_net(vxlan->dev))); if (err < 0) { /* skb is already freed. */ @@ -1976,10 +2024,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } ttl = ttl ? : ip6_dst_hoplimit(ndst); + md.vni = htonl(vni << 8); + md.gbp = skb->mark; err = vxlan6_xmit_skb(vxlan->vn_sock, ndst, skb, dev, &fl6.saddr, &fl6.daddr, 0, ttl, - src_port, dst_port, htonl(vni << 8), + src_port, dst_port, &md, !net_eq(vxlan->net, dev_net(vxlan->dev))); #endif } @@ -2382,6 +2432,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 }, [IFLA_VXLAN_REMCSUM_TX] = { .type = NLA_U8 }, [IFLA_VXLAN_REMCSUM_RX] = { .type = NLA_U8 }, + [IFLA_VXLAN_GBP] = { .type = NLA_FLAG, }, }; static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -2706,6 +2757,9 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, nla_get_u8(data[IFLA_VXLAN_REMCSUM_RX])) vxlan->flags |= VXLAN_F_REMCSUM_RX; + if (data[IFLA_VXLAN_GBP]) + vxlan->flags |= VXLAN_F_GBP; + if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET, vxlan->dst_port)) { pr_info("duplicate VNI %u\n", vni); @@ -2851,6 +2905,10 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) goto nla_put_failure; + if (vxlan->flags & VXLAN_F_GBP && + nla_put_flag(skb, IFLA_VXLAN_GBP)) + goto nla_put_failure; + return 0; nla_put_failure: -- cgit v1.2.1 From ac5132d1a03fe1ebbefb2382b36e829dff056283 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 15 Jan 2015 03:53:56 +0100 Subject: vxlan: Only bind to sockets with compatible flags enabled A VXLAN net_device looking for an appropriate socket may only consider a socket which has a matching set of flags/extensions enabled. If incompatible flags are enabled, return a conflict to have the caller create a distinct socket with distinct port. The OVS VXLAN port is kept unaware of extensions at this point. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 6dbf8e041922..6b6b45622a0a 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -263,15 +263,19 @@ static inline struct vxlan_rdst *first_remote_rtnl(struct vxlan_fdb *fdb) return list_first_entry(&fdb->remotes, struct vxlan_rdst, list); } -/* Find VXLAN socket based on network namespace, address family and UDP port */ -static struct vxlan_sock *vxlan_find_sock(struct net *net, - sa_family_t family, __be16 port) +/* Find VXLAN socket based on network namespace, address family and UDP port + * and enabled unshareable flags. + */ +static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family, + __be16 port, u32 flags) { struct vxlan_sock *vs; + u32 match_flags = flags & VXLAN_F_UNSHAREABLE; hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) { if (inet_sk(vs->sock->sk)->inet_sport == port && - inet_sk(vs->sock->sk)->sk.sk_family == family) + inet_sk(vs->sock->sk)->sk.sk_family == family && + (vs->flags & VXLAN_F_UNSHAREABLE) == match_flags) return vs; } return NULL; @@ -291,11 +295,12 @@ static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, u32 id) /* Look up VNI in a per net namespace table */ static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, - sa_family_t family, __be16 port) + sa_family_t family, __be16 port, + u32 flags) { struct vxlan_sock *vs; - vs = vxlan_find_sock(net, family, port); + vs = vxlan_find_sock(net, family, port, flags); if (!vs) return NULL; @@ -1957,7 +1962,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ip_rt_put(rt); dst_vxlan = vxlan_find_vni(vxlan->net, vni, - dst->sa.sa_family, dst_port); + dst->sa.sa_family, dst_port, + vxlan->flags); if (!dst_vxlan) goto tx_error; vxlan_encap_bypass(skb, vxlan, dst_vxlan); @@ -2016,7 +2022,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, dst_release(ndst); dst_vxlan = vxlan_find_vni(vxlan->net, vni, - dst->sa.sa_family, dst_port); + dst->sa.sa_family, dst_port, + vxlan->flags); if (!dst_vxlan) goto tx_error; vxlan_encap_bypass(skb, vxlan, dst_vxlan); @@ -2186,7 +2193,7 @@ static int vxlan_init(struct net_device *dev) spin_lock(&vn->sock_lock); vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET, - vxlan->dst_port); + vxlan->dst_port, vxlan->flags); if (vs && atomic_add_unless(&vs->refcnt, 1, 0)) { /* If we have a socket with same port already, reuse it */ vxlan_vs_add_dev(vs, vxlan); @@ -2593,7 +2600,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, return vs; spin_lock(&vn->sock_lock); - vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port); + vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port, flags); if (vs && ((vs->rcv != rcv) || !atomic_add_unless(&vs->refcnt, 1, 0))) vs = ERR_PTR(-EBUSY); @@ -2761,7 +2768,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, vxlan->flags |= VXLAN_F_GBP; if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET, - vxlan->dst_port)) { + vxlan->dst_port, vxlan->flags)) { pr_info("duplicate VNI %u\n", vni); return -EEXIST; } -- cgit v1.2.1 From 6bf1206289115c277cfa569f570a97ada345a2d5 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 13 Jan 2015 16:30:10 +0200 Subject: ath10k: implement new beacon tx status event This event is delivered to host by firmware if it supports beacon templates only. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 50 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 12 ++++++++ 2 files changed, 62 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 57d2b50c1f00..67138a69bb42 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -58,6 +58,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { = { .min_len = sizeof(struct wlan_host_mem_req) }, [WMI_TLV_TAG_STRUCT_READY_EVENT] = { .min_len = sizeof(struct wmi_tlv_rdy_ev) }, + [WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT] + = { .min_len = sizeof(struct wmi_tlv_bcn_tx_status_ev) }, }; static int @@ -156,6 +158,51 @@ static u16 ath10k_wmi_tlv_len(const void *ptr) return __le16_to_cpu((((const struct wmi_tlv *)ptr) - 1)->len); } +/**************/ +/* TLV events */ +/**************/ +static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_tlv_bcn_tx_status_ev *ev; + u32 vdev_id, tx_status; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + tx_status = __le32_to_cpu(ev->tx_status); + vdev_id = __le32_to_cpu(ev->vdev_id); + + switch (tx_status) { + case WMI_TLV_BCN_TX_STATUS_OK: + break; + case WMI_TLV_BCN_TX_STATUS_XRETRY: + case WMI_TLV_BCN_TX_STATUS_DROP: + case WMI_TLV_BCN_TX_STATUS_FILTERED: + /* FIXME: It's probably worth telling mac80211 to stop the + * interface as it is crippled. + */ + ath10k_warn(ar, "received bcn tmpl tx status on vdev %i: %d", + vdev_id, tx_status); + break; + } + + kfree(tb); + return 0; +} + /***********/ /* TLV ops */ /***********/ @@ -268,6 +315,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID: + ath10k_wmi_tlv_event_bcn_tx_status(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 54ffa120cd60..ee19353ce65c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1375,6 +1375,18 @@ struct wmi_tlv_pktlog_disable { __le32 reserved; } __packed; +enum wmi_tlv_bcn_tx_status { + WMI_TLV_BCN_TX_STATUS_OK, + WMI_TLV_BCN_TX_STATUS_XRETRY, + WMI_TLV_BCN_TX_STATUS_DROP, + WMI_TLV_BCN_TX_STATUS_FILTERED, +}; + +struct wmi_tlv_bcn_tx_status_ev { + __le32 vdev_id; + __le32 tx_status; +} __packed; + void ath10k_wmi_tlv_attach(struct ath10k *ar); #endif -- cgit v1.2.1 From be9ce9d8c196bf150eace10aaf43110672d6eb4c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 13 Jan 2015 16:30:11 +0200 Subject: ath10k: implement beacon template command New firmware revisions may support setting beacon template. Implement wmi interface for it. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 23 +++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 65 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 12 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 3 ++ 4 files changed, 103 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 3a3d15e65e0a..546970259de2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -129,6 +129,10 @@ struct wmi_ops { struct sk_buff *(*gen_delba_send)(struct ath10k *ar, u32 vdev_id, const u8 *mac, u32 tid, u32 initiator, u32 reason); + struct sk_buff *(*gen_bcn_tmpl)(struct ath10k *ar, u32 vdev_id, + u32 tim_ie_offset, struct sk_buff *bcn, + u32 prb_caps, u32 prb_erp, + void *prb_ies, size_t prb_ies_len); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -935,4 +939,23 @@ ath10k_wmi_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, ar->wmi.cmd->delba_send_cmdid); } +static inline int +ath10k_wmi_bcn_tmpl(struct ath10k *ar, u32 vdev_id, u32 tim_ie_offset, + struct sk_buff *bcn, u32 prb_caps, u32 prb_erp, + void *prb_ies, size_t prb_ies_len) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_bcn_tmpl) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_bcn_tmpl(ar, vdev_id, tim_ie_offset, bcn, + prb_caps, prb_erp, prb_ies, + prb_ies_len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->bcn_tmpl_cmdid); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 67138a69bb42..08a9b2b35d06 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1972,6 +1972,70 @@ ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar) return skb; } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_bcn_tmpl(struct ath10k *ar, u32 vdev_id, + u32 tim_ie_offset, struct sk_buff *bcn, + u32 prb_caps, u32 prb_erp, void *prb_ies, + size_t prb_ies_len) +{ + struct wmi_tlv_bcn_tmpl_cmd *cmd; + struct wmi_tlv_bcn_prb_info *info; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + if (WARN_ON(prb_ies_len > 0 && !prb_ies)) + return ERR_PTR(-EINVAL); + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + sizeof(*info) + prb_ies_len + + sizeof(*tlv) + roundup(bcn->len, 4); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->tim_ie_offset = __cpu_to_le32(tim_ie_offset); + cmd->buf_len = __cpu_to_le32(bcn->len); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + /* FIXME: prb_ies_len should be probably aligned to 4byte boundary but + * then it is then impossible to pass original ie len. + * This chunk is not used yet so if setting probe resp template yields + * problems with beaconing or crashes firmware look here. + */ + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_PRB_INFO); + tlv->len = __cpu_to_le16(sizeof(*info) + prb_ies_len); + info = (void *)tlv->value; + info->caps = __cpu_to_le32(prb_caps); + info->erp = __cpu_to_le32(prb_erp); + memcpy(info->ies, prb_ies, prb_ies_len); + + ptr += sizeof(*tlv); + ptr += sizeof(*info); + ptr += prb_ies_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(roundup(bcn->len, 4)); + memcpy(tlv->value, bcn->data, bcn->len); + + /* FIXME: Adjust TSF? */ + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv bcn tmpl vdev_id %i\n", + vdev_id); + return skb; +} + /****************/ /* TLV mappings */ /****************/ @@ -2261,6 +2325,7 @@ static const struct wmi_ops wmi_tlv_ops = { /* .gen_addba_send not implemented */ /* .gen_addba_set_resp not implemented */ /* .gen_delba_send not implemented */ + .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl, }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index ee19353ce65c..c4773652d380 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1387,6 +1387,18 @@ struct wmi_tlv_bcn_tx_status_ev { __le32 tx_status; } __packed; +struct wmi_tlv_bcn_prb_info { + __le32 caps; + __le32 erp; + u8 ies[0]; +} __packed; + +struct wmi_tlv_bcn_tmpl_cmd { + __le32 vdev_id; + __le32 tim_ie_offset; + __le32 buf_len; +} __packed; + void ath10k_wmi_tlv_attach(struct ath10k *ar); #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 2d3c700e2cbb..d37a4859fc2a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5038,6 +5038,7 @@ static const struct wmi_ops wmi_ops = { .gen_addba_send = ath10k_wmi_op_gen_addba_send, .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, .gen_delba_send = ath10k_wmi_op_gen_delba_send, + /* .gen_bcn_tmpl not implemented */ }; static const struct wmi_ops wmi_10_1_ops = { @@ -5096,6 +5097,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_addba_send = ath10k_wmi_op_gen_addba_send, .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, .gen_delba_send = ath10k_wmi_op_gen_delba_send, + /* .gen_bcn_tmpl not implemented */ }; static const struct wmi_ops wmi_10_2_ops = { @@ -5214,6 +5216,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .gen_addba_send = ath10k_wmi_op_gen_addba_send, .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, .gen_delba_send = ath10k_wmi_op_gen_delba_send, + /* .gen_bcn_tmpl not implemented */ }; int ath10k_wmi_attach(struct ath10k *ar) -- cgit v1.2.1 From 4c4955fe4f879fb0bd3bf8630ba23a9811617b59 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 13 Jan 2015 16:30:11 +0200 Subject: ath10k: implement prb tmpl wmi command New firmware revisions with beacon templates need probe templates as well because they don't forward probe requests to host at all. This is required for new firmware to work with direct probe requests (notably required by hidden ssid AP). Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 17 +++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 50 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 5 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 3 ++ 4 files changed, 75 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 546970259de2..7084096c0f62 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -133,6 +133,8 @@ struct wmi_ops { u32 tim_ie_offset, struct sk_buff *bcn, u32 prb_caps, u32 prb_erp, void *prb_ies, size_t prb_ies_len); + struct sk_buff *(*gen_prb_tmpl)(struct ath10k *ar, u32 vdev_id, + struct sk_buff *bcn); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -958,4 +960,19 @@ ath10k_wmi_bcn_tmpl(struct ath10k *ar, u32 vdev_id, u32 tim_ie_offset, return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->bcn_tmpl_cmdid); } +static inline int +ath10k_wmi_prb_tmpl(struct ath10k *ar, u32 vdev_id, struct sk_buff *prb) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_prb_tmpl) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_prb_tmpl(ar, vdev_id, prb); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->prb_tmpl_cmdid); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 08a9b2b35d06..29dc0941cf08 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2036,6 +2036,55 @@ ath10k_wmi_tlv_op_gen_bcn_tmpl(struct ath10k *ar, u32 vdev_id, return skb; } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_prb_tmpl(struct ath10k *ar, u32 vdev_id, + struct sk_buff *prb) +{ + struct wmi_tlv_prb_tmpl_cmd *cmd; + struct wmi_tlv_bcn_prb_info *info; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + sizeof(*info) + + sizeof(*tlv) + roundup(prb->len, 4); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->buf_len = __cpu_to_le32(prb->len); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_PRB_INFO); + tlv->len = __cpu_to_le16(sizeof(*info)); + info = (void *)tlv->value; + info->caps = 0; + info->erp = 0; + + ptr += sizeof(*tlv); + ptr += sizeof(*info); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(roundup(prb->len, 4)); + memcpy(tlv->value, prb->data, prb->len); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv prb tmpl vdev_id %i\n", + vdev_id); + return skb; +} + /****************/ /* TLV mappings */ /****************/ @@ -2326,6 +2375,7 @@ static const struct wmi_ops wmi_tlv_ops = { /* .gen_addba_set_resp not implemented */ /* .gen_delba_send not implemented */ .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl, + .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl, }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index c4773652d380..577251955c04 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1399,6 +1399,11 @@ struct wmi_tlv_bcn_tmpl_cmd { __le32 buf_len; } __packed; +struct wmi_tlv_prb_tmpl_cmd { + __le32 vdev_id; + __le32 buf_len; +} __packed; + void ath10k_wmi_tlv_attach(struct ath10k *ar); #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index d37a4859fc2a..bfa38628cdd0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5039,6 +5039,7 @@ static const struct wmi_ops wmi_ops = { .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, .gen_delba_send = ath10k_wmi_op_gen_delba_send, /* .gen_bcn_tmpl not implemented */ + /* .gen_prb_tmpl not implemented */ }; static const struct wmi_ops wmi_10_1_ops = { @@ -5098,6 +5099,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, .gen_delba_send = ath10k_wmi_op_gen_delba_send, /* .gen_bcn_tmpl not implemented */ + /* .gen_prb_tmpl not implemented */ }; static const struct wmi_ops wmi_10_2_ops = { @@ -5217,6 +5219,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, .gen_delba_send = ath10k_wmi_op_gen_delba_send, /* .gen_bcn_tmpl not implemented */ + /* .gen_prb_tmpl not implemented */ }; int ath10k_wmi_attach(struct ath10k *ar) -- cgit v1.2.1 From 369242b4e3f9d29ddead61895f97a3118484f2f1 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 13 Jan 2015 16:30:11 +0200 Subject: ath10k: implement p2p bcn ie command Along beacon template host is expected to setup p2p information elements as well. Implement wmi interface for it. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 17 +++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 41 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 5 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 3 +++ 4 files changed, 66 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 7084096c0f62..0dd49a7a89f0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -135,6 +135,8 @@ struct wmi_ops { void *prb_ies, size_t prb_ies_len); struct sk_buff *(*gen_prb_tmpl)(struct ath10k *ar, u32 vdev_id, struct sk_buff *bcn); + struct sk_buff *(*gen_p2p_go_bcn_ie)(struct ath10k *ar, u32 vdev_id, + const u8 *p2p_ie); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -975,4 +977,19 @@ ath10k_wmi_prb_tmpl(struct ath10k *ar, u32 vdev_id, struct sk_buff *prb) return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->prb_tmpl_cmdid); } +static inline int +ath10k_wmi_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id, const u8 *p2p_ie) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_p2p_go_bcn_ie) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_p2p_go_bcn_ie(ar, vdev_id, p2p_ie); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->p2p_go_set_beacon_ie); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 29dc0941cf08..6f34fc7d663e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2085,6 +2085,46 @@ ath10k_wmi_tlv_op_gen_prb_tmpl(struct ath10k *ar, u32 vdev_id, return skb; } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id, + const u8 *p2p_ie) +{ + struct wmi_tlv_p2p_go_bcn_ie *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + roundup(p2p_ie[1] + 2, 4); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->ie_len = __cpu_to_le32(p2p_ie[1] + 2); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(roundup(p2p_ie[1] + 2, 4)); + memcpy(tlv->value, p2p_ie, p2p_ie[1] + 2); + + ptr += sizeof(*tlv); + ptr += roundup(p2p_ie[1] + 2, 4); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv p2p go bcn ie for vdev %i\n", + vdev_id); + return skb; +} + /****************/ /* TLV mappings */ /****************/ @@ -2376,6 +2416,7 @@ static const struct wmi_ops wmi_tlv_ops = { /* .gen_delba_send not implemented */ .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl, .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl, + .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie, }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 577251955c04..eb02290075a7 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1404,6 +1404,11 @@ struct wmi_tlv_prb_tmpl_cmd { __le32 buf_len; } __packed; +struct wmi_tlv_p2p_go_bcn_ie { + __le32 vdev_id; + __le32 ie_len; +} __packed; + void ath10k_wmi_tlv_attach(struct ath10k *ar); #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index bfa38628cdd0..5fe17e80bc6b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5040,6 +5040,7 @@ static const struct wmi_ops wmi_ops = { .gen_delba_send = ath10k_wmi_op_gen_delba_send, /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ + /* .gen_p2p_go_bcn_ie not implemented */ }; static const struct wmi_ops wmi_10_1_ops = { @@ -5100,6 +5101,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_delba_send = ath10k_wmi_op_gen_delba_send, /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ + /* .gen_p2p_go_bcn_ie not implemented */ }; static const struct wmi_ops wmi_10_2_ops = { @@ -5220,6 +5222,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .gen_delba_send = ath10k_wmi_op_gen_delba_send, /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ + /* .gen_p2p_go_bcn_ie not implemented */ }; int ath10k_wmi_attach(struct ath10k *ar) -- cgit v1.2.1 From fbb8f1b729b82f2b48350ffc096f107d1a6ea12d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 13 Jan 2015 16:30:12 +0200 Subject: ath10k: implement support for ap beacon offloading New firmware revisions support beacon and probe response templates instead. This means SWBA events are no longer delivered for these firmware revisions. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 162 ++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b403cba0afc1..36dde244b95f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -967,6 +967,143 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) return ret; } +static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif, + struct sk_buff *bcn) +{ + struct ath10k *ar = arvif->ar; + struct ieee80211_mgmt *mgmt; + const u8 *p2p_ie; + int ret; + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP) + return 0; + + if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) + return 0; + + mgmt = (void *)bcn->data; + p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + mgmt->u.beacon.variable, + bcn->len - (mgmt->u.beacon.variable - + bcn->data)); + if (!p2p_ie) + return -ENOENT; + + ret = ath10k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie); + if (ret) { + ath10k_warn(ar, "failed to submit p2p go bcn ie for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + +static int ath10k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, + u8 oui_type, size_t ie_offset) +{ + size_t len; + const u8 *next; + const u8 *end; + u8 *ie; + + if (WARN_ON(skb->len < ie_offset)) + return -EINVAL; + + ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ie_offset, + skb->len - ie_offset); + if (!ie) + return -ENOENT; + + len = ie[1] + 2; + end = skb->data + skb->len; + next = ie + len; + + if (WARN_ON(next > end)) + return -EINVAL; + + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); + + return 0; +} + +static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + struct ieee80211_hw *hw = ar->hw; + struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_mutable_offsets offs = {}; + struct sk_buff *bcn; + int ret; + + if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) + return 0; + + bcn = ieee80211_beacon_get_template(hw, vif, &offs); + if (!bcn) { + ath10k_warn(ar, "failed to get beacon template from mac80211\n"); + return -EPERM; + } + + ret = ath10k_mac_setup_bcn_p2p_ie(arvif, bcn); + if (ret) { + ath10k_warn(ar, "failed to setup p2p go bcn ie: %d\n", ret); + kfree_skb(bcn); + return ret; + } + + /* P2P IE is inserted by firmware automatically (as configured above) + * so remove it from the base beacon template to avoid duplicate P2P + * IEs in beacon frames. + */ + ath10k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + offsetof(struct ieee80211_mgmt, + u.beacon.variable)); + + ret = ath10k_wmi_bcn_tmpl(ar, arvif->vdev_id, offs.tim_offset, bcn, 0, + 0, NULL, 0); + kfree_skb(bcn); + + if (ret) { + ath10k_warn(ar, "failed to submit beacon template command: %d\n", + ret); + return ret; + } + + return 0; +} + +static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + struct ieee80211_hw *hw = ar->hw; + struct ieee80211_vif *vif = arvif->vif; + struct sk_buff *prb; + int ret; + + if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) + return 0; + + prb = ieee80211_proberesp_get(hw, vif); + if (!prb) { + ath10k_warn(ar, "failed to get probe resp template from mac80211\n"); + return -EPERM; + } + + ret = ath10k_wmi_prb_tmpl(ar, arvif->vdev_id, prb); + kfree_skb(prb); + + if (ret) { + ath10k_warn(ar, "failed to submit probe resp template command: %d\n", + ret); + return ret; + } + + return 0; +} + static void ath10k_control_beaconing(struct ath10k_vif *arvif, struct ieee80211_bss_conf *info) { @@ -3283,6 +3420,18 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, if (ret) ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n", arvif->vdev_id, ret); + + ret = ath10k_mac_setup_bcn_tmpl(arvif); + if (ret) + ath10k_warn(ar, "failed to update beacon template: %d\n", + ret); + } + + if (changed & BSS_CHANGED_AP_PROBE_RESP) { + ret = ath10k_mac_setup_prb_tmpl(arvif); + if (ret) + ath10k_warn(ar, "failed to setup probe resp template on vdev %i: %d\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_BEACON_INFO) { @@ -5130,6 +5279,19 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; + if (test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) { + ar->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + + /* Firmware delivers WPS/P2P Probe Requests frames to driver so + * that userspace (e.g. wpa_supplicant/hostapd) can generate + * correct Probe Responses. This is more of a hack advert.. + */ + ar->hw->wiphy->probe_resp_offload |= + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; + } + 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; -- cgit v1.2.1 From 8bdadac13f65c14d7b6df711793eb31ba9db296e Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 13 Jan 2015 14:52:14 +0530 Subject: ath10k: fix duration calculation for quiet param The duty cycle (% of quiet duration) is used to put the device in quiet mode for the given period. Currently the quiet duration is wrongly calculated which results in not enabling quiet mode. Fix the calculation as below duration = (period * duty cycle) / 100 Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index c384c79975ba..41cff50baa41 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -98,7 +98,7 @@ static int ath10k_thermal_set_cur_dutycycle(struct thermal_cooling_device *cdev, } period = max(ATH10K_QUIET_PERIOD_MIN, (ATH10K_QUIET_PERIOD_DEFAULT / num_bss)); - duration = period * (duty_cycle / 100); + duration = (period * duty_cycle) / 100; enabled = duration ? 1 : 0; ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration, -- cgit v1.2.1 From a2fa88003213ea2167545b5306b4d54437b857b7 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 12 Jan 2015 15:29:37 +0100 Subject: ath10k: prevent fw reg dump spam Originally the explicit fw register dump was added to wait_for_target_init because interrupts are masked early during power_up. Due to some changes in power_up/reset sequences sometimes when fw crashed ath10k would print the dump more than once via hif_stop -> warm_reset -> wait_for_target_init, possibly with different values each. Prevent this by doing the explicit fw register dump only during power_up instead of wait_for_target_init. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 5e50214246f8..3b40a86304bf 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1910,6 +1910,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) */ ret = ath10k_pci_chip_reset(ar); if (ret) { + if (ath10k_pci_has_fw_crashed(ar)) { + ath10k_warn(ar, "firmware crashed during chip reset\n"); + ath10k_pci_fw_crashed_clear(ar); + ath10k_pci_fw_crashed_dump(ar); + } + ath10k_err(ar, "failed to reset chip: %d\n", ret); goto err_sleep; } @@ -2352,8 +2358,6 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) if (val & FW_IND_EVENT_PENDING) { ath10k_warn(ar, "device has crashed during init\n"); - ath10k_pci_fw_crashed_clear(ar); - ath10k_pci_fw_crashed_dump(ar); return -ECOMM; } -- cgit v1.2.1 From f6eaf1e063bc0cb8efbd514aaffe5a4ef575ee02 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Jan 2015 16:07:02 -0500 Subject: ath10k: document switch case fall-through in __ath10k_scan_finish Add a comment for indicating that the ATH10K_SCAN_RUNNING case falls through to the ATH10K_SCAN_ABORTING case in __ath10k_scan_finish. This will document that the lack of a break is intentional. Coverity: CID 1260017 Signed-off-by: John W. Linville Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 36dde244b95f..9524bc59997f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2427,6 +2427,7 @@ void __ath10k_scan_finish(struct ath10k *ar) case ATH10K_SCAN_RUNNING: if (ar->scan.is_roc) ieee80211_remain_on_channel_expired(ar->hw); + /* fall through */ case ATH10K_SCAN_ABORTING: if (!ar->scan.is_roc) ieee80211_scan_completed(ar->hw, -- cgit v1.2.1 From 6d48161678dcbeb1ac1736aaf11d10c55ed9a314 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 13 Jan 2015 12:44:24 +0530 Subject: ath10k: fix hwmon temperature input units To be compliant with the hwmon interface the unit needs to be millidegree Celsius. Fix that. Reported-by: Matthias Kaehlcke Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/thermal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index 41cff50baa41..aede750809fe 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -160,7 +160,8 @@ static ssize_t ath10k_thermal_show_temp(struct device *dev, temperature = ar->thermal.temperature; spin_unlock_bh(&ar->data_lock); - ret = snprintf(buf, PAGE_SIZE, "%d", temperature); + /* display in millidegree celcius */ + ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000); out: mutex_unlock(&ar->conf_mutex); return ret; -- cgit v1.2.1 From 2131fabb4b5cb3b167006e83a350704b8c05df2d Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Fri, 19 Dec 2014 06:33:56 +0530 Subject: ath9k: Add HW IDs for QCA956x Signed-off-by: Miaoqing Pan Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ahb.c | 4 ++++ drivers/net/wireless/ath/ath9k/hw.c | 4 ++++ drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/reg.h | 4 ++++ 4 files changed, 13 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index e000c4c27881..bd4a1a655f42 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -43,6 +43,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = { .name = "qca953x_wmac", .driver_data = AR9300_DEVID_AR953X, }, + { + .name = "qca956x_wmac", + .driver_data = AR9300_DEVID_QCA956X, + }, {}, }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 258c4d236cbe..916b370be033 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -246,6 +246,8 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) case AR9300_DEVID_AR953X: ah->hw_version.macVersion = AR_SREV_VERSION_9531; return; + case AR9300_DEVID_QCA956X: + ah->hw_version.macVersion = AR_SREV_VERSION_9561; } val = REG_READ(ah, AR_SREV) & AR_SREV_ID; @@ -539,6 +541,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) case AR_SREV_VERSION_9550: case AR_SREV_VERSION_9565: case AR_SREV_VERSION_9531: + case AR_SREV_VERSION_9561: break; default: ath_err(common, @@ -639,6 +642,7 @@ int ath9k_hw_init(struct ath_hw *ah) case AR9485_DEVID_AR1111: case AR9300_DEVID_AR9565: case AR9300_DEVID_AR953X: + case AR9300_DEVID_QCA956X: break; default: if (common->bus_ops->ath_bus_type == ATH_USB) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 1cbd33551513..64bfcbd9fcec 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -54,6 +54,7 @@ #define AR9485_DEVID_AR1111 0x0037 #define AR9300_DEVID_AR9565 0x0036 #define AR9300_DEVID_AR953X 0x003d +#define AR9300_DEVID_QCA956X 0x003f #define AR5416_AR9100_DEVID 0x000b diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index fb11a9172f38..eb2bb0db297f 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -814,6 +814,7 @@ #define AR_SREV_REVISION_9531_10 0 #define AR_SREV_REVISION_9531_11 1 #define AR_SREV_REVISION_9531_20 2 +#define AR_SREV_VERSION_9561 0x600 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -974,6 +975,9 @@ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_20)) +#define AR_SREV_9561(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9561)) + /* NOTE: When adding chips newer than Peacock, add chip check here */ #define AR_SREV_9580_10_OR_LATER(_ah) \ (AR_SREV_9580(_ah)) -- cgit v1.2.1 From 635d7c50a0ce1930ccf9572d821255cc4c175818 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Fri, 19 Dec 2014 06:33:57 +0530 Subject: ath9k: Add initvals for QCA956x Signed-off-by: Miaoqing Pan Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 61 +- drivers/net/wireless/ath/ath9k/ar956x_initvals.h | 1046 ++++++++++++++++++++++ 2 files changed, 1106 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath9k/ar956x_initvals.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 06ad2172030e..4335ccbe7d7e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -29,6 +29,7 @@ #include "ar9565_1p0_initvals.h" #include "ar9565_1p1_initvals.h" #include "ar953x_initvals.h" +#include "ar956x_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -358,6 +359,40 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesFastClock, qca953x_1p0_modes_fast_clock); + } else if (AR_SREV_9561(ah)) { + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + qca956x_1p0_mac_core); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + qca956x_1p0_mac_postamble); + + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + qca956x_1p0_baseband_core); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + qca956x_1p0_baseband_postamble); + + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + qca956x_1p0_radio_core); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + qca956x_1p0_radio_postamble); + + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + qca956x_1p0_soc_preamble); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + qca956x_1p0_soc_postamble); + + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca956x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca956x_1p0_common_wo_xlna_rx_gain_bounds); + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_tx_gain_table); + + INIT_INI_ARRAY(&ah->ini_dfs, + qca956x_1p0_baseband_postamble_dfs_channel); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + qca956x_1p0_baseband_core_txfir_coeff_japan_2484); + INIT_INI_ARRAY(&ah->iniModesFastClock, + qca956x_1p0_modes_fast_clock); } else if (AR_SREV_9580(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -544,6 +579,9 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) else if (AR_SREV_9531_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, qca953x_2p0_modes_xpa_tx_gain_table); + else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_xpa_tx_gain_table); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_lowest_ob_db_tx_gain_table); @@ -594,7 +632,10 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) else INIT_INI_ARRAY(&ah->iniModesTxGain, qca953x_1p0_modes_no_xpa_tx_gain_table); - } else if (AR_SREV_9462_21(ah)) + } else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_tx_gain_table); + else if (AR_SREV_9462_21(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_2p1_modes_high_ob_db_tx_gain); else if (AR_SREV_9462_20(ah)) @@ -628,6 +669,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah) else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_low_ob_db_tx_gain_table); + else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_low_ob_db_tx_gain_table); else if (AR_SREV_9565_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p1_modes_low_ob_db_tx_gain_table); @@ -699,6 +743,9 @@ static void ar9003_tx_gain_table_mode5(struct ath_hw *ah) else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_type5_tx_gain_table); + else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_green_tx_gain_table); else if (AR_SREV_9300_22(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_type5_tx_gain_table_2p2); @@ -770,6 +817,13 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) qca953x_1p0_common_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, qca953x_1p0_common_rx_gain_bounds); + } else if (AR_SREV_9561(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca956x_1p0_common_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca956x_1p0_common_rx_gain_bounds); + INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna, + qca956x_1p0_xlna_only); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_rx_gain_table); @@ -825,6 +879,11 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) qca953x_2p0_common_wo_xlna_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, qca953x_2p0_common_wo_xlna_rx_gain_bounds); + } else if (AR_SREV_9561(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca956x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca956x_1p0_common_wo_xlna_rx_gain_bounds); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_wo_xlna_rx_gain_table); diff --git a/drivers/net/wireless/ath/ath9k/ar956x_initvals.h b/drivers/net/wireless/ath/ath9k/ar956x_initvals.h new file mode 100644 index 000000000000..c3a47eaaf0c0 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar956x_initvals.h @@ -0,0 +1,1046 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_956X_H +#define INITVALS_956X_H + +#define qca956x_1p0_mac_core ar955x_1p0_mac_core + +#define qca956x_1p0_mac_postamble ar9331_1p1_mac_postamble + +#define qca956x_1p0_soc_preamble ar955x_1p0_soc_preamble + +#define qca956x_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define qca956x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define qca956x_1p0_baseband_postamble_dfs_channel ar9300_2p2_baseband_postamble_dfs_channel + +#define qca956x_1p0_common_wo_xlna_rx_gain_bounds ar955x_1p0_common_wo_xlna_rx_gain_bounds + +#define qca956x_1p0_common_rx_gain_bounds ar955x_1p0_common_rx_gain_bounds + +#define qca956x_1p0_modes_fast_clock ar9462_2p0_modes_fast_clock + +static const u32 qca956x_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x0280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x6400a190}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14000600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840cbf}, + {0x000098bc, 0x00000002}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb514}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x813e4789}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x02993b93}, + {0x0000a20c, 0x00000000}, + {0x0000a218, 0x00000000}, + {0x0000a21c, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a248, 0x00000140}, + {0x0000a2a0, 0x00000007}, + {0x0000a2c0, 0x00000007}, + {0x0000a2c8, 0x00000000}, + {0x0000a2d4, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a360, 0x00000000}, + {0x0000a36c, 0x00000000}, + {0x0000a384, 0x00000001}, + {0x0000a388, 0x00000444}, + {0x0000a38c, 0x00000000}, + {0x0000a390, 0x210d0401}, + {0x0000a394, 0xab9a7144}, + {0x0000a398, 0x00000201}, + {0x0000a39c, 0x42424848}, + {0x0000a3a0, 0x3c466478}, + {0x0000a3a4, 0x3a363600}, + {0x0000a3a8, 0x0000003a}, + {0x0000a3ac, 0x00000000}, + {0x0000a3b0, 0x009011fe}, + {0x0000a3b4, 0x00000034}, + {0x0000a3b8, 0x00b3ec0a}, + {0x0000a3bc, 0x00000036}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000000}, + {0x0000a3f8, 0x0c9bd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d0019ce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00100000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x05000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a454, 0x05000000}, + {0x0000a458, 0x00000000}, + {0x0000a644, 0xbfad9fee}, + {0x0000a648, 0x0048660d}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x21200504}, + {0x0000a678, 0x61602322}, + {0x0000a67c, 0x65646362}, + {0x0000a680, 0x6b6a6968}, + {0x0000a684, 0xe2706d6c}, + {0x0000a688, 0x000000e3}, + {0x0000a690, 0x00000838}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, + {0x0000b8d0, 0x004b6a8e}, + {0x0000b8d4, 0x00000820}, + {0x0000b8dc, 0x00000000}, + {0x0000b8f0, 0x00000000}, + {0x0000b8f4, 0x00000000}, + {0x0000c2d0, 0x00000080}, + {0x0000c2d4, 0x00000000}, + {0x0000c2ec, 0x00000000}, + {0x0000c2f0, 0x00000000}, + {0x0000c2f4, 0x00000000}, + {0x0000c2f8, 0x00000000}, + {0x0000c408, 0x0e79e5c0}, + {0x0000c40c, 0x00820820}, + {0x0000c420, 0x00000000}, +}; + +static const u32 qca956x_1p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac621f1, 0x5ac621f1}, + {0x00009828, 0x06903081, 0x06903081, 0x07d43881, 0x07d43881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000de, 0x6c4000de}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x337d605e, 0x337d5d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003a6, 0x000003a6}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946222, 0xcf946222}, + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x045c0cc4, 0x045c0cc0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, + {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, + {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, + {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001a6, 0x000001a6}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be20, 0x000001b5, 0x000001b5, 0x000001a6, 0x000001a6}, + {0x0000c284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, +}; + +static const u32 qca956x_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x3f80fff8}, + {0x0001604c, 0x000f0278}, + {0x00016050, 0x8036db6c}, + {0x00016054, 0x6db60000}, + {0x00016080, 0x00080000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x14214514}, + {0x0001608c, 0x119f080a}, + {0x00016090, 0x24926490}, + {0x00016094, 0x00000000}, + {0x000160a0, 0xc2108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160b4, 0x92480000}, + {0x000160c0, 0x006db6d8}, + {0x000160c4, 0x24b6db6c}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x6db6fb7c}, + {0x000160d0, 0x6db6da44}, + {0x00016100, 0x07ff8001}, + {0x00016108, 0x00080010}, + {0x00016144, 0x01884080}, + {0x00016148, 0x00008058}, + {0x00016288, 0x001c6000}, + {0x0001628c, 0x50000000}, + {0x000162c0, 0x4b962100}, + {0x000162c4, 0x00000480}, + {0x000162c8, 0x04000144}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00800700}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x3f80fff8}, + {0x0001644c, 0x000f0278}, + {0x00016450, 0x8036db6c}, + {0x00016454, 0x6db60000}, + {0x00016500, 0x07ff8001}, + {0x00016508, 0x00080010}, + {0x00016544, 0x01884080}, + {0x00016548, 0x00008058}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00800700}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, + {0x00016800, 0x36db6db6}, + {0x00016804, 0x6db6db40}, + {0x00016808, 0x73f00000}, + {0x0001680c, 0x00000000}, + {0x00016840, 0x3f80fff8}, + {0x0001684c, 0x000f0278}, + {0x00016850, 0x8036db6c}, + {0x00016854, 0x6db60000}, + {0x00016900, 0x07ff8001}, + {0x00016908, 0x00080010}, + {0x00016944, 0x01884080}, + {0x00016948, 0x00008058}, + {0x00016b80, 0x00000000}, + {0x00016b84, 0x00000000}, + {0x00016b88, 0x00800700}, + {0x00016b8c, 0x00800700}, + {0x00016b90, 0x00800700}, + {0x00016b94, 0x00000000}, + {0x00016b98, 0x00000000}, + {0x00016b9c, 0x00000000}, + {0x00016ba0, 0x00000001}, + {0x00016ba4, 0x00000001}, + {0x00016ba8, 0x00000000}, + {0x00016bac, 0x00000000}, + {0x00016bb0, 0x00000000}, + {0x00016bb4, 0x00000000}, + {0x00016bb8, 0x00000000}, + {0x00016bbc, 0x00000000}, + {0x00016bc0, 0x000000a0}, + {0x00016bc4, 0x000c0000}, + {0x00016bc8, 0x14021402}, + {0x00016bcc, 0x00001402}, + {0x00016bd0, 0x00000000}, + {0x00016bd4, 0x00000000}, +}; + +static const u32 qca956x_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xc4128f5c, 0xc4128f5c}, + {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0fd08f25, 0x0fd08f25}, + {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24646800, 0x24646800}, + {0x000160b0, 0x01885f52, 0x01885f52, 0x00fe7f46, 0x00fe7f46}, + {0x00016104, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001}, + {0x0001610c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016140, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, + {0x00016504, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001}, + {0x0001650c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, + {0x00016904, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001}, + {0x0001690c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016940, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, +}; + +static const u32 qca956x_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { + /* Addr allmodes */ + {0x0000a38c, 0x00000000}, + {0x0000a390, 0x6f7f0301}, + {0x0000a394, 0xca9228ee}, +}; + +static const u32 qca956x_1p0_modes_no_xpa_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x0000a2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000a2e0, 0xff323118, 0xff323118}, + {0x0000a2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000a2e8, 0xffc00000, 0xffc00000}, + {0x0000a39c, 0x42424242, 0x42424242}, + {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00}, + {0x0000a3b0, 0x00a01404, 0x00a01404}, + {0x0000a3b4, 0x00000034, 0x00000034}, + {0x0000a3b8, 0x00800408, 0x00800408}, + {0x0000a3bc, 0x00000036, 0x00000036}, + {0x0000a410, 0x000050dc, 0x000050dc}, + {0x0000a500, 0x09000040, 0x09000040}, + {0x0000a504, 0x0b000041, 0x0b000041}, + {0x0000a508, 0x0d000042, 0x0d000042}, + {0x0000a50c, 0x11000044, 0x11000044}, + {0x0000a510, 0x15000046, 0x15000046}, + {0x0000a514, 0x1d000440, 0x1d000440}, + {0x0000a518, 0x1f000441, 0x1f000441}, + {0x0000a51c, 0x23000443, 0x23000443}, + {0x0000a520, 0x25000444, 0x25000444}, + {0x0000a524, 0x280004e0, 0x280004e0}, + {0x0000a528, 0x2c0004e2, 0x2c0004e2}, + {0x0000a52c, 0x2e0004e3, 0x2e0004e3}, + {0x0000a530, 0x300004e4, 0x300004e4}, + {0x0000a534, 0x340004e6, 0x340004e6}, + {0x0000a538, 0x37000ce0, 0x37000ce0}, + {0x0000a53c, 0x3b000ce2, 0x3b000ce2}, + {0x0000a540, 0x3d000ce3, 0x3d000ce3}, + {0x0000a544, 0x3f000ce4, 0x3f000ce4}, + {0x0000a548, 0x45001ee0, 0x45001ee0}, + {0x0000a54c, 0x49001ee2, 0x49001ee2}, + {0x0000a550, 0x4d001ee4, 0x4d001ee4}, + {0x0000a554, 0x51001ee6, 0x51001ee6}, + {0x0000a558, 0x55001eea, 0x55001eea}, + {0x0000a55c, 0x59001eec, 0x59001eec}, + {0x0000a560, 0x5d001ef0, 0x5d001ef0}, + {0x0000a564, 0x5f001ef1, 0x5f001ef1}, + {0x0000a568, 0x60001ef2, 0x60001ef2}, + {0x0000a56c, 0x61001ef3, 0x61001ef3}, + {0x0000a570, 0x62001ef4, 0x62001ef4}, + {0x0000a574, 0x63001ef5, 0x63001ef5}, + {0x0000a578, 0x64001ffc, 0x64001ffc}, + {0x0000a57c, 0x64001ffc, 0x64001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000}, + {0x0000a614, 0x00804201, 0x00804201}, + {0x0000a618, 0x00804201, 0x00804201}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000b2e0, 0xff323118, 0xff323118}, + {0x0000b2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000b2e8, 0xffc00000, 0xffc00000}, + {0x0000c2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000c2e0, 0xff323118, 0xff323118}, + {0x0000c2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000c2e8, 0xffc00000, 0xffc00000}, + {0x00016044, 0x049242db, 0x049242db}, + {0x00016048, 0x64925a70, 0x64925a70}, + {0x00016148, 0x00008050, 0x00008050}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a6000, 0x453a6000}, + {0x00016444, 0x049242db, 0x049242db}, + {0x00016448, 0x6c925a70, 0x6c925a70}, + {0x00016548, 0x00008050, 0x00008050}, + {0x00016844, 0x049242db, 0x049242db}, + {0x00016848, 0x6c925a70, 0x6c925a70}, + {0x00016948, 0x00008050, 0x00008050}, +}; + +static const u32 qca956x_1p0_modes_xpa_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x0000a2dc, 0xcc69ac94, 0xcc69ac94}, + {0x0000a2e0, 0xf0b23118, 0xf0b23118}, + {0x0000a2e4, 0xffffc000, 0xffffc000}, + {0x0000a2e8, 0xc0000000, 0xc0000000}, + {0x0000a410, 0x000050d2, 0x000050d2}, + {0x0000a500, 0x0a000040, 0x0a000040}, + {0x0000a504, 0x0c000041, 0x0c000041}, + {0x0000a508, 0x0e000042, 0x0e000042}, + {0x0000a50c, 0x12000044, 0x12000044}, + {0x0000a510, 0x16000046, 0x16000046}, + {0x0000a514, 0x1d000440, 0x1d000440}, + {0x0000a518, 0x1f000441, 0x1f000441}, + {0x0000a51c, 0x23000443, 0x23000443}, + {0x0000a520, 0x25000444, 0x25000444}, + {0x0000a524, 0x29000a40, 0x29000a40}, + {0x0000a528, 0x2d000a42, 0x2d000a42}, + {0x0000a52c, 0x2f000a43, 0x2f000a43}, + {0x0000a530, 0x31000a44, 0x31000a44}, + {0x0000a534, 0x35000a46, 0x35000a46}, + {0x0000a538, 0x38000ce0, 0x38000ce0}, + {0x0000a53c, 0x3c000ce2, 0x3c000ce2}, + {0x0000a540, 0x3e000ce3, 0x3e000ce3}, + {0x0000a544, 0x40000ce4, 0x40000ce4}, + {0x0000a548, 0x46001ee0, 0x46001ee0}, + {0x0000a54c, 0x4a001ee2, 0x4a001ee2}, + {0x0000a550, 0x4e001ee4, 0x4e001ee4}, + {0x0000a554, 0x52001ee6, 0x52001ee6}, + {0x0000a558, 0x56001eea, 0x56001eea}, + {0x0000a55c, 0x5a001eec, 0x5a001eec}, + {0x0000a560, 0x5e001ef0, 0x5e001ef0}, + {0x0000a564, 0x60001ef1, 0x60001ef1}, + {0x0000a568, 0x61001ef2, 0x61001ef2}, + {0x0000a56c, 0x62001ef3, 0x62001ef3}, + {0x0000a570, 0x63001ef4, 0x63001ef4}, + {0x0000a574, 0x64001ef5, 0x64001ef5}, + {0x0000a578, 0x65001ffc, 0x65001ffc}, + {0x0000a57c, 0x65001ffc, 0x65001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000}, + {0x0000a614, 0x00000000, 0x00000000}, + {0x0000a618, 0x00000000, 0x00000000}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xcc69ac94, 0xcc69ac94}, + {0x0000b2e0, 0xf0b23118, 0xf0b23118}, + {0x0000b2e4, 0xffffc000, 0xffffc000}, + {0x0000b2e8, 0xc0000000, 0xc0000000}, + {0x0000c2dc, 0xcc69ac94, 0xcc69ac94}, + {0x0000c2e0, 0xf0b23118, 0xf0b23118}, + {0x0000c2e4, 0xffffc000, 0xffffc000}, + {0x0000c2e8, 0xc0000000, 0xc0000000}, + {0x00016044, 0x012492db, 0x012492db}, + {0x00016048, 0x6c927a70, 0x6c927a70}, + {0x00016050, 0x8036d36c, 0x8036d36c}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a7e00, 0x453a7e00}, + {0x00016444, 0x012492db, 0x012492db}, + {0x00016448, 0x6c927a70, 0x6c927a70}, + {0x00016450, 0x8036d36c, 0x8036d36c}, + {0x00016844, 0x012492db, 0x012492db}, + {0x00016848, 0x6c927a70, 0x6c927a70}, + {0x00016850, 0x8036d36c, 0x8036d36c}, +}; + +static const u32 qca956x_1p0_modes_no_xpa_low_ob_db_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x0000a2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000a2e0, 0xff323118, 0xff323118}, + {0x0000a2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000a2e8, 0xffc00000, 0xffc00000}, + {0x0000a39c, 0x42424242, 0x42424242}, + {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00}, + {0x0000a3b0, 0x00a01404, 0x00a01404}, + {0x0000a3b4, 0x00000034, 0x00000034}, + {0x0000a3b8, 0x00800408, 0x00800408}, + {0x0000a3bc, 0x00000036, 0x00000036}, + {0x0000a410, 0x000050dc, 0x000050dc}, + {0x0000a414, 0x16b739ce, 0x16b739ce}, + {0x0000a418, 0x2d00198b, 0x2d00198b}, + {0x0000a41c, 0x16b5adce, 0x16b5adce}, + {0x0000a420, 0x0000014a, 0x0000014a}, + {0x0000a424, 0x14a525cc, 0x14a525cc}, + {0x0000a428, 0x0000012a, 0x0000012a}, + {0x0000a42c, 0x14a5294a, 0x14a5294a}, + {0x0000a430, 0x1294a929, 0x1294a929}, + {0x0000a500, 0x09000040, 0x09000040}, + {0x0000a504, 0x0b000041, 0x0b000041}, + {0x0000a508, 0x0d000042, 0x0d000042}, + {0x0000a50c, 0x11000044, 0x11000044}, + {0x0000a510, 0x15000046, 0x15000046}, + {0x0000a514, 0x1d000440, 0x1d000440}, + {0x0000a518, 0x1f000441, 0x1f000441}, + {0x0000a51c, 0x23000443, 0x23000443}, + {0x0000a520, 0x25000444, 0x25000444}, + {0x0000a524, 0x280004e0, 0x280004e0}, + {0x0000a528, 0x2c0004e2, 0x2c0004e2}, + {0x0000a52c, 0x2e0004e3, 0x2e0004e3}, + {0x0000a530, 0x300004e4, 0x300004e4}, + {0x0000a534, 0x340004e6, 0x340004e6}, + {0x0000a538, 0x37000ce0, 0x37000ce0}, + {0x0000a53c, 0x3b000ce2, 0x3b000ce2}, + {0x0000a540, 0x3d000ce3, 0x3d000ce3}, + {0x0000a544, 0x3f000ce4, 0x3f000ce4}, + {0x0000a548, 0x45001ee0, 0x45001ee0}, + {0x0000a54c, 0x49001ee2, 0x49001ee2}, + {0x0000a550, 0x4d001ee4, 0x4d001ee4}, + {0x0000a554, 0x51001ee6, 0x51001ee6}, + {0x0000a558, 0x55001eea, 0x55001eea}, + {0x0000a55c, 0x59001eec, 0x59001eec}, + {0x0000a560, 0x5d001ef0, 0x5d001ef0}, + {0x0000a564, 0x5f001ef1, 0x5f001ef1}, + {0x0000a568, 0x60001ef2, 0x60001ef2}, + {0x0000a56c, 0x61001ef3, 0x61001ef3}, + {0x0000a570, 0x62001ef4, 0x62001ef4}, + {0x0000a574, 0x63001ef5, 0x63001ef5}, + {0x0000a578, 0x64001ffc, 0x64001ffc}, + {0x0000a57c, 0x64001ffc, 0x64001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000}, + {0x0000a614, 0x00804201, 0x00804201}, + {0x0000a618, 0x00804201, 0x00804201}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000b2e0, 0xff323118, 0xff323118}, + {0x0000b2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000b2e8, 0xffc00000, 0xffc00000}, + {0x0000c2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000c2e0, 0xff323118, 0xff323118}, + {0x0000c2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000c2e8, 0xffc00000, 0xffc00000}, + {0x00016044, 0x046e42db, 0x046e42db}, + {0x00016048, 0x64925a70, 0x64925a70}, + {0x00016148, 0x00008050, 0x00008050}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a6000, 0x453a6000}, + {0x00016444, 0x046e42db, 0x046e42db}, + {0x00016448, 0x6c925a70, 0x6c925a70}, + {0x00016548, 0x00008050, 0x00008050}, + {0x00016844, 0x046e42db, 0x046e42db}, + {0x00016848, 0x6c925a70, 0x6c925a70}, + {0x00016948, 0x00008050, 0x00008050}, +}; + +static const u32 qca956x_1p0_modes_no_xpa_green_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x000098bc, 0x00000001, 0x00000001}, + {0x0000a2dc, 0xd3555284, 0xd3555284}, + {0x0000a2e0, 0x1c666318, 0x1c666318}, + {0x0000a2e4, 0xe07bbc00, 0xe07bbc00}, + {0x0000a2e8, 0xff800000, 0xff800000}, + {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00}, + {0x0000a410, 0x000050dc, 0x000050dc}, + {0x0000a500, 0x02000040, 0x02000040}, + {0x0000a504, 0x04000041, 0x04000041}, + {0x0000a508, 0x06000042, 0x06000042}, + {0x0000a50c, 0x0a000044, 0x0a000044}, + {0x0000a510, 0x0c000045, 0x0c000045}, + {0x0000a514, 0x13000440, 0x13000440}, + {0x0000a518, 0x15000441, 0x15000441}, + {0x0000a51c, 0x19000443, 0x19000443}, + {0x0000a520, 0x1b000444, 0x1b000444}, + {0x0000a524, 0x1e0004e0, 0x1e0004e0}, + {0x0000a528, 0x220004e2, 0x220004e2}, + {0x0000a52c, 0x240004e3, 0x240004e3}, + {0x0000a530, 0x260004e4, 0x260004e4}, + {0x0000a534, 0x2a0004e6, 0x2a0004e6}, + {0x0000a538, 0x32000ce0, 0x32000ce0}, + {0x0000a53c, 0x36000ce2, 0x36000ce2}, + {0x0000a540, 0x3a000ce4, 0x3a000ce4}, + {0x0000a544, 0x3e000ce6, 0x3e000ce6}, + {0x0000a548, 0x45001ee0, 0x45001ee0}, + {0x0000a54c, 0x49001ee2, 0x49001ee2}, + {0x0000a550, 0x4d001ee4, 0x4d001ee4}, + {0x0000a554, 0x51001ee6, 0x51001ee6}, + {0x0000a558, 0x55001eea, 0x55001eea}, + {0x0000a55c, 0x59001eec, 0x59001eec}, + {0x0000a560, 0x5d001ef0, 0x5d001ef0}, + {0x0000a564, 0x5f001ef1, 0x5f001ef1}, + {0x0000a568, 0x60001ef2, 0x60001ef2}, + {0x0000a56c, 0x61001ef3, 0x61001ef3}, + {0x0000a570, 0x62001ef4, 0x62001ef4}, + {0x0000a574, 0x63001ff5, 0x63001ff5}, + {0x0000a578, 0x64001ffc, 0x64001ffc}, + {0x0000a57c, 0x64001ffc, 0x64001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000}, + {0x0000a614, 0x00804201, 0x00804201}, + {0x0000a618, 0x00804201, 0x00804201}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xd3555284, 0xd3555284}, + {0x0000b2e0, 0x1c666318, 0x1c666318}, + {0x0000b2e4, 0xe07bbc00, 0xe07bbc00}, + {0x0000b2e8, 0xff800000, 0xff800000}, + {0x0000c2dc, 0xd3555284, 0xd3555284}, + {0x0000c2e0, 0x1c666318, 0x1c666318}, + {0x0000c2e4, 0xe07bbc00, 0xe07bbc00}, + {0x0000c2e8, 0xff800000, 0xff800000}, + {0x00016044, 0x849242db, 0x849242db}, + {0x00016048, 0x64925a70, 0x64925a70}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a6000, 0x453a6000}, + {0x00016444, 0x849242db, 0x849242db}, + {0x00016448, 0x6c925a70, 0x6c925a70}, + {0x00016844, 0x849242db, 0x849242db}, + {0x00016848, 0x6c925a70, 0x6c925a70}, + {0x0000a7f0, 0x800002cc, 0x800002cc}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, +}; + +static const u32 qca956x_1p0_common_rx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x22222222}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x17171717}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x23232323}, + {0x0000b084, 0x21232323}, + {0x0000b088, 0x19191c1e}, + {0x0000b08c, 0x12141417}, + {0x0000b090, 0x07070e0e}, + {0x0000b094, 0x03030305}, + {0x0000b098, 0x00000003}, + {0x0000b09c, 0x00000000}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 qca956x_1p0_xlna_only[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac621f1, 0x5ac621f1}, + {0x00009828, 0x06903081, 0x06903081, 0x07d43881, 0x07d43881}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x03721720}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000de, 0x6c4000da}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec86d2e, 0x7ec8ad2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x317a6062, 0x317a5ae2}, + {0x00009e18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003b2, 0x000003b2}, + {0x00009fc0, 0x813e4788, 0x813e4788, 0x813e4789, 0x813e4789}, + {0x0000ae18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001b2, 0x000001b2}, + {0x0000be18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000}, + {0x0000be20, 0x000001b5, 0x000001b5, 0x000001b2, 0x000001b2}, +}; + +#endif /* INITVALS_956X_H */ -- cgit v1.2.1 From df476df180bccb530b7c0db77bd9a9cde6451ff6 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Fri, 19 Dec 2014 06:33:58 +0530 Subject: ath9k: Fix register definitions for QCA956x Signed-off-by: Miaoqing Pan Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index fd090b1f2d0f..c311b2bfdb00 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -454,7 +454,7 @@ #define AR_PHY_GEN_CTRL (AR_SM_BASE + 0x4) #define AR_PHY_MODE (AR_SM_BASE + 0x8) #define AR_PHY_ACTIVE (AR_SM_BASE + 0xc) -#define AR_PHY_SPUR_MASK_A (AR_SM_BASE + 0x20) +#define AR_PHY_SPUR_MASK_A (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x18 : 0x20)) #define AR_PHY_SPUR_MASK_B (AR_SM_BASE + 0x24) #define AR_PHY_SPECTRAL_SCAN (AR_SM_BASE + 0x28) #define AR_PHY_RADAR_BW_FILTER (AR_SM_BASE + 0x2c) @@ -506,7 +506,7 @@ #define AR_PHY_TEST_CHAIN_SEL 0xC0000000 #define AR_PHY_TEST_CHAIN_SEL_S 30 -#define AR_PHY_TEST_CTL_STATUS (AR_SM_BASE + 0x164) +#define AR_PHY_TEST_CTL_STATUS (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x160 : 0x164)) #define AR_PHY_TEST_CTL_TSTDAC_EN 0x1 #define AR_PHY_TEST_CTL_TSTDAC_EN_S 0 #define AR_PHY_TEST_CTL_TX_OBS_SEL 0x1C @@ -525,7 +525,7 @@ #define AR_PHY_CHAN_STATUS (AR_SM_BASE + 0x16c) -#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + 0x170) +#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x16c : 0x170)) #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ 0x00000008 #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S 3 @@ -536,7 +536,7 @@ #define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + 0x190) #define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + 0x194) -#define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + 0x1a4) +#define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x198 : 0x1a4)) #define AR_PHY_HEAVYCLIP_20 (AR_SM_BASE + 0x1a8) #define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac) #define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0) @@ -726,21 +726,24 @@ #define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ (AR_SREV_9462(ah) ? 0x16290 : 0x16284)) -#define AR_CH0_TOP2_XPABIASLVL 0xf000 +#define AR_CH0_TOP2_XPABIASLVL (AR_SREV_9561(ah) ? 0x1e00 : 0xf000) #define AR_CH0_TOP2_XPABIASLVL_S 12 #define AR_CH0_XTAL (AR_SREV_9300(ah) ? 0x16294 : \ - ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : 0x16290)) + ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : \ + (AR_SREV_9561(ah) ? 0x162c0 : 0x16290))) #define AR_CH0_XTAL_CAPINDAC 0x7f000000 #define AR_CH0_XTAL_CAPINDAC_S 24 #define AR_CH0_XTAL_CAPOUTDAC 0x00fe0000 #define AR_CH0_XTAL_CAPOUTDAC_S 17 -#define AR_PHY_PMU1 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16340 : 0x16c40) +#define AR_PHY_PMU1 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16340 : \ + (AR_SREV_9561(ah) ? 0x16cc0 : 0x16c40)) #define AR_PHY_PMU1_PWD 0x1 #define AR_PHY_PMU1_PWD_S 0 -#define AR_PHY_PMU2 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16344 : 0x16c44) +#define AR_PHY_PMU2 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16344 : \ + (AR_SREV_9561(ah) ? 0x16cc4 : 0x16c44)) #define AR_PHY_PMU2_PGM 0x00200000 #define AR_PHY_PMU2_PGM_S 21 -- cgit v1.2.1 From ede6a5e7b8596f85607b9bd15f186d2b26163bc8 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Fri, 19 Dec 2014 06:33:59 +0530 Subject: ath9k: Add QCA956x HW support Signed-off-by: Miaoqing Pan Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ani.c | 3 +- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 15 +++++--- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 47 ++++++++++++++++++++------ drivers/net/wireless/ath/ath9k/hw.c | 37 ++++++++++++-------- drivers/net/wireless/ath/ath9k/mac.c | 3 +- drivers/net/wireless/ath/ath9k/recv.c | 3 +- 6 files changed, 76 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index ba502a2d199b..ca01d17d130f 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -259,7 +259,8 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, entry_cck->fir_step_level); /* Skip MRC CCK for pre AR9003 families */ - if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) + if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) || + AR_SREV_9565(ah) || AR_SREV_9561(ah)) return; if (aniState->mrcCCK != entry_cck->mrc_cck_on) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 08225a0067c2..8b4561e8ce1a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3536,7 +3536,7 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) int bias = ar9003_modal_header(ah, is2ghz)->xpaBiasLvl; if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah) || - AR_SREV_9531(ah)) + AR_SREV_9531(ah) || AR_SREV_9561(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); else if (AR_SREV_9462(ah) || AR_SREV_9550(ah) || AR_SREV_9565(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); @@ -3599,7 +3599,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9462_ALL, value); - } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) { REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9550_ALL, value); } else @@ -3929,9 +3929,13 @@ void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set); if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set)) return; - } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah) || + AR_SREV_9561(ah)) { reg_val = le32_to_cpu(pBase->swreg); REG_WRITE(ah, AR_PHY_PMU1, reg_val); + + if (AR_SREV_9561(ah)) + REG_WRITE(ah, AR_PHY_PMU2, 0x10200000); } else { /* Internal regulator is ON. Write swreg register. */ reg_val = le32_to_cpu(pBase->swreg); @@ -4034,7 +4038,8 @@ static void ar9003_hw_xpa_timing_control_apply(struct ath_hw *ah, bool is2ghz) if (!AR_SREV_9300(ah) && !AR_SREV_9340(ah) && !AR_SREV_9580(ah) && - !AR_SREV_9531(ah)) + !AR_SREV_9531(ah) && + !AR_SREV_9561(ah)) return; xpa_ctl = ar9003_modal_header(ah, is2ghz)->txFrameToXpaOn; @@ -4812,7 +4817,7 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah, } tempslope: - if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) { u8 txmask = (eep->baseEepHeader.txrxMask & 0xf0) >> 4; /* diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index ae6cde273414..1ad66b76749b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -183,7 +183,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) } else { channelSel = CHANSEL_2G(freq) >> 1; } - } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) { if (ah->is_clk_25mhz) div = 75; else @@ -198,7 +199,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) /* Set to 2G mode */ bMode = 1; } else { - if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) && + if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || + AR_SREV_9531(ah) || AR_SREV_9561(ah)) && ah->is_clk_25mhz) { channelSel = freq / 75; chan_frac = ((freq % 75) * 0x20000) / 75; @@ -265,7 +267,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, */ if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || - AR_SREV_9550(ah)) { + AR_SREV_9550(ah) || AR_SREV_9561(ah)) { if (spur_fbin_ptr[0] == 0) /* No spur */ return; max_spur_cnts = 5; @@ -292,7 +294,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, negative = 0; if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || - AR_SREV_9550(ah)) + AR_SREV_9550(ah) || AR_SREV_9561(ah)) cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i], IS_CHAN_2GHZ(chan)); else @@ -641,8 +643,10 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah, (REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO); /* Enable 11n HT, 20 MHz */ - phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | - AR_PHY_GC_SHORT_GI_40 | enableDacFifo; + phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SHORT_GI_40 | enableDacFifo; + + if (!AR_SREV_9561(ah)) + phymode |= AR_PHY_GC_SINGLE_HT_LTF1; /* Configure baseband for dynamic 20/40 operation */ if (IS_CHAN_HT40(chan)) { @@ -745,7 +749,8 @@ static void ar9003_hw_override_ini(struct ath_hw *ah) else ah->enabled_cals &= ~TX_CL_CAL; - if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) { + if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah) || + AR_SREV_9561(ah)) { if (ah->is_clk_25mhz) { REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); @@ -812,6 +817,19 @@ static int ar9550_hw_get_modes_txgain_index(struct ath_hw *ah, return ret; } +static int ar9561_hw_get_modes_txgain_index(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + if (IS_CHAN_2GHZ(chan)) { + if (IS_CHAN_HT40(chan)) + return 1; + else + return 2; + } + + return 0; +} + static void ar9003_doubler_fix(struct ath_hw *ah) { if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) { @@ -911,21 +929,29 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, REG_WRITE_ARRAY(&ah->ini_modes_rxgain_5g_xlna, modesIndex, regWrites); } + + if (AR_SREV_9561(ah) && (ar9003_hw_get_rx_gain_idx(ah) == 0)) + REG_WRITE_ARRAY(&ah->ini_modes_rxgain_5g_xlna, + modesIndex, regWrites); } - if (AR_SREV_9550(ah)) + if (AR_SREV_9550(ah) || AR_SREV_9561(ah)) REG_WRITE_ARRAY(&ah->ini_modes_rx_gain_bounds, modesIndex, regWrites); /* * TXGAIN initvals. */ - if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) { int modes_txgain_index = 1; if (AR_SREV_9550(ah)) modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan); + if (AR_SREV_9561(ah)) + modes_txgain_index = + ar9561_hw_get_modes_txgain_index(ah, chan); + if (modes_txgain_index < 0) return -EINVAL; @@ -1989,7 +2015,8 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->rf_set_freq = ar9003_hw_set_channel; priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate; - if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) priv_ops->compute_pll_control = ar9003_hw_compute_pll_control_soc; else priv_ops->compute_pll_control = ar9003_hw_compute_pll_control; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 916b370be033..051540f78030 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -783,7 +783,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, /* program BB PLL phase_shift */ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1); - } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) { u32 regval, pll2_divint, pll2_divfrac, refdiv; REG_WRITE(ah, AR_RTC_PLL_CONTROL, @@ -794,7 +795,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, udelay(100); if (ah->is_clk_25mhz) { - if (AR_SREV_9531(ah)) { + if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) { pll2_divint = 0x1c; pll2_divfrac = 0xa3d2; refdiv = 1; @@ -810,14 +811,15 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, refdiv = 5; } else { pll2_divint = 0x11; - pll2_divfrac = - AR_SREV_9531(ah) ? 0x26665 : 0x26666; + pll2_divfrac = (AR_SREV_9531(ah) || + AR_SREV_9561(ah)) ? + 0x26665 : 0x26666; refdiv = 1; } } regval = REG_READ(ah, AR_PHY_PLL_MODE); - if (AR_SREV_9531(ah)) + if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) regval |= (0x1 << 22); else regval |= (0x1 << 16); @@ -835,14 +837,16 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, (0x1 << 13) | (0x4 << 26) | (0x18 << 19); - else if (AR_SREV_9531(ah)) + else if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) { regval = (regval & 0x01c00fff) | (0x1 << 31) | (0x2 << 29) | (0xa << 25) | - (0x1 << 19) | - (0x6 << 12); - else + (0x1 << 19); + + if (AR_SREV_9531(ah)) + regval |= (0x6 << 12); + } else regval = (regval & 0x80071fff) | (0x3 << 30) | (0x1 << 13) | @@ -850,7 +854,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, (0x60 << 19); REG_WRITE(ah, AR_PHY_PLL_MODE, regval); - if (AR_SREV_9531(ah)) + if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) REG_WRITE(ah, AR_PHY_PLL_MODE, REG_READ(ah, AR_PHY_PLL_MODE) & 0xffbfffff); else @@ -889,7 +893,8 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXORN | AR_IMR_BCNMISC; - if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; if (AR_SREV_9300_20_OR_LATER(ah)) { @@ -1678,7 +1683,8 @@ static void ath9k_hw_init_desc(struct ath_hw *ah) } #ifdef __BIG_ENDIAN else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) || - AR_SREV_9550(ah) || AR_SREV_9531(ah)) + AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0); else REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); @@ -2466,7 +2472,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) { pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_FASTCLOCK; - if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah) && !AR_SREV_9565(ah)) + if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah) && + !AR_SREV_9561(ah) && !AR_SREV_9565(ah)) pCap->hw_caps |= ATH9K_HW_CAP_LDPC; pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH; @@ -2483,7 +2490,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED; - if (AR_SREV_9300_20_OR_LATER(ah)) + if (AR_SREV_9561(ah)) + ah->ent_mode = 0x3BDA000; + else if (AR_SREV_9300_20_OR_LATER(ah)) ah->ent_mode = REG_READ(ah, AR_ENT_OTP); if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah)) diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 3e58bfa0c1fd..bba85d1a6cd1 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -820,7 +820,8 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) return; } - if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; async_mask = AR_INTR_MAC_IRQ; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 7395afbc5124..6fb40ef86fd6 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -425,7 +425,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc) rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; } - if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah)) + if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah) || + AR_SREV_9561(sc->sc_ah)) rfilt |= ATH9K_RX_FILTER_4ADDRESS; if (ath9k_is_chanctx_enabled() && -- cgit v1.2.1 From 3277213feb1b6625e4d7ad9eef1778dc88cdf46f Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:03 +0200 Subject: wil6210: ADDBA/DELBA flows Introduce BACK establishment procedures; decision logic is not implemented yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0. debugfs usage: to establish BACK with agg_wsize 16: echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba to delete BACK: echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba to change agg_wsize, one need to delete BACK and establish it anew ADDBA flow for: - originator Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing agg_wsize and timeout parameters. Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID with negotiated parameters. On this event, update Tx vring data (struct vring_tx_data) and display BACK parameters on debugfs - recipient Rx side (recipient) firmware informs driver about ADDBA with WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work queue wq_service. It adjusts parameters and sends response with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success, driver updates Rx BACK reorder buffer. policy for BACK parameters: - aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes DELBA flow for: - originator driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID and updates struct vring_tx_data associated with vring; ignore WMI_DELBA_EVENTID. - recipient firmware informs driver with WMI_DELBA_EVENTID, driver deletes correspondent reorder buffer ADDBA request processing requires sending WMI command, therefore it is processed in work queue context. Same work queue used as for connect, it get renamed to wq_service Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 53 ++++++++- drivers/net/wireless/ath/wil6210/main.c | 24 ++-- drivers/net/wireless/ath/wil6210/rx_reorder.c | 146 +++++++++++++++++++++++ drivers/net/wireless/ath/wil6210/txrx.c | 2 +- drivers/net/wireless/ath/wil6210/wil6210.h | 36 +++++- drivers/net/wireless/ath/wil6210/wmi.c | 159 +++++++++++++++++++++----- 6 files changed, 376 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index cd991fa1cc3f..8b3b58c2d3c8 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -110,9 +110,11 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) snprintf(name, sizeof(name), "tx_%2d", i); - seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n", - wil->sta[cid].addr, cid, tid, used, avail, - (int)idle); + seq_printf(s, + "\n%pM CID %d TID %d BACK([%d] %d TU) [%3d|%3d] idle %3d%%\n", + wil->sta[cid].addr, cid, tid, + txdata->agg_wsize, txdata->agg_timeout, + used, avail, (int)idle); wil_print_vring(s, wil, name, vring, '_', 'H'); } @@ -558,6 +560,50 @@ static const struct file_operations fops_rxon = { .open = simple_open, }; +/* block ack for vring 0 + * write 0 to it to trigger DELBA + * write positive agg_wsize to trigger ADDBA + */ +static ssize_t wil_write_addba(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + int rc; + uint agg_wsize; + char *kbuf = kmalloc(len + 1, GFP_KERNEL); + + if (!kbuf) + return -ENOMEM; + + rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); + if (rc != len) { + kfree(kbuf); + return rc >= 0 ? -EIO : rc; + } + + kbuf[len] = '\0'; + rc = kstrtouint(kbuf, 0, &agg_wsize); + kfree(kbuf); + + if (rc) + return rc; + + if (!wil->vring_tx[0].va) + return -EINVAL; + + if (agg_wsize > 0) + wmi_addba(wil, 0, agg_wsize, 0); + else + wmi_delba(wil, 0, 0); + + return len; +} + +static const struct file_operations fops_addba = { + .write = wil_write_addba, + .open = simple_open, +}; + /*---tx_mgmt---*/ /* Write mgmt frame to this file to send it */ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, @@ -1217,6 +1263,7 @@ static const struct { {"rxon", S_IWUSR, &fops_rxon}, {"tx_mgmt", S_IWUSR, &fops_txmgmt}, {"wmi_send", S_IWUSR, &fops_wmi}, + {"addba", S_IWUSR, &fops_addba}, {"temp", S_IRUGO, &fops_temp}, {"freq", S_IRUGO, &fops_freq}, {"link", S_IRUGO, &fops_link}, diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 8ff3fe34fe05..9b402b94bfa5 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -384,6 +384,7 @@ int wil_priv_init(struct wil6210_priv *wil) mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); + mutex_init(&wil->back_rx_mutex); init_completion(&wil->wmi_ready); init_completion(&wil->wmi_call); @@ -396,25 +397,30 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); + INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); + INIT_LIST_HEAD(&wil->back_rx_pending); spin_lock_init(&wil->wmi_ev_lock); init_waitqueue_head(&wil->wq); - wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi"); + wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi"); if (!wil->wmi_wq) return -EAGAIN; - wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect"); - if (!wil->wmi_wq_conn) { - destroy_workqueue(wil->wmi_wq); - return -EAGAIN; - } + wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service"); + if (!wil->wq_service) + goto out_wmi_wq; wil->last_fw_recovery = jiffies; wil->itr_trsh = itr_trsh; return 0; + +out_wmi_wq: + destroy_workqueue(wil->wmi_wq); + + return -EAGAIN; } /** @@ -448,7 +454,9 @@ void wil_priv_deinit(struct wil6210_priv *wil) wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); mutex_unlock(&wil->mutex); wmi_event_flush(wil); - destroy_workqueue(wil->wmi_wq_conn); + wil_back_rx_flush(wil); + cancel_work_sync(&wil->back_rx_worker); + destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wmi_wq); } @@ -649,7 +657,7 @@ int wil_reset(struct wil6210_priv *wil) wmi_event_flush(wil); - flush_workqueue(wil->wmi_wq_conn); + flush_workqueue(wil->wq_service); flush_workqueue(wil->wmi_wq); rc = wil_target_reset(wil); diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 489cb73d139b..8e6d25a9f223 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -219,3 +219,149 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, kfree(r->reorder_time); kfree(r); } + +/* ADDBA processing */ +static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize) +{ + u16 max_agg_size = min_t(u16, WIL_MAX_AGG_WSIZE, WIL_MAX_AMPDU_SIZE / + (mtu_max + WIL_MAX_MPDU_OVERHEAD)); + + if (!req_agg_wsize) + return max_agg_size; + + return min(max_agg_size, req_agg_wsize); +} + +/* Block Ack - Rx side (recipient */ +int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, + u8 dialog_token, __le16 ba_param_set, + __le16 ba_timeout, __le16 ba_seq_ctrl) +{ + struct wil_back_rx *req = kzalloc(sizeof(*req), GFP_KERNEL); + + if (!req) + return -ENOMEM; + + req->cidxtid = cidxtid; + req->dialog_token = dialog_token; + req->ba_param_set = le16_to_cpu(ba_param_set); + req->ba_timeout = le16_to_cpu(ba_timeout); + req->ba_seq_ctrl = le16_to_cpu(ba_seq_ctrl); + + mutex_lock(&wil->back_rx_mutex); + list_add_tail(&req->list, &wil->back_rx_pending); + mutex_unlock(&wil->back_rx_mutex); + + queue_work(wil->wq_service, &wil->back_rx_worker); + + return 0; +} + +static void wil_back_rx_handle(struct wil6210_priv *wil, + struct wil_back_rx *req) +{ + struct wil_sta_info *sta; + u8 cid, tid; + u16 agg_wsize = 0; + /* bit 0: A-MSDU supported + * bit 1: policy (should be 0 for us) + * bits 2..5: TID + * bits 6..15: buffer size + */ + u16 req_agg_wsize = WIL_GET_BITS(req->ba_param_set, 6, 15); + bool agg_amsdu = !!(req->ba_param_set & BIT(0)); + int ba_policy = req->ba_param_set & BIT(1); + u16 agg_timeout = req->ba_timeout; + u16 status = WLAN_STATUS_SUCCESS; + unsigned long flags; + int rc; + + parse_cidxtid(req->cidxtid, &cid, &tid); + + /* sanity checks */ + if (cid >= WIL6210_MAX_CID) { + wil_err(wil, "BACK: invalid CID %d\n", cid); + return; + } + + sta = &wil->sta[cid]; + if (sta->status != wil_sta_connected) { + wil_err(wil, "BACK: CID %d not connected\n", cid); + return; + } + + wil_dbg_wmi(wil, + "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d\n", + cid, sta->addr, tid, req_agg_wsize, req->ba_timeout, + agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token); + + /* apply policies */ + if (ba_policy) { + wil_err(wil, "BACK requested unsupported ba_policy == 1\n"); + status = WLAN_STATUS_INVALID_QOS_PARAM; + } + if (status == WLAN_STATUS_SUCCESS) + agg_wsize = wil_agg_size(wil, req_agg_wsize); + + rc = wmi_addba_rx_resp(wil, cid, tid, req->dialog_token, status, + agg_amsdu, agg_wsize, agg_timeout); + if (rc || (status != WLAN_STATUS_SUCCESS)) + return; + + /* apply */ + spin_lock_irqsave(&sta->tid_rx_lock, flags); + + wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); + sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, + req->ba_seq_ctrl >> 4); + + spin_unlock_irqrestore(&sta->tid_rx_lock, flags); +} + +void wil_back_rx_flush(struct wil6210_priv *wil) +{ + struct wil_back_rx *evt, *t; + + wil_dbg_misc(wil, "%s()\n", __func__); + + mutex_lock(&wil->back_rx_mutex); + + list_for_each_entry_safe(evt, t, &wil->back_rx_pending, list) { + list_del(&evt->list); + kfree(evt); + } + + mutex_unlock(&wil->back_rx_mutex); +} + +/* Retrieve next ADDBA request from the pending list */ +static struct list_head *next_back_rx(struct wil6210_priv *wil) +{ + struct list_head *ret = NULL; + + mutex_lock(&wil->back_rx_mutex); + + if (!list_empty(&wil->back_rx_pending)) { + ret = wil->back_rx_pending.next; + list_del(ret); + } + + mutex_unlock(&wil->back_rx_mutex); + + return ret; +} + +void wil_back_rx_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, struct wil6210_priv, + back_rx_worker); + struct wil_back_rx *evt; + struct list_head *lh; + + while ((lh = next_back_rx(wil)) != NULL) { + evt = list_entry(lh, struct wil_back_rx, list); + + wil_back_rx_handle(wil, evt); + kfree(evt); + } +} diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index e3f8bdce5abc..d9268608f113 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -653,7 +653,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, .mac_ctrl = 0, .to_resolution = 0, - .agg_max_wsize = 16, + .agg_max_wsize = 0, .schd_params = { .priority = cpu_to_le16(0), .timeslot_us = cpu_to_le16(0xfff), diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c6ec5b99ac7d..4a9a68e7a007 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -57,6 +57,15 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MAX_TX_RINGS (24) /* HW limit */ #define WIL6210_MAX_CID (8) /* HW limit */ #define WIL6210_NAPI_BUDGET (16) /* arbitrary */ +#define WIL_MAX_AMPDU_SIZE (64 * 1024) /* FW/HW limit */ +#define WIL_MAX_AGG_WSIZE (32) /* FW/HW limit */ +/* Hardware offload block adds the following: + * 26 bytes - 3-address QoS data header + * 8 bytes - SNAP + * 4 bytes - CRC + * 24 bytes - security related (if connection is secure) + */ +#define WIL_MAX_MPDU_OVERHEAD (62) /* Max supported by wil6210 value for interrupt threshold is 5sec. */ #define WIL6210_ITR_TRSH_MAX (5000000) #define WIL6210_ITR_TRSH_DEFAULT (300) /* usec */ @@ -303,6 +312,8 @@ struct vring { struct vring_tx_data { int enabled; cycles_t idle, last_idle, begin; + u8 agg_wsize; /* agreed aggregation window, 0 - no agg */ + u16 agg_timeout; }; enum { /* for wil6210_priv.status */ @@ -397,6 +408,16 @@ enum { fw_recovery_running = 2, }; +struct wil_back_rx { + struct list_head list; + /* request params, converted to CPU byte order - what we asked for */ + u8 cidxtid; + u8 dialog_token; + u16 ba_param_set; + u16 ba_timeout; + u16 ba_seq_ctrl; +}; + struct wil6210_priv { struct pci_dev *pdev; int n_msi; @@ -429,7 +450,7 @@ struct wil6210_priv { u16 reply_size; struct workqueue_struct *wmi_wq; /* for deferred calls */ struct work_struct wmi_event_worker; - struct workqueue_struct *wmi_wq_conn; /* for connect worker */ + struct workqueue_struct *wq_service; struct work_struct connect_worker; struct work_struct disconnect_worker; struct work_struct fw_error_worker; /* for FW error recovery */ @@ -445,6 +466,10 @@ struct wil6210_priv { spinlock_t wmi_ev_lock; struct napi_struct napi_rx; struct napi_struct napi_tx; + /* BACK */ + struct list_head back_rx_pending; + struct mutex back_rx_mutex; /* protect @back_rx_pending */ + struct work_struct back_rx_worker; /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; @@ -567,6 +592,15 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason); +int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout); +int wmi_delba(struct wil6210_priv *wil, u8 ringid, u16 reason); +int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, + u16 status, bool amsdu, u16 agg_wsize, u16 timeout); +int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, + u8 dialog_token, __le16 ba_param_set, + __le16 ba_timeout, __le16 ba_seq_ctrl); +void wil_back_rx_worker(struct work_struct *work); +void wil_back_rx_flush(struct wil6210_priv *wil); void wil6210_clear_irq(struct wil6210_priv *wil); int wil6210_init_irq(struct wil6210_priv *wil, int irq); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 63476c86cd0e..e790c45c3c68 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -471,7 +471,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) wil->sta[evt->cid].status = wil_sta_conn_pending; wil->pending_connect_cid = evt->cid; - queue_work(wil->wmi_wq_conn, &wil->connect_worker); + queue_work(wil->wq_service, &wil->connect_worker); } static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, @@ -583,10 +583,7 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, int len) { struct wmi_vring_ba_status_event *evt = d; - struct wil_sta_info *sta; - uint i, cid; - - /* TODO: use Rx BA status, not Tx one */ + struct vring_tx_data *txdata; wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", evt->ringid, @@ -598,40 +595,71 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, return; } - mutex_lock(&wil->mutex); - - cid = wil->vring2cid_tid[evt->ringid][0]; - if (cid >= WIL6210_MAX_CID) { - wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid); - goto out; + if (evt->status != WMI_BA_AGREED) { + evt->ba_timeout = 0; + evt->agg_wsize = 0; } - sta = &wil->sta[cid]; - if (sta->status == wil_sta_unused) { - wil_err(wil, "CID %d unused\n", cid); - goto out; - } - - wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr); - for (i = 0; i < WIL_STA_TID_NUM; i++) { - struct wil_tid_ampdu_rx *r; - unsigned long flags; + txdata = &wil->vring_tx_data[evt->ringid]; - spin_lock_irqsave(&sta->tid_rx_lock, flags); + txdata->agg_timeout = le16_to_cpu(evt->ba_timeout); + txdata->agg_wsize = evt->agg_wsize; +} - r = sta->tid_rx[i]; - sta->tid_rx[i] = NULL; - wil_tid_ampdu_rx_free(wil, r); +static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d, + int len) +{ + struct wmi_rcp_addba_req_event *evt = d; - spin_unlock_irqrestore(&sta->tid_rx_lock, flags); + wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token, + evt->ba_param_set, evt->ba_timeout, + evt->ba_seq_ctrl); +} - if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize) - sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, - evt->agg_wsize, 0); +static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len) +{ + struct wmi_delba_event *evt = d; + u8 cid, tid; + u16 reason = __le16_to_cpu(evt->reason); + struct wil_sta_info *sta; + struct wil_tid_ampdu_rx *r; + unsigned long flags; + + parse_cidxtid(evt->cidxtid, &cid, &tid); + wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n", + cid, tid, + evt->from_initiator ? "originator" : "recipient", + reason); + if (!evt->from_initiator) { + int i; + /* find Tx vring it belongs to */ + for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) { + if ((wil->vring2cid_tid[i][0] == cid) && + (wil->vring2cid_tid[i][1] == tid)) { + struct vring_tx_data *txdata = + &wil->vring_tx_data[i]; + + wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i); + txdata->agg_timeout = 0; + txdata->agg_wsize = 0; + + break; /* max. 1 matching ring */ + } + } + if (i >= ARRAY_SIZE(wil->vring2cid_tid)) + wil_err(wil, "DELBA: unable to find Tx vring\n"); + return; } -out: - mutex_unlock(&wil->mutex); + sta = &wil->sta[cid]; + + spin_lock_irqsave(&sta->tid_rx_lock, flags); + + r = sta->tid_rx[tid]; + sta->tid_rx[tid] = NULL; + wil_tid_ampdu_rx_free(wil, r); + + spin_unlock_irqrestore(&sta->tid_rx_lock, flags); } static const struct { @@ -649,6 +677,8 @@ static const struct { {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup}, {WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown}, {WMI_BA_STATUS_EVENTID, wmi_evt_ba_status}, + {WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req}, + {WMI_DELBA_EVENTID, wmi_evt_delba}, }; /* @@ -1111,6 +1141,73 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd)); } +int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout) +{ + struct wmi_vring_ba_en_cmd cmd = { + .ringid = ringid, + .agg_max_wsize = size, + .ba_timeout = cpu_to_le16(timeout), + }; + + wil_dbg_wmi(wil, "%s(ring %d size %d timeout %d)\n", __func__, + ringid, size, timeout); + + return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd)); +} + +int wmi_delba(struct wil6210_priv *wil, u8 ringid, u16 reason) +{ + struct wmi_vring_ba_dis_cmd cmd = { + .ringid = ringid, + .reason = cpu_to_le16(reason), + }; + + wil_dbg_wmi(wil, "%s(ring %d reason %d)\n", __func__, + ringid, reason); + + return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd)); +} + +int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, + u16 status, bool amsdu, u16 agg_wsize, u16 timeout) +{ + int rc; + struct wmi_rcp_addba_resp_cmd cmd = { + .cidxtid = mk_cidxtid(cid, tid), + .dialog_token = token, + .status_code = cpu_to_le16(status), + /* bit 0: A-MSDU supported + * bit 1: policy (should be 0 for us) + * bits 2..5: TID + * bits 6..15: buffer size + */ + .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) | + (agg_wsize << 6)), + .ba_timeout = cpu_to_le16(timeout), + }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_rcp_addba_resp_sent_event evt; + } __packed reply; + + wil_dbg_wmi(wil, + "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n", + cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-"); + + rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd), + WMI_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply), 100); + if (rc) + return rc; + + if (reply.evt.status) { + wil_err(wil, "ADDBA response failed with status %d\n", + le16_to_cpu(reply.evt.status)); + rc = -EINVAL; + } + + return rc; +} + void wmi_event_flush(struct wil6210_priv *wil) { struct pending_wmi_event *evt, *t; -- cgit v1.2.1 From 3a124ed6454a939277c6b51bea542464be43ef6f Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:04 +0200 Subject: wil6210: simple ADDBA on originator (Tx) side Upon Tx vring creation, initiate BACK establishment with maximum possible window size. When establishing secure connection, there is EAPOL data exchange between connection itself and "data port open", where security is done and non-EAPOL data may be transferred. It is better to send EAPOL frames using normal ACK because of firmware considerations. send ADDBA only is 2 conditions met: - data port open for the corresponded STA - vring created Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 5 ++ drivers/net/wireless/ath/wil6210/rx_reorder.c | 91 +++++++++++++++++++++++++++ drivers/net/wireless/ath/wil6210/txrx.c | 4 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 15 +++++ drivers/net/wireless/ath/wil6210/wmi.c | 19 ++++++ 5 files changed, 134 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 9b402b94bfa5..42e119242107 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -385,6 +385,7 @@ int wil_priv_init(struct wil6210_priv *wil) mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); mutex_init(&wil->back_rx_mutex); + mutex_init(&wil->back_tx_mutex); init_completion(&wil->wmi_ready); init_completion(&wil->wmi_call); @@ -398,9 +399,11 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker); + INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); INIT_LIST_HEAD(&wil->back_rx_pending); + INIT_LIST_HEAD(&wil->back_tx_pending); spin_lock_init(&wil->wmi_ev_lock); init_waitqueue_head(&wil->wq); @@ -456,6 +459,8 @@ void wil_priv_deinit(struct wil6210_priv *wil) wmi_event_flush(wil); wil_back_rx_flush(wil); cancel_work_sync(&wil->back_rx_worker); + wil_back_tx_flush(wil); + cancel_work_sync(&wil->back_tx_worker); destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wmi_wq); } diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 8e6d25a9f223..ce1206aff5e5 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -365,3 +365,94 @@ void wil_back_rx_worker(struct work_struct *work) kfree(evt); } } + +/* BACK - Tx (originator) side */ +static void wil_back_tx_handle(struct wil6210_priv *wil, + struct wil_back_tx *req) +{ + struct vring_tx_data *txdata = &wil->vring_tx_data[req->ringid]; + int rc; + + if (txdata->addba_in_progress) { + wil_dbg_misc(wil, "ADDBA for vring[%d] already in progress\n", + req->ringid); + return; + } + if (txdata->agg_wsize) { + wil_dbg_misc(wil, + "ADDBA for vring[%d] already established wsize %d\n", + req->ringid, txdata->agg_wsize); + return; + } + txdata->addba_in_progress = true; + rc = wmi_addba(wil, req->ringid, req->agg_wsize, req->agg_timeout); + if (rc) + txdata->addba_in_progress = false; +} + +static struct list_head *next_back_tx(struct wil6210_priv *wil) +{ + struct list_head *ret = NULL; + + mutex_lock(&wil->back_tx_mutex); + + if (!list_empty(&wil->back_tx_pending)) { + ret = wil->back_tx_pending.next; + list_del(ret); + } + + mutex_unlock(&wil->back_tx_mutex); + + return ret; +} + +void wil_back_tx_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, struct wil6210_priv, + back_tx_worker); + struct wil_back_tx *evt; + struct list_head *lh; + + while ((lh = next_back_tx(wil)) != NULL) { + evt = list_entry(lh, struct wil_back_tx, list); + + wil_back_tx_handle(wil, evt); + kfree(evt); + } +} + +void wil_back_tx_flush(struct wil6210_priv *wil) +{ + struct wil_back_tx *evt, *t; + + wil_dbg_misc(wil, "%s()\n", __func__); + + mutex_lock(&wil->back_tx_mutex); + + list_for_each_entry_safe(evt, t, &wil->back_tx_pending, list) { + list_del(&evt->list); + kfree(evt); + } + + mutex_unlock(&wil->back_tx_mutex); +} + +int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid) +{ + struct wil_back_tx *req = kzalloc(sizeof(*req), GFP_KERNEL); + + if (!req) + return -ENOMEM; + + req->ringid = ringid; + req->agg_wsize = wil_agg_size(wil, 0); + req->agg_timeout = 0; + + mutex_lock(&wil->back_tx_mutex); + list_add_tail(&req->list, &wil->back_tx_pending); + mutex_unlock(&wil->back_tx_mutex); + + queue_work(wil->wq_service, &wil->back_tx_worker); + + return 0; +} diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index d9268608f113..71eaeec50639 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -701,6 +701,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); txdata->enabled = 1; + if (wil->sta[cid].data_port_open) + wil_addba_tx_request(wil, id); return 0; out_free: @@ -713,6 +715,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, void wil_vring_fini_tx(struct wil6210_priv *wil, int id) { struct vring *vring = &wil->vring_tx[id]; + struct vring_tx_data *txdata = &wil->vring_tx_data[id]; WARN_ON(!mutex_is_locked(&wil->mutex)); @@ -727,6 +730,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) napi_synchronize(&wil->napi_tx); wil_vring_free(wil, vring, 1); + memset(txdata, 0, sizeof(*txdata)); } static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 4a9a68e7a007..9cd76da3738d 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -314,6 +314,7 @@ struct vring_tx_data { cycles_t idle, last_idle, begin; u8 agg_wsize; /* agreed aggregation window, 0 - no agg */ u16 agg_timeout; + bool addba_in_progress; /* if set, agg_xxx is for request in progress */ }; enum { /* for wil6210_priv.status */ @@ -418,6 +419,14 @@ struct wil_back_rx { u16 ba_seq_ctrl; }; +struct wil_back_tx { + struct list_head list; + /* request params, converted to CPU byte order - what we asked for */ + u8 ringid; + u8 agg_wsize; + u16 agg_timeout; +}; + struct wil6210_priv { struct pci_dev *pdev; int n_msi; @@ -470,6 +479,9 @@ struct wil6210_priv { struct list_head back_rx_pending; struct mutex back_rx_mutex; /* protect @back_rx_pending */ struct work_struct back_rx_worker; + struct list_head back_tx_pending; + struct mutex back_tx_mutex; /* protect @back_tx_pending */ + struct work_struct back_tx_worker; /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; @@ -601,6 +613,9 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, __le16 ba_timeout, __le16 ba_seq_ctrl); void wil_back_rx_worker(struct work_struct *work); void wil_back_rx_flush(struct wil6210_priv *wil); +int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid); +void wil_back_tx_worker(struct work_struct *work); +void wil_back_tx_flush(struct wil6210_priv *wil); void wil6210_clear_irq(struct wil6210_priv *wil); int wil6210_init_irq(struct wil6210_priv *wil, int irq); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index e790c45c3c68..8a4f8b7243e0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -544,6 +544,22 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, } } +static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid) +{ + struct vring_tx_data *t; + int i; + + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + if (cid != wil->vring2cid_tid[i][0]) + continue; + t = &wil->vring_tx_data[i]; + if (!t->enabled) + continue; + + wil_addba_tx_request(wil, i); + } +} + static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) { struct net_device *ndev = wil_to_ndev(wil); @@ -558,6 +574,7 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) } wil->sta[cid].data_port_open = true; + wil_addba_tx_cid(wil, cid); netif_carrier_on(ndev); } @@ -604,6 +621,7 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, txdata->agg_timeout = le16_to_cpu(evt->ba_timeout); txdata->agg_wsize = evt->agg_wsize; + txdata->addba_in_progress = false; } static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d, @@ -642,6 +660,7 @@ static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len) wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i); txdata->agg_timeout = 0; txdata->agg_wsize = 0; + txdata->addba_in_progress = false; break; /* max. 1 matching ring */ } -- cgit v1.2.1 From 3a3def8dbe65082d2319cac4791139d4ab786b4d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:05 +0200 Subject: wil6210: allow to configure ADDBA request For manual ADDBA configuration, allow to set desired window size or disable automatic mechanism. Introduce module parameter (int) agg_wsize. It can be changed on run time, will be taken into account on the next connect. Interpretation: - <0 - disable automatic ADDBA; intended for manual testing through debugfs - 0 - use automatically calculated window size - >0 - use this for window size. Clipped by maximum supported by the hardware with current environment. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/rx_reorder.c | 4 ++-- drivers/net/wireless/ath/wil6210/txrx.c | 4 ++-- drivers/net/wireless/ath/wil6210/wil6210.h | 3 ++- drivers/net/wireless/ath/wil6210/wmi.c | 12 +++++++++--- 4 files changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index ce1206aff5e5..0865c3430e51 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -437,7 +437,7 @@ void wil_back_tx_flush(struct wil6210_priv *wil) mutex_unlock(&wil->back_tx_mutex); } -int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid) +int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize) { struct wil_back_tx *req = kzalloc(sizeof(*req), GFP_KERNEL); @@ -445,7 +445,7 @@ int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid) return -ENOMEM; req->ringid = ringid; - req->agg_wsize = wil_agg_size(wil, 0); + req->agg_wsize = wil_agg_size(wil, wsize); req->agg_timeout = 0; mutex_lock(&wil->back_tx_mutex); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 71eaeec50639..b7ffcfb8f38f 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -701,8 +701,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); txdata->enabled = 1; - if (wil->sta[cid].data_port_open) - wil_addba_tx_request(wil, id); + if (wil->sta[cid].data_port_open && (agg_wsize >= 0)) + wil_addba_tx_request(wil, id, agg_wsize); return 0; out_free: diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 9cd76da3738d..a94d67db59af 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -25,6 +25,7 @@ extern bool no_fw_recovery; extern unsigned int mtu_max; +extern int agg_wsize; #define WIL_NAME "wil6210" #define WIL_FW_NAME "wil6210.fw" @@ -613,7 +614,7 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, __le16 ba_timeout, __le16 ba_seq_ctrl); void wil_back_rx_worker(struct work_struct *work); void wil_back_rx_flush(struct wil6210_priv *wil); -int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid); +int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize); void wil_back_tx_worker(struct work_struct *work); void wil_back_tx_flush(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 8a4f8b7243e0..253816105f14 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -27,6 +27,11 @@ static uint max_assoc_sta = 1; module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP"); +int agg_wsize; /* = 0; */ +module_param(agg_wsize, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;" + " 0 - use default; < 0 - don't auto-establish"); + /** * WMI event receiving - theory of operations * @@ -544,7 +549,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, } } -static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid) +static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize) { struct vring_tx_data *t; int i; @@ -556,7 +561,7 @@ static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid) if (!t->enabled) continue; - wil_addba_tx_request(wil, i); + wil_addba_tx_request(wil, i, wsize); } } @@ -574,7 +579,8 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) } wil->sta[cid].data_port_open = true; - wil_addba_tx_cid(wil, cid); + if (agg_wsize >= 0) + wil_addba_tx_cid(wil, cid, agg_wsize); netif_carrier_on(ndev); } -- cgit v1.2.1 From 56637e7b53d1800a071a1117a80144bb88f52038 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:06 +0200 Subject: wil6210: improve debugfs for reorder buffer When printing debugfs for the reorder buffer, include BACK parameters: window size and timeout Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 8b3b58c2d3c8..32df4b7c5e62 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1162,7 +1162,8 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) int i; u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; - seq_printf(s, "0x%03x [", r->head_seq_num); + seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout, + r->head_seq_num); for (i = 0; i < r->buf_size; i++) { if (i == index) seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); -- cgit v1.2.1 From 100106d7021fe34ba4d0195a519aa5e2ecae82ab Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:07 +0200 Subject: wil6210: fix disconnect 1 STA in AP When disconnecting single STA in AP, it might be that STA in question is already disconnected. In this case, need to do nothing. Previously, it was mis-interpreted as "disconnect all" Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 42e119242107..18a2eb5b5d66 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -188,18 +188,29 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, struct wireless_dev *wdev = wil->wdev; might_sleep(); - if (bssid) { + wil_dbg_misc(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid, + reason_code, from_event ? "+" : "-"); + + /* Cases are: + * - disconnect single STA, still connected + * - disconnect single STA, already disconnected + * - disconnect all + * + * For "disconnect all", there are 2 options: + * - bssid == NULL + * - bssid is our MAC address + */ + if (bssid && memcmp(ndev->dev_addr, bssid, ETH_ALEN)) { cid = wil_find_cid(wil, bssid); - wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid); - } else { - wil_dbg_misc(wil, "%s(all)\n", __func__); - } - - if (cid >= 0) /* disconnect 1 peer */ - wil_disconnect_cid(wil, cid, reason_code, from_event); - else /* disconnect all */ + wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n", + bssid, cid, reason_code); + if (cid >= 0) /* disconnect 1 peer */ + wil_disconnect_cid(wil, cid, reason_code, from_event); + } else { /* all */ + wil_dbg_misc(wil, "Disconnect all\n"); for (cid = 0; cid < WIL6210_MAX_CID; cid++) wil_disconnect_cid(wil, cid, reason_code, from_event); + } /* link state */ switch (wdev->iftype) { -- cgit v1.2.1 From 995cdd0ebd064156247c983c14e8e7aef23785c8 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:08 +0200 Subject: wil6210: improve debugfs for VRING When printing VRING on debugfs (file "vrings"), software head & tail indexes were printed in decimal format while hardware tail in hexadecimal only. It is not comfortable to compare indexes in different formats; on the other hand, hexadecimal output useful to see hardware glitches. To serve all purposes, print hardware tail in both decimal and hexadecimal formats. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 32df4b7c5e62..59bc49475be4 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -50,6 +50,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, char _s, char _h) { void __iomem *x = wmi_addr(wil, vring->hwtail); + u32 v; seq_printf(s, "VRING %s = {\n", name); seq_printf(s, " pa = %pad\n", &vring->pa); @@ -58,10 +59,12 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, seq_printf(s, " swtail = %d\n", vring->swtail); seq_printf(s, " swhead = %d\n", vring->swhead); seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail); - if (x) - seq_printf(s, "0x%08x\n", ioread32(x)); - else + if (x) { + v = ioread32(x); + seq_printf(s, "0x%08x = %d\n", v, v); + } else { seq_puts(s, "???\n"); + } if (vring->va && (vring->size < 1025)) { uint i; -- cgit v1.2.1 From cbcf58661b43aeef2e2d90aa884f7879d14dd9bf Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:09 +0200 Subject: wil6210: control AMSDU on Tx side of Block Ack When establishing Block Ack as originator (Tx), control AMSDU flag when sending ADDBA and update status upon establishment flow completion. To be used in AMSDU flows Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 3 ++- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + drivers/net/wireless/ath/wil6210/wmi.c | 8 ++++++-- drivers/net/wireless/ath/wil6210/wmi.h | 12 +++++++++++- 4 files changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 59bc49475be4..b0b5c6ebcc55 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -114,9 +114,10 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) snprintf(name, sizeof(name), "tx_%2d", i); seq_printf(s, - "\n%pM CID %d TID %d BACK([%d] %d TU) [%3d|%3d] idle %3d%%\n", + "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %3d%%\n", wil->sta[cid].addr, cid, tid, txdata->agg_wsize, txdata->agg_timeout, + txdata->agg_amsdu ? "+" : "-", used, avail, (int)idle); wil_print_vring(s, wil, name, vring, '_', 'H'); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index a94d67db59af..747052d2c754 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -315,6 +315,7 @@ struct vring_tx_data { cycles_t idle, last_idle, begin; u8 agg_wsize; /* agreed aggregation window, 0 - no agg */ u16 agg_timeout; + u8 agg_amsdu; bool addba_in_progress; /* if set, agg_xxx is for request in progress */ }; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 253816105f14..00cba4aca3c0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -608,10 +608,11 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, struct wmi_vring_ba_status_event *evt = d; struct vring_tx_data *txdata; - wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", + wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n", evt->ringid, evt->status == WMI_BA_AGREED ? "OK" : "N/A", - evt->agg_wsize, __le16_to_cpu(evt->ba_timeout)); + evt->agg_wsize, __le16_to_cpu(evt->ba_timeout), + evt->amsdu ? "+" : "-"); if (evt->ringid >= WIL6210_MAX_TX_RINGS) { wil_err(wil, "invalid ring id %d\n", evt->ringid); @@ -621,12 +622,14 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, if (evt->status != WMI_BA_AGREED) { evt->ba_timeout = 0; evt->agg_wsize = 0; + evt->amsdu = 0; } txdata = &wil->vring_tx_data[evt->ringid]; txdata->agg_timeout = le16_to_cpu(evt->ba_timeout); txdata->agg_wsize = evt->agg_wsize; + txdata->agg_amsdu = evt->amsdu; txdata->addba_in_progress = false; } @@ -1172,6 +1175,7 @@ int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout) .ringid = ringid, .agg_max_wsize = size, .ba_timeout = cpu_to_le16(timeout), + .amsdu = 0, }; wil_dbg_wmi(wil, "%s(ring %d size %d timeout %d)\n", __func__, diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 27b97432d1c2..b5102f0b97f4 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -586,6 +586,7 @@ struct wmi_vring_ba_en_cmd { u8 ringid; u8 agg_max_wsize; __le16 ba_timeout; + u8 amsdu; } __packed; /* @@ -1052,14 +1053,23 @@ struct wmi_scan_complete_event { enum wmi_vring_ba_status { WMI_BA_AGREED = 0, WMI_BA_NON_AGREED = 1, + /* BA_EN in middle of teardown flow */ + WMI_BA_TD_WIP = 2, + /* BA_DIS or BA_EN in middle of BA SETUP flow */ + WMI_BA_SETUP_WIP = 3, + /* BA_EN when the BA session is already active */ + WMI_BA_SESSION_ACTIVE = 4, + /* BA_DIS when the BA session is not active */ + WMI_BA_SESSION_NOT_ACTIVE = 5, }; struct wmi_vring_ba_status_event { - __le16 status; + __le16 status; /* enum wmi_vring_ba_status */ u8 reserved[2]; u8 ringid; u8 agg_wsize; __le16 ba_timeout; + u8 amsdu; } __packed; /* -- cgit v1.2.1 From 26a359d914e977aeab582c868236b450762973f7 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:10 +0200 Subject: wil6210: delba for responder Implement delba flow for the responder (Rx) side Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- drivers/net/wireless/ath/wil6210/wil6210.h | 3 ++- drivers/net/wireless/ath/wil6210/wmi.c | 15 ++++++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index b0b5c6ebcc55..b027d87bf1a0 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -598,7 +598,7 @@ static ssize_t wil_write_addba(struct file *file, const char __user *buf, if (agg_wsize > 0) wmi_addba(wil, 0, agg_wsize, 0); else - wmi_delba(wil, 0, 0); + wmi_delba_tx(wil, 0, 0); return len; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 747052d2c754..1b4efd2ea09f 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -607,7 +607,8 @@ int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason); int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout); -int wmi_delba(struct wil6210_priv *wil, u8 ringid, u16 reason); +int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason); +int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason); int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, u16 status, bool amsdu, u16 agg_wsize, u16 timeout); int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 00cba4aca3c0..af2ca461fd86 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1184,7 +1184,7 @@ int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout) return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd)); } -int wmi_delba(struct wil6210_priv *wil, u8 ringid, u16 reason) +int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason) { struct wmi_vring_ba_dis_cmd cmd = { .ringid = ringid, @@ -1197,6 +1197,19 @@ int wmi_delba(struct wil6210_priv *wil, u8 ringid, u16 reason) return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd)); } +int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason) +{ + struct wmi_rcp_delba_cmd cmd = { + .cidxtid = cidxtid, + .reason = cpu_to_le16(reason), + }; + + wil_dbg_wmi(wil, "%s(CID %d TID %d reason %d)\n", __func__, + cidxtid & 0xf, (cidxtid >> 4) & 0xf, reason); + + return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd)); +} + int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, u16 status, bool amsdu, u16 agg_wsize, u16 timeout) { -- cgit v1.2.1 From c44690a157719437d09c83eec393211e7fd65076 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:11 +0200 Subject: wil6210: fix max. MPDU size When configuring Tx/Rx VRING's, driver need to specify max. MPDU size It should take into account all overhead introduced by 802.3->208.11 transformation. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.h | 4 ++-- drivers/net/wireless/ath/wil6210/wil6210.h | 12 +++++++++++- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 5 files changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 18a2eb5b5d66..0af51fc2d981 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs."); /* We allow allocation of more than 1 page buffers to support large packets. * It is suboptimal behavior performance wise in case MTU above page size. */ -unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN; +unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD; static int mtu_max_set(const char *val, const struct kernel_param *kp) { int ret; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index b7ffcfb8f38f..f33ea577efb3 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -645,7 +645,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, .vring_cfg = { .tx_sw_ring = { .max_mpdu_size = - cpu_to_le16(mtu_max + ETH_HLEN), + cpu_to_le16(wil_mtu2macbuf(mtu_max)), .ring_size = cpu_to_le16(size), }, .ringid = id, diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 630aeb5fa7f4..e7db35646cdd 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -20,8 +20,8 @@ #define BUF_SW_OWNED (1) #define BUF_HW_OWNED (0) -/* size of max. Tx/Rx buffers, as supported by FW */ -#define TXRX_BUF_LEN_DEFAULT (2242) +/* default size of MAC Tx/Rx buffers */ +#define TXRX_BUF_LEN_DEFAULT (2048) /* how many bytes to reserve for rtap header? */ #define WIL6210_RTAP_SIZE (128) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 1b4efd2ea09f..bedb9ed372f4 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -62,11 +62,21 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL_MAX_AGG_WSIZE (32) /* FW/HW limit */ /* Hardware offload block adds the following: * 26 bytes - 3-address QoS data header + * 8 bytes - IV + EIV (for GCMP) * 8 bytes - SNAP + * 16 bytes - MIC (for GCMP) * 4 bytes - CRC - * 24 bytes - security related (if connection is secure) */ #define WIL_MAX_MPDU_OVERHEAD (62) + +/* Calculate MAC buffer size for the firmware. It includes all overhead, + * as it will go over the air, and need to be 8 byte aligned + */ +static inline u32 wil_mtu2macbuf(u32 mtu) +{ + return ALIGN(mtu + WIL_MAX_MPDU_OVERHEAD, 8); +} + /* Max supported by wil6210 value for interrupt threshold is 5sec. */ #define WIL6210_ITR_TRSH_MAX (5000000) #define WIL6210_ITR_TRSH_DEFAULT (300) /* usec */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index af2ca461fd86..70b055c59a37 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1083,7 +1083,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) struct wmi_cfg_rx_chain_cmd cmd = { .action = WMI_RX_CHAIN_ADD, .rx_sw_ring = { - .max_mpdu_size = cpu_to_le16(mtu_max + ETH_HLEN), + .max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)), .ring_mem_base = cpu_to_le64(vring->pa), .ring_size = cpu_to_le16(vring->size), }, -- cgit v1.2.1 From 4590d8125eef6b0c69da71cb1738afbef0100f50 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:12 +0200 Subject: wil6210: consider SNAP header in MTU calculations When encapsulating 802.3 frames into the 802.11 ones, 8-byte SNAP header added to save ethtype. SNAP is part of the frame body, thus should be counted in MSDU. So, MTU = MSDU - SNAP Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 2 +- drivers/net/wireless/ath/wil6210/wil6210.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 0af51fc2d981..71ebbc1df6d1 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -53,7 +53,7 @@ static int mtu_max_set(const char *val, const struct kernel_param *kp) if (ret) return ret; - if (mtu_max < 68 || mtu_max > IEEE80211_MAX_DATA_LEN_DMG) + if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU) ret = -EINVAL; return ret; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index bedb9ed372f4..81309dc3e5a1 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -77,6 +77,10 @@ static inline u32 wil_mtu2macbuf(u32 mtu) return ALIGN(mtu + WIL_MAX_MPDU_OVERHEAD, 8); } +/* MTU for Ethernet need to take into account 8-byte SNAP header + * to be added when encapsulating Ethernet frame into 802.11 + */ +#define WIL_MAX_ETH_MTU (IEEE80211_MAX_DATA_LEN_DMG - 8) /* Max supported by wil6210 value for interrupt threshold is 5sec. */ #define WIL6210_ITR_TRSH_MAX (5000000) #define WIL6210_ITR_TRSH_DEFAULT (300) /* usec */ -- cgit v1.2.1 From 327755fb8c6b5d653af621729afeb20fb8528fd7 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:13 +0200 Subject: wil6210: Increase number of associated stations Change default to support maximum number of associated stations to an AP Signed-off-by: Hamad Kadmany Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 70b055c59a37..245215a32bad 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -23,7 +23,7 @@ #include "wmi.h" #include "trace.h" -static uint max_assoc_sta = 1; +static uint max_assoc_sta = WIL6210_MAX_CID; module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP"); -- cgit v1.2.1 From 9419b6a206860b1063492aca7cee20cfcb546406 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:14 +0200 Subject: wil6210: use bitmap API for "status" wil->status used as bitmap; use DECLARE_BITMAP for it. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 12 ++++++------ drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- drivers/net/wireless/ath/wil6210/interrupt.c | 16 ++++++++-------- drivers/net/wireless/ath/wil6210/main.c | 27 ++++++++++++++------------- drivers/net/wireless/ath/wil6210/txrx.c | 6 +++--- drivers/net/wireless/ath/wil6210/wil6210.h | 3 ++- drivers/net/wireless/ath/wil6210/wmi.c | 12 ++++++------ 7 files changed, 40 insertions(+), 38 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 38332a6dfb3a..5c79f1d62103 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -162,7 +162,7 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, sinfo->tx_packets = stats->tx_packets; sinfo->tx_failed = stats->tx_errors; - if (test_bit(wil_status_fwconnected, &wil->status)) { + if (test_bit(wil_status_fwconnected, wil->status)) { sinfo->filled |= STATION_INFO_SIGNAL; sinfo->signal = reply.evt.sqi; } @@ -282,7 +282,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, } /* FW don't support scan after connection attempt */ - if (test_bit(wil_status_dontscan, &wil->status)) { + if (test_bit(wil_status_dontscan, wil->status)) { wil_err(wil, "Can't scan now\n"); return -EBUSY; } @@ -362,8 +362,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int ch; int rc = 0; - if (test_bit(wil_status_fwconnecting, &wil->status) || - test_bit(wil_status_fwconnected, &wil->status)) + if (test_bit(wil_status_fwconnecting, wil->status) || + test_bit(wil_status_fwconnected, wil->status)) return -EALREADY; wil_print_connect_params(wil, sme); @@ -450,7 +450,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, memcpy(conn.bssid, bss->bssid, ETH_ALEN); memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); - set_bit(wil_status_fwconnecting, &wil->status); + set_bit(wil_status_fwconnecting, wil->status); rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); if (rc == 0) { @@ -458,7 +458,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); } else { - clear_bit(wil_status_fwconnecting, &wil->status); + clear_bit(wil_status_fwconnecting, wil->status); } out: diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index b027d87bf1a0..68bbb569d4b4 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1313,7 +1313,7 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, /* fields in struct wil6210_priv */ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32), - WIL_FIELD(status, S_IRUGO | S_IWUSR, doff_ulong), + WIL_FIELD(status[0], S_IRUGO | S_IWUSR, doff_ulong), WIL_FIELD(fw_version, S_IRUGO, doff_u32), WIL_FIELD(hw_version, S_IRUGO, doff_x32), WIL_FIELD(recovery_count, S_IRUGO, doff_u32), diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 4bcbd6297b3e..5a0ea72d3710 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -102,7 +102,7 @@ static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) iowrite32(WIL6210_IRQ_DISABLE, wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); - clear_bit(wil_status_irqen, &wil->status); + clear_bit(wil_status_irqen, wil->status); } void wil6210_unmask_irq_tx(struct wil6210_priv *wil) @@ -130,7 +130,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); - set_bit(wil_status_irqen, &wil->status); + set_bit(wil_status_irqen, wil->status); iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); @@ -198,8 +198,8 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) "of overflow\" interrupt\n"); isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH); - if (test_bit(wil_status_reset_done, &wil->status)) { - if (test_bit(wil_status_napi_en, &wil->status)) { + if (test_bit(wil_status_reset_done, wil->status)) { + if (test_bit(wil_status_napi_en, wil->status)) { wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_rx); @@ -248,7 +248,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; /* clear also all VRING interrupts */ isr &= ~(BIT(25) - 1UL); - if (test_bit(wil_status_reset_done, &wil->status)) { + if (test_bit(wil_status_reset_done, wil->status)) { wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_tx); @@ -310,7 +310,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) if (isr & ISR_MISC_FW_ERROR) { wil_err(wil, "Firmware error detected\n"); - clear_bit(wil_status_fwready, &wil->status); + clear_bit(wil_status_fwready, wil->status); /* * do not clear @isr here - we do 2-nd part in thread * there, user space get notified, and it should be done @@ -321,7 +321,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) if (isr & ISR_MISC_FW_READY) { wil_dbg_irq(wil, "IRQ: FW ready\n"); wil_cache_mbox_regs(wil); - set_bit(wil_status_reset_done, &wil->status); + set_bit(wil_status_reset_done, wil->status); /** * Actual FW ready indicated by the * WMI_FW_READY_EVENTID @@ -394,7 +394,7 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) */ static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) { - if (!test_bit(wil_status_irqen, &wil->status)) { + if (!test_bit(wil_status_irqen, wil->status)) { u32 icm_rx = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + offsetof(struct RGF_ICR, ICM)); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 71ebbc1df6d1..a17278f4090a 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -217,16 +217,16 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: wil_link_off(wil); - if (test_bit(wil_status_fwconnected, &wil->status)) { - clear_bit(wil_status_fwconnected, &wil->status); + if (test_bit(wil_status_fwconnected, wil->status)) { + clear_bit(wil_status_fwconnected, wil->status); cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL); - } else if (test_bit(wil_status_fwconnecting, &wil->status)) { + } else if (test_bit(wil_status_fwconnecting, wil->status)) { cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); } - clear_bit(wil_status_fwconnecting, &wil->status); + clear_bit(wil_status_fwconnecting, wil->status); break; default: break; @@ -259,7 +259,7 @@ static void wil_scan_timer_fn(ulong x) { struct wil6210_priv *wil = (void *)x; - clear_bit(wil_status_fwready, &wil->status); + clear_bit(wil_status_fwready, wil->status); wil_err(wil, "Scan timeout detected, start fw error recovery\n"); wil->recovery_state = fw_recovery_pending; schedule_work(&wil->fw_error_worker); @@ -654,12 +654,13 @@ int wil_reset(struct wil6210_priv *wil) wil_dbg_misc(wil, "%s()\n", __func__); WARN_ON(!mutex_is_locked(&wil->mutex)); - WARN_ON(test_bit(wil_status_napi_en, &wil->status)); + WARN_ON(test_bit(wil_status_napi_en, wil->status)); cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); - wil->status = 0; /* prevent NAPI from being scheduled */ + /* prevent NAPI from being scheduled */ + bitmap_zero(wil->status, wil_status_last); if (wil->scan_request) { wil_dbg_misc(wil, "Abort scan_request 0x%p\n", @@ -798,7 +799,7 @@ int __wil_up(struct wil6210_priv *wil) wil_dbg_misc(wil, "NAPI enable\n"); napi_enable(&wil->napi_rx); napi_enable(&wil->napi_tx); - set_bit(wil_status_napi_en, &wil->status); + set_bit(wil_status_napi_en, wil->status); if (wil->platform_ops.bus_request) wil->platform_ops.bus_request(wil->platform_handle, @@ -831,7 +832,7 @@ int __wil_down(struct wil6210_priv *wil) wil->platform_ops.bus_request(wil->platform_handle, 0); wil_disable_irq(wil); - if (test_and_clear_bit(wil_status_napi_en, &wil->status)) { + if (test_and_clear_bit(wil_status_napi_en, wil->status)) { napi_disable(&wil->napi_rx); napi_disable(&wil->napi_tx); wil_dbg_misc(wil, "NAPI disable\n"); @@ -846,15 +847,15 @@ int __wil_down(struct wil6210_priv *wil) wil->scan_request = NULL; } - if (test_bit(wil_status_fwconnected, &wil->status) || - test_bit(wil_status_fwconnecting, &wil->status)) + if (test_bit(wil_status_fwconnected, wil->status) || + test_bit(wil_status_fwconnecting, wil->status)) wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); /* make sure wil is idle (not connected) */ mutex_unlock(&wil->mutex); while (iter--) { - int idle = !test_bit(wil_status_fwconnected, &wil->status) && - !test_bit(wil_status_fwconnecting, &wil->status); + int idle = !test_bit(wil_status_fwconnected, wil->status) && + !test_bit(wil_status_fwconnecting, wil->status); if (idle) break; msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index f33ea577efb3..33961caab509 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -726,7 +726,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) /* make sure NAPI won't touch this vring */ wil->vring_tx_data[id].enabled = 0; - if (test_bit(wil_status_napi_en, &wil->status)) + if (test_bit(wil_status_napi_en, wil->status)) napi_synchronize(&wil->napi_tx); wil_vring_free(wil, vring, 1); @@ -1038,14 +1038,14 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) int rc; wil_dbg_txrx(wil, "%s()\n", __func__); - if (!test_bit(wil_status_fwready, &wil->status)) { + if (!test_bit(wil_status_fwready, wil->status)) { if (!pr_once_fw) { wil_err(wil, "FW not ready\n"); pr_once_fw = true; } goto drop; } - if (!test_bit(wil_status_fwconnected, &wil->status)) { + if (!test_bit(wil_status_fwconnected, wil->status)) { wil_err(wil, "FW not connected\n"); goto drop; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 81309dc3e5a1..64a6d49a3001 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -341,6 +341,7 @@ enum { /* for wil6210_priv.status */ wil_status_reset_done, wil_status_irqen, /* FIXME: interrupts enabled - for debug */ wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ + wil_status_last /* keep last */ }; struct pci_dev; @@ -448,7 +449,7 @@ struct wil6210_priv { int n_msi; struct wireless_dev *wdev; void __iomem *csr; - ulong status; + DECLARE_BITMAP(status, wil_status_last); u32 fw_version; u32 hw_version; struct wil_board *board; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 245215a32bad..a4b30a40cefa 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -202,7 +202,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) might_sleep(); - if (!test_bit(wil_status_fwready, &wil->status)) { + if (!test_bit(wil_status_fwready, wil->status)) { wil_err(wil, "WMI: cannot send command while FW not ready\n"); return -EAGAIN; } @@ -305,7 +305,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, wil_dbg_wmi(wil, "WMI: got FW ready event\n"); wil_set_recovery_state(wil, fw_recovery_idle); - set_bit(wil_status_fwready, &wil->status); + set_bit(wil_status_fwready, wil->status); /* let the reset sequence continue */ complete(&wil->wmi_ready); } @@ -443,7 +443,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) if ((wdev->iftype == NL80211_IFTYPE_STATION) || (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { - if (!test_bit(wil_status_fwconnecting, &wil->status)) { + if (!test_bit(wil_status_fwconnecting, wil->status)) { wil_err(wil, "Not in connecting state\n"); return; } @@ -467,8 +467,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); } - clear_bit(wil_status_fwconnecting, &wil->status); - set_bit(wil_status_fwconnected, &wil->status); + clear_bit(wil_status_fwconnecting, wil->status); + set_bit(wil_status_fwconnected, wil->status); /* FIXME FW can transmit only ucast frames to peer */ /* FIXME real ring_id instead of hard coded 0 */ @@ -726,7 +726,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) ulong flags; unsigned n; - if (!test_bit(wil_status_reset_done, &wil->status)) { + if (!test_bit(wil_status_reset_done, wil->status)) { wil_err(wil, "Reset in progress. Cannot handle WMI event\n"); return; } -- cgit v1.2.1 From 54ed90a826e088ee3883ae6437d0aa5adf87f972 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:15 +0200 Subject: wil6210: fix Tx VRING for STA mode In STA mode, all Tx should be directed to the same VRING towards the AP. Thus, look up for the 1-st eligible VRING and use it. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 46 +++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 33961caab509..4c145eea9c32 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -777,6 +777,38 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil, static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, struct sk_buff *skb); + +static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, + struct sk_buff *skb) +{ + struct vring *v; + int i; + u8 cid; + + /* In the STA mode, it is expected to have only 1 VRING + * for the AP we connected to. + * find 1-st vring and see whether it is eligible for data + */ + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + v = &wil->vring_tx[i]; + if (!v->va) + continue; + + cid = wil->vring2cid_tid[i][0]; + if (!wil->sta[cid].data_port_open && + (skb->protocol != cpu_to_be16(ETH_P_PAE))) + break; + + wil_dbg_txrx(wil, "Tx -> ring %d\n", i); + + return v; + } + + wil_dbg_txrx(wil, "Tx while no vrings active?\n"); + + return NULL; +} + /* * Find 1-st vring and return it; set dest address for this vring in skb * duplicate skb and send it to other active vrings @@ -1056,15 +1088,19 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) pr_once_fw = false; /* find vring */ - if (is_unicast_ether_addr(eth->h_dest)) - vring = wil_find_tx_vring(wil, skb); - else - vring = wil_tx_bcast(wil, skb); + if (wil->wdev->iftype == NL80211_IFTYPE_STATION) { + /* in STA mode (ESS), all to same VRING */ + vring = wil_find_tx_vring_sta(wil, skb); + } else { /* direct communication, find matching VRING */ + if (is_unicast_ether_addr(eth->h_dest)) + vring = wil_find_tx_vring(wil, skb); + else + vring = wil_tx_bcast(wil, skb); + } if (!vring) { wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } - /* set up vring entry */ rc = wil_tx_vring(wil, vring, skb); -- cgit v1.2.1 From 49cb5dfb5d358c9b5810c69197bdde1d3570d5cc Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:16 +0200 Subject: wil6210: rework debugfs for BACK Enable more flexible control over block ack: - allow addba for any Tx vring - allow to specify block ack timeout - allow to delba for Tx or Rx side of any agreement; with reason Renamed "addba" entry to "back"; it prints short help when read; write: - "add " to trigger ADDBA If missing, defaults to 0 - "del_tx " to trigger DELBA for Tx side - "del_rx " to trigger DELBA for Rx side If missing, set to "STA_LEAVING" (36) Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 71 +++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 68bbb569d4b4..05f9620c260d 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -564,17 +564,19 @@ static const struct file_operations fops_rxon = { .open = simple_open, }; -/* block ack for vring 0 - * write 0 to it to trigger DELBA - * write positive agg_wsize to trigger ADDBA +/* block ack control, write: + * - "add " to trigger ADDBA + * - "del_tx " to trigger DELBA for Tx side + * - "del_rx " to trigger DELBA for Rx side */ -static ssize_t wil_write_addba(struct file *file, const char __user *buf, - size_t len, loff_t *ppos) +static ssize_t wil_write_back(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; int rc; - uint agg_wsize; char *kbuf = kmalloc(len + 1, GFP_KERNEL); + char cmd[8]; + int p1, p2, p3; if (!kbuf) return -ENOMEM; @@ -586,25 +588,60 @@ static ssize_t wil_write_addba(struct file *file, const char __user *buf, } kbuf[len] = '\0'; - rc = kstrtouint(kbuf, 0, &agg_wsize); + rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3); kfree(kbuf); - if (rc) + if (rc < 0) return rc; - - if (!wil->vring_tx[0].va) + if (rc < 2) return -EINVAL; - if (agg_wsize > 0) - wmi_addba(wil, 0, agg_wsize, 0); - else - wmi_delba_tx(wil, 0, 0); + if (0 == strcmp(cmd, "add")) { + if (rc < 3) { + wil_err(wil, "BACK: add require at least 2 params\n"); + return -EINVAL; + } + if (rc < 4) + p3 = 0; + wmi_addba(wil, p1, p2, p3); + } else if (0 == strcmp(cmd, "del_tx")) { + if (rc < 3) + p2 = WLAN_REASON_QSTA_LEAVE_QBSS; + wmi_delba_tx(wil, p1, p2); + } else if (0 == strcmp(cmd, "del_rx")) { + if (rc < 3) { + wil_err(wil, + "BACK: del_rx require at least 2 params\n"); + return -EINVAL; + } + if (rc < 4) + p3 = WLAN_REASON_QSTA_LEAVE_QBSS; + wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3); + } else { + wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd); + return -EINVAL; + } return len; } -static const struct file_operations fops_addba = { - .write = wil_write_addba, +static ssize_t wil_read_back(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + static const char text[] = "block ack control, write:\n" + " - \"add \" to trigger ADDBA\n" + "If missing, defaults to 0\n" + " - \"del_tx \" to trigger DELBA for Tx side\n" + " - \"del_rx \" to trigger DELBA for Rx side\n" + "If missing, set to \"STA_LEAVING\" (36)\n"; + + return simple_read_from_buffer(user_buf, count, ppos, text, + sizeof(text)); +} + +static const struct file_operations fops_back = { + .read = wil_read_back, + .write = wil_write_back, .open = simple_open, }; @@ -1268,7 +1305,7 @@ static const struct { {"rxon", S_IWUSR, &fops_rxon}, {"tx_mgmt", S_IWUSR, &fops_txmgmt}, {"wmi_send", S_IWUSR, &fops_wmi}, - {"addba", S_IWUSR, &fops_addba}, + {"back", S_IRUGO | S_IWUSR, &fops_back}, {"temp", S_IRUGO, &fops_temp}, {"freq", S_IRUGO, &fops_freq}, {"link", S_IRUGO, &fops_link}, -- cgit v1.2.1 From d8cfb80cb70711412a0b43d1a325fda8747d9b57 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:17 +0200 Subject: wil6210: detect HW capabilities Read relevant information (HW ID for now) once on init and set capabilities accordingly. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/pcie_bus.c | 32 ++++++++++++++++++++++++++++- drivers/net/wireless/ath/wil6210/wil6210.h | 20 ++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 66626a8ee728..371809dfca73 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -31,6 +31,36 @@ static bool debug_fw; /* = false; */ module_param(debug_fw, bool, S_IRUGO); MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug"); +static +void wil_set_capabilities(struct wil6210_priv *wil) +{ + u32 rev_id = ioread32(wil->csr + HOSTADDR(RGF_USER_JTAG_DEV_ID)); + + bitmap_zero(wil->hw_capabilities, hw_capability_last); + + switch (rev_id) { + case JTAG_DEV_ID_MARLON_B0: + wil_info(wil, "Board hardware is Marlon B0\n"); + wil->hw_version = HW_VER_MARLON_B0; + break; + case JTAG_DEV_ID_SPARROW_A0: + wil_info(wil, "Board hardware is Sparrow A0\n"); + wil->hw_version = HW_VER_SPARROW_A0; + break; + case JTAG_DEV_ID_SPARROW_A1: + wil_info(wil, "Board hardware is Sparrow A1\n"); + wil->hw_version = HW_VER_SPARROW_A1; + break; + case JTAG_DEV_ID_SPARROW_B0: + wil_info(wil, "Board hardware is Sparrow B0\n"); + wil->hw_version = HW_VER_SPARROW_B0; + break; + default: + wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id); + wil->hw_version = HW_VER_UNKNOWN; + } +} + void wil_disable_irq(struct wil6210_priv *wil) { int irq = wil->pdev->irq; @@ -205,7 +235,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, wil); wil->pdev = pdev; wil->board = board; - + wil_set_capabilities(wil); wil6210_clear_irq(wil); wil->platform_handle = diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 64a6d49a3001..d296f2e17e56 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -188,6 +188,20 @@ struct RGF_ICR { #define RGF_CAF_PLL_LOCK_STATUS (0x88afec) #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) +#define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */ + #define JTAG_DEV_ID_MARLON_B0 (0x0612072f) + #define JTAG_DEV_ID_SPARROW_A0 (0x0632072f) + #define JTAG_DEV_ID_SPARROW_A1 (0x1632072f) + #define JTAG_DEV_ID_SPARROW_B0 (0x2632072f) + +enum { + HW_VER_UNKNOWN, + HW_VER_MARLON_B0, /* JTAG_DEV_ID_MARLON_B0 */ + HW_VER_SPARROW_A0, /* JTAG_DEV_ID_SPARROW_A0 */ + HW_VER_SPARROW_A1, /* JTAG_DEV_ID_SPARROW_A1 */ + HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */ +}; + /* popular locations */ #define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ @@ -426,6 +440,11 @@ enum { fw_recovery_running = 2, }; +enum { + hw_capability_dummy, /* to avoid zero array */ + hw_capability_last +}; + struct wil_back_rx { struct list_head list; /* request params, converted to CPU byte order - what we asked for */ @@ -452,6 +471,7 @@ struct wil6210_priv { DECLARE_BITMAP(status, wil_status_last); u32 fw_version; u32 hw_version; + DECLARE_BITMAP(hw_capabilities, hw_capability_last); struct wil_board *board; u8 n_mids; /* number of additional MIDs as reported by FW */ u32 recovery_count; /* num of FW recovery attempts in a short time */ -- cgit v1.2.1 From 1aeda13be061d005b4b84c2a974bf11d0b8675ad Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:18 +0200 Subject: wil6210: use HW capabilities mask in reset Use the proper reset follow based on HW capabilities detection instead of chip ID. Remove old hw ID mechanism which was used only for reset flow. Remove support for Marlon A0. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/interrupt.c | 11 +++++---- drivers/net/wireless/ath/wil6210/main.c | 33 +++++++++++-------------- drivers/net/wireless/ath/wil6210/pcie_bus.c | 37 +++++++++++----------------- drivers/net/wireless/ath/wil6210/wil6210.h | 11 ++------- 4 files changed, 36 insertions(+), 56 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 5a0ea72d3710..384bb3171c45 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -194,18 +194,19 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) wil_dbg_irq(wil, "RX done\n"); if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH) - wil_err_ratelimited(wil, "Received \"Rx buffer is in risk " - "of overflow\" interrupt\n"); + wil_err_ratelimited(wil, + "Received \"Rx buffer is in risk of overflow\" interrupt\n"); - isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH); + isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | + BIT_DMA_EP_RX_ICR_RX_HTRSH); if (test_bit(wil_status_reset_done, wil->status)) { if (test_bit(wil_status_napi_en, wil->status)) { wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_rx); } else { - wil_err(wil, "Got Rx interrupt while " - "stopping interface\n"); + wil_err(wil, + "Got Rx interrupt while stopping interface\n"); } } else { wil_err(wil, "Got Rx interrupt while in reset\n"); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index a17278f4090a..fb73ac5fa00e 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -502,13 +502,10 @@ static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; u32 x; - u32 rev_id; - bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW); + bool is_reset_v2 = test_bit(hw_capability_reset_v2, + wil->hw_capabilities); - wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name); - - wil->hw_version = R(RGF_USER_FW_REV_ID); - rev_id = wil->hw_version & 0xff; + wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); /* Clear MAC link up */ S(RGF_HP_CTRL, BIT(15)); @@ -520,7 +517,7 @@ static int wil_target_reset(struct wil6210_priv *wil) /* Clear Fw Download notification */ C(RGF_USER_USAGE_6, BIT(0)); - if (is_sparrow) { + if (is_reset_v2) { S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); /* XTAL stabilization should take about 3ms */ usleep_range(5000, 7000); @@ -541,10 +538,11 @@ static int wil_target_reset(struct wil6210_priv *wil) W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, + is_reset_v2 ? 0x000000f0 : 0x00000170); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); - if (is_sparrow) { + if (is_reset_v2) { W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); } @@ -554,19 +552,14 @@ static int wil_target_reset(struct wil6210_priv *wil) W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - if (is_sparrow) { + if (is_reset_v2) { W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); /* reset A2 PCIE AHB */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); } else { W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); - if (rev_id == 1) { - /* reset A1 BOTH PCIE AHB & PCIE RGF */ - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); - } else { - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } + W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); } /* TODO: check order here!!! Erez code is different */ @@ -583,8 +576,7 @@ static int wil_target_reset(struct wil6210_priv *wil) } } while (x != HW_MACHINE_BOOT_DONE); - /* TODO: Erez check rev_id != 1 */ - if (!is_sparrow && (rev_id != 1)) + if (!is_reset_v2) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); @@ -653,6 +645,9 @@ int wil_reset(struct wil6210_priv *wil) wil_dbg_misc(wil, "%s()\n", __func__); + if (wil->hw_version == HW_VER_UNKNOWN) + return -ENODEV; + WARN_ON(!mutex_is_locked(&wil->mutex)); WARN_ON(test_bit(wil_status_napi_en, wil->status)); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 371809dfca73..9b1a589cefbd 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -40,25 +40,31 @@ void wil_set_capabilities(struct wil6210_priv *wil) switch (rev_id) { case JTAG_DEV_ID_MARLON_B0: - wil_info(wil, "Board hardware is Marlon B0\n"); + wil->hw_name = "Marlon B0"; wil->hw_version = HW_VER_MARLON_B0; break; case JTAG_DEV_ID_SPARROW_A0: - wil_info(wil, "Board hardware is Sparrow A0\n"); + wil->hw_name = "Sparrow A0"; wil->hw_version = HW_VER_SPARROW_A0; break; case JTAG_DEV_ID_SPARROW_A1: - wil_info(wil, "Board hardware is Sparrow A1\n"); + wil->hw_name = "Sparrow A1"; wil->hw_version = HW_VER_SPARROW_A1; break; case JTAG_DEV_ID_SPARROW_B0: - wil_info(wil, "Board hardware is Sparrow B0\n"); + wil->hw_name = "Sparrow B0"; wil->hw_version = HW_VER_SPARROW_B0; break; default: wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id); + wil->hw_name = "Unknown"; wil->hw_version = HW_VER_UNKNOWN; } + + wil_info(wil, "Board hardware is %s\n", wil->hw_name); + + if (wil->hw_version >= HW_VER_SPARROW_A0) + set_bit(hw_capability_reset_v2, wil->hw_capabilities); } void wil_disable_irq(struct wil6210_priv *wil) @@ -179,12 +185,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct wil6210_priv *wil; struct device *dev = &pdev->dev; void __iomem *csr; - struct wil_board *board = (struct wil_board *)id->driver_data; int rc; /* check HW */ dev_info(&pdev->dev, WIL_NAME - " \"%s\" device found [%04x:%04x] (rev %x)\n", board->name, + " device found [%04x:%04x] (rev %x)\n", (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { @@ -234,7 +239,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, wil); wil->pdev = pdev; - wil->board = board; wil_set_capabilities(wil); wil6210_clear_irq(wil); @@ -296,23 +300,10 @@ static void wil_pcie_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static const struct wil_board wil_board_marlon = { - .board = WIL_BOARD_MARLON, - .name = "marlon", -}; - -static const struct wil_board wil_board_sparrow = { - .board = WIL_BOARD_SPARROW, - .name = "sparrow", -}; - static const struct pci_device_id wil6210_pcie_ids[] = { - { PCI_DEVICE(0x1ae9, 0x0301), - .driver_data = (kernel_ulong_t)&wil_board_marlon }, - { PCI_DEVICE(0x1ae9, 0x0310), - .driver_data = (kernel_ulong_t)&wil_board_sparrow }, - { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */ - .driver_data = (kernel_ulong_t)&wil_board_sparrow }, + { PCI_DEVICE(0x1ae9, 0x0301) }, + { PCI_DEVICE(0x1ae9, 0x0310) }, + { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index d296f2e17e56..8a52a5ffd6b1 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -32,13 +32,6 @@ extern int agg_wsize; #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ -struct wil_board { - int board; -#define WIL_BOARD_MARLON (1) -#define WIL_BOARD_SPARROW (2) - const char * const name; -}; - /** * extract bits [@b0:@b1] (inclusive) from the value @x * it should be @b0 <= @b1, or result is incorrect @@ -441,7 +434,7 @@ enum { }; enum { - hw_capability_dummy, /* to avoid zero array */ + hw_capability_reset_v2 = 0, hw_capability_last }; @@ -471,8 +464,8 @@ struct wil6210_priv { DECLARE_BITMAP(status, wil_status_last); u32 fw_version; u32 hw_version; + const char *hw_name; DECLARE_BITMAP(hw_capabilities, hw_capability_last); - struct wil_board *board; u8 n_mids; /* number of additional MIDs as reported by FW */ u32 recovery_count; /* num of FW recovery attempts in a short time */ u32 recovery_state; /* FW recovery state machine */ -- cgit v1.2.1 From 78366f69beb604717a12191eee35300057b6bcfc Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:19 +0200 Subject: wil6210: add advanced interrupt moderation Add advanced interrupt moderation support available since "Sparrow B0". Legacy interrupt moderation used only one counter to moderate tx, rx, and misc interrupts. Advanced interrupt moderation bypasses misc, and handles separately tx and rx interrupts. In addition it has two timers for each interrupt type. Max burst duration timer which defines how long to postpone interrupt after first event (receive event for rx and tx complete event for tx), and interframe timeout which defines how to determine the end of the burst and issue interrupt even if the first timer still pending. Capabilities flags in wil_priv is set on initialization according to HW. The rest of the code checks for advanced interrupt capability bit in capabilities flags field. Debugfs is split accordingly: "legacy" interrupt moderation remains unchanged, new debugs files added for advanced interrupt moderation support. Module params are aligned to support advanced interrupt moderation (tx & rx). When not available (for legacy interrupt moderation) will use only rx configuration; Tx configuration will be ignored in this case. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 49 ++++++++++++++++- drivers/net/wireless/ath/wil6210/ethtool.c | 46 ++++++++++++---- drivers/net/wireless/ath/wil6210/interrupt.c | 82 +++++++++++++++++++++++++++- drivers/net/wireless/ath/wil6210/main.c | 56 +++++++++++-------- drivers/net/wireless/ath/wil6210/pcie_bus.c | 4 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 56 +++++++++++++++++-- 6 files changed, 247 insertions(+), 46 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 05f9620c260d..2f6f520c29fa 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -390,24 +390,67 @@ static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, return 0; } -static const struct dbg_off itr_cnt_off[] = { +static const struct dbg_off lgc_itr_cnt_off[] = { {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32}, {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32}, {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32}, {}, }; +static const struct dbg_off tx_itr_cnt_off[] = { + {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH), + doff_io32}, + {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA), + doff_io32}, + {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL), + doff_io32}, + {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH), + doff_io32}, + {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA), + doff_io32}, + {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL), + doff_io32}, + {}, +}; + +static const struct dbg_off rx_itr_cnt_off[] = { + {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH), + doff_io32}, + {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA), + doff_io32}, + {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL), + doff_io32}, + {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH), + doff_io32}, + {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA), + doff_io32}, + {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL), + doff_io32}, + {}, +}; + static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, struct dentry *parent) { - struct dentry *d = debugfs_create_dir("ITR_CNT", parent); + struct dentry *d, *dtx, *drx; + d = debugfs_create_dir("ITR_CNT", parent); if (IS_ERR_OR_NULL(d)) return -ENODEV; + dtx = debugfs_create_dir("TX", d); + drx = debugfs_create_dir("RX", d); + if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx)) + return -ENODEV; + wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, - itr_cnt_off); + lgc_itr_cnt_off); + + wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr, + tx_itr_cnt_off); + wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr, + rx_itr_cnt_off); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index d686638972be..4c44a82c34d7 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -45,16 +45,35 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *cp) { struct wil6210_priv *wil = ndev_to_wil(ndev); - u32 itr_en, itr_val = 0; + u32 tx_itr_en, tx_itr_val = 0; + u32 rx_itr_en, rx_itr_val = 0; wil_dbg_misc(wil, "%s()\n", __func__); - itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); - if (itr_en & BIT_DMA_ITR_CNT_CRL_EN) - itr_val = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); - - cp->rx_coalesce_usecs = itr_val; + if (test_bit(hw_capability_advanced_itr_moderation, + wil->hw_capabilities)) { + tx_itr_en = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); + if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) + tx_itr_val = + ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); + + rx_itr_en = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); + if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) + rx_itr_val = + ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); + } else { + rx_itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); + if (rx_itr_en & BIT_DMA_ITR_CNT_CRL_EN) + rx_itr_val = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); + } + cp->tx_coalesce_usecs = tx_itr_val; + cp->rx_coalesce_usecs = rx_itr_val; return 0; } @@ -63,22 +82,25 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev, { struct wil6210_priv *wil = ndev_to_wil(ndev); - wil_dbg_misc(wil, "%s(%d usec)\n", __func__, cp->rx_coalesce_usecs); + wil_dbg_misc(wil, "%s(rx %d usec, tx %d usec)\n", __func__, + cp->rx_coalesce_usecs, cp->tx_coalesce_usecs); if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n"); return -EINVAL; } - /* only @rx_coalesce_usecs supported, ignore - * other parameters + /* only @rx_coalesce_usecs and @tx_coalesce_usecs supported, + * ignore other parameters */ - if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX) + if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX || + cp->tx_coalesce_usecs > WIL6210_ITR_TRSH_MAX) goto out_bad; - wil->itr_trsh = cp->rx_coalesce_usecs; - wil_set_itr_trsh(wil); + wil->tx_max_burst_duration = cp->tx_coalesce_usecs; + wil->rx_max_burst_duration = cp->rx_coalesce_usecs; + wil_configure_interrupt_moderation(wil); return 0; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 384bb3171c45..a6f923086f31 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -157,15 +157,91 @@ void wil_unmask_irq(struct wil6210_priv *wil) iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICC)); - /* interrupt moderation parameters */ - wil_set_itr_trsh(wil); - wil6210_unmask_irq_pseudo(wil); wil6210_unmask_irq_tx(wil); wil6210_unmask_irq_rx(wil); wil6210_unmask_irq_misc(wil); } +/* target write operation */ +#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) + +static +void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil) +{ + /* Disable and clear tx counter before (re)configuration */ + W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); + W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration); + wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n", + wil->tx_max_burst_duration); + /* Configure TX max burst duration timer to use usec units */ + W(RGF_DMA_ITR_TX_CNT_CTL, + BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL); + + /* Disable and clear tx idle counter before (re)configuration */ + W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR); + W(RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout); + wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n", + wil->tx_interframe_timeout); + /* Configure TX max burst duration timer to use usec units */ + W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN | + BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL); + + /* Disable and clear rx counter before (re)configuration */ + W(RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR); + W(RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration); + wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n", + wil->rx_max_burst_duration); + /* Configure TX max burst duration timer to use usec units */ + W(RGF_DMA_ITR_RX_CNT_CTL, + BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL); + + /* Disable and clear rx idle counter before (re)configuration */ + W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR); + W(RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout); + wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n", + wil->rx_interframe_timeout); + /* Configure TX max burst duration timer to use usec units */ + W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN | + BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL); +} + +static +void wil_configure_interrupt_moderation_lgc(struct wil6210_priv *wil) +{ + /* disable, use usec resolution */ + W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_CLR); + + wil_info(wil, "set ITR_TRSH = %d usec\n", wil->rx_max_burst_duration); + W(RGF_DMA_ITR_CNT_TRSH, wil->rx_max_burst_duration); + /* start it */ + W(RGF_DMA_ITR_CNT_CRL, + BIT_DMA_ITR_CNT_CRL_EN | BIT_DMA_ITR_CNT_CRL_EXT_TICK); +} + +#undef W + +void wil_configure_interrupt_moderation(struct wil6210_priv *wil) +{ + wil_dbg_irq(wil, "%s()\n", __func__); + + /* disable interrupt moderation for monitor + * to get better timestamp precision + */ + if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) + return; + + if (test_bit(hw_capability_advanced_itr_moderation, + wil->hw_capabilities)) + wil_configure_interrupt_moderation_new(wil); + else { + /* Advanced interrupt moderation is not available before + * Sparrow v2. Will use legacy interrupt moderation + */ + wil_configure_interrupt_moderation_lgc(wil); + } +} + static irqreturn_t wil6210_irq_rx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index fb73ac5fa00e..d28615369d20 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -33,10 +33,34 @@ static bool no_fw_load = true; module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash."); -static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT; +static unsigned int tx_interframe_timeout = + WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT; + +module_param(tx_interframe_timeout, uint, S_IRUGO); +MODULE_PARM_DESC(tx_interframe_timeout, + " Interrupt moderation TX interframe timeout, usecs."); + +static unsigned int rx_interframe_timeout = + WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT; + +module_param(rx_interframe_timeout, uint, S_IRUGO); +MODULE_PARM_DESC(rx_interframe_timeout, + " Interrupt moderation RX interframe timeout, usecs."); + +static unsigned int tx_max_burst_duration = + WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT; + +module_param(tx_max_burst_duration, uint, S_IRUGO); +MODULE_PARM_DESC(tx_max_burst_duration, + " Interrupt moderation TX max burst duration, usecs."); + +static unsigned int rx_max_burst_duration = + WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT; + +module_param(rx_max_burst_duration, uint, S_IRUGO); +MODULE_PARM_DESC(rx_max_burst_duration, + " Interrupt moderation RX max burst duration, usecs."); -module_param(itr_trsh, uint, S_IRUGO); -MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs."); /* We allow allocation of more than 1 page buffers to support large packets. * It is suboptimal behavior performance wise in case MTU above page size. @@ -427,7 +451,10 @@ int wil_priv_init(struct wil6210_priv *wil) goto out_wmi_wq; wil->last_fw_recovery = jiffies; - wil->itr_trsh = itr_trsh; + wil->tx_interframe_timeout = tx_interframe_timeout; + wil->rx_interframe_timeout = rx_interframe_timeout; + wil->tx_max_burst_duration = tx_max_burst_duration; + wil->rx_max_burst_duration = rx_max_burst_duration; return 0; @@ -585,26 +612,6 @@ static int wil_target_reset(struct wil6210_priv *wil) return 0; } -/** - * wil_set_itr_trsh: - apply interrupt coalescing params - */ -void wil_set_itr_trsh(struct wil6210_priv *wil) -{ - /* disable, use usec resolution */ - W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EXT_TICK); - - /* disable interrupt moderation for monitor - * to get better timestamp precision - */ - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) - return; - - wil_info(wil, "set ITR_TRSH = %d usec\n", wil->itr_trsh); - W(RGF_DMA_ITR_CNT_TRSH, wil->itr_trsh); - W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EN | - BIT_DMA_ITR_CNT_CRL_EXT_TICK); /* start it */ -} - #undef R #undef W #undef S @@ -708,6 +715,7 @@ int wil_reset(struct wil6210_priv *wil) reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_call); + wil_configure_interrupt_moderation(wil); wil_unmask_irq(wil); /* we just started MAC, wait for FW ready */ diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 9b1a589cefbd..3dd26709ccb2 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -65,6 +65,10 @@ void wil_set_capabilities(struct wil6210_priv *wil) if (wil->hw_version >= HW_VER_SPARROW_A0) set_bit(hw_capability_reset_v2, wil->hw_capabilities); + + if (wil->hw_version >= HW_VER_SPARROW_B0) + set_bit(hw_capability_advanced_itr_moderation, + wil->hw_capabilities); } void wil_disable_irq(struct wil6210_priv *wil) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 8a52a5ffd6b1..a6d63c157b2f 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -76,7 +76,10 @@ static inline u32 wil_mtu2macbuf(u32 mtu) #define WIL_MAX_ETH_MTU (IEEE80211_MAX_DATA_LEN_DMG - 8) /* Max supported by wil6210 value for interrupt threshold is 5sec. */ #define WIL6210_ITR_TRSH_MAX (5000000) -#define WIL6210_ITR_TRSH_DEFAULT (300) /* usec */ +#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */ +#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */ +#define WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT (500) /* usec */ +#define WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT (500) /* usec */ #define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */ #define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000) #define WIL6210_SCAN_TO msecs_to_jiffies(10000) @@ -152,7 +155,7 @@ struct RGF_ICR { #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) #define BIT_DMA_EP_MISC_ICR_FW_INT(n) BIT(28+n) /* n = [0..3] */ -/* Interrupt moderation control */ +/* Legacy interrupt moderation control (before Sparrow v2)*/ #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) #define RGF_DMA_ITR_CNT_DATA (0x881c60) #define RGF_DMA_ITR_CNT_CRL (0x881c64) @@ -162,6 +165,46 @@ struct RGF_ICR { #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) +/* New (sparrow v2+) interrupt moderation control */ +#define RGF_DMA_ITR_TX_DESQ_NO_MOD (0x881d40) +#define RGF_DMA_ITR_TX_CNT_TRSH (0x881d34) +#define RGF_DMA_ITR_TX_CNT_DATA (0x881d38) +#define RGF_DMA_ITR_TX_CNT_CTL (0x881d3c) + #define BIT_DMA_ITR_TX_CNT_CTL_EN BIT(0) + #define BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL BIT(1) + #define BIT_DMA_ITR_TX_CNT_CTL_FOREVER BIT(2) + #define BIT_DMA_ITR_TX_CNT_CTL_CLR BIT(3) + #define BIT_DMA_ITR_TX_CNT_CTL_REACHED_TRESH BIT(4) + #define BIT_DMA_ITR_TX_CNT_CTL_CROSS_EN BIT(5) + #define BIT_DMA_ITR_TX_CNT_CTL_FREE_RUNNIG BIT(6) +#define RGF_DMA_ITR_TX_IDL_CNT_TRSH (0x881d60) +#define RGF_DMA_ITR_TX_IDL_CNT_DATA (0x881d64) +#define RGF_DMA_ITR_TX_IDL_CNT_CTL (0x881d68) + #define BIT_DMA_ITR_TX_IDL_CNT_CTL_EN BIT(0) + #define BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL BIT(1) + #define BIT_DMA_ITR_TX_IDL_CNT_CTL_FOREVER BIT(2) + #define BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR BIT(3) + #define BIT_DMA_ITR_TX_IDL_CNT_CTL_REACHED_TRESH BIT(4) +#define RGF_DMA_ITR_RX_DESQ_NO_MOD (0x881d50) +#define RGF_DMA_ITR_RX_CNT_TRSH (0x881d44) +#define RGF_DMA_ITR_RX_CNT_DATA (0x881d48) +#define RGF_DMA_ITR_RX_CNT_CTL (0x881d4c) + #define BIT_DMA_ITR_RX_CNT_CTL_EN BIT(0) + #define BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL BIT(1) + #define BIT_DMA_ITR_RX_CNT_CTL_FOREVER BIT(2) + #define BIT_DMA_ITR_RX_CNT_CTL_CLR BIT(3) + #define BIT_DMA_ITR_RX_CNT_CTL_REACHED_TRESH BIT(4) + #define BIT_DMA_ITR_RX_CNT_CTL_CROSS_EN BIT(5) + #define BIT_DMA_ITR_RX_CNT_CTL_FREE_RUNNIG BIT(6) +#define RGF_DMA_ITR_RX_IDL_CNT_TRSH (0x881d54) +#define RGF_DMA_ITR_RX_IDL_CNT_DATA (0x881d58) +#define RGF_DMA_ITR_RX_IDL_CNT_CTL (0x881d5c) + #define BIT_DMA_ITR_RX_IDL_CNT_CTL_EN BIT(0) + #define BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL BIT(1) + #define BIT_DMA_ITR_RX_IDL_CNT_CTL_FOREVER BIT(2) + #define BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR BIT(3) + #define BIT_DMA_ITR_RX_IDL_CNT_CTL_REACHED_TRESH BIT(4) + #define RGF_DMA_PSEUDO_CAUSE (0x881c68) #define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) #define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) @@ -435,6 +478,7 @@ enum { enum { hw_capability_reset_v2 = 0, + hw_capability_advanced_itr_moderation = 1, hw_capability_last }; @@ -475,7 +519,11 @@ struct wil6210_priv { u32 monitor_flags; u32 secure_pcp; /* create secure PCP? */ int sinfo_gen; - u32 itr_trsh; + /* interrupt moderation */ + u32 tx_max_burst_duration; + u32 tx_interframe_timeout; + u32 rx_max_burst_duration; + u32 rx_interframe_timeout; /* cached ISR registers */ u32 isr_misc; /* mailbox related */ @@ -596,7 +644,6 @@ void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); int wil_reset(struct wil6210_priv *wil); -void wil_set_itr_trsh(struct wil6210_priv *wil); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); void wil_link_on(struct wil6210_priv *wil); @@ -653,6 +700,7 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); void wil_mask_irq(struct wil6210_priv *wil); void wil_unmask_irq(struct wil6210_priv *wil); +void wil_configure_interrupt_moderation(struct wil6210_priv *wil); void wil_disable_irq(struct wil6210_priv *wil); void wil_enable_irq(struct wil6210_priv *wil); int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, -- cgit v1.2.1 From ab95462825edf7decdd0f77be5c2c1ebb07a1943 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:20 +0200 Subject: wil6210: RX high threshold interrupt configuration Rx high threshold interrupt is reported by the hardware in case when number of not utilized by the HW descriptors in the Rx ring becomes low. Introduce module parameter for RX high threshold. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 9 +++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 5 ++++- drivers/net/wireless/ath/wil6210/wmi.c | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index d28615369d20..f44b640dff79 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -61,6 +61,13 @@ module_param(rx_max_burst_duration, uint, S_IRUGO); MODULE_PARM_DESC(rx_max_burst_duration, " Interrupt moderation RX max burst duration, usecs."); +/* if not set via modparam, will be set to default value of 1/8 of + * rx ring size during init flow + */ +unsigned short rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_INIT; +module_param(rx_ring_overflow_thrsh, ushort, S_IRUGO); +MODULE_PARM_DESC(rx_ring_overflow_thrsh, + " RX ring overflow threshold in descriptors."); /* We allow allocation of more than 1 page buffers to support large packets. * It is suboptimal behavior performance wise in case MTU above page size. @@ -456,6 +463,8 @@ int wil_priv_init(struct wil6210_priv *wil) wil->tx_max_burst_duration = tx_max_burst_duration; wil->rx_max_burst_duration = rx_max_burst_duration; + if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT) + rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT; return 0; out_wmi_wq: diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index a6d63c157b2f..da3fe7853d63 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -25,6 +25,7 @@ extern bool no_fw_recovery; extern unsigned int mtu_max; +extern unsigned short rx_ring_overflow_thrsh; extern int agg_wsize; #define WIL_NAME "wil6210" @@ -83,7 +84,9 @@ static inline u32 wil_mtu2macbuf(u32 mtu) #define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */ #define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000) #define WIL6210_SCAN_TO msecs_to_jiffies(10000) - +#define WIL6210_RX_HIGH_TRSH_INIT (0) +#define WIL6210_RX_HIGH_TRSH_DEFAULT \ + (1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3)) /* Hardware definitions begin */ /* diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index a4b30a40cefa..432ec55298f2 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1090,6 +1090,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) .mid = 0, /* TODO - what is it? */ .decap_trans_type = WMI_DECAP_TYPE_802_3, .reorder_type = WMI_RX_SW_REORDER, + .host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh), }; struct { struct wil6210_mbox_hdr_wmi wmi; -- cgit v1.2.1 From e4373d8e4a340c530dfdbe3afef14cea96b13792 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:21 +0200 Subject: wil6210: fix reordering for MCAST In the reordering block, Ethernet DA was checked for MCAST, this is wrong. Check instead MCAST indication from 802.11 MAC header. Hardware saves this into Rx descriptor. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/rx_reorder.c | 10 ++++++++-- drivers/net/wireless/ath/wil6210/txrx.c | 8 +------- drivers/net/wireless/ath/wil6210/txrx.h | 5 +++++ 3 files changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 0865c3430e51..20d65f224f7c 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -97,14 +97,20 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) int cid = wil_rxdesc_cid(d); int mid = wil_rxdesc_mid(d); u16 seq = wil_rxdesc_seq(d); + int mcast = wil_rxdesc_mcast(d); struct wil_sta_info *sta = &wil->sta[cid]; struct wil_tid_ampdu_rx *r; u16 hseq; int index; unsigned long flags; - wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n", - mid, cid, tid, seq); + wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n", + mid, cid, tid, seq, mcast); + + if (unlikely(mcast)) { + wil_netif_rx_any(skb, ndev); + return; + } spin_lock_irqsave(&sta->tid_rx_lock, flags); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 4c145eea9c32..5fc5f56545ce 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -581,14 +581,8 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) skb->protocol = htons(ETH_P_802_2); wil_netif_rx_any(skb, ndev); } else { - struct ethhdr *eth = (void *)skb->data; - skb->protocol = eth_type_trans(skb, ndev); - - if (is_unicast_ether_addr(eth->h_dest)) - wil_rx_reorder(wil, skb); - else - wil_netif_rx_any(skb, ndev); + wil_rx_reorder(wil, skb); } } wil_rx_refill(wil, v->size); diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index e7db35646cdd..c906c5f0b663 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -423,6 +423,11 @@ static inline int wil_rxdesc_mcs(struct vring_rx_desc *d) return WIL_GET_BITS(d->mac.d1, 21, 24); } +static inline int wil_rxdesc_mcast(struct vring_rx_desc *d) +{ + return WIL_GET_BITS(d->mac.d1, 13, 14); +} + static inline int wil_rxdesc_phy_length(struct vring_rx_desc *d) { return WIL_GET_BITS(d->dma.d0, 16, 29); -- cgit v1.2.1 From 8d3b2f033f8ceb30db60fd23ffbf9525ed2456f4 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:22 +0200 Subject: wil6210: Tx/Rx descriptors documentation Sync documentation for the Tx/Rx descriptors with the firmware/hardware documentation. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.h | 149 +++++++++++++++++++++----------- 2 files changed, 98 insertions(+), 53 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 5fc5f56545ce..b58ee52e1860 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -463,7 +463,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, * and in case of error drop the packet * higher stack layers will handle retransmission (if required) */ - if (d->dma.status & RX_DMA_STATUS_L4_IDENT) { + if (d->dma.status & RX_DMA_STATUS_L4I) { /* L4 protocol identified, csum calculated */ if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0) skb->ip_summed = CHECKSUM_UNNECESSARY; diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index c906c5f0b663..d90c8aa20c15 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -28,9 +28,7 @@ /* Tx/Rx path */ -/* - * Common representation of physical address in Vring - */ +/* Common representation of physical address in Vring */ struct vring_dma_addr { __le32 addr_low; __le16 addr_high; @@ -49,11 +47,10 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr, addr->addr_high = cpu_to_le16((u16)upper_32_bits(pa)); } -/* - * Tx descriptor - MAC part +/* Tx descriptor - MAC part * [dword 0] * bit 0.. 9 : lifetime_expiry_value:10 - * bit 10 : interrup_en:1 + * bit 10 : interrupt_en:1 * bit 11 : status_en:1 * bit 12..13 : txss_override:2 * bit 14 : timestamp_insertion:1 @@ -61,15 +58,12 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr, * bit 16..21 : reserved0:6 * bit 22..26 : mcs_index:5 * bit 27 : mcs_en:1 - * bit 28..29 : reserved1:2 - * bit 30 : reserved2:1 + * bit 28..30 : reserved1:3 * bit 31 : sn_preserved:1 * [dword 1] * bit 0.. 3 : pkt_mode:4 * bit 4 : pkt_mode_en:1 - * bit 5.. 7 : reserved0:3 - * bit 8..13 : reserved1:6 - * bit 14 : reserved2:1 + * bit 5..14 : reserved0:10 * bit 15 : ack_policy_en:1 * bit 16..19 : dst_index:4 * bit 20 : dst_index_en:1 @@ -80,7 +74,7 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr, * [dword 2] * bit 0.. 7 : num_of_descriptors:8 * bit 8..17 : reserved:10 - * bit 18..19 : l2_translation_type:2 + * bit 18..19 : l2_translation_type:2 00 - bypass, 01 - 802.3, 10 - 802.11 * bit 20 : snap_hdr_insertion_en:1 * bit 21 : vlan_removal_en:1 * bit 22..31 : reserved0:10 @@ -247,6 +241,46 @@ struct vring_tx_mac { #define TX_DMA_STATUS_DU BIT(0) +/* Tx descriptor - DMA part + * [dword 0] + * bit 0.. 7 : l4_length:8 layer 4 length + * bit 8 : cmd_eop:1 This descriptor is the last one in the packet + * bit 9 : reserved + * bit 10 : cmd_dma_it:1 immediate interrupt + * bit 11..12 : SBD - Segment Buffer Details + * 00 - Header Segment + * 01 - First Data Segment + * 10 - Medium Data Segment + * 11 - Last Data Segment + * bit 13 : TSE - TCP Segmentation Enable + * bit 14 : IIC - Directs the HW to Insert IPv4 Checksum + * bit 15 : ITC - Directs the HW to Insert TCP/UDP Checksum + * bit 16..20 : QID - The target QID that the packet should be stored + * in the MAC. + * bit 21 : PO - Pseudo header Offload: + * 0 - Use the pseudo header value from the TCP checksum field + * 1- Calculate Pseudo header Checksum + * bit 22 : NC - No UDP Checksum + * bit 23..29 : reserved + * bit 30..31 : L4T - Layer 4 Type: 00 - UDP , 10 - TCP , 10, 11 - Reserved + * If L4Len equal 0, no L4 at all + * [dword 1] + * bit 0..31 : addr_low:32 The payload buffer low address + * [dword 2] + * bit 0..15 : addr_high:16 The payload buffer high address + * bit 16..23 : ip_length:8 The IP header length for the TX IP checksum + * offload feature + * bit 24..30 : mac_length:7 + * bit 31 : ip_version:1 1 - IPv4, 0 - IPv6 + * [dword 3] + * [byte 12] error + * bit 0 2 : mac_status:3 + * bit 3 7 : reserved:5 + * [byte 13] status + * bit 0 : DU:1 Descriptor Used + * bit 1 7 : reserved:7 + * [word 7] length + */ struct vring_tx_dma { u32 d0; struct vring_dma_addr addr; @@ -257,45 +291,45 @@ struct vring_tx_dma { __le16 length; } __packed; -/* - * Rx descriptor - MAC part +/* Rx descriptor - MAC part * [dword 0] * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field - * bit 4.. 6 : connection_id:3 :The Source index that was found during - * Parsing the TA. This field is used to define the source of the packet + * bit 4.. 6 : cid:3 The Source index that was found during parsing the TA. + * This field is used to define the source of the packet * bit 7 : reserved:1 - * bit 8.. 9 : mac_id:2 : The MAC virtual Ring number (always zero) - * bit 10..11 : frame_type:2 : The FC Control (b3-2) - MPDU Type - * (management, data, control and extension) - * bit 12..15 : frame_subtype:4 : The FC Control (b7-4) - Frame Subtype + * bit 8.. 9 : mid:2 The MAC virtual number + * bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type + * (management, data, control and extension) + * bit 12..15 : frame_subtype:4 : The FC (b7-4) - Frame Subtype * bit 16..27 : seq_number:12 The received Sequence number field * bit 28..31 : extended:4 extended subtype * [dword 1] * bit 0.. 3 : reserved * bit 4.. 5 : key_id:2 * bit 6 : decrypt_bypass:1 - * bit 7 : security:1 - * bit 8.. 9 : ds_bits:2 - * bit 10 : a_msdu_present:1 from qos header - * bit 11 : a_msdu_type:1 from qos header + * bit 7 : security:1 FC (b14) + * bit 8.. 9 : ds_bits:2 FC (b9-8) + * bit 10 : a_msdu_present:1 QoS (b7) + * bit 11 : a_msdu_type:1 QoS (b8) * bit 12 : a_mpdu:1 part of AMPDU aggregation * bit 13 : broadcast:1 * bit 14 : mutlicast:1 * bit 15 : reserved:1 - * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet - * is received from + * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet + * is received from * bit 21..24 : mcs:4 - * bit 25..28 : mic_icr:4 + * bit 25..28 : mic_icr:4 this signal tells the DMA to assert an interrupt + * after it writes the packet * bit 29..31 : reserved:3 * [dword 2] * bit 0.. 2 : time_slot:3 The timeslot that the MPDU is received - * bit 3 : fc_protocol_ver:1 The FC Control (b0) - Protocol Version - * bit 4 : fc_order:1 The FC Control (b15) -Order - * bit 5.. 7 : qos_ack_policy:3 The QoS (b6-5) ack policy Field + * bit 3.. 4 : fc_protocol_ver:1 The FC (b1-0) - Protocol Version + * bit 5 : fc_order:1 The FC Control (b15) -Order + * bit 6.. 7 : qos_ack_policy:2 The QoS (b6-5) ack policy Field * bit 8 : esop:1 The QoS (b4) ESOP field - * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field - * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field - * bit 15 : qos_ac_constraint:1 + * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field + * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field + * bit 15 : qos_ac_constraint:1 QoS (b15) * bit 16..31 : pn_15_0:16 low 2 bytes of PN * [dword 3] * bit 0..31 : pn_47_16:32 high 4 bytes of PN @@ -308,35 +342,46 @@ struct vring_rx_mac { u32 pn_47_16; } __packed; -/* - * Rx descriptor - DMA part +/* Rx descriptor - DMA part * [dword 0] - * bit 0.. 7 : l4_length:8 layer 4 length - * bit 8.. 9 : reserved:2 - * bit 10 : cmd_dma_it:1 + * bit 0.. 7 : l4_length:8 layer 4 length. The field is only valid if + * L4I bit is set + * bit 8 : cmd_eop:1 set to 1 + * bit 9 : cmd_rt:1 set to 1 + * bit 10 : cmd_dma_it:1 immediate interrupt * bit 11..15 : reserved:5 - * bit 16..29 : phy_info_length:14 + * bit 16..29 : phy_info_length:14 It is valid when the PII is set. + * When the FFM bit is set bits 29-27 are used for for + * Flex Filter Match. Matching Index to one of the L2 + * EtherType Flex Filter * bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field + * 00 - UDP, 01 - TCP, 10, 11 - reserved * [dword 1] * bit 0..31 : addr_low:32 The payload buffer low address * [dword 2] * bit 0..15 : addr_high:16 The payload buffer high address - * bit 16..23 : ip_length:8 + * bit 16..23 : ip_length:8 The filed is valid only if the L3I bit is set * bit 24..30 : mac_length:7 - * bit 31 : ip_version:1 + * bit 31 : ip_version:1 1 - IPv4, 0 - IPv6 * [dword 3] * [byte 12] error + * bit 0 : FCS:1 + * bit 1 : MIC:1 + * bit 2 : Key miss:1 + * bit 3 : Replay:1 + * bit 4 : L3:1 IPv4 checksum + * bit 5 : L4:1 TCP/UDP checksum + * bit 6 7 : reserved:2 * [byte 13] status - * bit 0 : du:1 - * bit 1 : eop:1 + * bit 0 : DU:1 Descriptor Used + * bit 1 : EOP:1 The descriptor indicates the End of Packet * bit 2 : error:1 - * bit 3 : mi:1 - * bit 4 : l3_identified:1 - * bit 5 : l4_identified:1 - * bit 6 : phy_info_included:1 - * bit 7 : reserved:1 + * bit 3 : MI:1 MAC Interrupt is asserted (according to parser decision) + * bit 4 : L3I:1 L3 identified and checksum calculated + * bit 5 : L4I:1 L4 identified and checksum calculated + * bit 6 : PII:1 PHY Info Included in the packet + * bit 7 : FFM:1 EtherType Flex Filter Match * [word 7] length - * */ #define RX_DMA_D0_CMD_DMA_IT BIT(10) @@ -349,9 +394,9 @@ struct vring_rx_mac { #define RX_DMA_STATUS_DU BIT(0) #define RX_DMA_STATUS_ERROR BIT(2) -#define RX_DMA_STATUS_L3_IDENT BIT(4) -#define RX_DMA_STATUS_L4_IDENT BIT(5) -#define RX_DMA_STATUS_PHY_INFO BIT(6) +#define RX_DMA_STATUS_L3I BIT(4) +#define RX_DMA_STATUS_L4I BIT(5) +#define RX_DMA_STATUS_PHY_INFO BIT(6) struct vring_rx_dma { u32 d0; -- cgit v1.2.1 From ff7c5c3beff79e3f09b9805ff3cff29e2799ec61 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:23 +0200 Subject: wil6210: workaround for BACK establishment race When establishing BACK, WMI may be handled earlier then Rx, in this case late Rx will be mis-handled. Detect early Rx and pass it to the stack, bypass reordering Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/rx_reorder.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 20d65f224f7c..5af8012f931e 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -127,13 +127,24 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) * reported, and data Rx, few packets may be pass up before reorder * buffer get allocated. Catch up by pretending SSN is what we * see in the 1-st Rx packet + * + * Another scenario, Rx get delayed and we got packet from before + * BACK. Pass it to the stack and wait. */ if (r->first_time) { r->first_time = false; if (seq != r->head_seq_num) { - wil_err(wil, "Error: 1-st frame with wrong sequence" - " %d, should be %d. Fixing...\n", seq, - r->head_seq_num); + if (seq_less(seq, r->head_seq_num)) { + wil_err(wil, + "Error: frame with early sequence 0x%03x, should be 0x%03x. Waiting...\n", + seq, r->head_seq_num); + r->first_time = true; + wil_netif_rx_any(skb, ndev); + goto out; + } + wil_err(wil, + "Error: 1-st frame with wrong sequence 0x%03x, should be 0x%03x. Fixing...\n", + seq, r->head_seq_num); r->head_seq_num = seq; r->ssn = seq; } @@ -279,6 +290,7 @@ static void wil_back_rx_handle(struct wil6210_priv *wil, int ba_policy = req->ba_param_set & BIT(1); u16 agg_timeout = req->ba_timeout; u16 status = WLAN_STATUS_SUCCESS; + u16 ssn = req->ba_seq_ctrl >> 4; unsigned long flags; int rc; @@ -297,9 +309,9 @@ static void wil_back_rx_handle(struct wil6210_priv *wil, } wil_dbg_wmi(wil, - "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d\n", + "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d SSN 0x%03x\n", cid, sta->addr, tid, req_agg_wsize, req->ba_timeout, - agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token); + agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token, ssn); /* apply policies */ if (ba_policy) { @@ -318,8 +330,7 @@ static void wil_back_rx_handle(struct wil6210_priv *wil, spin_lock_irqsave(&sta->tid_rx_lock, flags); wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); - sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, - req->ba_seq_ctrl >> 4); + sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); spin_unlock_irqrestore(&sta->tid_rx_lock, flags); } -- cgit v1.2.1 From bd33273b652c85fd6c9e251cebd4362c72718639 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 23 Dec 2014 09:47:24 +0200 Subject: wil6210: relax spinlocks in rx reorder In the Rx reorder mechanism, nothing is done in the interrupt context, so there is no need to use 'irq' flavors of spinlock. Rx done in NAPI context (tasklet), other manipulations - in the thread context. Having interrupts enabled makes it better for the OS in general. Besides, if enslaved under bonding, bridge or team driver, Rx won't work with interrupts disabled. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 6 +++--- drivers/net/wireless/ath/wil6210/main.c | 7 ++++--- drivers/net/wireless/ath/wil6210/rx_reorder.c | 17 +++++++++-------- drivers/net/wireless/ath/wil6210/wmi.c | 7 ++++--- 4 files changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 2f6f520c29fa..45c3558ec804 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1258,10 +1258,10 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) } static int wil_sta_debugfs_show(struct seq_file *s, void *data) +__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) { struct wil6210_priv *wil = s->private; int i, tid; - unsigned long flags; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; @@ -1282,7 +1282,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) (p->data_port_open ? " data_port_open" : "")); if (p->status == wil_sta_connected) { - spin_lock_irqsave(&p->tid_rx_lock, flags); + spin_lock_bh(&p->tid_rx_lock); for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; @@ -1291,7 +1291,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) wil_print_rxtid(s, r); } } - spin_unlock_irqrestore(&p->tid_rx_lock, flags); + spin_unlock_bh(&p->tid_rx_lock); } } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index f44b640dff79..62dc24189bd3 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -166,12 +166,14 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, u16 reason_code, bool from_event) +__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { uint i; struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; struct wil_sta_info *sta = &wil->sta[cid]; + might_sleep(); wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid, sta->status); @@ -194,15 +196,14 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, for (i = 0; i < WIL_STA_TID_NUM; i++) { struct wil_tid_ampdu_rx *r; - unsigned long flags; - spin_lock_irqsave(&sta->tid_rx_lock, flags); + spin_lock_bh(&sta->tid_rx_lock); r = sta->tid_rx[i]; sta->tid_rx[i] = NULL; wil_tid_ampdu_rx_free(wil, r); - spin_unlock_irqrestore(&sta->tid_rx_lock, flags); + spin_unlock_bh(&sta->tid_rx_lock); } for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { if (wil->vring2cid_tid[i][0] == cid) diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 5af8012f931e..552209227de9 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -89,7 +89,9 @@ static void wil_reorder_release(struct wil6210_priv *wil, } } +/* called in NAPI context */ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) +__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { struct net_device *ndev = wil_to_ndev(wil); struct vring_rx_desc *d = wil_skb_rxdesc(skb); @@ -102,7 +104,6 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) struct wil_tid_ampdu_rx *r; u16 hseq; int index; - unsigned long flags; wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n", mid, cid, tid, seq, mcast); @@ -112,13 +113,12 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) return; } - spin_lock_irqsave(&sta->tid_rx_lock, flags); + spin_lock(&sta->tid_rx_lock); r = sta->tid_rx[tid]; if (!r) { - spin_unlock_irqrestore(&sta->tid_rx_lock, flags); wil_netif_rx_any(skb, ndev); - return; + goto out; } hseq = r->head_seq_num; @@ -196,7 +196,7 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) wil_reorder_release(wil, r); out: - spin_unlock_irqrestore(&sta->tid_rx_lock, flags); + spin_unlock(&sta->tid_rx_lock); } struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, @@ -276,6 +276,7 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, static void wil_back_rx_handle(struct wil6210_priv *wil, struct wil_back_rx *req) +__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { struct wil_sta_info *sta; u8 cid, tid; @@ -291,9 +292,9 @@ static void wil_back_rx_handle(struct wil6210_priv *wil, u16 agg_timeout = req->ba_timeout; u16 status = WLAN_STATUS_SUCCESS; u16 ssn = req->ba_seq_ctrl >> 4; - unsigned long flags; int rc; + might_sleep(); parse_cidxtid(req->cidxtid, &cid, &tid); /* sanity checks */ @@ -327,12 +328,12 @@ static void wil_back_rx_handle(struct wil6210_priv *wil, return; /* apply */ - spin_lock_irqsave(&sta->tid_rx_lock, flags); + spin_lock_bh(&sta->tid_rx_lock); wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); - spin_unlock_irqrestore(&sta->tid_rx_lock, flags); + spin_unlock_bh(&sta->tid_rx_lock); } void wil_back_rx_flush(struct wil6210_priv *wil) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 432ec55298f2..f3524a15b1ad 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -644,14 +644,15 @@ static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d, } static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len) +__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { struct wmi_delba_event *evt = d; u8 cid, tid; u16 reason = __le16_to_cpu(evt->reason); struct wil_sta_info *sta; struct wil_tid_ampdu_rx *r; - unsigned long flags; + might_sleep(); parse_cidxtid(evt->cidxtid, &cid, &tid); wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n", cid, tid, @@ -681,13 +682,13 @@ static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len) sta = &wil->sta[cid]; - spin_lock_irqsave(&sta->tid_rx_lock, flags); + spin_lock_bh(&sta->tid_rx_lock); r = sta->tid_rx[tid]; sta->tid_rx[tid] = NULL; wil_tid_ampdu_rx_free(wil, r); - spin_unlock_irqrestore(&sta->tid_rx_lock, flags); + spin_unlock_bh(&sta->tid_rx_lock); } static const struct { -- cgit v1.2.1 From 4447d815fd0f89d64b78011e82c18c7e83f7f29e Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 27 Dec 2014 14:13:00 +0100 Subject: ath: ath9k: use debugfs_create_devm_seqfile() helper for seq_file entries Use the helper to get rid of the file operations per debugfs file. The device driver data contains struct ieee80211_hw pointer and the struct ath9k_softc pointer is assigned to ieee80211_hw::priv so it can be accessed in the seq_file read operation. Cc: ath9k-devel@lists.ath9k.org Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug.c | 129 ++++++++------------------------- 1 file changed, 29 insertions(+), 100 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index c43e2ad36587..1bed9d7589af 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -403,7 +403,8 @@ static const struct file_operations fops_antenna_diversity = { static int read_file_dma(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; int i, qcuOffset = 0, dcuOffset = 0; @@ -470,20 +471,6 @@ static int read_file_dma(struct seq_file *file, void *data) return 0; } -static int open_file_dma(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_dma, inode->i_private); -} - -static const struct file_operations fops_dma = { - .open = open_file_dma, - .read = seq_read, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - - void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { if (status) @@ -539,7 +526,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) static int read_file_interrupt(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; #define PR_IS(a, s) \ do { \ @@ -600,22 +588,10 @@ static int read_file_interrupt(struct seq_file *file, void *data) return 0; } -static int open_file_interrupt(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_interrupt, inode->i_private); -} - -static const struct file_operations fops_interrupt = { - .read = seq_read, - .open = open_file_interrupt, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - static int read_file_xmit(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; seq_printf(file, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); @@ -661,7 +637,8 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq, static int read_file_queues(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_txq *txq; int i; static const char *qname[4] = { @@ -682,7 +659,8 @@ static int read_file_queues(struct seq_file *file, void *data) static int read_file_misc(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_vif_iter_data iter_data; struct ath_chanctx *ctx; @@ -773,7 +751,8 @@ static int read_file_misc(struct seq_file *file, void *data) static int read_file_reset(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; static const char * const reset_cause[__RESET_TYPE_MAX] = { [RESET_TYPE_BB_HANG] = "Baseband Hang", [RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog", @@ -837,58 +816,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, TX_STAT_INC(qnum, delim_underrun); } -static int open_file_xmit(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_xmit, inode->i_private); -} - -static const struct file_operations fops_xmit = { - .read = seq_read, - .open = open_file_xmit, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - -static int open_file_queues(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_queues, inode->i_private); -} - -static const struct file_operations fops_queues = { - .read = seq_read, - .open = open_file_queues, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - -static int open_file_misc(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_misc, inode->i_private); -} - -static const struct file_operations fops_misc = { - .read = seq_read, - .open = open_file_misc, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - -static int open_file_reset(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_reset, inode->i_private); -} - -static const struct file_operations fops_reset = { - .read = seq_read, - .open = open_file_reset, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { ath9k_cmn_debug_stat_rx(&sc->debug.stats.rxstats, rs); @@ -1018,7 +945,8 @@ static const struct file_operations fops_regdump = { static int read_file_dump_nfcal(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath9k_nfcal_hist *h = sc->cur_chan->caldata.nfCalHist; struct ath_common *common = ath9k_hw_common(ah); @@ -1329,14 +1257,14 @@ int ath9k_init_debug(struct ath_hw *ah) ath9k_tx99_init_debug(sc); ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy); - debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_dma); - debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_interrupt); - debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_xmit); - debugfs_create_file("queues", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_queues); + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, + read_file_interrupt); + debugfs_create_devm_seqfile(sc->dev, "xmit", sc->debug.debugfs_phy, + read_file_xmit); + debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy, + read_file_queues); debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->tx.txq_max_pending[IEEE80211_AC_BK]); debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, @@ -1345,10 +1273,10 @@ int ath9k_init_debug(struct ath_hw *ah) &sc->tx.txq_max_pending[IEEE80211_AC_VI]); debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->tx.txq_max_pending[IEEE80211_AC_VO]); - debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_misc); - debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_reset); + debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy, + read_file_misc); + debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy, + read_file_reset); ath9k_cmn_debug_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); ath9k_cmn_debug_phy_err(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); @@ -1370,8 +1298,9 @@ int ath9k_init_debug(struct ath_hw *ah) &ah->config.cwm_ignore_extcca); debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_regdump); - debugfs_create_file("dump_nfcal", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_dump_nfcal); + debugfs_create_devm_seqfile(sc->dev, "dump_nfcal", + sc->debug.debugfs_phy, + read_file_dump_nfcal); ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah); ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah); -- cgit v1.2.1 From 72e121191c0b4bde8cd2cea24c0ebc9d70bf8037 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 29 Dec 2014 18:04:41 +0100 Subject: adm8211: fix error return code Return a negative error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/adm8211.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 17fcaabb2687..f07a61899545 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1837,6 +1837,7 @@ static int adm8211_probe(struct pci_dev *pdev, if (!priv->map) { printk(KERN_ERR "%s (adm8211): Cannot map device memory\n", pci_name(pdev)); + err = -ENOMEM; goto err_free_dev; } -- cgit v1.2.1 From c08267dc9a3641c78846bfac92abfc54984c6694 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 30 Dec 2014 23:10:18 +0100 Subject: ath9k: add power per-rate tables for AR9002 chips Add TX power per-rate tables for MIMO/legacy modes for AR9002 based chips in order to cap the maximum TX power value per-rate in the TX descriptor path. Add TX power adjustments for HT40 mode, open loop CCK rates and eeprom power bias for AR9280 and later chips Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 80 ++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/eeprom_4k.c | 14 +++++ drivers/net/wireless/ath/ath9k/eeprom_9287.c | 15 ++++++ drivers/net/wireless/ath/ath9k/eeprom_def.c | 14 +++++ drivers/net/wireless/ath/ath9k/hw.h | 2 + 5 files changed, 125 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 5829074208fa..f273427fdd29 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -22,6 +22,21 @@ /* All code below is for AR5008, AR9001, AR9002 */ +#define AR5008_OFDM_RATES 8 +#define AR5008_HT_SS_RATES 8 +#define AR5008_HT_DS_RATES 8 + +#define AR5008_HT20_SHIFT 16 +#define AR5008_HT40_SHIFT 24 + +#define AR5008_11NA_OFDM_SHIFT 0 +#define AR5008_11NA_HT_SS_SHIFT 8 +#define AR5008_11NA_HT_DS_SHIFT 16 + +#define AR5008_11NG_OFDM_SHIFT 4 +#define AR5008_11NG_HT_SS_SHIFT 12 +#define AR5008_11NG_HT_DS_SHIFT 20 + static const int firstep_table[] = /* level: 0 1 2 3 4 5 6 7 8 */ { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */ @@ -1235,6 +1250,71 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah) conf->radar_inband = 8; } +static void ar5008_hw_init_txpower_cck(struct ath_hw *ah, int16_t *rate_array) +{ +#define CCK_DELTA(x) ((OLC_FOR_AR9280_20_LATER) ? max((x) - 2, 0) : (x)) + ah->tx_power[0] = CCK_DELTA(rate_array[rate1l]); + ah->tx_power[1] = CCK_DELTA(min(rate_array[rate2l], + rate_array[rate2s])); + ah->tx_power[2] = CCK_DELTA(min(rate_array[rate5_5l], + rate_array[rate5_5s])); + ah->tx_power[3] = CCK_DELTA(min(rate_array[rate11l], + rate_array[rate11s])); +#undef CCK_DELTA +} + +static void ar5008_hw_init_txpower_ofdm(struct ath_hw *ah, int16_t *rate_array, + int offset) +{ + int i, idx = 0; + + for (i = offset; i < offset + AR5008_OFDM_RATES; i++) { + ah->tx_power[i] = rate_array[idx]; + idx++; + } +} + +static void ar5008_hw_init_txpower_ht(struct ath_hw *ah, int16_t *rate_array, + int ss_offset, int ds_offset, + bool is_40, int ht40_delta) +{ + int i, mcs_idx = (is_40) ? AR5008_HT40_SHIFT : AR5008_HT20_SHIFT; + + for (i = ss_offset; i < ss_offset + AR5008_HT_SS_RATES; i++) { + ah->tx_power[i] = rate_array[mcs_idx] + ht40_delta; + mcs_idx++; + } + memcpy(&ah->tx_power[ds_offset], &ah->tx_power[ss_offset], + AR5008_HT_SS_RATES); +} + +void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array, + struct ath9k_channel *chan, int ht40_delta) +{ + if (IS_CHAN_5GHZ(chan)) { + ar5008_hw_init_txpower_ofdm(ah, rate_array, + AR5008_11NA_OFDM_SHIFT); + if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) { + ar5008_hw_init_txpower_ht(ah, rate_array, + AR5008_11NA_HT_SS_SHIFT, + AR5008_11NA_HT_DS_SHIFT, + IS_CHAN_HT40(chan), + ht40_delta); + } + } else { + ar5008_hw_init_txpower_cck(ah, rate_array); + ar5008_hw_init_txpower_ofdm(ah, rate_array, + AR5008_11NG_OFDM_SHIFT); + if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) { + ar5008_hw_init_txpower_ht(ah, rate_array, + AR5008_11NG_HT_SS_SHIFT, + AR5008_11NG_HT_DS_SHIFT, + IS_CHAN_HT40(chan), + ht40_delta); + } + } +} + int ar5008_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 07b806c56c56..e5a78d4fd66e 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -748,6 +748,20 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } + /* TPC initializations */ + if (ah->tpc_enabled) { + int ht40_delta; + + ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0; + ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta); + /* Enable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, + MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); + } else { + /* Disable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER); + } + REGWRITE_BUFFER_FLUSH(ah); } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 5ba1385c9838..6ca33dfde1fd 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -886,6 +886,21 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } + + /* TPC initializations */ + if (ah->tpc_enabled) { + int ht40_delta; + + ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0; + ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta); + /* Enable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, + MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); + } else { + /* Disable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER); + } + REGWRITE_BUFFER_FLUSH(ah); } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 122b846b8ec0..098059039351 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -1332,6 +1332,20 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + /* TPC initializations */ + if (ah->tpc_enabled) { + int ht40_delta; + + ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0; + ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta); + /* Enable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, + MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); + } else { + /* Disable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER); + } + REGWRITE_BUFFER_FLUSH(ah); } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 64bfcbd9fcec..450704e49f03 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1087,6 +1087,8 @@ bool ar9003_is_paprd_enabled(struct ath_hw *ah); void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array, struct ath9k_channel *chan); +void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array, + struct ath9k_channel *chan, int ht40_delta); /* Hardware family op attach helpers */ int ar5008_hw_attach_phy_ops(struct ath_hw *ah); -- cgit v1.2.1 From 9ddad58bee51663001ff118d65cc9166bafcd122 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 30 Dec 2014 23:10:19 +0100 Subject: ath9k: add TPC to TX path for AR9002 based chips Add TPC capability to TX descriptor path for AR9002 based chips. Scale per-packet TX power according to eeprom power bias, power adjustments for HT40 mode and open loop CCK rates. Cap per-packet TX power according to TX power per-rate tables Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/xmit.c | 68 ++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 52d63de4a93d..9c332f9c3fc5 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1097,24 +1097,65 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop) } static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, - u8 rateidx) + u8 rateidx, bool is_40, bool is_cck) { u8 max_power; + struct sk_buff *skb; + struct ath_frame_info *fi; + struct ieee80211_tx_info *info; struct ath_hw *ah = sc->sc_ah; - if (sc->tx99_state) + if (sc->tx99_state || !ah->tpc_enabled) return MAX_RATE_POWER; + skb = bf->bf_mpdu; + fi = get_frame_info(skb); + info = IEEE80211_SKB_CB(skb); + if (!AR_SREV_9300_20_OR_LATER(ah)) { - /* ar9002 does not support TPC for the moment */ - return MAX_RATE_POWER; - } + int txpower = fi->tx_power; - if (!bf->bf_state.bfs_paprd) { - struct sk_buff *skb = bf->bf_mpdu; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ath_frame_info *fi = get_frame_info(skb); + if (is_40) { + u8 power_ht40delta; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { + bool is_2ghz; + struct modal_eep_header *pmodal; + + is_2ghz = info->band == IEEE80211_BAND_2GHZ; + pmodal = &eep->modalHeader[is_2ghz]; + power_ht40delta = pmodal->ht40PowerIncForPdadc; + } else { + power_ht40delta = 2; + } + txpower += power_ht40delta; + } + + if (AR_SREV_9287(ah) || AR_SREV_9285(ah) || + AR_SREV_9271(ah)) { + txpower -= 2 * AR9287_PWR_TABLE_OFFSET_DB; + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + s8 power_offset; + + power_offset = ah->eep_ops->get_eeprom(ah, + EEP_PWR_TABLE_OFFSET); + txpower -= 2 * power_offset; + } + + if (OLC_FOR_AR9280_20_LATER && is_cck) + txpower -= 2; + + txpower = max(txpower, 0); + max_power = min_t(u8, ah->tx_power[rateidx], txpower); + + /* XXX: clamp minimum TX power at 1 for AR9160 since if + * max_power is set to 0, frames are transmitted at max + * TX power + */ + if (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) + max_power = 1; + } else if (!bf->bf_state.bfs_paprd) { if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC)) max_power = min(ah->tx_power_stbc[rateidx], fi->tx_power); @@ -1152,7 +1193,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, info->rtscts_rate = fi->rtscts_rate; for (i = 0; i < ARRAY_SIZE(bf->rates); i++) { - bool is_40, is_sgi, is_sp; + bool is_40, is_sgi, is_sp, is_cck; int phy; if (!rates[i].count || (rates[i].idx < 0)) @@ -1198,7 +1239,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC; - info->txpower[i] = ath_get_rate_txpower(sc, bf, rix); + info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, + is_40, false); continue; } @@ -1227,7 +1269,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, phy, rate->bitrate * 100, len, rix, is_sp); - info->txpower[i] = ath_get_rate_txpower(sc, bf, rix); + is_cck = IS_CCK_RATE(info->rates[i].Rate); + info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, false, + is_cck); } /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ -- cgit v1.2.1 From b5939e8c71292bbedf1d36adf7784ce2d71ae3d7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 30 Dec 2014 23:10:20 +0100 Subject: ath9k: enable per-packet TPC on AR9002 based chips Enable per-packet TPC on AR9002 based chips by default Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug.c | 5 ----- drivers/net/wireless/ath/ath9k/hw.c | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 1bed9d7589af..dd5d3914799b 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1078,11 +1078,6 @@ static ssize_t write_file_tpc(struct file *file, const char __user *user_buf, ssize_t len; bool tpc_enabled; - if (!AR_SREV_9300_20_OR_LATER(ah)) { - /* ar9002 does not support TPC for the moment */ - return -EOPNOTSUPP; - } - len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 051540f78030..82d8f32a3461 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -424,8 +424,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->power_mode = ATH9K_PM_UNDEFINED; ah->htc_reset_init = true; - /* ar9002 does not support TPC for the moment */ - ah->tpc_enabled = !!AR_SREV_9300_20_OR_LATER(ah); + ah->tpc_enabled = true; ah->ani_function = ATH9K_ANI_ALL; if (!AR_SREV_9300_20_OR_LATER(ah)) -- cgit v1.2.1 From edea2acb8b3ce9fdadfc49ee39ac21f01d4f3d01 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 5 Jan 2015 11:14:25 +0530 Subject: ath9k: Update PCI IDs for AR9565 This patch adds several new PCI IDs for AR9565. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/pci.c | 85 ++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index f009b5b57e5e..cc5c6810f32e 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -424,6 +424,11 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x11AD, /* LITEON */ 0x0842), .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x1842), + .driver_data = ATH9K_PCI_AR9565_1ANT }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x11AD, /* LITEON */ @@ -444,11 +449,21 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x1B9A, /* XAVI */ 0x28A1), .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A3), + .driver_data = ATH9K_PCI_AR9565_1ANT }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_AZWAVE, 0x218A), .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2F8A), + .driver_data = ATH9K_PCI_AR9565_1ANT }, /* WB335 1-ANT / Antenna Diversity */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, @@ -506,6 +521,11 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_AZWAVE, 0x213A), .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x213C), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_HP, @@ -553,6 +573,16 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_SAMSUNG, 0x411E), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x4129), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x412A), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_ATHEROS, @@ -583,11 +613,26 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x11AD, /* LITEON */ 0x0832), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x1832), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x11AD, /* LITEON */ 0x0692), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0803), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0813), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_AZWAVE, @@ -603,6 +648,21 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_AZWAVE, 0x2182), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x218B), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x218C), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2F82), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x144F, /* ASKEY */ @@ -613,11 +673,21 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x1B9A, /* XAVI */ 0x2810), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x2813), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x1B9A, /* XAVI */ 0x28A2), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A4), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x185F, /* WNC */ @@ -633,11 +703,26 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_FOXCONN, 0xE07F), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE08F), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_FOXCONN, 0xE081), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE091), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE099), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_LENOVO, -- cgit v1.2.1 From a2bd36c210ba5533fb12e9dc737711a5cb59d7bb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jan 2015 13:46:57 +0100 Subject: orinoco/hermes: select CFG80211_WEXT It makes no sense to require the user to find and enable CFG80211_WEXT before the driver can be selected, make the driver select the needed Kconfig symbol itself. Signed-off-by: Johannes Berg Signed-off-by: Kalle Valo --- drivers/net/wireless/orinoco/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index 60698b020851..6d831d4d1b5f 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -1,7 +1,8 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" depends on (PPC_PMAC || PCI || PCMCIA) - depends on CFG80211 && CFG80211_WEXT + depends on CFG80211 + select CFG80211_WEXT select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV -- cgit v1.2.1 From d0c102f70aec07eaeb23de30892f425e4c5f6045 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Tue, 6 Jan 2015 18:59:35 +0100 Subject: b43legacy: Remove unused b43legacy_radio_set_tx_iq() Remove the function b43legacy_radio_set_tx_iq() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Acked-by: Larry Finger Acked-by: Rafa? Mi?ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/b43legacy/radio.c | 19 ------------------- drivers/net/wireless/b43legacy/radio.h | 1 - 2 files changed, 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index 896177690394..9501420340a9 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -1743,25 +1743,6 @@ u16 freq_r3A_value(u16 frequency) return value; } -void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev) -{ - static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; - static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; - u16 tmp = b43legacy_radio_read16(dev, 0x001E); - int i; - int j; - - for (i = 0; i < 5; i++) { - for (j = 0; j < 5; j++) { - if (tmp == (data_high[i] | data_low[j])) { - b43legacy_phy_write(dev, 0x0069, (i - j) << 8 | - 0x00C0); - return; - } - } - } -} - int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel, int synthetic_pu_workaround) diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h index bccb3d7da682..dd2976d1d561 100644 --- a/drivers/net/wireless/b43legacy/radio.h +++ b/drivers/net/wireless/b43legacy/radio.h @@ -92,7 +92,6 @@ void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val); void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val); void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev); -void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev); u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev); #endif /* B43legacy_RADIO_H_ */ -- cgit v1.2.1 From 7994fe55a4a2009d9e9153ded4ac4369d1adaaa3 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Thu, 15 Jan 2015 10:12:26 +0000 Subject: dm9000: Add regulator and reset support to dm9000 In boards, the dm9000 chip's power and reset can be controlled by gpio. It makes sense to add them to the dm9000 driver and let dt be used to enable power and reset the phy. Signed-off-by: Zubair Lutfullah Kakakhel Signed-off-by: Paul Burton Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index ef0bb58750e6..c0a7813603c3 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include #include #include @@ -1426,11 +1429,48 @@ dm9000_probe(struct platform_device *pdev) struct dm9000_plat_data *pdata = dev_get_platdata(&pdev->dev); struct board_info *db; /* Point a board information structure */ struct net_device *ndev; + struct device *dev = &pdev->dev; const unsigned char *mac_src; int ret = 0; int iosize; int i; u32 id_val; + int reset_gpios; + enum of_gpio_flags flags; + struct regulator *power; + + power = devm_regulator_get(dev, "vcc"); + if (IS_ERR(power)) { + if (PTR_ERR(power) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_dbg(dev, "no regulator provided\n"); + } else { + ret = regulator_enable(power); + if (ret != 0) { + dev_err(dev, + "Failed to enable power regulator: %d\n", ret); + return ret; + } + dev_dbg(dev, "regulator enabled\n"); + } + + reset_gpios = of_get_named_gpio_flags(dev->of_node, "reset-gpios", 0, + &flags); + if (gpio_is_valid(reset_gpios)) { + ret = devm_gpio_request_one(dev, reset_gpios, flags, + "dm9000_reset"); + if (ret) { + dev_err(dev, "failed to request reset gpio %d: %d\n", + reset_gpios, ret); + return -ENODEV; + } + + /* According to manual PWRST# Low Period Min 1ms */ + msleep(2); + gpio_set_value(reset_gpios, 1); + /* Needs 3ms to read eeprom when PWRST is deasserted */ + msleep(4); + } if (!pdata) { pdata = dm9000_parse_dt(&pdev->dev); -- cgit v1.2.1 From 0799c2d6f42db2b275b6479035f5b7a30ef4ee39 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Jan 2015 11:54:28 +0100 Subject: net: sh_eth: Use u32 for 32-bit register data Replace "unsigned long" by "u32" when handling 32-bit register data. A.o., this saves 11 * 36 bytes in the static sh_eth_cpu_data structures when compiling for 64-bit. Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 14 +++++++------- drivers/net/ethernet/renesas/sh_eth.h | 30 ++++++++++++++---------------- 2 files changed, 21 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 37583a9d8853..167737fa59de 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -594,7 +594,7 @@ static struct sh_eth_cpu_data sh7757_data = { static void sh_eth_chip_reset_giga(struct net_device *ndev) { int i; - unsigned long mahr[2], malr[2]; + u32 mahr[2], malr[2]; /* save MAHR and MALR */ for (i = 0; i < 2; i++) { @@ -988,7 +988,7 @@ static void read_mac_address(struct net_device *ndev, unsigned char *mac) } } -static unsigned long sh_eth_get_edtrr_trns(struct sh_eth_private *mdp) +static u32 sh_eth_get_edtrr_trns(struct sh_eth_private *mdp) { if (sh_eth_is_gether(mdp) || sh_eth_is_rz_fast_ether(mdp)) return EDTRR_TRNS_GETHER; @@ -1521,7 +1521,7 @@ static void sh_eth_rcv_snd_enable(struct net_device *ndev) } /* error control function */ -static void sh_eth_error(struct net_device *ndev, int intr_status) +static void sh_eth_error(struct net_device *ndev, u32 intr_status) { struct sh_eth_private *mdp = netdev_priv(ndev); u32 felic_stat; @@ -1637,7 +1637,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) struct sh_eth_private *mdp = netdev_priv(ndev); struct sh_eth_cpu_data *cd = mdp->cd; irqreturn_t ret = IRQ_NONE; - unsigned long intr_status, intr_enable; + u32 intr_status, intr_enable; spin_lock(&mdp->lock); @@ -1663,7 +1663,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) __napi_schedule(&mdp->napi); } else { netdev_warn(ndev, - "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n", + "ignoring interrupt, status 0x%08x, mask 0x%08x.\n", intr_status, intr_enable); } } @@ -1696,7 +1696,7 @@ static int sh_eth_poll(struct napi_struct *napi, int budget) napi); struct net_device *ndev = napi->dev; int quota = budget; - unsigned long intr_status; + u32 intr_status; for (;;) { intr_status = sh_eth_read(ndev, EESR); @@ -2067,7 +2067,7 @@ static void sh_eth_tx_timeout(struct net_device *ndev) netif_err(mdp, timer, ndev, "transmit timed out, status %8.8x, resetting...\n", - (int)sh_eth_read(ndev, EESR)); + sh_eth_read(ndev, EESR)); /* tx_errors count up */ ndev->stats.tx_errors++; diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 71f5de1171bd..7bfaf1c81ea2 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -459,21 +459,21 @@ struct sh_eth_cpu_data { /* mandatory initialize value */ int register_type; - unsigned long eesipr_value; + u32 eesipr_value; /* optional initialize value */ - unsigned long ecsr_value; - unsigned long ecsipr_value; - unsigned long fdr_value; - unsigned long fcftr_value; - unsigned long rpadir_value; + u32 ecsr_value; + u32 ecsipr_value; + u32 fdr_value; + u32 fcftr_value; + u32 rpadir_value; /* interrupt checking mask */ - unsigned long tx_check; - unsigned long eesr_err_check; + u32 tx_check; + u32 eesr_err_check; /* Error mask */ - unsigned long trscer_err_mask; + u32 trscer_err_mask; /* hardware features */ unsigned long irq_flags; /* IRQ configuration flags */ @@ -542,7 +542,7 @@ static inline void sh_eth_soft_swap(char *src, int len) #endif } -static inline void sh_eth_write(struct net_device *ndev, unsigned long data, +static inline void sh_eth_write(struct net_device *ndev, u32 data, int enum_index) { struct sh_eth_private *mdp = netdev_priv(ndev); @@ -550,8 +550,7 @@ static inline void sh_eth_write(struct net_device *ndev, unsigned long data, iowrite32(data, mdp->addr + mdp->reg_offset[enum_index]); } -static inline unsigned long sh_eth_read(struct net_device *ndev, - int enum_index) +static inline u32 sh_eth_read(struct net_device *ndev, int enum_index) { struct sh_eth_private *mdp = netdev_priv(ndev); @@ -564,14 +563,13 @@ static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp, return mdp->tsu_addr + mdp->reg_offset[enum_index]; } -static inline void sh_eth_tsu_write(struct sh_eth_private *mdp, - unsigned long data, int enum_index) +static inline void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data, + int enum_index) { iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]); } -static inline unsigned long sh_eth_tsu_read(struct sh_eth_private *mdp, - int enum_index) +static inline u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index) { return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]); } -- cgit v1.2.1 From b51f3beecfbbfc946749a91fb444cb8917cf444f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 15 Jan 2015 16:14:02 +0100 Subject: cfg80211: change bandwidth reporting to explicit field For some reason, we made the bandwidth separate flags, which is rather confusing - a single rate cannot have different bandwidths at the same time. Change this to no longer be flags but use a separate field for the bandwidth ('bw') instead. While at it, add support for 5 and 10 MHz rates - these are reported as regular legacy rates with their real bitrate, but tagged as 5/10 now to make it easier to distinguish them. In the nl80211 API, the flags are preserved, but the code now can also clearly only set a single one of the flags. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 3 ++- drivers/net/wireless/mwifiex/cfg80211.c | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 44dd6ef923cd..85da63a67faf 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1827,6 +1827,7 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, } sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + sinfo->txrate.bw = RATE_INFO_BW_20; } else if (is_rate_ht40(rate, &mcs, &sgi)) { if (sgi) { sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; @@ -1835,7 +1836,7 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, sinfo->txrate.mcs = mcs; } - sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + sinfo->txrate.bw = RATE_INFO_BW_40; sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; } else { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 71312ff52703..1996a8b612d2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -856,16 +856,16 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo, /* HT or VHT */ switch (tx_htinfo & (BIT(3) | BIT(2))) { case 0: - /* This will be 20MHz */ + rate->bw = RATE_INFO_BW_20; break; case (BIT(2)): - rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + rate->bw = RATE_INFO_BW_40; break; case (BIT(3)): - rate->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; + rate->bw = RATE_INFO_BW_80; break; case (BIT(3) | BIT(2)): - rate->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; + rate->bw = RATE_INFO_BW_160; break; } @@ -885,8 +885,9 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo, if ((tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) { rate->mcs = priv->tx_rate; rate->flags |= RATE_INFO_FLAGS_MCS; + rate->bw = RATE_INFO_BW_20; if (tx_htinfo & BIT(1)) - rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + rate->bw = RATE_INFO_BW_40; if (tx_htinfo & BIT(2)) rate->flags |= RATE_INFO_FLAGS_SHORT_GI; } -- cgit v1.2.1 From b5a02f503caa0837b64907468359b075990afcce Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Wed, 14 Jan 2015 15:17:34 -0800 Subject: cxgb4 : Update ipv6 address handling api This patch improves on previously added support for ipv6 addresses. The code is consolidated to a single file and adds an api for use by dependent upper level drivers such as cxgb4i/iw_cxgb4 etc. Signed-off-by: Anish Bhatt Signed-off-by: Deepak Singh Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/Makefile | 2 +- drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c | 314 +++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h | 41 +++ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 3 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 19 ++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 228 +++++---------- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 3 - 7 files changed, 447 insertions(+), 163 deletions(-) create mode 100644 drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile index b85280775997..ae50cd72358c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/Makefile +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -4,6 +4,6 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o -cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o +cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c new file mode 100644 index 000000000000..2b407b6a35a8 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c @@ -0,0 +1,314 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * Copyright (C) 2003-2014 Chelsio Communications. All rights reserved. + * + * Written by Deepak (deepak.s@chelsio.com) + * + * 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 LICENSE file included in this + * release for licensing terms and conditions. + */ + +#include +#include +#include +#include +#include +#include "cxgb4.h" +#include "clip_tbl.h" + +static inline unsigned int ipv4_clip_hash(struct clip_tbl *c, const u32 *key) +{ + unsigned int clipt_size_half = c->clipt_size / 2; + + return jhash_1word(*key, 0) % clipt_size_half; +} + +static inline unsigned int ipv6_clip_hash(struct clip_tbl *d, const u32 *key) +{ + unsigned int clipt_size_half = d->clipt_size / 2; + u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3]; + + return clipt_size_half + + (jhash_1word(xor, 0) % clipt_size_half); +} + +static unsigned int clip_addr_hash(struct clip_tbl *ctbl, const u32 *addr, + int addr_len) +{ + return addr_len == 4 ? ipv4_clip_hash(ctbl, addr) : + ipv6_clip_hash(ctbl, addr); +} + +static int clip6_get_mbox(const struct net_device *dev, + const struct in6_addr *lip) +{ + struct adapter *adap = netdev2adap(dev); + struct fw_clip_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) | + FW_CMD_REQUEST_F | FW_CMD_WRITE_F); + c.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F | FW_LEN16(c)); + *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr); + *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8); + return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); +} + +static int clip6_release_mbox(const struct net_device *dev, + const struct in6_addr *lip) +{ + struct adapter *adap = netdev2adap(dev); + struct fw_clip_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) | + FW_CMD_REQUEST_F | FW_CMD_READ_F); + c.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F | FW_LEN16(c)); + *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr); + *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8); + return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); +} + +int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) +{ + struct adapter *adap = netdev2adap(dev); + struct clip_tbl *ctbl = adap->clipt; + struct clip_entry *ce, *cte; + u32 *addr = (u32 *)lip; + int hash; + int addr_len; + int ret = 0; + + if (v6) + addr_len = 16; + else + addr_len = 4; + + hash = clip_addr_hash(ctbl, addr, addr_len); + + read_lock_bh(&ctbl->lock); + list_for_each_entry(cte, &ctbl->hash_list[hash], list) { + if (addr_len == cte->addr_len && + memcmp(lip, cte->addr, cte->addr_len) == 0) { + ce = cte; + read_unlock_bh(&ctbl->lock); + goto found; + } + } + read_unlock_bh(&ctbl->lock); + + write_lock_bh(&ctbl->lock); + if (!list_empty(&ctbl->ce_free_head)) { + ce = list_first_entry(&ctbl->ce_free_head, + struct clip_entry, list); + list_del(&ce->list); + INIT_LIST_HEAD(&ce->list); + spin_lock_init(&ce->lock); + atomic_set(&ce->refcnt, 0); + atomic_dec(&ctbl->nfree); + ce->addr_len = addr_len; + memcpy(ce->addr, lip, addr_len); + list_add_tail(&ce->list, &ctbl->hash_list[hash]); + if (v6) { + ret = clip6_get_mbox(dev, (const struct in6_addr *)lip); + if (ret) { + write_unlock_bh(&ctbl->lock); + return ret; + } + } + } else { + write_unlock_bh(&ctbl->lock); + return -ENOMEM; + } + write_unlock_bh(&ctbl->lock); +found: + atomic_inc(&ce->refcnt); + + return 0; +} +EXPORT_SYMBOL(cxgb4_clip_get); + +void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6) +{ + struct adapter *adap = netdev2adap(dev); + struct clip_tbl *ctbl = adap->clipt; + struct clip_entry *ce, *cte; + u32 *addr = (u32 *)lip; + int hash; + int addr_len; + + if (v6) + addr_len = 16; + else + addr_len = 4; + + hash = clip_addr_hash(ctbl, addr, addr_len); + + read_lock_bh(&ctbl->lock); + list_for_each_entry(cte, &ctbl->hash_list[hash], list) { + if (addr_len == cte->addr_len && + memcmp(lip, cte->addr, cte->addr_len) == 0) { + ce = cte; + read_unlock_bh(&ctbl->lock); + goto found; + } + } + read_unlock_bh(&ctbl->lock); + + return; +found: + write_lock_bh(&ctbl->lock); + spin_lock_bh(&ce->lock); + if (atomic_dec_and_test(&ce->refcnt)) { + list_del(&ce->list); + INIT_LIST_HEAD(&ce->list); + list_add_tail(&ce->list, &ctbl->ce_free_head); + atomic_inc(&ctbl->nfree); + if (v6) + clip6_release_mbox(dev, (const struct in6_addr *)lip); + } + spin_unlock_bh(&ce->lock); + write_unlock_bh(&ctbl->lock); +} +EXPORT_SYMBOL(cxgb4_clip_release); + +/* Retrieves IPv6 addresses from a root device (bond, vlan) associated with + * a physical device. + * The physical device reference is needed to send the actul CLIP command. + */ +static int cxgb4_update_dev_clip(struct net_device *root_dev, + struct net_device *dev) +{ + struct inet6_dev *idev = NULL; + struct inet6_ifaddr *ifa; + int ret = 0; + + idev = __in6_dev_get(root_dev); + if (!idev) + return ret; + + read_lock_bh(&idev->lock); + list_for_each_entry(ifa, &idev->addr_list, if_list) { + ret = cxgb4_clip_get(dev, (const u32 *)ifa->addr.s6_addr, 1); + if (ret < 0) + break; + } + read_unlock_bh(&idev->lock); + + return ret; +} + +int cxgb4_update_root_dev_clip(struct net_device *dev) +{ + struct net_device *root_dev = NULL; + int i, ret = 0; + + /* First populate the real net device's IPv6 addresses */ + ret = cxgb4_update_dev_clip(dev, dev); + if (ret) + return ret; + + /* Parse all bond and vlan devices layered on top of the physical dev */ + root_dev = netdev_master_upper_dev_get_rcu(dev); + if (root_dev) { + ret = cxgb4_update_dev_clip(root_dev, dev); + if (ret) + return ret; + } + + for (i = 0; i < VLAN_N_VID; i++) { + root_dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), i); + if (!root_dev) + continue; + + ret = cxgb4_update_dev_clip(root_dev, dev); + if (ret) + break; + } + + return ret; +} +EXPORT_SYMBOL(cxgb4_update_root_dev_clip); + +int clip_tbl_show(struct seq_file *seq, void *v) +{ + struct adapter *adapter = seq->private; + struct clip_tbl *ctbl = adapter->clipt; + struct clip_entry *ce; + char ip[60]; + int i; + + read_lock_bh(&ctbl->lock); + + seq_puts(seq, "IP Address Users\n"); + for (i = 0 ; i < ctbl->clipt_size; ++i) { + list_for_each_entry(ce, &ctbl->hash_list[i], list) { + ip[0] = '\0'; + if (ce->addr_len == 16) + sprintf(ip, "%pI6c", ce->addr); + else + sprintf(ip, "%pI4c", ce->addr); + seq_printf(seq, "%-25s %u\n", ip, + atomic_read(&ce->refcnt)); + } + } + seq_printf(seq, "Free clip entries : %d\n", atomic_read(&ctbl->nfree)); + + read_unlock_bh(&ctbl->lock); + + return 0; +} + +struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start, + unsigned int clipt_end) +{ + struct clip_entry *cl_list; + struct clip_tbl *ctbl; + unsigned int clipt_size; + int i; + + if (clipt_start >= clipt_end) + return NULL; + clipt_size = clipt_end - clipt_start + 1; + if (clipt_size < CLIPT_MIN_HASH_BUCKETS) + return NULL; + + ctbl = t4_alloc_mem(sizeof(*ctbl) + + clipt_size*sizeof(struct list_head)); + if (!ctbl) + return NULL; + + ctbl->clipt_start = clipt_start; + ctbl->clipt_size = clipt_size; + INIT_LIST_HEAD(&ctbl->ce_free_head); + + atomic_set(&ctbl->nfree, clipt_size); + rwlock_init(&ctbl->lock); + + for (i = 0; i < ctbl->clipt_size; ++i) + INIT_LIST_HEAD(&ctbl->hash_list[i]); + + cl_list = t4_alloc_mem(clipt_size*sizeof(struct clip_entry)); + ctbl->cl_list = (void *)cl_list; + + for (i = 0; i < clipt_size; i++) { + INIT_LIST_HEAD(&cl_list[i].list); + list_add_tail(&cl_list[i].list, &ctbl->ce_free_head); + } + + return ctbl; +} + +void t4_cleanup_clip_tbl(struct adapter *adap) +{ + struct clip_tbl *ctbl = adap->clipt; + + if (ctbl) { + if (ctbl->cl_list) + t4_free_mem(ctbl->cl_list); + t4_free_mem(ctbl); + } +} +EXPORT_SYMBOL(t4_cleanup_clip_tbl); diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h new file mode 100644 index 000000000000..2eaba0161cf8 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * Copyright (C) 2003-2014 Chelsio Communications. All rights reserved. + * + * Written by Deepak (deepak.s@chelsio.com) + * + * 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 LICENSE file included in this + * release for licensing terms and conditions. + */ + +struct clip_entry { + spinlock_t lock; /* Hold while modifying clip reference */ + atomic_t refcnt; + struct list_head list; + u32 addr[4]; + int addr_len; +}; + +struct clip_tbl { + unsigned int clipt_start; + unsigned int clipt_size; + rwlock_t lock; + atomic_t nfree; + struct list_head ce_free_head; + void *cl_list; + struct list_head hash_list[0]; +}; + +enum { + CLIPT_MIN_HASH_BUCKETS = 2, +}; + +struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start, + unsigned int clipt_end); +int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6); +void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6); +int clip_tbl_show(struct seq_file *seq, void *v); +int cxgb4_update_root_dev_clip(struct net_device *dev); +void t4_cleanup_clip_tbl(struct adapter *adap); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 7c785b5e7757..e468f920892f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -668,6 +668,9 @@ struct adapter { unsigned int l2t_start; unsigned int l2t_end; struct l2t_data *l2t; + unsigned int clipt_start; + unsigned int clipt_end; + struct clip_tbl *clipt; void *uld_handle[CXGB4_ULD_MAX]; struct list_head list_node; struct list_head rcu_node; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index e9f348942eb0..6dabfe5ba44e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -41,6 +41,7 @@ #include "t4_regs.h" #include "t4fw_api.h" #include "cxgb4_debugfs.h" +#include "clip_tbl.h" #include "l2t.h" /* generic seq_file support for showing a table of size rows x width. */ @@ -563,6 +564,21 @@ static const struct file_operations mps_tcam_debugfs_fops = { .release = seq_release, }; +#if IS_ENABLED(CONFIG_IPV6) +static int clip_tbl_open(struct inode *inode, struct file *file) +{ + return single_open(file, clip_tbl_show, PDE_DATA(inode)); +} + +static const struct file_operations clip_tbl_debugfs_fops = { + .owner = THIS_MODULE, + .open = clip_tbl_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release +}; +#endif + static ssize_t mem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -646,6 +662,9 @@ int t4_setup_debugfs(struct adapter *adap) { "devlog", &devlog_fops, S_IRUSR, 0 }, { "l2t", &t4_l2t_fops, S_IRUSR, 0}, { "mps_tcam", &mps_tcam_debugfs_fops, S_IRUSR, 0 }, +#if IS_ENABLED(CONFIG_IPV6) + { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 }, +#endif }; add_debugfs_files(adap, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 082a596a4264..1147e1e88314 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include "cxgb4.h" @@ -71,6 +72,7 @@ #include "t4fw_api.h" #include "cxgb4_dcb.h" #include "cxgb4_debugfs.h" +#include "clip_tbl.h" #include "l2t.h" #ifdef DRV_VERSION @@ -3236,40 +3238,6 @@ static int tid_init(struct tid_info *t) return 0; } -int cxgb4_clip_get(const struct net_device *dev, - const struct in6_addr *lip) -{ - struct adapter *adap; - struct fw_clip_cmd c; - - adap = netdev2adap(dev); - memset(&c, 0, sizeof(c)); - c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) | - FW_CMD_REQUEST_F | FW_CMD_WRITE_F); - c.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F | FW_LEN16(c)); - c.ip_hi = *(__be64 *)(lip->s6_addr); - c.ip_lo = *(__be64 *)(lip->s6_addr + 8); - return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); -} -EXPORT_SYMBOL(cxgb4_clip_get); - -int cxgb4_clip_release(const struct net_device *dev, - const struct in6_addr *lip) -{ - struct adapter *adap; - struct fw_clip_cmd c; - - adap = netdev2adap(dev); - memset(&c, 0, sizeof(c)); - c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) | - FW_CMD_REQUEST_F | FW_CMD_READ_F); - c.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F | FW_LEN16(c)); - c.ip_hi = *(__be64 *)(lip->s6_addr); - c.ip_lo = *(__be64 *)(lip->s6_addr + 8); - return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); -} -EXPORT_SYMBOL(cxgb4_clip_release); - /** * cxgb4_create_server - create an IP server * @dev: the device @@ -4122,148 +4090,61 @@ int cxgb4_unregister_uld(enum cxgb4_uld type) } EXPORT_SYMBOL(cxgb4_unregister_uld); -/* Check if netdev on which event is occured belongs to us or not. Return - * success (true) if it belongs otherwise failure (false). - * Called with rcu_read_lock() held. - */ #if IS_ENABLED(CONFIG_IPV6) -static bool cxgb4_netdev(const struct net_device *netdev) +static int cxgb4_inet6addr_handler(struct notifier_block *this, + unsigned long event, void *data) { + struct inet6_ifaddr *ifa = data; + struct net_device *event_dev = ifa->idev->dev; + const struct device *parent = NULL; +#if IS_ENABLED(CONFIG_BONDING) struct adapter *adap; - int i; - - list_for_each_entry_rcu(adap, &adap_rcu_list, rcu_node) - for (i = 0; i < MAX_NPORTS; i++) - if (adap->port[i] == netdev) - return true; - return false; -} +#endif + if (event_dev->priv_flags & IFF_802_1Q_VLAN) + event_dev = vlan_dev_real_dev(event_dev); +#if IS_ENABLED(CONFIG_BONDING) + if (event_dev->flags & IFF_MASTER) { + list_for_each_entry(adap, &adapter_list, list_node) { + switch (event) { + case NETDEV_UP: + cxgb4_clip_get(adap->port[0], + (const u32 *)ifa, 1); + break; + case NETDEV_DOWN: + cxgb4_clip_release(adap->port[0], + (const u32 *)ifa, 1); + break; + default: + break; + } + } + return NOTIFY_OK; + } +#endif -static int clip_add(struct net_device *event_dev, struct inet6_ifaddr *ifa, - unsigned long event) -{ - int ret = NOTIFY_DONE; + if (event_dev) + parent = event_dev->dev.parent; - rcu_read_lock(); - if (cxgb4_netdev(event_dev)) { + if (parent && parent->driver == &cxgb4_driver.driver) { switch (event) { case NETDEV_UP: - ret = cxgb4_clip_get(event_dev, &ifa->addr); - if (ret < 0) { - rcu_read_unlock(); - return ret; - } - ret = NOTIFY_OK; + cxgb4_clip_get(event_dev, (const u32 *)ifa, 1); break; case NETDEV_DOWN: - cxgb4_clip_release(event_dev, &ifa->addr); - ret = NOTIFY_OK; + cxgb4_clip_release(event_dev, (const u32 *)ifa, 1); break; default: break; } } - rcu_read_unlock(); - return ret; -} - -static int cxgb4_inet6addr_handler(struct notifier_block *this, - unsigned long event, void *data) -{ - struct inet6_ifaddr *ifa = data; - struct net_device *event_dev; - int ret = NOTIFY_DONE; - struct bonding *bond = netdev_priv(ifa->idev->dev); - struct list_head *iter; - struct slave *slave; - struct pci_dev *first_pdev = NULL; - - if (ifa->idev->dev->priv_flags & IFF_802_1Q_VLAN) { - event_dev = vlan_dev_real_dev(ifa->idev->dev); - ret = clip_add(event_dev, ifa, event); - } else if (ifa->idev->dev->flags & IFF_MASTER) { - /* It is possible that two different adapters are bonded in one - * bond. We need to find such different adapters and add clip - * in all of them only once. - */ - bond_for_each_slave(bond, slave, iter) { - if (!first_pdev) { - ret = clip_add(slave->dev, ifa, event); - /* If clip_add is success then only initialize - * first_pdev since it means it is our device - */ - if (ret == NOTIFY_OK) - first_pdev = to_pci_dev( - slave->dev->dev.parent); - } else if (first_pdev != - to_pci_dev(slave->dev->dev.parent)) - ret = clip_add(slave->dev, ifa, event); - } - } else - ret = clip_add(ifa->idev->dev, ifa, event); - - return ret; + return NOTIFY_OK; } +static bool inet6addr_registered; static struct notifier_block cxgb4_inet6addr_notifier = { .notifier_call = cxgb4_inet6addr_handler }; -/* Retrieves IPv6 addresses from a root device (bond, vlan) associated with - * a physical device. - * The physical device reference is needed to send the actul CLIP command. - */ -static int update_dev_clip(struct net_device *root_dev, struct net_device *dev) -{ - struct inet6_dev *idev = NULL; - struct inet6_ifaddr *ifa; - int ret = 0; - - idev = __in6_dev_get(root_dev); - if (!idev) - return ret; - - read_lock_bh(&idev->lock); - list_for_each_entry(ifa, &idev->addr_list, if_list) { - ret = cxgb4_clip_get(dev, &ifa->addr); - if (ret < 0) - break; - } - read_unlock_bh(&idev->lock); - - return ret; -} - -static int update_root_dev_clip(struct net_device *dev) -{ - struct net_device *root_dev = NULL; - int i, ret = 0; - - /* First populate the real net device's IPv6 addresses */ - ret = update_dev_clip(dev, dev); - if (ret) - return ret; - - /* Parse all bond and vlan devices layered on top of the physical dev */ - root_dev = netdev_master_upper_dev_get_rcu(dev); - if (root_dev) { - ret = update_dev_clip(root_dev, dev); - if (ret) - return ret; - } - - for (i = 0; i < VLAN_N_VID; i++) { - root_dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), i); - if (!root_dev) - continue; - - ret = update_dev_clip(root_dev, dev); - if (ret) - break; - } - return ret; -} - static void update_clip(const struct adapter *adap) { int i; @@ -4277,7 +4158,7 @@ static void update_clip(const struct adapter *adap) ret = 0; if (dev) - ret = update_root_dev_clip(dev); + ret = cxgb4_update_root_dev_clip(dev); if (ret < 0) break; @@ -5391,6 +5272,14 @@ static int adap_init0(struct adapter *adap) adap->tids.nftids = val[4] - val[3] + 1; adap->sge.ingr_start = val[5]; + params[0] = FW_PARAM_PFVF(CLIP_START); + params[1] = FW_PARAM_PFVF(CLIP_END); + ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val); + if (ret < 0) + goto bye; + adap->clipt_start = val[0]; + adap->clipt_end = val[1]; + /* query params related to active filter region */ params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START); params[1] = FW_PARAM_PFVF(ACTIVE_FILTER_END); @@ -6211,6 +6100,18 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->params.offload = 0; } +#if IS_ENABLED(CONFIG_IPV6) + adapter->clipt = t4_init_clip_tbl(adapter->clipt_start, + adapter->clipt_end); + if (!adapter->clipt) { + /* We tolerate a lack of clip_table, giving up + * some functionality + */ + dev_warn(&pdev->dev, + "could not allocate Clip table, continuing\n"); + adapter->params.offload = 0; + } +#endif if (is_offload(adapter) && tid_init(&adapter->tids) < 0) { dev_warn(&pdev->dev, "could not allocate TID table, " "continuing\n"); @@ -6336,6 +6237,9 @@ static void remove_one(struct pci_dev *pdev) cxgb_down(adapter); free_some_resources(adapter); +#if IS_ENABLED(CONFIG_IPV6) + t4_cleanup_clip_tbl(adapter); +#endif iounmap(adapter->regs); if (!is_t4(adapter->params.chip)) iounmap(adapter->bar2); @@ -6374,7 +6278,10 @@ static int __init cxgb4_init_module(void) debugfs_remove(cxgb4_debugfs_root); #if IS_ENABLED(CONFIG_IPV6) - register_inet6addr_notifier(&cxgb4_inet6addr_notifier); + if (!inet6addr_registered) { + register_inet6addr_notifier(&cxgb4_inet6addr_notifier); + inet6addr_registered = true; + } #endif return ret; @@ -6383,7 +6290,10 @@ static int __init cxgb4_init_module(void) static void __exit cxgb4_cleanup_module(void) { #if IS_ENABLED(CONFIG_IPV6) - unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier); + if (inet6addr_registered && list_empty(&adapter_list)) { + unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier); + inet6addr_registered = false; + } #endif pci_unregister_driver(&cxgb4_driver); debugfs_remove(cxgb4_debugfs_root); /* NULL ok */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 152b4c4c7809..78ab4d406ce2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -173,9 +173,6 @@ int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid, unsigned char port, unsigned char mask); int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid, unsigned int queue, bool ipv6); -int cxgb4_clip_get(const struct net_device *dev, const struct in6_addr *lip); -int cxgb4_clip_release(const struct net_device *dev, - const struct in6_addr *lip); static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue) { -- cgit v1.2.1 From 6321b54a43e2dd3e2635f4a7cb7e4d83fd68dfe1 Mon Sep 17 00:00:00 2001 From: Michael Schmitz Date: Thu, 15 Jan 2015 14:06:15 +0100 Subject: net: smc91x: Add Atari EtherNAT support Add Atari specific code to the smc91x Ethernet driver. This code is used on the EtherNAT adapter card for the Atari Falcon extension port. Signed-off-by: Michael Schmitz Tested-by: Christian Steigies [geert: Sort Kconfig entries, split in hard and soft dependencies] Signed-off-by: Geert Uytterhoeven Acked-by: Nicolas Pitre Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/Kconfig | 10 ++++++---- drivers/net/ethernet/smsc/smc91x.h | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig index 9468e64e6007..3e97a8b43147 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -5,8 +5,9 @@ config NET_VENDOR_SMSC bool "SMC (SMSC)/Western Digital devices" default y - depends on ARM || ISA || MAC || ARM64 || MIPS || M32R || SUPERH || \ - BLACKFIN || MN10300 || COLDFIRE || XTENSA || NIOS2 || PCI || PCMCIA + depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \ + ISA || M32R || MAC || MIPS || MN10300 || NIOS2 || PCI || \ + PCMCIA || SUPERH || XTENSA ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from @@ -38,8 +39,9 @@ config SMC91X tristate "SMC 91C9x/91C1xxx support" select CRC32 select MII - depends on (ARM || M32R || SUPERH || MIPS || BLACKFIN || \ - MN10300 || COLDFIRE || ARM64 || XTENSA || NIOS2) && (!OF || GPIOLIB) + depends on !OF || GPIOLIB + depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \ + M32R || MIPS || MN10300 || NIOS2 || SUPERH || XTENSA ---help--- This is a driver for SMC's 91x series of Ethernet chipsets, including the SMC91C94 and the SMC91C111. Say Y if you want it diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h index 2a38dacbbd27..be67baf5f677 100644 --- a/drivers/net/ethernet/smsc/smc91x.h +++ b/drivers/net/ethernet/smsc/smc91x.h @@ -216,6 +216,27 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #include +#elif defined(CONFIG_ATARI) + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) +#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + +#define RPC_LSA_DEFAULT RPC_LED_100_10 +#define RPC_LSB_DEFAULT RPC_LED_TX_RX + #elif defined(CONFIG_ARCH_MSM) #define SMC_CAN_USE_8BIT 0 -- cgit v1.2.1 From 331b9ab80a1c65703ff0f198a4619a5cddf7da92 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Thu, 15 Jan 2015 11:54:30 -0800 Subject: Driver: Vmxnet3: Fix ethtool -S to return correct rx queue stats Signed-off-by: Gao Zhenyu Signed-off-by: Shrikrishna Khare Reviewed-by: Shreyas N Bhatewara Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_ethtool.c | 2 +- drivers/net/vmxnet3/vmxnet3_int.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 8a5a90eeb4f9..4c8a944d58b4 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -323,7 +323,7 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev, vmxnet3_tq_driver_stats[i].offset); } - for (j = 0; j < adapter->num_tx_queues; j++) { + for (j = 0; j < adapter->num_rx_queues; j++) { base = (u8 *)&adapter->rqd_start[j].stats; *buf++ = (u64) j; for (i = 1; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 6297d9fb0ae5..406144b436bf 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -69,10 +69,10 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.3.2.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.3.3.0-k" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01030200 +#define VMXNET3_DRIVER_VERSION_NUM 0x01030300 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */ -- cgit v1.2.1 From 6f79eed8865949bc430322d3b939a731ca7053b3 Mon Sep 17 00:00:00 2001 From: Xander Huff Date: Thu, 15 Jan 2015 15:55:18 -0600 Subject: net/macb: Fix comments to meet style guidelines Change comments to not exceed 80 characters per line. Update block comments in macb.h to start on the line after /*. Signed-off-by: Xander Huff Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.h | 734 ++++++++++++++---------------------- 1 file changed, 284 insertions(+), 450 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 378b2183ab8d..31dc080f2437 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -15,471 +15,309 @@ #define MACB_MAX_QUEUES 8 /* MACB register offsets */ -#define MACB_NCR 0x0000 /* Network Control */ -#define MACB_NCFGR 0x0004 /* Network Config */ -#define MACB_NSR 0x0008 /* Network Status */ -#define MACB_TAR 0x000c /* AT91RM9200 only */ -#define MACB_TCR 0x0010 /* AT91RM9200 only */ -#define MACB_TSR 0x0014 /* Transmit Status */ -#define MACB_RBQP 0x0018 /* RX Q Base Address */ -#define MACB_TBQP 0x001c /* TX Q Base Address */ -#define MACB_RSR 0x0020 /* Receive Status */ -#define MACB_ISR 0x0024 /* Interrupt Status */ -#define MACB_IER 0x0028 /* Interrupt Enable */ -#define MACB_IDR 0x002c /* Interrupt Disable */ -#define MACB_IMR 0x0030 /* Interrupt Mask */ -#define MACB_MAN 0x0034 /* PHY Maintenance */ -#define MACB_PTR 0x0038 -#define MACB_PFR 0x003c -#define MACB_FTO 0x0040 -#define MACB_SCF 0x0044 -#define MACB_MCF 0x0048 -#define MACB_FRO 0x004c -#define MACB_FCSE 0x0050 -#define MACB_ALE 0x0054 -#define MACB_DTF 0x0058 -#define MACB_LCOL 0x005c -#define MACB_EXCOL 0x0060 -#define MACB_TUND 0x0064 -#define MACB_CSE 0x0068 -#define MACB_RRE 0x006c -#define MACB_ROVR 0x0070 -#define MACB_RSE 0x0074 -#define MACB_ELE 0x0078 -#define MACB_RJA 0x007c -#define MACB_USF 0x0080 -#define MACB_STE 0x0084 -#define MACB_RLE 0x0088 -#define MACB_TPF 0x008c -#define MACB_HRB 0x0090 -#define MACB_HRT 0x0094 -#define MACB_SA1B 0x0098 -#define MACB_SA1T 0x009c -#define MACB_SA2B 0x00a0 -#define MACB_SA2T 0x00a4 -#define MACB_SA3B 0x00a8 -#define MACB_SA3T 0x00ac -#define MACB_SA4B 0x00b0 -#define MACB_SA4T 0x00b4 -#define MACB_TID 0x00b8 -#define MACB_TPQ 0x00bc -#define MACB_USRIO 0x00c0 -#define MACB_WOL 0x00c4 -#define MACB_MID 0x00fc +#define MACB_NCR 0x0000 /* Network Control */ +#define MACB_NCFGR 0x0004 /* Network Config */ +#define MACB_NSR 0x0008 /* Network Status */ +#define MACB_TAR 0x000c /* AT91RM9200 only */ +#define MACB_TCR 0x0010 /* AT91RM9200 only */ +#define MACB_TSR 0x0014 /* Transmit Status */ +#define MACB_RBQP 0x0018 /* RX Q Base Address */ +#define MACB_TBQP 0x001c /* TX Q Base Address */ +#define MACB_RSR 0x0020 /* Receive Status */ +#define MACB_ISR 0x0024 /* Interrupt Status */ +#define MACB_IER 0x0028 /* Interrupt Enable */ +#define MACB_IDR 0x002c /* Interrupt Disable */ +#define MACB_IMR 0x0030 /* Interrupt Mask */ +#define MACB_MAN 0x0034 /* PHY Maintenance */ +#define MACB_PTR 0x0038 +#define MACB_PFR 0x003c +#define MACB_FTO 0x0040 +#define MACB_SCF 0x0044 +#define MACB_MCF 0x0048 +#define MACB_FRO 0x004c +#define MACB_FCSE 0x0050 +#define MACB_ALE 0x0054 +#define MACB_DTF 0x0058 +#define MACB_LCOL 0x005c +#define MACB_EXCOL 0x0060 +#define MACB_TUND 0x0064 +#define MACB_CSE 0x0068 +#define MACB_RRE 0x006c +#define MACB_ROVR 0x0070 +#define MACB_RSE 0x0074 +#define MACB_ELE 0x0078 +#define MACB_RJA 0x007c +#define MACB_USF 0x0080 +#define MACB_STE 0x0084 +#define MACB_RLE 0x0088 +#define MACB_TPF 0x008c +#define MACB_HRB 0x0090 +#define MACB_HRT 0x0094 +#define MACB_SA1B 0x0098 +#define MACB_SA1T 0x009c +#define MACB_SA2B 0x00a0 +#define MACB_SA2T 0x00a4 +#define MACB_SA3B 0x00a8 +#define MACB_SA3T 0x00ac +#define MACB_SA4B 0x00b0 +#define MACB_SA4T 0x00b4 +#define MACB_TID 0x00b8 +#define MACB_TPQ 0x00bc +#define MACB_USRIO 0x00c0 +#define MACB_WOL 0x00c4 +#define MACB_MID 0x00fc /* GEM register offsets. */ -#define GEM_NCFGR 0x0004 /* Network Config */ -#define GEM_USRIO 0x000c /* User IO */ -#define GEM_DMACFG 0x0010 /* DMA Configuration */ -#define GEM_HRB 0x0080 /* Hash Bottom */ -#define GEM_HRT 0x0084 /* Hash Top */ -#define GEM_SA1B 0x0088 /* Specific1 Bottom */ -#define GEM_SA1T 0x008C /* Specific1 Top */ -#define GEM_SA2B 0x0090 /* Specific2 Bottom */ -#define GEM_SA2T 0x0094 /* Specific2 Top */ -#define GEM_SA3B 0x0098 /* Specific3 Bottom */ -#define GEM_SA3T 0x009C /* Specific3 Top */ -#define GEM_SA4B 0x00A0 /* Specific4 Bottom */ -#define GEM_SA4T 0x00A4 /* Specific4 Top */ -#define GEM_OTX 0x0100 /* Octets transmitted */ -#define GEM_OCTTXL 0x0100 /* Octets transmitted - * [31:0] - */ -#define GEM_OCTTXH 0x0104 /* Octets transmitted - * [47:32] - */ -#define GEM_TXCNT 0x0108 /* Error-free Frames - * Transmitted counter - */ -#define GEM_TXBCCNT 0x010c /* Error-free Broadcast - * Frames counter - */ -#define GEM_TXMCCNT 0x0110 /* Error-free Multicast - * Frames counter - */ -#define GEM_TXPAUSECNT 0x0114 /* Pause Frames - * Transmitted Counter - */ -#define GEM_TX64CNT 0x0118 /* Error-free 64 byte - * Frames Transmitted - * counter - */ -#define GEM_TX65CNT 0x011c /* Error-free 65-127 byte - * Frames Transmitted - * counter - */ -#define GEM_TX128CNT 0x0120 /* Error-free 128-255 - * byte Frames - * Transmitted counter - */ -#define GEM_TX256CNT 0x0124 /* Error-free 256-511 - * byte Frames - * transmitted counter - */ -#define GEM_TX512CNT 0x0128 /* Error-free 512-1023 - * byte Frames - * transmitted counter - */ -#define GEM_TX1024CNT 0x012c /* Error-free 1024-1518 - * byte Frames - * transmitted counter - */ -#define GEM_TX1519CNT 0x0130 /* Error-free larger than - * 1519 byte Frames - * tranmitted counter - */ -#define GEM_TXURUNCNT 0x0134 /* TX under run error - * counter - */ -#define GEM_SNGLCOLLCNT 0x0138 /* Single Collision Frame - * Counter - */ -#define GEM_MULTICOLLCNT 0x013c /* Multiple Collision - * Frame Counter - */ -#define GEM_EXCESSCOLLCNT 0x0140 /* Excessive Collision - * Frame Counter - */ -#define GEM_LATECOLLCNT 0x0144 /* Late Collision Frame - * Counter - */ -#define GEM_TXDEFERCNT 0x0148 /* Deferred Transmission - * Frame Counter - */ -#define GEM_TXCSENSECNT 0x014c /* Carrier Sense Error - * Counter - */ -#define GEM_ORX 0x0150 /* Octets received */ -#define GEM_OCTRXL 0x0150 /* Octets received - * [31:0] - */ -#define GEM_OCTRXH 0x0154 /* Octets received - * [47:32] - */ -#define GEM_RXCNT 0x0158 /* Error-free Frames - * Received Counter - */ -#define GEM_RXBROADCNT 0x015c /* Error-free Broadcast - * Frames Received - * Counter - */ -#define GEM_RXMULTICNT 0x0160 /* Error-free Multicast - * Frames Received - * Counter - */ -#define GEM_RXPAUSECNT 0x0164 /* Error-free Pause - * Frames Received - * Counter - */ -#define GEM_RX64CNT 0x0168 /* Error-free 64 byte - * Frames Received - * Counter - */ -#define GEM_RX65CNT 0x016c /* Error-free 65-127 byte - * Frames Received - * Counter - */ -#define GEM_RX128CNT 0x0170 /* Error-free 128-255 - * byte Frames Received - * Counter - */ -#define GEM_RX256CNT 0x0174 /* Error-free 256-511 - * byte Frames Received - * Counter - */ -#define GEM_RX512CNT 0x0178 /* Error-free 512-1023 - * byte Frames Received - * Counter - */ -#define GEM_RX1024CNT 0x017c /* Error-free 1024-1518 - * byte Frames Received - * Counter - */ -#define GEM_RX1519CNT 0x0180 /* Error-free larger than - * 1519 Frames Received - * Counter - */ -#define GEM_RXUNDRCNT 0x0184 /* Undersize Frames - * Received Counter - */ -#define GEM_RXOVRCNT 0x0188 /* Oversize Frames - * Received Counter - */ -#define GEM_RXJABCNT 0x018c /* Jabbers Received - * Counter - */ -#define GEM_RXFCSCNT 0x0190 /* Frame Check Sequence - * Error Counter - */ -#define GEM_RXLENGTHCNT 0x0194 /* Length Field Error - * Counter - */ -#define GEM_RXSYMBCNT 0x0198 /* Symbol Error - * Counter - */ -#define GEM_RXALIGNCNT 0x019c /* Alignment Error - * Counter - */ -#define GEM_RXRESERRCNT 0x01a0 /* Receive Resource Error - * Counter - */ -#define GEM_RXORCNT 0x01a4 /* Receive Overrun - * Counter - */ -#define GEM_RXIPCCNT 0x01a8 /* IP header Checksum - * Error Counter - */ -#define GEM_RXTCPCCNT 0x01ac /* TCP Checksum Error - * Counter - */ -#define GEM_RXUDPCCNT 0x01b0 /* UDP Checksum Error - * Counter - */ -#define GEM_DCFG1 0x0280 /* Design Config 1 */ -#define GEM_DCFG2 0x0284 /* Design Config 2 */ -#define GEM_DCFG3 0x0288 /* Design Config 3 */ -#define GEM_DCFG4 0x028c /* Design Config 4 */ -#define GEM_DCFG5 0x0290 /* Design Config 5 */ -#define GEM_DCFG6 0x0294 /* Design Config 6 */ -#define GEM_DCFG7 0x0298 /* Design Config 7 */ - -#define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2)) -#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2)) -#define GEM_RBQP(hw_q) (0x0480 + ((hw_q) << 2)) -#define GEM_IER(hw_q) (0x0600 + ((hw_q) << 2)) -#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2)) -#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2)) +#define GEM_NCFGR 0x0004 /* Network Config */ +#define GEM_USRIO 0x000c /* User IO */ +#define GEM_DMACFG 0x0010 /* DMA Configuration */ +#define GEM_HRB 0x0080 /* Hash Bottom */ +#define GEM_HRT 0x0084 /* Hash Top */ +#define GEM_SA1B 0x0088 /* Specific1 Bottom */ +#define GEM_SA1T 0x008C /* Specific1 Top */ +#define GEM_SA2B 0x0090 /* Specific2 Bottom */ +#define GEM_SA2T 0x0094 /* Specific2 Top */ +#define GEM_SA3B 0x0098 /* Specific3 Bottom */ +#define GEM_SA3T 0x009C /* Specific3 Top */ +#define GEM_SA4B 0x00A0 /* Specific4 Bottom */ +#define GEM_SA4T 0x00A4 /* Specific4 Top */ +#define GEM_OTX 0x0100 /* Octets transmitted */ +#define GEM_OCTTXL 0x0100 /* Octets transmitted [31:0] */ +#define GEM_OCTTXH 0x0104 /* Octets transmitted [47:32] */ +#define GEM_TXCNT 0x0108 /* Frames Transmitted counter */ +#define GEM_TXBCCNT 0x010c /* Broadcast Frames counter */ +#define GEM_TXMCCNT 0x0110 /* Multicast Frames counter */ +#define GEM_TXPAUSECNT 0x0114 /* Pause Frames Transmitted Counter */ +#define GEM_TX64CNT 0x0118 /* 64 byte Frames TX counter */ +#define GEM_TX65CNT 0x011c /* 65-127 byte Frames TX counter */ +#define GEM_TX128CNT 0x0120 /* 128-255 byte Frames TX counter */ +#define GEM_TX256CNT 0x0124 /* 256-511 byte Frames TX counter */ +#define GEM_TX512CNT 0x0128 /* 512-1023 byte Frames TX counter */ +#define GEM_TX1024CNT 0x012c /* 1024-1518 byte Frames TX counter */ +#define GEM_TX1519CNT 0x0130 /* 1519+ byte Frames TX counter */ +#define GEM_TXURUNCNT 0x0134 /* TX under run error counter */ +#define GEM_SNGLCOLLCNT 0x0138 /* Single Collision Frame Counter */ +#define GEM_MULTICOLLCNT 0x013c /* Multiple Collision Frame Counter */ +#define GEM_EXCESSCOLLCNT 0x0140 /* Excessive Collision Frame Counter */ +#define GEM_LATECOLLCNT 0x0144 /* Late Collision Frame Counter */ +#define GEM_TXDEFERCNT 0x0148 /* Deferred Transmission Frame Counter */ +#define GEM_TXCSENSECNT 0x014c /* Carrier Sense Error Counter */ +#define GEM_ORX 0x0150 /* Octets received */ +#define GEM_OCTRXL 0x0150 /* Octets received [31:0] */ +#define GEM_OCTRXH 0x0154 /* Octets received [47:32] */ +#define GEM_RXCNT 0x0158 /* Frames Received Counter */ +#define GEM_RXBROADCNT 0x015c /* Broadcast Frames Received Counter */ +#define GEM_RXMULTICNT 0x0160 /* Multicast Frames Received Counter */ +#define GEM_RXPAUSECNT 0x0164 /* Pause Frames Received Counter */ +#define GEM_RX64CNT 0x0168 /* 64 byte Frames RX Counter */ +#define GEM_RX65CNT 0x016c /* 65-127 byte Frames RX Counter */ +#define GEM_RX128CNT 0x0170 /* 128-255 byte Frames RX Counter */ +#define GEM_RX256CNT 0x0174 /* 256-511 byte Frames RX Counter */ +#define GEM_RX512CNT 0x0178 /* 512-1023 byte Frames RX Counter */ +#define GEM_RX1024CNT 0x017c /* 1024-1518 byte Frames RX Counter */ +#define GEM_RX1519CNT 0x0180 /* 1519+ byte Frames RX Counter */ +#define GEM_RXUNDRCNT 0x0184 /* Undersize Frames Received Counter */ +#define GEM_RXOVRCNT 0x0188 /* Oversize Frames Received Counter */ +#define GEM_RXJABCNT 0x018c /* Jabbers Received Counter */ +#define GEM_RXFCSCNT 0x0190 /* Frame Check Sequence Error Counter */ +#define GEM_RXLENGTHCNT 0x0194 /* Length Field Error Counter */ +#define GEM_RXSYMBCNT 0x0198 /* Symbol Error Counter */ +#define GEM_RXALIGNCNT 0x019c /* Alignment Error Counter */ +#define GEM_RXRESERRCNT 0x01a0 /* Receive Resource Error Counter */ +#define GEM_RXORCNT 0x01a4 /* Receive Overrun Counter */ +#define GEM_RXIPCCNT 0x01a8 /* IP header Checksum Error Counter */ +#define GEM_RXTCPCCNT 0x01ac /* TCP Checksum Error Counter */ +#define GEM_RXUDPCCNT 0x01b0 /* UDP Checksum Error Counter */ +#define GEM_DCFG1 0x0280 /* Design Config 1 */ +#define GEM_DCFG2 0x0284 /* Design Config 2 */ +#define GEM_DCFG3 0x0288 /* Design Config 3 */ +#define GEM_DCFG4 0x028c /* Design Config 4 */ +#define GEM_DCFG5 0x0290 /* Design Config 5 */ +#define GEM_DCFG6 0x0294 /* Design Config 6 */ +#define GEM_DCFG7 0x0298 /* Design Config 7 */ + +#define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2)) +#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2)) +#define GEM_RBQP(hw_q) (0x0480 + ((hw_q) << 2)) +#define GEM_IER(hw_q) (0x0600 + ((hw_q) << 2)) +#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2)) +#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2)) /* Bitfields in NCR */ -#define MACB_LB_OFFSET 0 /* reserved */ -#define MACB_LB_SIZE 1 -#define MACB_LLB_OFFSET 1 /* Loop back local */ -#define MACB_LLB_SIZE 1 -#define MACB_RE_OFFSET 2 /* Receive enable */ -#define MACB_RE_SIZE 1 -#define MACB_TE_OFFSET 3 /* Transmit enable */ -#define MACB_TE_SIZE 1 -#define MACB_MPE_OFFSET 4 /* Management port enable */ -#define MACB_MPE_SIZE 1 -#define MACB_CLRSTAT_OFFSET 5 /* Clear stats regs */ -#define MACB_CLRSTAT_SIZE 1 -#define MACB_INCSTAT_OFFSET 6 /* Incremental stats regs */ -#define MACB_INCSTAT_SIZE 1 -#define MACB_WESTAT_OFFSET 7 /* Write enable stats regs */ -#define MACB_WESTAT_SIZE 1 -#define MACB_BP_OFFSET 8 /* Back pressure */ -#define MACB_BP_SIZE 1 -#define MACB_TSTART_OFFSET 9 /* Start transmission */ -#define MACB_TSTART_SIZE 1 -#define MACB_THALT_OFFSET 10 /* Transmit halt */ -#define MACB_THALT_SIZE 1 -#define MACB_NCR_TPF_OFFSET 11 /* Transmit pause frame */ -#define MACB_NCR_TPF_SIZE 1 -#define MACB_TZQ_OFFSET 12 /* Transmit zero quantum - * pause frame - */ -#define MACB_TZQ_SIZE 1 +#define MACB_LB_OFFSET 0 /* reserved */ +#define MACB_LB_SIZE 1 +#define MACB_LLB_OFFSET 1 /* Loop back local */ +#define MACB_LLB_SIZE 1 +#define MACB_RE_OFFSET 2 /* Receive enable */ +#define MACB_RE_SIZE 1 +#define MACB_TE_OFFSET 3 /* Transmit enable */ +#define MACB_TE_SIZE 1 +#define MACB_MPE_OFFSET 4 /* Management port enable */ +#define MACB_MPE_SIZE 1 +#define MACB_CLRSTAT_OFFSET 5 /* Clear stats regs */ +#define MACB_CLRSTAT_SIZE 1 +#define MACB_INCSTAT_OFFSET 6 /* Incremental stats regs */ +#define MACB_INCSTAT_SIZE 1 +#define MACB_WESTAT_OFFSET 7 /* Write enable stats regs */ +#define MACB_WESTAT_SIZE 1 +#define MACB_BP_OFFSET 8 /* Back pressure */ +#define MACB_BP_SIZE 1 +#define MACB_TSTART_OFFSET 9 /* Start transmission */ +#define MACB_TSTART_SIZE 1 +#define MACB_THALT_OFFSET 10 /* Transmit halt */ +#define MACB_THALT_SIZE 1 +#define MACB_NCR_TPF_OFFSET 11 /* Transmit pause frame */ +#define MACB_NCR_TPF_SIZE 1 +#define MACB_TZQ_OFFSET 12 /* Transmit zero quantum pause frame */ +#define MACB_TZQ_SIZE 1 /* Bitfields in NCFGR */ -#define MACB_SPD_OFFSET 0 /* Speed */ -#define MACB_SPD_SIZE 1 -#define MACB_FD_OFFSET 1 /* Full duplex */ -#define MACB_FD_SIZE 1 -#define MACB_BIT_RATE_OFFSET 2 /* Discard non-VLAN frames */ -#define MACB_BIT_RATE_SIZE 1 -#define MACB_JFRAME_OFFSET 3 /* reserved */ -#define MACB_JFRAME_SIZE 1 -#define MACB_CAF_OFFSET 4 /* Copy all frames */ -#define MACB_CAF_SIZE 1 -#define MACB_NBC_OFFSET 5 /* No broadcast */ -#define MACB_NBC_SIZE 1 -#define MACB_NCFGR_MTI_OFFSET 6 /* Multicast hash enable */ -#define MACB_NCFGR_MTI_SIZE 1 -#define MACB_UNI_OFFSET 7 /* Unicast hash enable */ -#define MACB_UNI_SIZE 1 -#define MACB_BIG_OFFSET 8 /* Receive 1536 byte frames */ -#define MACB_BIG_SIZE 1 -#define MACB_EAE_OFFSET 9 /* External address match - * enable - */ -#define MACB_EAE_SIZE 1 -#define MACB_CLK_OFFSET 10 -#define MACB_CLK_SIZE 2 -#define MACB_RTY_OFFSET 12 /* Retry test */ -#define MACB_RTY_SIZE 1 -#define MACB_PAE_OFFSET 13 /* Pause enable */ -#define MACB_PAE_SIZE 1 -#define MACB_RM9200_RMII_OFFSET 13 /* AT91RM9200 only */ -#define MACB_RM9200_RMII_SIZE 1 /* AT91RM9200 only */ -#define MACB_RBOF_OFFSET 14 /* Receive buffer offset */ -#define MACB_RBOF_SIZE 2 -#define MACB_RLCE_OFFSET 16 /* Length field error frame - * discard - */ -#define MACB_RLCE_SIZE 1 -#define MACB_DRFCS_OFFSET 17 /* FCS remove */ -#define MACB_DRFCS_SIZE 1 -#define MACB_EFRHD_OFFSET 18 -#define MACB_EFRHD_SIZE 1 -#define MACB_IRXFCS_OFFSET 19 -#define MACB_IRXFCS_SIZE 1 +#define MACB_SPD_OFFSET 0 /* Speed */ +#define MACB_SPD_SIZE 1 +#define MACB_FD_OFFSET 1 /* Full duplex */ +#define MACB_FD_SIZE 1 +#define MACB_BIT_RATE_OFFSET 2 /* Discard non-VLAN frames */ +#define MACB_BIT_RATE_SIZE 1 +#define MACB_JFRAME_OFFSET 3 /* reserved */ +#define MACB_JFRAME_SIZE 1 +#define MACB_CAF_OFFSET 4 /* Copy all frames */ +#define MACB_CAF_SIZE 1 +#define MACB_NBC_OFFSET 5 /* No broadcast */ +#define MACB_NBC_SIZE 1 +#define MACB_NCFGR_MTI_OFFSET 6 /* Multicast hash enable */ +#define MACB_NCFGR_MTI_SIZE 1 +#define MACB_UNI_OFFSET 7 /* Unicast hash enable */ +#define MACB_UNI_SIZE 1 +#define MACB_BIG_OFFSET 8 /* Receive 1536 byte frames */ +#define MACB_BIG_SIZE 1 +#define MACB_EAE_OFFSET 9 /* External address match enable */ +#define MACB_EAE_SIZE 1 +#define MACB_CLK_OFFSET 10 +#define MACB_CLK_SIZE 2 +#define MACB_RTY_OFFSET 12 /* Retry test */ +#define MACB_RTY_SIZE 1 +#define MACB_PAE_OFFSET 13 /* Pause enable */ +#define MACB_PAE_SIZE 1 +#define MACB_RM9200_RMII_OFFSET 13 /* AT91RM9200 only */ +#define MACB_RM9200_RMII_SIZE 1 /* AT91RM9200 only */ +#define MACB_RBOF_OFFSET 14 /* Receive buffer offset */ +#define MACB_RBOF_SIZE 2 +#define MACB_RLCE_OFFSET 16 /* Length field error frame discard */ +#define MACB_RLCE_SIZE 1 +#define MACB_DRFCS_OFFSET 17 /* FCS remove */ +#define MACB_DRFCS_SIZE 1 +#define MACB_EFRHD_OFFSET 18 +#define MACB_EFRHD_SIZE 1 +#define MACB_IRXFCS_OFFSET 19 +#define MACB_IRXFCS_SIZE 1 /* GEM specific NCFGR bitfields. */ -#define GEM_GBE_OFFSET 10 /* Gigabit mode enable */ -#define GEM_GBE_SIZE 1 -#define GEM_CLK_OFFSET 18 /* MDC clock division */ -#define GEM_CLK_SIZE 3 -#define GEM_DBW_OFFSET 21 /* Data bus width */ -#define GEM_DBW_SIZE 2 -#define GEM_RXCOEN_OFFSET 24 -#define GEM_RXCOEN_SIZE 1 +#define GEM_GBE_OFFSET 10 /* Gigabit mode enable */ +#define GEM_GBE_SIZE 1 +#define GEM_CLK_OFFSET 18 /* MDC clock division */ +#define GEM_CLK_SIZE 3 +#define GEM_DBW_OFFSET 21 /* Data bus width */ +#define GEM_DBW_SIZE 2 +#define GEM_RXCOEN_OFFSET 24 +#define GEM_RXCOEN_SIZE 1 /* Constants for data bus width. */ -#define GEM_DBW32 0 /* 32 bit AMBA AHB data bus - * width - */ -#define GEM_DBW64 1 /* 64 bit AMBA AHB data bus - * width - */ -#define GEM_DBW128 2 /* 128 bit AMBA AHB data bus - * width - */ +#define GEM_DBW32 0 /* 32 bit AMBA AHB data bus width */ +#define GEM_DBW64 1 /* 64 bit AMBA AHB data bus width */ +#define GEM_DBW128 2 /* 128 bit AMBA AHB data bus width */ /* Bitfields in DMACFG. */ -#define GEM_FBLDO_OFFSET 0 /* AHB fixed burst length for - * DMA data operations - */ -#define GEM_FBLDO_SIZE 5 -#define GEM_ENDIA_OFFSET 7 /* AHB endian swap mode enable - * for packet data accesses - */ -#define GEM_ENDIA_SIZE 1 -#define GEM_RXBMS_OFFSET 8 /* Receiver packet buffer - * memory size select - */ -#define GEM_RXBMS_SIZE 2 -#define GEM_TXPBMS_OFFSET 10 /* Transmitter packet buffer - * memory size select - */ -#define GEM_TXPBMS_SIZE 1 -#define GEM_TXCOEN_OFFSET 11 /* Transmitter IP, TCP and - * UDP checksum generation - * offload enable - */ -#define GEM_TXCOEN_SIZE 1 -#define GEM_RXBS_OFFSET 16 /* DMA receive buffer size in - * AHB system memory - */ -#define GEM_RXBS_SIZE 8 -#define GEM_DDRP_OFFSET 24 /* disc_when_no_ahb */ -#define GEM_DDRP_SIZE 1 +#define GEM_FBLDO_OFFSET 0 /* fixed burst length for DMA */ +#define GEM_FBLDO_SIZE 5 +#define GEM_ENDIA_OFFSET 7 /* endian swap mode for packet data access */ +#define GEM_ENDIA_SIZE 1 +#define GEM_RXBMS_OFFSET 8 /* RX packet buffer memory size select */ +#define GEM_RXBMS_SIZE 2 +#define GEM_TXPBMS_OFFSET 10 /* TX packet buffer memory size select */ +#define GEM_TXPBMS_SIZE 1 +#define GEM_TXCOEN_OFFSET 11 /* TX IP/TCP/UDP checksum gen offload */ +#define GEM_TXCOEN_SIZE 1 +#define GEM_RXBS_OFFSET 16 /* DMA receive buffer size */ +#define GEM_RXBS_SIZE 8 +#define GEM_DDRP_OFFSET 24 /* disc_when_no_ahb */ +#define GEM_DDRP_SIZE 1 /* Bitfields in NSR */ -#define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */ -#define MACB_NSR_LINK_SIZE 1 -#define MACB_MDIO_OFFSET 1 /* status of the mdio_in - * pin - */ -#define MACB_MDIO_SIZE 1 -#define MACB_IDLE_OFFSET 2 /* The PHY management logic is - * idle (i.e. has completed) - */ -#define MACB_IDLE_SIZE 1 +#define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */ +#define MACB_NSR_LINK_SIZE 1 +#define MACB_MDIO_OFFSET 1 /* status of the mdio_in pin */ +#define MACB_MDIO_SIZE 1 +#define MACB_IDLE_OFFSET 2 /* The PHY management logic is idle */ +#define MACB_IDLE_SIZE 1 /* Bitfields in TSR */ -#define MACB_UBR_OFFSET 0 /* Used bit read */ -#define MACB_UBR_SIZE 1 -#define MACB_COL_OFFSET 1 /* Collision occurred */ -#define MACB_COL_SIZE 1 -#define MACB_TSR_RLE_OFFSET 2 /* Retry limit exceeded */ -#define MACB_TSR_RLE_SIZE 1 -#define MACB_TGO_OFFSET 3 /* Transmit go */ -#define MACB_TGO_SIZE 1 -#define MACB_BEX_OFFSET 4 /* Transmit frame corruption - * due to AHB error - */ -#define MACB_BEX_SIZE 1 -#define MACB_RM9200_BNQ_OFFSET 4 /* AT91RM9200 only */ -#define MACB_RM9200_BNQ_SIZE 1 /* AT91RM9200 only */ -#define MACB_COMP_OFFSET 5 /* Trnasmit complete */ -#define MACB_COMP_SIZE 1 -#define MACB_UND_OFFSET 6 /* Trnasmit under run */ -#define MACB_UND_SIZE 1 +#define MACB_UBR_OFFSET 0 /* Used bit read */ +#define MACB_UBR_SIZE 1 +#define MACB_COL_OFFSET 1 /* Collision occurred */ +#define MACB_COL_SIZE 1 +#define MACB_TSR_RLE_OFFSET 2 /* Retry limit exceeded */ +#define MACB_TSR_RLE_SIZE 1 +#define MACB_TGO_OFFSET 3 /* Transmit go */ +#define MACB_TGO_SIZE 1 +#define MACB_BEX_OFFSET 4 /* TX frame corruption due to AHB error */ +#define MACB_BEX_SIZE 1 +#define MACB_RM9200_BNQ_OFFSET 4 /* AT91RM9200 only */ +#define MACB_RM9200_BNQ_SIZE 1 /* AT91RM9200 only */ +#define MACB_COMP_OFFSET 5 /* Trnasmit complete */ +#define MACB_COMP_SIZE 1 +#define MACB_UND_OFFSET 6 /* Trnasmit under run */ +#define MACB_UND_SIZE 1 /* Bitfields in RSR */ -#define MACB_BNA_OFFSET 0 /* Buffer not available */ -#define MACB_BNA_SIZE 1 -#define MACB_REC_OFFSET 1 /* Frame received */ -#define MACB_REC_SIZE 1 -#define MACB_OVR_OFFSET 2 /* Receive overrun */ -#define MACB_OVR_SIZE 1 +#define MACB_BNA_OFFSET 0 /* Buffer not available */ +#define MACB_BNA_SIZE 1 +#define MACB_REC_OFFSET 1 /* Frame received */ +#define MACB_REC_SIZE 1 +#define MACB_OVR_OFFSET 2 /* Receive overrun */ +#define MACB_OVR_SIZE 1 /* Bitfields in ISR/IER/IDR/IMR */ -#define MACB_MFD_OFFSET 0 /* Management frame sent */ -#define MACB_MFD_SIZE 1 -#define MACB_RCOMP_OFFSET 1 /* Receive complete */ -#define MACB_RCOMP_SIZE 1 -#define MACB_RXUBR_OFFSET 2 /* RX used bit read */ -#define MACB_RXUBR_SIZE 1 -#define MACB_TXUBR_OFFSET 3 /* TX used bit read */ -#define MACB_TXUBR_SIZE 1 -#define MACB_ISR_TUND_OFFSET 4 /* Enable trnasmit buffer - * under run interrupt - */ -#define MACB_ISR_TUND_SIZE 1 -#define MACB_ISR_RLE_OFFSET 5 /* Enable retry limit exceeded - * or late collision interrupt - */ -#define MACB_ISR_RLE_SIZE 1 -#define MACB_TXERR_OFFSET 6 /* Enable transmit frame - * corruption due to AHB error - * interrupt - */ -#define MACB_TXERR_SIZE 1 -#define MACB_TCOMP_OFFSET 7 /* Enable transmit complete - * interrupt - */ -#define MACB_TCOMP_SIZE 1 -#define MACB_ISR_LINK_OFFSET 9 /* Enable link change - * interrupt - */ -#define MACB_ISR_LINK_SIZE 1 -#define MACB_ISR_ROVR_OFFSET 10 /* Enable receive overrun - * interrupt - */ -#define MACB_ISR_ROVR_SIZE 1 -#define MACB_HRESP_OFFSET 11 /* Enable hrsep not OK - * interrupt - */ -#define MACB_HRESP_SIZE 1 -#define MACB_PFR_OFFSET 12 /* Enable pause frame with - * non-zero pause quantum - * interrupt - */ -#define MACB_PFR_SIZE 1 -#define MACB_PTZ_OFFSET 13 /* Enable pause time zero - * interrupt - */ -#define MACB_PTZ_SIZE 1 +#define MACB_MFD_OFFSET 0 /* Management frame sent */ +#define MACB_MFD_SIZE 1 +#define MACB_RCOMP_OFFSET 1 /* Receive complete */ +#define MACB_RCOMP_SIZE 1 +#define MACB_RXUBR_OFFSET 2 /* RX used bit read */ +#define MACB_RXUBR_SIZE 1 +#define MACB_TXUBR_OFFSET 3 /* TX used bit read */ +#define MACB_TXUBR_SIZE 1 +#define MACB_ISR_TUND_OFFSET 4 /* Enable TX buffer under run interrupt */ +#define MACB_ISR_TUND_SIZE 1 +#define MACB_ISR_RLE_OFFSET 5 /* EN retry exceeded/late coll interrupt */ +#define MACB_ISR_RLE_SIZE 1 +#define MACB_TXERR_OFFSET 6 /* EN TX frame corrupt from error interrupt */ +#define MACB_TXERR_SIZE 1 +#define MACB_TCOMP_OFFSET 7 /* Enable transmit complete interrupt */ +#define MACB_TCOMP_SIZE 1 +#define MACB_ISR_LINK_OFFSET 9 /* Enable link change interrupt */ +#define MACB_ISR_LINK_SIZE 1 +#define MACB_ISR_ROVR_OFFSET 10 /* Enable receive overrun interrupt */ +#define MACB_ISR_ROVR_SIZE 1 +#define MACB_HRESP_OFFSET 11 /* Enable hrsep not OK interrupt */ +#define MACB_HRESP_SIZE 1 +#define MACB_PFR_OFFSET 12 /* Enable pause frame w/ quantum interrupt */ +#define MACB_PFR_SIZE 1 +#define MACB_PTZ_OFFSET 13 /* Enable pause time zero interrupt */ +#define MACB_PTZ_SIZE 1 /* Bitfields in MAN */ -#define MACB_DATA_OFFSET 0 /* data */ -#define MACB_DATA_SIZE 16 -#define MACB_CODE_OFFSET 16 /* Must be written to 10 */ -#define MACB_CODE_SIZE 2 -#define MACB_REGA_OFFSET 18 /* Register address */ -#define MACB_REGA_SIZE 5 -#define MACB_PHYA_OFFSET 23 /* PHY address */ -#define MACB_PHYA_SIZE 5 -#define MACB_RW_OFFSET 28 /* Operation. 10 is read. 01 - * is write. - */ -#define MACB_RW_SIZE 2 -#define MACB_SOF_OFFSET 30 /* Must be written to 1 for - * Clause 22 operation - */ -#define MACB_SOF_SIZE 2 +#define MACB_DATA_OFFSET 0 /* data */ +#define MACB_DATA_SIZE 16 +#define MACB_CODE_OFFSET 16 /* Must be written to 10 */ +#define MACB_CODE_SIZE 2 +#define MACB_REGA_OFFSET 18 /* Register address */ +#define MACB_REGA_SIZE 5 +#define MACB_PHYA_OFFSET 23 /* PHY address */ +#define MACB_PHYA_SIZE 5 +#define MACB_RW_OFFSET 28 /* Operation. 10 is read. 01 is write. */ +#define MACB_RW_SIZE 2 +#define MACB_SOF_OFFSET 30 /* Must be written to 1 for Clause 22 */ +#define MACB_SOF_SIZE 2 /* Bitfields in USRIO (AVR32) */ #define MACB_MII_OFFSET 0 @@ -597,8 +435,7 @@ #define queue_writel(queue, reg, value) \ __raw_writel((value), (queue)->bp->regs + (queue)->reg) -/* - * Conditional GEM/MACB macros. These perform the operation to the correct +/* Conditional GEM/MACB macros. These perform the operation to the correct * register dependent on whether the device is a GEM or a MACB. For registers * and bitfields that are common across both devices, use macb_{read,write}l * to avoid the cost of the conditional. @@ -621,8 +458,7 @@ __v; \ }) -/** - * struct macb_dma_desc - Hardware DMA descriptor +/* struct macb_dma_desc - Hardware DMA descriptor * @addr: DMA address of data buffer * @ctrl: Control and status bits */ @@ -711,8 +547,7 @@ struct macb_dma_desc { /* limit RX checksum offload to TCP and UDP packets */ #define GEM_RX_CSUM_CHECKED_MASK 2 -/** - * struct macb_tx_skb - data about an skb which is being transmitted +/* struct macb_tx_skb - data about an skb which is being transmitted * @skb: skb currently being transmitted, only set for the last buffer * of the frame * @mapping: DMA address of the skb's fragment buffer @@ -727,8 +562,7 @@ struct macb_tx_skb { bool mapped_as_page; }; -/* - * Hardware-collected statistics. Used when updating the network +/* Hardware-collected statistics. Used when updating the network * device stats by a periodic timer. */ struct macb_stats { -- cgit v1.2.1 From 2fa45e22c8dee81a9e7232391f19aaaa9b70e7dd Mon Sep 17 00:00:00 2001 From: Xander Huff Date: Thu, 15 Jan 2015 15:55:19 -0600 Subject: net/macb: Add whitespace around arithmetic operators Spaces should surround add, multiply, and bitshift operators. Signed-off-by: Xander Huff Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index dd8c202c0708..9edd7872c420 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1691,7 +1691,7 @@ static int hash_get_index(__u8 *addr) for (j = 0; j < 6; j++) { for (i = 0, bitval = 0; i < 8; i++) - bitval ^= hash_bit_value(i*6 + j, addr); + bitval ^= hash_bit_value(i * 6 + j, addr); hash_index |= (bitval << j); } @@ -1832,15 +1832,15 @@ static void gem_update_stats(struct macb *bp) for (i = 0; i < GEM_STATS_LEN; ++i, ++p) { u32 offset = gem_statistics[i].offset; - u64 val = __raw_readl(bp->regs+offset); + u64 val = __raw_readl(bp->regs + offset); bp->ethtool_stats[i] += val; *p += val; if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) { /* Add GEM_OCTTXH, GEM_OCTRXH */ - val = __raw_readl(bp->regs+offset+4); - bp->ethtool_stats[i] += ((u64)val)<<32; + val = __raw_readl(bp->regs + offset + 4); + bp->ethtool_stats[i] += ((u64)val) << 32; *(++p) += val; } } @@ -1891,7 +1891,7 @@ static void gem_get_ethtool_stats(struct net_device *dev, bp = netdev_priv(dev); gem_update_stats(bp); - memcpy(data, &bp->ethtool_stats, sizeof(u64)*GEM_STATS_LEN); + memcpy(data, &bp->ethtool_stats, sizeof(u64) * GEM_STATS_LEN); } static int gem_get_sset_count(struct net_device *dev, int sset) -- cgit v1.2.1 From 8cd5a56c2b7c27dc574b465401e4f41a5e363e24 Mon Sep 17 00:00:00 2001 From: Xander Huff Date: Thu, 15 Jan 2015 15:55:20 -0600 Subject: net/macb: Create gem_ethtool_ops for new statistics functions 10/100 MACB does not have the same statistics possibilities as GEM. Separate macb_ethtool_ops to make a new GEM-specific struct with the new statistics functions included. Signed-off-by: Xander Huff Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 9edd7872c420..f2f9ca00567b 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2032,11 +2032,21 @@ const struct ethtool_ops macb_ethtool_ops = { .get_regs = macb_get_regs, .get_link = ethtool_op_get_link, .get_ts_info = ethtool_op_get_ts_info, +}; +EXPORT_SYMBOL_GPL(macb_ethtool_ops); + +const struct ethtool_ops gem_ethtool_ops = { + .get_settings = macb_get_settings, + .set_settings = macb_set_settings, + .get_regs_len = macb_get_regs_len, + .get_regs = macb_get_regs, + .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, .get_ethtool_stats = gem_get_ethtool_stats, .get_strings = gem_get_ethtool_strings, .get_sset_count = gem_get_sset_count, }; -EXPORT_SYMBOL_GPL(macb_ethtool_ops); +EXPORT_SYMBOL_GPL(gem_ethtool_ops); int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { @@ -2325,7 +2335,6 @@ static int __init macb_probe(struct platform_device *pdev) dev->netdev_ops = &macb_netdev_ops; netif_napi_add(dev, &bp->napi, macb_poll, 64); - dev->ethtool_ops = &macb_ethtool_ops; dev->base_addr = regs->start; @@ -2339,12 +2348,14 @@ static int __init macb_probe(struct platform_device *pdev) bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers; bp->macbgem_ops.mog_init_rings = gem_init_rings; bp->macbgem_ops.mog_rx = gem_rx; + dev->ethtool_ops = &gem_ethtool_ops; } else { bp->max_tx_length = MACB_MAX_TX_LEN; bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers; bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers; bp->macbgem_ops.mog_init_rings = macb_init_rings; bp->macbgem_ops.mog_rx = macb_rx; + dev->ethtool_ops = &macb_ethtool_ops; } /* Set features */ -- cgit v1.2.1 From 35155fe6e60d0729b51a5a197b857ae4269b155e Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Fri, 12 Dec 2014 07:50:07 +0000 Subject: i40e/i40evf: AdminQ updates ww36 Several little tweaks to keep FW, SV, and SW in line together - Remove the unused and deprecated i40e_aqc_opc_debug_modify_internals - Add define for iSCSI capability - Fix queue mask size - Adjust i40e_aqc_oem_param_change for ease-of-use Change-ID: I51f250b367912968a7cec61b3a68110d9796e914 Signed-off-by: Shannon Nelson Signed-off-by: Kamil Kacperski Acked-by: Greg Rose Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 9 +++++---- drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 8835aeeff23e..490dfcf61ea0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -276,7 +276,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_debug_write_reg = 0xFF04, i40e_aqc_opc_debug_modify_reg = 0xFF07, i40e_aqc_opc_debug_dump_internals = 0xFF08, - i40e_aqc_opc_debug_modify_internals = 0xFF09, }; /* command structures and indirect data structures */ @@ -410,6 +409,7 @@ struct i40e_aqc_list_capabilities_element_resp { #define I40E_AQ_CAP_ID_VSI 0x0017 #define I40E_AQ_CAP_ID_DCB 0x0018 #define I40E_AQ_CAP_ID_FCOE 0x0021 +#define I40E_AQ_CAP_ID_ISCSI 0x0022 #define I40E_AQ_CAP_ID_RSS 0x0040 #define I40E_AQ_CAP_ID_RXQ 0x0041 #define I40E_AQ_CAP_ID_TXQ 0x0042 @@ -1207,7 +1207,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data { } ipaddr; __le16 flags; #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \ +#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \ I40E_AQC_ADD_CLOUD_FILTER_SHIFT) /* 0x0000 reserved */ #define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001 @@ -1240,7 +1240,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data { u8 reserved[4]; __le16 queue_number; #define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x3F << \ +#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x7FF << \ I40E_AQC_ADD_CLOUD_QUEUE_SHIFT) u8 reserved2[14]; /* response section */ @@ -2106,7 +2106,8 @@ struct i40e_aqc_oem_param_change { #define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1 #define I40E_AQ_OEM_PARAM_MAC 2 __le32 param_value1; - u8 param_value2[8]; + __le16 param_value2; + u8 reserved[6]; }; I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index ff1b16370da9..a20b2b0d5d8c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -276,7 +276,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_debug_write_reg = 0xFF04, i40e_aqc_opc_debug_modify_reg = 0xFF07, i40e_aqc_opc_debug_dump_internals = 0xFF08, - i40e_aqc_opc_debug_modify_internals = 0xFF09, }; /* command structures and indirect data structures */ @@ -410,6 +409,7 @@ struct i40e_aqc_list_capabilities_element_resp { #define I40E_AQ_CAP_ID_VSI 0x0017 #define I40E_AQ_CAP_ID_DCB 0x0018 #define I40E_AQ_CAP_ID_FCOE 0x0021 +#define I40E_AQ_CAP_ID_ISCSI 0x0022 #define I40E_AQ_CAP_ID_RSS 0x0040 #define I40E_AQ_CAP_ID_RXQ 0x0041 #define I40E_AQ_CAP_ID_TXQ 0x0042 @@ -1207,7 +1207,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data { } ipaddr; __le16 flags; #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \ +#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \ I40E_AQC_ADD_CLOUD_FILTER_SHIFT) /* 0x0000 reserved */ #define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001 @@ -1240,7 +1240,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data { u8 reserved[4]; __le16 queue_number; #define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x3F << \ +#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x7FF << \ I40E_AQC_ADD_CLOUD_QUEUE_SHIFT) u8 reserved2[14]; /* response section */ @@ -2082,7 +2082,8 @@ struct i40e_aqc_oem_param_change { #define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1 #define I40E_AQ_OEM_PARAM_MAC 2 __le32 param_value1; - u8 param_value2[8]; + __le16 param_value2; + u8 reserved[6]; }; I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change); -- cgit v1.2.1 From 83c5fe7723dc6f69c49bb7020b02141308a5bc3a Mon Sep 17 00:00:00 2001 From: Kevin Scott Date: Thu, 11 Dec 2014 07:06:36 +0000 Subject: i40e/i40evf: Increase ASQ timeout Increase ASQ timeout for some scenarios with multi-function devices Change-ID: I2d7655b19e6c6f9a7ad04deacb106ca8d53886db Signed-off-by: Kevin Scott Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.h | 2 +- drivers/net/ethernet/intel/i40evf/i40e_adminq.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h index 564d0b0192f7..de17b6fbcc4e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h @@ -148,7 +148,7 @@ static inline int i40e_aq_rc_to_posix(u32 aq_ret, u16 aq_rc) /* general information */ #define I40E_AQ_LARGE_BUF 512 -#define I40E_ASQ_CMD_TIMEOUT 100 /* msecs */ +#define I40E_ASQ_CMD_TIMEOUT 250 /* msecs */ void i40e_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h index 6c31bf22c2c3..60f04e96a80e 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h @@ -148,7 +148,7 @@ static inline int i40e_aq_rc_to_posix(u32 aq_ret, u16 aq_rc) /* general information */ #define I40E_AQ_LARGE_BUF 512 -#define I40E_ASQ_CMD_TIMEOUT 100 /* msecs */ +#define I40E_ASQ_CMD_TIMEOUT 250 /* msecs */ void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode); -- cgit v1.2.1 From e240f674eca856bde09b1101e2c5477002e920f2 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Thu, 11 Dec 2014 07:06:37 +0000 Subject: i40e: fix proc/int descriptions This patch fixes a problem where the /proc/interrupts descriptions from the msix configuration were truncating the needed bus info, making it hard to distinguish configuration from port to port. This patch increases the string buffer size in order to allow the full data to be displayed and sync's the text formatting of the misc and fdir interrupt names Change-ID: Ib01d6c61fb3f4ac70fbdf5bcc520b22638ea54b7 Signed-off-by: Carolyn Wyborny Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index f3b036d19b6b..cd34d9bd3b56 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4845,7 +4845,7 @@ static int i40e_open(struct net_device *netdev) int i40e_vsi_open(struct i40e_vsi *vsi) { struct i40e_pf *pf = vsi->back; - char int_name[IFNAMSIZ]; + char int_name[IFNAMSIZ + 9]; int err; /* allocate descriptors */ @@ -4879,7 +4879,7 @@ int i40e_vsi_open(struct i40e_vsi *vsi) goto err_set_queues; } else if (vsi->type == I40E_VSI_FDIR) { - snprintf(int_name, sizeof(int_name) - 1, "%s-%s-fdir", + snprintf(int_name, sizeof(int_name) - 1, "%s-%s:fdir", dev_driver_string(&pf->pdev->dev), dev_name(&pf->pdev->dev)); err = i40e_vsi_request_irq(vsi, int_name); -- cgit v1.2.1 From aebfc8169aa78a3a69f4681c47d4a506c72d430e Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Thu, 11 Dec 2014 07:06:38 +0000 Subject: i40e: don't give up on DCB error after reset We don't need to give up in the reset/rebuild process if the DCB setup failed, so handle it here the same as in the probe setup. Also adjust the log strings a little to look less scary. Change-ID: I57308d703047e61d3f1a5e471ea77be232444ca0 Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index cd34d9bd3b56..fd6411eb48ee 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4533,7 +4533,8 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) "DCBX offload is supported for this PF.\n"); } } else { - dev_info(&pf->pdev->dev, "AQ Querying DCB configuration failed: %d\n", + dev_info(&pf->pdev->dev, + "AQ Querying DCB configuration failed: aq_err %d\n", pf->hw.aq.asq_last_status); } @@ -6188,8 +6189,9 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) #ifdef CONFIG_I40E_DCB ret = i40e_init_pf_dcb(pf); if (ret) { - dev_info(&pf->pdev->dev, "init_pf_dcb failed: %d\n", ret); - goto end_core_reset; + dev_info(&pf->pdev->dev, "DCB init failed %d, disabled\n", ret); + pf->flags &= ~I40E_FLAG_DCB_CAPABLE; + /* Continue without DCB enabled */ } #endif /* CONFIG_I40E_DCB */ #ifdef I40E_FCOE @@ -9269,7 +9271,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef CONFIG_I40E_DCB err = i40e_init_pf_dcb(pf); if (err) { - dev_info(&pdev->dev, "init_pf_dcb failed: %d\n", err); + dev_info(&pdev->dev, "DCB init failed %d, disabled\n", err); pf->flags &= ~I40E_FLAG_DCB_CAPABLE; /* Continue without DCB enabled */ } -- cgit v1.2.1 From b294ac70fcfa6b76defd9c2e3f2b28947a8a8d76 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Thu, 11 Dec 2014 07:06:39 +0000 Subject: i40e: Add define for interrupt name string len This patch creates a define for interrupt name string configuration that is large enough to contain full bus/slot info, rather than just netdev->name. Change-ID: Iaac0d23dfb8526defeed69d91cea85ed4a50ddb2 Signed-off-by: Carolyn Wyborny Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 5 +++-- drivers/net/ethernet/intel/i40e/i40e_main.c | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index fc50f6461b13..fadf8fa3cb75 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -92,6 +92,7 @@ #define I40E_MAX_USER_PRIORITY 8 #define I40E_DEFAULT_MSG_ENABLE 4 #define I40E_QUEUE_WAIT_RETRY_LIMIT 10 +#define I40E_INT_NAME_STR_LEN (IFNAMSIZ + 9) #define I40E_NVM_VERSION_LO_SHIFT 0 #define I40E_NVM_VERSION_LO_MASK (0xff << I40E_NVM_VERSION_LO_SHIFT) @@ -268,7 +269,7 @@ struct i40e_pf { u16 rx_itr_default; u16 tx_itr_default; u16 msg_enable; - char misc_int_name[IFNAMSIZ + 9]; + char int_name[I40E_INT_NAME_STR_LEN]; u16 adminq_work_limit; /* num of admin receive queue desc to process */ unsigned long service_timer_period; unsigned long service_timer_previous; @@ -524,7 +525,7 @@ struct i40e_q_vector { cpumask_t affinity_mask; struct rcu_head rcu; /* to avoid race with update stats on free */ - char name[IFNAMSIZ + 9]; + char name[I40E_INT_NAME_STR_LEN]; } ____cacheline_internodealigned_in_smp; /* lan device */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index fd6411eb48ee..4d1fe5689537 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3402,10 +3402,10 @@ static int i40e_vsi_request_irq(struct i40e_vsi *vsi, char *basename) err = i40e_vsi_request_irq_msix(vsi, basename); else if (pf->flags & I40E_FLAG_MSI_ENABLED) err = request_irq(pf->pdev->irq, i40e_intr, 0, - pf->misc_int_name, pf); + pf->int_name, pf); else err = request_irq(pf->pdev->irq, i40e_intr, IRQF_SHARED, - pf->misc_int_name, pf); + pf->int_name, pf); if (err) dev_info(&pf->pdev->dev, "request_irq failed, Error %d\n", err); @@ -4846,7 +4846,7 @@ static int i40e_open(struct net_device *netdev) int i40e_vsi_open(struct i40e_vsi *vsi) { struct i40e_pf *pf = vsi->back; - char int_name[IFNAMSIZ + 9]; + char int_name[I40E_INT_NAME_STR_LEN]; int err; /* allocate descriptors */ @@ -7128,11 +7128,11 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf) */ if (!test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) { err = request_irq(pf->msix_entries[0].vector, - i40e_intr, 0, pf->misc_int_name, pf); + i40e_intr, 0, pf->int_name, pf); if (err) { dev_info(&pf->pdev->dev, "request_irq for %s failed: %d\n", - pf->misc_int_name, err); + pf->int_name, err); return -EFAULT; } } @@ -9179,7 +9179,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->aq.asq_buf_size = I40E_MAX_AQ_BUF_SIZE; pf->adminq_work_limit = I40E_AQ_WORK_LIMIT; - snprintf(pf->misc_int_name, sizeof(pf->misc_int_name) - 1, + snprintf(pf->int_name, sizeof(pf->int_name) - 1, "%s-%s:misc", dev_driver_string(&pf->pdev->dev), dev_name(&pdev->dev)); -- cgit v1.2.1 From d67079e539f4437b13e9cf52242c9861872ee7c2 Mon Sep 17 00:00:00 2001 From: Sravanthi Tangeda Date: Thu, 11 Dec 2014 07:06:40 +0000 Subject: i40e: Dump Stats string removed from debugfs help command Dump Stats string has been removed from functional debugfs help message. Now it does not show up when we echo command to debugfs/Fortville queue. Change-ID: I9333473826b574f1afa6ddb785fd7adfbdcb2884 Signed-off-by: Sravanthi Tangeda Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index cb0de455683e..61236f983971 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1890,7 +1890,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp, dev_info(&pf->pdev->dev, " dump desc tx []\n"); dev_info(&pf->pdev->dev, " dump desc rx []\n"); dev_info(&pf->pdev->dev, " dump desc aq\n"); - dev_info(&pf->pdev->dev, " dump stats\n"); dev_info(&pf->pdev->dev, " dump reset stats\n"); dev_info(&pf->pdev->dev, " msg_enable [level]\n"); dev_info(&pf->pdev->dev, " read \n"); -- cgit v1.2.1 From 65b206d24e52d539e2e0f96e2f5cf3404bf9ce26 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Thu, 11 Dec 2014 07:06:41 +0000 Subject: i40e/i40evf: Bump i40e/i40evf versions Bump i40e to 1.2.5 and i40evf to 1.0.7. Change-ID: I622556829056e3ed42d3b9d285fc5ffb693b21cc Signed-off-by: Catherine Sullivan Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 4d1fe5689537..c3a353dd524e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 1 #define DRV_VERSION_MINOR 2 -#define DRV_VERSION_BUILD 2 +#define DRV_VERSION_BUILD 5 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 21ccbe8b6d13..a4920328438d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710/X710 Virtual Function Network Driver"; -#define DRV_VERSION "1.0.6" +#define DRV_VERSION "1.0.7" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; -- cgit v1.2.1 From ab437b5a0fd4534c68933671a2a44c5ca0e75479 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sun, 14 Dec 2014 01:55:08 +0000 Subject: i40e: only enable PTP interrupt cause if PTP is enabled We should not blindly enable the PTP interrupt flags for all PFs. We should only enable the PTP interrupt in PFs which have enabled PTP. Change-ID: I051a17cae4c199a2f3cf7852266e27eda6630525 Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c3a353dd524e..0cc02665a8e3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2819,8 +2819,9 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi) * i40e_enable_misc_int_causes - enable the non-queue interrupts * @hw: ptr to the hardware info **/ -static void i40e_enable_misc_int_causes(struct i40e_hw *hw) +static void i40e_enable_misc_int_causes(struct i40e_pf *pf) { + struct i40e_hw *hw = &pf->hw; u32 val; /* clear things first */ @@ -2832,11 +2833,13 @@ static void i40e_enable_misc_int_causes(struct i40e_hw *hw) I40E_PFINT_ICR0_ENA_GRST_MASK | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK | I40E_PFINT_ICR0_ENA_GPIO_MASK | - I40E_PFINT_ICR0_ENA_TIMESYNC_MASK | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | I40E_PFINT_ICR0_ENA_VFLR_MASK | I40E_PFINT_ICR0_ENA_ADMINQ_MASK; + if (pf->flags & I40E_FLAG_PTP) + val |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; + wr32(hw, I40E_PFINT_ICR0_ENA, val); /* SW_ITR_IDX = 0, but don't change INTENA */ @@ -2866,7 +2869,7 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi) q_vector->tx.latency_range = I40E_LOW_LATENCY; wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.itr); - i40e_enable_misc_int_causes(hw); + i40e_enable_misc_int_causes(pf); /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ wr32(hw, I40E_PFINT_LNKLST0, 0); @@ -7137,7 +7140,7 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf) } } - i40e_enable_misc_int_causes(hw); + i40e_enable_misc_int_causes(pf); /* associate no queues to the misc vector */ wr32(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_END_OF_LIST); -- cgit v1.2.1 From 22b4777da2b34e3e4e886c6eec866a9e43852357 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sun, 14 Dec 2014 01:55:09 +0000 Subject: i40e: check I40E_FLAG_PTP before handling Tx or Rx timestamps We should not be doing Tx or Rx timestamps if we do not have PTP enabled. Add checks to ensure that we don't attempt to handle any PTP related timestamping code if we have not enabled PTP on that PF. Change-ID: I4335942ae2d5c5f91abfdbeeea02bcace49e7677 Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 9 ++++++++- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 6d1ec926aa37..a15287845570 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -305,6 +305,13 @@ void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) u32 hi, lo; u64 ns; + if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx) + return; + + /* don't attempt to timestamp if we don't have an skb */ + if (!pf->ptp_tx_skb) + return; + lo = rd32(hw, I40E_PRTTSYN_TXTIME_L); hi = rd32(hw, I40E_PRTTSYN_TXTIME_H); @@ -338,7 +345,7 @@ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) /* Since we cannot turn off the Rx timestamp logic if the device is * doing Tx timestamping, check if Rx timestamping is configured. */ - if (!pf->ptp_rx) + if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) return; hw = &pf->hw; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index bb86390a0967..420d66274d69 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1939,6 +1939,9 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, * we are not already transmitting a packet to be timestamped */ pf = i40e_netdev_to_pf(tx_ring->netdev); + if (!(pf->flags & I40E_FLAG_PTP)) + return 0; + if (pf->ptp_tx && !test_and_set_bit_lock(__I40E_PTP_TX_IN_PROGRESS, &pf->state)) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; -- cgit v1.2.1 From b686ece59ba824e87b850e6348b37013a220ec60 Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Sun, 14 Dec 2014 01:55:11 +0000 Subject: i40e: Issue "Stop LLDP" command for firmware older than v4.3 Disable firmware LLDP agent for NICs with firmware version lower than v4.3. Added a message when driver disables the firmware LLDP agent on such NICs. Change-ID: Ia8abf89439c70cb50e23db82753d7d282265506b Signed-off-by: Neerav Parikh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 0cc02665a8e3..d7efc1cd0732 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -9245,6 +9245,16 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_configure_lan_hmc; } + /* Disable LLDP for NICs that have firmware versions lower than v4.3. + * Ignore error return codes because if it was already disabled via + * hardware settings this will fail + */ + if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || + (pf->hw.aq.fw_maj_ver < 4)) { + dev_info(&pdev->dev, "Stopping firmware LLDP agent.\n"); + i40e_aq_stop_lldp(hw, true, NULL); + } + i40e_get_mac_addr(hw, hw->mac.addr); if (!is_valid_ether_addr(hw->mac.addr)) { dev_info(&pdev->dev, "invalid MAC address %pM\n", hw->mac.addr); -- cgit v1.2.1 From 8d5e33ad726a020db685ad473dd7db3877d9f07e Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Sun, 14 Dec 2014 01:55:12 +0000 Subject: i40e: add more struct size checks Add struct size checks to many of the indirect structs and a few command structs that were left out previously. Change-ID: I7810b9af0f04e3ced670639f8671daf7df9b3f4d Signed-off-by: Shannon Nelson Acked-by: Greg Rose Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 43 ++++++++++++++++++++++ .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 43 ++++++++++++++++++++++ 2 files changed, 86 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 490dfcf61ea0..20cada5c9084 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -456,6 +456,8 @@ struct i40e_aqc_arp_proxy_data { u8 mac_addr[6]; }; +I40E_CHECK_STRUCT_LEN(0x14, i40e_aqc_arp_proxy_data); + /* Set NS Proxy Table Entry Command (indirect 0x0105) */ struct i40e_aqc_ns_proxy_data { __le16 table_idx_mac_addr_0; @@ -481,6 +483,8 @@ struct i40e_aqc_ns_proxy_data { u8 ipv6_addr_1[16]; }; +I40E_CHECK_STRUCT_LEN(0x3c, i40e_aqc_ns_proxy_data); + /* Manage LAA Command (0x0106) - obsolete */ struct i40e_aqc_mng_laa { __le16 command_flags; @@ -491,6 +495,8 @@ struct i40e_aqc_mng_laa { u8 reserved2[6]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_mng_laa); + /* Manage MAC Address Read Command (indirect 0x0107) */ struct i40e_aqc_mac_address_read { __le16 command_flags; @@ -562,6 +568,8 @@ struct i40e_aqc_get_switch_config_header_resp { u8 reserved[12]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_config_header_resp); + struct i40e_aqc_switch_config_element_resp { u8 element_type; #define I40E_AQ_SW_ELEM_TYPE_MAC 1 @@ -587,6 +595,8 @@ struct i40e_aqc_switch_config_element_resp { __le16 element_info; }; +I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_config_element_resp); + /* Get Switch Configuration (indirect 0x0200) * an array of elements are returned in the response buffer * the first in the array is the header, remainder are elements @@ -596,6 +606,8 @@ struct i40e_aqc_get_switch_config_resp { struct i40e_aqc_switch_config_element_resp element[1]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_switch_config_resp); + /* Add Statistics (direct 0x0201) * Remove Statistics (direct 0x0202) */ @@ -661,6 +673,8 @@ struct i40e_aqc_switch_resource_alloc_element_resp { u8 reserved2[6]; }; +I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp); + /* Add VSI (indirect 0x0210) * this indirect command uses struct i40e_aqc_vsi_properties_data * as the indirect buffer (128 bytes) @@ -1092,6 +1106,8 @@ struct i40e_aqc_remove_tag { u8 reserved[12]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_tag); + /* Add multicast E-Tag (direct 0x0257) * del multicast E-Tag (direct 0x0258) only uses pv_seid and etag fields * and no external data @@ -1359,6 +1375,8 @@ struct i40e_aqc_configure_vsi_ets_sla_bw_data { u8 reserved1[28]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_configure_vsi_ets_sla_bw_data); + /* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407) * responds with i40e_aqc_qs_handles_resp */ @@ -1370,6 +1388,8 @@ struct i40e_aqc_configure_vsi_tc_bw_data { __le16 qs_handles[8]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_vsi_tc_bw_data); + /* Query vsi bw configuration (indirect 0x0408) */ struct i40e_aqc_query_vsi_bw_config_resp { u8 tc_valid_bits; @@ -1383,6 +1403,8 @@ struct i40e_aqc_query_vsi_bw_config_resp { u8 reserved3[23]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_vsi_bw_config_resp); + /* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */ struct i40e_aqc_query_vsi_ets_sla_config_resp { u8 tc_valid_bits; @@ -1394,6 +1416,8 @@ struct i40e_aqc_query_vsi_ets_sla_config_resp { __le16 tc_bw_max[2]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_vsi_ets_sla_config_resp); + /* Configure Switching Component Bandwidth Limit (direct 0x0410) */ struct i40e_aqc_configure_switching_comp_bw_limit { __le16 seid; @@ -1421,6 +1445,8 @@ struct i40e_aqc_configure_switching_comp_ets_data { u8 reserved2[96]; }; +I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_configure_switching_comp_ets_data); + /* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */ struct i40e_aqc_configure_switching_comp_ets_bw_limit_data { u8 tc_valid_bits; @@ -1432,6 +1458,9 @@ struct i40e_aqc_configure_switching_comp_ets_bw_limit_data { u8 reserved1[28]; }; +I40E_CHECK_STRUCT_LEN(0x40, + i40e_aqc_configure_switching_comp_ets_bw_limit_data); + /* Configure Switching Component Bandwidth Allocation per Tc * (indirect 0x0417) */ @@ -1443,6 +1472,8 @@ struct i40e_aqc_configure_switching_comp_bw_config_data { u8 reserved1[20]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_switching_comp_bw_config_data); + /* Query Switching Component Configuration (indirect 0x0418) */ struct i40e_aqc_query_switching_comp_ets_config_resp { u8 tc_valid_bits; @@ -1453,6 +1484,8 @@ struct i40e_aqc_query_switching_comp_ets_config_resp { u8 reserved2[23]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_switching_comp_ets_config_resp); + /* Query PhysicalPort ETS Configuration (indirect 0x0419) */ struct i40e_aqc_query_port_ets_config_resp { u8 reserved[4]; @@ -1468,6 +1501,8 @@ struct i40e_aqc_query_port_ets_config_resp { u8 reserved3[32]; }; +I40E_CHECK_STRUCT_LEN(0x44, i40e_aqc_query_port_ets_config_resp); + /* Query Switching Component Bandwidth Allocation per Traffic Type * (indirect 0x041A) */ @@ -1482,6 +1517,8 @@ struct i40e_aqc_query_switching_comp_bw_config_resp { __le16 tc_bw_max[2]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_switching_comp_bw_config_resp); + /* Suspend/resume port TX traffic * (direct 0x041B and 0x041C) uses the generic SEID struct */ @@ -1495,6 +1532,8 @@ struct i40e_aqc_configure_partition_bw_data { u8 max_bw[16]; /* bandwidth limit */ }; +I40E_CHECK_STRUCT_LEN(0x22, i40e_aqc_configure_partition_bw_data); + /* Get and set the active HMC resource profile and status. * (direct 0x0500) and (direct 0x0501) */ @@ -1577,6 +1616,8 @@ struct i40e_aqc_module_desc { u8 reserved2[8]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_module_desc); + struct i40e_aq_get_phy_abilities_resp { __le32 phy_type; /* bitmap using the above enum for offsets */ u8 link_speed; /* bitmap using the above enum bit patterns */ @@ -1605,6 +1646,8 @@ struct i40e_aq_get_phy_abilities_resp { struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS]; }; +I40E_CHECK_STRUCT_LEN(0x218, i40e_aq_get_phy_abilities_resp); + /* Set PHY Config (direct 0x0601) */ struct i40e_aq_set_phy_config { /* same bits as above in all */ __le32 phy_type; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index a20b2b0d5d8c..1b80846d6e10 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -456,6 +456,8 @@ struct i40e_aqc_arp_proxy_data { u8 mac_addr[6]; }; +I40E_CHECK_STRUCT_LEN(0x14, i40e_aqc_arp_proxy_data); + /* Set NS Proxy Table Entry Command (indirect 0x0105) */ struct i40e_aqc_ns_proxy_data { __le16 table_idx_mac_addr_0; @@ -481,6 +483,8 @@ struct i40e_aqc_ns_proxy_data { u8 ipv6_addr_1[16]; }; +I40E_CHECK_STRUCT_LEN(0x3c, i40e_aqc_ns_proxy_data); + /* Manage LAA Command (0x0106) - obsolete */ struct i40e_aqc_mng_laa { __le16 command_flags; @@ -491,6 +495,8 @@ struct i40e_aqc_mng_laa { u8 reserved2[6]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_mng_laa); + /* Manage MAC Address Read Command (indirect 0x0107) */ struct i40e_aqc_mac_address_read { __le16 command_flags; @@ -562,6 +568,8 @@ struct i40e_aqc_get_switch_config_header_resp { u8 reserved[12]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_config_header_resp); + struct i40e_aqc_switch_config_element_resp { u8 element_type; #define I40E_AQ_SW_ELEM_TYPE_MAC 1 @@ -587,6 +595,8 @@ struct i40e_aqc_switch_config_element_resp { __le16 element_info; }; +I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_config_element_resp); + /* Get Switch Configuration (indirect 0x0200) * an array of elements are returned in the response buffer * the first in the array is the header, remainder are elements @@ -596,6 +606,8 @@ struct i40e_aqc_get_switch_config_resp { struct i40e_aqc_switch_config_element_resp element[1]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_switch_config_resp); + /* Add Statistics (direct 0x0201) * Remove Statistics (direct 0x0202) */ @@ -661,6 +673,8 @@ struct i40e_aqc_switch_resource_alloc_element_resp { u8 reserved2[6]; }; +I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp); + /* Add VSI (indirect 0x0210) * this indirect command uses struct i40e_aqc_vsi_properties_data * as the indirect buffer (128 bytes) @@ -1092,6 +1106,8 @@ struct i40e_aqc_remove_tag { u8 reserved[12]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_tag); + /* Add multicast E-Tag (direct 0x0257) * del multicast E-Tag (direct 0x0258) only uses pv_seid and etag fields * and no external data @@ -1359,6 +1375,8 @@ struct i40e_aqc_configure_vsi_ets_sla_bw_data { u8 reserved1[28]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_configure_vsi_ets_sla_bw_data); + /* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407) * responds with i40e_aqc_qs_handles_resp */ @@ -1370,6 +1388,8 @@ struct i40e_aqc_configure_vsi_tc_bw_data { __le16 qs_handles[8]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_vsi_tc_bw_data); + /* Query vsi bw configuration (indirect 0x0408) */ struct i40e_aqc_query_vsi_bw_config_resp { u8 tc_valid_bits; @@ -1383,6 +1403,8 @@ struct i40e_aqc_query_vsi_bw_config_resp { u8 reserved3[23]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_vsi_bw_config_resp); + /* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */ struct i40e_aqc_query_vsi_ets_sla_config_resp { u8 tc_valid_bits; @@ -1394,6 +1416,8 @@ struct i40e_aqc_query_vsi_ets_sla_config_resp { __le16 tc_bw_max[2]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_vsi_ets_sla_config_resp); + /* Configure Switching Component Bandwidth Limit (direct 0x0410) */ struct i40e_aqc_configure_switching_comp_bw_limit { __le16 seid; @@ -1421,6 +1445,8 @@ struct i40e_aqc_configure_switching_comp_ets_data { u8 reserved2[96]; }; +I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_configure_switching_comp_ets_data); + /* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */ struct i40e_aqc_configure_switching_comp_ets_bw_limit_data { u8 tc_valid_bits; @@ -1432,6 +1458,9 @@ struct i40e_aqc_configure_switching_comp_ets_bw_limit_data { u8 reserved1[28]; }; +I40E_CHECK_STRUCT_LEN(0x40, + i40e_aqc_configure_switching_comp_ets_bw_limit_data); + /* Configure Switching Component Bandwidth Allocation per Tc * (indirect 0x0417) */ @@ -1443,6 +1472,8 @@ struct i40e_aqc_configure_switching_comp_bw_config_data { u8 reserved1[20]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_switching_comp_bw_config_data); + /* Query Switching Component Configuration (indirect 0x0418) */ struct i40e_aqc_query_switching_comp_ets_config_resp { u8 tc_valid_bits; @@ -1453,6 +1484,8 @@ struct i40e_aqc_query_switching_comp_ets_config_resp { u8 reserved2[23]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_switching_comp_ets_config_resp); + /* Query PhysicalPort ETS Configuration (indirect 0x0419) */ struct i40e_aqc_query_port_ets_config_resp { u8 reserved[4]; @@ -1468,6 +1501,8 @@ struct i40e_aqc_query_port_ets_config_resp { u8 reserved3[32]; }; +I40E_CHECK_STRUCT_LEN(0x44, i40e_aqc_query_port_ets_config_resp); + /* Query Switching Component Bandwidth Allocation per Traffic Type * (indirect 0x041A) */ @@ -1482,6 +1517,8 @@ struct i40e_aqc_query_switching_comp_bw_config_resp { __le16 tc_bw_max[2]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_switching_comp_bw_config_resp); + /* Suspend/resume port TX traffic * (direct 0x041B and 0x041C) uses the generic SEID struct */ @@ -1495,6 +1532,8 @@ struct i40e_aqc_configure_partition_bw_data { u8 max_bw[16]; /* bandwidth limit */ }; +I40E_CHECK_STRUCT_LEN(0x22, i40e_aqc_configure_partition_bw_data); + /* Get and set the active HMC resource profile and status. * (direct 0x0500) and (direct 0x0501) */ @@ -1577,6 +1616,8 @@ struct i40e_aqc_module_desc { u8 reserved2[8]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_module_desc); + struct i40e_aq_get_phy_abilities_resp { __le32 phy_type; /* bitmap using the above enum for offsets */ u8 link_speed; /* bitmap using the above enum bit patterns */ @@ -1605,6 +1646,8 @@ struct i40e_aq_get_phy_abilities_resp { struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS]; }; +I40E_CHECK_STRUCT_LEN(0x218, i40e_aq_get_phy_abilities_resp); + /* Set PHY Config (direct 0x0601) */ struct i40e_aq_set_phy_config { /* same bits as above in all */ __le32 phy_type; -- cgit v1.2.1 From e910ca7cfce026f433d90bc1815ab804ff967d93 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 16 Jan 2015 05:02:52 -0800 Subject: i40e: AQ API updates Fix up NVM config read and write data structs. Signed-off-by: Shannon Nelson Signed-off-by: Kamil Krawczyk Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 10 +++++----- drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 20cada5c9084..70b8e5558a9b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -1831,12 +1831,12 @@ I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update); /* NVM Config Read (indirect 0x0704) */ struct i40e_aqc_nvm_config_read { __le16 cmd_flags; -#define ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1 -#define ANVM_READ_SINGLE_FEATURE 0 -#define ANVM_READ_MULTIPLE_FEATURES 1 +#define I40E_AQ_ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1 +#define I40E_AQ_ANVM_READ_SINGLE_FEATURE 0 +#define I40E_AQ_ANVM_READ_MULTIPLE_FEATURES 1 __le16 element_count; - __le16 element_id; /* Feature/field ID */ - u8 reserved[2]; + __le16 element_id; /* Feature/field ID */ + __le16 element_id_msw; /* MSWord of field ID */ __le32 address_high; __le32 address_low; }; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index 1b80846d6e10..5363cbf38eb8 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -1831,12 +1831,12 @@ I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update); /* NVM Config Read (indirect 0x0704) */ struct i40e_aqc_nvm_config_read { __le16 cmd_flags; -#define ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1 -#define ANVM_READ_SINGLE_FEATURE 0 -#define ANVM_READ_MULTIPLE_FEATURES 1 +#define I40E_AQ_ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1 +#define I40E_AQ_ANVM_READ_SINGLE_FEATURE 0 +#define I40E_AQ_ANVM_READ_MULTIPLE_FEATURES 1 __le16 element_count; - __le16 element_id; /* Feature/field ID */ - u8 reserved[2]; + __le16 element_id; /* Feature/field ID */ + __le16 element_id_msw; /* MSWord of field ID */ __le32 address_high; __le32 address_low; }; -- cgit v1.2.1 From 672415c5f024affb9fd560484c073ce8ee450001 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Sun, 14 Dec 2014 01:55:13 +0000 Subject: i40e: AQ API updates for new commands Add lldp control commands, add oem ocsd and ocbb commands. Change-ID: I89eba2bd02013d0a44e1ce900559c54bb15f4a66 Signed-off-by: Shannon Nelson Signed-off-by: Kamil Krawczyk Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 90 ++++++++++++++++++++-- .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 46 +++++++++-- 2 files changed, 126 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 70b8e5558a9b..929e3d72a01e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -256,6 +256,8 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_lldp_stop = 0x0A05, i40e_aqc_opc_lldp_start = 0x0A06, i40e_aqc_opc_get_cee_dcb_cfg = 0x0A07, + i40e_aqc_opc_lldp_set_local_mib = 0x0A08, + i40e_aqc_opc_lldp_stop_start_spec_agent = 0x0A09, /* Tunnel commands */ i40e_aqc_opc_add_udp_tunnel = 0x0B00, @@ -268,6 +270,8 @@ enum i40e_admin_queue_opc { /* OEM commands */ i40e_aqc_opc_oem_parameter_change = 0xFE00, i40e_aqc_opc_oem_device_status_change = 0xFE01, + i40e_aqc_opc_oem_ocsd_initialize = 0xFE02, + i40e_aqc_opc_oem_ocbb_initialize = 0xFE03, /* debug commands */ i40e_aqc_opc_debug_get_deviceid = 0xFF00, @@ -454,6 +458,7 @@ struct i40e_aqc_arp_proxy_data { __le32 pfpm_proxyfc; __le32 ip_addr; u8 mac_addr[6]; + u8 reserved[2]; }; I40E_CHECK_STRUCT_LEN(0x14, i40e_aqc_arp_proxy_data); @@ -1854,21 +1859,32 @@ struct i40e_aqc_nvm_config_write { I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_write); +/* Used for 0x0704 as well as for 0x0705 commands */ +#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT 1 +#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_MASK \ + (1 << I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT) +#define I40E_AQ_ANVM_FEATURE 0 +#define I40E_AQ_ANVM_IMMEDIATE_FIELD (1 << FEATURE_OR_IMMEDIATE_SHIFT) struct i40e_aqc_nvm_config_data_feature { __le16 feature_id; - __le16 instance_id; +#define I40E_AQ_ANVM_FEATURE_OPTION_OEM_ONLY 0x01 +#define I40E_AQ_ANVM_FEATURE_OPTION_DWORD_MAP 0x08 +#define I40E_AQ_ANVM_FEATURE_OPTION_POR_CSR 0x10 __le16 feature_options; __le16 feature_selection; }; +I40E_CHECK_STRUCT_LEN(0x6, i40e_aqc_nvm_config_data_feature); + struct i40e_aqc_nvm_config_data_immediate_field { -#define ANVM_FEATURE_OR_IMMEDIATE_MASK 0x2 - __le16 field_id; - __le16 instance_id; + __le32 field_id; + __le32 field_value; __le16 field_options; - __le16 field_value; + __le16 reserved; }; +I40E_CHECK_STRUCT_LEN(0xc, i40e_aqc_nvm_config_data_immediate_field); + /* Send to PF command (indirect 0x0801) id is only used by PF * Send to VF command (indirect 0x0802) id is only used by PF * Send to Peer PF command (indirect 0x0803) @@ -2069,12 +2085,54 @@ struct i40e_aqc_get_cee_dcb_cfg_resp { u8 oper_tc_bw[8]; u8 oper_pfc_en; __le16 oper_app_prio; +#define I40E_AQC_CEE_APP_FCOE_SHIFT 0x0 +#define I40E_AQC_CEE_APP_FCOE_MASK (0x7 << I40E_AQC_CEE_APP_FCOE_SHIFT) +#define I40E_AQC_CEE_APP_ISCSI_SHIFT 0x3 +#define I40E_AQC_CEE_APP_ISCSI_MASK (0x7 << I40E_AQC_CEE_APP_ISCSI_SHIFT) +#define I40E_AQC_CEE_APP_FIP_SHIFT 0x8 +#define I40E_AQC_CEE_APP_FIP_MASK (0x7 << I40E_AQC_CEE_APP_FIP_SHIFT) +#define I40E_AQC_CEE_APP_FIP_MASK (0x7 << I40E_AQC_CEE_APP_FIP_SHIFT) __le32 tlv_status; +#define I40E_AQC_CEE_PG_STATUS_SHIFT 0x0 +#define I40E_AQC_CEE_PG_STATUS_MASK (0x7 << I40E_AQC_CEE_PG_STATUS_SHIFT) +#define I40E_AQC_CEE_PFC_STATUS_SHIFT 0x3 +#define I40E_AQC_CEE_PFC_STATUS_MASK (0x7 << I40E_AQC_CEE_PFC_STATUS_SHIFT) +#define I40E_AQC_CEE_APP_STATUS_SHIFT 0x8 +#define I40E_AQC_CEE_APP_STATUS_MASK (0x7 << I40E_AQC_CEE_APP_STATUS_SHIFT) u8 reserved[12]; }; I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_cee_dcb_cfg_resp); +/* Set Local LLDP MIB (indirect 0x0A08) + * Used to replace the local MIB of a given LLDP agent. e.g. DCBx + */ +struct i40e_aqc_lldp_set_local_mib { +#define SET_LOCAL_MIB_AC_TYPE_DCBX_SHIFT 0 +#define SET_LOCAL_MIB_AC_TYPE_DCBX_MASK (1 << SET_LOCAL_MIB_AC_TYPE_DCBX_SHIFT) + u8 type; + u8 reserved0; + __le16 length; + u8 reserved1[4]; + __le32 address_high; + __le32 address_low; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_set_local_mib); + +/* Stop/Start LLDP Agent (direct 0x0A09) + * Used for stopping/starting specific LLDP agent. e.g. DCBx + */ +struct i40e_aqc_lldp_stop_start_specific_agent { +#define I40E_AQC_START_SPECIFIC_AGENT_SHIFT 0 +#define I40E_AQC_START_SPECIFIC_AGENT_MASK \ + (1 << I40E_AQC_START_SPECIFIC_AGENT_SHIFT) + u8 command; + u8 reserved[15]; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_stop_start_specific_agent); + /* Add Udp Tunnel command and completion (direct 0x0B00) */ struct i40e_aqc_add_udp_tunnel { __le16 udp_port; @@ -2164,6 +2222,28 @@ struct i40e_aqc_oem_state_change { I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change); +/* Initialize OCSD (0xFE02, direct) */ +struct i40e_aqc_opc_oem_ocsd_initialize { + u8 type_status; + u8 reserved1[3]; + __le32 ocsd_memory_block_addr_high; + __le32 ocsd_memory_block_addr_low; + __le32 requested_update_interval; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocsd_initialize); + +/* Initialize OCBB (0xFE03, direct) */ +struct i40e_aqc_opc_oem_ocbb_initialize { + u8 type_status; + u8 reserved1[3]; + __le32 ocbb_memory_block_addr_high; + __le32 ocbb_memory_block_addr_low; + u8 reserved2[4]; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocbb_initialize); + /* debug commands */ /* get device id (0xFF00) uses the generic structure */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index 5363cbf38eb8..e715bccfb5d2 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -268,6 +268,8 @@ enum i40e_admin_queue_opc { /* OEM commands */ i40e_aqc_opc_oem_parameter_change = 0xFE00, i40e_aqc_opc_oem_device_status_change = 0xFE01, + i40e_aqc_opc_oem_ocsd_initialize = 0xFE02, + i40e_aqc_opc_oem_ocbb_initialize = 0xFE03, /* debug commands */ i40e_aqc_opc_debug_get_deviceid = 0xFF00, @@ -454,6 +456,7 @@ struct i40e_aqc_arp_proxy_data { __le32 pfpm_proxyfc; __le32 ip_addr; u8 mac_addr[6]; + u8 reserved[2]; }; I40E_CHECK_STRUCT_LEN(0x14, i40e_aqc_arp_proxy_data); @@ -1854,21 +1857,32 @@ struct i40e_aqc_nvm_config_write { I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_write); +/* Used for 0x0704 as well as for 0x0705 commands */ +#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT 1 +#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_MASK \ + (1 << I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT) +#define I40E_AQ_ANVM_FEATURE 0 +#define I40E_AQ_ANVM_IMMEDIATE_FIELD (1 << FEATURE_OR_IMMEDIATE_SHIFT) struct i40e_aqc_nvm_config_data_feature { __le16 feature_id; - __le16 instance_id; +#define I40E_AQ_ANVM_FEATURE_OPTION_OEM_ONLY 0x01 +#define I40E_AQ_ANVM_FEATURE_OPTION_DWORD_MAP 0x08 +#define I40E_AQ_ANVM_FEATURE_OPTION_POR_CSR 0x10 __le16 feature_options; __le16 feature_selection; }; +I40E_CHECK_STRUCT_LEN(0x6, i40e_aqc_nvm_config_data_feature); + struct i40e_aqc_nvm_config_data_immediate_field { -#define ANVM_FEATURE_OR_IMMEDIATE_MASK 0x2 - __le16 field_id; - __le16 instance_id; + __le32 field_id; + __le32 field_value; __le16 field_options; - __le16 field_value; + __le16 reserved; }; +I40E_CHECK_STRUCT_LEN(0xc, i40e_aqc_nvm_config_data_immediate_field); + /* Send to PF command (indirect 0x0801) id is only used by PF * Send to VF command (indirect 0x0802) id is only used by PF * Send to Peer PF command (indirect 0x0803) @@ -2140,6 +2154,28 @@ struct i40e_aqc_oem_state_change { I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change); +/* Initialize OCSD (0xFE02, direct) */ +struct i40e_aqc_opc_oem_ocsd_initialize { + u8 type_status; + u8 reserved1[3]; + __le32 ocsd_memory_block_addr_high; + __le32 ocsd_memory_block_addr_low; + __le32 requested_update_interval; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocsd_initialize); + +/* Initialize OCBB (0xFE03, direct) */ +struct i40e_aqc_opc_oem_ocbb_initialize { + u8 type_status; + u8 reserved1[3]; + __le32 ocbb_memory_block_addr_high; + __le32 ocbb_memory_block_addr_low; + u8 reserved2[4]; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocbb_initialize); + /* debug commands */ /* get device id (0xFF00) uses the generic structure */ -- cgit v1.2.1 From b535a0131958332815eb6c71f633e8c24a19dd86 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sun, 14 Dec 2014 01:55:14 +0000 Subject: i40e: use same check for Rx hang as for Rx timestamps It's possible that the user configured only Tx hardware timestamping, and thus we might be receiving PTP traffic which we timestamp but which software never reads. In this case we don't want to check for Rx timestamp hang, because we already know that software won't be handling them. Thus, we add the same check against pf->ptp_rx as we have in the Rx timestamp code path. Change-ID: I66486c8dba307facbff8eace4e52e2f083789d1b Signed-off-by: Jacob Keller Acked-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index a15287845570..9f756b42d514 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -247,7 +247,12 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi) u32 prttsyn_stat; int n; - if (!(pf->flags & I40E_FLAG_PTP)) + /* Since we cannot turn off the Rx timestamp logic if the device is + * configured for Tx timestamping, we check if Rx timestamping is + * configured. We don't want to spuriously warn about Rx timestamp + * hangs if we don't care about the timestamps. + */ + if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) return; prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); -- cgit v1.2.1 From 4fda14ca0f9debd8e5e7ef699a8bf07427d092ba Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sun, 14 Dec 2014 01:55:15 +0000 Subject: i40e: when Rx timestamps disabled set specific mode Instead of leaving the Rx timestamps in the same mode as before if we disable the Rx logic, we can set it into a mode that has the fewest possible timestamps generated. To do this, select only V1 mode, but do not enable UDP packet recognition. This should eliminate all (or at least almost all) Rx timestamps, since V1 packets are always over UDP. Change-ID: If847288e0030a716e059c4c33ab114f2cf038f05 Signed-off-by: Jacob Keller Acked-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 9f756b42d514..fabcfa1b45b2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -479,7 +479,12 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE: pf->ptp_rx = false; - tsyntype = 0; + /* We set the type to V1, but do not enable UDP packet + * recognition. In this way, we should be as close to + * disabling PTP Rx timestamps as possible since V1 packets + * are always UDP, since L2 packets are a V2 feature. + */ + tsyntype = I40E_PRTTSYN_CTL1_TSYNTYPE_V1; break; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: @@ -533,17 +538,18 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, regval &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; wr32(hw, I40E_PFINT_ICR0_ENA, regval); - /* There is no simple on/off switch for Rx. To "disable" Rx support, - * ignore any received timestamps, rather than turn off the clock. + /* Although there is no simple on/off switch for Rx, we "disable" Rx + * timestamps by setting to V1 only mode and clear the UDP + * recognition. This ought to disable all PTP Rx timestamps as V1 + * packets are always over UDP. Note that software is configured to + * ignore Rx timestamps via the pf->ptp_rx flag. */ - if (pf->ptp_rx) { - regval = rd32(hw, I40E_PRTTSYN_CTL1); - /* clear everything but the enable bit */ - regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK; - /* now enable bits for desired Rx timestamps */ - regval |= tsyntype; - wr32(hw, I40E_PRTTSYN_CTL1, regval); - } + regval = rd32(hw, I40E_PRTTSYN_CTL1); + /* clear everything but the enable bit */ + regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK; + /* now enable bits for desired Rx timestamps */ + regval |= tsyntype; + wr32(hw, I40E_PRTTSYN_CTL1, regval); return 0; } -- cgit v1.2.1 From 63d7e5a413d8419d1223ba963107c79ded6a4b70 Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Sun, 14 Dec 2014 01:55:16 +0000 Subject: i40e: Support for NPAR iSCSI partition with DCB Add parsing and reporting of iSCSI capability for a given device or function. Also add support for iSCSI partition type with DCB in NPAR mode. In this mode it is expected that software would configure both the LAN and iSCSI traffic classes for the iSCSI partition; whereas all the NIC type partitions will use LAN TC (TC0) only. Hence, the patch enables querying of DCB configuration in MFP mode and configures TCs for iSCSI partition type. Though NIC type partitions may not have more than 1 TC enabled for them the port may have multiple TCs enabled and hence I40E_FLAG_DCB_ENABLED will be set/reset on all the partitions based on number of TCs on the port. This is required as in DCB environment it is expected that all traffic will be priority tagged. Change-ID: I8c6e1cfd46c46d8a39c57d9020d9ff8d42ed8a7d Signed-off-by: Neerav Parikh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 5 ++ drivers/net/ethernet/intel/i40e/i40e_main.c | 73 ++++++++++++++++++++------- drivers/net/ethernet/intel/i40e/i40e_type.h | 1 + drivers/net/ethernet/intel/i40evf/i40e_type.h | 1 + 4 files changed, 62 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 4f4d9d16bddb..5669bfa39f14 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -2360,6 +2360,7 @@ i40e_aq_erase_nvm_exit: #define I40E_DEV_FUNC_CAP_VSI 0x17 #define I40E_DEV_FUNC_CAP_DCB 0x18 #define I40E_DEV_FUNC_CAP_FCOE 0x21 +#define I40E_DEV_FUNC_CAP_ISCSI 0x22 #define I40E_DEV_FUNC_CAP_RSS 0x40 #define I40E_DEV_FUNC_CAP_RX_QUEUES 0x41 #define I40E_DEV_FUNC_CAP_TX_QUEUES 0x42 @@ -2459,6 +2460,10 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, if (number == 1) p->fcoe = true; break; + case I40E_DEV_FUNC_CAP_ISCSI: + if (number == 1) + p->iscsi = true; + break; case I40E_DEV_FUNC_CAP_RSS: p->rss = true; p->rss_table_size = number; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d7efc1cd0732..f1256f96944d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4001,6 +4001,35 @@ static int i40e_pf_wait_txq_disabled(struct i40e_pf *pf) } #endif +/** + * i40e_get_iscsi_tc_map - Return TC map for iSCSI APP + * @pf: pointer to pf + * + * Get TC map for ISCSI PF type that will include iSCSI TC + * and LAN TC. + **/ +static u8 i40e_get_iscsi_tc_map(struct i40e_pf *pf) +{ + struct i40e_dcb_app_priority_table app; + struct i40e_hw *hw = &pf->hw; + u8 enabled_tc = 1; /* TC0 is always enabled */ + u8 tc, i; + /* Get the iSCSI APP TLV */ + struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config; + + for (i = 0; i < dcbcfg->numapps; i++) { + app = dcbcfg->app[i]; + if (app.selector == I40E_APP_SEL_TCPIP && + app.protocolid == I40E_APP_PROTOID_ISCSI) { + tc = dcbcfg->etscfg.prioritytable[app.priority]; + enabled_tc |= (1 << tc); + break; + } + } + + return enabled_tc; +} + /** * i40e_dcb_get_num_tc - Get the number of TCs from DCBx config * @dcbcfg: the corresponding DCBx configuration structure @@ -4064,18 +4093,23 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf) if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) return 1; + /* SFP mode will be enabled for all TCs on port */ + if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) + return i40e_dcb_get_num_tc(dcbcfg); + /* MFP mode return count of enabled TCs for this PF */ - if (pf->flags & I40E_FLAG_MFP_ENABLED) { + if (pf->hw.func_caps.iscsi) + enabled_tc = i40e_get_iscsi_tc_map(pf); + else enabled_tc = pf->hw.func_caps.enabled_tcmap; - for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) - num_tc++; - } - return num_tc; - } - /* SFP mode will be enabled for all TCs on port */ - return i40e_dcb_get_num_tc(dcbcfg); + /* At least have TC0 */ + enabled_tc = (enabled_tc ? enabled_tc : 0x1); + for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { + if (enabled_tc & (1 << i)) + num_tc++; + } + return num_tc; } /** @@ -4113,12 +4147,15 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf) if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) return i40e_pf_get_default_tc(pf); - /* MFP mode will have enabled TCs set by FW */ - if (pf->flags & I40E_FLAG_MFP_ENABLED) - return pf->hw.func_caps.enabled_tcmap; - /* SFP mode we want PF to be enabled for all TCs */ - return i40e_dcb_get_enabled_tc(&pf->hw.local_dcbx_config); + if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) + return i40e_dcb_get_enabled_tc(&pf->hw.local_dcbx_config); + + /* MPF enabled and iSCSI PF type */ + if (pf->hw.func_caps.iscsi) + return i40e_get_iscsi_tc_map(pf); + else + return pf->hw.func_caps.enabled_tcmap; } /** @@ -4508,9 +4545,6 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) struct i40e_hw *hw = &pf->hw; int err = 0; - if (pf->hw.func_caps.npar_enable) - goto out; - /* Get the initial DCB configuration */ err = i40e_init_dcb(hw); if (!err) { @@ -7784,7 +7818,8 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) enabled_tc = i40e_pf_get_tc_map(pf); /* MFP mode setup queue map and update VSI */ - if (pf->flags & I40E_FLAG_MFP_ENABLED) { + if ((pf->flags & I40E_FLAG_MFP_ENABLED) && + !(pf->hw.func_caps.iscsi)) { /* NIC type PF */ memset(&ctxt, 0, sizeof(ctxt)); ctxt.seid = pf->main_vsi_seid; ctxt.pf_num = pf->hw.pf_id; @@ -7805,6 +7840,8 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) /* Default/Main VSI is only enabled for TC0 * reconfigure it to enable all TCs that are * available on the port in SFP mode. + * For MFP case the iSCSI PF would use this + * flow to enable LAN+iSCSI TC. */ ret = i40e_vsi_config_tc(vsi, enabled_tc); if (ret) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index ff121fe98dd4..e9901ef06a63 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -211,6 +211,7 @@ struct i40e_hw_capabilities { bool evb_802_1_qbh; /* Bridge Port Extension */ bool dcb; bool fcoe; + bool iscsi; /* Indicates iSCSI enabled */ bool mfp_mode_1; bool mgmt_cem; bool ieee_1588; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index d1c2b5a6e648..3d0fdaab5cc8 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -211,6 +211,7 @@ struct i40e_hw_capabilities { bool evb_802_1_qbh; /* Bridge Port Extension */ bool dcb; bool fcoe; + bool iscsi; /* Indicates iSCSI enabled */ bool mfp_mode_1; bool mgmt_cem; bool ieee_1588; -- cgit v1.2.1 From 300c34c13edf9c4d6d643e2b92860a6d9d0d0498 Mon Sep 17 00:00:00 2001 From: Sravanthi Tangeda Date: Sun, 14 Dec 2014 01:55:17 +0000 Subject: i40e/i40evf: Bump i40e and i40evf versions Bump i40e to 1.2.6 and i40evf to 1.2.0 version. Change-ID: Ice127eee3a5a5d1b8765d83cff8c30f9f3b1bc32 Signed-off-by: Sravanthi Tangeda Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index f1256f96944d..e774a23901f9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 1 #define DRV_VERSION_MINOR 2 -#define DRV_VERSION_BUILD 5 +#define DRV_VERSION_BUILD 6 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index a4920328438d..f946aac1df71 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710/X710 Virtual Function Network Driver"; -#define DRV_VERSION "1.0.7" +#define DRV_VERSION "1.2.0" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; -- cgit v1.2.1 From 1d67d7f6e925af985345e2a93ddc6aeaec3bc354 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:46:24 -0600 Subject: amd-xgbe: Checkpatch fixes This set of patches resolves some checks reported by the checkpatch tool. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c | 2 +- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 2 +- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c index 76479d04b903..2c063b60db4b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c @@ -328,7 +328,7 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata) buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name); pdata->xgbe_debugfs = debugfs_create_dir(buf, NULL); - if (pdata->xgbe_debugfs == NULL) { + if (!pdata->xgbe_debugfs) { netdev_err(pdata->netdev, "debugfs_create_dir failed\n"); return; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 2ba1dd22ad64..e2e921768185 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -692,7 +692,7 @@ static void xgbe_adjust_link(struct net_device *netdev) struct phy_device *phydev = pdata->phydev; int new_state = 0; - if (phydev == NULL) + if (!phydev) return; if (phydev->link) { diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 363b210560f3..7eeb03d271e2 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -220,7 +220,7 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) } mii = mdiobus_alloc(); - if (mii == NULL) { + if (!mii) { dev_err(pdata->dev, "mdiobus_alloc failed\n"); ret = -ENOMEM; goto err_node_get; -- cgit v1.2.1 From cb69cb07685c11e8bc346fcda017e847f1658c88 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:46:29 -0600 Subject: amd-xgbe-phy: Checkpatch fixes This set of patches resolves some checks reported by the checkpatch tool. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/phy/amd-xgbe-phy.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 903dc3dc9ea7..b65a0a8f921d 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -74,6 +74,7 @@ #include #include #include +#include MODULE_AUTHOR("Tom Lendacky "); MODULE_LICENSE("Dual BSD/GPL"); @@ -90,9 +91,9 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define XGBE_AN_PG_RCV 0x04 #define XNP_MCF_NULL_MESSAGE 0x001 -#define XNP_ACK_PROCESSED (1 << 12) -#define XNP_MP_FORMATTED (1 << 13) -#define XNP_NP_EXCHANGE (1 << 15) +#define XNP_ACK_PROCESSED BIT(12) +#define XNP_MP_FORMATTED BIT(13) +#define XNP_NP_EXCHANGE BIT(15) #define XGBE_PHY_RATECHANGE_COUNT 500 -- cgit v1.2.1 From 94c043e53324478ed8ba33757dd7bc03298c83c7 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:46:34 -0600 Subject: amd-xgbe: Add check to be sure amd-xgbe-phy driver is used The amd-xgbe driver relies on the amd-xgbe-phy phylib driver. Add a check to be sure that if any errors occur during probing of the amd-xgbe-phy driver then the amd-xgbe driver returns an error. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 7eeb03d271e2..41e29e2a65b0 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -260,10 +260,14 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) of_node_put(phy_node); goto err_phy_device; } + if (!phydev->dev.driver) { + dev_err(pdata->dev, "phy driver probe failed\n"); + ret = -EIO; + goto err_phy_device; + } /* Add a reference to the PHY driver so it can't be unloaded */ - pdata->phy_module = phydev->dev.driver ? - phydev->dev.driver->owner : NULL; + pdata->phy_module = phydev->dev.driver->owner; if (!try_module_get(pdata->phy_module)) { dev_err(pdata->dev, "try_module_get failed\n"); ret = -EIO; -- cgit v1.2.1 From 03e50fd7b18351ab4766d4d0f7d25c5b4fefa9d9 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:46:39 -0600 Subject: amd-xgbe-phy: On suspend, save CTRL1 reg for use on resume Reads to registers are undefined when the PCS is powered down. To be safe, save the CTRL1 register used for power down during suspend and restore that value during resume. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/phy/amd-xgbe-phy.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index b65a0a8f921d..5ce42e324eb7 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -350,6 +350,8 @@ struct amd_xgbe_phy_priv { struct work_struct an_work; struct workqueue_struct *an_workqueue; unsigned int parallel_detect; + + unsigned int lpm_ctrl; /* CTRL1 for resume */ }; static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev) @@ -1250,6 +1252,7 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev) static int amd_xgbe_phy_suspend(struct phy_device *phydev) { + struct amd_xgbe_phy_priv *priv = phydev->priv; int ret; mutex_lock(&phydev->lock); @@ -1258,6 +1261,8 @@ static int amd_xgbe_phy_suspend(struct phy_device *phydev) if (ret < 0) goto unlock; + priv->lpm_ctrl = ret; + ret |= MDIO_CTRL1_LPOWER; phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); @@ -1271,23 +1276,16 @@ unlock: static int amd_xgbe_phy_resume(struct phy_device *phydev) { - int ret; + struct amd_xgbe_phy_priv *priv = phydev->priv; mutex_lock(&phydev->lock); - ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); - if (ret < 0) - goto unlock; - - ret &= ~MDIO_CTRL1_LPOWER; - phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); - - ret = 0; + priv->lpm_ctrl &= ~MDIO_CTRL1_LPOWER; + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, priv->lpm_ctrl); -unlock: mutex_unlock(&phydev->lock); - return ret; + return 0; } static int amd_xgbe_phy_probe(struct phy_device *phydev) -- cgit v1.2.1 From 916102c6664dcfc11f76ab1da27882aee1d01d8c Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:46:45 -0600 Subject: amd-xgbe: Clear all state during a device restart When performing a device restart, like during an MTU change, sometimes the device queues still have data and get hung up trying to flush resulting in the device becoming unresponsive until brought down and back up. To prevent this, always perform a device reset during a restart. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 18 ++++++++++++++++++ drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 11 +++++------ drivers/net/ethernet/amd/xgbe/xgbe-main.c | 1 + 3 files changed, 24 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 53f5f66ec2ee..e424997afc55 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -2107,6 +2107,23 @@ static void xgbe_config_jumbo_enable(struct xgbe_prv_data *pdata) XGMAC_IOWRITE_BITS(pdata, MAC_RCR, JE, val); } +static void xgbe_config_mac_speed(struct xgbe_prv_data *pdata) +{ + switch (pdata->phy_speed) { + case SPEED_10000: + xgbe_set_xgmii_speed(pdata); + break; + + case SPEED_2500: + xgbe_set_gmii_2500_speed(pdata); + break; + + case SPEED_1000: + xgbe_set_gmii_speed(pdata); + break; + } +} + static void xgbe_config_checksum_offload(struct xgbe_prv_data *pdata) { if (pdata->netdev->features & NETIF_F_RXCSUM) @@ -2757,6 +2774,7 @@ static int xgbe_init(struct xgbe_prv_data *pdata) xgbe_config_mac_address(pdata); xgbe_config_jumbo_enable(pdata); xgbe_config_flow_control(pdata); + xgbe_config_mac_speed(pdata); xgbe_config_checksum_offload(pdata); xgbe_config_vlan_support(pdata); xgbe_config_mmc(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index e2e921768185..bdb373c87050 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -927,7 +927,7 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) DBGPR("<--xgbe_stop\n"); } -static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset) +static void xgbe_restart_dev(struct xgbe_prv_data *pdata) { struct xgbe_channel *channel; struct xgbe_hw_if *hw_if = &pdata->hw_if; @@ -950,9 +950,8 @@ static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset) xgbe_free_tx_data(pdata); xgbe_free_rx_data(pdata); - /* Issue software reset to device if requested */ - if (reset) - hw_if->exit(pdata); + /* Issue software reset to device */ + hw_if->exit(pdata); xgbe_start(pdata); @@ -967,7 +966,7 @@ static void xgbe_restart(struct work_struct *work) rtnl_lock(); - xgbe_restart_dev(pdata, 1); + xgbe_restart_dev(pdata); rtnl_unlock(); } @@ -1587,7 +1586,7 @@ static int xgbe_change_mtu(struct net_device *netdev, int mtu) pdata->rx_buf_size = ret; netdev->mtu = mtu; - xgbe_restart_dev(pdata, 0); + xgbe_restart_dev(pdata); DBGPR("<--xgbe_change_mtu\n"); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index dbd3850b8b0a..a50dccd67de7 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -148,6 +148,7 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata) pdata->pause_autoneg = 1; pdata->tx_pause = 1; pdata->rx_pause = 1; + pdata->phy_speed = SPEED_UNKNOWN; pdata->power_down = 0; pdata->default_autoneg = AUTONEG_ENABLE; pdata->default_speed = SPEED_10000; -- cgit v1.2.1 From 270894e7dc7afad8fb79592fe02aa05e604ddfc8 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:46:50 -0600 Subject: amd-xgbe: Simplify the Rx desciptor ring tracking Make the Rx descriptor ring processing similar to the Tx descriptor ring processing. Remove the realloc_index and realloc_threshold variables and base everything on the current index counter and the dirty index counter. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 32 +------------------------------ drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 25 ++++++++++++++++++++---- drivers/net/ethernet/amd/xgbe/xgbe.h | 11 +++-------- 3 files changed, 25 insertions(+), 43 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c index a50891f52197..d81fc6bd4759 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -422,7 +422,6 @@ static void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata) ring->cur = 0; ring->dirty = 0; - memset(&ring->rx, 0, sizeof(ring->rx)); hw_if->rx_desc_init(channel); } @@ -621,35 +620,6 @@ err_out: return 0; } -static void xgbe_realloc_rx_buffer(struct xgbe_channel *channel) -{ - struct xgbe_prv_data *pdata = channel->pdata; - struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct xgbe_ring *ring = channel->rx_ring; - struct xgbe_ring_data *rdata; - int i; - - DBGPR("-->xgbe_realloc_rx_buffer: rx_ring->rx.realloc_index = %u\n", - ring->rx.realloc_index); - - for (i = 0; i < ring->dirty; i++) { - rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index); - - /* Reset rdata values */ - xgbe_unmap_rdata(pdata, rdata); - - if (xgbe_map_rx_buffer(pdata, ring, rdata)) - break; - - hw_if->rx_desc_reset(rdata); - - ring->rx.realloc_index++; - } - ring->dirty = 0; - - DBGPR("<--xgbe_realloc_rx_buffer\n"); -} - void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if) { DBGPR("-->xgbe_init_function_ptrs_desc\n"); @@ -657,7 +627,7 @@ void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if) desc_if->alloc_ring_resources = xgbe_alloc_ring_resources; desc_if->free_ring_resources = xgbe_free_ring_resources; desc_if->map_tx_skb = xgbe_map_tx_skb; - desc_if->realloc_rx_buffer = xgbe_realloc_rx_buffer; + desc_if->map_rx_buffer = xgbe_map_rx_buffer; desc_if->unmap_rdata = xgbe_unmap_rdata; desc_if->wrapper_tx_desc_init = xgbe_wrapper_tx_descriptor_init; desc_if->wrapper_rx_desc_init = xgbe_wrapper_rx_descriptor_init; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index bdb373c87050..e2f560ff5104 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -225,6 +225,11 @@ static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring) return (ring->rdesc_count - (ring->cur - ring->dirty)); } +static inline unsigned int xgbe_rx_dirty_desc(struct xgbe_ring *ring) +{ + return (ring->cur - ring->dirty); +} + static int xgbe_maybe_stop_tx_queue(struct xgbe_channel *channel, struct xgbe_ring *ring, unsigned int count) { @@ -1775,15 +1780,28 @@ struct net_device_ops *xgbe_get_netdev_ops(void) static void xgbe_rx_refresh(struct xgbe_channel *channel) { struct xgbe_prv_data *pdata = channel->pdata; + struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_desc_if *desc_if = &pdata->desc_if; struct xgbe_ring *ring = channel->rx_ring; struct xgbe_ring_data *rdata; - desc_if->realloc_rx_buffer(channel); + while (ring->dirty != ring->cur) { + rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); + + /* Reset rdata values */ + desc_if->unmap_rdata(pdata, rdata); + + if (desc_if->map_rx_buffer(pdata, ring, rdata)) + break; + + hw_if->rx_desc_reset(rdata); + + ring->dirty++; + } /* Update the Rx Tail Pointer Register with address of * the last cleaned entry */ - rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index - 1); + rdata = XGBE_GET_DESC_DATA(ring, ring->dirty - 1); XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, lower_32_bits(rdata->rdesc_dma)); } @@ -1933,7 +1951,7 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) read_again: rdata = XGBE_GET_DESC_DATA(ring, ring->cur); - if (ring->dirty > (XGBE_RX_DESC_CNT >> 3)) + if (xgbe_rx_dirty_desc(ring) > (XGBE_RX_DESC_CNT >> 3)) xgbe_rx_refresh(channel); if (hw_if->dev_read(channel)) @@ -1941,7 +1959,6 @@ read_again: received++; ring->cur++; - ring->dirty++; incomplete = XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 2af6affc35a7..e6ee64e1d6ec 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -361,8 +361,7 @@ struct xgbe_ring { * cur - Tx: index of descriptor to be used for current transfer * Rx: index of descriptor to check for packet availability * dirty - Tx: index of descriptor to check for transfer complete - * Rx: count of descriptors in which a packet has been received - * (used with skb_realloc_index to refresh the ring) + * Rx: index of descriptor to check for buffer reallocation */ unsigned int cur; unsigned int dirty; @@ -377,11 +376,6 @@ struct xgbe_ring { unsigned short cur_mss; unsigned short cur_vlan_ctag; } tx; - - struct { - unsigned int realloc_index; - unsigned int realloc_threshold; - } rx; }; } ____cacheline_aligned; @@ -596,7 +590,8 @@ struct xgbe_desc_if { int (*alloc_ring_resources)(struct xgbe_prv_data *); void (*free_ring_resources)(struct xgbe_prv_data *); int (*map_tx_skb)(struct xgbe_channel *, struct sk_buff *); - void (*realloc_rx_buffer)(struct xgbe_channel *); + int (*map_rx_buffer)(struct xgbe_prv_data *, struct xgbe_ring *, + struct xgbe_ring_data *); void (*unmap_rdata)(struct xgbe_prv_data *, struct xgbe_ring_data *); void (*wrapper_tx_desc_init)(struct xgbe_prv_data *); void (*wrapper_rx_desc_init)(struct xgbe_prv_data *); -- cgit v1.2.1 From a83ef427b7d97314df30d6e25abc7aa3a80ffcfd Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:46:55 -0600 Subject: amd-xgbe: Remove need for Tx path spinlock Since the Tx ring cleanup can run at the same time that data is being transmitted, a spin lock was used to protect the ring. This patch eliminates the need for Tx spinlocks by updating the current ring position only after all ownership bits for data being transmitted have been set. This will insure that ring operations in the Tx cleanup path do not interfere with the ring operations in the Tx transmit path. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 17 +++++++++-------- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 21 +-------------------- 2 files changed, 10 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index e424997afc55..5dff127a0823 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1359,6 +1359,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) unsigned int tso_context, vlan_context; unsigned int tx_set_ic; int start_index = ring->cur; + int cur_index = ring->cur; int i; DBGPR("-->xgbe_dev_xmit\n"); @@ -1401,7 +1402,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) else tx_set_ic = 0; - rdata = XGBE_GET_DESC_DATA(ring, ring->cur); + rdata = XGBE_GET_DESC_DATA(ring, cur_index); rdesc = rdata->rdesc; /* Create a context descriptor if this is a TSO packet */ @@ -1444,8 +1445,8 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) ring->tx.cur_vlan_ctag = packet->vlan_ctag; } - ring->cur++; - rdata = XGBE_GET_DESC_DATA(ring, ring->cur); + cur_index++; + rdata = XGBE_GET_DESC_DATA(ring, cur_index); rdesc = rdata->rdesc; } @@ -1473,7 +1474,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT, 0); /* Set OWN bit if not the first descriptor */ - if (ring->cur != start_index) + if (cur_index != start_index) XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1); if (tso) { @@ -1497,9 +1498,9 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) packet->length); } - for (i = ring->cur - start_index + 1; i < packet->rdesc_count; i++) { - ring->cur++; - rdata = XGBE_GET_DESC_DATA(ring, ring->cur); + for (i = cur_index - start_index + 1; i < packet->rdesc_count; i++) { + cur_index++; + rdata = XGBE_GET_DESC_DATA(ring, cur_index); rdesc = rdata->rdesc; /* Update buffer address */ @@ -1551,7 +1552,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) /* Make sure ownership is written to the descriptor */ wmb(); - ring->cur++; + ring->cur = cur_index + 1; if (!packet->skb->xmit_more || netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev, channel->queue_index))) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index e2f560ff5104..c036a0e61bba 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -415,17 +415,13 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) struct xgbe_channel *channel = container_of(timer, struct xgbe_channel, tx_timer); - struct xgbe_ring *ring = channel->tx_ring; struct xgbe_prv_data *pdata = channel->pdata; struct napi_struct *napi; - unsigned long flags; DBGPR("-->xgbe_tx_timer\n"); napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi; - spin_lock_irqsave(&ring->lock, flags); - if (napi_schedule_prep(napi)) { /* Disable Tx and Rx interrupts */ if (pdata->per_channel_irq) @@ -439,8 +435,6 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) channel->tx_timer_active = 0; - spin_unlock_irqrestore(&ring->lock, flags); - DBGPR("<--xgbe_tx_timer\n"); return HRTIMER_NORESTART; @@ -1450,7 +1444,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) struct xgbe_ring *ring; struct xgbe_packet_data *packet; struct netdev_queue *txq; - unsigned long flags; int ret; DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len); @@ -1462,8 +1455,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) ret = NETDEV_TX_OK; - spin_lock_irqsave(&ring->lock, flags); - if (skb->len == 0) { netdev_err(netdev, "empty skb received from stack\n"); dev_kfree_skb_any(skb); @@ -1510,10 +1501,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) ret = NETDEV_TX_OK; tx_netdev_return: - spin_unlock_irqrestore(&ring->lock, flags); - - DBGPR("<--xgbe_xmit\n"); - return ret; } @@ -1841,7 +1828,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) struct xgbe_ring_desc *rdesc; struct net_device *netdev = pdata->netdev; struct netdev_queue *txq; - unsigned long flags; int processed = 0; unsigned int tx_packets = 0, tx_bytes = 0; @@ -1853,8 +1839,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) txq = netdev_get_tx_queue(netdev, channel->queue_index); - spin_lock_irqsave(&ring->lock, flags); - while ((processed < XGBE_TX_DESC_MAX_PROC) && (ring->dirty != ring->cur)) { rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); @@ -1885,7 +1869,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) } if (!processed) - goto unlock; + return 0; netdev_tx_completed_queue(txq, tx_packets, tx_bytes); @@ -1897,9 +1881,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) DBGPR("<--xgbe_tx_poll: processed=%d\n", processed); -unlock: - spin_unlock_irqrestore(&ring->lock, flags); - return processed; } -- cgit v1.2.1 From c3152d4728ca5f87688b1d9bf3e61de43235cbb0 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:47:00 -0600 Subject: amd-xgbe-phy: Change auto-negotiation logic The auto negotiation logic was geared to being the initiator of the auto negotiation. This presented problems when auto negotiation was initiated by the remote end. Change the auto negotiation logic to make use of the auto negotiation event interrupt thus allowing the auto negotiation state machine to function properly in either scenario. This also removes the polling during auto-negotiation. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 27 ++ drivers/net/phy/amd-xgbe-phy.c | 627 ++++++++++++++++++------------- 2 files changed, 388 insertions(+), 266 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 5dff127a0823..950ad2e02dcb 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -115,6 +115,7 @@ */ #include +#include #include #include #include @@ -673,6 +674,9 @@ static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata) static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata) { + if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x3) + return 0; + XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x3); return 0; @@ -680,6 +684,9 @@ static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata) static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata) { + if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x2) + return 0; + XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x2); return 0; @@ -687,6 +694,9 @@ static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata) static int xgbe_set_xgmii_speed(struct xgbe_prv_data *pdata) { + if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0) + return 0; + XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0); return 0; @@ -881,6 +891,23 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad, else mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff); + /* If the PCS is changing modes, match the MAC speed to it */ + if (((mmd_address >> 16) == MDIO_MMD_PCS) && + ((mmd_address & 0xffff) == MDIO_CTRL2)) { + struct phy_device *phydev = pdata->phydev; + + if (mmd_data & MDIO_PCS_CTRL2_TYPE) { + /* KX mode */ + if (phydev->supported & SUPPORTED_1000baseKX_Full) + xgbe_set_gmii_speed(pdata); + else + xgbe_set_gmii_2500_speed(pdata); + } else { + /* KR mode */ + xgbe_set_xgmii_speed(pdata); + } + } + /* The PCS registers are accessed using mmio. The underlying APB3 * management interface uses indirect addressing to access the MMD * register sets. This requires accessing of the PCS register in two diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 5ce42e324eb7..7fde5088c797 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,7 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define XGBE_AN_INT_CMPLT 0x01 #define XGBE_AN_INC_LINK 0x02 #define XGBE_AN_PG_RCV 0x04 +#define XGBE_AN_INT_MASK 0x07 #define XNP_MCF_NULL_MESSAGE 0x001 #define XNP_ACK_PROCESSED BIT(12) @@ -117,18 +119,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define MDIO_AN_INT 0x8002 #endif -#ifndef MDIO_AN_KR_CTRL -#define MDIO_AN_KR_CTRL 0x8003 -#endif - #ifndef MDIO_CTRL1_SPEED1G #define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100) #endif -#ifndef MDIO_KR_CTRL_PDETECT -#define MDIO_KR_CTRL_PDETECT 0x01 -#endif - /* SerDes integration register offsets */ #define SIR0_KR_RT_1 0x002c #define SIR0_STATUS 0x0040 @@ -294,21 +288,18 @@ do { \ enum amd_xgbe_phy_an { AMD_XGBE_AN_READY = 0, - AMD_XGBE_AN_START, - AMD_XGBE_AN_EVENT, AMD_XGBE_AN_PAGE_RECEIVED, AMD_XGBE_AN_INCOMPAT_LINK, AMD_XGBE_AN_COMPLETE, AMD_XGBE_AN_NO_LINK, - AMD_XGBE_AN_EXIT, AMD_XGBE_AN_ERROR, }; enum amd_xgbe_phy_rx { - AMD_XGBE_RX_READY = 0, - AMD_XGBE_RX_BPA, + AMD_XGBE_RX_BPA = 0, AMD_XGBE_RX_XNP, AMD_XGBE_RX_COMPLETE, + AMD_XGBE_RX_ERROR, }; enum amd_xgbe_phy_mode { @@ -337,8 +328,11 @@ struct amd_xgbe_phy_priv { void __iomem *sir0_regs; /* SerDes integration registers (1/2) */ void __iomem *sir1_regs; /* SerDes integration registers (2/2) */ - /* Maintain link status for re-starting auto-negotiation */ - unsigned int link; + int an_irq; + char an_irq_name[IFNAMSIZ + 32]; + struct work_struct an_irq_work; + unsigned int an_irq_allocated; + unsigned int speed_set; /* Auto-negotiation state machine support */ @@ -349,6 +343,7 @@ struct amd_xgbe_phy_priv { enum amd_xgbe_phy_rx kx_state; struct work_struct an_work; struct workqueue_struct *an_workqueue; + unsigned int an_supported; unsigned int parallel_detect; unsigned int lpm_ctrl; /* CTRL1 for resume */ @@ -638,6 +633,38 @@ static int amd_xgbe_phy_set_mode(struct phy_device *phydev, return ret; } +static int amd_xgbe_phy_set_an(struct phy_device *phydev, bool enable, + bool restart) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); + if (ret < 0) + return ret; + + ret &= ~MDIO_AN_CTRL1_ENABLE; + + if (enable) + ret |= MDIO_AN_CTRL1_ENABLE; + + if (restart) + ret |= MDIO_AN_CTRL1_RESTART; + + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); + + return 0; +} + +static int amd_xgbe_phy_restart_an(struct phy_device *phydev) +{ + return amd_xgbe_phy_set_an(phydev, true, true); +} + +static int amd_xgbe_phy_disable_an(struct phy_device *phydev) +{ + return amd_xgbe_phy_set_an(phydev, false, false); +} + static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, enum amd_xgbe_phy_rx *state) { @@ -648,7 +675,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, /* If we're not in KR mode then we're done */ if (!amd_xgbe_phy_in_kr_mode(phydev)) - return AMD_XGBE_AN_EVENT; + return AMD_XGBE_AN_PAGE_RECEIVED; /* Enable/Disable FEC */ ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); @@ -682,7 +709,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); - return AMD_XGBE_AN_EVENT; + return AMD_XGBE_AN_PAGE_RECEIVED; } static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, @@ -699,7 +726,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0); phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP, msg); - return AMD_XGBE_AN_EVENT; + return AMD_XGBE_AN_PAGE_RECEIVED; } static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev, @@ -751,226 +778,255 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev, amd_xgbe_an_tx_training(phydev, state); } -static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev) +static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) +{ + struct amd_xgbe_phy_priv *priv = phydev->priv; + enum amd_xgbe_phy_rx *state; + int ret; + + state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state + : &priv->kx_state; + + switch (*state) { + case AMD_XGBE_RX_BPA: + ret = amd_xgbe_an_rx_bpa(phydev, state); + break; + + case AMD_XGBE_RX_XNP: + ret = amd_xgbe_an_rx_xnp(phydev, state); + break; + + default: + ret = AMD_XGBE_AN_ERROR; + } + + return ret; +} + +static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; int ret; /* Be sure we aren't looping trying to negotiate */ if (amd_xgbe_phy_in_kr_mode(phydev)) { - if (priv->kr_state != AMD_XGBE_RX_READY) + priv->kr_state = AMD_XGBE_RX_ERROR; + + if (!(phydev->supported & SUPPORTED_1000baseKX_Full) && + !(phydev->supported & SUPPORTED_2500baseX_Full)) + return AMD_XGBE_AN_NO_LINK; + + if (priv->kx_state != AMD_XGBE_RX_BPA) return AMD_XGBE_AN_NO_LINK; - priv->kr_state = AMD_XGBE_RX_BPA; } else { - if (priv->kx_state != AMD_XGBE_RX_READY) + priv->kx_state = AMD_XGBE_RX_ERROR; + + if (!(phydev->supported & SUPPORTED_10000baseKR_Full)) + return AMD_XGBE_AN_NO_LINK; + + if (priv->kr_state != AMD_XGBE_RX_BPA) return AMD_XGBE_AN_NO_LINK; - priv->kx_state = AMD_XGBE_RX_BPA; } - /* Set up Advertisement register 3 first */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); - if (ret < 0) + ret = amd_xgbe_phy_disable_an(phydev); + if (ret) return AMD_XGBE_AN_ERROR; - if (phydev->supported & SUPPORTED_10000baseR_FEC) - ret |= 0xc000; - else - ret &= ~0xc000; - - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret); - - /* Set up Advertisement register 2 next */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); - if (ret < 0) + ret = amd_xgbe_phy_switch_mode(phydev); + if (ret) return AMD_XGBE_AN_ERROR; - if (phydev->supported & SUPPORTED_10000baseKR_Full) - ret |= 0x80; - else - ret &= ~0x80; - - if ((phydev->supported & SUPPORTED_1000baseKX_Full) || - (phydev->supported & SUPPORTED_2500baseX_Full)) - ret |= 0x20; - else - ret &= ~0x20; - - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret); - - /* Set up Advertisement register 1 last */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); - if (ret < 0) + ret = amd_xgbe_phy_restart_an(phydev); + if (ret) return AMD_XGBE_AN_ERROR; - if (phydev->supported & SUPPORTED_Pause) - ret |= 0x400; - else - ret &= ~0x400; + return AMD_XGBE_AN_INCOMPAT_LINK; +} - if (phydev->supported & SUPPORTED_Asym_Pause) - ret |= 0x800; - else - ret &= ~0x800; +static irqreturn_t amd_xgbe_an_isr(int irq, void *data) +{ + struct amd_xgbe_phy_priv *priv = (struct amd_xgbe_phy_priv *)data; - /* We don't intend to perform XNP */ - ret &= ~XNP_NP_EXCHANGE; + /* Interrupt reason must be read and cleared outside of IRQ context */ + disable_irq_nosync(priv->an_irq); - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret); + queue_work(priv->an_workqueue, &priv->an_irq_work); - /* Enable and start auto-negotiation */ - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + return IRQ_HANDLED; +} - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL); - if (ret < 0) - return AMD_XGBE_AN_ERROR; +static void amd_xgbe_an_irq_work(struct work_struct *work) +{ + struct amd_xgbe_phy_priv *priv = container_of(work, + struct amd_xgbe_phy_priv, + an_irq_work); - ret |= MDIO_KR_CTRL_PDETECT; - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL, ret); + /* Avoid a race between enabling the IRQ and exiting the work by + * waiting for the work to finish and then queueing it + */ + flush_work(&priv->an_work); + queue_work(priv->an_workqueue, &priv->an_work); +} - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); - if (ret < 0) - return AMD_XGBE_AN_ERROR; +static void amd_xgbe_an_state_machine(struct work_struct *work) +{ + struct amd_xgbe_phy_priv *priv = container_of(work, + struct amd_xgbe_phy_priv, + an_work); + struct phy_device *phydev = priv->phydev; + enum amd_xgbe_phy_an cur_state = priv->an_state; + int int_reg, int_mask; - ret |= MDIO_AN_CTRL1_ENABLE; - ret |= MDIO_AN_CTRL1_RESTART; - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); + mutex_lock(&priv->an_mutex); - return AMD_XGBE_AN_EVENT; -} + /* Read the interrupt */ + int_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT); + if (!int_reg) + goto out; -static enum amd_xgbe_phy_an amd_xgbe_an_event(struct phy_device *phydev) -{ - enum amd_xgbe_phy_an new_state; - int ret; +next_int: + if (int_reg < 0) { + priv->an_state = AMD_XGBE_AN_ERROR; + int_mask = XGBE_AN_INT_MASK; + } else if (int_reg & XGBE_AN_PG_RCV) { + priv->an_state = AMD_XGBE_AN_PAGE_RECEIVED; + int_mask = XGBE_AN_PG_RCV; + } else if (int_reg & XGBE_AN_INC_LINK) { + priv->an_state = AMD_XGBE_AN_INCOMPAT_LINK; + int_mask = XGBE_AN_INC_LINK; + } else if (int_reg & XGBE_AN_INT_CMPLT) { + priv->an_state = AMD_XGBE_AN_COMPLETE; + int_mask = XGBE_AN_INT_CMPLT; + } else { + priv->an_state = AMD_XGBE_AN_ERROR; + int_mask = 0; + } - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT); - if (ret < 0) - return AMD_XGBE_AN_ERROR; + /* Clear the interrupt to be processed */ + int_reg &= ~int_mask; + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, int_reg); - new_state = AMD_XGBE_AN_EVENT; - if (ret & XGBE_AN_PG_RCV) - new_state = AMD_XGBE_AN_PAGE_RECEIVED; - else if (ret & XGBE_AN_INC_LINK) - new_state = AMD_XGBE_AN_INCOMPAT_LINK; - else if (ret & XGBE_AN_INT_CMPLT) - new_state = AMD_XGBE_AN_COMPLETE; + priv->an_result = priv->an_state; - if (new_state != AMD_XGBE_AN_EVENT) - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); +again: + cur_state = priv->an_state; - return new_state; -} + switch (priv->an_state) { + case AMD_XGBE_AN_READY: + priv->an_supported = 0; + break; -static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) -{ - struct amd_xgbe_phy_priv *priv = phydev->priv; - enum amd_xgbe_phy_rx *state; - int ret; + case AMD_XGBE_AN_PAGE_RECEIVED: + priv->an_state = amd_xgbe_an_page_received(phydev); + priv->an_supported++; + break; - state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state - : &priv->kx_state; + case AMD_XGBE_AN_INCOMPAT_LINK: + priv->an_supported = 0; + priv->parallel_detect = 0; + priv->an_state = amd_xgbe_an_incompat_link(phydev); + break; - switch (*state) { - case AMD_XGBE_RX_BPA: - ret = amd_xgbe_an_rx_bpa(phydev, state); + case AMD_XGBE_AN_COMPLETE: + priv->parallel_detect = priv->an_supported ? 0 : 1; + netdev_dbg(phydev->attached_dev, "%s successful\n", + priv->an_supported ? "Auto negotiation" + : "Parallel detection"); break; - case AMD_XGBE_RX_XNP: - ret = amd_xgbe_an_rx_xnp(phydev, state); + case AMD_XGBE_AN_NO_LINK: break; default: - ret = AMD_XGBE_AN_ERROR; + priv->an_state = AMD_XGBE_AN_ERROR; } - return ret; -} + if (priv->an_state == AMD_XGBE_AN_NO_LINK) { + int_reg = 0; + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + } else if (priv->an_state == AMD_XGBE_AN_ERROR) { + netdev_err(phydev->attached_dev, + "error during auto-negotiation, state=%u\n", + cur_state); -static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev) -{ - int ret; + int_reg = 0; + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + } - ret = amd_xgbe_phy_switch_mode(phydev); - if (ret) - return AMD_XGBE_AN_ERROR; + if (priv->an_state >= AMD_XGBE_AN_COMPLETE) { + priv->an_result = priv->an_state; + priv->an_state = AMD_XGBE_AN_READY; + priv->kr_state = AMD_XGBE_RX_BPA; + priv->kx_state = AMD_XGBE_RX_BPA; + } - return AMD_XGBE_AN_START; -} + if (cur_state != priv->an_state) + goto again; -static void amd_xgbe_an_state_machine(struct work_struct *work) -{ - struct amd_xgbe_phy_priv *priv = container_of(work, - struct amd_xgbe_phy_priv, - an_work); - struct phy_device *phydev = priv->phydev; - enum amd_xgbe_phy_an cur_state; - int sleep; - unsigned int an_supported = 0; + if (int_reg) + goto next_int; - /* Start in KX mode */ - if (amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX)) - priv->an_state = AMD_XGBE_AN_ERROR; +out: + enable_irq(priv->an_irq); - while (1) { - mutex_lock(&priv->an_mutex); + mutex_unlock(&priv->an_mutex); +} - cur_state = priv->an_state; +static int amd_xgbe_an_init(struct phy_device *phydev) +{ + int ret; - switch (priv->an_state) { - case AMD_XGBE_AN_START: - an_supported = 0; - priv->parallel_detect = 0; - priv->an_state = amd_xgbe_an_start(phydev); - break; + /* Set up Advertisement register 3 first */ + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); + if (ret < 0) + return ret; - case AMD_XGBE_AN_EVENT: - priv->an_state = amd_xgbe_an_event(phydev); - break; + if (phydev->supported & SUPPORTED_10000baseR_FEC) + ret |= 0xc000; + else + ret &= ~0xc000; - case AMD_XGBE_AN_PAGE_RECEIVED: - priv->an_state = amd_xgbe_an_page_received(phydev); - an_supported++; - break; + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret); - case AMD_XGBE_AN_INCOMPAT_LINK: - priv->an_state = amd_xgbe_an_incompat_link(phydev); - break; + /* Set up Advertisement register 2 next */ + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); + if (ret < 0) + return ret; - case AMD_XGBE_AN_COMPLETE: - priv->parallel_detect = an_supported ? 0 : 1; - netdev_info(phydev->attached_dev, "%s successful\n", - an_supported ? "Auto negotiation" - : "Parallel detection"); - /* fall through */ + if (phydev->supported & SUPPORTED_10000baseKR_Full) + ret |= 0x80; + else + ret &= ~0x80; - case AMD_XGBE_AN_NO_LINK: - case AMD_XGBE_AN_EXIT: - goto exit_unlock; + if ((phydev->supported & SUPPORTED_1000baseKX_Full) || + (phydev->supported & SUPPORTED_2500baseX_Full)) + ret |= 0x20; + else + ret &= ~0x20; - default: - priv->an_state = AMD_XGBE_AN_ERROR; - } + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret); - if (priv->an_state == AMD_XGBE_AN_ERROR) { - netdev_err(phydev->attached_dev, - "error during auto-negotiation, state=%u\n", - cur_state); - goto exit_unlock; - } + /* Set up Advertisement register 1 last */ + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); + if (ret < 0) + return ret; - sleep = (priv->an_state == AMD_XGBE_AN_EVENT) ? 1 : 0; + if (phydev->supported & SUPPORTED_Pause) + ret |= 0x400; + else + ret &= ~0x400; - mutex_unlock(&priv->an_mutex); + if (phydev->supported & SUPPORTED_Asym_Pause) + ret |= 0x800; + else + ret &= ~0x800; - if (sleep) - usleep_range(20, 50); - } + /* We don't intend to perform XNP */ + ret &= ~XNP_NP_EXCHANGE; -exit_unlock: - priv->an_result = priv->an_state; - priv->an_state = AMD_XGBE_AN_READY; + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret); - mutex_unlock(&priv->an_mutex); + return 0; } static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) @@ -995,13 +1051,46 @@ static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) if (ret & MDIO_CTRL1_RESET) return -ETIMEDOUT; - /* Make sure the XPCS and SerDes are in compatible states */ - return amd_xgbe_phy_xgmii_mode(phydev); + /* Disable auto-negotiation for now */ + ret = amd_xgbe_phy_disable_an(phydev); + if (ret < 0) + return ret; + + /* Clear auto-negotiation interrupts */ + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + + return 0; } static int amd_xgbe_phy_config_init(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; + struct net_device *netdev = phydev->attached_dev; + int ret; + + if (!priv->an_irq_allocated) { + /* Allocate the auto-negotiation workqueue and interrupt */ + snprintf(priv->an_irq_name, sizeof(priv->an_irq_name) - 1, + "%s-pcs", netdev_name(netdev)); + + priv->an_workqueue = + create_singlethread_workqueue(priv->an_irq_name); + if (!priv->an_workqueue) { + netdev_err(netdev, "phy workqueue creation failed\n"); + return -ENOMEM; + } + + ret = devm_request_irq(priv->dev, priv->an_irq, + amd_xgbe_an_isr, 0, priv->an_irq_name, + priv); + if (ret) { + netdev_err(netdev, "phy irq request failed\n"); + destroy_workqueue(priv->an_workqueue); + return ret; + } + + priv->an_irq_allocated = 1; + } /* Initialize supported features */ phydev->supported = SUPPORTED_Autoneg; @@ -1019,9 +1108,27 @@ static int amd_xgbe_phy_config_init(struct phy_device *phydev) } phydev->advertising = phydev->supported; - /* Turn off and clear interrupts */ - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + /* Set initial mode - call the mode setting routines + * directly to insure we are properly configured + */ + if (phydev->supported & SUPPORTED_10000baseKR_Full) + ret = amd_xgbe_phy_xgmii_mode(phydev); + else if (phydev->supported & SUPPORTED_1000baseKX_Full) + ret = amd_xgbe_phy_gmii_mode(phydev); + else if (phydev->supported & SUPPORTED_2500baseX_Full) + ret = amd_xgbe_phy_gmii_2500_mode(phydev); + else + ret = -EINVAL; + if (ret < 0) + return ret; + + /* Set up advertisement registers based on current settings */ + ret = amd_xgbe_an_init(phydev); + if (ret) + return ret; + + /* Enable auto-negotiation interrupts */ + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07); return 0; } @@ -1031,25 +1138,19 @@ static int amd_xgbe_phy_setup_forced(struct phy_device *phydev) int ret; /* Disable auto-negotiation */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); + ret = amd_xgbe_phy_disable_an(phydev); if (ret < 0) return ret; - ret &= ~MDIO_AN_CTRL1_ENABLE; - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); - /* Validate/Set specified speed */ switch (phydev->speed) { case SPEED_10000: - ret = amd_xgbe_phy_xgmii_mode(phydev); + ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR); break; case SPEED_2500: - ret = amd_xgbe_phy_gmii_2500_mode(phydev); - break; - case SPEED_1000: - ret = amd_xgbe_phy_gmii_mode(phydev); + ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX); break; default: @@ -1069,10 +1170,11 @@ static int amd_xgbe_phy_setup_forced(struct phy_device *phydev) return 0; } -static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) +static int __amd_xgbe_phy_config_aneg(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; u32 mmd_mask = phydev->c45_ids.devices_in_package; + int ret; if (phydev->autoneg != AUTONEG_ENABLE) return amd_xgbe_phy_setup_forced(phydev); @@ -1081,56 +1183,79 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) if (!(mmd_mask & MDIO_DEVS_AN)) return -EINVAL; - /* Start/Restart the auto-negotiation state machine */ - mutex_lock(&priv->an_mutex); + /* Disable auto-negotiation interrupt */ + disable_irq(priv->an_irq); + + /* Start auto-negotiation in a supported mode */ + if (phydev->supported & SUPPORTED_10000baseKR_Full) + ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR); + else if ((phydev->supported & SUPPORTED_1000baseKX_Full) || + (phydev->supported & SUPPORTED_2500baseX_Full)) + ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX); + else + ret = -EINVAL; + if (ret < 0) { + enable_irq(priv->an_irq); + return ret; + } + + /* Disable and stop any in progress auto-negotiation */ + ret = amd_xgbe_phy_disable_an(phydev); + if (ret < 0) + return ret; + + /* Clear any auto-negotitation interrupts */ + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + priv->an_result = AMD_XGBE_AN_READY; - priv->an_state = AMD_XGBE_AN_START; - priv->kr_state = AMD_XGBE_RX_READY; - priv->kx_state = AMD_XGBE_RX_READY; - mutex_unlock(&priv->an_mutex); + priv->an_state = AMD_XGBE_AN_READY; + priv->kr_state = AMD_XGBE_RX_BPA; + priv->kx_state = AMD_XGBE_RX_BPA; - queue_work(priv->an_workqueue, &priv->an_work); + /* Re-enable auto-negotiation interrupt */ + enable_irq(priv->an_irq); - return 0; + /* Set up advertisement registers based on current settings */ + ret = amd_xgbe_an_init(phydev); + if (ret) + return ret; + + /* Enable and start auto-negotiation */ + return amd_xgbe_phy_restart_an(phydev); } -static int amd_xgbe_phy_aneg_done(struct phy_device *phydev) +static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; - enum amd_xgbe_phy_an state; + int ret; mutex_lock(&priv->an_mutex); - state = priv->an_result; + + ret = __amd_xgbe_phy_config_aneg(phydev); + mutex_unlock(&priv->an_mutex); - return (state == AMD_XGBE_AN_COMPLETE); + return ret; +} + +static int amd_xgbe_phy_aneg_done(struct phy_device *phydev) +{ + struct amd_xgbe_phy_priv *priv = phydev->priv; + + return (priv->an_result == AMD_XGBE_AN_COMPLETE); } static int amd_xgbe_phy_update_link(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; - enum amd_xgbe_phy_an state; - unsigned int check_again, autoneg; int ret; /* If we're doing auto-negotiation don't report link down */ - mutex_lock(&priv->an_mutex); - state = priv->an_state; - mutex_unlock(&priv->an_mutex); - - if (state != AMD_XGBE_AN_READY) { + if (priv->an_state != AMD_XGBE_AN_READY) { phydev->link = 1; return 0; } - /* Since the device can be in the wrong mode when a link is - * (re-)established (cable connected after the interface is - * up, etc.), the link status may report no link. If there - * is no link, try switching modes and checking the status - * again if auto negotiation is enabled. - */ - check_again = (phydev->autoneg == AUTONEG_ENABLE) ? 1 : 0; -again: /* Link status is latched low, so read once to clear * and then read again to get current state */ @@ -1144,25 +1269,6 @@ again: phydev->link = (ret & MDIO_STAT1_LSTATUS) ? 1 : 0; - if (!phydev->link) { - if (check_again) { - ret = amd_xgbe_phy_switch_mode(phydev); - if (ret < 0) - return ret; - check_again = 0; - goto again; - } - } - - autoneg = (phydev->link && !priv->link) ? 1 : 0; - priv->link = phydev->link; - if (autoneg) { - /* Link is (back) up, re-start auto-negotiation */ - ret = amd_xgbe_phy_config_aneg(phydev); - if (ret < 0) - return ret; - } - return 0; } @@ -1293,7 +1399,6 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) struct amd_xgbe_phy_priv *priv; struct platform_device *pdev; struct device *dev; - char *wq_name; const __be32 *property; unsigned int speed_set; int ret; @@ -1306,21 +1411,18 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) return -EINVAL; dev = &pdev->dev; - wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", phydev->bus->name); - if (!wq_name) { - ret = -ENOMEM; - goto err_pdev; - } - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; - goto err_name; + goto err_pdev; } priv->pdev = pdev; priv->dev = dev; priv->phydev = phydev; + mutex_init(&priv->an_mutex); + INIT_WORK(&priv->an_irq_work, amd_xgbe_an_irq_work); + INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); /* Get the device mmio areas */ priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1347,6 +1449,14 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) goto err_sir0; } + /* Get the auto-negotiation interrupt */ + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "platform_get_irq failed\n"); + goto err_sir1; + } + priv->an_irq = ret; + /* Get the device speed set property */ speed_set = 0; property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY, @@ -1367,19 +1477,8 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) goto err_sir1; } - priv->link = 1; - - mutex_init(&priv->an_mutex); - INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); - priv->an_workqueue = create_singlethread_workqueue(wq_name); - if (!priv->an_workqueue) { - ret = -ENOMEM; - goto err_sir1; - } - phydev->priv = priv; - kfree(wq_name); of_dev_put(pdev); return 0; @@ -1402,9 +1501,6 @@ err_rxtx: err_priv: devm_kfree(dev, priv); -err_name: - kfree(wq_name); - err_pdev: of_dev_put(pdev); @@ -1416,13 +1512,12 @@ static void amd_xgbe_phy_remove(struct phy_device *phydev) struct amd_xgbe_phy_priv *priv = phydev->priv; struct device *dev = priv->dev; - /* Stop any in process auto-negotiation */ - mutex_lock(&priv->an_mutex); - priv->an_state = AMD_XGBE_AN_EXIT; - mutex_unlock(&priv->an_mutex); + if (priv->an_irq_allocated) { + devm_free_irq(dev, priv->an_irq, priv); - flush_workqueue(priv->an_workqueue); - destroy_workqueue(priv->an_workqueue); + flush_workqueue(priv->an_workqueue); + destroy_workqueue(priv->an_workqueue); + } /* Release resources */ devm_iounmap(dev, priv->sir1_regs); -- cgit v1.2.1 From cf262527e53d45ba8957ca26e99c6a55fbb21477 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:47:05 -0600 Subject: amd-xgbe-phy: Properly support the FEC auto-negotiation Advertise and apply the Forward Error Correction capabilities of the device based on the FEC ability of the device. Also, remove the use of some hard coded values related to KR and FEC in preference of some #defines. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/phy/amd-xgbe-phy.c | 44 +++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 7fde5088c797..7207f361fa02 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -99,10 +99,21 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define XGBE_PHY_RATECHANGE_COUNT 500 +#define XGBE_PHY_KR_TRAINING_START 0x01 +#define XGBE_PHY_KR_TRAINING_ENABLE 0x02 + +#define XGBE_PHY_FEC_ENABLE 0x01 +#define XGBE_PHY_FEC_FORWARD 0x02 +#define XGBE_PHY_FEC_MASK 0x03 + #ifndef MDIO_PMA_10GBR_PMD_CTRL #define MDIO_PMA_10GBR_PMD_CTRL 0x0096 #endif +#ifndef MDIO_PMA_10GBR_FEC_ABILITY +#define MDIO_PMA_10GBR_FEC_ABILITY 0x00aa +#endif + #ifndef MDIO_PMA_10GBR_FEC_CTRL #define MDIO_PMA_10GBR_FEC_CTRL 0x00ab #endif @@ -345,6 +356,7 @@ struct amd_xgbe_phy_priv { struct workqueue_struct *an_workqueue; unsigned int an_supported; unsigned int parallel_detect; + unsigned int fec_ability; unsigned int lpm_ctrl; /* CTRL1 for resume */ }; @@ -357,7 +369,7 @@ static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev) if (ret < 0) return ret; - ret |= 0x02; + ret |= XGBE_PHY_KR_TRAINING_ENABLE; phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); return 0; @@ -371,7 +383,7 @@ static int amd_xgbe_an_disable_kr_training(struct phy_device *phydev) if (ret < 0) return ret; - ret &= ~0x02; + ret &= ~XGBE_PHY_KR_TRAINING_ENABLE; phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); return 0; @@ -690,10 +702,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, if (ret < 0) return AMD_XGBE_AN_ERROR; + ret &= ~XGBE_PHY_FEC_MASK; if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) - ret |= 0x01; - else - ret &= ~0x01; + ret |= priv->fec_ability; phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret); @@ -702,12 +713,15 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, if (ret < 0) return AMD_XGBE_AN_ERROR; - XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1); + if (ret & XGBE_PHY_KR_TRAINING_ENABLE) { + XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1); - ret |= 0x01; - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); + ret |= XGBE_PHY_KR_TRAINING_START; + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, + ret); - XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); + XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); + } return AMD_XGBE_AN_PAGE_RECEIVED; } @@ -1092,12 +1106,16 @@ static int amd_xgbe_phy_config_init(struct phy_device *phydev) priv->an_irq_allocated = 1; } + ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_ABILITY); + if (ret < 0) + return ret; + priv->fec_ability = ret & XGBE_PHY_FEC_MASK; + /* Initialize supported features */ phydev->supported = SUPPORTED_Autoneg; phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; phydev->supported |= SUPPORTED_Backplane; - phydev->supported |= SUPPORTED_10000baseKR_Full | - SUPPORTED_10000baseR_FEC; + phydev->supported |= SUPPORTED_10000baseKR_Full; switch (priv->speed_set) { case AMD_XGBE_PHY_SPEEDSET_1000_10000: phydev->supported |= SUPPORTED_1000baseKX_Full; @@ -1106,6 +1124,10 @@ static int amd_xgbe_phy_config_init(struct phy_device *phydev) phydev->supported |= SUPPORTED_2500baseX_Full; break; } + + if (priv->fec_ability & XGBE_PHY_FEC_ENABLE) + phydev->supported |= SUPPORTED_10000baseR_FEC; + phydev->advertising = phydev->supported; /* Set initial mode - call the mode setting routines -- cgit v1.2.1 From 0d40b6101fe41a14ebd871adefa2a7b844b1d309 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:47:10 -0600 Subject: amd-xgbe-phy: Use the proper auto-negotiation XNP registers When receiving and processing extended next pages the base registers were used instead of the XNP registers. Update the code to use the device XNP and link partner XNP registers. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/phy/amd-xgbe-phy.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 7207f361fa02..e2074c75891c 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -122,6 +122,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define MDIO_AN_XNP 0x0016 #endif +#ifndef MDIO_AN_LPX +#define MDIO_AN_LPX 0x0019 +#endif + #ifndef MDIO_AN_INTMASK #define MDIO_AN_INTMASK 0x8001 #endif @@ -779,11 +783,11 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev, int ad_reg, lp_reg; /* Check Extended Next Page support */ - ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); + ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP); if (ad_reg < 0) return AMD_XGBE_AN_ERROR; - lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA); + lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPX); if (lp_reg < 0) return AMD_XGBE_AN_ERROR; -- cgit v1.2.1 From 82a19035d000c8b4fd7d6f61b614f63dec75d389 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:47:16 -0600 Subject: amd-xgbe: Add ACPI support Add support for ACPI to the amd-xgbe and amd-xgbe-phy drivers. This support converts many of the device tree APIs to the new device_property APIs. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/Kconfig | 2 +- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 4 +- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 202 +++++++++++++++++++++++------- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 19 +-- drivers/net/ethernet/amd/xgbe/xgbe-ptp.c | 4 +- drivers/net/ethernet/amd/xgbe/xgbe.h | 18 ++- drivers/net/phy/Kconfig | 2 +- drivers/net/phy/amd-xgbe-phy.c | 128 +++++++++++++------ 8 files changed, 273 insertions(+), 106 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 7a5e4aa5415e..5d3b5202327c 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -179,7 +179,7 @@ config SUNLANCE config AMD_XGBE tristate "AMD 10GbE Ethernet driver" - depends on OF_NET && HAS_IOMEM + depends on (OF_NET || ACPI) && HAS_IOMEM select PHYLIB select AMD_XGBE_PHY select BITREVERSE diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 950ad2e02dcb..da593c42d183 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -131,7 +131,7 @@ static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata, DBGPR("-->xgbe_usec_to_riwt\n"); - rate = clk_get_rate(pdata->sysclk); + rate = pdata->sysclk_rate; /* * Convert the input usec value to the watchdog timer value. Each @@ -154,7 +154,7 @@ static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata, DBGPR("-->xgbe_riwt_to_usec\n"); - rate = clk_get_rate(pdata->sysclk); + rate = pdata->sysclk_rate; /* * Convert the input watchdog timer value to the usec value. Each diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index a50dccd67de7..32dd65137051 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -123,7 +123,10 @@ #include #include #include +#include #include +#include +#include #include "xgbe.h" #include "xgbe-common.h" @@ -162,6 +165,96 @@ static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata) xgbe_init_function_ptrs_desc(&pdata->desc_if); } +#ifdef CONFIG_ACPI +static int xgbe_acpi_support(struct xgbe_prv_data *pdata) +{ + struct acpi_device *adev = pdata->adev; + struct device *dev = pdata->dev; + u32 property; + acpi_handle handle; + acpi_status status; + unsigned long long data; + int cca; + int ret; + + /* Obtain the system clock setting */ + ret = device_property_read_u32(dev, XGBE_ACPI_DMA_FREQ, &property); + if (ret) { + dev_err(dev, "unable to obtain %s property\n", + XGBE_ACPI_DMA_FREQ); + return ret; + } + pdata->sysclk_rate = property; + + /* Obtain the PTP clock setting */ + ret = device_property_read_u32(dev, XGBE_ACPI_PTP_FREQ, &property); + if (ret) { + dev_err(dev, "unable to obtain %s property\n", + XGBE_ACPI_PTP_FREQ); + return ret; + } + pdata->ptpclk_rate = property; + + /* Retrieve the device cache coherency value */ + handle = adev->handle; + do { + status = acpi_evaluate_integer(handle, "_CCA", NULL, &data); + if (!ACPI_FAILURE(status)) { + cca = data; + break; + } + + status = acpi_get_parent(handle, &handle); + } while (!ACPI_FAILURE(status)); + + if (ACPI_FAILURE(status)) { + dev_err(dev, "error obtaining acpi coherency value\n"); + return -EINVAL; + } + pdata->coherent = !!cca; + + return 0; +} +#else /* CONFIG_ACPI */ +static int xgbe_acpi_support(struct xgbe_prv_data *pdata) +{ + return -EINVAL; +} +#endif /* CONFIG_ACPI */ + +#ifdef CONFIG_OF +static int xgbe_of_support(struct xgbe_prv_data *pdata) +{ + struct device *dev = pdata->dev; + + /* Obtain the system clock setting */ + pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); + if (IS_ERR(pdata->sysclk)) { + dev_err(dev, "dma devm_clk_get failed\n"); + return PTR_ERR(pdata->sysclk); + } + pdata->sysclk_rate = clk_get_rate(pdata->sysclk); + + /* Obtain the PTP clock setting */ + pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); + if (IS_ERR(pdata->ptpclk)) { + dev_err(dev, "ptp devm_clk_get failed\n"); + return PTR_ERR(pdata->ptpclk); + } + pdata->ptpclk_rate = clk_get_rate(pdata->ptpclk); + + /* Retrieve the device cache coherency value */ + pdata->coherent = of_dma_is_coherent(dev->of_node); + + return 0; +} +#else /* CONFIG_OF */ +static int xgbe_of_support(struct xgbe_prv_data *pdata) +{ + return -EINVAL; +} +#endif /*CONFIG_OF */ + static int xgbe_probe(struct platform_device *pdev) { struct xgbe_prv_data *pdata; @@ -170,7 +263,7 @@ static int xgbe_probe(struct platform_device *pdev) struct net_device *netdev; struct device *dev = &pdev->dev; struct resource *res; - const u8 *mac_addr; + const char *phy_mode; unsigned int i; int ret; @@ -187,6 +280,7 @@ static int xgbe_probe(struct platform_device *pdev) pdata = netdev_priv(netdev); pdata->netdev = netdev; pdata->pdev = pdev; + pdata->adev = ACPI_COMPANION(dev); pdata->dev = dev; platform_set_drvdata(pdev, netdev); @@ -195,6 +289,9 @@ static int xgbe_probe(struct platform_device *pdev) mutex_init(&pdata->rss_mutex); spin_lock_init(&pdata->tstamp_lock); + /* Check if we should use ACPI or DT */ + pdata->use_acpi = (!pdata->adev || acpi_disabled) ? 0 : 1; + /* Set and validate the number of descriptors for a ring */ BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT); pdata->tx_desc_count = XGBE_TX_DESC_CNT; @@ -213,22 +310,6 @@ static int xgbe_probe(struct platform_device *pdev) goto err_io; } - /* Obtain the system clock setting */ - pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); - if (IS_ERR(pdata->sysclk)) { - dev_err(dev, "dma devm_clk_get failed\n"); - ret = PTR_ERR(pdata->sysclk); - goto err_io; - } - - /* Obtain the PTP clock setting */ - pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); - if (IS_ERR(pdata->ptpclk)) { - dev_err(dev, "ptp devm_clk_get failed\n"); - ret = PTR_ERR(pdata->ptpclk); - goto err_io; - } - /* Obtain the mmio areas for the device */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pdata->xgmac_regs = devm_ioremap_resource(dev, res); @@ -248,16 +329,42 @@ static int xgbe_probe(struct platform_device *pdev) } DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs); - /* Set the DMA mask */ - if (!dev->dma_mask) - dev->dma_mask = &dev->coherent_dma_mask; - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); - if (ret) { - dev_err(dev, "dma_set_mask_and_coherent failed\n"); + /* Retrieve the MAC address */ + ret = device_property_read_u8_array(dev, XGBE_MAC_ADDR_PROPERTY, + pdata->mac_addr, + sizeof(pdata->mac_addr)); + if (ret || !is_valid_ether_addr(pdata->mac_addr)) { + dev_err(dev, "invalid %s property\n", XGBE_MAC_ADDR_PROPERTY); + if (!ret) + ret = -EINVAL; goto err_io; } - if (of_property_read_bool(dev->of_node, "dma-coherent")) { + /* Retrieve the PHY mode - it must be "xgmii" */ + ret = device_property_read_string(dev, XGBE_PHY_MODE_PROPERTY, + &phy_mode); + if (ret || strcmp(phy_mode, phy_modes(PHY_INTERFACE_MODE_XGMII))) { + dev_err(dev, "invalid %s property\n", XGBE_PHY_MODE_PROPERTY); + if (!ret) + ret = -EINVAL; + goto err_io; + } + pdata->phy_mode = PHY_INTERFACE_MODE_XGMII; + + /* Check for per channel interrupt support */ + if (device_property_present(dev, XGBE_DMA_IRQS_PROPERTY)) + pdata->per_channel_irq = 1; + + /* Obtain device settings unique to ACPI/OF */ + if (pdata->use_acpi) + ret = xgbe_acpi_support(pdata); + else + ret = xgbe_of_support(pdata); + if (ret) + goto err_io; + + /* Set the DMA coherency values */ + if (pdata->coherent) { pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; pdata->arcache = XGBE_DMA_OS_ARCACHE; pdata->awcache = XGBE_DMA_OS_AWCACHE; @@ -267,10 +374,16 @@ static int xgbe_probe(struct platform_device *pdev) pdata->awcache = XGBE_DMA_SYS_AWCACHE; } - /* Check for per channel interrupt support */ - if (of_property_read_bool(dev->of_node, XGBE_DMA_IRQS)) - pdata->per_channel_irq = 1; + /* Set the DMA mask */ + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); + if (ret) { + dev_err(dev, "dma_set_mask_and_coherent failed\n"); + goto err_io; + } + /* Get the device interrupt */ ret = platform_get_irq(pdev, 0); if (ret < 0) { dev_err(dev, "platform_get_irq 0 failed\n"); @@ -280,6 +393,7 @@ static int xgbe_probe(struct platform_device *pdev) netdev->irq = pdata->dev_irq; netdev->base_addr = (unsigned long)pdata->xgmac_regs; + memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len); /* Set all the function pointers */ xgbe_init_all_fptrs(pdata); @@ -292,23 +406,6 @@ static int xgbe_probe(struct platform_device *pdev) /* Populate the hardware features */ xgbe_get_all_hw_features(pdata); - /* Retrieve the MAC address */ - mac_addr = of_get_mac_address(dev->of_node); - if (!mac_addr) { - dev_err(dev, "invalid mac address for this device\n"); - ret = -EINVAL; - goto err_io; - } - memcpy(netdev->dev_addr, mac_addr, netdev->addr_len); - - /* Retrieve the PHY mode - it must be "xgmii" */ - pdata->phy_mode = of_get_phy_mode(dev->of_node); - if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { - dev_err(dev, "invalid phy-mode specified for this device\n"); - ret = -EINVAL; - goto err_io; - } - /* Set default configuration data */ xgbe_default_config(pdata); @@ -492,18 +589,35 @@ static int xgbe_resume(struct device *dev) } #endif /* CONFIG_PM */ +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgbe_acpi_match[] = { + { "AMDI8001", 0 }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, xgbe_acpi_match); +#endif + +#ifdef CONFIG_OF static const struct of_device_id xgbe_of_match[] = { { .compatible = "amd,xgbe-seattle-v1a", }, {}, }; MODULE_DEVICE_TABLE(of, xgbe_of_match); +#endif + static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume); static struct platform_driver xgbe_driver = { .driver = { .name = "amd-xgbe", +#ifdef CONFIG_ACPI + .acpi_match_table = xgbe_acpi_match, +#endif +#ifdef CONFIG_OF .of_match_table = xgbe_of_match, +#endif .pm = &xgbe_pm_ops, }, .probe = xgbe_probe, diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 41e29e2a65b0..59e267f3f1b7 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -205,25 +205,16 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) int xgbe_mdio_register(struct xgbe_prv_data *pdata) { - struct device_node *phy_node; struct mii_bus *mii; struct phy_device *phydev; int ret = 0; DBGPR("-->xgbe_mdio_register\n"); - /* Retrieve the phy-handle */ - phy_node = of_parse_phandle(pdata->dev->of_node, "phy-handle", 0); - if (!phy_node) { - dev_err(pdata->dev, "unable to parse phy-handle\n"); - return -EINVAL; - } - mii = mdiobus_alloc(); if (!mii) { dev_err(pdata->dev, "mdiobus_alloc failed\n"); - ret = -ENOMEM; - goto err_node_get; + return -ENOMEM; } /* Register on the MDIO bus (don't probe any PHYs) */ @@ -252,12 +243,9 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS])); - of_node_get(phy_node); - phydev->dev.of_node = phy_node; ret = phy_device_register(phydev); if (ret) { dev_err(pdata->dev, "phy_device_register failed\n"); - of_node_put(phy_node); goto err_phy_device; } if (!phydev->dev.driver) { @@ -287,8 +275,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) pdata->phydev = phydev; - of_node_put(phy_node); - DBGPHY_REGS(pdata); DBGPR("<--xgbe_mdio_register\n"); @@ -304,9 +290,6 @@ err_mdiobus_register: err_mdiobus_alloc: mdiobus_free(mii); -err_node_get: - of_node_put(phy_node); - return ret; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c index f5acf4cc69bd..f326178ef376 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c @@ -233,7 +233,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) snprintf(info->name, sizeof(info->name), "%s", netdev_name(pdata->netdev)); info->owner = THIS_MODULE; - info->max_adj = clk_get_rate(pdata->ptpclk); + info->max_adj = pdata->ptpclk_rate; info->adjfreq = xgbe_adjfreq; info->adjtime = xgbe_adjtime; info->gettime = xgbe_gettime; @@ -254,7 +254,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) */ dividend = 50000000; dividend <<= 32; - pdata->tstamp_addend = div_u64(dividend, clk_get_rate(pdata->ptpclk)); + pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate); /* Setup the timecounter */ cc->read = xgbe_cc_read; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index e6ee64e1d6ec..13e8f95c077c 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -182,10 +182,18 @@ #define XGBE_PHY_NAME "amd_xgbe_phy" #define XGBE_PRTAD 0 +/* Common property names */ +#define XGBE_MAC_ADDR_PROPERTY "mac-address" +#define XGBE_PHY_MODE_PROPERTY "phy-mode" +#define XGBE_DMA_IRQS_PROPERTY "amd,per-channel-interrupt" + /* Device-tree clock names */ #define XGBE_DMA_CLOCK "dma_clk" #define XGBE_PTP_CLOCK "ptp_clk" -#define XGBE_DMA_IRQS "amd,per-channel-interrupt" + +/* ACPI property names */ +#define XGBE_ACPI_DMA_FREQ "amd,dma-freq" +#define XGBE_ACPI_PTP_FREQ "amd,ptp-freq" /* Timestamp support - values based on 50MHz PTP clock * 50MHz => 20 nsec @@ -645,8 +653,12 @@ struct xgbe_hw_features { struct xgbe_prv_data { struct net_device *netdev; struct platform_device *pdev; + struct acpi_device *adev; struct device *dev; + /* ACPI or DT flag */ + unsigned int use_acpi; + /* XGMAC/XPCS related mmio registers */ void __iomem *xgmac_regs; /* XGMAC CSRs */ void __iomem *xpcs_regs; /* XPCS MMD registers */ @@ -667,6 +679,7 @@ struct xgbe_prv_data { struct xgbe_desc_if desc_if; /* AXI DMA settings */ + unsigned int coherent; unsigned int axdomain; unsigned int arcache; unsigned int awcache; @@ -734,6 +747,7 @@ struct xgbe_prv_data { unsigned int phy_rx_pause; /* Netdev related settings */ + unsigned char mac_addr[ETH_ALEN]; netdev_features_t netdev_features; struct napi_struct napi; struct xgbe_mmc_stats mmc_stats; @@ -743,7 +757,9 @@ struct xgbe_prv_data { /* Device clocks */ struct clk *sysclk; + unsigned long sysclk_rate; struct clk *ptpclk; + unsigned long ptpclk_rate; /* Timestamp support */ spinlock_t tstamp_lock; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index a3c251b79f38..16adbc481772 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -26,7 +26,7 @@ config AMD_PHY config AMD_XGBE_PHY tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs" - depends on OF && HAS_IOMEM + depends on (OF || ACPI) && HAS_IOMEM ---help--- Currently supports the AMD 10GbE PHY diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index e2074c75891c..2f2107436738 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -76,6 +76,8 @@ #include #include #include +#include +#include MODULE_AUTHOR("Tom Lendacky "); MODULE_LICENSE("Dual BSD/GPL"); @@ -323,12 +325,13 @@ enum amd_xgbe_phy_mode { }; enum amd_xgbe_phy_speedset { - AMD_XGBE_PHY_SPEEDSET_1000_10000, + AMD_XGBE_PHY_SPEEDSET_1000_10000 = 0, AMD_XGBE_PHY_SPEEDSET_2500_10000, }; struct amd_xgbe_phy_priv { struct platform_device *pdev; + struct acpi_device *adev; struct device *dev; struct phy_device *phydev; @@ -1420,46 +1423,94 @@ static int amd_xgbe_phy_resume(struct phy_device *phydev) return 0; } +static unsigned int amd_xgbe_phy_resource_count(struct platform_device *pdev, + unsigned int type) +{ + unsigned int count; + int i; + + for (i = 0, count = 0; i < pdev->num_resources; i++) { + struct resource *r = &pdev->resource[i]; + + if (type == resource_type(r)) + count++; + } + + return count; +} + static int amd_xgbe_phy_probe(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv; - struct platform_device *pdev; - struct device *dev; - const __be32 *property; - unsigned int speed_set; + struct platform_device *phy_pdev; + struct device *dev, *phy_dev; + unsigned int phy_resnum, phy_irqnum; int ret; - if (!phydev->dev.of_node) + if (!phydev->bus || !phydev->bus->parent) return -EINVAL; - pdev = of_find_device_by_node(phydev->dev.of_node); - if (!pdev) - return -EINVAL; - dev = &pdev->dev; + dev = phydev->bus->parent; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_pdev; - } + if (!priv) + return -ENOMEM; - priv->pdev = pdev; + priv->pdev = to_platform_device(dev); + priv->adev = ACPI_COMPANION(dev); priv->dev = dev; priv->phydev = phydev; mutex_init(&priv->an_mutex); INIT_WORK(&priv->an_irq_work, amd_xgbe_an_irq_work); INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); + if (!priv->adev || acpi_disabled) { + struct device_node *bus_node; + struct device_node *phy_node; + + bus_node = priv->dev->of_node; + phy_node = of_parse_phandle(bus_node, "phy-handle", 0); + if (!phy_node) { + dev_err(dev, "unable to parse phy-handle\n"); + ret = -EINVAL; + goto err_priv; + } + + phy_pdev = of_find_device_by_node(phy_node); + of_node_put(phy_node); + + if (!phy_pdev) { + dev_err(dev, "unable to obtain phy device\n"); + ret = -EINVAL; + goto err_priv; + } + + phy_resnum = 0; + phy_irqnum = 0; + } else { + /* In ACPI, the XGBE and PHY resources are the grouped + * together with the PHY resources at the end + */ + phy_pdev = priv->pdev; + phy_resnum = amd_xgbe_phy_resource_count(phy_pdev, + IORESOURCE_MEM) - 3; + phy_irqnum = amd_xgbe_phy_resource_count(phy_pdev, + IORESOURCE_IRQ) - 1; + } + phy_dev = &phy_pdev->dev; + /* Get the device mmio areas */ - priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->rxtx_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, + phy_resnum++); priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res); if (IS_ERR(priv->rxtx_regs)) { dev_err(dev, "rxtx ioremap failed\n"); ret = PTR_ERR(priv->rxtx_regs); - goto err_priv; + goto err_put; } - priv->sir0_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->sir0_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, + phy_resnum++); priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res); if (IS_ERR(priv->sir0_regs)) { dev_err(dev, "sir0 ioremap failed\n"); @@ -1467,7 +1518,8 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) goto err_rxtx; } - priv->sir1_res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + priv->sir1_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, + phy_resnum++); priv->sir1_regs = devm_ioremap_resource(dev, priv->sir1_res); if (IS_ERR(priv->sir1_regs)) { dev_err(dev, "sir1 ioremap failed\n"); @@ -1476,7 +1528,7 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) } /* Get the auto-negotiation interrupt */ - ret = platform_get_irq(pdev, 0); + ret = platform_get_irq(phy_pdev, phy_irqnum); if (ret < 0) { dev_err(dev, "platform_get_irq failed\n"); goto err_sir1; @@ -1484,28 +1536,29 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) priv->an_irq = ret; /* Get the device speed set property */ - speed_set = 0; - property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY, - NULL); - if (property) - speed_set = be32_to_cpu(*property); - - switch (speed_set) { - case 0: - priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000; - break; - case 1: - priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000; + ret = device_property_read_u32(phy_dev, XGBE_PHY_SPEEDSET_PROPERTY, + &priv->speed_set); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_SPEEDSET_PROPERTY); + goto err_sir1; + } + + switch (priv->speed_set) { + case AMD_XGBE_PHY_SPEEDSET_1000_10000: + case AMD_XGBE_PHY_SPEEDSET_2500_10000: break; default: - dev_err(dev, "invalid amd,speed-set property\n"); + dev_err(dev, "invalid %s property\n", + XGBE_PHY_SPEEDSET_PROPERTY); ret = -EINVAL; goto err_sir1; } phydev->priv = priv; - of_dev_put(pdev); + if (!priv->adev || acpi_disabled) + platform_device_put(phy_pdev); return 0; @@ -1524,12 +1577,13 @@ err_rxtx: devm_release_mem_region(dev, priv->rxtx_res->start, resource_size(priv->rxtx_res)); +err_put: + if (!priv->adev || acpi_disabled) + platform_device_put(phy_pdev); + err_priv: devm_kfree(dev, priv); -err_pdev: - of_dev_put(pdev); - return ret; } -- cgit v1.2.1 From 8fdb1a09e1568062f6c434e3e828630950b7e16a Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 16 Jan 2015 12:47:21 -0600 Subject: amd-xgbe-phy: Allow certain PHY settings to be set by UEFI Certain PHY settings need to be configurable by UEFI depending on the platform being used. Add new device tree / ACPI properties that, if present, will override the pre-determined values currently used. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/phy/amd-xgbe-phy.c | 159 +++++++++++++++++++++++++++++++++++------ 1 file changed, 136 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 2f2107436738..9e3af54c9010 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -88,6 +88,15 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define XGBE_PHY_MASK 0xfffffff0 #define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set" +#define XGBE_PHY_BLWC_PROPERTY "amd,serdes-blwc" +#define XGBE_PHY_CDR_RATE_PROPERTY "amd,serdes-cdr-rate" +#define XGBE_PHY_PQ_SKEW_PROPERTY "amd,serdes-pq-skew" +#define XGBE_PHY_TX_AMP_PROPERTY "amd,serdes-tx-amp" + +#define XGBE_PHY_SPEEDS 3 +#define XGBE_PHY_SPEED_1000 0 +#define XGBE_PHY_SPEED_2500 1 +#define XGBE_PHY_SPEED_10000 2 #define XGBE_AN_INT_CMPLT 0x01 #define XGBE_AN_INC_LINK 0x02 @@ -152,10 +161,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define SIR0_STATUS_RX_READY_WIDTH 1 #define SIR0_STATUS_TX_READY_INDEX 8 #define SIR0_STATUS_TX_READY_WIDTH 1 +#define SIR1_SPEED_CDR_RATE_INDEX 12 +#define SIR1_SPEED_CDR_RATE_WIDTH 4 #define SIR1_SPEED_DATARATE_INDEX 4 #define SIR1_SPEED_DATARATE_WIDTH 2 -#define SIR1_SPEED_PI_SPD_SEL_INDEX 12 -#define SIR1_SPEED_PI_SPD_SEL_WIDTH 4 #define SIR1_SPEED_PLLSEL_INDEX 3 #define SIR1_SPEED_PLLSEL_WIDTH 1 #define SIR1_SPEED_RATECHANGE_INDEX 6 @@ -165,20 +174,26 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define SIR1_SPEED_WORDMODE_INDEX 0 #define SIR1_SPEED_WORDMODE_WIDTH 3 +#define SPEED_10000_BLWC 0 #define SPEED_10000_CDR 0x7 #define SPEED_10000_PLL 0x1 +#define SPEED_10000_PQ 0x1e #define SPEED_10000_RATE 0x0 #define SPEED_10000_TXAMP 0xa #define SPEED_10000_WORD 0x7 +#define SPEED_2500_BLWC 1 #define SPEED_2500_CDR 0x2 #define SPEED_2500_PLL 0x0 +#define SPEED_2500_PQ 0xa #define SPEED_2500_RATE 0x1 #define SPEED_2500_TXAMP 0xf #define SPEED_2500_WORD 0x1 +#define SPEED_1000_BLWC 1 #define SPEED_1000_CDR 0x2 #define SPEED_1000_PLL 0x0 +#define SPEED_1000_PQ 0xa #define SPEED_1000_RATE 0x3 #define SPEED_1000_TXAMP 0xf #define SPEED_1000_WORD 0x1 @@ -193,15 +208,6 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define RXTX_REG114_PQ_REG_INDEX 9 #define RXTX_REG114_PQ_REG_WIDTH 7 -#define RXTX_10000_BLWC 0 -#define RXTX_10000_PQ 0x1e - -#define RXTX_2500_BLWC 1 -#define RXTX_2500_PQ 0xa - -#define RXTX_1000_BLWC 1 -#define RXTX_1000_PQ 0xa - /* Bit setting and getting macros * The get macro will extract the current bit field value from within * the variable @@ -303,6 +309,30 @@ do { \ XRXTX_IOWRITE((_priv), _reg, reg_val); \ } while (0) +static const u32 amd_xgbe_phy_serdes_blwc[] = { + SPEED_1000_BLWC, + SPEED_2500_BLWC, + SPEED_10000_BLWC, +}; + +static const u32 amd_xgbe_phy_serdes_cdr_rate[] = { + SPEED_1000_CDR, + SPEED_2500_CDR, + SPEED_10000_CDR, +}; + +static const u32 amd_xgbe_phy_serdes_pq_skew[] = { + SPEED_1000_PQ, + SPEED_2500_PQ, + SPEED_10000_PQ, +}; + +static const u32 amd_xgbe_phy_serdes_tx_amp[] = { + SPEED_1000_TXAMP, + SPEED_2500_TXAMP, + SPEED_10000_TXAMP, +}; + enum amd_xgbe_phy_an { AMD_XGBE_AN_READY = 0, AMD_XGBE_AN_PAGE_RECEIVED, @@ -353,6 +383,17 @@ struct amd_xgbe_phy_priv { unsigned int speed_set; + /* SerDes UEFI configurable settings. + * Switching between modes/speeds requires new values for some + * SerDes settings. The values can be supplied as device + * properties in array format. The first array entry is for + * 1GbE, second for 2.5GbE and third for 10GbE + */ + u32 serdes_blwc[XGBE_PHY_SPEEDS]; + u32 serdes_cdr_rate[XGBE_PHY_SPEEDS]; + u32 serdes_pq_skew[XGBE_PHY_SPEEDS]; + u32 serdes_tx_amp[XGBE_PHY_SPEEDS]; + /* Auto-negotiation state machine support */ struct mutex an_mutex; enum amd_xgbe_phy_an an_result; @@ -483,12 +524,16 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_10000_RATE); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_10000_WORD); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_10000_TXAMP); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_10000_PLL); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_10000_CDR); - XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_10000_BLWC); - XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_10000_PQ); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, + priv->serdes_cdr_rate[XGBE_PHY_SPEED_10000]); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, + priv->serdes_tx_amp[XGBE_PHY_SPEED_10000]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, + priv->serdes_blwc[XGBE_PHY_SPEED_10000]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, + priv->serdes_pq_skew[XGBE_PHY_SPEED_10000]); amd_xgbe_phy_serdes_complete_ratechange(phydev); @@ -531,12 +576,16 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev) XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_2500_RATE); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_2500_WORD); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_2500_TXAMP); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_2500_PLL); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_2500_CDR); - XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_2500_BLWC); - XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_2500_PQ); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, + priv->serdes_cdr_rate[XGBE_PHY_SPEED_2500]); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, + priv->serdes_tx_amp[XGBE_PHY_SPEED_2500]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, + priv->serdes_blwc[XGBE_PHY_SPEED_2500]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, + priv->serdes_pq_skew[XGBE_PHY_SPEED_2500]); amd_xgbe_phy_serdes_complete_ratechange(phydev); @@ -579,12 +628,16 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev) XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_1000_RATE); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_1000_WORD); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_1000_TXAMP); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_1000_PLL); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_1000_CDR); - XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_1000_BLWC); - XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1000_PQ); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, + priv->serdes_cdr_rate[XGBE_PHY_SPEED_1000]); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, + priv->serdes_tx_amp[XGBE_PHY_SPEED_1000]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, + priv->serdes_blwc[XGBE_PHY_SPEED_1000]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, + priv->serdes_pq_skew[XGBE_PHY_SPEED_1000]); amd_xgbe_phy_serdes_complete_ratechange(phydev); @@ -1555,6 +1608,66 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) goto err_sir1; } + if (device_property_present(phy_dev, XGBE_PHY_BLWC_PROPERTY)) { + ret = device_property_read_u32_array(phy_dev, + XGBE_PHY_BLWC_PROPERTY, + priv->serdes_blwc, + XGBE_PHY_SPEEDS); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_BLWC_PROPERTY); + goto err_sir1; + } + } else { + memcpy(priv->serdes_blwc, amd_xgbe_phy_serdes_blwc, + sizeof(priv->serdes_blwc)); + } + + if (device_property_present(phy_dev, XGBE_PHY_CDR_RATE_PROPERTY)) { + ret = device_property_read_u32_array(phy_dev, + XGBE_PHY_CDR_RATE_PROPERTY, + priv->serdes_cdr_rate, + XGBE_PHY_SPEEDS); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_CDR_RATE_PROPERTY); + goto err_sir1; + } + } else { + memcpy(priv->serdes_cdr_rate, amd_xgbe_phy_serdes_cdr_rate, + sizeof(priv->serdes_cdr_rate)); + } + + if (device_property_present(phy_dev, XGBE_PHY_PQ_SKEW_PROPERTY)) { + ret = device_property_read_u32_array(phy_dev, + XGBE_PHY_PQ_SKEW_PROPERTY, + priv->serdes_pq_skew, + XGBE_PHY_SPEEDS); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_PQ_SKEW_PROPERTY); + goto err_sir1; + } + } else { + memcpy(priv->serdes_pq_skew, amd_xgbe_phy_serdes_pq_skew, + sizeof(priv->serdes_pq_skew)); + } + + if (device_property_present(phy_dev, XGBE_PHY_TX_AMP_PROPERTY)) { + ret = device_property_read_u32_array(phy_dev, + XGBE_PHY_TX_AMP_PROPERTY, + priv->serdes_tx_amp, + XGBE_PHY_SPEEDS); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_TX_AMP_PROPERTY); + goto err_sir1; + } + } else { + memcpy(priv->serdes_tx_amp, amd_xgbe_phy_serdes_tx_amp, + sizeof(priv->serdes_tx_amp)); + } + phydev->priv = priv; if (!priv->adev || acpi_disabled) -- cgit v1.2.1 From ff8b335610cac5509156f28e03355c895bcc94f5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 16 Jan 2015 05:39:30 -0800 Subject: niu: remove one compound_head() call After a "page = alloc_page(mask);", we do not need to use compound_head() : page already points to the right place. This would be true even if using alloc_pages(). Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/sun/niu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index 0c6416213837..4b51f903fb73 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -3341,8 +3341,7 @@ static int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp, niu_hash_page(rp, page, addr); if (rp->rbr_blocks_per_page > 1) - atomic_add(rp->rbr_blocks_per_page - 1, - &compound_head(page)->_count); + atomic_add(rp->rbr_blocks_per_page - 1, &page->_count); for (i = 0; i < rp->rbr_blocks_per_page; i++) { __le32 *rbr = &rp->rbr[start_index + i]; -- cgit v1.2.1 From 3aeb66176ffa8fefd7a9f7d37bda1d8adcf469a1 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 15 Jan 2015 23:49:37 +0100 Subject: net: replace br_fdb_external_learn_* calls with switchdev notifier events This patch benefits from newly introduced switchdev notifier and uses it to propagate fdb learn events from rocker driver to bridge. That avoids direct function calls and possible use by other listeners (ovs). Suggested-by: Thomas Graf Signed-off-by: Jiri Pirko Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index cad8cf962cdf..964d719b150f 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -3026,11 +3026,17 @@ static void rocker_port_fdb_learn_work(struct work_struct *work) container_of(work, struct rocker_fdb_learn_work, work); bool removing = (lw->flags & ROCKER_OP_FLAG_REMOVE); bool learned = (lw->flags & ROCKER_OP_FLAG_LEARNED); + struct netdev_switch_notifier_fdb_info info; + + info.addr = lw->addr; + info.vid = lw->vid; if (learned && removing) - br_fdb_external_learn_del(lw->dev, lw->addr, lw->vid); + call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_DEL, + lw->dev, &info.info); else if (learned && !removing) - br_fdb_external_learn_add(lw->dev, lw->addr, lw->vid); + call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_ADD, + lw->dev, &info.info); kfree(work); } -- cgit v1.2.1 From 053c095a82cf773075e83d7233b5cc19a1f73ece Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Jan 2015 22:09:00 +0100 Subject: netlink: make nlmsg_end() and genlmsg_end() void Contrary to common expectations for an "int" return, these functions return only a positive value -- if used correctly they cannot even return 0 because the message header will necessarily be in the skb. This makes the very common pattern of if (genlmsg_end(...) < 0) { ... } be a whole bunch of dead code. Many places also simply do return nlmsg_end(...); and the caller is expected to deal with it. This also commonly (at least for me) causes errors, because it is very common to write if (my_function(...)) /* error condition */ and if my_function() does "return nlmsg_end()" this is of course wrong. Additionally, there's not a single place in the kernel that actually needs the message length returned, and if anyone needs it later then it'll be very easy to just use skb->len there. Remove this, and make the functions void. This removes a bunch of dead code as described above. The patch adds lines because I did - return nlmsg_end(...); + nlmsg_end(...); + return 0; I could have preserved all the function's return values by returning skb->len, but instead I've audited all the places calling the affected functions and found that none cared. A few places actually compared the return value with <= 0 in dump functionality, but that could just be changed to < 0 with no change in behaviour, so I opted for the more efficient version. One instance of the error I've made numerous times now is also present in net/phonet/pn_netlink.c in the route_dumpit() function - it didn't check for <0 or <=0 and thus broke out of the loop every single time. I've preserved this since it will (I think) have caused the messages to userspace to be formatted differently with just a single message for every SKB returned to userspace. It's possible that this isn't needed for the tools that actually use this, but I don't even know what they are so couldn't test that changing this behaviour would be acceptable. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 3 ++- drivers/net/vxlan.c | 3 ++- drivers/net/wireless/mac80211_hwsim.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 964d719b150f..d54781e71cd4 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -3674,7 +3674,8 @@ static int rocker_fdb_fill_info(struct sk_buff *skb, if (vid && nla_put_u16(skb, NDA_VLAN, vid)) goto nla_put_failure; - return nlmsg_end(skb, nlh); + nlmsg_end(skb, nlh); + return 0; nla_put_failure: nlmsg_cancel(skb, nlh); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 6b6b45622a0a..c5f79e7513a6 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -363,7 +363,8 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) goto nla_put_failure; - return nlmsg_end(skb, nlh); + nlmsg_end(skb, nlh); + return 0; nla_put_failure: nlmsg_cancel(skb, nlh); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 494e7335aa64..4a4c6586a8d2 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2557,7 +2557,8 @@ static int mac80211_hwsim_get_radio(struct sk_buff *skb, if (res < 0) goto out_err; - return genlmsg_end(skb, hdr); + genlmsg_end(skb, hdr); + return 0; out_err: genlmsg_cancel(skb, hdr); -- cgit v1.2.1 From 5087b915d5c33a0dd1af90eb41cc3e04117c5231 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 16 Jan 2015 10:11:11 -0600 Subject: net: ethernet: cpsw: unroll IRQ request loop This patch is in preparation for a nicer IRQ handling scheme where we use different IRQ handlers for each IRQ line (as it should be). Later, we will also drop IRQs offset 0 and 3 because they are always disabled in this driver. Signed-off-by: Felipe Balbi Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 62 ++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 64d1cef4cda1..fd5157296100 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -2163,7 +2163,8 @@ static int cpsw_probe(struct platform_device *pdev) void __iomem *ss_regs; struct resource *res, *ss_res; u32 slave_offset, sliver_offset, slave_size; - int ret = 0, i, k = 0; + int ret = 0, i; + int irq; ndev = alloc_etherdev(sizeof(struct cpsw_priv)); if (!ndev) { @@ -2352,24 +2353,55 @@ static int cpsw_probe(struct platform_device *pdev) goto clean_ale_ret; } - while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { - if (k >= ARRAY_SIZE(priv->irqs_table)) { - ret = -EINVAL; - goto clean_ale_ret; - } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + goto clean_ale_ret; - ret = devm_request_irq(&pdev->dev, res->start, cpsw_interrupt, - 0, dev_name(&pdev->dev), priv); - if (ret < 0) { - dev_err(priv->dev, "error attaching irq (%d)\n", ret); - goto clean_ale_ret; - } + priv->irqs_table[0] = irq; + ret = devm_request_irq(&pdev->dev, irq, cpsw_interrupt, + 0, dev_name(&pdev->dev), priv); + if (ret < 0) { + dev_err(priv->dev, "error attaching irq (%d)\n", ret); + goto clean_ale_ret; + } - priv->irqs_table[k] = res->start; - k++; + irq = platform_get_irq(pdev, 1); + if (irq < 0) + goto clean_ale_ret; + + priv->irqs_table[1] = irq; + ret = devm_request_irq(&pdev->dev, irq, cpsw_interrupt, + 0, dev_name(&pdev->dev), priv); + if (ret < 0) { + dev_err(priv->dev, "error attaching irq (%d)\n", ret); + goto clean_ale_ret; + } + + irq = platform_get_irq(pdev, 2); + if (irq < 0) + goto clean_ale_ret; + + priv->irqs_table[2] = irq; + ret = devm_request_irq(&pdev->dev, irq, cpsw_interrupt, + 0, dev_name(&pdev->dev), priv); + if (ret < 0) { + dev_err(priv->dev, "error attaching irq (%d)\n", ret); + goto clean_ale_ret; + } + + irq = platform_get_irq(pdev, 3); + if (irq < 0) + goto clean_ale_ret; + + priv->irqs_table[3] = irq; + ret = devm_request_irq(&pdev->dev, irq, cpsw_interrupt, + 0, dev_name(&pdev->dev), priv); + if (ret < 0) { + dev_err(priv->dev, "error attaching irq (%d)\n", ret); + goto clean_ale_ret; } - priv->num_irqs = k; + priv->num_irqs = 4; ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; -- cgit v1.2.1 From c03abd84634dca47476565f7608fea02408c5882 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 16 Jan 2015 10:11:12 -0600 Subject: net: ethernet: cpsw: don't requests IRQs we don't use CPSW never uses RX_THRESHOLD or MISC interrupts. In fact, they are always kept masked in their appropriate IRQ Enable register. Instead of allocating an IRQ that never fires, it's best to remove that code altogether and let future patches implement it if anybody needs those. Signed-off-by: Felipe Balbi Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 72 +++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index fd5157296100..4f508aa782c5 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -761,17 +761,25 @@ requeue: dev_kfree_skb_any(new_skb); } -static irqreturn_t cpsw_interrupt(int irq, void *dev_id) +static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) { struct cpsw_priv *priv = dev_id; - int value = irq - priv->irqs_table[0]; - /* NOTICE: Ending IRQ here. The trick with the 'value' variable above - * is to make sure we will always write the correct value to the EOI - * register. Namely 0 for RX_THRESH Interrupt, 1 for RX Interrupt, 2 - * for TX Interrupt and 3 for MISC Interrupt. - */ - cpdma_ctlr_eoi(priv->dma, value); + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); + cpdma_chan_process(priv->txch, 128); + + priv = cpsw_get_slave_priv(priv, 1); + if (priv) + cpdma_chan_process(priv->txch, 128); + + return IRQ_HANDLED; +} + +static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) +{ + struct cpsw_priv *priv = dev_id; + + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); cpsw_intr_disable(priv); if (priv->irq_enabled == true) { @@ -1624,7 +1632,8 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev) cpsw_intr_disable(priv); cpdma_ctlr_int_ctrl(priv->dma, false); - cpsw_interrupt(ndev->irq, priv); + cpsw_rx_interrupt(priv->irq[0], priv); + cpsw_tx_interrupt(priv->irq[1], priv); cpdma_ctlr_int_ctrl(priv->dma, true); cpsw_intr_enable(priv); } @@ -2346,62 +2355,47 @@ static int cpsw_probe(struct platform_device *pdev) goto clean_dma_ret; } - ndev->irq = platform_get_irq(pdev, 0); + ndev->irq = platform_get_irq(pdev, 1); if (ndev->irq < 0) { dev_err(priv->dev, "error getting irq resource\n"); ret = -ENOENT; goto clean_ale_ret; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) - goto clean_ale_ret; - - priv->irqs_table[0] = irq; - ret = devm_request_irq(&pdev->dev, irq, cpsw_interrupt, - 0, dev_name(&pdev->dev), priv); - if (ret < 0) { - dev_err(priv->dev, "error attaching irq (%d)\n", ret); - goto clean_ale_ret; - } + /* Grab RX and TX IRQs. Note that we also have RX_THRESHOLD and + * MISC IRQs which are always kept disabled with this driver so + * we will not request them. + * + * If anyone wants to implement support for those, make sure to + * first request and append them to irqs_table array. + */ + /* RX IRQ */ irq = platform_get_irq(pdev, 1); if (irq < 0) goto clean_ale_ret; - priv->irqs_table[1] = irq; - ret = devm_request_irq(&pdev->dev, irq, cpsw_interrupt, + priv->irqs_table[0] = irq; + ret = devm_request_irq(&pdev->dev, irq, cpsw_rx_interrupt, 0, dev_name(&pdev->dev), priv); if (ret < 0) { dev_err(priv->dev, "error attaching irq (%d)\n", ret); goto clean_ale_ret; } + /* TX IRQ */ irq = platform_get_irq(pdev, 2); if (irq < 0) goto clean_ale_ret; - priv->irqs_table[2] = irq; - ret = devm_request_irq(&pdev->dev, irq, cpsw_interrupt, - 0, dev_name(&pdev->dev), priv); - if (ret < 0) { - dev_err(priv->dev, "error attaching irq (%d)\n", ret); - goto clean_ale_ret; - } - - irq = platform_get_irq(pdev, 3); - if (irq < 0) - goto clean_ale_ret; - - priv->irqs_table[3] = irq; - ret = devm_request_irq(&pdev->dev, irq, cpsw_interrupt, + priv->irqs_table[1] = irq; + ret = devm_request_irq(&pdev->dev, irq, cpsw_tx_interrupt, 0, dev_name(&pdev->dev), priv); if (ret < 0) { dev_err(priv->dev, "error attaching irq (%d)\n", ret); goto clean_ale_ret; } - - priv->num_irqs = 4; + priv->num_irqs = 2; ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; -- cgit v1.2.1 From f2bbca513c80081245ce2cb39f314ec37703afb3 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 16 Jan 2015 14:22:29 -0700 Subject: net: rocker: Add basic netdev counters - v2 Add packet and byte counters for RX and TX paths. $ ifconfig eth1 eth1: flags=4163 mtu 1500 inet6 fe80::5054:ff:fe12:3501 prefixlen 64 scopeid 0x20 ether 52:54:00:12:35:01 txqueuelen 1000 (Ethernet) RX packets 63 bytes 15813 (15.4 KiB) RX errors 1 dropped 0 overruns 0 frame 0 TX packets 79 bytes 17991 (17.5 KiB) TX errors 7 dropped 0 overruns 0 carrier 0 collisions 0 Rx / Tx errors tested by injecting faults in qemu's hardware model for Rocker. v2: - moved counter locations to avoid potential use after free per Florian's comment Signed-off-by: David Ahern Cc: Scott Feldman Cc: Jiri Pirko Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index d54781e71cd4..11f4ffcc113d 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -3571,6 +3571,8 @@ nest_cancel: rocker_tlv_nest_cancel(desc_info, frags); out: dev_kfree_skb(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; } @@ -3857,12 +3859,22 @@ static int rocker_port_poll_tx(struct napi_struct *napi, int budget) /* Cleanup tx descriptors */ while ((desc_info = rocker_desc_tail_get(&rocker_port->tx_ring))) { + struct sk_buff *skb; + err = rocker_desc_err(desc_info); if (err && net_ratelimit()) netdev_err(rocker_port->dev, "tx desc received with err %d\n", err); rocker_tx_desc_frags_unmap(rocker_port, desc_info); - dev_kfree_skb_any(rocker_desc_cookie_ptr_get(desc_info)); + + skb = rocker_desc_cookie_ptr_get(desc_info); + if (err == 0) { + rocker_port->dev->stats.tx_packets++; + rocker_port->dev->stats.tx_bytes += skb->len; + } else + rocker_port->dev->stats.tx_errors++; + + dev_kfree_skb_any(skb); credits++; } @@ -3895,6 +3907,10 @@ static int rocker_port_rx_proc(struct rocker *rocker, rx_len = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FRAG_LEN]); skb_put(skb, rx_len); skb->protocol = eth_type_trans(skb, rocker_port->dev); + + rocker_port->dev->stats.rx_packets++; + rocker_port->dev->stats.rx_bytes += skb->len; + netif_receive_skb(skb); return rocker_dma_rx_ring_skb_alloc(rocker, rocker_port, desc_info); @@ -3928,6 +3944,9 @@ static int rocker_port_poll_rx(struct napi_struct *napi, int budget) netdev_err(rocker_port->dev, "rx processing failed with err %d\n", err); } + if (err) + rocker_port->dev->stats.rx_errors++; + rocker_desc_gen_clear(desc_info); rocker_desc_head_set(rocker, &rocker_port->rx_ring, desc_info); credits++; -- cgit v1.2.1 From 1728d4fabd1bc9965728de25dda0b694b8da6450 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 15 Jan 2015 15:11:17 +0100 Subject: tunnels: advertise link netns via netlink Implement rtnl_link_ops->get_link_net() callback so that IFLA_LINK_NETNSID is added to rtnetlink messages. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index c5f79e7513a6..0346eaa6d236 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2923,6 +2923,13 @@ nla_put_failure: return -EMSGSIZE; } +static struct net *vxlan_get_link_net(const struct net_device *dev) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + + return vxlan->net; +} + static struct rtnl_link_ops vxlan_link_ops __read_mostly = { .kind = "vxlan", .maxtype = IFLA_VXLAN_MAX, @@ -2934,6 +2941,7 @@ static struct rtnl_link_ops vxlan_link_ops __read_mostly = { .dellink = vxlan_dellink, .get_size = vxlan_get_size, .fill_info = vxlan_fill_info, + .get_link_net = vxlan_get_link_net, }; static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn, -- cgit v1.2.1 From 92cb13fb21c60b3567c7bb7e55be7c38dc6bda38 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 19 Jan 2015 11:52:36 -0600 Subject: net: ethernet: ti: cpsw: fix buld break when NET_POLL_CONTROLLER Commit c03abd84634d (net: ethernet: cpsw: don't requests IRQs we don't use) left one build breakage when NET_POLL_CONTROLLER is enabled. Fix this build break by referring to the correct irqs_table array. Fixes: c03abd84634d (net: ethernet: cpsw: don't requests IRQs we don't use) Reported-by: kbuild test robot Signed-off-by: Felipe Balbi Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 4f508aa782c5..a1ba3a0c28da 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1632,8 +1632,8 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev) cpsw_intr_disable(priv); cpdma_ctlr_int_ctrl(priv->dma, false); - cpsw_rx_interrupt(priv->irq[0], priv); - cpsw_tx_interrupt(priv->irq[1], priv); + cpsw_rx_interrupt(priv->irqs_table[0], priv); + cpsw_tx_interrupt(priv->irqs_table[1], priv); cpdma_ctlr_int_ctrl(priv->dma, true); cpsw_intr_enable(priv); } -- cgit v1.2.1 From 84640e27f23041d474c31d3362c3e2185ad68ec2 Mon Sep 17 00:00:00 2001 From: "Karicheri, Muralidharan" Date: Thu, 15 Jan 2015 19:12:50 -0500 Subject: net: netcp: Add Keystone NetCP core ethernet driver The network coprocessor (NetCP) is a hardware accelerator available in Keystone SoCs that processes Ethernet packets. NetCP consists of following hardware components 1 Gigabit Ethernet (GbE) subsystem with a Ethernet switch sub-module to send and receive packets. 2 Packet Accelerator (PA) module to perform packet classification operations such as header matching, and packet modification operations such as checksum generation. 3 Security Accelerator(SA) capable of performing IPSec operations on ingress/egress packets. 4 An optional 10 Gigabit Ethernet Subsystem (XGbE) which includes a 3-port Ethernet switch sub-module capable of 10Gb/s and 1Gb/s rates per Ethernet port. 5 Packet DMA and Queue Management Subsystem (QMSS) to enqueue and dequeue packets and DMA the packets between memory and NetCP hardware components described above. NetCP core driver make use of the Keystone Navigator driver API to allocate DMA channel for the Ethenet device and to handle packet queue/de-queue, Please refer API's in include/linux/soc/ti/knav_dma.h and drivers/soc/ti/knav_qmss.h for details. NetCP driver consists of NetCP core driver and at a minimum Gigabit Ethernet (GBE) module (1) driver to implement the Network device function. Other modules (2,3) can be optionally added to achieve supported hardware acceleration function. The initial version of the driver include NetCP core driver and GBE driver modules. Please refer Documentation/devicetree/bindings/net/keystone-netcp.txt for design of the driver. Cc: David Miller Cc: Rob Herring Cc: Grant Likely Cc: Santosh Shilimkar Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Signed-off-by: Murali Karicheri Signed-off-by: Wingman Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/Kconfig | 11 + drivers/net/ethernet/ti/Makefile | 3 + drivers/net/ethernet/ti/netcp.h | 229 ++++ drivers/net/ethernet/ti/netcp_core.c | 2141 ++++++++++++++++++++++++++++++++++ 4 files changed, 2384 insertions(+) create mode 100644 drivers/net/ethernet/ti/netcp.h create mode 100644 drivers/net/ethernet/ti/netcp_core.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 605dd909bcc3..e11bcfa69f52 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -73,12 +73,23 @@ config TI_CPSW config TI_CPTS boolean "TI Common Platform Time Sync (CPTS) Support" depends on TI_CPSW + depends on TI_CPSW || TI_KEYSTONE_NET select PTP_1588_CLOCK ---help--- This driver supports the Common Platform Time Sync unit of the CPSW Ethernet Switch. The unit can time stamp PTP UDP/IPv4 and Layer 2 packets, and the driver offers a PTP Hardware Clock. +config TI_KEYSTONE_NETCP + tristate "TI Keystone NETCP Ethernet subsystem Support" + depends on OF + depends on KEYSTONE_NAVIGATOR_DMA && KEYSTONE_NAVIGATOR_QMSS + ---help--- + This driver supports TI's Keystone NETCP Ethernet subsystem. + + To compile this driver as a module, choose M here: the module + will be called keystone_netcp. + config TLAN tristate "TI ThunderLAN support" depends on (PCI || EISA) diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 9cfaab8152be..4e8a8e41f69f 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -10,3 +10,6 @@ obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o obj-$(CONFIG_TI_CPSW) += ti_cpsw.o ti_cpsw-y := cpsw_ale.o cpsw.o cpts.o + +obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o +keystone_netcp-y := netcp_core.o diff --git a/drivers/net/ethernet/ti/netcp.h b/drivers/net/ethernet/ti/netcp.h new file mode 100644 index 000000000000..906e9bc412f5 --- /dev/null +++ b/drivers/net/ethernet/ti/netcp.h @@ -0,0 +1,229 @@ +/* + * NetCP driver local header + * + * Copyright (C) 2014 Texas Instruments Incorporated + * Authors: Sandeep Nair + * Sandeep Paulraj + * Cyril Chemparathy + * Santosh Shilimkar + * Wingman Kwok + * Murali Karicheri + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __NETCP_H__ +#define __NETCP_H__ + +#include +#include + +/* Maximum Ethernet frame size supported by Keystone switch */ +#define NETCP_MAX_FRAME_SIZE 9504 + +#define SGMII_LINK_MAC_MAC_AUTONEG 0 +#define SGMII_LINK_MAC_PHY 1 +#define SGMII_LINK_MAC_MAC_FORCED 2 +#define SGMII_LINK_MAC_FIBER 3 +#define SGMII_LINK_MAC_PHY_NO_MDIO 4 +#define XGMII_LINK_MAC_PHY 10 +#define XGMII_LINK_MAC_MAC_FORCED 11 + +struct netcp_device; + +struct netcp_tx_pipe { + struct netcp_device *netcp_device; + void *dma_queue; + unsigned int dma_queue_id; + u8 dma_psflags; + void *dma_channel; + const char *dma_chan_name; +}; + +#define ADDR_NEW BIT(0) +#define ADDR_VALID BIT(1) + +enum netcp_addr_type { + ADDR_ANY, + ADDR_DEV, + ADDR_UCAST, + ADDR_MCAST, + ADDR_BCAST +}; + +struct netcp_addr { + struct netcp_intf *netcp; + unsigned char addr[ETH_ALEN]; + enum netcp_addr_type type; + unsigned int flags; + struct list_head node; +}; + +struct netcp_intf { + struct device *dev; + struct device *ndev_dev; + struct net_device *ndev; + bool big_endian; + unsigned int tx_compl_qid; + void *tx_pool; + struct list_head txhook_list_head; + unsigned int tx_pause_threshold; + void *tx_compl_q; + + unsigned int tx_resume_threshold; + void *rx_queue; + void *rx_pool; + struct list_head rxhook_list_head; + unsigned int rx_queue_id; + void *rx_fdq[KNAV_DMA_FDQ_PER_CHAN]; + u32 rx_buffer_sizes[KNAV_DMA_FDQ_PER_CHAN]; + struct napi_struct rx_napi; + struct napi_struct tx_napi; + + void *rx_channel; + const char *dma_chan_name; + u32 rx_pool_size; + u32 rx_pool_region_id; + u32 tx_pool_size; + u32 tx_pool_region_id; + struct list_head module_head; + struct list_head interface_list; + struct list_head addr_list; + bool netdev_registered; + bool primary_module_attached; + + /* Lock used for protecting Rx/Tx hook list management */ + spinlock_t lock; + struct netcp_device *netcp_device; + struct device_node *node_interface; + + /* DMA configuration data */ + u32 msg_enable; + u32 rx_queue_depths[KNAV_DMA_FDQ_PER_CHAN]; +}; + +#define NETCP_PSDATA_LEN KNAV_DMA_NUM_PS_WORDS +struct netcp_packet { + struct sk_buff *skb; + u32 *epib; + u32 *psdata; + unsigned int psdata_len; + struct netcp_intf *netcp; + struct netcp_tx_pipe *tx_pipe; + bool rxtstamp_complete; + void *ts_context; + + int (*txtstamp_complete)(void *ctx, struct netcp_packet *pkt); +}; + +static inline u32 *netcp_push_psdata(struct netcp_packet *p_info, + unsigned int bytes) +{ + u32 *buf; + unsigned int words; + + if ((bytes & 0x03) != 0) + return NULL; + words = bytes >> 2; + + if ((p_info->psdata_len + words) > NETCP_PSDATA_LEN) + return NULL; + + p_info->psdata_len += words; + buf = &p_info->psdata[NETCP_PSDATA_LEN - p_info->psdata_len]; + return buf; +} + +static inline int netcp_align_psdata(struct netcp_packet *p_info, + unsigned int byte_align) +{ + int padding; + + switch (byte_align) { + case 0: + padding = -EINVAL; + break; + case 1: + case 2: + case 4: + padding = 0; + break; + case 8: + padding = (p_info->psdata_len << 2) % 8; + break; + case 16: + padding = (p_info->psdata_len << 2) % 16; + break; + default: + padding = (p_info->psdata_len << 2) % byte_align; + break; + } + return padding; +} + +struct netcp_module { + const char *name; + struct module *owner; + bool primary; + + /* probe/remove: called once per NETCP instance */ + int (*probe)(struct netcp_device *netcp_device, + struct device *device, struct device_node *node, + void **inst_priv); + int (*remove)(struct netcp_device *netcp_device, void *inst_priv); + + /* attach/release: called once per network interface */ + int (*attach)(void *inst_priv, struct net_device *ndev, + struct device_node *node, void **intf_priv); + int (*release)(void *intf_priv); + int (*open)(void *intf_priv, struct net_device *ndev); + int (*close)(void *intf_priv, struct net_device *ndev); + int (*add_addr)(void *intf_priv, struct netcp_addr *naddr); + int (*del_addr)(void *intf_priv, struct netcp_addr *naddr); + int (*add_vid)(void *intf_priv, int vid); + int (*del_vid)(void *intf_priv, int vid); + int (*ioctl)(void *intf_priv, struct ifreq *req, int cmd); + + /* used internally */ + struct list_head module_list; + struct list_head interface_list; +}; + +int netcp_register_module(struct netcp_module *module); +void netcp_unregister_module(struct netcp_module *module); +void *netcp_module_get_intf_data(struct netcp_module *module, + struct netcp_intf *intf); + +int netcp_txpipe_init(struct netcp_tx_pipe *tx_pipe, + struct netcp_device *netcp_device, + const char *dma_chan_name, unsigned int dma_queue_id); +int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe); +int netcp_txpipe_close(struct netcp_tx_pipe *tx_pipe); + +typedef int netcp_hook_rtn(int order, void *data, struct netcp_packet *packet); +int netcp_register_txhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data); +int netcp_unregister_txhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data); +int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data); +int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data); +void *netcp_device_find_module(struct netcp_device *netcp_device, + const char *name); + +/* SGMII functions */ +int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port); +int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port); +int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface); + +/* XGBE SERDES init functions */ +int netcp_xgbe_serdes_init(void __iomem *serdes_regs, void __iomem *xgbe_regs); + +#endif /* __NETCP_H__ */ diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c new file mode 100644 index 000000000000..ba3002ec710a --- /dev/null +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -0,0 +1,2141 @@ +/* + * Keystone NetCP Core driver + * + * Copyright (C) 2014 Texas Instruments Incorporated + * Authors: Sandeep Nair + * Sandeep Paulraj + * Cyril Chemparathy + * Santosh Shilimkar + * Murali Karicheri + * Wingman Kwok + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netcp.h" + +#define NETCP_SOP_OFFSET (NET_IP_ALIGN + NET_SKB_PAD) +#define NETCP_NAPI_WEIGHT 64 +#define NETCP_TX_TIMEOUT (5 * HZ) +#define NETCP_MIN_PACKET_SIZE ETH_ZLEN +#define NETCP_MAX_MCAST_ADDR 16 + +#define NETCP_EFUSE_REG_INDEX 0 + +#define NETCP_MOD_PROBE_SKIPPED 1 +#define NETCP_MOD_PROBE_FAILED 2 + +#define NETCP_DEBUG (NETIF_MSG_HW | NETIF_MSG_WOL | \ + NETIF_MSG_DRV | NETIF_MSG_LINK | \ + NETIF_MSG_IFUP | NETIF_MSG_INTR | \ + NETIF_MSG_PROBE | NETIF_MSG_TIMER | \ + NETIF_MSG_IFDOWN | NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR | NETIF_MSG_TX_DONE | \ + NETIF_MSG_PKTDATA | NETIF_MSG_TX_QUEUED | \ + NETIF_MSG_RX_STATUS) + +#define knav_queue_get_id(q) knav_queue_device_control(q, \ + KNAV_QUEUE_GET_ID, (unsigned long)NULL) + +#define knav_queue_enable_notify(q) knav_queue_device_control(q, \ + KNAV_QUEUE_ENABLE_NOTIFY, \ + (unsigned long)NULL) + +#define knav_queue_disable_notify(q) knav_queue_device_control(q, \ + KNAV_QUEUE_DISABLE_NOTIFY, \ + (unsigned long)NULL) + +#define knav_queue_get_count(q) knav_queue_device_control(q, \ + KNAV_QUEUE_GET_COUNT, (unsigned long)NULL) + +#define for_each_netcp_module(module) \ + list_for_each_entry(module, &netcp_modules, module_list) + +#define for_each_netcp_device_module(netcp_device, inst_modpriv) \ + list_for_each_entry(inst_modpriv, \ + &((netcp_device)->modpriv_head), inst_list) + +#define for_each_module(netcp, intf_modpriv) \ + list_for_each_entry(intf_modpriv, &netcp->module_head, intf_list) + +/* Module management structures */ +struct netcp_device { + struct list_head device_list; + struct list_head interface_head; + struct list_head modpriv_head; + struct device *device; +}; + +struct netcp_inst_modpriv { + struct netcp_device *netcp_device; + struct netcp_module *netcp_module; + struct list_head inst_list; + void *module_priv; +}; + +struct netcp_intf_modpriv { + struct netcp_intf *netcp_priv; + struct netcp_module *netcp_module; + struct list_head intf_list; + void *module_priv; +}; + +static LIST_HEAD(netcp_devices); +static LIST_HEAD(netcp_modules); +static DEFINE_MUTEX(netcp_modules_lock); + +static int netcp_debug_level = -1; +module_param(netcp_debug_level, int, 0); +MODULE_PARM_DESC(netcp_debug_level, "Netcp debug level (NETIF_MSG bits) (0=none,...,16=all)"); + +/* Helper functions - Get/Set */ +static void get_pkt_info(u32 *buff, u32 *buff_len, u32 *ndesc, + struct knav_dma_desc *desc) +{ + *buff_len = desc->buff_len; + *buff = desc->buff; + *ndesc = desc->next_desc; +} + +static void get_pad_info(u32 *pad0, u32 *pad1, struct knav_dma_desc *desc) +{ + *pad0 = desc->pad[0]; + *pad1 = desc->pad[1]; +} + +static void get_org_pkt_info(u32 *buff, u32 *buff_len, + struct knav_dma_desc *desc) +{ + *buff = desc->orig_buff; + *buff_len = desc->orig_len; +} + +static void get_words(u32 *words, int num_words, u32 *desc) +{ + int i; + + for (i = 0; i < num_words; i++) + words[i] = desc[i]; +} + +static void set_pkt_info(u32 buff, u32 buff_len, u32 ndesc, + struct knav_dma_desc *desc) +{ + desc->buff_len = buff_len; + desc->buff = buff; + desc->next_desc = ndesc; +} + +static void set_desc_info(u32 desc_info, u32 pkt_info, + struct knav_dma_desc *desc) +{ + desc->desc_info = desc_info; + desc->packet_info = pkt_info; +} + +static void set_pad_info(u32 pad0, u32 pad1, struct knav_dma_desc *desc) +{ + desc->pad[0] = pad0; + desc->pad[1] = pad1; +} + +static void set_org_pkt_info(u32 buff, u32 buff_len, + struct knav_dma_desc *desc) +{ + desc->orig_buff = buff; + desc->orig_len = buff_len; +} + +static void set_words(u32 *words, int num_words, u32 *desc) +{ + int i; + + for (i = 0; i < num_words; i++) + desc[i] = words[i]; +} + +/* Read the e-fuse value as 32 bit values to be endian independent */ +static int emac_arch_get_mac_addr(char *x, void __iomem *efuse_mac) +{ + unsigned int addr0, addr1; + + addr1 = readl(efuse_mac + 4); + addr0 = readl(efuse_mac); + + x[0] = (addr1 & 0x0000ff00) >> 8; + x[1] = addr1 & 0x000000ff; + x[2] = (addr0 & 0xff000000) >> 24; + x[3] = (addr0 & 0x00ff0000) >> 16; + x[4] = (addr0 & 0x0000ff00) >> 8; + x[5] = addr0 & 0x000000ff; + + return 0; +} + +static const char *netcp_node_name(struct device_node *node) +{ + const char *name; + + if (of_property_read_string(node, "label", &name) < 0) + name = node->name; + if (!name) + name = "unknown"; + return name; +} + +/* Module management routines */ +static int netcp_register_interface(struct netcp_intf *netcp) +{ + int ret; + + ret = register_netdev(netcp->ndev); + if (!ret) + netcp->netdev_registered = true; + return ret; +} + +static int netcp_module_probe(struct netcp_device *netcp_device, + struct netcp_module *module) +{ + struct device *dev = netcp_device->device; + struct device_node *devices, *interface, *node = dev->of_node; + struct device_node *child; + struct netcp_inst_modpriv *inst_modpriv; + struct netcp_intf *netcp_intf; + struct netcp_module *tmp; + bool primary_module_registered = false; + int ret; + + /* Find this module in the sub-tree for this device */ + devices = of_get_child_by_name(node, "netcp-devices"); + if (!devices) { + dev_err(dev, "could not find netcp-devices node\n"); + return NETCP_MOD_PROBE_SKIPPED; + } + + for_each_available_child_of_node(devices, child) { + const char *name = netcp_node_name(child); + + if (!strcasecmp(module->name, name)) + break; + } + + of_node_put(devices); + /* If module not used for this device, skip it */ + if (!child) { + dev_warn(dev, "module(%s) not used for device\n", module->name); + return NETCP_MOD_PROBE_SKIPPED; + } + + inst_modpriv = devm_kzalloc(dev, sizeof(*inst_modpriv), GFP_KERNEL); + if (!inst_modpriv) { + of_node_put(child); + return -ENOMEM; + } + + inst_modpriv->netcp_device = netcp_device; + inst_modpriv->netcp_module = module; + list_add_tail(&inst_modpriv->inst_list, &netcp_device->modpriv_head); + + ret = module->probe(netcp_device, dev, child, + &inst_modpriv->module_priv); + of_node_put(child); + if (ret) { + dev_err(dev, "Probe of module(%s) failed with %d\n", + module->name, ret); + list_del(&inst_modpriv->inst_list); + devm_kfree(dev, inst_modpriv); + return NETCP_MOD_PROBE_FAILED; + } + + /* Attach modules only if the primary module is probed */ + for_each_netcp_module(tmp) { + if (tmp->primary) + primary_module_registered = true; + } + + if (!primary_module_registered) + return 0; + + /* Attach module to interfaces */ + list_for_each_entry(netcp_intf, &netcp_device->interface_head, + interface_list) { + struct netcp_intf_modpriv *intf_modpriv; + + /* If interface not registered then register now */ + if (!netcp_intf->netdev_registered) + ret = netcp_register_interface(netcp_intf); + + if (ret) + return -ENODEV; + + intf_modpriv = devm_kzalloc(dev, sizeof(*intf_modpriv), + GFP_KERNEL); + if (!intf_modpriv) + return -ENOMEM; + + interface = of_parse_phandle(netcp_intf->node_interface, + module->name, 0); + + intf_modpriv->netcp_priv = netcp_intf; + intf_modpriv->netcp_module = module; + list_add_tail(&intf_modpriv->intf_list, + &netcp_intf->module_head); + + ret = module->attach(inst_modpriv->module_priv, + netcp_intf->ndev, interface, + &intf_modpriv->module_priv); + of_node_put(interface); + if (ret) { + dev_dbg(dev, "Attach of module %s declined with %d\n", + module->name, ret); + list_del(&intf_modpriv->intf_list); + devm_kfree(dev, intf_modpriv); + continue; + } + } + return 0; +} + +int netcp_register_module(struct netcp_module *module) +{ + struct netcp_device *netcp_device; + struct netcp_module *tmp; + int ret; + + if (!module->name) { + WARN(1, "error registering netcp module: no name\n"); + return -EINVAL; + } + + if (!module->probe) { + WARN(1, "error registering netcp module: no probe\n"); + return -EINVAL; + } + + mutex_lock(&netcp_modules_lock); + + for_each_netcp_module(tmp) { + if (!strcasecmp(tmp->name, module->name)) { + mutex_unlock(&netcp_modules_lock); + return -EEXIST; + } + } + list_add_tail(&module->module_list, &netcp_modules); + + list_for_each_entry(netcp_device, &netcp_devices, device_list) { + ret = netcp_module_probe(netcp_device, module); + if (ret < 0) + goto fail; + } + + mutex_unlock(&netcp_modules_lock); + return 0; + +fail: + mutex_unlock(&netcp_modules_lock); + netcp_unregister_module(module); + return ret; +} + +static void netcp_release_module(struct netcp_device *netcp_device, + struct netcp_module *module) +{ + struct netcp_inst_modpriv *inst_modpriv, *inst_tmp; + struct netcp_intf *netcp_intf, *netcp_tmp; + struct device *dev = netcp_device->device; + + /* Release the module from each interface */ + list_for_each_entry_safe(netcp_intf, netcp_tmp, + &netcp_device->interface_head, + interface_list) { + struct netcp_intf_modpriv *intf_modpriv, *intf_tmp; + + list_for_each_entry_safe(intf_modpriv, intf_tmp, + &netcp_intf->module_head, + intf_list) { + if (intf_modpriv->netcp_module == module) { + module->release(intf_modpriv->module_priv); + list_del(&intf_modpriv->intf_list); + devm_kfree(dev, intf_modpriv); + break; + } + } + } + + /* Remove the module from each instance */ + list_for_each_entry_safe(inst_modpriv, inst_tmp, + &netcp_device->modpriv_head, inst_list) { + if (inst_modpriv->netcp_module == module) { + module->remove(netcp_device, + inst_modpriv->module_priv); + list_del(&inst_modpriv->inst_list); + devm_kfree(dev, inst_modpriv); + break; + } + } +} + +void netcp_unregister_module(struct netcp_module *module) +{ + struct netcp_device *netcp_device; + struct netcp_module *module_tmp; + + mutex_lock(&netcp_modules_lock); + + list_for_each_entry(netcp_device, &netcp_devices, device_list) { + netcp_release_module(netcp_device, module); + } + + /* Remove the module from the module list */ + for_each_netcp_module(module_tmp) { + if (module == module_tmp) { + list_del(&module->module_list); + break; + } + } + + mutex_unlock(&netcp_modules_lock); +} + +void *netcp_module_get_intf_data(struct netcp_module *module, + struct netcp_intf *intf) +{ + struct netcp_intf_modpriv *intf_modpriv; + + list_for_each_entry(intf_modpriv, &intf->module_head, intf_list) + if (intf_modpriv->netcp_module == module) + return intf_modpriv->module_priv; + return NULL; +} + +/* Module TX and RX Hook management */ +struct netcp_hook_list { + struct list_head list; + netcp_hook_rtn *hook_rtn; + void *hook_data; + int order; +}; + +int netcp_register_txhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data) +{ + struct netcp_hook_list *entry; + struct netcp_hook_list *next; + unsigned long flags; + + entry = devm_kzalloc(netcp_priv->dev, sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + entry->hook_rtn = hook_rtn; + entry->hook_data = hook_data; + entry->order = order; + + spin_lock_irqsave(&netcp_priv->lock, flags); + list_for_each_entry(next, &netcp_priv->txhook_list_head, list) { + if (next->order > order) + break; + } + __list_add(&entry->list, next->list.prev, &next->list); + spin_unlock_irqrestore(&netcp_priv->lock, flags); + + return 0; +} + +int netcp_unregister_txhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data) +{ + struct netcp_hook_list *next, *n; + unsigned long flags; + + spin_lock_irqsave(&netcp_priv->lock, flags); + list_for_each_entry_safe(next, n, &netcp_priv->txhook_list_head, list) { + if ((next->order == order) && + (next->hook_rtn == hook_rtn) && + (next->hook_data == hook_data)) { + list_del(&next->list); + spin_unlock_irqrestore(&netcp_priv->lock, flags); + devm_kfree(netcp_priv->dev, next); + return 0; + } + } + spin_unlock_irqrestore(&netcp_priv->lock, flags); + return -ENOENT; +} + +int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data) +{ + struct netcp_hook_list *entry; + struct netcp_hook_list *next; + unsigned long flags; + + entry = devm_kzalloc(netcp_priv->dev, sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + entry->hook_rtn = hook_rtn; + entry->hook_data = hook_data; + entry->order = order; + + spin_lock_irqsave(&netcp_priv->lock, flags); + list_for_each_entry(next, &netcp_priv->rxhook_list_head, list) { + if (next->order > order) + break; + } + __list_add(&entry->list, next->list.prev, &next->list); + spin_unlock_irqrestore(&netcp_priv->lock, flags); + + return 0; +} + +int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data) +{ + struct netcp_hook_list *next, *n; + unsigned long flags; + + spin_lock_irqsave(&netcp_priv->lock, flags); + list_for_each_entry_safe(next, n, &netcp_priv->rxhook_list_head, list) { + if ((next->order == order) && + (next->hook_rtn == hook_rtn) && + (next->hook_data == hook_data)) { + list_del(&next->list); + spin_unlock_irqrestore(&netcp_priv->lock, flags); + devm_kfree(netcp_priv->dev, next); + return 0; + } + } + spin_unlock_irqrestore(&netcp_priv->lock, flags); + + return -ENOENT; +} + +static void netcp_frag_free(bool is_frag, void *ptr) +{ + if (is_frag) + put_page(virt_to_head_page(ptr)); + else + kfree(ptr); +} + +static void netcp_free_rx_desc_chain(struct netcp_intf *netcp, + struct knav_dma_desc *desc) +{ + struct knav_dma_desc *ndesc; + dma_addr_t dma_desc, dma_buf; + unsigned int buf_len, dma_sz = sizeof(*ndesc); + void *buf_ptr; + u32 tmp; + + get_words(&dma_desc, 1, &desc->next_desc); + + while (dma_desc) { + ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz); + if (unlikely(!ndesc)) { + dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); + break; + } + get_pkt_info(&dma_buf, &tmp, &dma_desc, ndesc); + get_pad_info((u32 *)&buf_ptr, &tmp, ndesc); + dma_unmap_page(netcp->dev, dma_buf, PAGE_SIZE, DMA_FROM_DEVICE); + __free_page(buf_ptr); + knav_pool_desc_put(netcp->rx_pool, desc); + } + + get_pad_info((u32 *)&buf_ptr, &buf_len, desc); + if (buf_ptr) + netcp_frag_free(buf_len <= PAGE_SIZE, buf_ptr); + knav_pool_desc_put(netcp->rx_pool, desc); +} + +static void netcp_empty_rx_queue(struct netcp_intf *netcp) +{ + struct knav_dma_desc *desc; + unsigned int dma_sz; + dma_addr_t dma; + + for (; ;) { + dma = knav_queue_pop(netcp->rx_queue, &dma_sz); + if (!dma) + break; + + desc = knav_pool_desc_unmap(netcp->rx_pool, dma, dma_sz); + if (unlikely(!desc)) { + dev_err(netcp->ndev_dev, "%s: failed to unmap Rx desc\n", + __func__); + netcp->ndev->stats.rx_errors++; + continue; + } + netcp_free_rx_desc_chain(netcp, desc); + netcp->ndev->stats.rx_dropped++; + } +} + +static int netcp_process_one_rx_packet(struct netcp_intf *netcp) +{ + unsigned int dma_sz, buf_len, org_buf_len; + struct knav_dma_desc *desc, *ndesc; + unsigned int pkt_sz = 0, accum_sz; + struct netcp_hook_list *rx_hook; + dma_addr_t dma_desc, dma_buff; + struct netcp_packet p_info; + struct sk_buff *skb; + void *org_buf_ptr; + u32 tmp; + + dma_desc = knav_queue_pop(netcp->rx_queue, &dma_sz); + if (!dma_desc) + return -1; + + desc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz); + if (unlikely(!desc)) { + dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); + return 0; + } + + get_pkt_info(&dma_buff, &buf_len, &dma_desc, desc); + get_pad_info((u32 *)&org_buf_ptr, &org_buf_len, desc); + + if (unlikely(!org_buf_ptr)) { + dev_err(netcp->ndev_dev, "NULL bufptr in desc\n"); + goto free_desc; + } + + pkt_sz &= KNAV_DMA_DESC_PKT_LEN_MASK; + accum_sz = buf_len; + dma_unmap_single(netcp->dev, dma_buff, buf_len, DMA_FROM_DEVICE); + + /* Build a new sk_buff for the primary buffer */ + skb = build_skb(org_buf_ptr, org_buf_len); + if (unlikely(!skb)) { + dev_err(netcp->ndev_dev, "build_skb() failed\n"); + goto free_desc; + } + + /* update data, tail and len */ + skb_reserve(skb, NETCP_SOP_OFFSET); + __skb_put(skb, buf_len); + + /* Fill in the page fragment list */ + while (dma_desc) { + struct page *page; + + ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz); + if (unlikely(!ndesc)) { + dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); + goto free_desc; + } + + get_pkt_info(&dma_buff, &buf_len, &dma_desc, ndesc); + get_pad_info((u32 *)&page, &tmp, ndesc); + + if (likely(dma_buff && buf_len && page)) { + dma_unmap_page(netcp->dev, dma_buff, PAGE_SIZE, + DMA_FROM_DEVICE); + } else { + dev_err(netcp->ndev_dev, "Bad Rx desc dma_buff(%p), len(%d), page(%p)\n", + (void *)dma_buff, buf_len, page); + goto free_desc; + } + + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, + offset_in_page(dma_buff), buf_len, PAGE_SIZE); + accum_sz += buf_len; + + /* Free the descriptor */ + knav_pool_desc_put(netcp->rx_pool, ndesc); + } + + /* Free the primary descriptor */ + knav_pool_desc_put(netcp->rx_pool, desc); + + /* check for packet len and warn */ + if (unlikely(pkt_sz != accum_sz)) + dev_dbg(netcp->ndev_dev, "mismatch in packet size(%d) & sum of fragments(%d)\n", + pkt_sz, accum_sz); + + /* Remove ethernet FCS from the packet */ + __pskb_trim(skb, skb->len - ETH_FCS_LEN); + + /* Call each of the RX hooks */ + p_info.skb = skb; + p_info.rxtstamp_complete = false; + list_for_each_entry(rx_hook, &netcp->rxhook_list_head, list) { + int ret; + + ret = rx_hook->hook_rtn(rx_hook->order, rx_hook->hook_data, + &p_info); + if (unlikely(ret)) { + dev_err(netcp->ndev_dev, "RX hook %d failed: %d\n", + rx_hook->order, ret); + netcp->ndev->stats.rx_errors++; + dev_kfree_skb(skb); + return 0; + } + } + + netcp->ndev->last_rx = jiffies; + netcp->ndev->stats.rx_packets++; + netcp->ndev->stats.rx_bytes += skb->len; + + /* push skb up the stack */ + skb->protocol = eth_type_trans(skb, netcp->ndev); + netif_receive_skb(skb); + return 0; + +free_desc: + netcp_free_rx_desc_chain(netcp, desc); + netcp->ndev->stats.rx_errors++; + return 0; +} + +static int netcp_process_rx_packets(struct netcp_intf *netcp, + unsigned int budget) +{ + int i; + + for (i = 0; (i < budget) && !netcp_process_one_rx_packet(netcp); i++) + ; + return i; +} + +/* Release descriptors and attached buffers from Rx FDQ */ +static void netcp_free_rx_buf(struct netcp_intf *netcp, int fdq) +{ + struct knav_dma_desc *desc; + unsigned int buf_len, dma_sz; + dma_addr_t dma; + void *buf_ptr; + u32 tmp; + + /* Allocate descriptor */ + while ((dma = knav_queue_pop(netcp->rx_fdq[fdq], &dma_sz))) { + desc = knav_pool_desc_unmap(netcp->rx_pool, dma, dma_sz); + if (unlikely(!desc)) { + dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); + continue; + } + + get_org_pkt_info(&dma, &buf_len, desc); + get_pad_info((u32 *)&buf_ptr, &tmp, desc); + + if (unlikely(!dma)) { + dev_err(netcp->ndev_dev, "NULL orig_buff in desc\n"); + knav_pool_desc_put(netcp->rx_pool, desc); + continue; + } + + if (unlikely(!buf_ptr)) { + dev_err(netcp->ndev_dev, "NULL bufptr in desc\n"); + knav_pool_desc_put(netcp->rx_pool, desc); + continue; + } + + if (fdq == 0) { + dma_unmap_single(netcp->dev, dma, buf_len, + DMA_FROM_DEVICE); + netcp_frag_free((buf_len <= PAGE_SIZE), buf_ptr); + } else { + dma_unmap_page(netcp->dev, dma, buf_len, + DMA_FROM_DEVICE); + __free_page(buf_ptr); + } + + knav_pool_desc_put(netcp->rx_pool, desc); + } +} + +static void netcp_rxpool_free(struct netcp_intf *netcp) +{ + int i; + + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && + !IS_ERR_OR_NULL(netcp->rx_fdq[i]); i++) + netcp_free_rx_buf(netcp, i); + + if (knav_pool_count(netcp->rx_pool) != netcp->rx_pool_size) + dev_err(netcp->ndev_dev, "Lost Rx (%d) descriptors\n", + netcp->rx_pool_size - knav_pool_count(netcp->rx_pool)); + + knav_pool_destroy(netcp->rx_pool); + netcp->rx_pool = NULL; +} + +static void netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq) +{ + struct knav_dma_desc *hwdesc; + unsigned int buf_len, dma_sz; + u32 desc_info, pkt_info; + struct page *page; + dma_addr_t dma; + void *bufptr; + u32 pad[2]; + + /* Allocate descriptor */ + hwdesc = knav_pool_desc_get(netcp->rx_pool); + if (IS_ERR_OR_NULL(hwdesc)) { + dev_dbg(netcp->ndev_dev, "out of rx pool desc\n"); + return; + } + + if (likely(fdq == 0)) { + unsigned int primary_buf_len; + /* Allocate a primary receive queue entry */ + buf_len = netcp->rx_buffer_sizes[0] + NETCP_SOP_OFFSET; + primary_buf_len = SKB_DATA_ALIGN(buf_len) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + if (primary_buf_len <= PAGE_SIZE) { + bufptr = netdev_alloc_frag(primary_buf_len); + pad[1] = primary_buf_len; + } else { + bufptr = kmalloc(primary_buf_len, GFP_ATOMIC | + GFP_DMA32 | __GFP_COLD); + pad[1] = 0; + } + + if (unlikely(!bufptr)) { + dev_warn_ratelimited(netcp->ndev_dev, "Primary RX buffer alloc failed\n"); + goto fail; + } + dma = dma_map_single(netcp->dev, bufptr, buf_len, + DMA_TO_DEVICE); + pad[0] = (u32)bufptr; + + } else { + /* Allocate a secondary receive queue entry */ + page = alloc_page(GFP_ATOMIC | GFP_DMA32 | __GFP_COLD); + if (unlikely(!page)) { + dev_warn_ratelimited(netcp->ndev_dev, "Secondary page alloc failed\n"); + goto fail; + } + buf_len = PAGE_SIZE; + dma = dma_map_page(netcp->dev, page, 0, buf_len, DMA_TO_DEVICE); + pad[0] = (u32)page; + pad[1] = 0; + } + + desc_info = KNAV_DMA_DESC_PS_INFO_IN_DESC; + desc_info |= buf_len & KNAV_DMA_DESC_PKT_LEN_MASK; + pkt_info = KNAV_DMA_DESC_HAS_EPIB; + pkt_info |= KNAV_DMA_NUM_PS_WORDS << KNAV_DMA_DESC_PSLEN_SHIFT; + pkt_info |= (netcp->rx_queue_id & KNAV_DMA_DESC_RETQ_MASK) << + KNAV_DMA_DESC_RETQ_SHIFT; + set_org_pkt_info(dma, buf_len, hwdesc); + set_pad_info(pad[0], pad[1], hwdesc); + set_desc_info(desc_info, pkt_info, hwdesc); + + /* Push to FDQs */ + knav_pool_desc_map(netcp->rx_pool, hwdesc, sizeof(*hwdesc), &dma, + &dma_sz); + knav_queue_push(netcp->rx_fdq[fdq], dma, sizeof(*hwdesc), 0); + return; + +fail: + knav_pool_desc_put(netcp->rx_pool, hwdesc); +} + +/* Refill Rx FDQ with descriptors & attached buffers */ +static void netcp_rxpool_refill(struct netcp_intf *netcp) +{ + u32 fdq_deficit[KNAV_DMA_FDQ_PER_CHAN] = {0}; + int i; + + /* Calculate the FDQ deficit and refill */ + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && netcp->rx_fdq[i]; i++) { + fdq_deficit[i] = netcp->rx_queue_depths[i] - + knav_queue_get_count(netcp->rx_fdq[i]); + + while (fdq_deficit[i]--) + netcp_allocate_rx_buf(netcp, i); + } /* end for fdqs */ +} + +/* NAPI poll */ +static int netcp_rx_poll(struct napi_struct *napi, int budget) +{ + struct netcp_intf *netcp = container_of(napi, struct netcp_intf, + rx_napi); + unsigned int packets; + + packets = netcp_process_rx_packets(netcp, budget); + + if (packets < budget) { + napi_complete(&netcp->rx_napi); + knav_queue_enable_notify(netcp->rx_queue); + } + + netcp_rxpool_refill(netcp); + return packets; +} + +static void netcp_rx_notify(void *arg) +{ + struct netcp_intf *netcp = arg; + + knav_queue_disable_notify(netcp->rx_queue); + napi_schedule(&netcp->rx_napi); +} + +static void netcp_free_tx_desc_chain(struct netcp_intf *netcp, + struct knav_dma_desc *desc, + unsigned int desc_sz) +{ + struct knav_dma_desc *ndesc = desc; + dma_addr_t dma_desc, dma_buf; + unsigned int buf_len; + + while (ndesc) { + get_pkt_info(&dma_buf, &buf_len, &dma_desc, ndesc); + + if (dma_buf && buf_len) + dma_unmap_single(netcp->dev, dma_buf, buf_len, + DMA_TO_DEVICE); + else + dev_warn(netcp->ndev_dev, "bad Tx desc buf(%p), len(%d)\n", + (void *)dma_buf, buf_len); + + knav_pool_desc_put(netcp->tx_pool, ndesc); + ndesc = NULL; + if (dma_desc) { + ndesc = knav_pool_desc_unmap(netcp->tx_pool, dma_desc, + desc_sz); + if (!ndesc) + dev_err(netcp->ndev_dev, "failed to unmap Tx desc\n"); + } + } +} + +static int netcp_process_tx_compl_packets(struct netcp_intf *netcp, + unsigned int budget) +{ + struct knav_dma_desc *desc; + struct sk_buff *skb; + unsigned int dma_sz; + dma_addr_t dma; + int pkts = 0; + u32 tmp; + + while (budget--) { + dma = knav_queue_pop(netcp->tx_compl_q, &dma_sz); + if (!dma) + break; + desc = knav_pool_desc_unmap(netcp->tx_pool, dma, dma_sz); + if (unlikely(!desc)) { + dev_err(netcp->ndev_dev, "failed to unmap Tx desc\n"); + netcp->ndev->stats.tx_errors++; + continue; + } + + get_pad_info((u32 *)&skb, &tmp, desc); + netcp_free_tx_desc_chain(netcp, desc, dma_sz); + if (!skb) { + dev_err(netcp->ndev_dev, "No skb in Tx desc\n"); + netcp->ndev->stats.tx_errors++; + continue; + } + + if (netif_subqueue_stopped(netcp->ndev, skb) && + netif_running(netcp->ndev) && + (knav_pool_count(netcp->tx_pool) > + netcp->tx_resume_threshold)) { + u16 subqueue = skb_get_queue_mapping(skb); + + netif_wake_subqueue(netcp->ndev, subqueue); + } + + netcp->ndev->stats.tx_packets++; + netcp->ndev->stats.tx_bytes += skb->len; + dev_kfree_skb(skb); + pkts++; + } + return pkts; +} + +static int netcp_tx_poll(struct napi_struct *napi, int budget) +{ + int packets; + struct netcp_intf *netcp = container_of(napi, struct netcp_intf, + tx_napi); + + packets = netcp_process_tx_compl_packets(netcp, budget); + if (packets < budget) { + napi_complete(&netcp->tx_napi); + knav_queue_enable_notify(netcp->tx_compl_q); + } + + return packets; +} + +static void netcp_tx_notify(void *arg) +{ + struct netcp_intf *netcp = arg; + + knav_queue_disable_notify(netcp->tx_compl_q); + napi_schedule(&netcp->tx_napi); +} + +static struct knav_dma_desc* +netcp_tx_map_skb(struct sk_buff *skb, struct netcp_intf *netcp) +{ + struct knav_dma_desc *desc, *ndesc, *pdesc; + unsigned int pkt_len = skb_headlen(skb); + struct device *dev = netcp->dev; + dma_addr_t dma_addr; + unsigned int dma_sz; + int i; + + /* Map the linear buffer */ + dma_addr = dma_map_single(dev, skb->data, pkt_len, DMA_TO_DEVICE); + if (unlikely(!dma_addr)) { + dev_err(netcp->ndev_dev, "Failed to map skb buffer\n"); + return NULL; + } + + desc = knav_pool_desc_get(netcp->tx_pool); + if (unlikely(IS_ERR_OR_NULL(desc))) { + dev_err(netcp->ndev_dev, "out of TX desc\n"); + dma_unmap_single(dev, dma_addr, pkt_len, DMA_TO_DEVICE); + return NULL; + } + + set_pkt_info(dma_addr, pkt_len, 0, desc); + if (skb_is_nonlinear(skb)) { + prefetchw(skb_shinfo(skb)); + } else { + desc->next_desc = 0; + goto upd_pkt_len; + } + + pdesc = desc; + + /* Handle the case where skb is fragmented in pages */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct page *page = skb_frag_page(frag); + u32 page_offset = frag->page_offset; + u32 buf_len = skb_frag_size(frag); + dma_addr_t desc_dma; + u32 pkt_info; + + dma_addr = dma_map_page(dev, page, page_offset, buf_len, + DMA_TO_DEVICE); + if (unlikely(!dma_addr)) { + dev_err(netcp->ndev_dev, "Failed to map skb page\n"); + goto free_descs; + } + + ndesc = knav_pool_desc_get(netcp->tx_pool); + if (unlikely(IS_ERR_OR_NULL(ndesc))) { + dev_err(netcp->ndev_dev, "out of TX desc for frags\n"); + dma_unmap_page(dev, dma_addr, buf_len, DMA_TO_DEVICE); + goto free_descs; + } + + desc_dma = knav_pool_desc_virt_to_dma(netcp->tx_pool, + (void *)ndesc); + pkt_info = + (netcp->tx_compl_qid & KNAV_DMA_DESC_RETQ_MASK) << + KNAV_DMA_DESC_RETQ_SHIFT; + set_pkt_info(dma_addr, buf_len, 0, ndesc); + set_words(&desc_dma, 1, &pdesc->next_desc); + pkt_len += buf_len; + if (pdesc != desc) + knav_pool_desc_map(netcp->tx_pool, pdesc, + sizeof(*pdesc), &desc_dma, &dma_sz); + pdesc = ndesc; + } + if (pdesc != desc) + knav_pool_desc_map(netcp->tx_pool, pdesc, sizeof(*pdesc), + &dma_addr, &dma_sz); + + /* frag list based linkage is not supported for now. */ + if (skb_shinfo(skb)->frag_list) { + dev_err_ratelimited(netcp->ndev_dev, "NETIF_F_FRAGLIST not supported\n"); + goto free_descs; + } + +upd_pkt_len: + WARN_ON(pkt_len != skb->len); + + pkt_len &= KNAV_DMA_DESC_PKT_LEN_MASK; + set_words(&pkt_len, 1, &desc->desc_info); + return desc; + +free_descs: + netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc)); + return NULL; +} + +static int netcp_tx_submit_skb(struct netcp_intf *netcp, + struct sk_buff *skb, + struct knav_dma_desc *desc) +{ + struct netcp_tx_pipe *tx_pipe = NULL; + struct netcp_hook_list *tx_hook; + struct netcp_packet p_info; + u32 packet_info = 0; + unsigned int dma_sz; + dma_addr_t dma; + int ret = 0; + + p_info.netcp = netcp; + p_info.skb = skb; + p_info.tx_pipe = NULL; + p_info.psdata_len = 0; + p_info.ts_context = NULL; + p_info.txtstamp_complete = NULL; + p_info.epib = desc->epib; + p_info.psdata = desc->psdata; + memset(p_info.epib, 0, KNAV_DMA_NUM_EPIB_WORDS * sizeof(u32)); + + /* Find out where to inject the packet for transmission */ + list_for_each_entry(tx_hook, &netcp->txhook_list_head, list) { + ret = tx_hook->hook_rtn(tx_hook->order, tx_hook->hook_data, + &p_info); + if (unlikely(ret != 0)) { + dev_err(netcp->ndev_dev, "TX hook %d rejected the packet with reason(%d)\n", + tx_hook->order, ret); + ret = (ret < 0) ? ret : NETDEV_TX_OK; + goto out; + } + } + + /* Make sure some TX hook claimed the packet */ + tx_pipe = p_info.tx_pipe; + if (!tx_pipe) { + dev_err(netcp->ndev_dev, "No TX hook claimed the packet!\n"); + ret = -ENXIO; + goto out; + } + + /* update descriptor */ + if (p_info.psdata_len) { + u32 *psdata = p_info.psdata; + + memmove(p_info.psdata, p_info.psdata + p_info.psdata_len, + p_info.psdata_len); + set_words(psdata, p_info.psdata_len, psdata); + packet_info |= + (p_info.psdata_len & KNAV_DMA_DESC_PSLEN_MASK) << + KNAV_DMA_DESC_PSLEN_SHIFT; + } + + packet_info |= KNAV_DMA_DESC_HAS_EPIB | + ((netcp->tx_compl_qid & KNAV_DMA_DESC_RETQ_MASK) << + KNAV_DMA_DESC_RETQ_SHIFT) | + ((tx_pipe->dma_psflags & KNAV_DMA_DESC_PSFLAG_MASK) << + KNAV_DMA_DESC_PSFLAG_SHIFT); + + set_words(&packet_info, 1, &desc->packet_info); + set_words((u32 *)&skb, 1, &desc->pad[0]); + + /* submit packet descriptor */ + ret = knav_pool_desc_map(netcp->tx_pool, desc, sizeof(*desc), &dma, + &dma_sz); + if (unlikely(ret)) { + dev_err(netcp->ndev_dev, "%s() failed to map desc\n", __func__); + ret = -ENOMEM; + goto out; + } + skb_tx_timestamp(skb); + knav_queue_push(tx_pipe->dma_queue, dma, dma_sz, 0); + +out: + return ret; +} + +/* Submit the packet */ +static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + int subqueue = skb_get_queue_mapping(skb); + struct knav_dma_desc *desc; + int desc_count, ret = 0; + + if (unlikely(skb->len <= 0)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + if (unlikely(skb->len < NETCP_MIN_PACKET_SIZE)) { + ret = skb_padto(skb, NETCP_MIN_PACKET_SIZE); + if (ret < 0) { + /* If we get here, the skb has already been dropped */ + dev_warn(netcp->ndev_dev, "padding failed (%d), packet dropped\n", + ret); + ndev->stats.tx_dropped++; + return ret; + } + skb->len = NETCP_MIN_PACKET_SIZE; + } + + desc = netcp_tx_map_skb(skb, netcp); + if (unlikely(!desc)) { + netif_stop_subqueue(ndev, subqueue); + ret = -ENOBUFS; + goto drop; + } + + ret = netcp_tx_submit_skb(netcp, skb, desc); + if (ret) + goto drop; + + ndev->trans_start = jiffies; + + /* Check Tx pool count & stop subqueue if needed */ + desc_count = knav_pool_count(netcp->tx_pool); + if (desc_count < netcp->tx_pause_threshold) { + dev_dbg(netcp->ndev_dev, "pausing tx, count(%d)\n", desc_count); + netif_stop_subqueue(ndev, subqueue); + } + return NETDEV_TX_OK; + +drop: + ndev->stats.tx_dropped++; + if (desc) + netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc)); + dev_kfree_skb(skb); + return ret; +} + +int netcp_txpipe_close(struct netcp_tx_pipe *tx_pipe) +{ + if (tx_pipe->dma_channel) { + knav_dma_close_channel(tx_pipe->dma_channel); + tx_pipe->dma_channel = NULL; + } + return 0; +} + +int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe) +{ + struct device *dev = tx_pipe->netcp_device->device; + struct knav_dma_cfg config; + int ret = 0; + u8 name[16]; + + memset(&config, 0, sizeof(config)); + config.direction = DMA_MEM_TO_DEV; + config.u.tx.filt_einfo = false; + config.u.tx.filt_pswords = false; + config.u.tx.priority = DMA_PRIO_MED_L; + + tx_pipe->dma_channel = knav_dma_open_channel(dev, + tx_pipe->dma_chan_name, &config); + if (IS_ERR_OR_NULL(tx_pipe->dma_channel)) { + dev_err(dev, "failed opening tx chan(%s)\n", + tx_pipe->dma_chan_name); + goto err; + } + + snprintf(name, sizeof(name), "tx-pipe-%s", dev_name(dev)); + tx_pipe->dma_queue = knav_queue_open(name, tx_pipe->dma_queue_id, + KNAV_QUEUE_SHARED); + if (IS_ERR(tx_pipe->dma_queue)) { + dev_err(dev, "Could not open DMA queue for channel \"%s\": %d\n", + name, ret); + ret = PTR_ERR(tx_pipe->dma_queue); + goto err; + } + + dev_dbg(dev, "opened tx pipe %s\n", name); + return 0; + +err: + if (!IS_ERR_OR_NULL(tx_pipe->dma_channel)) + knav_dma_close_channel(tx_pipe->dma_channel); + tx_pipe->dma_channel = NULL; + return ret; +} + +int netcp_txpipe_init(struct netcp_tx_pipe *tx_pipe, + struct netcp_device *netcp_device, + const char *dma_chan_name, unsigned int dma_queue_id) +{ + memset(tx_pipe, 0, sizeof(*tx_pipe)); + tx_pipe->netcp_device = netcp_device; + tx_pipe->dma_chan_name = dma_chan_name; + tx_pipe->dma_queue_id = dma_queue_id; + return 0; +} + +static struct netcp_addr *netcp_addr_find(struct netcp_intf *netcp, + const u8 *addr, + enum netcp_addr_type type) +{ + struct netcp_addr *naddr; + + list_for_each_entry(naddr, &netcp->addr_list, node) { + if (naddr->type != type) + continue; + if (addr && memcmp(addr, naddr->addr, ETH_ALEN)) + continue; + return naddr; + } + + return NULL; +} + +static struct netcp_addr *netcp_addr_add(struct netcp_intf *netcp, + const u8 *addr, + enum netcp_addr_type type) +{ + struct netcp_addr *naddr; + + naddr = devm_kmalloc(netcp->dev, sizeof(*naddr), GFP_ATOMIC); + if (!naddr) + return NULL; + + naddr->type = type; + naddr->flags = 0; + naddr->netcp = netcp; + if (addr) + ether_addr_copy(naddr->addr, addr); + else + memset(naddr->addr, 0, ETH_ALEN); + list_add_tail(&naddr->node, &netcp->addr_list); + + return naddr; +} + +static void netcp_addr_del(struct netcp_intf *netcp, struct netcp_addr *naddr) +{ + list_del(&naddr->node); + devm_kfree(netcp->dev, naddr); +} + +static void netcp_addr_clear_mark(struct netcp_intf *netcp) +{ + struct netcp_addr *naddr; + + list_for_each_entry(naddr, &netcp->addr_list, node) + naddr->flags = 0; +} + +static void netcp_addr_add_mark(struct netcp_intf *netcp, const u8 *addr, + enum netcp_addr_type type) +{ + struct netcp_addr *naddr; + + naddr = netcp_addr_find(netcp, addr, type); + if (naddr) { + naddr->flags |= ADDR_VALID; + return; + } + + naddr = netcp_addr_add(netcp, addr, type); + if (!WARN_ON(!naddr)) + naddr->flags |= ADDR_NEW; +} + +static void netcp_addr_sweep_del(struct netcp_intf *netcp) +{ + struct netcp_addr *naddr, *tmp; + struct netcp_intf_modpriv *priv; + struct netcp_module *module; + int error; + + list_for_each_entry_safe(naddr, tmp, &netcp->addr_list, node) { + if (naddr->flags & (ADDR_VALID | ADDR_NEW)) + continue; + dev_dbg(netcp->ndev_dev, "deleting address %pM, type %x\n", + naddr->addr, naddr->type); + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, priv) { + module = priv->netcp_module; + if (!module->del_addr) + continue; + error = module->del_addr(priv->module_priv, + naddr); + WARN_ON(error); + } + mutex_unlock(&netcp_modules_lock); + netcp_addr_del(netcp, naddr); + } +} + +static void netcp_addr_sweep_add(struct netcp_intf *netcp) +{ + struct netcp_addr *naddr, *tmp; + struct netcp_intf_modpriv *priv; + struct netcp_module *module; + int error; + + list_for_each_entry_safe(naddr, tmp, &netcp->addr_list, node) { + if (!(naddr->flags & ADDR_NEW)) + continue; + dev_dbg(netcp->ndev_dev, "adding address %pM, type %x\n", + naddr->addr, naddr->type); + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, priv) { + module = priv->netcp_module; + if (!module->add_addr) + continue; + error = module->add_addr(priv->module_priv, naddr); + WARN_ON(error); + } + mutex_unlock(&netcp_modules_lock); + } +} + +static void netcp_set_rx_mode(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netdev_hw_addr *ndev_addr; + bool promisc; + + promisc = (ndev->flags & IFF_PROMISC || + ndev->flags & IFF_ALLMULTI || + netdev_mc_count(ndev) > NETCP_MAX_MCAST_ADDR); + + /* first clear all marks */ + netcp_addr_clear_mark(netcp); + + /* next add new entries, mark existing ones */ + netcp_addr_add_mark(netcp, ndev->broadcast, ADDR_BCAST); + for_each_dev_addr(ndev, ndev_addr) + netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_DEV); + netdev_for_each_uc_addr(ndev_addr, ndev) + netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_UCAST); + netdev_for_each_mc_addr(ndev_addr, ndev) + netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_MCAST); + + if (promisc) + netcp_addr_add_mark(netcp, NULL, ADDR_ANY); + + /* finally sweep and callout into modules */ + netcp_addr_sweep_del(netcp); + netcp_addr_sweep_add(netcp); +} + +static void netcp_free_navigator_resources(struct netcp_intf *netcp) +{ + int i; + + if (netcp->rx_channel) { + knav_dma_close_channel(netcp->rx_channel); + netcp->rx_channel = NULL; + } + + if (!IS_ERR_OR_NULL(netcp->rx_pool)) + netcp_rxpool_free(netcp); + + if (!IS_ERR_OR_NULL(netcp->rx_queue)) { + knav_queue_close(netcp->rx_queue); + netcp->rx_queue = NULL; + } + + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && + !IS_ERR_OR_NULL(netcp->rx_fdq[i]) ; ++i) { + knav_queue_close(netcp->rx_fdq[i]); + netcp->rx_fdq[i] = NULL; + } + + if (!IS_ERR_OR_NULL(netcp->tx_compl_q)) { + knav_queue_close(netcp->tx_compl_q); + netcp->tx_compl_q = NULL; + } + + if (!IS_ERR_OR_NULL(netcp->tx_pool)) { + knav_pool_destroy(netcp->tx_pool); + netcp->tx_pool = NULL; + } +} + +static int netcp_setup_navigator_resources(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct knav_queue_notify_config notify_cfg; + struct knav_dma_cfg config; + u32 last_fdq = 0; + u8 name[16]; + int ret; + int i; + + /* Create Rx/Tx descriptor pools */ + snprintf(name, sizeof(name), "rx-pool-%s", ndev->name); + netcp->rx_pool = knav_pool_create(name, netcp->rx_pool_size, + netcp->rx_pool_region_id); + if (IS_ERR_OR_NULL(netcp->rx_pool)) { + dev_err(netcp->ndev_dev, "Couldn't create rx pool\n"); + ret = PTR_ERR(netcp->rx_pool); + goto fail; + } + + snprintf(name, sizeof(name), "tx-pool-%s", ndev->name); + netcp->tx_pool = knav_pool_create(name, netcp->tx_pool_size, + netcp->tx_pool_region_id); + if (IS_ERR_OR_NULL(netcp->tx_pool)) { + dev_err(netcp->ndev_dev, "Couldn't create tx pool\n"); + ret = PTR_ERR(netcp->tx_pool); + goto fail; + } + + /* open Tx completion queue */ + snprintf(name, sizeof(name), "tx-compl-%s", ndev->name); + netcp->tx_compl_q = knav_queue_open(name, netcp->tx_compl_qid, 0); + if (IS_ERR_OR_NULL(netcp->tx_compl_q)) { + ret = PTR_ERR(netcp->tx_compl_q); + goto fail; + } + netcp->tx_compl_qid = knav_queue_get_id(netcp->tx_compl_q); + + /* Set notification for Tx completion */ + notify_cfg.fn = netcp_tx_notify; + notify_cfg.fn_arg = netcp; + ret = knav_queue_device_control(netcp->tx_compl_q, + KNAV_QUEUE_SET_NOTIFIER, + (unsigned long)¬ify_cfg); + if (ret) + goto fail; + + knav_queue_disable_notify(netcp->tx_compl_q); + + /* open Rx completion queue */ + snprintf(name, sizeof(name), "rx-compl-%s", ndev->name); + netcp->rx_queue = knav_queue_open(name, netcp->rx_queue_id, 0); + if (IS_ERR_OR_NULL(netcp->rx_queue)) { + ret = PTR_ERR(netcp->rx_queue); + goto fail; + } + netcp->rx_queue_id = knav_queue_get_id(netcp->rx_queue); + + /* Set notification for Rx completion */ + notify_cfg.fn = netcp_rx_notify; + notify_cfg.fn_arg = netcp; + ret = knav_queue_device_control(netcp->rx_queue, + KNAV_QUEUE_SET_NOTIFIER, + (unsigned long)¬ify_cfg); + if (ret) + goto fail; + + knav_queue_disable_notify(netcp->rx_queue); + + /* open Rx FDQs */ + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && + netcp->rx_queue_depths[i] && netcp->rx_buffer_sizes[i]; ++i) { + snprintf(name, sizeof(name), "rx-fdq-%s-%d", ndev->name, i); + netcp->rx_fdq[i] = knav_queue_open(name, KNAV_QUEUE_GP, 0); + if (IS_ERR_OR_NULL(netcp->rx_fdq[i])) { + ret = PTR_ERR(netcp->rx_fdq[i]); + goto fail; + } + } + + memset(&config, 0, sizeof(config)); + config.direction = DMA_DEV_TO_MEM; + config.u.rx.einfo_present = true; + config.u.rx.psinfo_present = true; + config.u.rx.err_mode = DMA_DROP; + config.u.rx.desc_type = DMA_DESC_HOST; + config.u.rx.psinfo_at_sop = false; + config.u.rx.sop_offset = NETCP_SOP_OFFSET; + config.u.rx.dst_q = netcp->rx_queue_id; + config.u.rx.thresh = DMA_THRESH_NONE; + + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN; ++i) { + if (netcp->rx_fdq[i]) + last_fdq = knav_queue_get_id(netcp->rx_fdq[i]); + config.u.rx.fdq[i] = last_fdq; + } + + netcp->rx_channel = knav_dma_open_channel(netcp->netcp_device->device, + netcp->dma_chan_name, &config); + if (IS_ERR_OR_NULL(netcp->rx_channel)) { + dev_err(netcp->ndev_dev, "failed opening rx chan(%s\n", + netcp->dma_chan_name); + goto fail; + } + + dev_dbg(netcp->ndev_dev, "opened RX channel: %p\n", netcp->rx_channel); + return 0; + +fail: + netcp_free_navigator_resources(netcp); + return ret; +} + +/* Open the device */ +static int netcp_ndo_open(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_intf_modpriv *intf_modpriv; + struct netcp_module *module; + int ret; + + netif_carrier_off(ndev); + ret = netcp_setup_navigator_resources(ndev); + if (ret) { + dev_err(netcp->ndev_dev, "Failed to setup navigator resources\n"); + goto fail; + } + + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if (module->open) { + ret = module->open(intf_modpriv->module_priv, ndev); + if (ret != 0) { + dev_err(netcp->ndev_dev, "module open failed\n"); + goto fail_open; + } + } + } + mutex_unlock(&netcp_modules_lock); + + netcp_rxpool_refill(netcp); + napi_enable(&netcp->rx_napi); + napi_enable(&netcp->tx_napi); + knav_queue_enable_notify(netcp->tx_compl_q); + knav_queue_enable_notify(netcp->rx_queue); + netif_tx_wake_all_queues(ndev); + dev_dbg(netcp->ndev_dev, "netcp device %s opened\n", ndev->name); + return 0; + +fail_open: + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if (module->close) + module->close(intf_modpriv->module_priv, ndev); + } + mutex_unlock(&netcp_modules_lock); + +fail: + netcp_free_navigator_resources(netcp); + return ret; +} + +/* Close the device */ +static int netcp_ndo_stop(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_intf_modpriv *intf_modpriv; + struct netcp_module *module; + int err = 0; + + netif_tx_stop_all_queues(ndev); + netif_carrier_off(ndev); + netcp_addr_clear_mark(netcp); + netcp_addr_sweep_del(netcp); + knav_queue_disable_notify(netcp->rx_queue); + knav_queue_disable_notify(netcp->tx_compl_q); + napi_disable(&netcp->rx_napi); + napi_disable(&netcp->tx_napi); + + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if (module->close) { + err = module->close(intf_modpriv->module_priv, ndev); + if (err != 0) + dev_err(netcp->ndev_dev, "Close failed\n"); + } + } + mutex_unlock(&netcp_modules_lock); + + /* Recycle Rx descriptors from completion queue */ + netcp_empty_rx_queue(netcp); + + /* Recycle Tx descriptors from completion queue */ + netcp_process_tx_compl_packets(netcp, netcp->tx_pool_size); + + if (knav_pool_count(netcp->tx_pool) != netcp->tx_pool_size) + dev_err(netcp->ndev_dev, "Lost (%d) Tx descs\n", + netcp->tx_pool_size - knav_pool_count(netcp->tx_pool)); + + netcp_free_navigator_resources(netcp); + dev_dbg(netcp->ndev_dev, "netcp device %s stopped\n", ndev->name); + return 0; +} + +static int netcp_ndo_ioctl(struct net_device *ndev, + struct ifreq *req, int cmd) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_intf_modpriv *intf_modpriv; + struct netcp_module *module; + int ret = -1, err = -EOPNOTSUPP; + + if (!netif_running(ndev)) + return -EINVAL; + + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if (!module->ioctl) + continue; + + err = module->ioctl(intf_modpriv->module_priv, req, cmd); + if ((err < 0) && (err != -EOPNOTSUPP)) { + ret = err; + goto out; + } + if (err == 0) + ret = err; + } + +out: + mutex_unlock(&netcp_modules_lock); + return (ret == 0) ? 0 : err; +} + +static int netcp_ndo_change_mtu(struct net_device *ndev, int new_mtu) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + + /* MTU < 68 is an error for IPv4 traffic */ + if ((new_mtu < 68) || + (new_mtu > (NETCP_MAX_FRAME_SIZE - ETH_HLEN - ETH_FCS_LEN))) { + dev_err(netcp->ndev_dev, "Invalid mtu size = %d\n", new_mtu); + return -EINVAL; + } + + ndev->mtu = new_mtu; + return 0; +} + +static void netcp_ndo_tx_timeout(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + unsigned int descs = knav_pool_count(netcp->tx_pool); + + dev_err(netcp->ndev_dev, "transmit timed out tx descs(%d)\n", descs); + netcp_process_tx_compl_packets(netcp, netcp->tx_pool_size); + ndev->trans_start = jiffies; + netif_tx_wake_all_queues(ndev); +} + +static int netcp_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_intf_modpriv *intf_modpriv; + struct netcp_module *module; + int err = 0; + + dev_dbg(netcp->ndev_dev, "adding rx vlan id: %d\n", vid); + + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if ((module->add_vid) && (vid != 0)) { + err = module->add_vid(intf_modpriv->module_priv, vid); + if (err != 0) { + dev_err(netcp->ndev_dev, "Could not add vlan id = %d\n", + vid); + break; + } + } + } + mutex_unlock(&netcp_modules_lock); + return err; +} + +static int netcp_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_intf_modpriv *intf_modpriv; + struct netcp_module *module; + int err = 0; + + dev_dbg(netcp->ndev_dev, "removing rx vlan id: %d\n", vid); + + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if (module->del_vid) { + err = module->del_vid(intf_modpriv->module_priv, vid); + if (err != 0) { + dev_err(netcp->ndev_dev, "Could not delete vlan id = %d\n", + vid); + break; + } + } + } + mutex_unlock(&netcp_modules_lock); + return err; +} + +static u16 netcp_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, + select_queue_fallback_t fallback) +{ + return 0; +} + +static int netcp_setup_tc(struct net_device *dev, u8 num_tc) +{ + int i; + + /* setup tc must be called under rtnl lock */ + ASSERT_RTNL(); + + /* Sanity-check the number of traffic classes requested */ + if ((dev->real_num_tx_queues <= 1) || + (dev->real_num_tx_queues < num_tc)) + return -EINVAL; + + /* Configure traffic class to queue mappings */ + if (num_tc) { + netdev_set_num_tc(dev, num_tc); + for (i = 0; i < num_tc; i++) + netdev_set_tc_queue(dev, i, 1, i); + } else { + netdev_reset_tc(dev); + } + + return 0; +} + +static const struct net_device_ops netcp_netdev_ops = { + .ndo_open = netcp_ndo_open, + .ndo_stop = netcp_ndo_stop, + .ndo_start_xmit = netcp_ndo_start_xmit, + .ndo_set_rx_mode = netcp_set_rx_mode, + .ndo_do_ioctl = netcp_ndo_ioctl, + .ndo_change_mtu = netcp_ndo_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_vlan_rx_add_vid = netcp_rx_add_vid, + .ndo_vlan_rx_kill_vid = netcp_rx_kill_vid, + .ndo_tx_timeout = netcp_ndo_tx_timeout, + .ndo_select_queue = netcp_select_queue, + .ndo_setup_tc = netcp_setup_tc, +}; + +static int netcp_create_interface(struct netcp_device *netcp_device, + struct device_node *node_interface) +{ + struct device *dev = netcp_device->device; + struct device_node *node = dev->of_node; + struct netcp_intf *netcp; + struct net_device *ndev; + resource_size_t size; + struct resource res; + void __iomem *efuse = NULL; + u32 efuse_mac = 0; + const void *mac_addr; + u8 efuse_mac_addr[6]; + u32 temp[2]; + int ret = 0; + + ndev = alloc_etherdev_mqs(sizeof(*netcp), 1, 1); + if (!ndev) { + dev_err(dev, "Error allocating netdev\n"); + return -ENOMEM; + } + + ndev->features |= NETIF_F_SG; + ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + ndev->hw_features = ndev->features; + ndev->vlan_features |= NETIF_F_SG; + + netcp = netdev_priv(ndev); + spin_lock_init(&netcp->lock); + INIT_LIST_HEAD(&netcp->module_head); + INIT_LIST_HEAD(&netcp->txhook_list_head); + INIT_LIST_HEAD(&netcp->rxhook_list_head); + INIT_LIST_HEAD(&netcp->addr_list); + netcp->netcp_device = netcp_device; + netcp->dev = netcp_device->device; + netcp->ndev = ndev; + netcp->ndev_dev = &ndev->dev; + netcp->msg_enable = netif_msg_init(netcp_debug_level, NETCP_DEBUG); + netcp->tx_pause_threshold = MAX_SKB_FRAGS; + netcp->tx_resume_threshold = netcp->tx_pause_threshold; + netcp->node_interface = node_interface; + + ret = of_property_read_u32(node_interface, "efuse-mac", &efuse_mac); + if (efuse_mac) { + if (of_address_to_resource(node, NETCP_EFUSE_REG_INDEX, &res)) { + dev_err(dev, "could not find efuse-mac reg resource\n"); + ret = -ENODEV; + goto quit; + } + size = resource_size(&res); + + if (!devm_request_mem_region(dev, res.start, size, + dev_name(dev))) { + dev_err(dev, "could not reserve resource\n"); + ret = -ENOMEM; + goto quit; + } + + efuse = devm_ioremap_nocache(dev, res.start, size); + if (!efuse) { + dev_err(dev, "could not map resource\n"); + devm_release_mem_region(dev, res.start, size); + ret = -ENOMEM; + goto quit; + } + + emac_arch_get_mac_addr(efuse_mac_addr, efuse); + if (is_valid_ether_addr(efuse_mac_addr)) + ether_addr_copy(ndev->dev_addr, efuse_mac_addr); + else + random_ether_addr(ndev->dev_addr); + + devm_iounmap(dev, efuse); + devm_release_mem_region(dev, res.start, size); + } else { + mac_addr = of_get_mac_address(node_interface); + if (mac_addr) + ether_addr_copy(ndev->dev_addr, mac_addr); + else + random_ether_addr(ndev->dev_addr); + } + + ret = of_property_read_string(node_interface, "rx-channel", + &netcp->dma_chan_name); + if (ret < 0) { + dev_err(dev, "missing \"rx-channel\" parameter\n"); + ret = -ENODEV; + goto quit; + } + + ret = of_property_read_u32(node_interface, "rx-queue", + &netcp->rx_queue_id); + if (ret < 0) { + dev_warn(dev, "missing \"rx-queue\" parameter\n"); + netcp->rx_queue_id = KNAV_QUEUE_QPEND; + } + + ret = of_property_read_u32_array(node_interface, "rx-queue-depth", + netcp->rx_queue_depths, + KNAV_DMA_FDQ_PER_CHAN); + if (ret < 0) { + dev_err(dev, "missing \"rx-queue-depth\" parameter\n"); + netcp->rx_queue_depths[0] = 128; + } + + ret = of_property_read_u32_array(node_interface, "rx-buffer-size", + netcp->rx_buffer_sizes, + KNAV_DMA_FDQ_PER_CHAN); + if (ret) { + dev_err(dev, "missing \"rx-buffer-size\" parameter\n"); + netcp->rx_buffer_sizes[0] = 1536; + } + + ret = of_property_read_u32_array(node_interface, "rx-pool", temp, 2); + if (ret < 0) { + dev_err(dev, "missing \"rx-pool\" parameter\n"); + ret = -ENODEV; + goto quit; + } + netcp->rx_pool_size = temp[0]; + netcp->rx_pool_region_id = temp[1]; + + ret = of_property_read_u32_array(node_interface, "tx-pool", temp, 2); + if (ret < 0) { + dev_err(dev, "missing \"tx-pool\" parameter\n"); + ret = -ENODEV; + goto quit; + } + netcp->tx_pool_size = temp[0]; + netcp->tx_pool_region_id = temp[1]; + + if (netcp->tx_pool_size < MAX_SKB_FRAGS) { + dev_err(dev, "tx-pool size too small, must be atleast(%ld)\n", + MAX_SKB_FRAGS); + ret = -ENODEV; + goto quit; + } + + ret = of_property_read_u32(node_interface, "tx-completion-queue", + &netcp->tx_compl_qid); + if (ret < 0) { + dev_warn(dev, "missing \"tx-completion-queue\" parameter\n"); + netcp->tx_compl_qid = KNAV_QUEUE_QPEND; + } + + /* NAPI register */ + netif_napi_add(ndev, &netcp->rx_napi, netcp_rx_poll, NETCP_NAPI_WEIGHT); + netif_napi_add(ndev, &netcp->tx_napi, netcp_tx_poll, NETCP_NAPI_WEIGHT); + + /* Register the network device */ + ndev->dev_id = 0; + ndev->watchdog_timeo = NETCP_TX_TIMEOUT; + ndev->netdev_ops = &netcp_netdev_ops; + SET_NETDEV_DEV(ndev, dev); + + list_add_tail(&netcp->interface_list, &netcp_device->interface_head); + return 0; + +quit: + free_netdev(ndev); + return ret; +} + +static void netcp_delete_interface(struct netcp_device *netcp_device, + struct net_device *ndev) +{ + struct netcp_intf_modpriv *intf_modpriv, *tmp; + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_module *module; + + dev_dbg(netcp_device->device, "Removing interface \"%s\"\n", + ndev->name); + + /* Notify each of the modules that the interface is going away */ + list_for_each_entry_safe(intf_modpriv, tmp, &netcp->module_head, + intf_list) { + module = intf_modpriv->netcp_module; + dev_dbg(netcp_device->device, "Releasing module \"%s\"\n", + module->name); + if (module->release) + module->release(intf_modpriv->module_priv); + list_del(&intf_modpriv->intf_list); + kfree(intf_modpriv); + } + WARN(!list_empty(&netcp->module_head), "%s interface module list is not empty!\n", + ndev->name); + + list_del(&netcp->interface_list); + + of_node_put(netcp->node_interface); + unregister_netdev(ndev); + netif_napi_del(&netcp->rx_napi); + free_netdev(ndev); +} + +static int netcp_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct netcp_intf *netcp_intf, *netcp_tmp; + struct device_node *child, *interfaces; + struct netcp_device *netcp_device; + struct device *dev = &pdev->dev; + struct netcp_module *module; + int ret; + + if (!node) { + dev_err(dev, "could not find device info\n"); + return -ENODEV; + } + + /* Allocate a new NETCP device instance */ + netcp_device = devm_kzalloc(dev, sizeof(*netcp_device), GFP_KERNEL); + if (!netcp_device) + return -ENOMEM; + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(dev, "Failed to enable NETCP power-domain\n"); + pm_runtime_disable(&pdev->dev); + return ret; + } + + /* Initialize the NETCP device instance */ + INIT_LIST_HEAD(&netcp_device->interface_head); + INIT_LIST_HEAD(&netcp_device->modpriv_head); + netcp_device->device = dev; + platform_set_drvdata(pdev, netcp_device); + + /* create interfaces */ + interfaces = of_get_child_by_name(node, "netcp-interfaces"); + if (!interfaces) { + dev_err(dev, "could not find netcp-interfaces node\n"); + ret = -ENODEV; + goto probe_quit; + } + + for_each_available_child_of_node(interfaces, child) { + ret = netcp_create_interface(netcp_device, child); + if (ret) { + dev_err(dev, "could not create interface(%s)\n", + child->name); + goto probe_quit_interface; + } + } + + /* Add the device instance to the list */ + list_add_tail(&netcp_device->device_list, &netcp_devices); + + /* Probe & attach any modules already registered */ + mutex_lock(&netcp_modules_lock); + for_each_netcp_module(module) { + ret = netcp_module_probe(netcp_device, module); + if (ret < 0) + dev_err(dev, "module(%s) probe failed\n", module->name); + } + mutex_unlock(&netcp_modules_lock); + return 0; + +probe_quit_interface: + list_for_each_entry_safe(netcp_intf, netcp_tmp, + &netcp_device->interface_head, + interface_list) { + netcp_delete_interface(netcp_device, netcp_intf->ndev); + } + +probe_quit: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + platform_set_drvdata(pdev, NULL); + return ret; +} + +static int netcp_remove(struct platform_device *pdev) +{ + struct netcp_device *netcp_device = platform_get_drvdata(pdev); + struct netcp_inst_modpriv *inst_modpriv, *tmp; + struct netcp_module *module; + + list_for_each_entry_safe(inst_modpriv, tmp, &netcp_device->modpriv_head, + inst_list) { + module = inst_modpriv->netcp_module; + dev_dbg(&pdev->dev, "Removing module \"%s\"\n", module->name); + module->remove(netcp_device, inst_modpriv->module_priv); + list_del(&inst_modpriv->inst_list); + kfree(inst_modpriv); + } + WARN(!list_empty(&netcp_device->interface_head), "%s interface list not empty!\n", + pdev->name); + + devm_kfree(&pdev->dev, netcp_device); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct of_device_id of_match[] = { + { .compatible = "ti,netcp-1.0", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_match); + +static struct platform_driver netcp_driver = { + .driver = { + .name = "netcp-1.0", + .owner = THIS_MODULE, + .of_match_table = of_match, + }, + .probe = netcp_probe, + .remove = netcp_remove, +}; +module_platform_driver(netcp_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI NETCP driver for Keystone SOCs"); +MODULE_AUTHOR("Sandeep Nair Date: Thu, 15 Jan 2015 19:12:51 -0500 Subject: net: netcp: Add Keystone NetCP GbE driver This patch add support for 1G Ethernet driver based on Keystone NetCP hardware. The gigabit Ethernet (GbE) switch subsystem is one of the main components of the network coprocessor (NETCP) peripheral. The purpose of the gigabit Ethernet switch subsystem in the NETCP is to provide an interface to transfer data between the host device and another connected device in compliance with the Ethernet protocol. GbE consists of 5 port Ethernet Switch module, 4 Serial Gigabit Media Independent Interface (SGMII) modules, MDIO module and SerDes. Driver for 5 port GbE switch and SGMII module is added in this patch. These hardware modules along with netcp core driver provides Network driver functions for 1G Ethernet. Detailed hardware spec is available at http://www.ti.com/lit/ug/sprugv9d/sprugv9d.pdf Cc: David Miller Cc: Rob Herring Cc: Grant Likely Cc: Santosh Shilimkar Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Signed-off-by: Wingman Kwok Signed-off-by: Murali Karicheri Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/Makefile | 3 +- drivers/net/ethernet/ti/netcp_ethss.c | 1714 +++++++++++++++++++++++++++++++++ drivers/net/ethernet/ti/netcp_sgmii.c | 131 +++ 3 files changed, 1847 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/ti/netcp_ethss.c create mode 100644 drivers/net/ethernet/ti/netcp_sgmii.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 4e8a8e41f69f..6d4dde8d8fdc 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -12,4 +12,5 @@ obj-$(CONFIG_TI_CPSW) += ti_cpsw.o ti_cpsw-y := cpsw_ale.o cpsw.o cpts.o obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o -keystone_netcp-y := netcp_core.o +keystone_netcp-y := netcp_core.o netcp_ethss.o netcp_sgmii.o \ + cpsw_ale.o cpts.o diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c new file mode 100644 index 000000000000..58f00c572546 --- /dev/null +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -0,0 +1,1714 @@ +/* + * Keystone GBE subsystem code + * + * Copyright (C) 2014 Texas Instruments Incorporated + * Authors: Sandeep Nair + * Sandeep Paulraj + * Cyril Chemparathy + * Santosh Shilimkar + * Wingman Kwok + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "cpsw_ale.h" +#include "netcp.h" + +#define NETCP_DRIVER_NAME "TI KeyStone Ethernet Driver" +#define NETCP_DRIVER_VERSION "v1.0" + +#define GBE_IDENT(reg) ((reg >> 16) & 0xffff) +#define GBE_MAJOR_VERSION(reg) (reg >> 8 & 0x7) +#define GBE_MINOR_VERSION(reg) (reg & 0xff) +#define GBE_RTL_VERSION(reg) ((reg >> 11) & 0x1f) + +/* 1G Ethernet SS defines */ +#define GBE_MODULE_NAME "netcp-gbe" +#define GBE_SS_VERSION_14 0x4ed21104 + +#define GBE13_SGMII_MODULE_OFFSET 0x100 +#define GBE13_SGMII34_MODULE_OFFSET 0x400 +#define GBE13_SWITCH_MODULE_OFFSET 0x800 +#define GBE13_HOST_PORT_OFFSET 0x834 +#define GBE13_SLAVE_PORT_OFFSET 0x860 +#define GBE13_EMAC_OFFSET 0x900 +#define GBE13_SLAVE_PORT2_OFFSET 0xa00 +#define GBE13_HW_STATS_OFFSET 0xb00 +#define GBE13_ALE_OFFSET 0xe00 +#define GBE13_HOST_PORT_NUM 0 +#define GBE13_NUM_SLAVES 4 +#define GBE13_NUM_ALE_PORTS (GBE13_NUM_SLAVES + 1) +#define GBE13_NUM_ALE_ENTRIES 1024 + +#define GBE_TIMER_INTERVAL (HZ / 2) + +/* Soft reset register values */ +#define SOFT_RESET_MASK BIT(0) +#define SOFT_RESET BIT(0) +#define DEVICE_EMACSL_RESET_POLL_COUNT 100 +#define GMACSL_RET_WARN_RESET_INCOMPLETE -2 + +#define MACSL_RX_ENABLE_CSF BIT(23) +#define MACSL_ENABLE_EXT_CTL BIT(18) +#define MACSL_GIG_MODE BIT(7) +#define MACSL_GMII_ENABLE BIT(5) +#define MACSL_FULLDUPLEX BIT(0) + +#define GBE_CTL_P0_ENABLE BIT(2) +#define GBE_REG_VAL_STAT_ENABLE_ALL 0xff +#define GBE_STATS_CD_SEL BIT(28) + +#define GBE_PORT_MASK(x) (BIT(x) - 1) +#define GBE_MASK_NO_PORTS 0 + +#define GBE_DEF_1G_MAC_CONTROL \ + (MACSL_GIG_MODE | MACSL_GMII_ENABLE | \ + MACSL_ENABLE_EXT_CTL | MACSL_RX_ENABLE_CSF) + +#define GBE_STATSA_MODULE 0 +#define GBE_STATSB_MODULE 1 +#define GBE_STATSC_MODULE 2 +#define GBE_STATSD_MODULE 3 + +#define MAX_SLAVES GBE13_NUM_SLAVES +/* s: 0-based slave_port */ +#define SGMII_BASE(s) \ + (((s) < 2) ? gbe_dev->sgmii_port_regs : gbe_dev->sgmii_port34_regs) + +#define GBE_TX_QUEUE 648 +#define GBE_TXHOOK_ORDER 0 +#define GBE_DEFAULT_ALE_AGEOUT 30 +#define NETCP_LINK_STATE_INVALID -1 + +#define GBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ + offsetof(struct gbe##_##rb, rn) +#define GBE_REG_ADDR(p, rb, rn) (p->rb + p->rb##_ofs.rn) + +struct gbe_ss_regs { + u32 id_ver; + u32 synce_count; + u32 synce_mux; +}; + +struct gbe_ss_regs_ofs { + u16 id_ver; + u16 control; +}; + +struct gbe_switch_regs { + u32 id_ver; + u32 control; + u32 soft_reset; + u32 stat_port_en; + u32 ptype; + u32 soft_idle; + u32 thru_rate; + u32 gap_thresh; + u32 tx_start_wds; + u32 flow_control; +}; + +struct gbe_switch_regs_ofs { + u16 id_ver; + u16 control; + u16 soft_reset; + u16 emcontrol; + u16 stat_port_en; + u16 ptype; + u16 flow_control; +}; + +struct gbe_port_regs { + u32 max_blks; + u32 blk_cnt; + u32 port_vlan; + u32 tx_pri_map; + u32 sa_lo; + u32 sa_hi; + u32 ts_ctl; + u32 ts_seq_ltype; + u32 ts_vlan; + u32 ts_ctl_ltype2; + u32 ts_ctl2; +}; + +struct gbe_port_regs_ofs { + u16 port_vlan; + u16 tx_pri_map; + u16 sa_lo; + u16 sa_hi; + u16 ts_ctl; + u16 ts_seq_ltype; + u16 ts_vlan; + u16 ts_ctl_ltype2; + u16 ts_ctl2; +}; + +struct gbe_host_port_regs { + u32 src_id; + u32 port_vlan; + u32 rx_pri_map; + u32 rx_maxlen; +}; + +struct gbe_host_port_regs_ofs { + u16 port_vlan; + u16 tx_pri_map; + u16 rx_maxlen; +}; + +struct gbe_emac_regs { + u32 id_ver; + u32 mac_control; + u32 mac_status; + u32 soft_reset; + u32 rx_maxlen; + u32 __reserved_0; + u32 rx_pause; + u32 tx_pause; + u32 __reserved_1; + u32 rx_pri_map; + u32 rsvd[6]; +}; + +struct gbe_emac_regs_ofs { + u16 mac_control; + u16 soft_reset; + u16 rx_maxlen; +}; + +struct gbe_hw_stats { + u32 rx_good_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 rx_pause_frames; + u32 rx_crc_errors; + u32 rx_align_code_errors; + u32 rx_oversized_frames; + u32 rx_jabber_frames; + u32 rx_undersized_frames; + u32 rx_fragments; + u32 __pad_0[2]; + u32 rx_bytes; + u32 tx_good_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 tx_pause_frames; + u32 tx_deferred_frames; + u32 tx_collision_frames; + u32 tx_single_coll_frames; + u32 tx_mult_coll_frames; + u32 tx_excessive_collisions; + u32 tx_late_collisions; + u32 tx_underrun; + u32 tx_carrier_sense_errors; + u32 tx_bytes; + u32 tx_64byte_frames; + u32 tx_65_to_127byte_frames; + u32 tx_128_to_255byte_frames; + u32 tx_256_to_511byte_frames; + u32 tx_512_to_1023byte_frames; + u32 tx_1024byte_frames; + u32 net_bytes; + u32 rx_sof_overruns; + u32 rx_mof_overruns; + u32 rx_dma_overruns; +}; + +#define GBE13_NUM_HW_STAT_ENTRIES (sizeof(struct gbe_hw_stats)/sizeof(u32)) +#define GBE13_NUM_HW_STATS_MOD 2 +#define GBE_MAX_HW_STAT_MODS 3 +#define GBE_HW_STATS_REG_MAP_SZ 0x100 + +struct gbe_slave { + void __iomem *port_regs; + void __iomem *emac_regs; + struct gbe_port_regs_ofs port_regs_ofs; + struct gbe_emac_regs_ofs emac_regs_ofs; + int slave_num; /* 0 based logical number */ + int port_num; /* actual port number */ + atomic_t link_state; + bool open; + struct phy_device *phy; + u32 link_interface; + u32 mac_control; + u8 phy_port_t; + struct device_node *phy_node; + struct list_head slave_list; +}; + +struct gbe_priv { + struct device *dev; + struct netcp_device *netcp_device; + struct timer_list timer; + u32 num_slaves; + u32 ale_entries; + u32 ale_ports; + bool enable_ale; + struct netcp_tx_pipe tx_pipe; + + int host_port; + u32 rx_packet_max; + u32 ss_version; + + void __iomem *ss_regs; + void __iomem *switch_regs; + void __iomem *host_port_regs; + void __iomem *ale_reg; + void __iomem *sgmii_port_regs; + void __iomem *sgmii_port34_regs; + void __iomem *xgbe_serdes_regs; + void __iomem *hw_stats_regs[GBE_MAX_HW_STAT_MODS]; + + struct gbe_ss_regs_ofs ss_regs_ofs; + struct gbe_switch_regs_ofs switch_regs_ofs; + struct gbe_host_port_regs_ofs host_port_regs_ofs; + + struct cpsw_ale *ale; + unsigned int tx_queue_id; + const char *dma_chan_name; + + struct list_head gbe_intf_head; + struct list_head secondary_slaves; + struct net_device *dummy_ndev; + + u64 *hw_stats; + const struct netcp_ethtool_stat *et_stats; + int num_et_stats; + /* Lock for updating the hwstats */ + spinlock_t hw_stats_lock; +}; + +struct gbe_intf { + struct net_device *ndev; + struct device *dev; + struct gbe_priv *gbe_dev; + struct netcp_tx_pipe tx_pipe; + struct gbe_slave *slave; + struct list_head gbe_intf_list; + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; +}; + +static struct netcp_module gbe_module; + +/* Statistic management */ +struct netcp_ethtool_stat { + char desc[ETH_GSTRING_LEN]; + int type; + u32 size; + int offset; +}; + +#define GBE_STATSA_INFO(field) "GBE_A:"#field, GBE_STATSA_MODULE,\ + FIELD_SIZEOF(struct gbe_hw_stats, field), \ + offsetof(struct gbe_hw_stats, field) + +#define GBE_STATSB_INFO(field) "GBE_B:"#field, GBE_STATSB_MODULE,\ + FIELD_SIZEOF(struct gbe_hw_stats, field), \ + offsetof(struct gbe_hw_stats, field) + +#define GBE_STATSC_INFO(field) "GBE_C:"#field, GBE_STATSC_MODULE,\ + FIELD_SIZEOF(struct gbe_hw_stats, field), \ + offsetof(struct gbe_hw_stats, field) + +#define GBE_STATSD_INFO(field) "GBE_D:"#field, GBE_STATSD_MODULE,\ + FIELD_SIZEOF(struct gbe_hw_stats, field), \ + offsetof(struct gbe_hw_stats, field) + +static const struct netcp_ethtool_stat gbe13_et_stats[] = { + /* GBE module A */ + {GBE_STATSA_INFO(rx_good_frames)}, + {GBE_STATSA_INFO(rx_broadcast_frames)}, + {GBE_STATSA_INFO(rx_multicast_frames)}, + {GBE_STATSA_INFO(rx_pause_frames)}, + {GBE_STATSA_INFO(rx_crc_errors)}, + {GBE_STATSA_INFO(rx_align_code_errors)}, + {GBE_STATSA_INFO(rx_oversized_frames)}, + {GBE_STATSA_INFO(rx_jabber_frames)}, + {GBE_STATSA_INFO(rx_undersized_frames)}, + {GBE_STATSA_INFO(rx_fragments)}, + {GBE_STATSA_INFO(rx_bytes)}, + {GBE_STATSA_INFO(tx_good_frames)}, + {GBE_STATSA_INFO(tx_broadcast_frames)}, + {GBE_STATSA_INFO(tx_multicast_frames)}, + {GBE_STATSA_INFO(tx_pause_frames)}, + {GBE_STATSA_INFO(tx_deferred_frames)}, + {GBE_STATSA_INFO(tx_collision_frames)}, + {GBE_STATSA_INFO(tx_single_coll_frames)}, + {GBE_STATSA_INFO(tx_mult_coll_frames)}, + {GBE_STATSA_INFO(tx_excessive_collisions)}, + {GBE_STATSA_INFO(tx_late_collisions)}, + {GBE_STATSA_INFO(tx_underrun)}, + {GBE_STATSA_INFO(tx_carrier_sense_errors)}, + {GBE_STATSA_INFO(tx_bytes)}, + {GBE_STATSA_INFO(tx_64byte_frames)}, + {GBE_STATSA_INFO(tx_65_to_127byte_frames)}, + {GBE_STATSA_INFO(tx_128_to_255byte_frames)}, + {GBE_STATSA_INFO(tx_256_to_511byte_frames)}, + {GBE_STATSA_INFO(tx_512_to_1023byte_frames)}, + {GBE_STATSA_INFO(tx_1024byte_frames)}, + {GBE_STATSA_INFO(net_bytes)}, + {GBE_STATSA_INFO(rx_sof_overruns)}, + {GBE_STATSA_INFO(rx_mof_overruns)}, + {GBE_STATSA_INFO(rx_dma_overruns)}, + /* GBE module B */ + {GBE_STATSB_INFO(rx_good_frames)}, + {GBE_STATSB_INFO(rx_broadcast_frames)}, + {GBE_STATSB_INFO(rx_multicast_frames)}, + {GBE_STATSB_INFO(rx_pause_frames)}, + {GBE_STATSB_INFO(rx_crc_errors)}, + {GBE_STATSB_INFO(rx_align_code_errors)}, + {GBE_STATSB_INFO(rx_oversized_frames)}, + {GBE_STATSB_INFO(rx_jabber_frames)}, + {GBE_STATSB_INFO(rx_undersized_frames)}, + {GBE_STATSB_INFO(rx_fragments)}, + {GBE_STATSB_INFO(rx_bytes)}, + {GBE_STATSB_INFO(tx_good_frames)}, + {GBE_STATSB_INFO(tx_broadcast_frames)}, + {GBE_STATSB_INFO(tx_multicast_frames)}, + {GBE_STATSB_INFO(tx_pause_frames)}, + {GBE_STATSB_INFO(tx_deferred_frames)}, + {GBE_STATSB_INFO(tx_collision_frames)}, + {GBE_STATSB_INFO(tx_single_coll_frames)}, + {GBE_STATSB_INFO(tx_mult_coll_frames)}, + {GBE_STATSB_INFO(tx_excessive_collisions)}, + {GBE_STATSB_INFO(tx_late_collisions)}, + {GBE_STATSB_INFO(tx_underrun)}, + {GBE_STATSB_INFO(tx_carrier_sense_errors)}, + {GBE_STATSB_INFO(tx_bytes)}, + {GBE_STATSB_INFO(tx_64byte_frames)}, + {GBE_STATSB_INFO(tx_65_to_127byte_frames)}, + {GBE_STATSB_INFO(tx_128_to_255byte_frames)}, + {GBE_STATSB_INFO(tx_256_to_511byte_frames)}, + {GBE_STATSB_INFO(tx_512_to_1023byte_frames)}, + {GBE_STATSB_INFO(tx_1024byte_frames)}, + {GBE_STATSB_INFO(net_bytes)}, + {GBE_STATSB_INFO(rx_sof_overruns)}, + {GBE_STATSB_INFO(rx_mof_overruns)}, + {GBE_STATSB_INFO(rx_dma_overruns)}, + /* GBE module C */ + {GBE_STATSC_INFO(rx_good_frames)}, + {GBE_STATSC_INFO(rx_broadcast_frames)}, + {GBE_STATSC_INFO(rx_multicast_frames)}, + {GBE_STATSC_INFO(rx_pause_frames)}, + {GBE_STATSC_INFO(rx_crc_errors)}, + {GBE_STATSC_INFO(rx_align_code_errors)}, + {GBE_STATSC_INFO(rx_oversized_frames)}, + {GBE_STATSC_INFO(rx_jabber_frames)}, + {GBE_STATSC_INFO(rx_undersized_frames)}, + {GBE_STATSC_INFO(rx_fragments)}, + {GBE_STATSC_INFO(rx_bytes)}, + {GBE_STATSC_INFO(tx_good_frames)}, + {GBE_STATSC_INFO(tx_broadcast_frames)}, + {GBE_STATSC_INFO(tx_multicast_frames)}, + {GBE_STATSC_INFO(tx_pause_frames)}, + {GBE_STATSC_INFO(tx_deferred_frames)}, + {GBE_STATSC_INFO(tx_collision_frames)}, + {GBE_STATSC_INFO(tx_single_coll_frames)}, + {GBE_STATSC_INFO(tx_mult_coll_frames)}, + {GBE_STATSC_INFO(tx_excessive_collisions)}, + {GBE_STATSC_INFO(tx_late_collisions)}, + {GBE_STATSC_INFO(tx_underrun)}, + {GBE_STATSC_INFO(tx_carrier_sense_errors)}, + {GBE_STATSC_INFO(tx_bytes)}, + {GBE_STATSC_INFO(tx_64byte_frames)}, + {GBE_STATSC_INFO(tx_65_to_127byte_frames)}, + {GBE_STATSC_INFO(tx_128_to_255byte_frames)}, + {GBE_STATSC_INFO(tx_256_to_511byte_frames)}, + {GBE_STATSC_INFO(tx_512_to_1023byte_frames)}, + {GBE_STATSC_INFO(tx_1024byte_frames)}, + {GBE_STATSC_INFO(net_bytes)}, + {GBE_STATSC_INFO(rx_sof_overruns)}, + {GBE_STATSC_INFO(rx_mof_overruns)}, + {GBE_STATSC_INFO(rx_dma_overruns)}, + /* GBE module D */ + {GBE_STATSD_INFO(rx_good_frames)}, + {GBE_STATSD_INFO(rx_broadcast_frames)}, + {GBE_STATSD_INFO(rx_multicast_frames)}, + {GBE_STATSD_INFO(rx_pause_frames)}, + {GBE_STATSD_INFO(rx_crc_errors)}, + {GBE_STATSD_INFO(rx_align_code_errors)}, + {GBE_STATSD_INFO(rx_oversized_frames)}, + {GBE_STATSD_INFO(rx_jabber_frames)}, + {GBE_STATSD_INFO(rx_undersized_frames)}, + {GBE_STATSD_INFO(rx_fragments)}, + {GBE_STATSD_INFO(rx_bytes)}, + {GBE_STATSD_INFO(tx_good_frames)}, + {GBE_STATSD_INFO(tx_broadcast_frames)}, + {GBE_STATSD_INFO(tx_multicast_frames)}, + {GBE_STATSD_INFO(tx_pause_frames)}, + {GBE_STATSD_INFO(tx_deferred_frames)}, + {GBE_STATSD_INFO(tx_collision_frames)}, + {GBE_STATSD_INFO(tx_single_coll_frames)}, + {GBE_STATSD_INFO(tx_mult_coll_frames)}, + {GBE_STATSD_INFO(tx_excessive_collisions)}, + {GBE_STATSD_INFO(tx_late_collisions)}, + {GBE_STATSD_INFO(tx_underrun)}, + {GBE_STATSD_INFO(tx_carrier_sense_errors)}, + {GBE_STATSD_INFO(tx_bytes)}, + {GBE_STATSD_INFO(tx_64byte_frames)}, + {GBE_STATSD_INFO(tx_65_to_127byte_frames)}, + {GBE_STATSD_INFO(tx_128_to_255byte_frames)}, + {GBE_STATSD_INFO(tx_256_to_511byte_frames)}, + {GBE_STATSD_INFO(tx_512_to_1023byte_frames)}, + {GBE_STATSD_INFO(tx_1024byte_frames)}, + {GBE_STATSD_INFO(net_bytes)}, + {GBE_STATSD_INFO(rx_sof_overruns)}, + {GBE_STATSD_INFO(rx_mof_overruns)}, + {GBE_STATSD_INFO(rx_dma_overruns)}, +}; + +#define for_each_intf(i, priv) \ + list_for_each_entry((i), &(priv)->gbe_intf_head, gbe_intf_list) + +#define for_each_sec_slave(slave, priv) \ + list_for_each_entry((slave), &(priv)->secondary_slaves, slave_list) + +#define first_sec_slave(priv) \ + list_first_entry(&priv->secondary_slaves, \ + struct gbe_slave, slave_list) + +static void keystone_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + strncpy(info->driver, NETCP_DRIVER_NAME, sizeof(info->driver)); + strncpy(info->version, NETCP_DRIVER_VERSION, sizeof(info->version)); +} + +static u32 keystone_get_msglevel(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + + return netcp->msg_enable; +} + +static void keystone_set_msglevel(struct net_device *ndev, u32 value) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + + netcp->msg_enable = value; +} + +static void keystone_get_stat_strings(struct net_device *ndev, + uint32_t stringset, uint8_t *data) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_intf *gbe_intf; + struct gbe_priv *gbe_dev; + int i; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return; + gbe_dev = gbe_intf->gbe_dev; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < gbe_dev->num_et_stats; i++) { + memcpy(data, gbe_dev->et_stats[i].desc, + ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } + break; + case ETH_SS_TEST: + break; + } +} + +static int keystone_get_sset_count(struct net_device *ndev, int stringset) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_intf *gbe_intf; + struct gbe_priv *gbe_dev; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return -EINVAL; + gbe_dev = gbe_intf->gbe_dev; + + switch (stringset) { + case ETH_SS_TEST: + return 0; + case ETH_SS_STATS: + return gbe_dev->num_et_stats; + default: + return -EINVAL; + } +} + +static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data) +{ + void __iomem *base = NULL; + u32 __iomem *p; + u32 tmp = 0; + int i; + + for (i = 0; i < gbe_dev->num_et_stats; i++) { + base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[i].type]; + p = base + gbe_dev->et_stats[i].offset; + tmp = readl(p); + gbe_dev->hw_stats[i] = gbe_dev->hw_stats[i] + tmp; + if (data) + data[i] = gbe_dev->hw_stats[i]; + /* write-to-decrement: + * new register value = old register value - write value + */ + writel(tmp, p); + } +} + +static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data) +{ + void __iomem *gbe_statsa = gbe_dev->hw_stats_regs[0]; + void __iomem *gbe_statsb = gbe_dev->hw_stats_regs[1]; + u64 *hw_stats = &gbe_dev->hw_stats[0]; + void __iomem *base = NULL; + u32 __iomem *p; + u32 tmp = 0, val, pair_size = (gbe_dev->num_et_stats / 2); + int i, j, pair; + + for (pair = 0; pair < 2; pair++) { + val = readl(GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); + + if (pair == 0) + val &= ~GBE_STATS_CD_SEL; + else + val |= GBE_STATS_CD_SEL; + + /* make the stat modules visible */ + writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); + + for (i = 0; i < pair_size; i++) { + j = pair * pair_size + i; + switch (gbe_dev->et_stats[j].type) { + case GBE_STATSA_MODULE: + case GBE_STATSC_MODULE: + base = gbe_statsa; + break; + case GBE_STATSB_MODULE: + case GBE_STATSD_MODULE: + base = gbe_statsb; + break; + } + + p = base + gbe_dev->et_stats[j].offset; + tmp = readl(p); + hw_stats[j] += tmp; + if (data) + data[j] = hw_stats[j]; + /* write-to-decrement: + * new register value = old register value - write value + */ + writel(tmp, p); + } + } +} + +static void keystone_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *stats, + uint64_t *data) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_intf *gbe_intf; + struct gbe_priv *gbe_dev; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return; + + gbe_dev = gbe_intf->gbe_dev; + spin_lock_bh(&gbe_dev->hw_stats_lock); + gbe_update_stats_ver14(gbe_dev, data); + spin_unlock_bh(&gbe_dev->hw_stats_lock); +} + +static int keystone_get_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct phy_device *phy = ndev->phydev; + struct gbe_intf *gbe_intf; + int ret; + + if (!phy) + return -EINVAL; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return -EINVAL; + + if (!gbe_intf->slave) + return -EINVAL; + + ret = phy_ethtool_gset(phy, cmd); + if (!ret) + cmd->port = gbe_intf->slave->phy_port_t; + + return ret; +} + +static int keystone_set_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct phy_device *phy = ndev->phydev; + struct gbe_intf *gbe_intf; + u32 features = cmd->advertising & cmd->supported; + + if (!phy) + return -EINVAL; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return -EINVAL; + + if (!gbe_intf->slave) + return -EINVAL; + + if (cmd->port != gbe_intf->slave->phy_port_t) { + if ((cmd->port == PORT_TP) && !(features & ADVERTISED_TP)) + return -EINVAL; + + if ((cmd->port == PORT_AUI) && !(features & ADVERTISED_AUI)) + return -EINVAL; + + if ((cmd->port == PORT_BNC) && !(features & ADVERTISED_BNC)) + return -EINVAL; + + if ((cmd->port == PORT_MII) && !(features & ADVERTISED_MII)) + return -EINVAL; + + if ((cmd->port == PORT_FIBRE) && !(features & ADVERTISED_FIBRE)) + return -EINVAL; + } + + gbe_intf->slave->phy_port_t = cmd->port; + return phy_ethtool_sset(phy, cmd); +} + +static const struct ethtool_ops keystone_ethtool_ops = { + .get_drvinfo = keystone_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = keystone_get_msglevel, + .set_msglevel = keystone_set_msglevel, + .get_strings = keystone_get_stat_strings, + .get_sset_count = keystone_get_sset_count, + .get_ethtool_stats = keystone_get_ethtool_stats, + .get_settings = keystone_get_settings, + .set_settings = keystone_set_settings, +}; + +#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \ + ((mac)[2] << 16) | ((mac)[3] << 24)) +#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8)) + +static void gbe_set_slave_mac(struct gbe_slave *slave, + struct gbe_intf *gbe_intf) +{ + struct net_device *ndev = gbe_intf->ndev; + + writel(mac_hi(ndev->dev_addr), GBE_REG_ADDR(slave, port_regs, sa_hi)); + writel(mac_lo(ndev->dev_addr), GBE_REG_ADDR(slave, port_regs, sa_lo)); +} + +static int gbe_get_slave_port(struct gbe_priv *priv, u32 slave_num) +{ + if (priv->host_port == 0) + return slave_num + 1; + + return slave_num; +} + +static void netcp_ethss_link_state_action(struct gbe_priv *gbe_dev, + struct net_device *ndev, + struct gbe_slave *slave, + int up) +{ + struct phy_device *phy = slave->phy; + u32 mac_control = 0; + + if (up) { + mac_control = slave->mac_control; + if (phy && (phy->speed == SPEED_1000)) + mac_control |= MACSL_GIG_MODE; + + writel(mac_control, GBE_REG_ADDR(slave, emac_regs, + mac_control)); + + cpsw_ale_control_set(gbe_dev->ale, slave->port_num, + ALE_PORT_STATE, + ALE_PORT_STATE_FORWARD); + + if (ndev && slave->open) + netif_carrier_on(ndev); + } else { + writel(mac_control, GBE_REG_ADDR(slave, emac_regs, + mac_control)); + cpsw_ale_control_set(gbe_dev->ale, slave->port_num, + ALE_PORT_STATE, + ALE_PORT_STATE_DISABLE); + if (ndev) + netif_carrier_off(ndev); + } + + if (phy) + phy_print_status(phy); +} + +static bool gbe_phy_link_status(struct gbe_slave *slave) +{ + return !slave->phy || slave->phy->link; +} + +static void netcp_ethss_update_link_state(struct gbe_priv *gbe_dev, + struct gbe_slave *slave, + struct net_device *ndev) +{ + int sp = slave->slave_num; + int phy_link_state, sgmii_link_state = 1, link_state; + + if (!slave->open) + return; + + sgmii_link_state = netcp_sgmii_get_port_link(SGMII_BASE(sp), sp); + phy_link_state = gbe_phy_link_status(slave); + link_state = phy_link_state & sgmii_link_state; + + if (atomic_xchg(&slave->link_state, link_state) != link_state) + netcp_ethss_link_state_action(gbe_dev, ndev, slave, + link_state); +} + +static void gbe_adjust_link(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_intf *gbe_intf; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return; + + netcp_ethss_update_link_state(gbe_intf->gbe_dev, gbe_intf->slave, + ndev); +} + +static void gbe_adjust_link_sec_slaves(struct net_device *ndev) +{ + struct gbe_priv *gbe_dev = netdev_priv(ndev); + struct gbe_slave *slave; + + for_each_sec_slave(slave, gbe_dev) + netcp_ethss_update_link_state(gbe_dev, slave, NULL); +} + +/* Reset EMAC + * Soft reset is set and polled until clear, or until a timeout occurs + */ +static int gbe_port_reset(struct gbe_slave *slave) +{ + u32 i, v; + + /* Set the soft reset bit */ + writel(SOFT_RESET, GBE_REG_ADDR(slave, emac_regs, soft_reset)); + + /* Wait for the bit to clear */ + for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) { + v = readl(GBE_REG_ADDR(slave, emac_regs, soft_reset)); + if ((v & SOFT_RESET_MASK) != SOFT_RESET) + return 0; + } + + /* Timeout on the reset */ + return GMACSL_RET_WARN_RESET_INCOMPLETE; +} + +/* Configure EMAC */ +static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave, + int max_rx_len) +{ + if (max_rx_len > NETCP_MAX_FRAME_SIZE) + max_rx_len = NETCP_MAX_FRAME_SIZE; + + writel(max_rx_len, GBE_REG_ADDR(slave, emac_regs, rx_maxlen)); + writel(slave->mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control)); +} + +static void gbe_slave_stop(struct gbe_intf *intf) +{ + struct gbe_priv *gbe_dev = intf->gbe_dev; + struct gbe_slave *slave = intf->slave; + + gbe_port_reset(slave); + /* Disable forwarding */ + cpsw_ale_control_set(gbe_dev->ale, slave->port_num, + ALE_PORT_STATE, ALE_PORT_STATE_DISABLE); + cpsw_ale_del_mcast(gbe_dev->ale, intf->ndev->broadcast, + 1 << slave->port_num, 0, 0); + + if (!slave->phy) + return; + + phy_stop(slave->phy); + phy_disconnect(slave->phy); + slave->phy = NULL; +} + +static void gbe_sgmii_config(struct gbe_priv *priv, struct gbe_slave *slave) +{ + void __iomem *sgmii_port_regs; + + sgmii_port_regs = priv->sgmii_port_regs; + if ((priv->ss_version == GBE_SS_VERSION_14) && (slave->slave_num >= 2)) + sgmii_port_regs = priv->sgmii_port34_regs; + + netcp_sgmii_reset(sgmii_port_regs, slave->slave_num); + netcp_sgmii_config(sgmii_port_regs, slave->slave_num, + slave->link_interface); +} + +static int gbe_slave_open(struct gbe_intf *gbe_intf) +{ + struct gbe_priv *priv = gbe_intf->gbe_dev; + struct gbe_slave *slave = gbe_intf->slave; + phy_interface_t phy_mode; + bool has_phy = false; + + void (*hndlr)(struct net_device *) = gbe_adjust_link; + + gbe_sgmii_config(priv, slave); + gbe_port_reset(slave); + gbe_port_config(priv, slave, priv->rx_packet_max); + gbe_set_slave_mac(slave, gbe_intf); + /* enable forwarding */ + cpsw_ale_control_set(priv->ale, slave->port_num, + ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); + cpsw_ale_add_mcast(priv->ale, gbe_intf->ndev->broadcast, + 1 << slave->port_num, 0, 0, ALE_MCAST_FWD_2); + + if (slave->link_interface == SGMII_LINK_MAC_PHY) { + has_phy = true; + phy_mode = PHY_INTERFACE_MODE_SGMII; + slave->phy_port_t = PORT_MII; + } else if (slave->link_interface == XGMII_LINK_MAC_PHY) { + has_phy = true; + phy_mode = PHY_INTERFACE_MODE_NA; + slave->phy_port_t = PORT_FIBRE; + } + + if (has_phy) { + slave->phy = of_phy_connect(gbe_intf->ndev, + slave->phy_node, + hndlr, 0, + phy_mode); + if (!slave->phy) { + dev_err(priv->dev, "phy not found on slave %d\n", + slave->slave_num); + return -ENODEV; + } + dev_dbg(priv->dev, "phy found: id is: 0x%s\n", + dev_name(&slave->phy->dev)); + phy_start(slave->phy); + phy_read_status(slave->phy); + } + return 0; +} + +static void gbe_init_host_port(struct gbe_priv *priv) +{ + int bypass_en = 1; + /* Max length register */ + writel(NETCP_MAX_FRAME_SIZE, GBE_REG_ADDR(priv, host_port_regs, + rx_maxlen)); + + cpsw_ale_start(priv->ale); + + if (priv->enable_ale) + bypass_en = 0; + + cpsw_ale_control_set(priv->ale, 0, ALE_BYPASS, bypass_en); + + cpsw_ale_control_set(priv->ale, 0, ALE_NO_PORT_VLAN, 1); + + cpsw_ale_control_set(priv->ale, priv->host_port, + ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); + + cpsw_ale_control_set(priv->ale, 0, + ALE_PORT_UNKNOWN_VLAN_MEMBER, + GBE_PORT_MASK(priv->ale_ports)); + + cpsw_ale_control_set(priv->ale, 0, + ALE_PORT_UNKNOWN_MCAST_FLOOD, + GBE_PORT_MASK(priv->ale_ports - 1)); + + cpsw_ale_control_set(priv->ale, 0, + ALE_PORT_UNKNOWN_REG_MCAST_FLOOD, + GBE_PORT_MASK(priv->ale_ports)); + + cpsw_ale_control_set(priv->ale, 0, + ALE_PORT_UNTAGGED_EGRESS, + GBE_PORT_MASK(priv->ale_ports)); +} + +static void gbe_add_mcast_addr(struct gbe_intf *gbe_intf, u8 *addr) +{ + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + u16 vlan_id; + + cpsw_ale_add_mcast(gbe_dev->ale, addr, + GBE_PORT_MASK(gbe_dev->ale_ports), 0, 0, + ALE_MCAST_FWD_2); + for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) { + cpsw_ale_add_mcast(gbe_dev->ale, addr, + GBE_PORT_MASK(gbe_dev->ale_ports), + ALE_VLAN, vlan_id, ALE_MCAST_FWD_2); + } +} + +static void gbe_add_ucast_addr(struct gbe_intf *gbe_intf, u8 *addr) +{ + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + u16 vlan_id; + + cpsw_ale_add_ucast(gbe_dev->ale, addr, gbe_dev->host_port, 0, 0); + + for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) + cpsw_ale_add_ucast(gbe_dev->ale, addr, gbe_dev->host_port, + ALE_VLAN, vlan_id); +} + +static void gbe_del_mcast_addr(struct gbe_intf *gbe_intf, u8 *addr) +{ + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + u16 vlan_id; + + cpsw_ale_del_mcast(gbe_dev->ale, addr, 0, 0, 0); + + for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) { + cpsw_ale_del_mcast(gbe_dev->ale, addr, 0, ALE_VLAN, vlan_id); + } +} + +static void gbe_del_ucast_addr(struct gbe_intf *gbe_intf, u8 *addr) +{ + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + u16 vlan_id; + + cpsw_ale_del_ucast(gbe_dev->ale, addr, gbe_dev->host_port, 0, 0); + + for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) { + cpsw_ale_del_ucast(gbe_dev->ale, addr, gbe_dev->host_port, + ALE_VLAN, vlan_id); + } +} + +static int gbe_add_addr(void *intf_priv, struct netcp_addr *naddr) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + + dev_dbg(gbe_dev->dev, "ethss adding address %pM, type %d\n", + naddr->addr, naddr->type); + + switch (naddr->type) { + case ADDR_MCAST: + case ADDR_BCAST: + gbe_add_mcast_addr(gbe_intf, naddr->addr); + break; + case ADDR_UCAST: + case ADDR_DEV: + gbe_add_ucast_addr(gbe_intf, naddr->addr); + break; + case ADDR_ANY: + /* nothing to do for promiscuous */ + default: + break; + } + + return 0; +} + +static int gbe_del_addr(void *intf_priv, struct netcp_addr *naddr) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + + dev_dbg(gbe_dev->dev, "ethss deleting address %pM, type %d\n", + naddr->addr, naddr->type); + + switch (naddr->type) { + case ADDR_MCAST: + case ADDR_BCAST: + gbe_del_mcast_addr(gbe_intf, naddr->addr); + break; + case ADDR_UCAST: + case ADDR_DEV: + gbe_del_ucast_addr(gbe_intf, naddr->addr); + break; + case ADDR_ANY: + /* nothing to do for promiscuous */ + default: + break; + } + + return 0; +} + +static int gbe_add_vid(void *intf_priv, int vid) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + + set_bit(vid, gbe_intf->active_vlans); + + cpsw_ale_add_vlan(gbe_dev->ale, vid, + GBE_PORT_MASK(gbe_dev->ale_ports), + GBE_MASK_NO_PORTS, + GBE_PORT_MASK(gbe_dev->ale_ports), + GBE_PORT_MASK(gbe_dev->ale_ports - 1)); + + return 0; +} + +static int gbe_del_vid(void *intf_priv, int vid) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + + cpsw_ale_del_vlan(gbe_dev->ale, vid, 0); + clear_bit(vid, gbe_intf->active_vlans); + return 0; +} + +static int gbe_ioctl(void *intf_priv, struct ifreq *req, int cmd) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct phy_device *phy = gbe_intf->slave->phy; + int ret = -EOPNOTSUPP; + + if (phy) + ret = phy_mii_ioctl(phy, req, cmd); + + return ret; +} + +static void netcp_ethss_timer(unsigned long arg) +{ + struct gbe_priv *gbe_dev = (struct gbe_priv *)arg; + struct gbe_intf *gbe_intf; + struct gbe_slave *slave; + + /* Check & update SGMII link state of interfaces */ + for_each_intf(gbe_intf, gbe_dev) { + if (!gbe_intf->slave->open) + continue; + netcp_ethss_update_link_state(gbe_dev, gbe_intf->slave, + gbe_intf->ndev); + } + + /* Check & update SGMII link state of secondary ports */ + for_each_sec_slave(slave, gbe_dev) { + netcp_ethss_update_link_state(gbe_dev, slave, NULL); + } + + spin_lock_bh(&gbe_dev->hw_stats_lock); + + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + gbe_update_stats_ver14(gbe_dev, NULL); + else + gbe_update_stats(gbe_dev, NULL); + + spin_unlock_bh(&gbe_dev->hw_stats_lock); + + gbe_dev->timer.expires = jiffies + GBE_TIMER_INTERVAL; + add_timer(&gbe_dev->timer); +} + +static int gbe_tx_hook(int order, void *data, struct netcp_packet *p_info) +{ + struct gbe_intf *gbe_intf = data; + + p_info->tx_pipe = &gbe_intf->tx_pipe; + return 0; +} + +static int gbe_open(void *intf_priv, struct net_device *ndev) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_slave *slave = gbe_intf->slave; + int port_num = slave->port_num; + u32 reg; + int ret; + + reg = readl(GBE_REG_ADDR(gbe_dev, switch_regs, id_ver)); + dev_dbg(gbe_dev->dev, "initializing gbe version %d.%d (%d) GBE identification value 0x%x\n", + GBE_MAJOR_VERSION(reg), GBE_MINOR_VERSION(reg), + GBE_RTL_VERSION(reg), GBE_IDENT(reg)); + + if (gbe_dev->enable_ale) + gbe_intf->tx_pipe.dma_psflags = 0; + else + gbe_intf->tx_pipe.dma_psflags = port_num; + + dev_dbg(gbe_dev->dev, "opened TX channel %s: %p with psflags %d\n", + gbe_intf->tx_pipe.dma_chan_name, + gbe_intf->tx_pipe.dma_channel, + gbe_intf->tx_pipe.dma_psflags); + + gbe_slave_stop(gbe_intf); + + /* disable priority elevation and enable statistics on all ports */ + writel(0, GBE_REG_ADDR(gbe_dev, switch_regs, ptype)); + + /* Control register */ + writel(GBE_CTL_P0_ENABLE, GBE_REG_ADDR(gbe_dev, switch_regs, control)); + + /* All statistics enabled and STAT AB visible by default */ + writel(GBE_REG_VAL_STAT_ENABLE_ALL, GBE_REG_ADDR(gbe_dev, switch_regs, + stat_port_en)); + + ret = gbe_slave_open(gbe_intf); + if (ret) + goto fail; + + netcp_register_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook, + gbe_intf); + + slave->open = true; + netcp_ethss_update_link_state(gbe_dev, slave, ndev); + return 0; + +fail: + gbe_slave_stop(gbe_intf); + return ret; +} + +static int gbe_close(void *intf_priv, struct net_device *ndev) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct netcp_intf *netcp = netdev_priv(ndev); + + gbe_slave_stop(gbe_intf); + netcp_unregister_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook, + gbe_intf); + + gbe_intf->slave->open = false; + atomic_set(&gbe_intf->slave->link_state, NETCP_LINK_STATE_INVALID); + return 0; +} + +static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, + struct device_node *node) +{ + int port_reg_num; + u32 port_reg_ofs, emac_reg_ofs; + + if (of_property_read_u32(node, "slave-port", &slave->slave_num)) { + dev_err(gbe_dev->dev, "missing slave-port parameter\n"); + return -EINVAL; + } + + if (of_property_read_u32(node, "link-interface", + &slave->link_interface)) { + dev_warn(gbe_dev->dev, + "missing link-interface value defaulting to 1G mac-phy link\n"); + slave->link_interface = SGMII_LINK_MAC_PHY; + } + + slave->open = false; + slave->phy_node = of_parse_phandle(node, "phy-handle", 0); + slave->port_num = gbe_get_slave_port(gbe_dev, slave->slave_num); + + slave->mac_control = GBE_DEF_1G_MAC_CONTROL; + + /* Emac regs memmap are contiguous but port regs are not */ + port_reg_num = slave->slave_num; + if (gbe_dev->ss_version == GBE_SS_VERSION_14) { + if (slave->slave_num > 1) { + port_reg_ofs = GBE13_SLAVE_PORT2_OFFSET; + port_reg_num -= 2; + } else { + port_reg_ofs = GBE13_SLAVE_PORT_OFFSET; + } + } else { + dev_err(gbe_dev->dev, "unknown ethss(0x%x)\n", + gbe_dev->ss_version); + return -EINVAL; + } + + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + emac_reg_ofs = GBE13_EMAC_OFFSET; + + slave->port_regs = gbe_dev->ss_regs + port_reg_ofs + + (0x30 * port_reg_num); + slave->emac_regs = gbe_dev->ss_regs + emac_reg_ofs + + (0x40 * slave->slave_num); + + if (gbe_dev->ss_version == GBE_SS_VERSION_14) { + /* Initialize slave port register offsets */ + GBE_SET_REG_OFS(slave, port_regs, port_vlan); + GBE_SET_REG_OFS(slave, port_regs, tx_pri_map); + GBE_SET_REG_OFS(slave, port_regs, sa_lo); + GBE_SET_REG_OFS(slave, port_regs, sa_hi); + GBE_SET_REG_OFS(slave, port_regs, ts_ctl); + GBE_SET_REG_OFS(slave, port_regs, ts_seq_ltype); + GBE_SET_REG_OFS(slave, port_regs, ts_vlan); + GBE_SET_REG_OFS(slave, port_regs, ts_ctl_ltype2); + GBE_SET_REG_OFS(slave, port_regs, ts_ctl2); + + /* Initialize EMAC register offsets */ + GBE_SET_REG_OFS(slave, emac_regs, mac_control); + GBE_SET_REG_OFS(slave, emac_regs, soft_reset); + GBE_SET_REG_OFS(slave, emac_regs, rx_maxlen); + + } else { + dev_err(gbe_dev->dev, "unknown ethss(0x%x)\n", + gbe_dev->ss_version); + return -EINVAL; + } + + atomic_set(&slave->link_state, NETCP_LINK_STATE_INVALID); + return 0; +} + +static void init_secondary_ports(struct gbe_priv *gbe_dev, + struct device_node *node) +{ + struct device *dev = gbe_dev->dev; + phy_interface_t phy_mode; + struct gbe_priv **priv; + struct device_node *port; + struct gbe_slave *slave; + bool mac_phy_link = false; + + for_each_child_of_node(node, port) { + slave = devm_kzalloc(dev, sizeof(*slave), GFP_KERNEL); + if (!slave) { + dev_err(dev, + "memomry alloc failed for secondary port(%s), skipping...\n", + port->name); + continue; + } + + if (init_slave(gbe_dev, slave, port)) { + dev_err(dev, + "Failed to initialize secondary port(%s), skipping...\n", + port->name); + devm_kfree(dev, slave); + continue; + } + + gbe_sgmii_config(gbe_dev, slave); + gbe_port_reset(slave); + gbe_port_config(gbe_dev, slave, gbe_dev->rx_packet_max); + list_add_tail(&slave->slave_list, &gbe_dev->secondary_slaves); + gbe_dev->num_slaves++; + if (slave->link_interface == SGMII_LINK_MAC_PHY) + mac_phy_link = true; + + slave->open = true; + } + + /* of_phy_connect() is needed only for MAC-PHY interface */ + if (!mac_phy_link) + return; + + /* Allocate dummy netdev device for attaching to phy device */ + gbe_dev->dummy_ndev = alloc_netdev(sizeof(gbe_dev), "dummy", + NET_NAME_UNKNOWN, ether_setup); + if (!gbe_dev->dummy_ndev) { + dev_err(dev, + "Failed to allocate dummy netdev for secondary ports, skipping phy_connect()...\n"); + return; + } + priv = netdev_priv(gbe_dev->dummy_ndev); + *priv = gbe_dev; + + if (slave->link_interface == SGMII_LINK_MAC_PHY) { + phy_mode = PHY_INTERFACE_MODE_SGMII; + slave->phy_port_t = PORT_MII; + } else { + phy_mode = PHY_INTERFACE_MODE_NA; + slave->phy_port_t = PORT_FIBRE; + } + + for_each_sec_slave(slave, gbe_dev) { + if (slave->link_interface != SGMII_LINK_MAC_PHY) + continue; + slave->phy = + of_phy_connect(gbe_dev->dummy_ndev, + slave->phy_node, + gbe_adjust_link_sec_slaves, + 0, phy_mode); + if (!slave->phy) { + dev_err(dev, "phy not found for slave %d\n", + slave->slave_num); + slave->phy = NULL; + } else { + dev_dbg(dev, "phy found: id is: 0x%s\n", + dev_name(&slave->phy->dev)); + phy_start(slave->phy); + phy_read_status(slave->phy); + } + } +} + +static void free_secondary_ports(struct gbe_priv *gbe_dev) +{ + struct gbe_slave *slave; + + for (;;) { + slave = first_sec_slave(gbe_dev); + if (!slave) + break; + if (slave->phy) + phy_disconnect(slave->phy); + list_del(&slave->slave_list); + } + if (gbe_dev->dummy_ndev) + free_netdev(gbe_dev->dummy_ndev); +} + +static int get_gbe_resource_version(struct gbe_priv *gbe_dev, + struct device_node *node) +{ + struct resource res; + void __iomem *regs; + int ret; + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + dev_err(gbe_dev->dev, "Can't translate of node(%s) address\n", + node->name); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, "Failed to map gbe register base\n"); + return PTR_ERR(regs); + } + gbe_dev->ss_regs = regs; + gbe_dev->ss_version = readl(gbe_dev->ss_regs); + return 0; +} + +static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, + struct device_node *node) +{ + void __iomem *regs; + int i; + + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, + GBE13_NUM_HW_STAT_ENTRIES * + GBE13_NUM_SLAVES * sizeof(u64), + GFP_KERNEL); + if (!gbe_dev->hw_stats) { + dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); + return -ENOMEM; + } + + regs = gbe_dev->ss_regs; + gbe_dev->sgmii_port_regs = regs + GBE13_SGMII_MODULE_OFFSET; + gbe_dev->sgmii_port34_regs = regs + GBE13_SGMII34_MODULE_OFFSET; + gbe_dev->switch_regs = regs + GBE13_SWITCH_MODULE_OFFSET; + gbe_dev->host_port_regs = regs + GBE13_HOST_PORT_OFFSET; + + for (i = 0; i < GBE13_NUM_HW_STATS_MOD; i++) + gbe_dev->hw_stats_regs[i] = regs + GBE13_HW_STATS_OFFSET + + (GBE_HW_STATS_REG_MAP_SZ * i); + + gbe_dev->ale_reg = regs + GBE13_ALE_OFFSET; + gbe_dev->ale_ports = GBE13_NUM_ALE_PORTS; + gbe_dev->host_port = GBE13_HOST_PORT_NUM; + gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; + gbe_dev->et_stats = gbe13_et_stats; + gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); + + /* Subsystem registers */ + GBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver); + + /* Switch module registers */ + GBE_SET_REG_OFS(gbe_dev, switch_regs, id_ver); + GBE_SET_REG_OFS(gbe_dev, switch_regs, control); + GBE_SET_REG_OFS(gbe_dev, switch_regs, soft_reset); + GBE_SET_REG_OFS(gbe_dev, switch_regs, stat_port_en); + GBE_SET_REG_OFS(gbe_dev, switch_regs, ptype); + GBE_SET_REG_OFS(gbe_dev, switch_regs, flow_control); + + /* Host port registers */ + GBE_SET_REG_OFS(gbe_dev, host_port_regs, port_vlan); + GBE_SET_REG_OFS(gbe_dev, host_port_regs, rx_maxlen); + return 0; +} + +static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, + struct device_node *node, void **inst_priv) +{ + struct device_node *interfaces, *interface; + struct device_node *secondary_ports; + struct cpsw_ale_params ale_params; + struct gbe_priv *gbe_dev; + u32 slave_num; + int ret = 0; + + if (!node) { + dev_err(dev, "device tree info unavailable\n"); + return -ENODEV; + } + + gbe_dev = devm_kzalloc(dev, sizeof(struct gbe_priv), GFP_KERNEL); + if (!gbe_dev) + return -ENOMEM; + + gbe_dev->dev = dev; + gbe_dev->netcp_device = netcp_device; + gbe_dev->rx_packet_max = NETCP_MAX_FRAME_SIZE; + + /* init the hw stats lock */ + spin_lock_init(&gbe_dev->hw_stats_lock); + + if (of_find_property(node, "enable-ale", NULL)) { + gbe_dev->enable_ale = true; + dev_info(dev, "ALE enabled\n"); + } else { + gbe_dev->enable_ale = false; + dev_dbg(dev, "ALE bypass enabled*\n"); + } + + ret = of_property_read_u32(node, "tx-queue", + &gbe_dev->tx_queue_id); + if (ret < 0) { + dev_err(dev, "missing tx_queue parameter\n"); + gbe_dev->tx_queue_id = GBE_TX_QUEUE; + } + + ret = of_property_read_string(node, "tx-channel", + &gbe_dev->dma_chan_name); + if (ret < 0) { + dev_err(dev, "missing \"tx-channel\" parameter\n"); + ret = -ENODEV; + goto quit; + } + + if (!strcmp(node->name, "gbe")) { + ret = get_gbe_resource_version(gbe_dev, node); + if (ret) + goto quit; + + ret = set_gbe_ethss14_priv(gbe_dev, node); + if (ret) + goto quit; + } else { + dev_err(dev, "unknown GBE node(%s)\n", node->name); + ret = -ENODEV; + goto quit; + } + + interfaces = of_get_child_by_name(node, "interfaces"); + if (!interfaces) + dev_err(dev, "could not find interfaces\n"); + + ret = netcp_txpipe_init(&gbe_dev->tx_pipe, netcp_device, + gbe_dev->dma_chan_name, gbe_dev->tx_queue_id); + if (ret) + goto quit; + + ret = netcp_txpipe_open(&gbe_dev->tx_pipe); + if (ret) + goto quit; + + /* Create network interfaces */ + INIT_LIST_HEAD(&gbe_dev->gbe_intf_head); + for_each_child_of_node(interfaces, interface) { + ret = of_property_read_u32(interface, "slave-port", &slave_num); + if (ret) { + dev_err(dev, "missing slave-port parameter, skipping interface configuration for %s\n", + interface->name); + continue; + } + gbe_dev->num_slaves++; + } + + if (!gbe_dev->num_slaves) + dev_warn(dev, "No network interface configured\n"); + + /* Initialize Secondary slave ports */ + secondary_ports = of_get_child_by_name(node, "secondary-slave-ports"); + INIT_LIST_HEAD(&gbe_dev->secondary_slaves); + if (secondary_ports) + init_secondary_ports(gbe_dev, secondary_ports); + of_node_put(secondary_ports); + + if (!gbe_dev->num_slaves) { + dev_err(dev, "No network interface or secondary ports configured\n"); + ret = -ENODEV; + goto quit; + } + + memset(&ale_params, 0, sizeof(ale_params)); + ale_params.dev = gbe_dev->dev; + ale_params.ale_regs = gbe_dev->ale_reg; + ale_params.ale_ageout = GBE_DEFAULT_ALE_AGEOUT; + ale_params.ale_entries = gbe_dev->ale_entries; + ale_params.ale_ports = gbe_dev->ale_ports; + + gbe_dev->ale = cpsw_ale_create(&ale_params); + if (!gbe_dev->ale) { + dev_err(gbe_dev->dev, "error initializing ale engine\n"); + ret = -ENODEV; + goto quit; + } else { + dev_dbg(gbe_dev->dev, "Created a gbe ale engine\n"); + } + + /* initialize host port */ + gbe_init_host_port(gbe_dev); + + init_timer(&gbe_dev->timer); + gbe_dev->timer.data = (unsigned long)gbe_dev; + gbe_dev->timer.function = netcp_ethss_timer; + gbe_dev->timer.expires = jiffies + GBE_TIMER_INTERVAL; + add_timer(&gbe_dev->timer); + *inst_priv = gbe_dev; + return 0; + +quit: + if (gbe_dev->hw_stats) + devm_kfree(dev, gbe_dev->hw_stats); + if (gbe_dev->ale) + cpsw_ale_destroy(gbe_dev->ale); + if (gbe_dev->ss_regs) + devm_iounmap(dev, gbe_dev->ss_regs); + if (interfaces) + of_node_put(interfaces); + devm_kfree(dev, gbe_dev); + return ret; +} + +static int gbe_attach(void *inst_priv, struct net_device *ndev, + struct device_node *node, void **intf_priv) +{ + struct gbe_priv *gbe_dev = inst_priv; + struct gbe_intf *gbe_intf; + int ret; + + if (!node) { + dev_err(gbe_dev->dev, "interface node not available\n"); + return -ENODEV; + } + + gbe_intf = devm_kzalloc(gbe_dev->dev, sizeof(*gbe_intf), GFP_KERNEL); + if (!gbe_intf) + return -ENOMEM; + + gbe_intf->ndev = ndev; + gbe_intf->dev = gbe_dev->dev; + gbe_intf->gbe_dev = gbe_dev; + + gbe_intf->slave = devm_kzalloc(gbe_dev->dev, + sizeof(*gbe_intf->slave), + GFP_KERNEL); + if (!gbe_intf->slave) { + ret = -ENOMEM; + goto fail; + } + + if (init_slave(gbe_dev, gbe_intf->slave, node)) { + ret = -ENODEV; + goto fail; + } + + gbe_intf->tx_pipe = gbe_dev->tx_pipe; + ndev->ethtool_ops = &keystone_ethtool_ops; + list_add_tail(&gbe_intf->gbe_intf_list, &gbe_dev->gbe_intf_head); + *intf_priv = gbe_intf; + return 0; + +fail: + if (gbe_intf->slave) + devm_kfree(gbe_dev->dev, gbe_intf->slave); + if (gbe_intf) + devm_kfree(gbe_dev->dev, gbe_intf); + return ret; +} + +static int gbe_release(void *intf_priv) +{ + struct gbe_intf *gbe_intf = intf_priv; + + gbe_intf->ndev->ethtool_ops = NULL; + list_del(&gbe_intf->gbe_intf_list); + devm_kfree(gbe_intf->dev, gbe_intf->slave); + devm_kfree(gbe_intf->dev, gbe_intf); + return 0; +} + +static int gbe_remove(struct netcp_device *netcp_device, void *inst_priv) +{ + struct gbe_priv *gbe_dev = inst_priv; + + del_timer_sync(&gbe_dev->timer); + cpsw_ale_stop(gbe_dev->ale); + cpsw_ale_destroy(gbe_dev->ale); + netcp_txpipe_close(&gbe_dev->tx_pipe); + free_secondary_ports(gbe_dev); + + if (!list_empty(&gbe_dev->gbe_intf_head)) + dev_alert(gbe_dev->dev, "unreleased ethss interfaces present\n"); + + devm_kfree(gbe_dev->dev, gbe_dev->hw_stats); + devm_iounmap(gbe_dev->dev, gbe_dev->ss_regs); + memset(gbe_dev, 0x00, sizeof(*gbe_dev)); + devm_kfree(gbe_dev->dev, gbe_dev); + return 0; +} + +static struct netcp_module gbe_module = { + .name = GBE_MODULE_NAME, + .owner = THIS_MODULE, + .primary = true, + .probe = gbe_probe, + .open = gbe_open, + .close = gbe_close, + .remove = gbe_remove, + .attach = gbe_attach, + .release = gbe_release, + .add_addr = gbe_add_addr, + .del_addr = gbe_del_addr, + .add_vid = gbe_add_vid, + .del_vid = gbe_del_vid, + .ioctl = gbe_ioctl, +}; + +static int __init keystone_gbe_init(void) +{ + int ret; + + ret = netcp_register_module(&gbe_module); + if (ret) + return ret; + + return 0; +} +module_init(keystone_gbe_init); + +static void __exit keystone_gbe_exit(void) +{ + netcp_unregister_module(&gbe_module); +} +module_exit(keystone_gbe_exit); diff --git a/drivers/net/ethernet/ti/netcp_sgmii.c b/drivers/net/ethernet/ti/netcp_sgmii.c new file mode 100644 index 000000000000..dbeb14266e2f --- /dev/null +++ b/drivers/net/ethernet/ti/netcp_sgmii.c @@ -0,0 +1,131 @@ +/* + * SGMI module initialisation + * + * Copyright (C) 2014 Texas Instruments Incorporated + * Authors: Sandeep Nair + * Sandeep Paulraj + * Wingman Kwok + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "netcp.h" + +#define SGMII_REG_STATUS_LOCK BIT(4) +#define SGMII_REG_STATUS_LINK BIT(0) +#define SGMII_REG_STATUS_AUTONEG BIT(2) +#define SGMII_REG_CONTROL_AUTONEG BIT(0) + +#define SGMII23_OFFSET(x) ((x - 2) * 0x100) +#define SGMII_OFFSET(x) ((x <= 1) ? (x * 0x100) : (SGMII23_OFFSET(x))) + +/* SGMII registers */ +#define SGMII_SRESET_REG(x) (SGMII_OFFSET(x) + 0x004) +#define SGMII_CTL_REG(x) (SGMII_OFFSET(x) + 0x010) +#define SGMII_STATUS_REG(x) (SGMII_OFFSET(x) + 0x014) +#define SGMII_MRADV_REG(x) (SGMII_OFFSET(x) + 0x018) + +static void sgmii_write_reg(void __iomem *base, int reg, u32 val) +{ + writel(val, base + reg); +} + +static u32 sgmii_read_reg(void __iomem *base, int reg) +{ + return readl(base + reg); +} + +static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val) +{ + writel((readl(base + reg) | val), base + reg); +} + +/* port is 0 based */ +int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port) +{ + /* Soft reset */ + sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port), 0x1); + while (sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) != 0x0) + ; + return 0; +} + +int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port) +{ + u32 status = 0, link = 0; + + status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); + if ((status & SGMII_REG_STATUS_LINK) != 0) + link = 1; + return link; +} + +int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface) +{ + unsigned int i, status, mask; + u32 mr_adv_ability; + u32 control; + + switch (interface) { + case SGMII_LINK_MAC_MAC_AUTONEG: + mr_adv_ability = 0x9801; + control = 0x21; + break; + + case SGMII_LINK_MAC_PHY: + case SGMII_LINK_MAC_PHY_NO_MDIO: + mr_adv_ability = 1; + control = 1; + break; + + case SGMII_LINK_MAC_MAC_FORCED: + mr_adv_ability = 0x9801; + control = 0x20; + break; + + case SGMII_LINK_MAC_FIBER: + mr_adv_ability = 0x20; + control = 0x1; + break; + + default: + WARN_ONCE(1, "Invalid sgmii interface: %d\n", interface); + return -EINVAL; + } + + sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), 0); + + /* Wait for the SerDes pll to lock */ + for (i = 0; i < 1000; i++) { + usleep_range(1000, 2000); + status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); + if ((status & SGMII_REG_STATUS_LOCK) != 0) + break; + } + + if ((status & SGMII_REG_STATUS_LOCK) == 0) + pr_err("serdes PLL not locked\n"); + + sgmii_write_reg(sgmii_ofs, SGMII_MRADV_REG(port), mr_adv_ability); + sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), control); + + mask = SGMII_REG_STATUS_LINK; + if (control & SGMII_REG_CONTROL_AUTONEG) + mask |= SGMII_REG_STATUS_AUTONEG; + + for (i = 0; i < 1000; i++) { + usleep_range(200, 500); + status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); + if ((status & mask) == mask) + break; + } + + return 0; +} -- cgit v1.2.1 From 90cff9e2da9f7be6d7847001f430c3e5f8e9532e Mon Sep 17 00:00:00 2001 From: Wingman Kwok Date: Thu, 15 Jan 2015 19:12:52 -0500 Subject: net: netcp: Enhance GBE driver to support 10G Ethernet This patch enhances the NetCP gbe driver to support 10GbE subsystem available in Keystone NetCP. The 3-port 10GbE switch sub-module contains the following components:- 10GbE Switch, MDIO Module, 2 PCS-R Modules (10GBase-R) and 2 SGMII modules (10/100/1000Base-T). The GBE driver together with netcp core driver provides support for 10G Ethernet on Keystone SoCs. 10GbE hardware spec is available at http://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=spruhj5&fileType=pdf Cc: David Miller Cc: Rob Herring Cc: Grant Likely Cc: Santosh Shilimkar Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Signed-off-by: Wingman Kwok Signed-off-by: Murali Karicheri Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/Makefile | 2 +- drivers/net/ethernet/ti/netcp_ethss.c | 470 ++++++++++++++++++++++++++++- drivers/net/ethernet/ti/netcp_xgbepcsr.c | 501 +++++++++++++++++++++++++++++++ 3 files changed, 958 insertions(+), 15 deletions(-) create mode 100644 drivers/net/ethernet/ti/netcp_xgbepcsr.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 6d4dde8d8fdc..465d03ddf441 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -13,4 +13,4 @@ ti_cpsw-y := cpsw_ale.o cpsw.o cpts.o obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o keystone_netcp-y := netcp_core.o netcp_ethss.o netcp_sgmii.o \ - cpsw_ale.o cpts.o + netcp_xgbepcsr.o cpsw_ale.o cpts.o diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 58f00c572546..fa1041a78b46 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -1,5 +1,5 @@ /* - * Keystone GBE subsystem code + * Keystone GBE and XGBE subsystem code * * Copyright (C) 2014 Texas Instruments Incorporated * Authors: Sandeep Nair @@ -53,6 +53,23 @@ #define GBE13_NUM_ALE_PORTS (GBE13_NUM_SLAVES + 1) #define GBE13_NUM_ALE_ENTRIES 1024 +/* 10G Ethernet SS defines */ +#define XGBE_MODULE_NAME "netcp-xgbe" +#define XGBE_SS_VERSION_10 0x4ee42100 + +#define XGBE_SERDES_REG_INDEX 1 +#define XGBE10_SGMII_MODULE_OFFSET 0x100 +#define XGBE10_SWITCH_MODULE_OFFSET 0x1000 +#define XGBE10_HOST_PORT_OFFSET 0x1034 +#define XGBE10_SLAVE_PORT_OFFSET 0x1064 +#define XGBE10_EMAC_OFFSET 0x1400 +#define XGBE10_ALE_OFFSET 0x1700 +#define XGBE10_HW_STATS_OFFSET 0x1800 +#define XGBE10_HOST_PORT_NUM 0 +#define XGBE10_NUM_SLAVES 2 +#define XGBE10_NUM_ALE_PORTS (XGBE10_NUM_SLAVES + 1) +#define XGBE10_NUM_ALE_ENTRIES 1024 + #define GBE_TIMER_INTERVAL (HZ / 2) /* Soft reset register values */ @@ -63,12 +80,15 @@ #define MACSL_RX_ENABLE_CSF BIT(23) #define MACSL_ENABLE_EXT_CTL BIT(18) +#define MACSL_XGMII_ENABLE BIT(13) +#define MACSL_XGIG_MODE BIT(8) #define MACSL_GIG_MODE BIT(7) #define MACSL_GMII_ENABLE BIT(5) #define MACSL_FULLDUPLEX BIT(0) #define GBE_CTL_P0_ENABLE BIT(2) #define GBE_REG_VAL_STAT_ENABLE_ALL 0xff +#define XGBE_REG_VAL_STAT_ENABLE_ALL 0xf #define GBE_STATS_CD_SEL BIT(28) #define GBE_PORT_MASK(x) (BIT(x) - 1) @@ -78,11 +98,19 @@ (MACSL_GIG_MODE | MACSL_GMII_ENABLE | \ MACSL_ENABLE_EXT_CTL | MACSL_RX_ENABLE_CSF) +#define GBE_DEF_10G_MAC_CONTROL \ + (MACSL_XGIG_MODE | MACSL_XGMII_ENABLE | \ + MACSL_ENABLE_EXT_CTL | MACSL_RX_ENABLE_CSF) + #define GBE_STATSA_MODULE 0 #define GBE_STATSB_MODULE 1 #define GBE_STATSC_MODULE 2 #define GBE_STATSD_MODULE 3 +#define XGBE_STATS0_MODULE 0 +#define XGBE_STATS1_MODULE 1 +#define XGBE_STATS2_MODULE 2 + #define MAX_SLAVES GBE13_NUM_SLAVES /* s: 0-based slave_port */ #define SGMII_BASE(s) \ @@ -91,12 +119,144 @@ #define GBE_TX_QUEUE 648 #define GBE_TXHOOK_ORDER 0 #define GBE_DEFAULT_ALE_AGEOUT 30 +#define SLAVE_LINK_IS_XGMII(s) ((s)->link_interface >= XGMII_LINK_MAC_PHY) #define NETCP_LINK_STATE_INVALID -1 #define GBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ offsetof(struct gbe##_##rb, rn) +#define XGBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ + offsetof(struct xgbe##_##rb, rn) #define GBE_REG_ADDR(p, rb, rn) (p->rb + p->rb##_ofs.rn) +struct xgbe_ss_regs { + u32 id_ver; + u32 synce_count; + u32 synce_mux; + u32 control; +}; + +struct xgbe_switch_regs { + u32 id_ver; + u32 control; + u32 emcontrol; + u32 stat_port_en; + u32 ptype; + u32 soft_idle; + u32 thru_rate; + u32 gap_thresh; + u32 tx_start_wds; + u32 flow_control; + u32 cppi_thresh; +}; + +struct xgbe_port_regs { + u32 blk_cnt; + u32 port_vlan; + u32 tx_pri_map; + u32 sa_lo; + u32 sa_hi; + u32 ts_ctl; + u32 ts_seq_ltype; + u32 ts_vlan; + u32 ts_ctl_ltype2; + u32 ts_ctl2; + u32 control; +}; + +struct xgbe_host_port_regs { + u32 blk_cnt; + u32 port_vlan; + u32 tx_pri_map; + u32 src_id; + u32 rx_pri_map; + u32 rx_maxlen; +}; + +struct xgbe_emac_regs { + u32 id_ver; + u32 mac_control; + u32 mac_status; + u32 soft_reset; + u32 rx_maxlen; + u32 __reserved_0; + u32 rx_pause; + u32 tx_pause; + u32 em_control; + u32 __reserved_1; + u32 tx_gap; + u32 rsvd[4]; +}; + +struct xgbe_host_hw_stats { + u32 rx_good_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 __rsvd_0[3]; + u32 rx_oversized_frames; + u32 __rsvd_1; + u32 rx_undersized_frames; + u32 __rsvd_2; + u32 overrun_type4; + u32 overrun_type5; + u32 rx_bytes; + u32 tx_good_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 __rsvd_3[9]; + u32 tx_bytes; + u32 tx_64byte_frames; + u32 tx_65_to_127byte_frames; + u32 tx_128_to_255byte_frames; + u32 tx_256_to_511byte_frames; + u32 tx_512_to_1023byte_frames; + u32 tx_1024byte_frames; + u32 net_bytes; + u32 rx_sof_overruns; + u32 rx_mof_overruns; + u32 rx_dma_overruns; +}; + +struct xgbe_hw_stats { + u32 rx_good_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 rx_pause_frames; + u32 rx_crc_errors; + u32 rx_align_code_errors; + u32 rx_oversized_frames; + u32 rx_jabber_frames; + u32 rx_undersized_frames; + u32 rx_fragments; + u32 overrun_type4; + u32 overrun_type5; + u32 rx_bytes; + u32 tx_good_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 tx_pause_frames; + u32 tx_deferred_frames; + u32 tx_collision_frames; + u32 tx_single_coll_frames; + u32 tx_mult_coll_frames; + u32 tx_excessive_collisions; + u32 tx_late_collisions; + u32 tx_underrun; + u32 tx_carrier_sense_errors; + u32 tx_bytes; + u32 tx_64byte_frames; + u32 tx_65_to_127byte_frames; + u32 tx_128_to_255byte_frames; + u32 tx_256_to_511byte_frames; + u32 tx_512_to_1023byte_frames; + u32 tx_1024byte_frames; + u32 net_bytes; + u32 rx_sof_overruns; + u32 rx_mof_overruns; + u32 rx_dma_overruns; +}; + +#define XGBE10_NUM_STAT_ENTRIES (sizeof(struct xgbe_hw_stats)/sizeof(u32)) + struct gbe_ss_regs { u32 id_ver; u32 synce_count; @@ -230,6 +390,7 @@ struct gbe_hw_stats { #define GBE13_NUM_HW_STAT_ENTRIES (sizeof(struct gbe_hw_stats)/sizeof(u32)) #define GBE13_NUM_HW_STATS_MOD 2 +#define XGBE10_NUM_HW_STATS_MOD 3 #define GBE_MAX_HW_STAT_MODS 3 #define GBE_HW_STATS_REG_MAP_SZ 0x100 @@ -303,6 +464,7 @@ struct gbe_intf { }; static struct netcp_module gbe_module; +static struct netcp_module xgbe_module; /* Statistic management */ struct netcp_ethtool_stat { @@ -471,6 +633,118 @@ static const struct netcp_ethtool_stat gbe13_et_stats[] = { {GBE_STATSD_INFO(rx_dma_overruns)}, }; +#define XGBE_STATS0_INFO(field) "GBE_0:"#field, XGBE_STATS0_MODULE, \ + FIELD_SIZEOF(struct xgbe_hw_stats, field), \ + offsetof(struct xgbe_hw_stats, field) + +#define XGBE_STATS1_INFO(field) "GBE_1:"#field, XGBE_STATS1_MODULE, \ + FIELD_SIZEOF(struct xgbe_hw_stats, field), \ + offsetof(struct xgbe_hw_stats, field) + +#define XGBE_STATS2_INFO(field) "GBE_2:"#field, XGBE_STATS2_MODULE, \ + FIELD_SIZEOF(struct xgbe_hw_stats, field), \ + offsetof(struct xgbe_hw_stats, field) + +static const struct netcp_ethtool_stat xgbe10_et_stats[] = { + /* GBE module 0 */ + {XGBE_STATS0_INFO(rx_good_frames)}, + {XGBE_STATS0_INFO(rx_broadcast_frames)}, + {XGBE_STATS0_INFO(rx_multicast_frames)}, + {XGBE_STATS0_INFO(rx_oversized_frames)}, + {XGBE_STATS0_INFO(rx_undersized_frames)}, + {XGBE_STATS0_INFO(overrun_type4)}, + {XGBE_STATS0_INFO(overrun_type5)}, + {XGBE_STATS0_INFO(rx_bytes)}, + {XGBE_STATS0_INFO(tx_good_frames)}, + {XGBE_STATS0_INFO(tx_broadcast_frames)}, + {XGBE_STATS0_INFO(tx_multicast_frames)}, + {XGBE_STATS0_INFO(tx_bytes)}, + {XGBE_STATS0_INFO(tx_64byte_frames)}, + {XGBE_STATS0_INFO(tx_65_to_127byte_frames)}, + {XGBE_STATS0_INFO(tx_128_to_255byte_frames)}, + {XGBE_STATS0_INFO(tx_256_to_511byte_frames)}, + {XGBE_STATS0_INFO(tx_512_to_1023byte_frames)}, + {XGBE_STATS0_INFO(tx_1024byte_frames)}, + {XGBE_STATS0_INFO(net_bytes)}, + {XGBE_STATS0_INFO(rx_sof_overruns)}, + {XGBE_STATS0_INFO(rx_mof_overruns)}, + {XGBE_STATS0_INFO(rx_dma_overruns)}, + /* XGBE module 1 */ + {XGBE_STATS1_INFO(rx_good_frames)}, + {XGBE_STATS1_INFO(rx_broadcast_frames)}, + {XGBE_STATS1_INFO(rx_multicast_frames)}, + {XGBE_STATS1_INFO(rx_pause_frames)}, + {XGBE_STATS1_INFO(rx_crc_errors)}, + {XGBE_STATS1_INFO(rx_align_code_errors)}, + {XGBE_STATS1_INFO(rx_oversized_frames)}, + {XGBE_STATS1_INFO(rx_jabber_frames)}, + {XGBE_STATS1_INFO(rx_undersized_frames)}, + {XGBE_STATS1_INFO(rx_fragments)}, + {XGBE_STATS1_INFO(overrun_type4)}, + {XGBE_STATS1_INFO(overrun_type5)}, + {XGBE_STATS1_INFO(rx_bytes)}, + {XGBE_STATS1_INFO(tx_good_frames)}, + {XGBE_STATS1_INFO(tx_broadcast_frames)}, + {XGBE_STATS1_INFO(tx_multicast_frames)}, + {XGBE_STATS1_INFO(tx_pause_frames)}, + {XGBE_STATS1_INFO(tx_deferred_frames)}, + {XGBE_STATS1_INFO(tx_collision_frames)}, + {XGBE_STATS1_INFO(tx_single_coll_frames)}, + {XGBE_STATS1_INFO(tx_mult_coll_frames)}, + {XGBE_STATS1_INFO(tx_excessive_collisions)}, + {XGBE_STATS1_INFO(tx_late_collisions)}, + {XGBE_STATS1_INFO(tx_underrun)}, + {XGBE_STATS1_INFO(tx_carrier_sense_errors)}, + {XGBE_STATS1_INFO(tx_bytes)}, + {XGBE_STATS1_INFO(tx_64byte_frames)}, + {XGBE_STATS1_INFO(tx_65_to_127byte_frames)}, + {XGBE_STATS1_INFO(tx_128_to_255byte_frames)}, + {XGBE_STATS1_INFO(tx_256_to_511byte_frames)}, + {XGBE_STATS1_INFO(tx_512_to_1023byte_frames)}, + {XGBE_STATS1_INFO(tx_1024byte_frames)}, + {XGBE_STATS1_INFO(net_bytes)}, + {XGBE_STATS1_INFO(rx_sof_overruns)}, + {XGBE_STATS1_INFO(rx_mof_overruns)}, + {XGBE_STATS1_INFO(rx_dma_overruns)}, + /* XGBE module 2 */ + {XGBE_STATS2_INFO(rx_good_frames)}, + {XGBE_STATS2_INFO(rx_broadcast_frames)}, + {XGBE_STATS2_INFO(rx_multicast_frames)}, + {XGBE_STATS2_INFO(rx_pause_frames)}, + {XGBE_STATS2_INFO(rx_crc_errors)}, + {XGBE_STATS2_INFO(rx_align_code_errors)}, + {XGBE_STATS2_INFO(rx_oversized_frames)}, + {XGBE_STATS2_INFO(rx_jabber_frames)}, + {XGBE_STATS2_INFO(rx_undersized_frames)}, + {XGBE_STATS2_INFO(rx_fragments)}, + {XGBE_STATS2_INFO(overrun_type4)}, + {XGBE_STATS2_INFO(overrun_type5)}, + {XGBE_STATS2_INFO(rx_bytes)}, + {XGBE_STATS2_INFO(tx_good_frames)}, + {XGBE_STATS2_INFO(tx_broadcast_frames)}, + {XGBE_STATS2_INFO(tx_multicast_frames)}, + {XGBE_STATS2_INFO(tx_pause_frames)}, + {XGBE_STATS2_INFO(tx_deferred_frames)}, + {XGBE_STATS2_INFO(tx_collision_frames)}, + {XGBE_STATS2_INFO(tx_single_coll_frames)}, + {XGBE_STATS2_INFO(tx_mult_coll_frames)}, + {XGBE_STATS2_INFO(tx_excessive_collisions)}, + {XGBE_STATS2_INFO(tx_late_collisions)}, + {XGBE_STATS2_INFO(tx_underrun)}, + {XGBE_STATS2_INFO(tx_carrier_sense_errors)}, + {XGBE_STATS2_INFO(tx_bytes)}, + {XGBE_STATS2_INFO(tx_64byte_frames)}, + {XGBE_STATS2_INFO(tx_65_to_127byte_frames)}, + {XGBE_STATS2_INFO(tx_128_to_255byte_frames)}, + {XGBE_STATS2_INFO(tx_256_to_511byte_frames)}, + {XGBE_STATS2_INFO(tx_512_to_1023byte_frames)}, + {XGBE_STATS2_INFO(tx_1024byte_frames)}, + {XGBE_STATS2_INFO(net_bytes)}, + {XGBE_STATS2_INFO(rx_sof_overruns)}, + {XGBE_STATS2_INFO(rx_mof_overruns)}, + {XGBE_STATS2_INFO(rx_dma_overruns)}, +}; + #define for_each_intf(i, priv) \ list_for_each_entry((i), &(priv)->gbe_intf_head, gbe_intf_list) @@ -631,7 +905,10 @@ static void keystone_get_ethtool_stats(struct net_device *ndev, gbe_dev = gbe_intf->gbe_dev; spin_lock_bh(&gbe_dev->hw_stats_lock); - gbe_update_stats_ver14(gbe_dev, data); + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + gbe_update_stats_ver14(gbe_dev, data); + else + gbe_update_stats(gbe_dev, data); spin_unlock_bh(&gbe_dev->hw_stats_lock); } @@ -742,8 +1019,13 @@ static void netcp_ethss_link_state_action(struct gbe_priv *gbe_dev, if (up) { mac_control = slave->mac_control; - if (phy && (phy->speed == SPEED_1000)) + if (phy && (phy->speed == SPEED_1000)) { mac_control |= MACSL_GIG_MODE; + mac_control &= ~MACSL_XGIG_MODE; + } else if (phy && (phy->speed == SPEED_10000)) { + mac_control |= MACSL_XGIG_MODE; + mac_control &= ~MACSL_GIG_MODE; + } writel(mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control)); @@ -783,7 +1065,9 @@ static void netcp_ethss_update_link_state(struct gbe_priv *gbe_dev, if (!slave->open) return; - sgmii_link_state = netcp_sgmii_get_port_link(SGMII_BASE(sp), sp); + if (!SLAVE_LINK_IS_XGMII(slave)) + sgmii_link_state = netcp_sgmii_get_port_link(SGMII_BASE(sp), + sp); phy_link_state = gbe_phy_link_status(slave); link_state = phy_link_state & sgmii_link_state; @@ -792,6 +1076,19 @@ static void netcp_ethss_update_link_state(struct gbe_priv *gbe_dev, link_state); } +static void xgbe_adjust_link(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_intf *gbe_intf; + + gbe_intf = netcp_module_get_intf_data(&xgbe_module, netcp); + if (!gbe_intf) + return; + + netcp_ethss_update_link_state(gbe_intf->gbe_dev, gbe_intf->slave, + ndev); +} + static void gbe_adjust_link(struct net_device *ndev) { struct netcp_intf *netcp = netdev_priv(ndev); @@ -839,9 +1136,19 @@ static int gbe_port_reset(struct gbe_slave *slave) static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave, int max_rx_len) { + u32 xgmii_mode; + if (max_rx_len > NETCP_MAX_FRAME_SIZE) max_rx_len = NETCP_MAX_FRAME_SIZE; + /* Enable correct MII mode at SS level */ + if ((gbe_dev->ss_version == XGBE_SS_VERSION_10) && + (slave->link_interface >= XGMII_LINK_MAC_PHY)) { + xgmii_mode = readl(GBE_REG_ADDR(gbe_dev, ss_regs, control)); + xgmii_mode |= (1 << slave->slave_num); + writel(xgmii_mode, GBE_REG_ADDR(gbe_dev, ss_regs, control)); + } + writel(max_rx_len, GBE_REG_ADDR(slave, emac_regs, rx_maxlen)); writel(slave->mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control)); } @@ -874,9 +1181,11 @@ static void gbe_sgmii_config(struct gbe_priv *priv, struct gbe_slave *slave) if ((priv->ss_version == GBE_SS_VERSION_14) && (slave->slave_num >= 2)) sgmii_port_regs = priv->sgmii_port34_regs; - netcp_sgmii_reset(sgmii_port_regs, slave->slave_num); - netcp_sgmii_config(sgmii_port_regs, slave->slave_num, - slave->link_interface); + if (!SLAVE_LINK_IS_XGMII(slave)) { + netcp_sgmii_reset(sgmii_port_regs, slave->slave_num); + netcp_sgmii_config(sgmii_port_regs, slave->slave_num, + slave->link_interface); + } } static int gbe_slave_open(struct gbe_intf *gbe_intf) @@ -909,6 +1218,9 @@ static int gbe_slave_open(struct gbe_intf *gbe_intf) } if (has_phy) { + if (priv->ss_version == XGBE_SS_VERSION_10) + hndlr = xgbe_adjust_link; + slave->phy = of_phy_connect(gbe_intf->ndev, slave->phy_node, hndlr, 0, @@ -1233,7 +1545,10 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, slave->phy_node = of_parse_phandle(node, "phy-handle", 0); slave->port_num = gbe_get_slave_port(gbe_dev, slave->slave_num); - slave->mac_control = GBE_DEF_1G_MAC_CONTROL; + if (slave->link_interface >= XGMII_LINK_MAC_PHY) + slave->mac_control = GBE_DEF_10G_MAC_CONTROL; + else + slave->mac_control = GBE_DEF_1G_MAC_CONTROL; /* Emac regs memmap are contiguous but port regs are not */ port_reg_num = slave->slave_num; @@ -1244,6 +1559,8 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, } else { port_reg_ofs = GBE13_SLAVE_PORT_OFFSET; } + } else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) { + port_reg_ofs = XGBE10_SLAVE_PORT_OFFSET; } else { dev_err(gbe_dev->dev, "unknown ethss(0x%x)\n", gbe_dev->ss_version); @@ -1252,6 +1569,8 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, if (gbe_dev->ss_version == GBE_SS_VERSION_14) emac_reg_ofs = GBE13_EMAC_OFFSET; + else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) + emac_reg_ofs = XGBE10_EMAC_OFFSET; slave->port_regs = gbe_dev->ss_regs + port_reg_ofs + (0x30 * port_reg_num); @@ -1275,10 +1594,22 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, GBE_SET_REG_OFS(slave, emac_regs, soft_reset); GBE_SET_REG_OFS(slave, emac_regs, rx_maxlen); - } else { - dev_err(gbe_dev->dev, "unknown ethss(0x%x)\n", - gbe_dev->ss_version); - return -EINVAL; + } else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) { + /* Initialize slave port register offsets */ + XGBE_SET_REG_OFS(slave, port_regs, port_vlan); + XGBE_SET_REG_OFS(slave, port_regs, tx_pri_map); + XGBE_SET_REG_OFS(slave, port_regs, sa_lo); + XGBE_SET_REG_OFS(slave, port_regs, sa_hi); + XGBE_SET_REG_OFS(slave, port_regs, ts_ctl); + XGBE_SET_REG_OFS(slave, port_regs, ts_seq_ltype); + XGBE_SET_REG_OFS(slave, port_regs, ts_vlan); + XGBE_SET_REG_OFS(slave, port_regs, ts_ctl_ltype2); + XGBE_SET_REG_OFS(slave, port_regs, ts_ctl2); + + /* Initialize EMAC register offsets */ + XGBE_SET_REG_OFS(slave, emac_regs, mac_control); + XGBE_SET_REG_OFS(slave, emac_regs, soft_reset); + XGBE_SET_REG_OFS(slave, emac_regs, rx_maxlen); } atomic_set(&slave->link_state, NETCP_LINK_STATE_INVALID); @@ -1317,7 +1648,8 @@ static void init_secondary_ports(struct gbe_priv *gbe_dev, gbe_port_config(gbe_dev, slave, gbe_dev->rx_packet_max); list_add_tail(&slave->slave_list, &gbe_dev->secondary_slaves); gbe_dev->num_slaves++; - if (slave->link_interface == SGMII_LINK_MAC_PHY) + if ((slave->link_interface == SGMII_LINK_MAC_PHY) || + (slave->link_interface == XGMII_LINK_MAC_PHY)) mac_phy_link = true; slave->open = true; @@ -1347,7 +1679,8 @@ static void init_secondary_ports(struct gbe_priv *gbe_dev, } for_each_sec_slave(slave, gbe_dev) { - if (slave->link_interface != SGMII_LINK_MAC_PHY) + if ((slave->link_interface != SGMII_LINK_MAC_PHY) && + (slave->link_interface != XGMII_LINK_MAC_PHY)) continue; slave->phy = of_phy_connect(gbe_dev->dummy_ndev, @@ -1383,6 +1716,85 @@ static void free_secondary_ports(struct gbe_priv *gbe_dev) free_netdev(gbe_dev->dummy_ndev); } +static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, + struct device_node *node) +{ + struct resource res; + void __iomem *regs; + int ret, i; + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe subsystem regs\n", + node->name); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, "Failed to map xgbe register base\n"); + return PTR_ERR(regs); + } + gbe_dev->ss_regs = regs; + + ret = of_address_to_resource(node, XGBE_SERDES_REG_INDEX, &res); + if (ret) { + dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe serdes regs\n", + node->name); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, "Failed to map xgbe serdes register base\n"); + return PTR_ERR(regs); + } + gbe_dev->xgbe_serdes_regs = regs; + + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, + XGBE10_NUM_STAT_ENTRIES * + (XGBE10_NUM_SLAVES + 1) * sizeof(u64), + GFP_KERNEL); + if (!gbe_dev->hw_stats) { + dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); + return -ENOMEM; + } + + gbe_dev->ss_version = XGBE_SS_VERSION_10; + gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + + XGBE10_SGMII_MODULE_OFFSET; + gbe_dev->switch_regs = gbe_dev->ss_regs + XGBE10_SWITCH_MODULE_OFFSET; + gbe_dev->host_port_regs = gbe_dev->ss_regs + XGBE10_HOST_PORT_OFFSET; + + for (i = 0; i < XGBE10_NUM_HW_STATS_MOD; i++) + gbe_dev->hw_stats_regs[i] = gbe_dev->ss_regs + + XGBE10_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i); + + gbe_dev->ale_reg = gbe_dev->ss_regs + XGBE10_ALE_OFFSET; + gbe_dev->ale_ports = XGBE10_NUM_ALE_PORTS; + gbe_dev->host_port = XGBE10_HOST_PORT_NUM; + gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES; + gbe_dev->et_stats = xgbe10_et_stats; + gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); + + /* Subsystem registers */ + XGBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver); + XGBE_SET_REG_OFS(gbe_dev, ss_regs, control); + + /* Switch module registers */ + XGBE_SET_REG_OFS(gbe_dev, switch_regs, id_ver); + XGBE_SET_REG_OFS(gbe_dev, switch_regs, control); + XGBE_SET_REG_OFS(gbe_dev, switch_regs, ptype); + XGBE_SET_REG_OFS(gbe_dev, switch_regs, stat_port_en); + XGBE_SET_REG_OFS(gbe_dev, switch_regs, flow_control); + + /* Host port registers */ + XGBE_SET_REG_OFS(gbe_dev, host_port_regs, port_vlan); + XGBE_SET_REG_OFS(gbe_dev, host_port_regs, tx_pri_map); + XGBE_SET_REG_OFS(gbe_dev, host_port_regs, rx_maxlen); + return 0; +} + static int get_gbe_resource_version(struct gbe_priv *gbe_dev, struct device_node *node) { @@ -1513,6 +1925,14 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, ret = set_gbe_ethss14_priv(gbe_dev, node); if (ret) goto quit; + } else if (!strcmp(node->name, "xgbe")) { + ret = set_xgbe_ethss10_priv(gbe_dev, node); + if (ret) + goto quit; + ret = netcp_xgbe_serdes_init(gbe_dev->xgbe_serdes_regs, + gbe_dev->ss_regs); + if (ret) + goto quit; } else { dev_err(dev, "unknown GBE node(%s)\n", node->name); ret = -ENODEV; @@ -1695,6 +2115,23 @@ static struct netcp_module gbe_module = { .ioctl = gbe_ioctl, }; +static struct netcp_module xgbe_module = { + .name = XGBE_MODULE_NAME, + .owner = THIS_MODULE, + .primary = true, + .probe = gbe_probe, + .open = gbe_open, + .close = gbe_close, + .remove = gbe_remove, + .attach = gbe_attach, + .release = gbe_release, + .add_addr = gbe_add_addr, + .del_addr = gbe_del_addr, + .add_vid = gbe_add_vid, + .del_vid = gbe_del_vid, + .ioctl = gbe_ioctl, +}; + static int __init keystone_gbe_init(void) { int ret; @@ -1703,6 +2140,10 @@ static int __init keystone_gbe_init(void) if (ret) return ret; + ret = netcp_register_module(&xgbe_module); + if (ret) + return ret; + return 0; } module_init(keystone_gbe_init); @@ -1710,5 +2151,6 @@ module_init(keystone_gbe_init); static void __exit keystone_gbe_exit(void) { netcp_unregister_module(&gbe_module); + netcp_unregister_module(&xgbe_module); } module_exit(keystone_gbe_exit); diff --git a/drivers/net/ethernet/ti/netcp_xgbepcsr.c b/drivers/net/ethernet/ti/netcp_xgbepcsr.c new file mode 100644 index 000000000000..33571acc52b6 --- /dev/null +++ b/drivers/net/ethernet/ti/netcp_xgbepcsr.c @@ -0,0 +1,501 @@ +/* + * XGE PCSR module initialisation + * + * Copyright (C) 2014 Texas Instruments Incorporated + * Authors: Sandeep Nair + * WingMan Kwok + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "netcp.h" + +/* XGBE registers */ +#define XGBE_CTRL_OFFSET 0x0c +#define XGBE_SGMII_1_OFFSET 0x0114 +#define XGBE_SGMII_2_OFFSET 0x0214 + +/* PCS-R registers */ +#define PCSR_CPU_CTRL_OFFSET 0x1fd0 +#define POR_EN BIT(29) + +#define reg_rmw(addr, value, mask) \ + writel(((readl(addr) & (~(mask))) | \ + (value & (mask))), (addr)) + +/* bit mask of width w at offset s */ +#define MASK_WID_SH(w, s) (((1 << w) - 1) << s) + +/* shift value v to offset s */ +#define VAL_SH(v, s) (v << s) + +#define PHY_A(serdes) 0 + +struct serdes_cfg { + u32 ofs; + u32 val; + u32 mask; +}; + +static struct serdes_cfg cfg_phyb_1p25g_156p25mhz_cmu0[] = { + {0x0000, 0x00800002, 0x00ff00ff}, + {0x0014, 0x00003838, 0x0000ffff}, + {0x0060, 0x1c44e438, 0xffffffff}, + {0x0064, 0x00c18400, 0x00ffffff}, + {0x0068, 0x17078200, 0xffffff00}, + {0x006c, 0x00000014, 0x000000ff}, + {0x0078, 0x0000c000, 0x0000ff00}, + {0x0000, 0x00000003, 0x000000ff}, +}; + +static struct serdes_cfg cfg_phyb_10p3125g_156p25mhz_cmu1[] = { + {0x0c00, 0x00030002, 0x00ff00ff}, + {0x0c14, 0x00005252, 0x0000ffff}, + {0x0c28, 0x80000000, 0xff000000}, + {0x0c2c, 0x000000f6, 0x000000ff}, + {0x0c3c, 0x04000405, 0xff00ffff}, + {0x0c40, 0xc0800000, 0xffff0000}, + {0x0c44, 0x5a202062, 0xffffffff}, + {0x0c48, 0x40040424, 0xffffffff}, + {0x0c4c, 0x00004002, 0x0000ffff}, + {0x0c50, 0x19001c00, 0xff00ff00}, + {0x0c54, 0x00002100, 0x0000ff00}, + {0x0c58, 0x00000060, 0x000000ff}, + {0x0c60, 0x80131e7c, 0xffffffff}, + {0x0c64, 0x8400cb02, 0xff00ffff}, + {0x0c68, 0x17078200, 0xffffff00}, + {0x0c6c, 0x00000016, 0x000000ff}, + {0x0c74, 0x00000400, 0x0000ff00}, + {0x0c78, 0x0000c000, 0x0000ff00}, + {0x0c00, 0x00000003, 0x000000ff}, +}; + +static struct serdes_cfg cfg_phyb_10p3125g_16bit_lane[] = { + {0x0204, 0x00000080, 0x000000ff}, + {0x0208, 0x0000920d, 0x0000ffff}, + {0x0204, 0xfc000000, 0xff000000}, + {0x0208, 0x00009104, 0x0000ffff}, + {0x0210, 0x1a000000, 0xff000000}, + {0x0214, 0x00006b58, 0x00ffffff}, + {0x0218, 0x75800084, 0xffff00ff}, + {0x022c, 0x00300000, 0x00ff0000}, + {0x0230, 0x00003800, 0x0000ff00}, + {0x024c, 0x008f0000, 0x00ff0000}, + {0x0250, 0x30000000, 0xff000000}, + {0x0260, 0x00000002, 0x000000ff}, + {0x0264, 0x00000057, 0x000000ff}, + {0x0268, 0x00575700, 0x00ffff00}, + {0x0278, 0xff000000, 0xff000000}, + {0x0280, 0x00500050, 0x00ff00ff}, + {0x0284, 0x00001f15, 0x0000ffff}, + {0x028c, 0x00006f00, 0x0000ff00}, + {0x0294, 0x00000000, 0xffffff00}, + {0x0298, 0x00002640, 0xff00ffff}, + {0x029c, 0x00000003, 0x000000ff}, + {0x02a4, 0x00000f13, 0x0000ffff}, + {0x02a8, 0x0001b600, 0x00ffff00}, + {0x0380, 0x00000030, 0x000000ff}, + {0x03c0, 0x00000200, 0x0000ff00}, + {0x03cc, 0x00000018, 0x000000ff}, + {0x03cc, 0x00000000, 0x000000ff}, +}; + +static struct serdes_cfg cfg_phyb_10p3125g_comlane[] = { + {0x0a00, 0x00000800, 0x0000ff00}, + {0x0a84, 0x00000000, 0x000000ff}, + {0x0a8c, 0x00130000, 0x00ff0000}, + {0x0a90, 0x77a00000, 0xffff0000}, + {0x0a94, 0x00007777, 0x0000ffff}, + {0x0b08, 0x000f0000, 0xffff0000}, + {0x0b0c, 0x000f0000, 0x00ffffff}, + {0x0b10, 0xbe000000, 0xff000000}, + {0x0b14, 0x000000ff, 0x000000ff}, + {0x0b18, 0x00000014, 0x000000ff}, + {0x0b5c, 0x981b0000, 0xffff0000}, + {0x0b64, 0x00001100, 0x0000ff00}, + {0x0b78, 0x00000c00, 0x0000ff00}, + {0x0abc, 0xff000000, 0xff000000}, + {0x0ac0, 0x0000008b, 0x000000ff}, +}; + +static struct serdes_cfg cfg_cm_c1_c2[] = { + {0x0208, 0x00000000, 0x00000f00}, + {0x0208, 0x00000000, 0x0000001f}, + {0x0204, 0x00000000, 0x00040000}, + {0x0208, 0x000000a0, 0x000000e0}, +}; + +static void netcp_xgbe_serdes_cmu_init(void __iomem *serdes_regs) +{ + int i; + + /* cmu0 setup */ + for (i = 0; i < ARRAY_SIZE(cfg_phyb_1p25g_156p25mhz_cmu0); i++) { + reg_rmw(serdes_regs + cfg_phyb_1p25g_156p25mhz_cmu0[i].ofs, + cfg_phyb_1p25g_156p25mhz_cmu0[i].val, + cfg_phyb_1p25g_156p25mhz_cmu0[i].mask); + } + + /* cmu1 setup */ + for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_156p25mhz_cmu1); i++) { + reg_rmw(serdes_regs + cfg_phyb_10p3125g_156p25mhz_cmu1[i].ofs, + cfg_phyb_10p3125g_156p25mhz_cmu1[i].val, + cfg_phyb_10p3125g_156p25mhz_cmu1[i].mask); + } +} + +/* lane is 0 based */ +static void netcp_xgbe_serdes_lane_config( + void __iomem *serdes_regs, int lane) +{ + int i; + + /* lane setup */ + for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_16bit_lane); i++) { + reg_rmw(serdes_regs + + cfg_phyb_10p3125g_16bit_lane[i].ofs + + (0x200 * lane), + cfg_phyb_10p3125g_16bit_lane[i].val, + cfg_phyb_10p3125g_16bit_lane[i].mask); + } + + /* disable auto negotiation*/ + reg_rmw(serdes_regs + (0x200 * lane) + 0x0380, + 0x00000000, 0x00000010); + + /* disable link training */ + reg_rmw(serdes_regs + (0x200 * lane) + 0x03c0, + 0x00000000, 0x00000200); +} + +static void netcp_xgbe_serdes_com_enable(void __iomem *serdes_regs) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_comlane); i++) { + reg_rmw(serdes_regs + cfg_phyb_10p3125g_comlane[i].ofs, + cfg_phyb_10p3125g_comlane[i].val, + cfg_phyb_10p3125g_comlane[i].mask); + } +} + +static void netcp_xgbe_serdes_lane_enable( + void __iomem *serdes_regs, int lane) +{ + /* Set Lane Control Rate */ + writel(0xe0e9e038, serdes_regs + 0x1fe0 + (4 * lane)); +} + +static void netcp_xgbe_serdes_phyb_rst_clr(void __iomem *serdes_regs) +{ + reg_rmw(serdes_regs + 0x0a00, 0x0000001f, 0x000000ff); +} + +static void netcp_xgbe_serdes_pll_disable(void __iomem *serdes_regs) +{ + writel(0x88000000, serdes_regs + 0x1ff4); +} + +static void netcp_xgbe_serdes_pll_enable(void __iomem *serdes_regs) +{ + netcp_xgbe_serdes_phyb_rst_clr(serdes_regs); + writel(0xee000000, serdes_regs + 0x1ff4); +} + +static int netcp_xgbe_wait_pll_locked(void __iomem *sw_regs) +{ + unsigned long timeout; + int ret = 0; + u32 val_1, val_0; + + timeout = jiffies + msecs_to_jiffies(500); + do { + val_0 = (readl(sw_regs + XGBE_SGMII_1_OFFSET) & BIT(4)); + val_1 = (readl(sw_regs + XGBE_SGMII_2_OFFSET) & BIT(4)); + + if (val_1 && val_0) + return 0; + + if (time_after(jiffies, timeout)) { + ret = -ETIMEDOUT; + break; + } + + cpu_relax(); + } while (true); + + pr_err("XGBE serdes not locked: time out.\n"); + return ret; +} + +static void netcp_xgbe_serdes_enable_xgmii_port(void __iomem *sw_regs) +{ + writel(0x03, sw_regs + XGBE_CTRL_OFFSET); +} + +static u32 netcp_xgbe_serdes_read_tbus_val(void __iomem *serdes_regs) +{ + u32 tmp; + + if (PHY_A(serdes_regs)) { + tmp = (readl(serdes_regs + 0x0ec) >> 24) & 0x0ff; + tmp |= ((readl(serdes_regs + 0x0fc) >> 16) & 0x00f00); + } else { + tmp = (readl(serdes_regs + 0x0f8) >> 16) & 0x0fff; + } + + return tmp; +} + +static void netcp_xgbe_serdes_write_tbus_addr(void __iomem *serdes_regs, + int select, int ofs) +{ + if (PHY_A(serdes_regs)) { + reg_rmw(serdes_regs + 0x0008, ((select << 5) + ofs) << 24, + ~0x00ffffff); + return; + } + + /* For 2 lane Phy-B, lane0 is actually lane1 */ + switch (select) { + case 1: + select = 2; + break; + case 2: + select = 3; + break; + default: + return; + } + + reg_rmw(serdes_regs + 0x00fc, ((select << 8) + ofs) << 16, ~0xf800ffff); +} + +static u32 netcp_xgbe_serdes_read_select_tbus(void __iomem *serdes_regs, + int select, int ofs) +{ + /* Set tbus address */ + netcp_xgbe_serdes_write_tbus_addr(serdes_regs, select, ofs); + /* Get TBUS Value */ + return netcp_xgbe_serdes_read_tbus_val(serdes_regs); +} + +static void netcp_xgbe_serdes_reset_cdr(void __iomem *serdes_regs, + void __iomem *sig_detect_reg, int lane) +{ + u32 tmp, dlpf, tbus; + + /*Get the DLPF values */ + tmp = netcp_xgbe_serdes_read_select_tbus( + serdes_regs, lane + 1, 5); + + dlpf = tmp >> 2; + + if (dlpf < 400 || dlpf > 700) { + reg_rmw(sig_detect_reg, VAL_SH(2, 1), MASK_WID_SH(2, 1)); + mdelay(1); + reg_rmw(sig_detect_reg, VAL_SH(0, 1), MASK_WID_SH(2, 1)); + } else { + tbus = netcp_xgbe_serdes_read_select_tbus(serdes_regs, lane + + 1, 0xe); + + pr_debug("XGBE: CDR centered, DLPF: %4d,%d,%d.\n", + tmp >> 2, tmp & 3, (tbus >> 2) & 3); + } +} + +/* Call every 100 ms */ +static int netcp_xgbe_check_link_status(void __iomem *serdes_regs, + void __iomem *sw_regs, u32 lanes, + u32 *current_state, u32 *lane_down) +{ + void __iomem *pcsr_base = sw_regs + 0x0600; + void __iomem *sig_detect_reg; + u32 pcsr_rx_stat, blk_lock, blk_errs; + int loss, i, status = 1; + + for (i = 0; i < lanes; i++) { + /* Get the Loss bit */ + loss = readl(serdes_regs + 0x1fc0 + 0x20 + (i * 0x04)) & 0x1; + + /* Get Block Errors and Block Lock bits */ + pcsr_rx_stat = readl(pcsr_base + 0x0c + (i * 0x80)); + blk_lock = (pcsr_rx_stat >> 30) & 0x1; + blk_errs = (pcsr_rx_stat >> 16) & 0x0ff; + + /* Get Signal Detect Overlay Address */ + sig_detect_reg = serdes_regs + (i * 0x200) + 0x200 + 0x04; + + /* If Block errors maxed out, attempt recovery! */ + if (blk_errs == 0x0ff) + blk_lock = 0; + + switch (current_state[i]) { + case 0: + /* if good link lock the signal detect ON! */ + if (!loss && blk_lock) { + pr_debug("XGBE PCSR Linked Lane: %d\n", i); + reg_rmw(sig_detect_reg, VAL_SH(3, 1), + MASK_WID_SH(2, 1)); + current_state[i] = 1; + } else if (!blk_lock) { + /* if no lock, then reset CDR */ + pr_debug("XGBE PCSR Recover Lane: %d\n", i); + netcp_xgbe_serdes_reset_cdr(serdes_regs, + sig_detect_reg, i); + } + break; + + case 1: + if (!blk_lock) { + /* Link Lost? */ + lane_down[i] = 1; + current_state[i] = 2; + } + break; + + case 2: + if (blk_lock) + /* Nope just noise */ + current_state[i] = 1; + else { + /* Lost the block lock, reset CDR if it is + * not centered and go back to sync state + */ + netcp_xgbe_serdes_reset_cdr(serdes_regs, + sig_detect_reg, i); + current_state[i] = 0; + } + break; + + default: + pr_err("XGBE: unknown current_state[%d] %d\n", + i, current_state[i]); + break; + } + + if (blk_errs > 0) { + /* Reset the Error counts! */ + reg_rmw(pcsr_base + 0x08 + (i * 0x80), VAL_SH(0x19, 0), + MASK_WID_SH(8, 0)); + + reg_rmw(pcsr_base + 0x08 + (i * 0x80), VAL_SH(0x00, 0), + MASK_WID_SH(8, 0)); + } + + status &= (current_state[i] == 1); + } + + return status; +} + +static int netcp_xgbe_serdes_check_lane(void __iomem *serdes_regs, + void __iomem *sw_regs) +{ + u32 current_state[2] = {0, 0}; + int retries = 0, link_up; + u32 lane_down[2]; + + do { + lane_down[0] = 0; + lane_down[1] = 0; + + link_up = netcp_xgbe_check_link_status(serdes_regs, sw_regs, 2, + current_state, + lane_down); + + /* if we did not get link up then wait 100ms before calling + * it again + */ + if (link_up) + break; + + if (lane_down[0]) + pr_debug("XGBE: detected link down on lane 0\n"); + + if (lane_down[1]) + pr_debug("XGBE: detected link down on lane 1\n"); + + if (++retries > 1) { + pr_debug("XGBE: timeout waiting for serdes link up\n"); + return -ETIMEDOUT; + } + mdelay(100); + } while (!link_up); + + pr_debug("XGBE: PCSR link is up\n"); + return 0; +} + +static void netcp_xgbe_serdes_setup_cm_c1_c2(void __iomem *serdes_regs, + int lane, int cm, int c1, int c2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cfg_cm_c1_c2); i++) { + reg_rmw(serdes_regs + cfg_cm_c1_c2[i].ofs + (0x200 * lane), + cfg_cm_c1_c2[i].val, + cfg_cm_c1_c2[i].mask); + } +} + +static void netcp_xgbe_reset_serdes(void __iomem *serdes_regs) +{ + /* Toggle the POR_EN bit in CONFIG.CPU_CTRL */ + /* enable POR_EN bit */ + reg_rmw(serdes_regs + PCSR_CPU_CTRL_OFFSET, POR_EN, POR_EN); + usleep_range(10, 100); + + /* disable POR_EN bit */ + reg_rmw(serdes_regs + PCSR_CPU_CTRL_OFFSET, 0, POR_EN); + usleep_range(10, 100); +} + +static int netcp_xgbe_serdes_config(void __iomem *serdes_regs, + void __iomem *sw_regs) +{ + u32 ret, i; + + netcp_xgbe_serdes_pll_disable(serdes_regs); + netcp_xgbe_serdes_cmu_init(serdes_regs); + + for (i = 0; i < 2; i++) + netcp_xgbe_serdes_lane_config(serdes_regs, i); + + netcp_xgbe_serdes_com_enable(serdes_regs); + /* This is EVM + RTM-BOC specific */ + for (i = 0; i < 2; i++) + netcp_xgbe_serdes_setup_cm_c1_c2(serdes_regs, i, 0, 0, 5); + + netcp_xgbe_serdes_pll_enable(serdes_regs); + for (i = 0; i < 2; i++) + netcp_xgbe_serdes_lane_enable(serdes_regs, i); + + /* SB PLL Status Poll */ + ret = netcp_xgbe_wait_pll_locked(sw_regs); + if (ret) + return ret; + + netcp_xgbe_serdes_enable_xgmii_port(sw_regs); + netcp_xgbe_serdes_check_lane(serdes_regs, sw_regs); + return ret; +} + +int netcp_xgbe_serdes_init(void __iomem *serdes_regs, void __iomem *xgbe_regs) +{ + u32 val; + + /* read COMLANE bits 4:0 */ + val = readl(serdes_regs + 0xa00); + if (val & 0x1f) { + pr_debug("XGBE: serdes already in operation - reset\n"); + netcp_xgbe_reset_serdes(serdes_regs); + } + return netcp_xgbe_serdes_config(serdes_regs, xgbe_regs); +} -- cgit v1.2.1 From 5bdc73800dad3ef5d06977a4b90304bd34353933 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 16 Jan 2015 17:55:35 +0000 Subject: mii: Handle link state changes for forced modes in mii_check_media() mii_check_media() does not update the link (carrier) state or log link changes when the link mode is forced. Drivers using the mii library must do this themselves, but most of them do not. Instead of changing them all, provide a sensible default behaviour similar to mii_check_link() when the mode is forced. via-rhine depends on it being a no-op in this case, so make its call to mii_check_media() conditional. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/pcnet32.c | 2 +- drivers/net/ethernet/via/via-rhine.c | 3 ++- drivers/net/mii.c | 12 +++++++----- 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index e2e3aaf501a2..11d6e6561df1 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -2806,7 +2806,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose) /* * Check for loss of link and link establishment. - * Can not use mii_check_media because it does nothing if mode is forced. + * Could possibly be changed to use mii_check_media instead. */ static void pcnet32_watchdog(struct net_device *dev) diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index 0ac76102b33d..17e276651601 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -1326,7 +1326,8 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; - mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media); + if (!rp->mii_if.force_media) + mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media); if (rp->mii_if.full_duplex) iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1FDuplex, diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 4a99c3919037..993570b1e2ae 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -302,7 +302,7 @@ void mii_check_link (struct mii_if_info *mii) } /** - * mii_check_media - check the MII interface for a duplex change + * mii_check_media - check the MII interface for a carrier/speed/duplex change * @mii: the MII interface * @ok_to_print: OK to print link up/down messages * @init_media: OK to save duplex mode in @mii @@ -318,10 +318,6 @@ unsigned int mii_check_media (struct mii_if_info *mii, int advertise, lpa, media, duplex; int lpa2 = 0; - /* if forced media, go no further */ - if (mii->force_media) - return 0; /* duplex did not change */ - /* check current and old link status */ old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0; new_carrier = (unsigned int) mii_link_ok(mii); @@ -345,6 +341,12 @@ unsigned int mii_check_media (struct mii_if_info *mii, */ netif_carrier_on(mii->dev); + if (mii->force_media) { + if (ok_to_print) + netdev_info(mii->dev, "link up\n"); + return 0; /* duplex did not change */ + } + /* get MII advertise and LPA values */ if ((!init_media) && (mii->advertising)) advertise = mii->advertising; -- cgit v1.2.1 From 2cee4762c528a9bd2cdff793197bf591a2196c11 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Fri, 16 Jan 2015 11:09:30 +0200 Subject: iwlwifi: mvm: validate tid and sta_id in ba_notif These are coming from the FW and are used to access arrays. Bad values can cause an out of bounds access so discard such ba_notifs and warn. CC: [3.10+] Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index c59d07567d90..650a5f0b94c7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -930,6 +930,11 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, sta_id = ba_notif->sta_id; tid = ba_notif->tid; + if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT || + tid >= IWL_MAX_TID_COUNT, + "sta_id %d tid %d", sta_id, tid)) + return 0; + rcu_read_lock(); sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); -- cgit v1.2.1 From be38a6f9f4093b0f1fa9e7d8cb47d588bc117c21 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Fri, 16 Jan 2015 14:30:28 +0000 Subject: can: move can_stats.bus_off++ from can_bus_off into can_change_state In order to be able to move the stats increment from can_bus_off() into can_change_state(), the increment had to be moved back into code that was using can_bus_off() but not can_change_state(). As a side-effect, this patch fixes the following bugs: * Redundant call to can_bus_off() in c_can. * Bus-off counted twice in xilinx_can. Signed-off-by: Andri Yngvason Signed-off-by: Marc Kleine-Budde --- drivers/net/can/bfin_can.c | 1 + drivers/net/can/c_can/c_can.c | 2 +- drivers/net/can/cc770/cc770.c | 1 + drivers/net/can/dev.c | 3 ++- drivers/net/can/janz-ican3.c | 1 + drivers/net/can/m_can/m_can.c | 1 + drivers/net/can/pch_can.c | 1 + drivers/net/can/rcar_can.c | 1 + drivers/net/can/softing/softing_main.c | 1 + drivers/net/can/spi/mcp251x.c | 1 + drivers/net/can/ti_hecc.c | 1 + drivers/net/can/usb/ems_usb.c | 1 + drivers/net/can/usb/esd_usb2.c | 1 + drivers/net/can/usb/peak_usb/pcan_usb.c | 1 + drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 1 + drivers/net/can/usb/usb_8dev.c | 1 + 16 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index 417d50998e31..e7a6363e736b 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -352,6 +352,7 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) netdev_dbg(dev, "bus-off mode interrupt\n"); state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + priv->can.can_stats.bus_off++; can_bus_off(dev); } diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index f94a9fa60488..70f77e96d409 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -866,7 +866,7 @@ static int c_can_handle_state_change(struct net_device *dev, case C_CAN_BUS_OFF: /* bus-off state */ priv->can.state = CAN_STATE_BUS_OFF; - can_bus_off(dev); + priv->can.can_stats.bus_off++; break; default: break; diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index c486fe510f37..c11d44984036 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -535,6 +535,7 @@ static int cc770_err(struct net_device *dev, u8 status) cc770_write_reg(priv, control, CTRL_INI); cf->can_id |= CAN_ERR_BUSOFF; priv->can.state = CAN_STATE_BUS_OFF; + priv->can.can_stats.bus_off++; can_bus_off(dev); } else if (status & STAT_WARN) { cf->can_id |= CAN_ERR_CRTL; diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 3ec8f6f25e5f..e54dbc1a76ba 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -289,6 +289,8 @@ static void can_update_state_error_stats(struct net_device *dev, priv->can_stats.error_passive++; break; case CAN_STATE_BUS_OFF: + priv->can_stats.bus_off++; + break; default: break; }; @@ -544,7 +546,6 @@ void can_bus_off(struct net_device *dev) netdev_dbg(dev, "bus-off\n"); netif_carrier_off(dev); - priv->can_stats.bus_off++; if (priv->restart_ms) mod_timer(&priv->restart_timer, diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 1b118394907f..0eb4d181ae4d 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -1008,6 +1008,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) if (status & SR_BS) { state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + mod->can.can_stats.bus_off++; can_bus_off(dev); } else if (status & SR_ES) { if (rxerr >= 128 || txerr >= 128) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index d7bc462aafdc..b2ecb6c5e94b 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -589,6 +589,7 @@ static int m_can_handle_state_change(struct net_device *dev, /* bus-off state */ priv->can.state = CAN_STATE_BUS_OFF; m_can_disable_all_interrupts(priv); + priv->can.can_stats.bus_off++; can_bus_off(dev); break; default: diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c index a67eb01f3028..e187ca783da0 100644 --- a/drivers/net/can/pch_can.c +++ b/drivers/net/can/pch_can.c @@ -505,6 +505,7 @@ static void pch_can_error(struct net_device *ndev, u32 status) pch_can_set_rx_all(priv, 0); state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + priv->can.can_stats.bus_off++; can_bus_off(ndev); } diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c index 91cd48ca0efc..7deb80dcbe8c 100644 --- a/drivers/net/can/rcar_can.c +++ b/drivers/net/can/rcar_can.c @@ -331,6 +331,7 @@ static void rcar_can_error(struct net_device *ndev) priv->can.state = CAN_STATE_BUS_OFF; /* Clear interrupt condition */ writeb(~RCAR_CAN_EIFR_BOEIF, &priv->regs->eifr); + priv->can.can_stats.bus_off++; can_bus_off(ndev); if (skb) cf->can_id |= CAN_ERR_BUSOFF; diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c index 2bf98d862302..7621f91a8a20 100644 --- a/drivers/net/can/softing/softing_main.c +++ b/drivers/net/can/softing/softing_main.c @@ -261,6 +261,7 @@ static int softing_handle_1(struct softing *card) ++priv->can.can_stats.error_passive; else if (can_state == CAN_STATE_BUS_OFF) { /* this calls can_close_cleanup() */ + ++priv->can.can_stats.bus_off; can_bus_off(netdev); netif_stop_queue(netdev); } diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index c66d699640a9..bf63fee4e743 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -905,6 +905,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) if (priv->can.state == CAN_STATE_BUS_OFF) { if (priv->can.restart_ms == 0) { priv->force_quit = 1; + priv->can.can_stats.bus_off++; can_bus_off(net); mcp251x_hw_sleep(spi); break; diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 9a07eafe554b..e95a9e1a889f 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -715,6 +715,7 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_CCR); /* Disable all interrupts in bus-off to avoid int hog */ hecc_write(priv, HECC_CANGIM, 0); + ++priv->can.can_stats.bus_off; can_bus_off(ndev); } diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 29d3f0938eb8..9376f5e5b94e 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -347,6 +347,7 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) dev->can.state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + dev->can.can_stats.bus_off++; can_bus_off(dev->netdev); } else if (state & SJA1000_SR_ES) { dev->can.state = CAN_STATE_ERROR_WARNING; diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index c063a54ab8dd..bacca0bd89c1 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -250,6 +250,7 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv, case ESD_BUSSTATE_BUSOFF: priv->can.state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + priv->can.can_stats.bus_off++; can_bus_off(priv->netdev); break; case ESD_BUSSTATE_WARN: diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 4e1659d07979..2a1c9ce53fae 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -488,6 +488,7 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, switch (new_state) { case CAN_STATE_BUS_OFF: cf->can_id |= CAN_ERR_BUSOFF; + mc->pdev->dev.can.can_stats.bus_off++; can_bus_off(mc->netdev); break; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 4cfa3b8605b1..145fa87c31b9 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -634,6 +634,7 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, switch (new_state) { case CAN_STATE_BUS_OFF: can_frame->can_id |= CAN_ERR_BUSOFF; + dev->can.can_stats.bus_off++; can_bus_off(netdev); break; diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index ef674ecb82f8..dd52c7a4c80d 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -377,6 +377,7 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv, case USB_8DEV_STATUSMSG_BUSOFF: priv->can.state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + priv->can.can_stats.bus_off++; can_bus_off(priv->netdev); break; case USB_8DEV_STATUSMSG_OVERRUN: -- cgit v1.2.1 From 5b5ba2af82e07a11681d9908fef0f22c9eb70abb Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 16 Jan 2015 16:52:21 +0800 Subject: can: dev: fix semicolon.cocci warnings drivers/net/can/dev.c:294:2-3: Unneeded semicolon Removes unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Cc: Andri Yngvason Signed-off-by: Fengguang Wu Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index e54dbc1a76ba..6ac02c8d747e 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -293,7 +293,7 @@ static void can_update_state_error_stats(struct net_device *dev, break; default: break; - }; + } } static int can_tx_state_to_frame(struct net_device *dev, enum can_state state) -- cgit v1.2.1 From 3673796808099abb25de5eb2bd586427dfdad439 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 27 Nov 2014 21:28:17 +0100 Subject: can: flexcan: remove unused variable This patch removes the unused variable "struct net_device *dev" from the "struct flexcan_priv". Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index b1d583ba9674..80c46ad4cee4 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -247,7 +247,6 @@ struct flexcan_devtype_data { struct flexcan_priv { struct can_priv can; - struct net_device *dev; struct napi_struct napi; void __iomem *base; @@ -1220,7 +1219,6 @@ static int flexcan_probe(struct platform_device *pdev) CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_BERR_REPORTING; priv->base = base; - priv->dev = dev; priv->clk_ipg = clk_ipg; priv->clk_per = clk_per; priv->pdata = dev_get_platdata(&pdev->dev); -- cgit v1.2.1 From ef186f25fdf00d92c6bd5d3301fc0ee44f17ca33 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 27 Nov 2014 21:28:17 +0100 Subject: can: at91_can: remove unused variable This patch removes the unused variable "struct net_device *dev" from the "struct at91_priv". Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index d0c2463b573f..eeb4b8b6b335 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -138,7 +138,6 @@ struct at91_devtype_data { struct at91_priv { struct can_priv can; /* must be the first member! */ - struct net_device *dev; struct napi_struct napi; void __iomem *reg_base; @@ -1350,7 +1349,6 @@ static int at91_can_probe(struct platform_device *pdev) priv->can.do_get_berr_counter = at91_get_berr_counter; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY; - priv->dev = dev; priv->reg_base = addr; priv->devtype_data = *devtype_data; priv->clk = clk; -- cgit v1.2.1 From 9ce578a5585c31d32325d89d2d168b93e496b4ed Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 31 Dec 2014 15:22:38 +0200 Subject: iwlwifi: mvm: don't indicate no BA if STA was in powersave If Tx failed because the STA was in powersave there's no point in sending a BAR so avoid indicating AMPDU_NO_BACK to mac80211. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index d6cdb770881a..1fff0f40f765 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -656,7 +656,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, /* Single frame failure in an AMPDU queue => send BAR */ if (txq_id >= mvm->first_agg_queue && - !(info->flags & IEEE80211_TX_STAT_ACK)) + !(info->flags & IEEE80211_TX_STAT_ACK) && + !(info->flags & IEEE80211_TX_STAT_TX_FILTERED)) info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; /* W/A FW bug: seq_ctl is wrong when the status isn't success */ -- cgit v1.2.1 From bd9993182a5bc70e9f11506ceb9ae4765e39b08c Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 28 Dec 2014 22:12:38 +0200 Subject: iwlwifi: mvm: rs: repeat initial legacy rates in LQ table Repeating the legacy rates avoids degrading quickly to lower rates due to collisions which is common when doing TCP Tx traffic in legacy. This slightly improves TCP Tx throughput while working in legacy in different scenarios. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/constants.h | 5 +++-- drivers/net/wireless/iwlwifi/mvm/rs.c | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 7cd1de820ca7..2d8e7e3f100b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -103,12 +103,13 @@ #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_DISABLE_MIMO 0 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 -#define IWL_MVM_RS_LEGACY_RETRIES_PER_RATE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 #define IWL_MVM_RS_INITIAL_MIMO_NUM_RATES 3 #define IWL_MVM_RS_INITIAL_SISO_NUM_RATES 3 -#define IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES 16 +#define IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES 2 +#define IWL_MVM_RS_INITIAL_LEGACY_RETRIES 2 +#define IWL_MVM_RS_SECONDARY_LEGACY_RETRIES 1 #define IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES 16 #define IWL_MVM_RS_SECONDARY_SISO_NUM_RATES 3 #define IWL_MVM_RS_SECONDARY_SISO_RETRIES 1 diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 7ba6e5dbbbd0..474722403556 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2862,12 +2862,13 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm, int index = *rs_table_index; for (i = 0; i < num_rates && index < end; i++) { - ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm, rate)); - for (j = 0; j < num_retries && index < end; j++, index++) + for (j = 0; j < num_retries && index < end; j++, index++) { + ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm, + rate)); rs_table[index] = ucode_rate; - - if (toggle_ant) - rs_toggle_antenna(valid_tx_ant, rate); + if (toggle_ant) + rs_toggle_antenna(valid_tx_ant, rate); + } prev_rate_idx = rate->index; bottom_reached = rs_get_lower_rate_in_column(lq_sta, rate); @@ -2875,7 +2876,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm, break; } - if (!bottom_reached) + if (!bottom_reached && !is_legacy(rate)) rate->index = prev_rate_idx; *rs_table_index = index; @@ -2925,7 +2926,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE; } else { num_rates = IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES; - num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE; + num_retries = IWL_MVM_RS_INITIAL_LEGACY_RETRIES; toggle_ant = true; } @@ -2941,7 +2942,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, lq_cmd->mimo_delim = index; } else if (is_legacy(&rate)) { num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES; - num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE; + num_retries = IWL_MVM_RS_SECONDARY_LEGACY_RETRIES; } else { WARN_ON_ONCE(1); } @@ -2955,7 +2956,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, rs_get_lower_rate_down_column(lq_sta, &rate); num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES; - num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE; + num_retries = IWL_MVM_RS_SECONDARY_LEGACY_RETRIES; rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index, num_rates, num_retries, valid_tx_ant, -- cgit v1.2.1 From fb2380a206eae822b17be63e30b5451db992e290 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Thu, 1 Jan 2015 17:42:46 +0200 Subject: iwlwifi: mvm: make sure state isn't in d0i3 when collecting fw dbg This makes sure that we're not trying to read/write any of the FW debug data collected during d0i3. Signed-off-by: Liad Kaufman Reviewed-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 1 + drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/ops.c | 5 +++++ 3 files changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index a1b276c4dee0..f1b3405c44bd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -1390,6 +1390,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, PRINT_MVM_REF(IWL_MVM_REF_TM_CMD); PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA); + PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index b2100b414055..c95297e1f836 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -276,6 +276,7 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_TM_CMD, IWL_MVM_REF_EXIT_WORK, IWL_MVM_REF_PROTECT_CSA, + IWL_MVM_REF_FW_DBG_COLLECT, /* update debugfs.c when changing this */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 239f033e3b93..b0583fc227a7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -818,9 +818,14 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) struct iwl_mvm *mvm = container_of(work, struct iwl_mvm, fw_error_dump_wk); + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_FW_DBG_COLLECT)) + return; + mutex_lock(&mvm->mutex); iwl_mvm_fw_error_dump(mvm); mutex_unlock(&mvm->mutex); + + iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT); } void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) -- cgit v1.2.1 From 9b8a7a90773c4d25d64f7e81bf32f465659d3567 Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Tue, 23 Dec 2014 10:39:48 +0200 Subject: iwlwifi: add new config and PCI IDs for 4165 series Add a new config for 4165 series over PCI and insert support for two new 4165 series PCI IDs. Signed-off-by: Oren Givon Reviewed-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-config.h | 1 + drivers/net/wireless/iwlwifi/pcie/drv.c | 2 ++ 3 files changed, 13 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 46e9c9ac6ba2..9eca5337ffde 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -156,6 +156,16 @@ const struct iwl_cfg iwl8260_2ac_cfg = { .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; +const struct iwl_cfg iwl4165_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 4165", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8000, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .name = "Intel(R) Dual Band Wireless-AC 8260", .fw_name_pre = IWL8000_FW_PRE, diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index fa0bc4845e1a..0eaafd88d97b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -378,6 +378,7 @@ extern const struct iwl_cfg iwl7265d_2n_cfg; extern const struct iwl_cfg iwl7265d_n_cfg; extern const struct iwl_cfg iwl8260_2n_cfg; extern const struct iwl_cfg iwl8260_2ac_cfg; +extern const struct iwl_cfg iwl4165_2ac_cfg; extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; extern const struct iwl_cfg iwl4165_2ac_sdio_cfg; #endif /* CONFIG_IWLMVM */ diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 3ee8e3848876..c7820aa6aaea 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -411,6 +411,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ {0} -- cgit v1.2.1 From e5d74646526335a00c9591578a188dfb59ad745b Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Tue, 9 Dec 2014 19:15:49 +0200 Subject: iwlwifi: mvm: Add debugfs entry to enable scan offload notification This option enables scan offload iteration complete notification from firmware which includes the last iteration's status and the scanned channels from the current iteration. Signed-off-by: Haim Dreyfuss Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 23 +++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 +++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/scan.c | 18 ++++++++++++++++++ 4 files changed, 48 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index f1b3405c44bd..f89b795fd4be 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -1490,6 +1490,26 @@ out: return count; } +static ssize_t iwl_dbgfs_enable_scan_iteration_notif_write(struct iwl_mvm *mvm, + char *buf, + size_t count, + loff_t *ppos) +{ + int val; + + mutex_lock(&mvm->mutex); + + if (kstrtoint(buf, 10, &val)) { + mutex_unlock(&mvm->mutex); + return -EINVAL; + } + + mvm->scan_iter_notif_enabled = val; + mutex_unlock(&mvm->mutex); + + return count; +} + MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); /* Device wide debugfs entries */ @@ -1512,6 +1532,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(enable_scan_iteration_notif, 8); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); @@ -1555,6 +1576,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(enable_scan_iteration_notif, mvm->debugfs_dir, + S_IWUSR); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index c95297e1f836..6355127487dd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -642,6 +642,8 @@ struct iwl_mvm { bool disable_power_off; bool disable_power_off_d3; + bool scan_iter_notif_enabled; + struct debugfs_blob_wrapper nvm_hw_blob; struct debugfs_blob_wrapper nvm_sw_blob; struct debugfs_blob_wrapper nvm_calib_blob; @@ -1061,6 +1063,9 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan); int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); +int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd); int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index b0583fc227a7..12b565a6f1a6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -234,6 +234,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true), + RX_HANDLER(SCAN_ITERATION_COMPLETE, + iwl_mvm_rx_scan_offload_iter_complete_notif, false), RX_HANDLER(SCAN_OFFLOAD_COMPLETE, iwl_mvm_rx_scan_offload_complete_notif, true), RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results, diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 348b9c4b694a..199f6fce0968 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -536,6 +536,19 @@ int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, return 0; } +int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_scan_complete_notif *notif = (void *)pkt->data; + + IWL_DEBUG_SCAN(mvm, + "Scan offload iteration complete: status=0x%x scanned channels=%d\n", + notif->status, notif->scanned_channels); + return 0; +} + int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) { @@ -1468,6 +1481,11 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, if (req->n_ssids == 0) flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE; +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvm->scan_iter_notif_enabled) + flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE; +#endif + cmd->scan_flags |= cpu_to_le32(flags); cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band); -- cgit v1.2.1 From e93475a0ff492000bfd911f44626a3d1d44025b5 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 4 Jan 2015 11:03:13 +0200 Subject: iwlwifi: mvm: make sure state isn't in d0i3 when stopping fw monitor In case platform is in d0i3 - make sure it is awake when writing the registers to stop the monitor when collecting FW debug data. Plus, remove unneeded mutex locking currently done. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index f89b795fd4be..afd1986a3216 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -988,9 +988,14 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - mutex_lock(&mvm->mutex); + int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); + + if (ret) + return ret; + iwl_mvm_fw_dbg_collect(mvm); - mutex_unlock(&mvm->mutex); + + iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); return count; } -- cgit v1.2.1 From e66e0b707630232b2683eacaa9f5803e008b52b3 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 29 Dec 2014 09:42:37 +0200 Subject: iwlwifi: mvm: allow to collect debug data from non-sleepable context iwl_mvm_fw_dbg_collect allows to collect debug data from the firmware. Most of the firmware interaction is done in non-sleepable context. It makes little sense to force the caller of iwl_mvm_fw_dbg_collect to sleep. Defer the actual collection to a worker so that this function will be able to be called from any context. Reviewed-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw.c | 8 +------- drivers/net/wireless/iwlwifi/mvm/ops.c | 6 ++++++ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 534ee3123a63..52338b737223 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -402,8 +402,6 @@ out: void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm) { - lockdep_assert_held(&mvm->mutex); - /* stop recording */ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); @@ -412,11 +410,7 @@ void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm) iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0); } - iwl_mvm_fw_error_dump(mvm); - - /* start recording again */ - WARN_ON_ONCE(mvm->fw->dbg_dest_tlv && - iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf)); + schedule_work(&mvm->fw_error_dump_wk); } int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 12b565a6f1a6..90143aa838be 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -825,6 +825,12 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) mutex_lock(&mvm->mutex); iwl_mvm_fw_error_dump(mvm); + + /* start recording again if the firmware is not crashed */ + WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) && + mvm->fw->dbg_dest_tlv && + iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf)); + mutex_unlock(&mvm->mutex); iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT); -- cgit v1.2.1 From afe08e1cd599adc589d2c0635f1de28f787d87e7 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 5 Jan 2015 09:48:54 +0200 Subject: iwlwifi: mvm: rs: allow to disable MIMO for P2P only This is to work around interoperability bugs with devices that don't hanle MIMO properly. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/constants.h | 2 +- drivers/net/wireless/iwlwifi/mvm/rs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 2d8e7e3f100b..f98f3efa2056 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -101,7 +101,7 @@ #define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 #define IWL_MVM_QUOTA_THRESHOLD 8 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 -#define IWL_MVM_RS_DISABLE_MIMO 0 +#define IWL_MVM_RS_DISABLE_P2P_MIMO 0 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 474722403556..57a60948a554 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2763,7 +2763,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->stbc = true; } - if (IWL_MVM_RS_DISABLE_MIMO) + if (IWL_MVM_RS_DISABLE_P2P_MIMO && sta_priv->vif->p2p) lq_sta->active_mimo2_rate = 0; lq_sta->max_legacy_rate_idx = -- cgit v1.2.1 From 44e9cd7e4044e3f3f19d0ce761c793d525509c6d Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Thu, 18 Dec 2014 12:34:01 +0200 Subject: iwlwifi: mvm: set max_out_time equal to frag_passive_dwell in fragmented scan Fragmented scan should be applied for all channels, passive and active. When scanning on passive channels the firmware uses frag_passive_dwell to define the maximum continuous scan time before returning to the operating channel. On active channels max_out_time is the parameter used by the firmware to define the maximum time allowed out of the operating channel. Since active channels' scan should also be fragmented set max_out_time equal to frag_passive_dwell. In addition: - Set max_out_time and suspend_time if the firmware doesn't support fragmented scan to avoid unexpected behavior. - Adjust max_out_time for second level of scan precedence. Signed-off-by: Haim Dreyfuss Reviewed-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 199f6fce0968..0ee0f81113fe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -309,18 +309,18 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, goto not_bound; params->suspend_time = 30; - params->max_out_time = 170; + params->max_out_time = 120; if (iwl_mvm_low_latency(mvm)) { if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_FRAGMENTED_SCAN) { params->suspend_time = 105; - params->max_out_time = 70; /* * If there is more than one active interface make * passive scan more fragmented. */ frag_passive_dwell = (global_cnt < 2) ? 40 : 20; + params->max_out_time = frag_passive_dwell; } else { params->suspend_time = 120; params->max_out_time = 120; -- cgit v1.2.1 From 2a831e0806218c1f1036e6de67ffa1c890bd017e Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Mon, 29 Dec 2014 13:02:13 +0200 Subject: iwlwifi: mvm: add print of he nvm version Print the nvm version in the log for debugging purposes. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/nvm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index d55fd8e3654c..d8ac01d97e26 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -565,6 +565,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) mvm->nvm_data = iwl_parse_nvm_sections(mvm); if (!mvm->nvm_data) return -ENODATA; + IWL_DEBUG_EEPROM(mvm->trans->dev, "nvm version = %x\n", + mvm->nvm_data->nvm_version); return 0; } -- cgit v1.2.1 From d42537bc479c9a0fdafc12c69b7f38a7a0379beb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 6 Jan 2015 09:48:54 +0200 Subject: iwlwifi: remove unused TLV capability flags The driver doesn't support the firmwares that don't have these capabilities. The code that actually used these flags has been removed already, but the flags were left for an unclear reason. Remove them. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 752c72b77fba..731f1db90857 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -235,10 +235,7 @@ enum iwl_ucode_tlv_flag { /** * enum iwl_ucode_tlv_api - ucode api - * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. - * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex - * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. @@ -246,10 +243,7 @@ enum iwl_ucode_tlv_flag { * longer than the passive one, which is essential for fragmented scan. */ enum iwl_ucode_tlv_api { - IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), - IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1), IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), - IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), -- cgit v1.2.1 From 3cae0734af7c17976ecf4e99a0447168e7fdf4cc Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Mon, 29 Dec 2014 15:43:48 +0200 Subject: iwlwifi: mvm: scan dwell time corrections Use only basic dwell time (10 ms for active scan and 110 for passive), regardless of the number of the probes and the band, if it is supported by the FW. The FW will add 3 ms for each probe sent and 10 ms for low band channels. Add a TLV flag to indicate such support in FW. This fix is needed to fix few bugs regarding scans that take too much time. Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 4 ++++ drivers/net/wireless/iwlwifi/mvm/scan.c | 17 ++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 731f1db90857..c4266b01bdb9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -241,6 +241,9 @@ enum iwl_ucode_tlv_flag { * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. + * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, + * regardless of the band or the number of the probes. FW will calculate + * the actual dwell time. */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), @@ -248,6 +251,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), + IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 0ee0f81113fe..33e42841c9a2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -173,15 +173,21 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid, * already included in the probe template, so we need to set only * req->n_ssids - 1 bits in addition to the first bit. */ -static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) +static u16 iwl_mvm_get_active_dwell(struct iwl_mvm *mvm, + enum ieee80211_band band, int n_ssids) { + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BASIC_DWELL) + return 10; if (band == IEEE80211_BAND_2GHZ) return 20 + 3 * (n_ssids + 1); return 10 + 2 * (n_ssids + 1); } -static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) +static u16 iwl_mvm_get_passive_dwell(struct iwl_mvm *mvm, + enum ieee80211_band band) { + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BASIC_DWELL) + return 110; return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10; } @@ -337,7 +343,8 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, */ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { u32 passive_dwell = - iwl_mvm_get_passive_dwell(IEEE80211_BAND_2GHZ); + iwl_mvm_get_passive_dwell(mvm, + IEEE80211_BAND_2GHZ); params->max_out_time = passive_dwell; } else { params->passive_fragmented = true; @@ -354,8 +361,8 @@ not_bound: params->dwell[band].passive = frag_passive_dwell; else params->dwell[band].passive = - iwl_mvm_get_passive_dwell(band); - params->dwell[band].active = iwl_mvm_get_active_dwell(band, + iwl_mvm_get_passive_dwell(mvm, band); + params->dwell[band].active = iwl_mvm_get_active_dwell(mvm, band, n_ssids); } } -- cgit v1.2.1 From 0294d9eece86dbe9bde7b21b097825106e3a3b4f Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 5 Jan 2015 16:52:55 +0200 Subject: iwlwifi: mvm: let the firmware configure the scheduler A new host command can be used to configure the scheduler instead of accessing the scheduler's registers from the driver. This is easier and less error prone since accessing the hardware at certain moments can lead to races with the firmware. Prefer to use the host command whenever it is available. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 3 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | 39 ++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 57 ----------------------- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 6 +-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 6 +-- drivers/net/wireless/iwlwifi/mvm/sta.c | 8 ++-- drivers/net/wireless/iwlwifi/mvm/tx.c | 2 +- drivers/net/wireless/iwlwifi/mvm/utils.c | 69 ++++++++++++++-------------- drivers/net/wireless/iwlwifi/pcie/tx.c | 14 ++++-- 9 files changed, 97 insertions(+), 107 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index c4266b01bdb9..32e8b5bf2b3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -244,6 +244,8 @@ enum iwl_ucode_tlv_flag { * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, * regardless of the band or the number of the probes. FW will calculate * the actual dwell time. + * @IWL_UCODE_TLV_API_SCD_CFG: This firmware can configure the scheduler + * through the dedicated host command. */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), @@ -252,6 +254,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), + IWL_UCODE_TLV_API_SCD_CFG = BIT(15), }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 5bca1f8bfebf..81c4ea3c6958 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -592,4 +592,43 @@ static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm_tx_resp *tx_resp) tx_resp->frame_count) & 0xfff; } +/** + * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command + * @token: + * @sta_id: station id + * @tid: + * @scd_queue: scheduler queue to confiug + * @enable: 1 queue enable, 0 queue disable + * @aggregate: 1 aggregated queue, 0 otherwise + * @tx_fifo: %enum iwl_mvm_tx_fifo + * @window: BA window size + * @ssn: SSN for the BA agreement + */ +struct iwl_scd_txq_cfg_cmd { + u8 token; + u8 sta_id; + u8 tid; + u8 scd_queue; + u8 enable; + u8 aggregate; + u8 tx_fifo; + u8 window; + __le16 ssn; + __le16 reserved; +} __packed; /* SCD_QUEUE_CFG_CMD_API_S_VER_1 */ + +/** + * struct iwl_scd_txq_cfg_rsp + * @token: taken from the command + * @sta_id: station id from the command + * @tid: tid from the command + * @scd_queue: scd_queue from the command + */ +struct iwl_scd_txq_cfg_rsp { + u8 token; + u8 sta_id; + u8 tid; + u8 scd_queue; +} __packed; /* SCD_QUEUE_CFG_RSP_API_S_VER_1 */ + #endif /* __fw_api_tx_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 88af6dd2ceaa..b1e9dac186c6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -1680,63 +1680,6 @@ struct iwl_dts_measurement_notif { __le32 voltage; } __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */ -/** - * enum iwl_scd_control - scheduler config command control flags - * @IWL_SCD_CONTROL_RM_TID: remove TID from this queue - * @IWL_SCD_CONTROL_SET_SSN: use the SSN and program it into HW - */ -enum iwl_scd_control { - IWL_SCD_CONTROL_RM_TID = BIT(4), - IWL_SCD_CONTROL_SET_SSN = BIT(5), -}; - -/** - * enum iwl_scd_flags - scheduler config command flags - * @IWL_SCD_FLAGS_SHARE_TID: multiple TIDs map to this queue - * @IWL_SCD_FLAGS_SHARE_RA: multiple RAs map to this queue - * @IWL_SCD_FLAGS_DQA_ENABLED: DQA is enabled - */ -enum iwl_scd_flags { - IWL_SCD_FLAGS_SHARE_TID = BIT(0), - IWL_SCD_FLAGS_SHARE_RA = BIT(1), - IWL_SCD_FLAGS_DQA_ENABLED = BIT(2), -}; - -#define IWL_SCDQ_INVALID_STA 0xff - -/** - * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command - * @token: dialog token addba - unused legacy - * @sta_id: station id 4-bit - * @tid: TID 0..7 - * @scd_queue: TFD queue num 0 .. 31 - * @enable: 1 queue enable, 0 queue disable - * @aggregate: 1 aggregated queue, 0 otherwise - * @tx_fifo: tx fifo num 0..7 - * @window: up to 64 - * @ssn: starting seq num 12-bit - * @control: command control flags - * @flags: flags - see &enum iwl_scd_flags - * - * Note that every time the command is sent, all parameters must - * be filled with the exception of - * - the SSN, which is only used with @IWL_SCD_CONTROL_SET_SSN - * - the window, which is only relevant when starting aggregation - */ -struct iwl_scd_txq_cfg_cmd { - u8 token; - u8 sta_id; - u8 tid; - u8 scd_queue; - u8 enable; - u8 aggregate; - u8 tx_fifo; - u8 window; - __le16 ssn; - u8 control; - u8 flags; -} __packed; - /*********************************** * TDLS API ***********************************/ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 7196b4d6b7cc..a3e9cd955e7d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -496,14 +496,14 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif) switch (vif->type) { case NL80211_IFTYPE_P2P_DEVICE: - iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE); + iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, 0); break; case NL80211_IFTYPE_AP: - iwl_mvm_disable_txq(mvm, vif->cab_queue); + iwl_mvm_disable_txq(mvm, vif->cab_queue, 0); /* fall through */ default: for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - iwl_mvm_disable_txq(mvm, vif->hw_queue[ac]); + iwl_mvm_disable_txq(mvm, vif->hw_queue[ac], 0); } } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 6355127487dd..e9c05d70dde0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -858,9 +858,9 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); } -static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm) +static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) { - return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_DQA_SUPPORT; + return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_API_SCD_CFG; } extern const u8 iwl_mvm_ac_to_tx_fifo[]; @@ -1298,7 +1298,7 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) /* hw scheduler queue config */ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg); -void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue); +void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags); static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, u8 fifo) diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index ad327984b099..b93a177b4a09 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -251,7 +251,7 @@ static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm, /* disable the TDLS STA-specific queues */ sta_msk = mvmsta->tfd_queue_msk; for_each_set_bit(i, &sta_msk, sizeof(sta_msk)) - iwl_mvm_disable_txq(mvm, i); + iwl_mvm_disable_txq(mvm, i, 0); } int iwl_mvm_add_sta(struct iwl_mvm *mvm, @@ -465,7 +465,7 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk) unsigned long i, msk = mvm->tfd_drained[sta_id]; for_each_set_bit(i, &msk, sizeof(msk)) - iwl_mvm_disable_txq(mvm, i); + iwl_mvm_disable_txq(mvm, i, 0); mvm->tfd_drained[sta_id] = 0; IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n", @@ -1058,7 +1058,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); - iwl_mvm_disable_txq(mvm, txq_id); + iwl_mvm_disable_txq(mvm, txq_id, 0); return 0; case IWL_AGG_STARTING: case IWL_EMPTYING_HW_QUEUE_ADDBA: @@ -1116,7 +1116,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); - iwl_mvm_disable_txq(mvm, tid_data->txq_id); + iwl_mvm_disable_txq(mvm, tid_data->txq_id, 0); } mvm->queue_to_mac80211[tid_data->txq_id] = diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 1fff0f40f765..8ed55d628e93 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -496,7 +496,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, IWL_DEBUG_TX_QUEUES(mvm, "Can continue DELBA flow ssn = next_recl = %d\n", tid_data->next_reclaimed); - iwl_mvm_disable_txq(mvm, tid_data->txq_id); + iwl_mvm_disable_txq(mvm, tid_data->txq_id, CMD_ASYNC); tid_data->state = IWL_AGG_OFF; /* * we can't hold the mutex - but since we are after a sequence diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index f0a114102c3f..85effe269a2a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -533,47 +533,46 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg) { - if (iwl_mvm_is_dqa_supported(mvm)) { - struct iwl_scd_txq_cfg_cmd cmd = { - .scd_queue = queue, - .enable = 1, - .window = cfg->frame_limit, - .sta_id = cfg->sta_id, - .ssn = cpu_to_le16(ssn), - .tx_fifo = cfg->fifo, - .aggregate = cfg->aggregate, - .flags = IWL_SCD_FLAGS_DQA_ENABLED, - .tid = cfg->tid, - .control = IWL_SCD_CONTROL_SET_SSN, - }; - int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, - "Failed to configure queue %d on FIFO %d\n", - queue, cfg->fifo); + struct iwl_scd_txq_cfg_cmd cmd = { + .scd_queue = queue, + .enable = 1, + .window = cfg->frame_limit, + .sta_id = cfg->sta_id, + .ssn = cpu_to_le16(ssn), + .tx_fifo = cfg->fifo, + .aggregate = cfg->aggregate, + .tid = cfg->tid, + }; + + if (!iwl_mvm_is_scd_cfg_supported(mvm)) { + iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, cfg); + return; } - iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, - iwl_mvm_is_dqa_supported(mvm) ? NULL : cfg); + iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL); + WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd), + "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); } -void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue) +void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags) { - iwl_trans_txq_disable(mvm->trans, queue, - !iwl_mvm_is_dqa_supported(mvm)); - - if (iwl_mvm_is_dqa_supported(mvm)) { - struct iwl_scd_txq_cfg_cmd cmd = { - .scd_queue = queue, - .enable = 0, - }; - int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, CMD_ASYNC, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n", - queue, ret); + struct iwl_scd_txq_cfg_cmd cmd = { + .scd_queue = queue, + .enable = 0, + }; + int ret; + + if (!iwl_mvm_is_scd_cfg_supported(mvm)) { + iwl_trans_txq_disable(mvm->trans, queue, true); + return; } + + iwl_trans_txq_disable(mvm->trans, queue, false); + ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, + sizeof(cmd), &cmd); + if (ret) + IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n", + queue, ret); } /** diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index c1c4c75026b2..d40cd4a67d6e 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1190,12 +1190,12 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, * Assumes that ssn_idx is valid (!= 0xFFF) */ trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff); trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff); + iwl_write_direct32(trans, HBUS_TARG_WRPTR, + (ssn & 0xff) | (txq_id << 8)); if (cfg) { u8 frame_limit = cfg->frame_limit; - iwl_write_direct32(trans, HBUS_TARG_WRPTR, - (ssn & 0xff) | (txq_id << 8)); iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn); /* Set up Tx window size and frame limit for this queue */ @@ -1220,11 +1220,17 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, if (txq_id == trans_pcie->cmd_queue && trans_pcie->scd_set_active) iwl_scd_enable_set_active(trans, BIT(txq_id)); + + IWL_DEBUG_TX_QUEUES(trans, + "Activate queue %d on FIFO %d WrPtr: %d\n", + txq_id, fifo, ssn & 0xff); + } else { + IWL_DEBUG_TX_QUEUES(trans, + "Activate queue %d WrPtr: %d\n", + txq_id, ssn & 0xff); } trans_pcie->txq[txq_id].active = true; - IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n", - txq_id, fifo, ssn & 0xff); } void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, -- cgit v1.2.1 From e39c1b5f5e8b157fdae0007523ffad270bcbcc3a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 9 Jan 2015 14:15:32 +0100 Subject: iwlwifi: mvm: add debugfs file for misbehaving U-APSD AP As this functionality relies on getting a firmware notification it is difficult to test. Allow accessing the data for it from debugfs to be able to trigger all kinds of scenarios to test. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 8dc3ca9f4904..5fe14591e1c4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -517,6 +517,34 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); } +static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + char buf[20]; + int len; + + len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif, + char *buf, size_t count, + loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + bool ret; + + mutex_lock(&mvm->mutex); + ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid); + mutex_unlock(&mvm->mutex); + + return ret ? count : -EINVAL; +} + #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ @@ -531,6 +559,7 @@ MVM_DEBUGFS_READ_FILE_OPS(mac_params); MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -564,6 +593,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && mvmvif == mvm->bf_allowed_vif) -- cgit v1.2.1 From 861383249d4d2e1019be79686e7250823fc102fd Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Wed, 10 Dec 2014 12:39:27 -0500 Subject: iwlwifi: mvm: add support for dumping a secondary SRAM Some HW modules have two SRAMs. In such cases add the secondary SRAM to the list of dumped segments. Signed-off-by: Ido Yariv Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-config.h | 4 ++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 28 ++++++++++++++++++++++++---- 3 files changed, 32 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 9eca5337ffde..d6c05eabb16f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -84,6 +84,8 @@ /* Memory offsets and lengths */ #define IWL8260_DCCM_OFFSET 0x800000 #define IWL8260_DCCM_LEN 0x18000 +#define IWL8260_DCCM2_OFFSET 0x880000 +#define IWL8260_DCCM2_LEN 0x8000 #define IWL8260_SMEM_OFFSET 0x400000 #define IWL8260_SMEM_LEN 0x68000 @@ -134,6 +136,8 @@ static const struct iwl_ht_params iwl8000_ht_params = { .non_shared_ant = ANT_A, \ .dccm_offset = IWL8260_DCCM_OFFSET, \ .dccm_len = IWL8260_DCCM_LEN, \ + .dccm2_offset = IWL8260_DCCM2_OFFSET, \ + .dccm2_len = IWL8260_DCCM2_LEN, \ .smem_offset = IWL8260_SMEM_OFFSET, \ .smem_len = IWL8260_SMEM_LEN diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 0eaafd88d97b..445bff690a63 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -263,6 +263,8 @@ struct iwl_pwr_tx_backoff { * station can receive in VHT * @dccm_offset: offset from which DCCM begins * @dccm_len: length of DCCM (including runtime stack CCM) + * @dccm2_offset: offset from which the second DCCM begins + * @dccm2_len: length of the second DCCM * @smem_offset: offset from which the SMEM begins * @smem_len: the length of SMEM * @@ -310,6 +312,8 @@ struct iwl_cfg { unsigned int max_vht_ampdu_exponent; const u32 dccm_offset; const u32 dccm_len; + const u32 dccm2_offset; + const u32 dccm2_len; const u32 smem_offset; const u32 smem_len; }; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index c4552b5f5c19..b5f401da91a0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -778,14 +778,19 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) unsigned long flags; int reg_val; u32 smem_len = mvm->cfg->smem_len; + u32 sram2_len = mvm->cfg->dccm2_len; lockdep_assert_held(&mvm->mutex); /* W/A for 8000 HW family A-step */ - if (mvm->cfg->smem_len && - mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) - smem_len = 0x38000; + if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) { + if (smem_len) + smem_len = 0x38000; + + if (sram2_len) + sram2_len = 0x10000; + } fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); if (!fw_error_dump) @@ -820,6 +825,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) if (smem_len) file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; + /* Make room for the secondary SRAM, if it exists */ + if (sram2_len) + file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len; + dump_file = vzalloc(file_len); if (!dump_file) { kfree(fw_error_dump); @@ -884,6 +893,17 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_mem->data, smem_len); } + if (sram2_len) { + dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem)); + dump_mem = (void *)dump_data->data; + dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); + dump_mem->offset = cpu_to_le32(mvm->cfg->dccm2_offset); + iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->dccm2_offset, + dump_mem->data, sram2_len); + } + fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); fw_error_dump->op_mode_len = file_len; if (fw_error_dump->trans_ptr) -- cgit v1.2.1 From 04fd2c28226f4ace5a7e0a4343a34e6d7c20248b Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Mon, 15 Dec 2014 17:54:16 +0200 Subject: iwlwifi: mvm: add rxf and txf to dump data When the FW is in error status - try to read the RXF and TXF (all of them) and add them to the dump data. This shouldn't happen in non-error statuses, as we don't want to stop the RXF/TXF while they are running. Signed-off-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 21 +++ drivers/net/wireless/iwlwifi/iwl-prph.h | 18 +++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 35 +++++ drivers/net/wireless/iwlwifi/mvm/fw.c | 53 +++++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 186 +++++++++++++++++++---- drivers/net/wireless/iwlwifi/mvm/mvm.h | 17 +++ drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + 7 files changed, 304 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index ec115bded88a..919a2548a92c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -134,6 +134,27 @@ struct iwl_fw_error_dump_txcmd { u8 data[]; } __packed; +/** + * struct iwl_fw_error_dump_fifo - RX/TX FIFO data + * @fifo_num: number of FIFO (starting from 0) + * @available_bytes: num of bytes available in FIFO (may be less than FIFO size) + * @wr_ptr: position of write pointer + * @rd_ptr: position of read pointer + * @fence_ptr: position of fence pointer + * @fence_mode: the current mode of the fence (before locking) - + * 0=follow RD pointer ; 1 = freeze + * @data: all of the FIFO's data + */ +struct iwl_fw_error_dump_fifo { + __le32 fifo_num; + __le32 available_bytes; + __le32 wr_ptr; + __le32 rd_ptr; + __le32 fence_ptr; + __le32 fence_mode; + u8 data[]; +} __packed; + enum iwl_fw_error_dump_family { IWL_FW_ERROR_DUMP_FAMILY_7 = 7, IWL_FW_ERROR_DUMP_FAMILY_8 = 8, diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 83ab4239082c..387a5aada0ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -359,12 +359,30 @@ enum secure_load_status_reg { /* Rx FIFO */ #define RXF_SIZE_ADDR (0xa00c88) +#define RXF_RD_D_SPACE (0xa00c40) +#define RXF_RD_WR_PTR (0xa00c50) +#define RXF_RD_RD_PTR (0xa00c54) +#define RXF_RD_FENCE_PTR (0xa00c4c) +#define RXF_SET_FENCE_MODE (0xa00c14) +#define RXF_LD_WR2FENCE (0xa00c1c) +#define RXF_FIFO_RD_FENCE_INC (0xa00c68) #define RXF_SIZE_BYTE_CND_POS (7) #define RXF_SIZE_BYTE_CNT_MSK (0x3ff << RXF_SIZE_BYTE_CND_POS) +#define RXF_DIFF_FROM_PREV (0x200) #define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10) #define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c) +/* Tx FIFO */ +#define TXF_FIFO_ITEM_CNT (0xa00438) +#define TXF_WR_PTR (0xa00414) +#define TXF_RD_PTR (0xa00410) +#define TXF_FENCE_PTR (0xa00418) +#define TXF_LOCK_FENCE (0xa00424) +#define TXF_LARC_NUM (0xa0043c) +#define TXF_READ_MODIFY_DATA (0xa00448) +#define TXF_READ_MODIFY_ADDR (0xa0044c) + /* FW monitor */ #define MON_BUFF_SAMPLE_CTL (0xa03c00) #define MON_BUFF_BASE_ADDR (0xa03c3c) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index b1e9dac186c6..b3badec1d228 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -128,6 +128,9 @@ enum { /* global key */ WEP_KEY = 0x20, + /* Memory */ + SHARED_MEM_CFG = 0x25, + /* TDLS */ TDLS_CHANNEL_SWITCH_CMD = 0x27, TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa, @@ -1821,4 +1824,36 @@ struct iwl_tdls_config_res { struct iwl_tdls_config_sta_info_res sta_info[IWL_MVM_TDLS_STA_COUNT]; } __packed; /* TDLS_CONFIG_RSP_API_S_VER_1 */ +#define TX_FIFO_MAX_NUM 8 +#define RX_FIFO_MAX_NUM 2 + +/** + * Shared memory configuration information from the FW + * + * @shared_mem_addr: shared memory addr (pre 8000 HW set to 0x0 as MARBH is not + * accessible) + * @shared_mem_size: shared memory size + * @sample_buff_addr: internal sample (mon/adc) buff addr (pre 8000 HW set to + * 0x0 as accessible only via DBGM RDAT) + * @sample_buff_size: internal sample buff size + * @txfifo_addr: start addr of TXF0 (excluding the context table 0.5KB), (pre + * 8000 HW set to 0x0 as not accessible) + * @txfifo_size: size of TXF0 ... TXF7 + * @rxfifo_size: RXF1, RXF2 sizes. If there is no RXF2, it'll have a value of 0 + * @page_buff_addr: used by UMAC and performance debug (page miss analysis), + * when paging is not supported this should be 0 + * @page_buff_size: size of %page_buff_addr + */ +struct iwl_shared_mem_cfg { + __le32 shared_mem_addr; + __le32 shared_mem_size; + __le32 sample_buff_addr; + __le32 sample_buff_size; + __le32 txfifo_addr; + __le32 txfifo_size[TX_FIFO_MAX_NUM]; + __le32 rxfifo_size[RX_FIFO_MAX_NUM]; + __le32 page_buff_addr; + __le32 page_buff_size; +} __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */ + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 52338b737223..2e12f41dd65b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -400,6 +400,57 @@ out: return ret; } +static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm) +{ + struct iwl_host_cmd cmd = { + .id = SHARED_MEM_CFG, + .flags = CMD_WANT_SKB, + .data = { NULL, }, + .len = { 0, }, + }; + struct iwl_rx_packet *pkt; + struct iwl_shared_mem_cfg *mem_cfg; + u32 i; + + lockdep_assert_held(&mvm->mutex); + + if (WARN_ON(iwl_mvm_send_cmd(mvm, &cmd))) + return; + + pkt = cmd.resp_pkt; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERR(mvm, "Bad return from SHARED_MEM_CFG (0x%08X)\n", + pkt->hdr.flags); + goto exit; + } + + mem_cfg = (void *)pkt->data; + + mvm->shared_mem_cfg.shared_mem_addr = + le32_to_cpu(mem_cfg->shared_mem_addr); + mvm->shared_mem_cfg.shared_mem_size = + le32_to_cpu(mem_cfg->shared_mem_size); + mvm->shared_mem_cfg.sample_buff_addr = + le32_to_cpu(mem_cfg->sample_buff_addr); + mvm->shared_mem_cfg.sample_buff_size = + le32_to_cpu(mem_cfg->sample_buff_size); + mvm->shared_mem_cfg.txfifo_addr = le32_to_cpu(mem_cfg->txfifo_addr); + for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++) + mvm->shared_mem_cfg.txfifo_size[i] = + le32_to_cpu(mem_cfg->txfifo_size[i]); + for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++) + mvm->shared_mem_cfg.rxfifo_size[i] = + le32_to_cpu(mem_cfg->rxfifo_size[i]); + mvm->shared_mem_cfg.page_buff_addr = + le32_to_cpu(mem_cfg->page_buff_addr); + mvm->shared_mem_cfg.page_buff_size = + le32_to_cpu(mem_cfg->page_buff_size); + IWL_DEBUG_INFO(mvm, "SHARED MEM CFG: got memory offsets/sizes\n"); + +exit: + iwl_free_resp(&cmd); +} + void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm) { /* stop recording */ @@ -495,6 +546,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } + iwl_mvm_get_shared_mem_conf(mvm); + ret = iwl_mvm_sf_update(mvm, NULL, false); if (ret) IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index b5f401da91a0..0ea0f0a2239a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -766,6 +766,132 @@ static void iwl_mvm_free_coredump(const void *data) kfree(fw_error_dump); } +static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, + struct iwl_fw_error_dump_data **dump_data) +{ + struct iwl_fw_error_dump_fifo *fifo_hdr; + u32 *fifo_data; + u32 fifo_len; + unsigned long flags; + int i, j; + + if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags)) + return; + + /* Pull RXF data from all RXFs */ + for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++) { + /* + * Keep aside the additional offset that might be needed for + * next RXF + */ + u32 offset_diff = RXF_DIFF_FROM_PREV * i; + + fifo_hdr = (void *)(*dump_data)->data; + fifo_data = (void *)fifo_hdr->data; + fifo_len = mvm->shared_mem_cfg.rxfifo_size[i]; + + /* No need to try to read the data if the length is 0 */ + if (fifo_len == 0) + continue; + + /* Add a TLV for the RXF */ + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); + (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); + + fifo_hdr->fifo_num = cpu_to_le32(i); + fifo_hdr->available_bytes = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_D_SPACE + + offset_diff)); + fifo_hdr->wr_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_WR_PTR + + offset_diff)); + fifo_hdr->rd_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_RD_PTR + + offset_diff)); + fifo_hdr->fence_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_FENCE_PTR + + offset_diff)); + fifo_hdr->fence_mode = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_SET_FENCE_MODE + + offset_diff)); + + /* Lock fence */ + iwl_trans_write_prph(mvm->trans, + RXF_SET_FENCE_MODE + offset_diff, 0x1); + /* Set fence pointer to the same place like WR pointer */ + iwl_trans_write_prph(mvm->trans, + RXF_LD_WR2FENCE + offset_diff, 0x1); + /* Set fence offset */ + iwl_trans_write_prph(mvm->trans, + RXF_LD_FENCE_OFFSET_ADDR + offset_diff, + 0x0); + + /* Read FIFO */ + fifo_len /= sizeof(u32); /* Size in DWORDS */ + for (j = 0; j < fifo_len; j++) + fifo_data[j] = iwl_trans_read_prph(mvm->trans, + RXF_FIFO_RD_FENCE_INC + + offset_diff); + *dump_data = iwl_fw_error_next_data(*dump_data); + } + + /* Pull TXF data from all TXFs */ + for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++) { + /* Mark the number of TXF we're pulling now */ + iwl_trans_write_prph(mvm->trans, TXF_LARC_NUM, i); + + fifo_hdr = (void *)(*dump_data)->data; + fifo_data = (void *)fifo_hdr->data; + fifo_len = mvm->shared_mem_cfg.txfifo_size[i]; + + /* No need to try to read the data if the length is 0 */ + if (fifo_len == 0) + continue; + + /* Add a TLV for the FIFO */ + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXF); + (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); + + fifo_hdr->fifo_num = cpu_to_le32(i); + fifo_hdr->available_bytes = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_FIFO_ITEM_CNT)); + fifo_hdr->wr_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_WR_PTR)); + fifo_hdr->rd_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_RD_PTR)); + fifo_hdr->fence_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_FENCE_PTR)); + fifo_hdr->fence_mode = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_LOCK_FENCE)); + + /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */ + iwl_trans_write_prph(mvm->trans, TXF_READ_MODIFY_ADDR, + TXF_WR_PTR); + + /* Dummy-read to advance the read pointer to the head */ + iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA); + + /* Read FIFO */ + fifo_len /= sizeof(u32); /* Size in DWORDS */ + for (j = 0; j < fifo_len; j++) + fifo_data[j] = iwl_trans_read_prph(mvm->trans, + TXF_READ_MODIFY_DATA); + *dump_data = iwl_fw_error_next_data(*dump_data); + } + + iwl_trans_release_nic_access(mvm->trans, &flags); +} + void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) { struct iwl_fw_error_dump_file *dump_file; @@ -774,9 +900,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) struct iwl_fw_error_dump_mem *dump_mem; struct iwl_mvm_dump_ptrs *fw_error_dump; u32 sram_len, sram_ofs; - u32 file_len, rxf_len; - unsigned long flags; - int reg_val; + u32 file_len, fifo_data_len = 0; u32 smem_len = mvm->cfg->smem_len; u32 sram2_len = mvm->cfg->dccm2_len; @@ -808,17 +932,39 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) sram_len = mvm->cfg->dccm_len; } - /* reading buffer size */ - reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); - rxf_len = (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS; + /* reading RXF/TXF sizes */ + if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) { + struct iwl_mvm_shared_mem_cfg *mem_cfg = &mvm->shared_mem_cfg; + int i; + + fifo_data_len = 0; + + /* Count RXF size */ + for (i = 0; i < ARRAY_SIZE(mem_cfg->rxfifo_size); i++) { + if (!mem_cfg->rxfifo_size[i]) + continue; + + /* Add header info */ + fifo_data_len += mem_cfg->rxfifo_size[i] + + sizeof(*dump_data) + + sizeof(struct iwl_fw_error_dump_fifo); + } + + for (i = 0; i < ARRAY_SIZE(mem_cfg->txfifo_size); i++) { + if (!mem_cfg->txfifo_size[i]) + continue; - /* the register holds the value divided by 128 */ - rxf_len = rxf_len << 7; + /* Add header info */ + fifo_data_len += mem_cfg->txfifo_size[i] + + sizeof(*dump_data) + + sizeof(struct iwl_fw_error_dump_fifo); + } + } file_len = sizeof(*dump_file) + - sizeof(*dump_data) * 3 + + sizeof(*dump_data) * 2 + sram_len + sizeof(*dump_mem) + - rxf_len + + fifo_data_len + sizeof(*dump_info); /* Make room for the SMEM, if it exists */ @@ -856,24 +1002,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) sizeof(dump_info->bus_human_readable)); dump_data = iwl_fw_error_next_data(dump_data); - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); - dump_data->len = cpu_to_le32(rxf_len); - - if (iwl_trans_grab_nic_access(mvm->trans, false, &flags)) { - u32 *rxf = (void *)dump_data->data; - int i; + /* We only dump the FIFOs if the FW is in error state */ + if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) + iwl_mvm_dump_fifos(mvm, &dump_data); - for (i = 0; i < (rxf_len / sizeof(u32)); i++) { - iwl_trans_write_prph(mvm->trans, - RXF_LD_FENCE_OFFSET_ADDR, - i * sizeof(u32)); - rxf[i] = iwl_trans_read_prph(mvm->trans, - RXF_FIFO_RD_FENCE_ADDR); - } - iwl_trans_release_nic_access(mvm->trans, &flags); - } - - dump_data = iwl_fw_error_next_data(dump_data); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e9c05d70dde0..aa93ee794670 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -536,6 +536,18 @@ enum iwl_mvm_tdls_cs_state { IWL_MVM_TDLS_SW_ACTIVE, }; +struct iwl_mvm_shared_mem_cfg { + u32 shared_mem_addr; + u32 shared_mem_size; + u32 sample_buff_addr; + u32 sample_buff_size; + u32 txfifo_addr; + u32 txfifo_size[TX_FIFO_MAX_NUM]; + u32 rxfifo_size[RX_FIFO_MAX_NUM]; + u32 page_buff_addr; + u32 page_buff_size; +}; + struct iwl_mvm { /* for logger access */ struct device *dev; @@ -787,6 +799,8 @@ struct iwl_mvm { u32 ch_sw_tm_ie; } peer; } tdls_cs; + + struct iwl_mvm_shared_mem_cfg shared_mem_cfg; }; /* Extract MVM priv from op_mode and _hw */ @@ -1002,6 +1016,9 @@ int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); +int iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd); /* MVM PHY */ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 90143aa838be..8bf8c2a29e5e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -270,6 +270,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(MGMT_MCAST_KEY), CMD(TX_CMD), CMD(TXPATH_FLUSH), + CMD(SHARED_MEM_CFG), CMD(MAC_CONTEXT_CMD), CMD(TIME_EVENT_CMD), CMD(TIME_EVENT_NOTIFICATION), -- cgit v1.2.1 From 66396583e1dc38359a4d182bbcf22b925f4e7233 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 7 Jan 2015 16:44:06 +0200 Subject: iwlwifi: correctly set the NMI register When we want to trigger an NMI in the device, we need to set bit 7 and not bit 0. However, older firmwares don't register to the interrupt issued by bit 7. Use bit 7 first so that the correct interrupt will be issued hoping that the firmware will react. To be on the safe side, set bit 0 in case the firmware didn't register to the proper interrupt. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-io.c | 10 +++++++--- drivers/net/wireless/iwlwifi/iwl-prph.h | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 7a2cbf6f90db..03250a45272e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -193,11 +193,15 @@ void iwl_force_nmi(struct iwl_trans *trans) * DEVICE_SET_NMI_8000B_REG - is used. */ if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) || - (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) - iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL); - else + (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) { + iwl_write_prph(trans, DEVICE_SET_NMI_REG, + DEVICE_SET_NMI_VAL_DRV); + iwl_write_prph(trans, DEVICE_SET_NMI_REG, + DEVICE_SET_NMI_VAL_HW); + } else { iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, DEVICE_SET_NMI_8000B_VAL); + } } IWL_EXPORT_SYMBOL(iwl_force_nmi); diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 387a5aada0ee..b21fcf042b77 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -108,7 +108,8 @@ /* Device NMI register */ #define DEVICE_SET_NMI_REG 0x00a01c30 -#define DEVICE_SET_NMI_VAL 0x1 +#define DEVICE_SET_NMI_VAL_HW BIT(0) +#define DEVICE_SET_NMI_VAL_DRV BIT(7) #define DEVICE_SET_NMI_8000B_REG 0x00a01c24 #define DEVICE_SET_NMI_8000B_VAL 0x1000000 -- cgit v1.2.1 From 75e52472add9bb6aa219c491103d240c899cf432 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jan 2015 15:16:03 +0100 Subject: iwlwifi: mvm: sync statistics firmware API The firmware API structs are split differently, synchronize the struct splits with the current firmware definitions. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 70 +++++++++++++++---------------- drivers/net/wireless/iwlwifi/mvm/rx.c | 4 +- 2 files changed, 37 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index b3badec1d228..1a934a64b358 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -1400,24 +1400,6 @@ struct mvm_statistics_div { __le32 reserved2; } __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */ -struct mvm_statistics_general_common { - __le32 temperature; /* radio temperature */ - __le32 temperature_m; /* radio voltage */ - struct mvm_statistics_dbg dbg; - __le32 sleep_time; - __le32 slots_out; - __le32 slots_idle; - __le32 ttl_timestamp; - struct mvm_statistics_div div; - __le32 rx_enable_counter; - /* - * num_of_sos_states: - * count the number of times we have to re-tune - * in order to get out of bad PHY status - */ - __le32 num_of_sos_states; -} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */ - struct mvm_statistics_rx_non_phy { __le32 bogus_cts; /* CTS received when not expecting CTS */ __le32 bogus_ack; /* ACK received when not expecting ACK */ @@ -1490,6 +1472,23 @@ struct mvm_statistics_rx_ht_phy { __le32 unsupport_mcs; } __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */ +struct mvm_statistics_tx_non_phy { + __le32 preamble_cnt; + __le32 rx_detected_cnt; + __le32 bt_prio_defer_cnt; + __le32 bt_prio_kill_cnt; + __le32 few_bytes_cnt; + __le32 cts_timeout; + __le32 ack_timeout; + __le32 expected_ack_cnt; + __le32 actual_ack_cnt; + __le32 dump_msdu_cnt; + __le32 burst_abort_next_frame_mismatch_cnt; + __le32 burst_abort_missing_next_frame_cnt; + __le32 cts_timeout_collision; + __le32 ack_or_ba_timeout_collision; +} __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_3 */ + #define MAX_CHAINS 3 struct mvm_statistics_tx_non_phy_agg { @@ -1520,20 +1519,7 @@ struct mvm_statistics_tx_channel_width { }; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ struct mvm_statistics_tx { - __le32 preamble_cnt; - __le32 rx_detected_cnt; - __le32 bt_prio_defer_cnt; - __le32 bt_prio_kill_cnt; - __le32 few_bytes_cnt; - __le32 cts_timeout; - __le32 ack_timeout; - __le32 expected_ack_cnt; - __le32 actual_ack_cnt; - __le32 dump_msdu_cnt; - __le32 burst_abort_next_frame_mismatch_cnt; - __le32 burst_abort_missing_next_frame_cnt; - __le32 cts_timeout_collision; - __le32 ack_or_ba_timeout_collision; + struct mvm_statistics_tx_non_phy general; struct mvm_statistics_tx_non_phy_agg agg; struct mvm_statistics_tx_channel_width channel_width; } __packed; /* STATISTICS_TX_API_S_VER_4 */ @@ -1551,7 +1537,21 @@ struct mvm_statistics_bt_activity { } __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ struct mvm_statistics_general { - struct mvm_statistics_general_common common; + __le32 radio_temperature; + __le32 radio_voltage; + struct mvm_statistics_dbg dbg; + __le32 sleep_time; + __le32 slots_out; + __le32 slots_idle; + __le32 ttl_timestamp; + struct mvm_statistics_div slow_div; + __le32 rx_enable_counter; + /* + * num_of_sos_states: + * count the number of times we have to re-tune + * in order to get out of bad PHY status + */ + __le32 num_of_sos_states; __le32 beacon_filtered; __le32 missed_beacons; __s8 beacon_filter_average_energy; @@ -1585,12 +1585,12 @@ struct mvm_statistics_rx { * one channel that has just been scanned. */ -struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */ +struct iwl_notif_statistics { __le32 flag; struct mvm_statistics_rx rx; struct mvm_statistics_tx tx; struct mvm_statistics_general general; -} __packed; +} __packed; /* STATISTICS_NTFY_API_S_VER_8 */ /*********************************** * Smart Fifo API diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 94b6e7297a1e..02e0f3703632 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -511,13 +511,13 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_notif_statistics *stats = (void *)&pkt->data; - struct mvm_statistics_general_common *common = &stats->general.common; struct iwl_mvm_stat_data data = { .stats = stats, .mvm = mvm, }; - iwl_mvm_tt_temp_changed(mvm, le32_to_cpu(common->temperature)); + iwl_mvm_tt_temp_changed(mvm, + le32_to_cpu(stats->general.radio_temperature)); iwl_mvm_update_rx_statistics(mvm, stats); -- cgit v1.2.1 From d19ac5897163aacb9d485a435f4d98f6fb209d77 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jan 2015 15:54:18 +0100 Subject: iwlwifi: mvm: move statistics API to new header file Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h | 277 ++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 209 +----------------- 2 files changed, 278 insertions(+), 208 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h new file mode 100644 index 000000000000..bda3a3691f20 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h @@ -0,0 +1,277 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + *****************************************************************************/ + +#ifndef __fw_api_stats_h__ +#define __fw_api_stats_h__ + +struct mvm_statistics_dbg { + __le32 burst_check; + __le32 burst_count; + __le32 wait_for_silence_timeout_cnt; + __le32 reserved[3]; +} __packed; /* STATISTICS_DEBUG_API_S_VER_2 */ + +struct mvm_statistics_div { + __le32 tx_on_a; + __le32 tx_on_b; + __le32 exec_time; + __le32 probe_time; + __le32 rssi_ant; + __le32 reserved2; +} __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */ + +struct mvm_statistics_rx_non_phy { + __le32 bogus_cts; /* CTS received when not expecting CTS */ + __le32 bogus_ack; /* ACK received when not expecting ACK */ + __le32 non_bssid_frames; /* number of frames with BSSID that + * doesn't belong to the STA BSSID */ + __le32 filtered_frames; /* count frames that were dumped in the + * filtering process */ + __le32 non_channel_beacons; /* beacons with our bss id but not on + * our serving channel */ + __le32 channel_beacons; /* beacons with our bss id and in our + * serving channel */ + __le32 num_missed_bcon; /* number of missed beacons */ + __le32 adc_rx_saturation_time; /* count in 0.8us units the time the + * ADC was in saturation */ + __le32 ina_detection_search_time;/* total time (in 0.8us) searched + * for INA */ + __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ + __le32 interference_data_flag; /* flag for interference data + * availability. 1 when data is + * available. */ + __le32 channel_load; /* counts RX Enable time in uSec */ + __le32 dsp_false_alarms; /* DSP false alarm (both OFDM + * and CCK) counter */ + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 beacon_rssi_c; + __le32 beacon_energy_a; + __le32 beacon_energy_b; + __le32 beacon_energy_c; + __le32 num_bt_kills; + __le32 mac_id; + __le32 directed_data_mpdu; +} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */ + +struct mvm_statistics_rx_phy { + __le32 ina_cnt; + __le32 fina_cnt; + __le32 plcp_err; + __le32 crc32_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 false_alarm_cnt; + __le32 fina_sync_err_cnt; + __le32 sfd_timeout; + __le32 fina_timeout; + __le32 unresponded_rts; + __le32 rxe_frame_limit_overrun; + __le32 sent_ack_cnt; + __le32 sent_cts_cnt; + __le32 sent_ba_rsp_cnt; + __le32 dsp_self_kill; + __le32 mh_format_err; + __le32 re_acq_main_rssi_sum; + __le32 reserved; +} __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */ + +struct mvm_statistics_rx_ht_phy { + __le32 plcp_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 crc32_err; + __le32 mh_format_err; + __le32 agg_crc32_good; + __le32 agg_mpdu_cnt; + __le32 agg_cnt; + __le32 unsupport_mcs; +} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */ + +struct mvm_statistics_tx_non_phy { + __le32 preamble_cnt; + __le32 rx_detected_cnt; + __le32 bt_prio_defer_cnt; + __le32 bt_prio_kill_cnt; + __le32 few_bytes_cnt; + __le32 cts_timeout; + __le32 ack_timeout; + __le32 expected_ack_cnt; + __le32 actual_ack_cnt; + __le32 dump_msdu_cnt; + __le32 burst_abort_next_frame_mismatch_cnt; + __le32 burst_abort_missing_next_frame_cnt; + __le32 cts_timeout_collision; + __le32 ack_or_ba_timeout_collision; +} __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_3 */ + +#define MAX_CHAINS 3 + +struct mvm_statistics_tx_non_phy_agg { + __le32 ba_timeout; + __le32 ba_reschedule_frames; + __le32 scd_query_agg_frame_cnt; + __le32 scd_query_no_agg; + __le32 scd_query_agg; + __le32 scd_query_mismatch; + __le32 frame_not_ready; + __le32 underrun; + __le32 bt_prio_kill; + __le32 rx_ba_rsp_cnt; + __s8 txpower[MAX_CHAINS]; + __s8 reserved; + __le32 reserved2; +} __packed; /* STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */ + +struct mvm_statistics_tx_channel_width { + __le32 ext_cca_narrow_ch20[1]; + __le32 ext_cca_narrow_ch40[2]; + __le32 ext_cca_narrow_ch80[3]; + __le32 ext_cca_narrow_ch160[4]; + __le32 last_tx_ch_width_indx; + __le32 rx_detected_per_ch_width[4]; + __le32 success_per_ch_width[4]; + __le32 fail_per_ch_width[4]; +}; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ + +struct mvm_statistics_tx { + struct mvm_statistics_tx_non_phy general; + struct mvm_statistics_tx_non_phy_agg agg; + struct mvm_statistics_tx_channel_width channel_width; +} __packed; /* STATISTICS_TX_API_S_VER_4 */ + + +struct mvm_statistics_bt_activity { + __le32 hi_priority_tx_req_cnt; + __le32 hi_priority_tx_denied_cnt; + __le32 lo_priority_tx_req_cnt; + __le32 lo_priority_tx_denied_cnt; + __le32 hi_priority_rx_req_cnt; + __le32 hi_priority_rx_denied_cnt; + __le32 lo_priority_rx_req_cnt; + __le32 lo_priority_rx_denied_cnt; +} __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ + +struct mvm_statistics_general { + __le32 radio_temperature; + __le32 radio_voltage; + struct mvm_statistics_dbg dbg; + __le32 sleep_time; + __le32 slots_out; + __le32 slots_idle; + __le32 ttl_timestamp; + struct mvm_statistics_div slow_div; + __le32 rx_enable_counter; + /* + * num_of_sos_states: + * count the number of times we have to re-tune + * in order to get out of bad PHY status + */ + __le32 num_of_sos_states; + __le32 beacon_filtered; + __le32 missed_beacons; + __s8 beacon_filter_average_energy; + __s8 beacon_filter_reason; + __s8 beacon_filter_current_energy; + __s8 beacon_filter_reserved; + __le32 beacon_filter_delta_time; + struct mvm_statistics_bt_activity bt_activity; +} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */ + +struct mvm_statistics_rx { + struct mvm_statistics_rx_phy ofdm; + struct mvm_statistics_rx_phy cck; + struct mvm_statistics_rx_non_phy general; + struct mvm_statistics_rx_ht_phy ofdm_ht; +} __packed; /* STATISTICS_RX_API_S_VER_3 */ + +/* + * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) + * + * By default, uCode issues this notification after receiving a beacon + * while associated. To disable this behavior, set DISABLE_NOTIF flag in the + * REPLY_STATISTICS_CMD 0x9c, above. + * + * Statistics counters continue to increment beacon after beacon, but are + * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD + * 0x9c with CLEAR_STATS bit set (see above). + * + * uCode also issues this notification during scans. uCode clears statistics + * appropriately so that each notification contains statistics for only the + * one channel that has just been scanned. + */ + +struct iwl_notif_statistics { + __le32 flag; + struct mvm_statistics_rx rx; + struct mvm_statistics_tx tx; + struct mvm_statistics_general general; +} __packed; /* STATISTICS_NTFY_API_S_VER_8 */ + +#endif /* __fw_api_stats_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 1a934a64b358..b56154fe8ec5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -74,6 +74,7 @@ #include "fw-api-d3.h" #include "fw-api-coex.h" #include "fw-api-scan.h" +#include "fw-api-stats.h" /* Tx queue numbers */ enum { @@ -1384,214 +1385,6 @@ struct iwl_mvm_marker { __le32 metadata[0]; } __packed; /* MARKER_API_S_VER_1 */ -struct mvm_statistics_dbg { - __le32 burst_check; - __le32 burst_count; - __le32 wait_for_silence_timeout_cnt; - __le32 reserved[3]; -} __packed; /* STATISTICS_DEBUG_API_S_VER_2 */ - -struct mvm_statistics_div { - __le32 tx_on_a; - __le32 tx_on_b; - __le32 exec_time; - __le32 probe_time; - __le32 rssi_ant; - __le32 reserved2; -} __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */ - -struct mvm_statistics_rx_non_phy { - __le32 bogus_cts; /* CTS received when not expecting CTS */ - __le32 bogus_ack; /* ACK received when not expecting ACK */ - __le32 non_bssid_frames; /* number of frames with BSSID that - * doesn't belong to the STA BSSID */ - __le32 filtered_frames; /* count frames that were dumped in the - * filtering process */ - __le32 non_channel_beacons; /* beacons with our bss id but not on - * our serving channel */ - __le32 channel_beacons; /* beacons with our bss id and in our - * serving channel */ - __le32 num_missed_bcon; /* number of missed beacons */ - __le32 adc_rx_saturation_time; /* count in 0.8us units the time the - * ADC was in saturation */ - __le32 ina_detection_search_time;/* total time (in 0.8us) searched - * for INA */ - __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ - __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ - __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ - __le32 interference_data_flag; /* flag for interference data - * availability. 1 when data is - * available. */ - __le32 channel_load; /* counts RX Enable time in uSec */ - __le32 dsp_false_alarms; /* DSP false alarm (both OFDM - * and CCK) counter */ - __le32 beacon_rssi_a; - __le32 beacon_rssi_b; - __le32 beacon_rssi_c; - __le32 beacon_energy_a; - __le32 beacon_energy_b; - __le32 beacon_energy_c; - __le32 num_bt_kills; - __le32 mac_id; - __le32 directed_data_mpdu; -} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */ - -struct mvm_statistics_rx_phy { - __le32 ina_cnt; - __le32 fina_cnt; - __le32 plcp_err; - __le32 crc32_err; - __le32 overrun_err; - __le32 early_overrun_err; - __le32 crc32_good; - __le32 false_alarm_cnt; - __le32 fina_sync_err_cnt; - __le32 sfd_timeout; - __le32 fina_timeout; - __le32 unresponded_rts; - __le32 rxe_frame_limit_overrun; - __le32 sent_ack_cnt; - __le32 sent_cts_cnt; - __le32 sent_ba_rsp_cnt; - __le32 dsp_self_kill; - __le32 mh_format_err; - __le32 re_acq_main_rssi_sum; - __le32 reserved; -} __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */ - -struct mvm_statistics_rx_ht_phy { - __le32 plcp_err; - __le32 overrun_err; - __le32 early_overrun_err; - __le32 crc32_good; - __le32 crc32_err; - __le32 mh_format_err; - __le32 agg_crc32_good; - __le32 agg_mpdu_cnt; - __le32 agg_cnt; - __le32 unsupport_mcs; -} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */ - -struct mvm_statistics_tx_non_phy { - __le32 preamble_cnt; - __le32 rx_detected_cnt; - __le32 bt_prio_defer_cnt; - __le32 bt_prio_kill_cnt; - __le32 few_bytes_cnt; - __le32 cts_timeout; - __le32 ack_timeout; - __le32 expected_ack_cnt; - __le32 actual_ack_cnt; - __le32 dump_msdu_cnt; - __le32 burst_abort_next_frame_mismatch_cnt; - __le32 burst_abort_missing_next_frame_cnt; - __le32 cts_timeout_collision; - __le32 ack_or_ba_timeout_collision; -} __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_3 */ - -#define MAX_CHAINS 3 - -struct mvm_statistics_tx_non_phy_agg { - __le32 ba_timeout; - __le32 ba_reschedule_frames; - __le32 scd_query_agg_frame_cnt; - __le32 scd_query_no_agg; - __le32 scd_query_agg; - __le32 scd_query_mismatch; - __le32 frame_not_ready; - __le32 underrun; - __le32 bt_prio_kill; - __le32 rx_ba_rsp_cnt; - __s8 txpower[MAX_CHAINS]; - __s8 reserved; - __le32 reserved2; -} __packed; /* STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */ - -struct mvm_statistics_tx_channel_width { - __le32 ext_cca_narrow_ch20[1]; - __le32 ext_cca_narrow_ch40[2]; - __le32 ext_cca_narrow_ch80[3]; - __le32 ext_cca_narrow_ch160[4]; - __le32 last_tx_ch_width_indx; - __le32 rx_detected_per_ch_width[4]; - __le32 success_per_ch_width[4]; - __le32 fail_per_ch_width[4]; -}; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ - -struct mvm_statistics_tx { - struct mvm_statistics_tx_non_phy general; - struct mvm_statistics_tx_non_phy_agg agg; - struct mvm_statistics_tx_channel_width channel_width; -} __packed; /* STATISTICS_TX_API_S_VER_4 */ - - -struct mvm_statistics_bt_activity { - __le32 hi_priority_tx_req_cnt; - __le32 hi_priority_tx_denied_cnt; - __le32 lo_priority_tx_req_cnt; - __le32 lo_priority_tx_denied_cnt; - __le32 hi_priority_rx_req_cnt; - __le32 hi_priority_rx_denied_cnt; - __le32 lo_priority_rx_req_cnt; - __le32 lo_priority_rx_denied_cnt; -} __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ - -struct mvm_statistics_general { - __le32 radio_temperature; - __le32 radio_voltage; - struct mvm_statistics_dbg dbg; - __le32 sleep_time; - __le32 slots_out; - __le32 slots_idle; - __le32 ttl_timestamp; - struct mvm_statistics_div slow_div; - __le32 rx_enable_counter; - /* - * num_of_sos_states: - * count the number of times we have to re-tune - * in order to get out of bad PHY status - */ - __le32 num_of_sos_states; - __le32 beacon_filtered; - __le32 missed_beacons; - __s8 beacon_filter_average_energy; - __s8 beacon_filter_reason; - __s8 beacon_filter_current_energy; - __s8 beacon_filter_reserved; - __le32 beacon_filter_delta_time; - struct mvm_statistics_bt_activity bt_activity; -} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */ - -struct mvm_statistics_rx { - struct mvm_statistics_rx_phy ofdm; - struct mvm_statistics_rx_phy cck; - struct mvm_statistics_rx_non_phy general; - struct mvm_statistics_rx_ht_phy ofdm_ht; -} __packed; /* STATISTICS_RX_API_S_VER_3 */ - -/* - * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) - * - * By default, uCode issues this notification after receiving a beacon - * while associated. To disable this behavior, set DISABLE_NOTIF flag in the - * REPLY_STATISTICS_CMD 0x9c, above. - * - * Statistics counters continue to increment beacon after beacon, but are - * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD - * 0x9c with CLEAR_STATS bit set (see above). - * - * uCode also issues this notification during scans. uCode clears statistics - * appropriately so that each notification contains statistics for only the - * one channel that has just been scanned. - */ - -struct iwl_notif_statistics { - __le32 flag; - struct mvm_statistics_rx rx; - struct mvm_statistics_tx tx; - struct mvm_statistics_general general; -} __packed; /* STATISTICS_NTFY_API_S_VER_8 */ - /*********************************** * Smart Fifo API ***********************************/ -- cgit v1.2.1 From 93d17cceb2620440aa3171e90b0ea69a97ac305d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 15 Jan 2015 12:59:26 +0100 Subject: iwlwifi: mvm: generate statistics debugfs code There's no need to duplicate the structure field name in the string, just generate the string in the macro that's there anyway. To keep the debugfs output the same, rename one (otherwise unused) field. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 162 +++++++++++------------- drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h | 2 +- 2 files changed, 78 insertions(+), 86 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index afd1986a3216..82c09d86af8c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -654,10 +654,10 @@ out: return ret ?: count; } -#define PRINT_STATS_LE32(_str, _val) \ +#define PRINT_STATS_LE32(_struct, _memb) \ pos += scnprintf(buf + pos, bufsz - pos, \ - fmt_table, _str, \ - le32_to_cpu(_val)) + fmt_table, #_memb, \ + le32_to_cpu(_struct->_memb)) static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, char __user *user_buf, size_t count, @@ -692,97 +692,89 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - OFDM"); - PRINT_STATS_LE32("ina_cnt", ofdm->ina_cnt); - PRINT_STATS_LE32("fina_cnt", ofdm->fina_cnt); - PRINT_STATS_LE32("plcp_err", ofdm->plcp_err); - PRINT_STATS_LE32("crc32_err", ofdm->crc32_err); - PRINT_STATS_LE32("overrun_err", ofdm->overrun_err); - PRINT_STATS_LE32("early_overrun_err", ofdm->early_overrun_err); - PRINT_STATS_LE32("crc32_good", ofdm->crc32_good); - PRINT_STATS_LE32("false_alarm_cnt", ofdm->false_alarm_cnt); - PRINT_STATS_LE32("fina_sync_err_cnt", ofdm->fina_sync_err_cnt); - PRINT_STATS_LE32("sfd_timeout", ofdm->sfd_timeout); - PRINT_STATS_LE32("fina_timeout", ofdm->fina_timeout); - PRINT_STATS_LE32("unresponded_rts", ofdm->unresponded_rts); - PRINT_STATS_LE32("rxe_frame_lmt_overrun", - ofdm->rxe_frame_limit_overrun); - PRINT_STATS_LE32("sent_ack_cnt", ofdm->sent_ack_cnt); - PRINT_STATS_LE32("sent_cts_cnt", ofdm->sent_cts_cnt); - PRINT_STATS_LE32("sent_ba_rsp_cnt", ofdm->sent_ba_rsp_cnt); - PRINT_STATS_LE32("dsp_self_kill", ofdm->dsp_self_kill); - PRINT_STATS_LE32("mh_format_err", ofdm->mh_format_err); - PRINT_STATS_LE32("re_acq_main_rssi_sum", ofdm->re_acq_main_rssi_sum); - PRINT_STATS_LE32("reserved", ofdm->reserved); + PRINT_STATS_LE32(ofdm, ina_cnt); + PRINT_STATS_LE32(ofdm, fina_cnt); + PRINT_STATS_LE32(ofdm, plcp_err); + PRINT_STATS_LE32(ofdm, crc32_err); + PRINT_STATS_LE32(ofdm, overrun_err); + PRINT_STATS_LE32(ofdm, early_overrun_err); + PRINT_STATS_LE32(ofdm, crc32_good); + PRINT_STATS_LE32(ofdm, false_alarm_cnt); + PRINT_STATS_LE32(ofdm, fina_sync_err_cnt); + PRINT_STATS_LE32(ofdm, sfd_timeout); + PRINT_STATS_LE32(ofdm, fina_timeout); + PRINT_STATS_LE32(ofdm, unresponded_rts); + PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(ofdm, sent_ack_cnt); + PRINT_STATS_LE32(ofdm, sent_cts_cnt); + PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt); + PRINT_STATS_LE32(ofdm, dsp_self_kill); + PRINT_STATS_LE32(ofdm, mh_format_err); + PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum); + PRINT_STATS_LE32(ofdm, reserved); pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - CCK"); - PRINT_STATS_LE32("ina_cnt", cck->ina_cnt); - PRINT_STATS_LE32("fina_cnt", cck->fina_cnt); - PRINT_STATS_LE32("plcp_err", cck->plcp_err); - PRINT_STATS_LE32("crc32_err", cck->crc32_err); - PRINT_STATS_LE32("overrun_err", cck->overrun_err); - PRINT_STATS_LE32("early_overrun_err", cck->early_overrun_err); - PRINT_STATS_LE32("crc32_good", cck->crc32_good); - PRINT_STATS_LE32("false_alarm_cnt", cck->false_alarm_cnt); - PRINT_STATS_LE32("fina_sync_err_cnt", cck->fina_sync_err_cnt); - PRINT_STATS_LE32("sfd_timeout", cck->sfd_timeout); - PRINT_STATS_LE32("fina_timeout", cck->fina_timeout); - PRINT_STATS_LE32("unresponded_rts", cck->unresponded_rts); - PRINT_STATS_LE32("rxe_frame_lmt_overrun", - cck->rxe_frame_limit_overrun); - PRINT_STATS_LE32("sent_ack_cnt", cck->sent_ack_cnt); - PRINT_STATS_LE32("sent_cts_cnt", cck->sent_cts_cnt); - PRINT_STATS_LE32("sent_ba_rsp_cnt", cck->sent_ba_rsp_cnt); - PRINT_STATS_LE32("dsp_self_kill", cck->dsp_self_kill); - PRINT_STATS_LE32("mh_format_err", cck->mh_format_err); - PRINT_STATS_LE32("re_acq_main_rssi_sum", cck->re_acq_main_rssi_sum); - PRINT_STATS_LE32("reserved", cck->reserved); + PRINT_STATS_LE32(cck, ina_cnt); + PRINT_STATS_LE32(cck, fina_cnt); + PRINT_STATS_LE32(cck, plcp_err); + PRINT_STATS_LE32(cck, crc32_err); + PRINT_STATS_LE32(cck, overrun_err); + PRINT_STATS_LE32(cck, early_overrun_err); + PRINT_STATS_LE32(cck, crc32_good); + PRINT_STATS_LE32(cck, false_alarm_cnt); + PRINT_STATS_LE32(cck, fina_sync_err_cnt); + PRINT_STATS_LE32(cck, sfd_timeout); + PRINT_STATS_LE32(cck, fina_timeout); + PRINT_STATS_LE32(cck, unresponded_rts); + PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(cck, sent_ack_cnt); + PRINT_STATS_LE32(cck, sent_cts_cnt); + PRINT_STATS_LE32(cck, sent_ba_rsp_cnt); + PRINT_STATS_LE32(cck, dsp_self_kill); + PRINT_STATS_LE32(cck, mh_format_err); + PRINT_STATS_LE32(cck, re_acq_main_rssi_sum); + PRINT_STATS_LE32(cck, reserved); pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - GENERAL"); - PRINT_STATS_LE32("bogus_cts", general->bogus_cts); - PRINT_STATS_LE32("bogus_ack", general->bogus_ack); - PRINT_STATS_LE32("non_bssid_frames", general->non_bssid_frames); - PRINT_STATS_LE32("filtered_frames", general->filtered_frames); - PRINT_STATS_LE32("non_channel_beacons", general->non_channel_beacons); - PRINT_STATS_LE32("channel_beacons", general->channel_beacons); - PRINT_STATS_LE32("num_missed_bcon", general->num_missed_bcon); - PRINT_STATS_LE32("adc_rx_saturation_time", - general->adc_rx_saturation_time); - PRINT_STATS_LE32("ina_detection_search_time", - general->ina_detection_search_time); - PRINT_STATS_LE32("beacon_silence_rssi_a", - general->beacon_silence_rssi_a); - PRINT_STATS_LE32("beacon_silence_rssi_b", - general->beacon_silence_rssi_b); - PRINT_STATS_LE32("beacon_silence_rssi_c", - general->beacon_silence_rssi_c); - PRINT_STATS_LE32("interference_data_flag", - general->interference_data_flag); - PRINT_STATS_LE32("channel_load", general->channel_load); - PRINT_STATS_LE32("dsp_false_alarms", general->dsp_false_alarms); - PRINT_STATS_LE32("beacon_rssi_a", general->beacon_rssi_a); - PRINT_STATS_LE32("beacon_rssi_b", general->beacon_rssi_b); - PRINT_STATS_LE32("beacon_rssi_c", general->beacon_rssi_c); - PRINT_STATS_LE32("beacon_energy_a", general->beacon_energy_a); - PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b); - PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c); - PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills); - PRINT_STATS_LE32("mac_id", general->mac_id); - PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu); + PRINT_STATS_LE32(general, bogus_cts); + PRINT_STATS_LE32(general, bogus_ack); + PRINT_STATS_LE32(general, non_bssid_frames); + PRINT_STATS_LE32(general, filtered_frames); + PRINT_STATS_LE32(general, non_channel_beacons); + PRINT_STATS_LE32(general, channel_beacons); + PRINT_STATS_LE32(general, num_missed_bcon); + PRINT_STATS_LE32(general, adc_rx_saturation_time); + PRINT_STATS_LE32(general, ina_detection_search_time); + PRINT_STATS_LE32(general, beacon_silence_rssi_a); + PRINT_STATS_LE32(general, beacon_silence_rssi_b); + PRINT_STATS_LE32(general, beacon_silence_rssi_c); + PRINT_STATS_LE32(general, interference_data_flag); + PRINT_STATS_LE32(general, channel_load); + PRINT_STATS_LE32(general, dsp_false_alarms); + PRINT_STATS_LE32(general, beacon_rssi_a); + PRINT_STATS_LE32(general, beacon_rssi_b); + PRINT_STATS_LE32(general, beacon_rssi_c); + PRINT_STATS_LE32(general, beacon_energy_a); + PRINT_STATS_LE32(general, beacon_energy_b); + PRINT_STATS_LE32(general, beacon_energy_c); + PRINT_STATS_LE32(general, num_bt_kills); + PRINT_STATS_LE32(general, mac_id); + PRINT_STATS_LE32(general, directed_data_mpdu); pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - HT"); - PRINT_STATS_LE32("plcp_err", ht->plcp_err); - PRINT_STATS_LE32("overrun_err", ht->overrun_err); - PRINT_STATS_LE32("early_overrun_err", ht->early_overrun_err); - PRINT_STATS_LE32("crc32_good", ht->crc32_good); - PRINT_STATS_LE32("crc32_err", ht->crc32_err); - PRINT_STATS_LE32("mh_format_err", ht->mh_format_err); - PRINT_STATS_LE32("agg_crc32_good", ht->agg_crc32_good); - PRINT_STATS_LE32("agg_mpdu_cnt", ht->agg_mpdu_cnt); - PRINT_STATS_LE32("agg_cnt", ht->agg_cnt); - PRINT_STATS_LE32("unsupport_mcs", ht->unsupport_mcs); + PRINT_STATS_LE32(ht, plcp_err); + PRINT_STATS_LE32(ht, overrun_err); + PRINT_STATS_LE32(ht, early_overrun_err); + PRINT_STATS_LE32(ht, crc32_good); + PRINT_STATS_LE32(ht, crc32_err); + PRINT_STATS_LE32(ht, mh_format_err); + PRINT_STATS_LE32(ht, agg_crc32_good); + PRINT_STATS_LE32(ht, agg_mpdu_cnt); + PRINT_STATS_LE32(ht, agg_cnt); + PRINT_STATS_LE32(ht, unsupport_mcs); mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h index bda3a3691f20..928168b18346 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h @@ -131,7 +131,7 @@ struct mvm_statistics_rx_phy { __le32 sfd_timeout; __le32 fina_timeout; __le32 unresponded_rts; - __le32 rxe_frame_limit_overrun; + __le32 rxe_frame_lmt_overrun; __le32 sent_ack_cnt; __le32 sent_cts_cnt; __le32 sent_ba_rsp_cnt; -- cgit v1.2.1 From be77c29cef285a8518078008a1751a90328f197c Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 15 Jan 2015 18:34:14 +0200 Subject: iwlwifi: mvm: rs: cleanup unuseful and overflowing traces These aren't useful and overflowing so drop them and also fix a minor typo. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 57a60948a554..dd2f966b3bf0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -917,7 +917,6 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, break; if (rate_mask & (1 << low)) break; - IWL_DEBUG_RATE(mvm, "Skipping masked lower rate: %d\n", low); } high = index; @@ -927,7 +926,6 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, break; if (rate_mask & (1 << high)) break; - IWL_DEBUG_RATE(mvm, "Skipping masked higher rate: %d\n", high); } return (high << 8) | low; @@ -2774,7 +2772,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate); IWL_DEBUG_RATE(mvm, - "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n", + "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d\n", lq_sta->active_legacy_rate, lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, -- cgit v1.2.1 From 57d7b6a4cda5a5247ab3b98a16a020af8e4f03fa Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 14 Jan 2015 21:39:34 +0200 Subject: iwlwifi: mvm: ignore temperature updates in the RX statistics notification If the firmware sends spontaneous DTS notfications with the temperature (indicated in a TLV), we can ignore the temperature we get in the RX statistics notifications. This prevents potentially handling the same temperature change twice. It also ignores notifications with temperature equal to 0 that happens from time to time. Signed-off-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/rx.c | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 32e8b5bf2b3d..115e604e1ac9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -246,6 +246,7 @@ enum iwl_ucode_tlv_flag { * the actual dwell time. * @IWL_UCODE_TLV_API_SCD_CFG: This firmware can configure the scheduler * through the dedicated host command. + * @IWL_UCODE_TLV_API_ASYNC_DTM: Async temperature notifications are supported. */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), @@ -255,6 +256,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), IWL_UCODE_TLV_API_SCD_CFG = BIT(15), + IWL_UCODE_TLV_API_ASYNC_DTM = BIT(17), }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 02e0f3703632..7919a7b00c7a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -516,7 +516,11 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, .mvm = mvm, }; - iwl_mvm_tt_temp_changed(mvm, + /* Only handle rx statistics temperature changes if async temp + * notifications are not supported + */ + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_ASYNC_DTM)) + iwl_mvm_tt_temp_changed(mvm, le32_to_cpu(stats->general.radio_temperature)); iwl_mvm_update_rx_statistics(mvm, stats); -- cgit v1.2.1 From bd1ba664147ae271e592aa90266cf9aba6efe116 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Nov 2014 20:53:45 +0100 Subject: iwlwifi: mvm: move U-APSD decision to authentication In order to change the usage of U-APSD on the fly later, move the enabling condition into a new function that is called when authenticated. This allows the module parameter to become writable, it won't take effect immediately but at least on the next association the new value will be used. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 0d3472679e4d..e3af724e0e0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1490,7 +1490,7 @@ module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable, MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)"); module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, - bool, S_IRUGO); + bool, S_IRUGO | S_IWUSR); #ifdef CONFIG_IWLWIFI_UAPSD MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)"); #else diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 076a781ceeb0..d13903eff2ec 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1354,10 +1354,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, mvm->bf_allowed_vif = mvmvif; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_CQM_RSSI; - if (mvm->fw->ucode_capa.flags & - IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && - !iwlwifi_mod_params.uapsd_disable) - vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; } /* @@ -2305,6 +2301,20 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } +static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + const u8 *bssid) +{ + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT)) + return; + + if (iwlwifi_mod_params.uapsd_disable) { + vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD; + return; + } + + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; +} + static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2364,6 +2374,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, * Reset EBS status here assuming environment has been changed. */ mvm->last_ebs_successful = true; + iwl_mvm_check_uapsd(mvm, vif, sta->addr); ret = 0; } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) { -- cgit v1.2.1 From 1c30f12ed2f53433c29e7f2f8bf1c1e1dbbdce96 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 13 Jan 2015 13:56:26 +0200 Subject: iwlwifi: mvm: BT Coex - fine tune the MPLUT register This allow to better preserve the BT performance while WiFi is running. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/constants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index f98f3efa2056..d91c46b0f888 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -94,7 +94,7 @@ #define IWL_MVM_BT_COEX_MPLUT 1 #define IWL_MVM_BT_COEX_RRC 1 #define IWL_MVM_BT_COEX_TTC 1 -#define IWL_MVM_BT_COEX_MPLUT_REG0 0x28412201 +#define IWL_MVM_BT_COEX_MPLUT_REG0 0x22002200 #define IWL_MVM_BT_COEX_MPLUT_REG1 0x11118451 #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 -- cgit v1.2.1 From 84bfffa96835435d138b315f90e5fdea1185eb4d Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 13 Jan 2015 10:16:30 +0200 Subject: iwlwifi: mvm: add support for new LTR command This new command will give finer granularity to configure the platform. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 20 ++++++++++++- drivers/net/wireless/iwlwifi/mvm/fw.c | 38 +++++++++++++++++++------ 3 files changed, 51 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 4aa26b2e2e23..b998aaf5efd1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -241,6 +241,7 @@ enum iwl_ucode_tlv_flag { * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. + * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, * regardless of the band or the number of the probes. FW will calculate * the actual dwell time. @@ -255,6 +256,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), + IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10), IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), IWL_UCODE_TLV_API_SCD_CFG = BIT(15), IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16), diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 430020047b77..4fc0938b3fb6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -91,15 +91,33 @@ enum iwl_ltr_config_flags { LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6), }; +/** + * struct iwl_ltr_config_cmd_v1 - configures the LTR + * @flags: See %enum iwl_ltr_config_flags + */ +struct iwl_ltr_config_cmd_v1 { + __le32 flags; + __le32 static_long; + __le32 static_short; +} __packed; /* LTR_CAPABLE_API_S_VER_1 */ + +#define LTR_VALID_STATES_NUM 4 + /** * struct iwl_ltr_config_cmd - configures the LTR * @flags: See %enum iwl_ltr_config_flags + * @static_long: + * @static_short: + * @ltr_cfg_values: + * @ltr_short_idle_timeout: */ struct iwl_ltr_config_cmd { __le32 flags; __le32 static_long; __le32 static_short; -} __packed; + __le32 ltr_cfg_values[LTR_VALID_STATES_NUM]; + __le32 ltr_short_idle_timeout; +} __packed; /* LTR_CAPABLE_API_S_VER_2 */ /* Radio LP RX Energy Threshold measured in dBm */ #define POWER_LPRX_RSSI_THRESHOLD 75 diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 2e12f41dd65b..a322a5e3d31b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -499,6 +499,35 @@ int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id) return ret; } +static int iwl_mvm_config_ltr_v1(struct iwl_mvm *mvm) +{ + struct iwl_ltr_config_cmd_v1 cmd_v1 = { + .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), + }; + + if (!mvm->trans->ltr_enabled) + return 0; + + return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, + sizeof(cmd_v1), &cmd_v1); +} + +static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) +{ + struct iwl_ltr_config_cmd cmd = { + .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), + }; + + if (!mvm->trans->ltr_enabled) + return 0; + + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_HDC_PHASE_0)) + return iwl_mvm_config_ltr_v1(mvm); + + return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, + sizeof(cmd), &cmd); +} + int iwl_mvm_up(struct iwl_mvm *mvm) { int ret, i; @@ -604,14 +633,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) /* Initialize tx backoffs to the minimal possible */ iwl_mvm_tt_tx_backoff(mvm, 0); - if (mvm->trans->ltr_enabled) { - struct iwl_ltr_config_cmd cmd = { - .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), - }; - - WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, - sizeof(cmd), &cmd)); - } + WARN_ON(iwl_mvm_config_ltr(mvm)); ret = iwl_mvm_power_update_device(mvm); if (ret) -- cgit v1.2.1 From 6d440b2559c9e477ff11b40c6f2dd69193d46161 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 20 Jan 2015 09:25:19 +0200 Subject: Revert "iwlwifi: mvm: drop non VO frames when flushing" This is now implemented by mac80211 (commit below). mac80211 will flush/drop the frames on the queues before suspending / disconnecting. It will then send the deauth and wait until the queues are empty. commit 3b24f4c65386dc0f2efb41027bc6e410ea2c0049 Author: Emmanuel Grumbach Date: Wed Jan 7 15:42:39 2015 +0200 mac80211: let flush() drop packets when possible This reverts commit 4e6c48e0984e28d064ee8fbc292aee7b7920c507. --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 2c79ad360cd9..cef6f3373542 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -3565,16 +3565,18 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, msk |= mvmsta->tfd_queue_msk; } - msk &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]); - - if (iwl_mvm_flush_tx_path(mvm, msk, true)) - IWL_ERR(mvm, "flush request fail\n"); - mutex_unlock(&mvm->mutex); + if (drop) { + if (iwl_mvm_flush_tx_path(mvm, msk, true)) + IWL_ERR(mvm, "flush request fail\n"); + mutex_unlock(&mvm->mutex); + } else { + mutex_unlock(&mvm->mutex); - /* this can take a while, and we may need/want other operations - * to succeed while doing this, so do it without the mutex held - */ - iwl_trans_wait_tx_queue_empty(mvm->trans, msk); + /* this can take a while, and we may need/want other operations + * to succeed while doing this, so do it without the mutex held + */ + iwl_trans_wait_tx_queue_empty(mvm->trans, msk); + } } const struct ieee80211_ops iwl_mvm_hw_ops = { -- cgit v1.2.1 From ec41088f2bff8c6b151c450798534a1037eda47e Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 12 Jan 2015 11:53:06 +0200 Subject: iwlwifi: mvm: rs: use STBC regardless of power save mode Tx STBC was used only when in CAM mode or if powersave is disabled. Effectively this meant we never used STBC as these modes aren't used on most platforms by default. Change that. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index dd2f966b3bf0..997a3831117c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1802,20 +1802,12 @@ out: static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta) { - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct ieee80211_vif *vif = mvmsta->vif; - bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION && - !vif->bss_conf.ps); - /* Our chip supports Tx STBC and the peer is an HT/VHT STA which * supports STBC of at least 1*SS */ if (!lq_sta->stbc) return false; - if (!mvm->ps_disabled && !sta_ps_disabled) - return false; - if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) return false; -- cgit v1.2.1 From aa0cb08b9575f4c37d6936b9189ecdcdbc94ee7a Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Jan 2015 16:18:11 -0500 Subject: iwlwifi: mvm: document switch case fall-through in iwl_mvm_send_sta_key Add a comment indicating that the WLAN_CIPHER_SUITE_WEP104 case falls through to the WLAN_CIPHER_SUITE_WEP40 case in iwl_mvm_send_sta_key. This will document that the lack of a break is intentional. Coverity: CID 1260023 Signed-off-by: John W. Linville Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/sta.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index b93a177b4a09..8e413d3b9c32 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1196,6 +1196,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, break; case WLAN_CIPHER_SUITE_WEP104: key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_13BYTES); + /* fall through */ case WLAN_CIPHER_SUITE_WEP40: key_flags |= cpu_to_le16(STA_KEY_FLG_WEP); memcpy(cmd.key + 3, keyconf->key, keyconf->keylen); -- cgit v1.2.1 From dad33ecfdb1d9a914df8ba879932bc930077153a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jan 2015 21:09:09 +0100 Subject: iwlwifi: pcie: init ref_lock The ref_lock that was recently added is missing initialization which makes lockdep unhappy and is generally a bad idea. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 9ee4ca0ba8d3..95c2ab1ec74c 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2348,6 +2348,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->trans = trans; spin_lock_init(&trans_pcie->irq_lock); spin_lock_init(&trans_pcie->reg_lock); + spin_lock_init(&trans_pcie->ref_lock); init_waitqueue_head(&trans_pcie->ucode_write_waitq); err = pci_enable_device(pdev); -- cgit v1.2.1 From 716e48a6505ed5a48e84bcbaa186c00b25a13484 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Mon, 12 Jan 2015 10:43:58 +0200 Subject: iwlwifi: mvm: support family 8000 C step C step functionality in the driver is exactly the same as B step besides the ucode name that present as iwlwifi-8000C-xx.ucode instead of iwlwifi-8000B-xx.ucode Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-csr.h | 1 + drivers/net/wireless/iwlwifi/mvm/nvm.c | 2 +- drivers/net/wireless/iwlwifi/pcie/trans.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 7f40cf36ec0e..faa17f2e352a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -307,6 +307,7 @@ enum { SILICON_A_STEP = 0, SILICON_B_STEP, + SILICON_C_STEP, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index d8ac01d97e26..5383429d96c1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -356,7 +356,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) max_section_size = IWL_MAX_NVM_SECTION_SIZE; else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE; - else /* Family 8000 B-step */ + else /* Family 8000 B-step or C-step */ max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE; /* diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 95c2ab1ec74c..49e32060eafb 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -982,7 +982,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, /* Load the given image to the HW */ if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) && - (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP)) + (CSR_HW_REV_STEP(trans->hw_rev) != SILICON_A_STEP)) return iwl_pcie_load_given_ucode_8000b(trans, fw); else return iwl_pcie_load_given_ucode(trans, fw); -- cgit v1.2.1 From e583b50c072b17137c3a55f0129b69eb821e81df Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 22 Jan 2015 15:14:38 +0200 Subject: iwlwifi: mvm: BT Coex - set all the co-running values to 0 With this value, we de-facto disable the feature. Since it is not working yet, disable it completely. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 16 ++++++++-------- drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index d2fd48c31d3d..1ec4d55155f7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -342,7 +342,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 12, .lut20 = { - cpu_to_le32(0x00000001), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -363,7 +363,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 20, .lut20 = { - cpu_to_le32(0x00000002), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -384,7 +384,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 21, .lut20 = { - cpu_to_le32(0x00000003), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -405,7 +405,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 23, .lut20 = { - cpu_to_le32(0x00000004), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -426,7 +426,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 27, .lut20 = { - cpu_to_le32(0x00000005), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -447,7 +447,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 30, .lut20 = { - cpu_to_le32(0x00000006), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -468,7 +468,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 32, .lut20 = { - cpu_to_le32(0x00000007), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -489,7 +489,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 33, .lut20 = { - cpu_to_le32(0x00000008), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 973f2881dd1d..d530ef3da107 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -330,7 +330,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 12, .lut20 = { - cpu_to_le32(0x00000001), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -351,7 +351,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 20, .lut20 = { - cpu_to_le32(0x00000002), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -372,7 +372,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 21, .lut20 = { - cpu_to_le32(0x00000003), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -393,7 +393,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 23, .lut20 = { - cpu_to_le32(0x00000004), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -414,7 +414,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 27, .lut20 = { - cpu_to_le32(0x00000005), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -435,7 +435,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 30, .lut20 = { - cpu_to_le32(0x00000006), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -456,7 +456,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 32, .lut20 = { - cpu_to_le32(0x00000007), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -477,7 +477,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 33, .lut20 = { - cpu_to_le32(0x00000008), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), -- cgit v1.2.1 From 1008e442e3feb80502a8afddedc590ad444d5110 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sat, 17 Jan 2015 22:35:00 -0500 Subject: iwlwifi: mvm: Do not consider invalid HW queues in queue mask The iwl_mvm_mac_get_queues_mask() added vif->hw_queue[ac] to the queue mask although it might be set to IEEE80211_INVAL_HW_QUEUE. Fix it. Signed-off-by: Ilan Peer Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index a3e9cd955e7d..8bf78fa8ace0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -208,8 +208,10 @@ u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif) if (vif->type == NL80211_IFTYPE_P2P_DEVICE) return BIT(IWL_MVM_OFFCHANNEL_QUEUE); - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - qmask |= BIT(vif->hw_queue[ac]); + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) + qmask |= BIT(vif->hw_queue[ac]); + } if (vif->type == NL80211_IFTYPE_AP) qmask |= BIT(vif->cab_queue); -- cgit v1.2.1 From a4ca3ed4ebefab9cfb342518009f2200847778e5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 20 Jan 2015 17:07:10 +0200 Subject: iwlwifi: mvm: really disable TDLS queues for_each_set_bit expect the size in number of bits and not in bytes. Fixes: a0f6bf2a5b01 ("iwlwifi: mvm: use private TFD queues for TDLS stations") Reviewed-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/sta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 8e413d3b9c32..14a848480d04 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -250,7 +250,7 @@ static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm, /* disable the TDLS STA-specific queues */ sta_msk = mvmsta->tfd_queue_msk; - for_each_set_bit(i, &sta_msk, sizeof(sta_msk)) + for_each_set_bit(i, &sta_msk, sizeof(sta_msk) * BITS_PER_BYTE) iwl_mvm_disable_txq(mvm, i, 0); } @@ -464,7 +464,7 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk) if (mvm->tfd_drained[sta_id]) { unsigned long i, msk = mvm->tfd_drained[sta_id]; - for_each_set_bit(i, &msk, sizeof(msk)) + for_each_set_bit(i, &msk, sizeof(msk) * BITS_PER_BYTE) iwl_mvm_disable_txq(mvm, i, 0); mvm->tfd_drained[sta_id] = 0; -- cgit v1.2.1 From 2c59d80c448c8b6c0978986bd687466a233bd8ae Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Fri, 16 Jan 2015 11:01:51 +0200 Subject: iwlwifi: mvm: rs: refactor ht/vht init Prepare to add some more code there so refactor to separate functions. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 42 ++++------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 997a3831117c..554b3a5e442c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2714,44 +2714,10 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value); /* TODO: should probably account for rx_highest for both HT/VHT */ - if (!vht_cap || !vht_cap->vht_supported) { - /* active_siso_rate mask includes 9 MBits (bit 5), - * and CCK (bits 0-3), supp_rates[] does not; - * shift to convert format, force 9 MBits off. - */ - lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; - lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; - lq_sta->active_siso_rate &= ~((u16)0x2); - lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; - - /* Same here */ - lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; - lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; - lq_sta->active_mimo2_rate &= ~((u16)0x2); - lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - - lq_sta->is_vht = false; - if (mvm->cfg->ht_params->ldpc && - (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) - lq_sta->ldpc = true; - - if (mvm->cfg->ht_params->stbc && - (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && - (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) - lq_sta->stbc = true; - } else { - rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); - lq_sta->is_vht = true; - - if (mvm->cfg->ht_params->ldpc && - (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)) - lq_sta->ldpc = true; - - if (mvm->cfg->ht_params->stbc && - (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && - (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) - lq_sta->stbc = true; - } + if (!vht_cap || !vht_cap->vht_supported) + rs_ht_init(mvm, sta, lq_sta, ht_cap); + else + rs_vht_init(mvm, sta, lq_sta, vht_cap); if (IWL_MVM_RS_DISABLE_P2P_MIMO && sta_priv->vif->p2p) lq_sta->active_mimo2_rate = 0; -- cgit v1.2.1 From c5d679a55dce1c025b12bcea5063d882565622b8 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 15 Jan 2015 20:22:34 +0200 Subject: iwlwifi: mvm: use a new API for enabling STBC The new API tells the FW that it's allowed to use STBC but the FW will decide on its own whether to use STBC or SISO (and in the future Beamformer). Keep support for the old API which sets STBC explicitly in the rates in the LQ table while we still support old FW revisions. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | 15 +++++++++++++-- drivers/net/wireless/iwlwifi/mvm/rs.c | 14 +++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index b998aaf5efd1..e4f589898eda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -249,6 +249,7 @@ enum iwl_ucode_tlv_flag { * through the dedicated host command. * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too. * @IWL_UCODE_TLV_API_ASYNC_DTM: Async temperature notifications are supported. + * @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), @@ -261,6 +262,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_SCD_CFG = BIT(15), IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16), IWL_UCODE_TLV_API_ASYNC_DTM = BIT(17), + IWL_UCODE_TLV_API_LQ_SS_PARAMS = BIT(18), }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 8bb5b94bf963..6a2a6b0ab91b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h @@ -308,6 +308,17 @@ enum { #define LQ_FLAG_DYNAMIC_BW_POS 6 #define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS) +/* Single Stream Parameters + * SS_STBC/BFER_ALLOWED - Controls whether STBC or Beamformer (BFER) is allowed + * ucode will make a smart decision between SISO/STBC/BFER + * SS_PARAMS_VALID - if not set ignore the ss_params field. + */ +enum { + RS_SS_STBC_ALLOWED = BIT(0), + RS_SS_BFER_ALLOWED = BIT(1), + RS_SS_PARAMS_VALID = BIT(31), +}; + /** * struct iwl_lq_cmd - link quality command * @sta_id: station to update @@ -330,7 +341,7 @@ enum { * 2 - 0x3f: maximal number of frames (up to 3f == 63) * @rs_table: array of rates for each TX try, each is rate_n_flags, * meaning it is a combination of RATE_MCS_* and IWL_RATE_*_PLCP - * @bf_params: beam forming params, currently not used + * @ss_params: single stream features. declare whether STBC or BFER are allowed. */ struct iwl_lq_cmd { u8 sta_id; @@ -348,6 +359,6 @@ struct iwl_lq_cmd { u8 agg_frame_cnt_limit; __le32 reserved2; __le32 rs_table[LQ_MAX_RETRY_NUM]; - __le32 bf_params; + __le32 ss_params; }; /* LINK_QUALITY_CMD_API_S_VER_1 */ #endif /* __fw_api_rs_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 554b3a5e442c..f30eff20cb6b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2868,11 +2868,23 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, u8 valid_tx_ant = 0; struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; bool toggle_ant = false; + bool stbc_allowed = false; memcpy(&rate, initial_rate, sizeof(rate)); valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); - rate.stbc = rs_stbc_allow(mvm, sta, lq_sta); + + stbc_allowed = rs_stbc_allow(mvm, sta, lq_sta); + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) { + u32 ss_params = RS_SS_PARAMS_VALID; + + if (stbc_allowed) + ss_params |= RS_SS_STBC_ALLOWED; + lq_cmd->ss_params = cpu_to_le32(ss_params); + } else { + /* TODO: remove old API when min FW API hits 14 */ + rate.stbc = stbc_allowed; + } if (is_siso(&rate)) { num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES; -- cgit v1.2.1 From 2f15a829ae3cbc4cb27185f523af3df33757fcae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jan 2015 18:05:04 +0100 Subject: iwlwifi: mvm: rs: remove stats argument from functions The stats argument is always only passed as &mvm->drv_rx_stats, so there's no point in passing it when the mvm pointer is passed. Remove the argument entirely. Signed-off-by: Johannes Berg Reviewed-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 +- drivers/net/wireless/iwlwifi/mvm/rs.c | 92 ++++++++++++++++++++++++++-------- drivers/net/wireless/iwlwifi/mvm/rx.c | 2 +- 3 files changed, 72 insertions(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index aa93ee794670..979ac23522f2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1143,9 +1143,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) /* rate scaling */ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); -void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, - struct iwl_mvm_frame_stats *stats, - u32 rate, bool agg); +void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg); int rs_pretty_print_rate(char *buf, const u32 rate); void rs_update_last_rssi(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_sta, diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index f30eff20cb6b..9f32f2db95bd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2600,68 +2600,116 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, } } +static void rs_ht_init(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta, + struct ieee80211_sta_ht_cap *ht_cap) +{ + /* active_siso_rate mask includes 9 MBits (bit 5), + * and CCK (bits 0-3), supp_rates[] does not; + * shift to convert format, force 9 MBits off. + */ + lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; + lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; + lq_sta->active_siso_rate &= ~((u16)0x2); + lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; + + lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; + lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; + lq_sta->active_mimo2_rate &= ~((u16)0x2); + lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; + + if (mvm->cfg->ht_params->ldpc && + (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) + lq_sta->ldpc = true; + + if (mvm->cfg->ht_params->stbc && + (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && + (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) + lq_sta->stbc = true; + + lq_sta->is_vht = false; +} + +static void rs_vht_init(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta, + struct ieee80211_sta_vht_cap *vht_cap) +{ + rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); + + if (mvm->cfg->ht_params->ldpc && + (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)) + lq_sta->ldpc = true; + + if (mvm->cfg->ht_params->stbc && + (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && + (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) + lq_sta->stbc = true; + + lq_sta->is_vht = true; +} + #ifdef CONFIG_IWLWIFI_DEBUGFS -static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm, - struct iwl_mvm_frame_stats *stats) +static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm) { spin_lock_bh(&mvm->drv_stats_lock); - memset(stats, 0, sizeof(*stats)); + memset(&mvm->drv_rx_stats, 0, sizeof(mvm->drv_rx_stats)); spin_unlock_bh(&mvm->drv_stats_lock); } -void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, - struct iwl_mvm_frame_stats *stats, - u32 rate, bool agg) +void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg) { u8 nss = 0, mcs = 0; spin_lock(&mvm->drv_stats_lock); if (agg) - stats->agg_frames++; + mvm->drv_rx_stats.agg_frames++; - stats->success_frames++; + mvm->drv_rx_stats.success_frames++; switch (rate & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: - stats->bw_20_frames++; + mvm->drv_rx_stats.bw_20_frames++; break; case RATE_MCS_CHAN_WIDTH_40: - stats->bw_40_frames++; + mvm->drv_rx_stats.bw_40_frames++; break; case RATE_MCS_CHAN_WIDTH_80: - stats->bw_80_frames++; + mvm->drv_rx_stats.bw_80_frames++; break; default: WARN_ONCE(1, "bad BW. rate 0x%x", rate); } if (rate & RATE_MCS_HT_MSK) { - stats->ht_frames++; + mvm->drv_rx_stats.ht_frames++; mcs = rate & RATE_HT_MCS_RATE_CODE_MSK; nss = ((rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1; } else if (rate & RATE_MCS_VHT_MSK) { - stats->vht_frames++; + mvm->drv_rx_stats.vht_frames++; mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK; nss = ((rate & RATE_VHT_MCS_NSS_MSK) >> RATE_VHT_MCS_NSS_POS) + 1; } else { - stats->legacy_frames++; + mvm->drv_rx_stats.legacy_frames++; } if (nss == 1) - stats->siso_frames++; + mvm->drv_rx_stats.siso_frames++; else if (nss == 2) - stats->mimo2_frames++; + mvm->drv_rx_stats.mimo2_frames++; if (rate & RATE_MCS_SGI_MSK) - stats->sgi_frames++; + mvm->drv_rx_stats.sgi_frames++; else - stats->ngi_frames++; + mvm->drv_rx_stats.ngi_frames++; - stats->last_rates[stats->last_frame_idx] = rate; - stats->last_frame_idx = (stats->last_frame_idx + 1) % - ARRAY_SIZE(stats->last_rates); + mvm->drv_rx_stats.last_rates[mvm->drv_rx_stats.last_frame_idx] = rate; + mvm->drv_rx_stats.last_frame_idx = + (mvm->drv_rx_stats.last_frame_idx + 1) % + ARRAY_SIZE(mvm->drv_rx_stats.last_rates); spin_unlock(&mvm->drv_stats_lock); } @@ -2749,7 +2797,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->is_agg = 0; #ifdef CONFIG_IWLWIFI_DEBUGFS - iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats); + iwl_mvm_reset_frame_stats(mvm); #endif rs_initialize_lq(mvm, sta, lq_sta, band, init); } diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 7919a7b00c7a..f922131b4eab 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -407,7 +407,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, } #ifdef CONFIG_IWLWIFI_DEBUGFS - iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags, + iwl_mvm_update_frame_stats(mvm, rate_n_flags, rx_status->flag & RX_FLAG_AMPDU_DETAILS); #endif iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status, -- cgit v1.2.1 From afb8891740263aca4988252a5f01da10ca7b581b Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Tue, 20 Jan 2015 15:37:34 +0200 Subject: iwlwifi: pcie: support secured boot flow for family 8000 B step The driver loads the 2 CPU sections, then it needs to let the firmware know to start the authentication of the sections. This is done by writing the relevants bits to FH_UCODE_LOAD_STATUS. For CPU1, the driver sets the lower 16 bits. For both CPUs, the driver sets all the 32 bits. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 49e32060eafb..1ff87677c3d3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -722,6 +722,11 @@ static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans, *first_ucode_section = last_read_idx; + if (cpu == 1) + iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFF); + else + iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF); + return 0; } @@ -911,9 +916,6 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, if (trans->dbg_dest_tlv) iwl_pcie_apply_destination(trans); - /* Notify FW loading is done */ - iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF); - /* wait for image verification to complete */ ret = iwl_poll_prph_bit(trans, LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0, LMPM_SECURE_BOOT_STATUS_SUCCESS, -- cgit v1.2.1 From 0b83795a110248db8f8e7c289a27b3b71b0bb35a Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Thu, 22 Jan 2015 19:01:35 +0200 Subject: iwlwifi: mvm: fix rx chains configuration in phy ctxt cmd In the PHY_CTXT command sent to the FW the TX chains were indeed configured by the values of both FW TLVs and of NVM, but the RX chains were left out and configured only by FW TLV. This causes problems in 4165 HW, where there are 1x1 antennas, and the wrong configuration denies the driver from connecting to the AP. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 540c36bae268..5b43616eeb06 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -170,7 +170,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, active_cnt = 2; } - cmd->rxchain_info = cpu_to_le32(mvm->fw->valid_rx_ant << + cmd->rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) << PHY_RX_CHAIN_VALID_POS); cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); cmd->rxchain_info |= cpu_to_le32(active_cnt << -- cgit v1.2.1 From d5c7d7f6427cd7c39353d09bf47bfbc7800b6a53 Mon Sep 17 00:00:00 2001 From: Asaf Vertz Date: Thu, 8 Jan 2015 06:01:00 +0000 Subject: e1000: fix time comparison To be future-proof and for better readability the time comparisons are modified to use time_after_eq() instead of plain, error-prone math. Signed-off-by: Asaf Vertz Acked-by: Jacob Keller Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index b691eb4f6376..4270ad2d4ddf 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -24,6 +24,7 @@ /* ethtool support for e1000 */ #include "e1000.h" +#include #include enum {NETDEV_STATS, E1000_STATS}; @@ -1460,7 +1461,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter) ret_val = 13; /* ret_val is the same as mis-compare */ break; } - if (jiffies >= (time + 2)) { + if (time_after_eq(jiffies, time + 2)) { ret_val = 14; /* error code for time out error */ break; } -- cgit v1.2.1 From 6930895df994af212985396f1274712aaaa5bc26 Mon Sep 17 00:00:00 2001 From: Mathias Koehrer Date: Thu, 7 Aug 2014 18:51:53 +0000 Subject: e1000e: Fix 82572EI that has no hardware timestamp support With the Intel 82527EI (driver: e1000e) there is an issue when running the ptpd2 program, that leads to a kernel oops. The reason is here that in e1000_xmit_frame() a work queue will be scheduled that has not been initialized in this case. The work queue "tx_hwstamp_work" will only be initialized if adapter->flags & FLAG_HAS_HW_TIMESTAMP set. This check is missing in e1000_xmit_frame(). The following patch adds the missing check. Signed-off-by: Mathias Koehrer Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 38cb586b1bf4..aa39a81a6df6 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5636,8 +5636,9 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, count = e1000_tx_map(tx_ring, skb, first, adapter->tx_fifo_limit, nr_frags); if (count) { - if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && - !adapter->tx_hwtstamp_skb)) { + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + (adapter->flags & FLAG_HAS_HW_TIMESTAMP) && + !adapter->tx_hwtstamp_skb) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; tx_flags |= E1000_TX_FLAGS_HWTSTAMP; adapter->tx_hwtstamp_skb = skb_get(skb); -- cgit v1.2.1 From 074c3582192b6cb340510b2a6e4579e78f671dcf Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 25 Jun 2014 02:37:13 +0000 Subject: virtio_net: add software timestamp support This patch enables the use of software timestamping via the virtio_net driver. Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/virtio_net.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 11e2e8131359..9bd71d53c5e0 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -925,6 +925,9 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) /* Free up any pending old buffers before queueing new ones. */ free_old_xmit_skbs(sq); + /* timestamp packet in software */ + skb_tx_timestamp(skb); + /* Try to transmit */ err = xmit_skb(sq, skb); @@ -1376,6 +1379,7 @@ static const struct ethtool_ops virtnet_ethtool_ops = { .get_ringparam = virtnet_get_ringparam, .set_channels = virtnet_set_channels, .get_channels = virtnet_get_channels, + .get_ts_info = ethtool_op_get_ts_info, }; #define MIN_MTU 68 -- cgit v1.2.1 From 95dd44b4f31eef3cce0f98967635431e10e31c98 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 14 Nov 2014 00:56:19 +0000 Subject: igb: Clean-up page reuse code This patch cleans up the page reuse code getting it into a state where all the workarounds needed are in place as well as cleaning up a few minor oversights such as using __free_pages instead of put_page to drop a locally allocated page. It also cleans up how we clear the descriptor status bits. Previously they were zeroed as a part of clearing the hdr_addr. However the hdr_addr is a 64 bit field and 64 bit writes can be a bit more expensive on on 32 bit systems. Since we are no longer using the header split feature the upper 32 bits of the address no longer need to be cleared. As a result we can just clear the status bits and leave the length and VLAN fields as-is which should provide more information in debugging. Signed-off-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 35 ++++++++++++++----------------- 1 file changed, 16 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 6c25ec314183..d1480f3054fe 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6527,15 +6527,17 @@ static void igb_reuse_rx_page(struct igb_ring *rx_ring, DMA_FROM_DEVICE); } +static inline bool igb_page_is_reserved(struct page *page) +{ + return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc; +} + static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer, struct page *page, unsigned int truesize) { /* avoid re-using remote pages */ - if (unlikely(page_to_nid(page) != numa_node_id())) - return false; - - if (unlikely(page->pfmemalloc)) + if (unlikely(igb_page_is_reserved(page))) return false; #if (PAGE_SIZE < 8192) @@ -6545,22 +6547,19 @@ static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer, /* flip page offset to other buffer */ rx_buffer->page_offset ^= IGB_RX_BUFSZ; - - /* Even if we own the page, we are not allowed to use atomic_set() - * This would break get_page_unless_zero() users. - */ - atomic_inc(&page->_count); #else /* move offset up to the next cache line */ rx_buffer->page_offset += truesize; if (rx_buffer->page_offset > (PAGE_SIZE - IGB_RX_BUFSZ)) return false; - - /* bump ref count on page before it is given to the stack */ - get_page(page); #endif + /* Even if we own the page, we are not allowed to use atomic_set() + * This would break get_page_unless_zero() users. + */ + atomic_inc(&page->_count); + return true; } @@ -6603,13 +6602,12 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring, memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long))); - /* we can reuse buffer as-is, just make sure it is local */ - if (likely((page_to_nid(page) == numa_node_id()) && - !page->pfmemalloc)) + /* page is not reserved, we can reuse buffer as-is */ + if (likely(!igb_page_is_reserved(page))) return true; /* this page cannot be reused so discard it */ - put_page(page); + __free_page(page); return false; } @@ -6627,7 +6625,6 @@ static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring, struct page *page; rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean]; - page = rx_buffer->page; prefetchw(page); @@ -7042,8 +7039,8 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count) i -= rx_ring->count; } - /* clear the hdr_addr for the next_to_use descriptor */ - rx_desc->read.hdr_addr = 0; + /* clear the status bits for the next_to_use descriptor */ + rx_desc->wb.upper.status_error = 0; cleaned_count--; } while (cleaned_count); -- cgit v1.2.1 From ba5b8dcdb865efaa35692516a7153dc631ba6ffa Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 14 Nov 2014 00:56:24 +0000 Subject: fm10k: Clean-up page reuse code This patch cleans up the page reuse code getting it into a state where all the workarounds needed are in place as well as cleaning up a few minor oversights such as using __free_pages instead of put_page to drop a locally allocated page. It also cleans up how we clear the descriptor status bits. Previously they were zeroed as a part of clearing the hdr_addr. However the hdr_addr is a 64 bit field and 64 bit writes can be a bit more expensive on on 32 bit systems. Since we are no longer using the header split feature the upper 32 bits of the address no longer need to be cleared. As a result we can just clear the status bits and leave the length and VLAN fields as-is which should provide more information in debugging. Signed-off-by: Alexander Duyck Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_main.c | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index caa43f7c2931..c7a19a5e0ec9 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -97,7 +97,6 @@ static bool fm10k_alloc_mapped_page(struct fm10k_ring *rx_ring, */ if (dma_mapping_error(rx_ring->dev, dma)) { __free_page(page); - bi->page = NULL; rx_ring->rx_stats.alloc_failed++; return false; @@ -147,8 +146,8 @@ void fm10k_alloc_rx_buffers(struct fm10k_ring *rx_ring, u16 cleaned_count) i -= rx_ring->count; } - /* clear the hdr_addr for the next_to_use descriptor */ - rx_desc->q.hdr_addr = 0; + /* clear the status bits for the next_to_use descriptor */ + rx_desc->d.staterr = 0; cleaned_count--; } while (cleaned_count); @@ -194,7 +193,7 @@ static void fm10k_reuse_rx_page(struct fm10k_ring *rx_ring, rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; /* transfer page from old buffer to new buffer */ - memcpy(new_buff, old_buff, sizeof(struct fm10k_rx_buffer)); + *new_buff = *old_buff; /* sync the buffer for use by the device */ dma_sync_single_range_for_device(rx_ring->dev, old_buff->dma, @@ -203,12 +202,17 @@ static void fm10k_reuse_rx_page(struct fm10k_ring *rx_ring, DMA_FROM_DEVICE); } +static inline bool fm10k_page_is_reserved(struct page *page) +{ + return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc; +} + static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer, struct page *page, unsigned int truesize) { /* avoid re-using remote pages */ - if (unlikely(page_to_nid(page) != numa_mem_id())) + if (unlikely(fm10k_page_is_reserved(page))) return false; #if (PAGE_SIZE < 8192) @@ -218,22 +222,19 @@ static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer, /* flip page offset to other buffer */ rx_buffer->page_offset ^= FM10K_RX_BUFSZ; - - /* Even if we own the page, we are not allowed to use atomic_set() - * This would break get_page_unless_zero() users. - */ - atomic_inc(&page->_count); #else /* move offset up to the next cache line */ rx_buffer->page_offset += truesize; if (rx_buffer->page_offset > (PAGE_SIZE - FM10K_RX_BUFSZ)) return false; - - /* bump ref count on page before it is given to the stack */ - get_page(page); #endif + /* Even if we own the page, we are not allowed to use atomic_set() + * This would break get_page_unless_zero() users. + */ + atomic_inc(&page->_count); + return true; } @@ -270,12 +271,12 @@ static bool fm10k_add_rx_frag(struct fm10k_ring *rx_ring, memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long))); - /* we can reuse buffer as-is, just make sure it is local */ - if (likely(page_to_nid(page) == numa_mem_id())) + /* page is not reserved, we can reuse buffer as-is */ + if (likely(!fm10k_page_is_reserved(page))) return true; /* this page cannot be reused so discard it */ - put_page(page); + __free_page(page); return false; } @@ -293,7 +294,6 @@ static struct sk_buff *fm10k_fetch_rx_buffer(struct fm10k_ring *rx_ring, struct page *page; rx_buffer = &rx_ring->rx_buffer[rx_ring->next_to_clean]; - page = rx_buffer->page; prefetchw(page); -- cgit v1.2.1 From 61d7f75f45231e4a2f2ab7d975555f55f0019800 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 21 Nov 2014 20:51:10 +0000 Subject: igb: refactor time sync interrupt handling The code that handles the time sync interrupt is repeated in three different places. This patch refactors the identical code blocks into a single helper function. Signed-off-by: Richard Cochran Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 49 ++++++++++++------------------- 1 file changed, 19 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index d1480f3054fe..135ac5c45abd 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -5384,6 +5384,19 @@ void igb_update_stats(struct igb_adapter *adapter, } } +static void igb_tsync_interrupt(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 tsicr = rd32(E1000_TSICR); + + if (tsicr & E1000_TSICR_TXTS) { + /* acknowledge the interrupt */ + wr32(E1000_TSICR, E1000_TSICR_TXTS); + /* retrieve hardware timestamp */ + schedule_work(&adapter->ptp_tx_work); + } +} + static irqreturn_t igb_msix_other(int irq, void *data) { struct igb_adapter *adapter = data; @@ -5415,16 +5428,8 @@ static irqreturn_t igb_msix_other(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (icr & E1000_ICR_TS) { - u32 tsicr = rd32(E1000_TSICR); - - if (tsicr & E1000_TSICR_TXTS) { - /* acknowledge the interrupt */ - wr32(E1000_TSICR, E1000_TSICR_TXTS); - /* retrieve hardware timestamp */ - schedule_work(&adapter->ptp_tx_work); - } - } + if (icr & E1000_ICR_TS) + igb_tsync_interrupt(adapter); wr32(E1000_EIMS, adapter->eims_other); @@ -6203,16 +6208,8 @@ static irqreturn_t igb_intr_msi(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (icr & E1000_ICR_TS) { - u32 tsicr = rd32(E1000_TSICR); - - if (tsicr & E1000_TSICR_TXTS) { - /* acknowledge the interrupt */ - wr32(E1000_TSICR, E1000_TSICR_TXTS); - /* retrieve hardware timestamp */ - schedule_work(&adapter->ptp_tx_work); - } - } + if (icr & E1000_ICR_TS) + igb_tsync_interrupt(adapter); napi_schedule(&q_vector->napi); @@ -6257,16 +6254,8 @@ static irqreturn_t igb_intr(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (icr & E1000_ICR_TS) { - u32 tsicr = rd32(E1000_TSICR); - - if (tsicr & E1000_TSICR_TXTS) { - /* acknowledge the interrupt */ - wr32(E1000_TSICR, E1000_TSICR_TXTS); - /* retrieve hardware timestamp */ - schedule_work(&adapter->ptp_tx_work); - } - } + if (icr & E1000_ICR_TS) + igb_tsync_interrupt(adapter); napi_schedule(&q_vector->napi); -- cgit v1.2.1 From 8298c1ecd534e45e52f05a29122b0f6c1a580d25 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 21 Nov 2014 20:51:15 +0000 Subject: igb: serialize access to the time sync interrupt registers The time sync related interrupt registers may be manipulated from different contexts. This patch protects the registers from being asynchronously changed by the reset function. Also, the patch removes a misleading comment. The reset function is disabling a bunch of functions, not enabling them. Signed-off-by: Richard Cochran Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_ptp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 5e7a4e30a7b6..8389bb40a4bf 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -900,6 +900,7 @@ void igb_ptp_stop(struct igb_adapter *adapter) void igb_ptp_reset(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; + unsigned long flags; if (!(adapter->flags & IGB_FLAG_PTP)) return; @@ -907,6 +908,8 @@ void igb_ptp_reset(struct igb_adapter *adapter) /* reset the tstamp_config */ igb_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); + spin_lock_irqsave(&adapter->tmreg_lock, flags); + switch (adapter->hw.mac.type) { case e1000_82576: /* Dial the nominal frequency. */ @@ -917,23 +920,24 @@ void igb_ptp_reset(struct igb_adapter *adapter) case e1000_i350: case e1000_i210: case e1000_i211: - /* Enable the timer functions and interrupts. */ wr32(E1000_TSAUXC, 0x0); wr32(E1000_TSIM, TSYNC_INTERRUPTS); wr32(E1000_IMS, E1000_IMS_TS); break; default: /* No work to do. */ - return; + goto out; } /* Re-initialize the timer. */ if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) { struct timespec ts = ktime_to_timespec(ktime_get_real()); - igb_ptp_settime_i210(&adapter->ptp_caps, &ts); + igb_ptp_write_i210(adapter, &ts); } else { timecounter_init(&adapter->tc, &adapter->cc, ktime_to_ns(ktime_get_real())); } +out: + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); } -- cgit v1.2.1 From 00c65578b47bec3f92ce259d0c9d959ac54fff28 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 21 Nov 2014 20:51:20 +0000 Subject: igb: enable internal PPS for the i210 The i210 device can produce an interrupt on the full second. This patch allows using this interrupt to generate an internal PPS event for adjusting the kernel system time. Signed-off-by: Richard Cochran Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 18 ++++++++++++++--- drivers/net/ethernet/intel/igb/igb_ptp.c | 32 +++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 135ac5c45abd..e84416286dde 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -5387,14 +5387,26 @@ void igb_update_stats(struct igb_adapter *adapter, static void igb_tsync_interrupt(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; - u32 tsicr = rd32(E1000_TSICR); + struct ptp_clock_event event; + u32 ack = 0, tsicr = rd32(E1000_TSICR); + + if (tsicr & TSINTR_SYS_WRAP) { + event.type = PTP_CLOCK_PPS; + if (adapter->ptp_caps.pps) + ptp_clock_event(adapter->ptp_clock, &event); + else + dev_err(&adapter->pdev->dev, "unexpected SYS WRAP"); + ack |= TSINTR_SYS_WRAP; + } if (tsicr & E1000_TSICR_TXTS) { - /* acknowledge the interrupt */ - wr32(E1000_TSICR, E1000_TSICR_TXTS); /* retrieve hardware timestamp */ schedule_work(&adapter->ptp_tx_work); + ack |= E1000_TSICR_TXTS; } + + /* acknowledge the interrupts */ + wr32(E1000_TSICR, ack); } static irqreturn_t igb_msix_other(int irq, void *data) diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 8389bb40a4bf..98c58d921228 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -355,6 +355,34 @@ static int igb_ptp_settime_i210(struct ptp_clock_info *ptp, return 0; } +static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct igb_adapter *igb = + container_of(ptp, struct igb_adapter, ptp_caps); + struct e1000_hw *hw = &igb->hw; + unsigned long flags; + u32 tsim; + + switch (rq->type) { + case PTP_CLK_REQ_PPS: + spin_lock_irqsave(&igb->tmreg_lock, flags); + tsim = rd32(E1000_TSIM); + if (on) + tsim |= TSINTR_SYS_WRAP; + else + tsim &= ~TSINTR_SYS_WRAP; + wr32(E1000_TSIM, tsim); + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + return 0; + + default: + break; + } + + return -EOPNOTSUPP; +} + static int igb_ptp_feature_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *rq, int on) { @@ -797,12 +825,12 @@ void igb_ptp_init(struct igb_adapter *adapter) adapter->ptp_caps.owner = THIS_MODULE; adapter->ptp_caps.max_adj = 62499999; adapter->ptp_caps.n_ext_ts = 0; - adapter->ptp_caps.pps = 0; + adapter->ptp_caps.pps = 1; adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580; adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210; adapter->ptp_caps.gettime = igb_ptp_gettime_i210; adapter->ptp_caps.settime = igb_ptp_settime_i210; - adapter->ptp_caps.enable = igb_ptp_feature_enable; + adapter->ptp_caps.enable = igb_ptp_feature_enable_i210; /* Enable the timer functions by clearing bit 31. */ wr32(E1000_TSAUXC, 0x0); break; -- cgit v1.2.1 From 720db4ffd0846570c1ddc82e7bb661ab0a676fad Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 21 Nov 2014 20:51:26 +0000 Subject: igb: enable auxiliary PHC functions for the i210 The i210 device offers a number of special PTP Hardware Clock features on the Software Defined Pins (SDPs). This patch adds support for two of the possible functions, namely time stamping external events, and periodic output signals. The assignment of PHC functions to the four SDP can be freely chosen by the user. Signed-off-by: Richard Cochran Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb.h | 9 ++ drivers/net/ethernet/intel/igb/igb_main.c | 51 ++++++- drivers/net/ethernet/intel/igb/igb_ptp.c | 222 +++++++++++++++++++++++++++++- 3 files changed, 276 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index ee22da391474..c2bd4f98a837 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -343,6 +343,9 @@ struct hwmon_buff { }; #endif +#define IGB_N_EXTTS 2 +#define IGB_N_PEROUT 2 +#define IGB_N_SDP 4 #define IGB_RETA_SIZE 128 /* board specific private data structure */ @@ -439,6 +442,12 @@ struct igb_adapter { u32 tx_hwtstamp_timeouts; u32 rx_hwtstamp_cleared; + struct ptp_pin_desc sdp_config[IGB_N_SDP]; + struct { + struct timespec start; + struct timespec period; + } perout[IGB_N_PEROUT]; + char fw_version[32]; #ifdef CONFIG_IGB_HWMON struct hwmon_buff *igb_hwmon_buff; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index e84416286dde..6e6544970b83 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -5388,7 +5388,8 @@ static void igb_tsync_interrupt(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct ptp_clock_event event; - u32 ack = 0, tsicr = rd32(E1000_TSICR); + struct timespec ts; + u32 ack = 0, tsauxc, sec, nsec, tsicr = rd32(E1000_TSICR); if (tsicr & TSINTR_SYS_WRAP) { event.type = PTP_CLOCK_PPS; @@ -5405,6 +5406,54 @@ static void igb_tsync_interrupt(struct igb_adapter *adapter) ack |= E1000_TSICR_TXTS; } + if (tsicr & TSINTR_TT0) { + spin_lock(&adapter->tmreg_lock); + ts = timespec_add(adapter->perout[0].start, + adapter->perout[0].period); + wr32(E1000_TRGTTIML0, ts.tv_nsec); + wr32(E1000_TRGTTIMH0, ts.tv_sec); + tsauxc = rd32(E1000_TSAUXC); + tsauxc |= TSAUXC_EN_TT0; + wr32(E1000_TSAUXC, tsauxc); + adapter->perout[0].start = ts; + spin_unlock(&adapter->tmreg_lock); + ack |= TSINTR_TT0; + } + + if (tsicr & TSINTR_TT1) { + spin_lock(&adapter->tmreg_lock); + ts = timespec_add(adapter->perout[1].start, + adapter->perout[1].period); + wr32(E1000_TRGTTIML1, ts.tv_nsec); + wr32(E1000_TRGTTIMH1, ts.tv_sec); + tsauxc = rd32(E1000_TSAUXC); + tsauxc |= TSAUXC_EN_TT1; + wr32(E1000_TSAUXC, tsauxc); + adapter->perout[1].start = ts; + spin_unlock(&adapter->tmreg_lock); + ack |= TSINTR_TT1; + } + + if (tsicr & TSINTR_AUTT0) { + nsec = rd32(E1000_AUXSTMPL0); + sec = rd32(E1000_AUXSTMPH0); + event.type = PTP_CLOCK_EXTTS; + event.index = 0; + event.timestamp = sec * 1000000000ULL + nsec; + ptp_clock_event(adapter->ptp_clock, &event); + ack |= TSINTR_AUTT0; + } + + if (tsicr & TSINTR_AUTT1) { + nsec = rd32(E1000_AUXSTMPL1); + sec = rd32(E1000_AUXSTMPH1); + event.type = PTP_CLOCK_EXTTS; + event.index = 1; + event.timestamp = sec * 1000000000ULL + nsec; + ptp_clock_event(adapter->ptp_clock, &event); + ack |= TSINTR_AUTT1; + } + /* acknowledge the interrupts */ wr32(E1000_TSICR, ack); } diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 98c58d921228..d20fc8ed11f1 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -355,16 +355,204 @@ static int igb_ptp_settime_i210(struct ptp_clock_info *ptp, return 0; } +static void igb_pin_direction(int pin, int input, u32 *ctrl, u32 *ctrl_ext) +{ + u32 *ptr = pin < 2 ? ctrl : ctrl_ext; + u32 mask[IGB_N_SDP] = { + E1000_CTRL_SDP0_DIR, + E1000_CTRL_SDP1_DIR, + E1000_CTRL_EXT_SDP2_DIR, + E1000_CTRL_EXT_SDP3_DIR, + }; + + if (input) + *ptr &= ~mask[pin]; + else + *ptr |= mask[pin]; +} + +static void igb_pin_extts(struct igb_adapter *igb, int chan, int pin) +{ + struct e1000_hw *hw = &igb->hw; + u32 aux0_sel_sdp[IGB_N_SDP] = { + AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3, + }; + u32 aux1_sel_sdp[IGB_N_SDP] = { + AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3, + }; + u32 ts_sdp_en[IGB_N_SDP] = { + TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN, + }; + u32 ctrl, ctrl_ext, tssdp = 0; + + ctrl = rd32(E1000_CTRL); + ctrl_ext = rd32(E1000_CTRL_EXT); + tssdp = rd32(E1000_TSSDP); + + igb_pin_direction(pin, 1, &ctrl, &ctrl_ext); + + /* Make sure this pin is not enabled as an output. */ + tssdp &= ~ts_sdp_en[pin]; + + if (chan == 1) { + tssdp &= ~AUX1_SEL_SDP3; + tssdp |= aux1_sel_sdp[pin] | AUX1_TS_SDP_EN; + } else { + tssdp &= ~AUX0_SEL_SDP3; + tssdp |= aux0_sel_sdp[pin] | AUX0_TS_SDP_EN; + } + + wr32(E1000_TSSDP, tssdp); + wr32(E1000_CTRL, ctrl); + wr32(E1000_CTRL_EXT, ctrl_ext); +} + +static void igb_pin_perout(struct igb_adapter *igb, int chan, int pin) +{ + struct e1000_hw *hw = &igb->hw; + u32 aux0_sel_sdp[IGB_N_SDP] = { + AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3, + }; + u32 aux1_sel_sdp[IGB_N_SDP] = { + AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3, + }; + u32 ts_sdp_en[IGB_N_SDP] = { + TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN, + }; + u32 ts_sdp_sel_tt0[IGB_N_SDP] = { + TS_SDP0_SEL_TT0, TS_SDP1_SEL_TT0, + TS_SDP2_SEL_TT0, TS_SDP3_SEL_TT0, + }; + u32 ts_sdp_sel_tt1[IGB_N_SDP] = { + TS_SDP0_SEL_TT1, TS_SDP1_SEL_TT1, + TS_SDP2_SEL_TT1, TS_SDP3_SEL_TT1, + }; + u32 ts_sdp_sel_clr[IGB_N_SDP] = { + TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1, + TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1, + }; + u32 ctrl, ctrl_ext, tssdp = 0; + + ctrl = rd32(E1000_CTRL); + ctrl_ext = rd32(E1000_CTRL_EXT); + tssdp = rd32(E1000_TSSDP); + + igb_pin_direction(pin, 0, &ctrl, &ctrl_ext); + + /* Make sure this pin is not enabled as an input. */ + if ((tssdp & AUX0_SEL_SDP3) == aux0_sel_sdp[pin]) + tssdp &= ~AUX0_TS_SDP_EN; + + if ((tssdp & AUX1_SEL_SDP3) == aux1_sel_sdp[pin]) + tssdp &= ~AUX1_TS_SDP_EN; + + tssdp &= ~ts_sdp_sel_clr[pin]; + if (chan == 1) + tssdp |= ts_sdp_sel_tt1[pin]; + else + tssdp |= ts_sdp_sel_tt0[pin]; + + tssdp |= ts_sdp_en[pin]; + + wr32(E1000_TSSDP, tssdp); + wr32(E1000_CTRL, ctrl); + wr32(E1000_CTRL_EXT, ctrl_ext); +} + static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp, struct ptp_clock_request *rq, int on) { struct igb_adapter *igb = container_of(ptp, struct igb_adapter, ptp_caps); struct e1000_hw *hw = &igb->hw; + u32 tsauxc, tsim, tsauxc_mask, tsim_mask, trgttiml, trgttimh; unsigned long flags; - u32 tsim; + struct timespec ts; + int pin; + s64 ns; switch (rq->type) { + case PTP_CLK_REQ_EXTTS: + if (on) { + pin = ptp_find_pin(igb->ptp_clock, PTP_PF_EXTTS, + rq->extts.index); + if (pin < 0) + return -EBUSY; + } + if (rq->extts.index == 1) { + tsauxc_mask = TSAUXC_EN_TS1; + tsim_mask = TSINTR_AUTT1; + } else { + tsauxc_mask = TSAUXC_EN_TS0; + tsim_mask = TSINTR_AUTT0; + } + spin_lock_irqsave(&igb->tmreg_lock, flags); + tsauxc = rd32(E1000_TSAUXC); + tsim = rd32(E1000_TSIM); + if (on) { + igb_pin_extts(igb, rq->extts.index, pin); + tsauxc |= tsauxc_mask; + tsim |= tsim_mask; + } else { + tsauxc &= ~tsauxc_mask; + tsim &= ~tsim_mask; + } + wr32(E1000_TSAUXC, tsauxc); + wr32(E1000_TSIM, tsim); + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + return 0; + + case PTP_CLK_REQ_PEROUT: + if (on) { + pin = ptp_find_pin(igb->ptp_clock, PTP_PF_PEROUT, + rq->perout.index); + if (pin < 0) + return -EBUSY; + } + ts.tv_sec = rq->perout.period.sec; + ts.tv_nsec = rq->perout.period.nsec; + ns = timespec_to_ns(&ts); + ns = ns >> 1; + if (on && ns < 500000LL) { + /* 2k interrupts per second is an awful lot. */ + return -EINVAL; + } + ts = ns_to_timespec(ns); + if (rq->perout.index == 1) { + tsauxc_mask = TSAUXC_EN_TT1; + tsim_mask = TSINTR_TT1; + trgttiml = E1000_TRGTTIML1; + trgttimh = E1000_TRGTTIMH1; + } else { + tsauxc_mask = TSAUXC_EN_TT0; + tsim_mask = TSINTR_TT0; + trgttiml = E1000_TRGTTIML0; + trgttimh = E1000_TRGTTIMH0; + } + spin_lock_irqsave(&igb->tmreg_lock, flags); + tsauxc = rd32(E1000_TSAUXC); + tsim = rd32(E1000_TSIM); + if (on) { + int i = rq->perout.index; + + igb_pin_perout(igb, i, pin); + igb->perout[i].start.tv_sec = rq->perout.start.sec; + igb->perout[i].start.tv_nsec = rq->perout.start.nsec; + igb->perout[i].period.tv_sec = ts.tv_sec; + igb->perout[i].period.tv_nsec = ts.tv_nsec; + wr32(trgttiml, rq->perout.start.sec); + wr32(trgttimh, rq->perout.start.nsec); + tsauxc |= tsauxc_mask; + tsim |= tsim_mask; + } else { + tsauxc &= ~tsauxc_mask; + tsim &= ~tsim_mask; + } + wr32(E1000_TSAUXC, tsauxc); + wr32(E1000_TSIM, tsim); + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + return 0; + case PTP_CLK_REQ_PPS: spin_lock_irqsave(&igb->tmreg_lock, flags); tsim = rd32(E1000_TSIM); @@ -375,9 +563,6 @@ static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp, wr32(E1000_TSIM, tsim); spin_unlock_irqrestore(&igb->tmreg_lock, flags); return 0; - - default: - break; } return -EOPNOTSUPP; @@ -389,6 +574,20 @@ static int igb_ptp_feature_enable(struct ptp_clock_info *ptp, return -EOPNOTSUPP; } +static int igb_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, + enum ptp_pin_function func, unsigned int chan) +{ + switch (func) { + case PTP_PF_NONE: + case PTP_PF_EXTTS: + case PTP_PF_PEROUT: + break; + case PTP_PF_PHYSYNC: + return -1; + } + return 0; +} + /** * igb_ptp_tx_work * @work: pointer to work struct @@ -779,6 +978,7 @@ void igb_ptp_init(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; + int i; switch (hw->mac.type) { case e1000_82576: @@ -821,16 +1021,27 @@ void igb_ptp_init(struct igb_adapter *adapter) break; case e1000_i210: case e1000_i211: + for (i = 0; i < IGB_N_SDP; i++) { + struct ptp_pin_desc *ppd = &adapter->sdp_config[i]; + + snprintf(ppd->name, sizeof(ppd->name), "SDP%d", i); + ppd->index = i; + ppd->func = PTP_PF_NONE; + } snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); adapter->ptp_caps.owner = THIS_MODULE; adapter->ptp_caps.max_adj = 62499999; - adapter->ptp_caps.n_ext_ts = 0; + adapter->ptp_caps.n_ext_ts = IGB_N_EXTTS; + adapter->ptp_caps.n_per_out = IGB_N_PEROUT; + adapter->ptp_caps.n_pins = IGB_N_SDP; adapter->ptp_caps.pps = 1; + adapter->ptp_caps.pin_config = adapter->sdp_config; adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580; adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210; adapter->ptp_caps.gettime = igb_ptp_gettime_i210; adapter->ptp_caps.settime = igb_ptp_settime_i210; adapter->ptp_caps.enable = igb_ptp_feature_enable_i210; + adapter->ptp_caps.verify = igb_ptp_verify_pin; /* Enable the timer functions by clearing bit 31. */ wr32(E1000_TSAUXC, 0x0); break; @@ -949,6 +1160,7 @@ void igb_ptp_reset(struct igb_adapter *adapter) case e1000_i210: case e1000_i211: wr32(E1000_TSAUXC, 0x0); + wr32(E1000_TSSDP, 0x0); wr32(E1000_TSIM, TSYNC_INTERRUPTS); wr32(E1000_IMS, E1000_IMS_TS); break; -- cgit v1.2.1 From e2929e453a1dddf489cc8bc360eb207df39d196c Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 11 Nov 2014 17:19:30 +0000 Subject: net/fm10k: Avoid double setting of NETIF_F_SG for the HW encapsulation feature mask The networking core does it for the driver during registration time. Signed-off-by: Or Gerlitz Acked-by: Matthew Vick Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 945b35d31c71..cfde8bac1aeb 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -1414,13 +1414,12 @@ struct net_device *fm10k_alloc_netdev(void) dev->vlan_features |= dev->features; /* configure tunnel offloads */ - dev->hw_enc_features = NETIF_F_IP_CSUM | - NETIF_F_TSO | - NETIF_F_TSO6 | - NETIF_F_TSO_ECN | - NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_IPV6_CSUM | - NETIF_F_SG; + dev->hw_enc_features |= NETIF_F_IP_CSUM | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_TSO_ECN | + NETIF_F_GSO_UDP_TUNNEL | + NETIF_F_IPV6_CSUM; /* we want to leave these both on as we cannot disable VLAN tag * insertion or stripping on the hardware since it is contained -- cgit v1.2.1 From b66b6d9f6dbe0655a570fb2a2482cceac5f1a9bc Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Fri, 14 Nov 2014 07:47:40 +0000 Subject: fm10k: Check tunnel header length in encap offload fm10k supports up to 184 bytes of inner+outer headers. Add an initial check to fail encap offload if these are too large. Signed-off-by: Joe Stringer Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index c7a19a5e0ec9..84ab9eea2768 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -727,6 +727,12 @@ static __be16 fm10k_tx_encap_offload(struct sk_buff *skb) struct ethhdr *eth_hdr; u8 l4_hdr = 0; +/* fm10k supports 184 octets of outer+inner headers. Minus 20 for inner L4. */ +#define FM10K_MAX_ENCAP_TRANSPORT_OFFSET 164 + if (skb_inner_transport_header(skb) - skb_mac_header(skb) > + FM10K_MAX_ENCAP_TRANSPORT_OFFSET) + return 0; + switch (vlan_get_protocol(skb)) { case htons(ETH_P_IP): l4_hdr = ip_hdr(skb)->protocol; -- cgit v1.2.1 From b4a9d6f17335ebd4d09f702cfffa059057ec238c Mon Sep 17 00:00:00 2001 From: Matthew Vick Date: Thu, 13 Nov 2014 07:29:18 +0000 Subject: fm10k: Increase the timeout for the data path reset Based on feedback from the hardware team, 100us is too short of a time to wait for the data path reset to complete and the recommendation is to increase this timeout to 150us. Signed-off-by: Matthew Vick Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_type.h b/drivers/net/ethernet/intel/fm10k/fm10k_type.h index 280296f29154..7c6d9d5a8ae5 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_type.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k_type.h @@ -354,7 +354,7 @@ struct fm10k_hw; /* Define timeouts for resets and disables */ #define FM10K_QUEUE_DISABLE_TIMEOUT 100 -#define FM10K_RESET_TIMEOUT 100 +#define FM10K_RESET_TIMEOUT 150 /* VF registers */ #define FM10K_VFCTRL 0x00000 -- cgit v1.2.1 From 6ddbc4cf1f4d5a3a58b4223c80881f299dae3774 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 9 Oct 2014 05:33:55 +0000 Subject: igb: Indicate failure on vf reset for empty mac address Commit 5ac6f91d changed the igb driver to expose a zero (empty) mac address to the VF on reset rather than a random one. However, that behavioral change also requires igbvf driver changes which can be hard especially when we want to talk to proprietary guest OSs. Looking at the code previous to the commit in Linux that made igbvf work with empty mac addresses (8d56b6d), we can see that on reset failure the driver will try to generate a new mac address with both the old and the new code. Furthermore, ixgbe does send reset failure when it detects an empty mac address (35055928c). So I think it's safe to make igb behave the same. With this patch I can successfully run a Windows 8.1 guest with an empty mac address and an assigned igbvf device that has no mac address set by the host. If anyone is aware of a guest driver that chokes on NACK returns of VF RESET commands, please speak up. Signed-off-by: Alexander Graf Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 6e6544970b83..f366b3b96d03 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6077,8 +6077,12 @@ static void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf) adapter->vf_data[vf].flags |= IGB_VF_FLAG_CTS; /* reply to reset with ack and vf mac address */ - msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK; - memcpy(addr, vf_mac, ETH_ALEN); + if (!is_zero_ether_addr(vf_mac)) { + msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK; + memcpy(addr, vf_mac, ETH_ALEN); + } else { + msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_NACK; + } igb_write_mbx(hw, msgbuf, 3, vf); } -- cgit v1.2.1 From 8a4d0b93c142a53c369998303d2114b5beeca7af Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 7 Jan 2015 11:40:33 +0000 Subject: net: e1000: support txtd update delay via xmit_more Don't update Tx tail descriptor if we queue hasn't been stopped and we know at least one more skb will be sent right away. Signed-off-by: Florian Westphal Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000/e1000_main.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 9242982db3e0..7f997d36948f 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -2977,7 +2977,6 @@ static void e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, int tx_flags, int count) { - struct e1000_hw *hw = &adapter->hw; struct e1000_tx_desc *tx_desc = NULL; struct e1000_tx_buffer *buffer_info; u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; @@ -3031,11 +3030,6 @@ static void e1000_tx_queue(struct e1000_adapter *adapter, wmb(); tx_ring->next_to_use = i; - writel(i, hw->hw_addr + tx_ring->tdt); - /* we need this if more than one processor can write to our tail - * at a time, it synchronizes IO on IA64/Altix systems - */ - mmiowb(); } /* 82547 workaround to avoid controller hang in half-duplex environment. @@ -3264,6 +3258,15 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, /* Make sure there is space in the ring for the next send. */ e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2); + if (!skb->xmit_more || + netif_xmit_stopped(netdev_get_tx_queue(netdev, 0))) { + writel(tx_ring->next_to_use, hw->hw_addr + tx_ring->tdt); + /* we need this if more than one processor can write to + * our tail at a time, it synchronizes IO on IA64/Altix + * systems + */ + mmiowb(); + } } else { dev_kfree_skb_any(skb); tx_ring->buffer_info[first].time_stamp = 0; -- cgit v1.2.1 From 472f31f5726ab2f41f09cb8175610f196fac2d7a Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 9 Jan 2015 09:26:14 +0000 Subject: net: e1000e: support txtd update delay via xmit_more Don't update Tx tail descriptor if queue hasn't been stopped and we know at least one more skb will be sent right away. Signed-off-by: Florian Westphal Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index aa39a81a6df6..1e8c40fd5c3d 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5444,16 +5444,6 @@ static void e1000_tx_queue(struct e1000_ring *tx_ring, int tx_flags, int count) wmb(); tx_ring->next_to_use = i; - - if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) - e1000e_update_tdt_wa(tx_ring, i); - else - writel(i, tx_ring->tail); - - /* we need this if more than one processor can write to our tail - * at a time, it synchronizes IO on IA64/Altix systems - */ - mmiowb(); } #define MINIMUM_DHCP_PACKET_SIZE 282 @@ -5655,6 +5645,21 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, (MAX_SKB_FRAGS * DIV_ROUND_UP(PAGE_SIZE, adapter->tx_fifo_limit) + 2)); + + if (!skb->xmit_more || + netif_xmit_stopped(netdev_get_tx_queue(netdev, 0))) { + if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) + e1000e_update_tdt_wa(tx_ring, + tx_ring->next_to_use); + else + writel(tx_ring->next_to_use, tx_ring->tail); + + /* we need this if more than one processor can write + * to our tail at a time, it synchronizes IO on + *IA64/Altix systems + */ + mmiowb(); + } } else { dev_kfree_skb_any(skb); tx_ring->buffer_info[first].time_stamp = 0; -- cgit v1.2.1 From 2b5b8f19fbf3b8337599db33cdf1afa84c1dde8d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 19 Dec 2014 06:33:55 +0530 Subject: ath9k: Fix no-ack frame status Check if the frame has been completed without any error and use IEEE80211_TX_STAT_NOACK_TRANSMITTED to indicate successful transmission of no-ack frames. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/xmit.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 1176d919569e..1b8e75c4d2c2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2489,9 +2489,12 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, if (sc->sc_ah->caldata) set_bit(PAPRD_PACKET_SENT, &sc->sc_ah->caldata->cal_flags); - if (!(tx_flags & ATH_TX_ERROR)) - /* Frame was ACKed */ - tx_info->flags |= IEEE80211_TX_STAT_ACK; + if (!(tx_flags & ATH_TX_ERROR)) { + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } padpos = ieee80211_hdrlen(hdr->frame_control); padsize = padpos & 3; -- cgit v1.2.1 From e00483f74682ea6aa7f3839a980c7cdb548de4d2 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 7 Jan 2015 03:57:39 -0800 Subject: mwifiex: check driver status in connect and scan handlers Ignore scan and connection requests from cfg80211 when driver unload is in process or previous command has timed out due to a firmware bug. This patch fixes corner case system crash issues. Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 8 ++++++++ drivers/net/wireless/mwifiex/scan.c | 6 ++++++ 2 files changed, 14 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b3bf2cd150b7..7be1e9b83fd0 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1786,6 +1786,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_adapter *adapter = priv->adapter; int ret; if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) { @@ -1800,6 +1801,13 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return -EALREADY; } + if (adapter->surprise_removed || adapter->is_cmd_timedout) { + wiphy_err(wiphy, + "%s: Ignore connection. Card removed or FW in bad state\n", + dev->name); + return -EFAULT; + } + wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", (char *) sme->ssid, sme->bssid); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 984a7a4fa93b..e304f0731647 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1429,6 +1429,12 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, return -EBUSY; } + if (adapter->surprise_removed || adapter->is_cmd_timedout) { + dev_err(adapter->dev, + "Ignore scan. Card removed or firmware in bad state\n"); + return -EFAULT; + } + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); adapter->scan_processing = true; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); -- cgit v1.2.1 From 09bd197659ae6e9e0ad67b08fb4fe7420a292387 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 7 Jan 2015 18:10:25 +0530 Subject: mwifiex: do not emit messages while holding spinlock Avoid printing dev_{warn/dbg} messages while holding spinlock. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11n.c | 2 +- drivers/net/wireless/mwifiex/11n_rxreorder.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 9d4786e7ddff..c5c83cf664d8 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -558,10 +558,10 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) spin_lock_irqsave(&priv->sta_list_spinlock, flags); sta_ptr = mwifiex_get_sta_entry(priv, peer_mac); if (!sta_ptr) { + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); dev_warn(priv->adapter->dev, "BA setup with unknown TDLS peer %pM!\n", peer_mac); - spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); return -1; } if (sta_ptr->is_11ac_enabled) diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index f33dc81c5228..c7ca5b734875 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -353,9 +353,6 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, spin_lock_irqsave(&priv->sta_list_spinlock, flags); if (mwifiex_queuing_ra_based(priv)) { - dev_dbg(priv->adapter->dev, - "info: AP/ADHOC:last_seq=%d start_win=%d\n", - last_seq, new_node->start_win); if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) { node = mwifiex_get_sta_entry(priv, ta); if (node) @@ -370,6 +367,9 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, } spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + dev_dbg(priv->adapter->dev, "info: last_seq=%d start_win=%d\n", + last_seq, new_node->start_win); + if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM && last_seq >= new_node->start_win) { new_node->start_win = last_seq + 1; @@ -466,10 +466,10 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, sta_ptr = mwifiex_get_sta_entry(priv, cmd_addba_req->peer_mac_addr); if (!sta_ptr) { + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); dev_warn(priv->adapter->dev, "BA setup with unknown TDLS peer %pM!\n", cmd_addba_req->peer_mac_addr); - spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); return -1; } if (sta_ptr->is_11ac_enabled) -- cgit v1.2.1 From 96dae59155eb98dd0ba10e8fe5d130f425e406df Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Wed, 7 Jan 2015 20:38:37 +0100 Subject: wlcore: fix copy-paste bug: assign from src struct not dest Signed-off-by: Giel van Schijndel Reported-at: http://www.viva64.com/en/b/0299/ Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/acx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c index b924ceadc02c..f28fa3b5029d 100644 --- a/drivers/net/wireless/ti/wlcore/acx.c +++ b/drivers/net/wireless/ti/wlcore/acx.c @@ -1725,7 +1725,7 @@ int wl12xx_acx_config_hangover(struct wl1271 *wl) acx->decrease_delta = conf->decrease_delta; acx->quiet_time = conf->quiet_time; acx->increase_time = conf->increase_time; - acx->window_size = acx->window_size; + acx->window_size = conf->window_size; ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx, sizeof(*acx)); -- cgit v1.2.1 From 69a88cc7b164d92b4e397d9505dd4533f95fbc8a Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 9 Jan 2015 14:15:45 -0500 Subject: wcn36xx: initialize device defaults on start Set up default configuration for the device when we call start. The defaults come from dumps from the prima driver for the same hardware. This fixes transmit A-MPDU; previously only one MPDU would be sent per A-MPDU due to missing MAX_MPDUS_IN_AMPDU setting. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/smd.c | 73 +++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 63986931829e..69ed39731902 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -21,6 +21,61 @@ #include #include "smd.h" +struct wcn36xx_cfg_val { + u32 cfg_id; + u32 value; +}; + +#define WCN36XX_CFG_VAL(id, val) \ +{ \ + .cfg_id = WCN36XX_HAL_CFG_ ## id, \ + .value = val \ +} + +static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = { + WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1), + WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1), + WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0), + WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785), + WCN36XX_CFG_VAL(CAL_PERIOD, 5), + WCN36XX_CFG_VAL(CAL_CONTROL, 1), + WCN36XX_CFG_VAL(PROXIMITY, 0), + WCN36XX_CFG_VAL(NETWORK_DENSITY, 3), + WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 6000), + WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64), + WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347), + WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 6), + WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 6), + WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000), + WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5), + WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10), + WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15), + WCN36XX_CFG_VAL(FIXED_RATE, 0), + WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4), + WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0), + WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0), + WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5), + WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1), + WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5), + WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5), + WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40), + WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200), + WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1), + WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1), + WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20), + WCN36XX_CFG_VAL(STATS_PERIOD, 10), + WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000), + WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0), + WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128), + WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560), + WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0), + WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1), + WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1), + WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0), + WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10), + WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0), +}; + static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value) { struct wcn36xx_hal_cfg *entry; @@ -357,8 +412,10 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len) int wcn36xx_smd_start(struct wcn36xx *wcn) { - struct wcn36xx_hal_mac_start_req_msg msg_body; + struct wcn36xx_hal_mac_start_req_msg msg_body, *body; int ret = 0; + int i; + size_t len; mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ); @@ -368,10 +425,22 @@ int wcn36xx_smd_start(struct wcn36xx *wcn) PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + body = (struct wcn36xx_hal_mac_start_req_msg *)wcn->hal_buf; + len = body->header.len; + + for (i = 0; i < ARRAY_SIZE(wcn36xx_cfg_vals); i++) { + ret = put_cfg_tlv_u32(wcn, &len, wcn36xx_cfg_vals[i].cfg_id, + wcn36xx_cfg_vals[i].value); + if (ret) + goto out; + } + body->header.len = len; + body->params.len = len - sizeof(*body); + wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start type %d\n", msg_body.params.type); - ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + ret = wcn36xx_smd_send_and_wait(wcn, body->header.len); if (ret) { wcn36xx_err("Sending hal_start failed\n"); goto out; -- cgit v1.2.1 From f786a6d4af92204351a31117c8eeae1a4518b7c6 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 9 Jan 2015 14:15:46 -0500 Subject: wcn36xx: use !! when assigning int as a boolean bd->tx_comp is a single bit in a bitfield, so assigning "info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS" only happens to work because TX_STATUS is defined to BIT(0); if it were any other bit this assignment would fail. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 32bb26a0db2a..f7018730be0d 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -237,7 +237,7 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, bd->dpu_rf = WCN36XX_BMU_WQ_TX; - bd->tx_comp = info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS; + bd->tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS); if (bd->tx_comp) { wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n"); spin_lock_irqsave(&wcn->dxe_lock, flags); -- cgit v1.2.1 From 232ddcd80fa5c878efd631c6562cbaa24535bdc1 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 9 Jan 2015 14:15:47 -0500 Subject: wcn36xx: let device generate qos seq numbers wcn36xx currently sends an incorrect sequence number into the BA session setup firmware command: it should be saving or updating the ssn in the TX_START ampdu_action callback instead of waiting until TX_OPERATIONAL. However, we can sidestep the issue by letting the hardware generate the sequence numbers for QoS frames, as is done in prima, so do that. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/txrx.c | 1 + drivers/net/wireless/ath/wcn36xx/txrx.h | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index f7018730be0d..277bc39e23df 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -93,6 +93,7 @@ static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd, bd->pdu.mpdu_header_off; bd->pdu.mpdu_len = len; bd->pdu.tid = tid; + bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_QOS; } static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn, diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.h b/drivers/net/wireless/ath/wcn36xx/txrx.h index bbfbcf808c77..032216e82b2b 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.h +++ b/drivers/net/wireless/ath/wcn36xx/txrx.h @@ -32,6 +32,12 @@ #define WCN36XX_BD_RATE_MGMT 2 #define WCN36XX_BD_RATE_CTRL 3 +enum wcn36xx_txbd_ssn_type { + WCN36XX_TXBD_SSN_FILL_HOST = 0, + WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS = 1, + WCN36XX_TXBD_SSN_FILL_DPU_QOS = 2, +}; + struct wcn36xx_pdu { u32 dpu_fb:8; u32 adu_fb:8; @@ -50,7 +56,8 @@ struct wcn36xx_pdu { /* 0x0c*/ u32 reserved4:8; u32 tid:4; - u32 reserved3:4; + u32 bd_ssn:2; + u32 reserved3:2; u32 mpdu_len:16; }; -- cgit v1.2.1 From bfa6696b39ae4da554a8b8ec9d17bba1ed6ae889 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 9 Jan 2015 14:15:48 -0500 Subject: wcn36xx: don't process 'valid' descriptors The DMA engine will reset the valid bit after a descriptor is complete; any with the valid bit still set may still be in use by the hardware, so check that before freeing the descriptor. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 73f12f196f14..3d6bc9b87176 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -354,6 +354,8 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) * and while-do will not make any cycles. */ do { + if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK) + break; if (ctl->skb) { dma_unmap_single(NULL, ctl->desc->src_addr_l, ctl->skb->len, DMA_TO_DEVICE); -- cgit v1.2.1 From 90dccb73e985a4efb278dcab83cd57d40aa35419 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 9 Jan 2015 14:15:49 -0500 Subject: wcn36xx: initialize skb_lock ctl->skb_lock is never initialized, a fact caught by lockdep. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 3d6bc9b87176..086549b732b9 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -84,6 +84,7 @@ static int wcn36xx_dxe_allocate_ctl_block(struct wcn36xx_dxe_ch *ch) if (!cur_ctl) goto out_fail; + spin_lock_init(&cur_ctl->skb_lock); cur_ctl->ctl_blk_order = i; if (i == 0) { ch->head_blk_ctl = cur_ctl; -- cgit v1.2.1 From 4b12462a3a7f44066aa2885a487a5154f5f75c99 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 9 Jan 2015 14:15:50 -0500 Subject: wcn36xx: initialize dxe lock The dxe lock is missing its initialization, so add it. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 7dd8873f757e..972bb3e653a1 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -298,6 +298,8 @@ static int wcn36xx_start(struct ieee80211_hw *hw) wcn36xx_debugfs_init(wcn); INIT_LIST_HEAD(&wcn->vif_list); + spin_lock_init(&wcn->dxe_lock); + return 0; out_smd_stop: -- cgit v1.2.1 From 5f3f928585b22aada39f87611df75bac4a12a6c7 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 9 Jan 2015 14:15:51 -0500 Subject: wcn36xx: move set_tx_pdu inside set_tx_data/mgmt The pdu is part of the buffer descriptor, so it makes sense that one function would fill both. Also, passing the whole skb instead of just the header pointer to the set_tx_data function paves the way for using its fields for ampdu setup inside set_tx_data(). Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/txrx.c | 37 ++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 277bc39e23df..7f0d9e6afcec 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -115,9 +115,10 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, struct wcn36xx *wcn, struct wcn36xx_vif **vif_priv, struct wcn36xx_sta *sta_priv, - struct ieee80211_hdr *hdr, + struct sk_buff *skb, bool bcast) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_vif *vif = NULL; struct wcn36xx_vif *__vif_priv = NULL; bd->bd_rate = WCN36XX_BD_RATE_DATA; @@ -158,14 +159,21 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, bd->ack_policy = 1; } *vif_priv = __vif_priv; + + wcn36xx_set_tx_pdu(bd, + ieee80211_is_data_qos(hdr->frame_control) ? + sizeof(struct ieee80211_qos_hdr) : + sizeof(struct ieee80211_hdr_3addr), + skb->len, sta_priv ? sta_priv->tid : 0); } static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, struct wcn36xx *wcn, struct wcn36xx_vif **vif_priv, - struct ieee80211_hdr *hdr, + struct sk_buff *skb, bool bcast) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct wcn36xx_vif *__vif_priv = get_vif_by_addr(wcn, hdr->addr2); bd->sta_index = __vif_priv->self_sta_index; @@ -199,6 +207,12 @@ static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, } else bd->queue_id = WCN36XX_TX_U_WQ_ID; *vif_priv = __vif_priv; + + wcn36xx_set_tx_pdu(bd, + ieee80211_is_data_qos(hdr->frame_control) ? + sizeof(struct ieee80211_qos_hdr) : + sizeof(struct ieee80211_hdr_3addr), + skb->len, WCN36XX_TID); } int wcn36xx_start_tx(struct wcn36xx *wcn, @@ -260,22 +274,11 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, } /* Data frames served first*/ - if (is_low) { - wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, hdr, bcast); - wcn36xx_set_tx_pdu(bd, - ieee80211_is_data_qos(hdr->frame_control) ? - sizeof(struct ieee80211_qos_hdr) : - sizeof(struct ieee80211_hdr_3addr), - skb->len, sta_priv ? sta_priv->tid : 0); - } else { + if (is_low) + wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, skb, bcast); + else /* MGMT and CTRL frames are handeld here*/ - wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, hdr, bcast); - wcn36xx_set_tx_pdu(bd, - ieee80211_is_data_qos(hdr->frame_control) ? - sizeof(struct ieee80211_qos_hdr) : - sizeof(struct ieee80211_hdr_3addr), - skb->len, WCN36XX_TID); - } + wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, skb, bcast); buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32)); bd->tx_bd_sign = 0xbdbdbdbd; -- cgit v1.2.1 From e26dc173a66ab3de38fbb8d71b58dbb72e29d6c9 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 9 Jan 2015 14:15:52 -0500 Subject: wcn36xx: initiate TX BA sessions Currently, wcn36xx only asks for a TX BA session if it has already established one for RX. Thus, two wcn36xx devices cannot do a-mpdu between themselves since they both wait for the other to go first. Fix this by starting a BA session after a few QoS data frames have been sent to a STA. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/main.c | 14 +++++++++- drivers/net/wireless/ath/wcn36xx/txrx.c | 45 +++++++++++++++++++++++++++++- drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 20 +++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 972bb3e653a1..0783d2ed8238 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -797,6 +797,7 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n", vif, sta->addr); + spin_lock_init(&sta_priv->ampdu_lock); vif_priv->sta = sta_priv; sta_priv->vif = vif_priv; /* @@ -875,21 +876,32 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, get_sta_index(vif, sta_priv)); wcn36xx_smd_add_ba(wcn); wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv)); - ieee80211_start_tx_ba_session(sta, tid, 0); break; case IEEE80211_AMPDU_RX_STOP: wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv)); break; case IEEE80211_AMPDU_TX_START: + spin_lock_bh(&sta_priv->ampdu_lock); + sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; + spin_unlock_bh(&sta_priv->ampdu_lock); + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: + spin_lock_bh(&sta_priv->ampdu_lock); + sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL; + spin_unlock_bh(&sta_priv->ampdu_lock); + wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1, get_sta_index(vif, sta_priv)); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: case IEEE80211_AMPDU_TX_STOP_CONT: + spin_lock_bh(&sta_priv->ampdu_lock); + sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE; + spin_unlock_bh(&sta_priv->ampdu_lock); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; default: diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 7f0d9e6afcec..9bec8237231d 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -111,6 +111,42 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn, wcn36xx_warn("vif %pM not found\n", addr); return NULL; } + +static void wcn36xx_tx_start_ampdu(struct wcn36xx *wcn, + struct wcn36xx_sta *sta_priv, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_sta *sta; + u8 *qc, tid; + + if (!conf_is_ht(&wcn->hw->conf)) + return; + + sta = wcn36xx_priv_to_sta(sta_priv); + + if (WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) + return; + + if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + return; + + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + + spin_lock(&sta_priv->ampdu_lock); + if (sta_priv->ampdu_state[tid] != WCN36XX_AMPDU_NONE) + goto out_unlock; + + if (sta_priv->non_agg_frame_ct++ >= WCN36XX_AMPDU_START_THRESH) { + sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; + sta_priv->non_agg_frame_ct = 0; + ieee80211_start_tx_ba_session(sta, tid, 0); + } +out_unlock: + spin_unlock(&sta_priv->ampdu_lock); +} + static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, struct wcn36xx *wcn, struct wcn36xx_vif **vif_priv, @@ -121,6 +157,8 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_vif *vif = NULL; struct wcn36xx_vif *__vif_priv = NULL; + bool is_data_qos; + bd->bd_rate = WCN36XX_BD_RATE_DATA; /* @@ -160,11 +198,16 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, } *vif_priv = __vif_priv; + is_data_qos = ieee80211_is_data_qos(hdr->frame_control); + wcn36xx_set_tx_pdu(bd, - ieee80211_is_data_qos(hdr->frame_control) ? + is_data_qos ? sizeof(struct ieee80211_qos_hdr) : sizeof(struct ieee80211_hdr_3addr), skb->len, sta_priv ? sta_priv->tid : 0); + + if (sta_priv && is_data_qos) + wcn36xx_tx_start_ampdu(wcn, sta_priv, skb); } static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index f0fb81dfd17b..7b41e833e18c 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -32,6 +32,9 @@ #define WLAN_NV_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" #define WCN36XX_AGGR_BUFFER_SIZE 64 +/* How many frames until we start a-mpdu TX session */ +#define WCN36XX_AMPDU_START_THRESH 20 + extern unsigned int wcn36xx_dbg_mask; enum wcn36xx_debug_mask { @@ -74,6 +77,13 @@ enum wcn36xx_debug_mask { buf, len, false); \ } while (0) +enum wcn36xx_ampdu_state { + WCN36XX_AMPDU_NONE, + WCN36XX_AMPDU_INIT, + WCN36XX_AMPDU_START, + WCN36XX_AMPDU_OPERATIONAL, +}; + #define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value) #define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band) #define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq) @@ -165,6 +175,10 @@ struct wcn36xx_sta { bool is_data_encrypted; /* Rates */ struct wcn36xx_hal_supported_rates supported_rates; + + spinlock_t ampdu_lock; /* protects next two fields */ + enum wcn36xx_ampdu_state ampdu_state[16]; + int non_agg_frame_ct; }; struct wcn36xx_dxe_ch; struct wcn36xx { @@ -243,4 +257,10 @@ static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn, } void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates); +static inline +struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv) +{ + return container_of((void *)sta_priv, struct ieee80211_sta, drv_priv); +} + #endif /* _WCN36XX_H_ */ -- cgit v1.2.1 From 3a939a671225909c19b09bfcb6e4761109e913d9 Mon Sep 17 00:00:00 2001 From: Hong Xu Date: Sun, 11 Jan 2015 11:45:53 -0800 Subject: ath9k_htc: Add a module parameter to disable blink Add an option "blink" to enable or disable the LED blink. The default value is set to 1 so that existing users would not experience any unexpected changes. Signed-off-by: Hong Xu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/htc.h | 3 +++ drivers/net/wireless/ath/ath9k/htc_drv_gpio.c | 4 ++++ drivers/net/wireless/ath/ath9k/htc_drv_init.c | 4 ++++ 3 files changed, 11 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 9dde265d3f84..c43fec51b8ec 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -44,6 +44,9 @@ extern struct ieee80211_ops ath9k_htc_ops; extern int htc_modparam_nohwcrypt; +#ifdef CONFIG_MAC80211_LEDS +extern int led_blink; +#endif enum htc_phymode { HTC_MODE_11NA = 0, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 50f74a2a4cf8..998b558d4126 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -279,6 +279,10 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv) else priv->ah->led_pin = ATH_LED_PIN_DEF; + if (!led_blink) + priv->led_cdev.default_trigger = + ieee80211_get_radio_led_name(priv->hw); + ath9k_configure_leds(priv); snprintf(priv->led_name, sizeof(priv->led_name), diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index e8fa9448da24..947012757f81 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -39,6 +39,10 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); #ifdef CONFIG_MAC80211_LEDS +int led_blink = 1; +module_param_named(blink, led_blink, int, 0444); +MODULE_PARM_DESC(blink, "Enable LED blink on activity"); + static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { { .throughput = 0 * 1024, .blink_time = 334 }, { .throughput = 1 * 1024, .blink_time = 260 }, -- cgit v1.2.1 From 59b23ebd7fd0af3facd174e96ee4dbc1494fa215 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 13 Jan 2015 14:07:34 +0000 Subject: rtlwifi/rtl8192de: remove redundant else if check The else if check condition checks for the opposite of the if check, hence the else if check is redundant and can be replaced with a simple else: if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) { .. } else if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) { .. } replaced with: if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) { .. } else { .. } Signed-off-by: Colin Ian King Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192de/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index 280c3da42993..01bcc2d218dc 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -546,7 +546,7 @@ static bool _rtl92de_llt_table_init(struct ieee80211_hw *hw) txpktbuf_bndy = 246; value8 = 0; value32 = 0x80bf0d29; - } else if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) { + } else { maxPage = 127; txpktbuf_bndy = 123; value8 = 0; -- cgit v1.2.1 From bcb514413e3b0f4d7e40b2f97bbb83a57e09f657 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 15 Jan 2015 14:43:40 +0300 Subject: wlcore: unlock on error in wl1271_op_suspend() We recently introduced a new error path which needs an unlock. Fixes: 6d5a748d4836 ('wlcore: add ability to reduce FW interrupts during suspend') Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 0a9d9a1b2d85..1e136993580f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1785,8 +1785,10 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + if (ret < 0) { + mutex_unlock(&wl->mutex); return ret; + } wl->wow_enabled = true; wl12xx_for_each_wlvif(wl, wlvif) { -- cgit v1.2.1 From 6b47aacaa4491ab04630ab0aec10d10e6ac9e14f Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Mon, 19 Jan 2015 15:34:32 +0100 Subject: b43: stop leds during suspend Call b43_leds_stop during suspend to avoid this WARN: WARNING: CPU: 1 PID: 0 at net/mac80211/util.c:755 ieee80211_can_queue_work.isra.11+0x35/0x50 [mac80211]() queueing ieee80211 work while going to suspend [...] Call Trace: [] dump_stack+0x48/0x69 [] warn_slowpath_common+0x8b/0xc0 [] ? ieee80211_can_queue_work.isra.11+0x35/0x50 [mac80211] [] ? ieee80211_can_queue_work.isra.11+0x35/0x50 [mac80211] [] warn_slowpath_fmt+0x33/0x40 [] ieee80211_can_queue_work.isra.11+0x35/0x50 [mac80211] [] ieee80211_queue_work+0x20/0x40 [mac80211] [] b43_led_brightness_set+0x28/0x30 [b43] [] led_timer_function+0xd5/0xe0 [] call_timer_fn+0xa4/0x4a0 Signed-off-by: Sabrina Dubroca Signed-off-by: Kalle Valo --- drivers/net/wireless/b43/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 47731cb0d815..58a2e88631fb 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4318,6 +4318,7 @@ redo: mutex_unlock(&wl->mutex); cancel_delayed_work_sync(&dev->periodic_work); cancel_work_sync(&wl->tx_work); + b43_leds_stop(dev); mutex_lock(&wl->mutex); dev = wl->current_dev; if (!dev || b43_status(dev) < B43_STAT_STARTED) { -- cgit v1.2.1 From 362126cddb22256db1e9ab6862aa720c3f091e52 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Fri, 16 Jan 2015 21:36:14 +0530 Subject: brcmfmac: Use put_unaligned_le32 This patch introduces the use of function put_unaligned_le32. This is done using Coccinelle and semantic patch used is as follows: @a@ typedef u32, __le32, uint32_t; {u32,__le32,uint32_t} e32; identifier tmp; expression ptr; expression y,e; type T; type T; @@ - tmp = cpu_to_le32(y); <+... when != tmp ( - memcpy(ptr, (T)&tmp, \(4\|sizeof(u32)\|sizeof(__le32)\|sizeof(uint32_t)\|sizeof(e32)\)); + put_unaligned_le32(y,ptr); | - memcpy(ptr, (T)&tmp, ...); + put_unaligned_le32(y,ptr); ) ...+> ? tmp = e @@ type T; identifier a.tmp; @@ - T tmp; ...when != tmp Signed-off-by: Vaishali Thakkar Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index ebe654312b74..5eba81bfc6ed 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -3737,17 +3737,12 @@ static u32 brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd) { - __le32 iecount_le; - __le32 pktflag_le; - strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1); iebuf[VNDR_IE_CMD_LEN - 1] = '\0'; - iecount_le = cpu_to_le32(1); - memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le)); + put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]); - pktflag_le = cpu_to_le32(pktflag); - memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le)); + put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]); memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len); -- cgit v1.2.1 From 811c69e63a85223dfd865443fde21d8c60569a58 Mon Sep 17 00:00:00 2001 From: John Linville Date: Mon, 19 Jan 2015 14:02:21 -0500 Subject: ath9k_htc: remove dead code in error path of ath9k_htc_txcompletion_cb This clause is conditioned on htc_hdr != NULL, but it will only be NULL when that check is reached. Coverity: CID 114318 Signed-off-by: John W. Linville Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/htc_hst.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index a0ff5b637054..d2408da38c1c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -351,11 +351,7 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, return; ret: - /* HTC-generated packets are freed here. */ - if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0) - dev_kfree_skb_any(skb); - else - kfree_skb(skb); + kfree_skb(skb); } static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle, -- cgit v1.2.1 From c0719334bf0b4d72fc0d22c484c698eec2a95c6d Mon Sep 17 00:00:00 2001 From: John Linville Date: Mon, 19 Jan 2015 14:09:15 -0500 Subject: ath5k: document a fall-through case in ath5k_hw_set_opmode Coverity: CID 114932 Signed-off-by: John W. Linville Acked-by: Nick Kossifidis Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath5k/pcu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index c60d36aa13e2..bf29da5e90da 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -912,6 +912,7 @@ ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_PWR_SV : 0); + /* fall through */ case NL80211_IFTYPE_MONITOR: pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | (ah->ah_version == AR5K_AR5210 ? -- cgit v1.2.1 From 5b4c6b4f0b2778351c5bef74888a5fbdfbdd0ef5 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Tue, 20 Jan 2015 06:25:43 +0100 Subject: p54: add handling of the signal case if(!wait_for_completion_interruptible_timeout(...)) only handles the timeout case - this patch adds handling the signal case the same as timeout. Signed-off-by: Nicholas Mc Guire Acked-by: Christian Lamparter Signed-off-by: Kalle Valo --- drivers/net/wireless/p54/fwio.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index bc065e8e348b..5367d510b22d 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -220,6 +220,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf, struct sk_buff *skb; size_t eeprom_hdr_size; int ret = 0; + long timeout; if (priv->fw_var >= 0x509) eeprom_hdr_size = sizeof(*eeprom_hdr); @@ -249,9 +250,11 @@ int p54_download_eeprom(struct p54_common *priv, void *buf, p54_tx(priv, skb); - if (!wait_for_completion_interruptible_timeout( - &priv->eeprom_comp, HZ)) { - wiphy_err(priv->hw->wiphy, "device does not respond!\n"); + timeout = wait_for_completion_interruptible_timeout( + &priv->eeprom_comp, HZ); + if (timeout <= 0) { + wiphy_err(priv->hw->wiphy, + "device does not respond or signal received!\n"); ret = -EBUSY; } priv->eeprom = NULL; -- cgit v1.2.1 From 961d1bbecf33de0321cc59f0ea16dd517ecbf3fb Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Tue, 20 Jan 2015 06:26:17 +0100 Subject: p54pci: add handling of signal case if(!wait_for_completion_interruptible_timeout(...)) only handles the timeout case - this patch adds handling the signal case the same as timeout. Signed-off-by: Nicholas Mc Guire Acked-by: Christian Lamparter Signed-off-by: Kalle Valo --- drivers/net/wireless/p54/p54pci.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index d4aee64fb5ea..27a49068d32d 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -431,6 +431,7 @@ static int p54p_open(struct ieee80211_hw *dev) { struct p54p_priv *priv = dev->priv; int err; + long timeout; init_completion(&priv->boot_comp); err = request_irq(priv->pdev->irq, p54p_interrupt, @@ -468,10 +469,12 @@ static int p54p_open(struct ieee80211_hw *dev) P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); P54P_READ(dev_int); - if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { + timeout = wait_for_completion_interruptible_timeout( + &priv->boot_comp, HZ); + if (timeout <= 0) { wiphy_err(dev->wiphy, "Cannot boot firmware!\n"); p54p_stop(dev); - return -ETIMEDOUT; + return timeout ? -ERESTARTSYS : -ETIMEDOUT; } P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)); -- cgit v1.2.1 From 908414af255ea974bd0cfe54918d7957cd457d15 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 21 Jan 2015 12:52:07 +0100 Subject: atmel: Remove open-coded and wrong strcasecmp The kernel's string library does in fact have strcasecmp, at least since ded220bd8f08 ("[STRING]: Move strcasecmp/strncasecmp to lib/string.c"). Moreover, this open-coded version is in fact wrong: If the strings only differ in their last character, a and b have already been incremented to point to the terminating NUL bytes, so they would wrongly be treated as equal. Signed-off-by: Rasmus Villemoes Signed-off-by: Kalle Valo --- drivers/net/wireless/atmel.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 9183f1cf89a7..55db9f03eb2a 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -2699,16 +2698,7 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) domain[REGDOMAINSZ] = 0; rc = -EINVAL; for (i = 0; i < ARRAY_SIZE(channel_table); i++) { - /* strcasecmp doesn't exist in the library */ - char *a = channel_table[i].name; - char *b = domain; - while (*a) { - char c1 = *a++; - char c2 = *b++; - if (tolower(c1) != tolower(c2)) - break; - } - if (!*a && !*b) { + if (!strcasecmp(channel_table[i].name, domain)) { priv->config_reg_domain = channel_table[i].reg_domain; rc = 0; } -- cgit v1.2.1 From eaca400f1d14eec98561ab9dad0da03d65c5e8d0 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 20 Jan 2015 15:15:45 +0100 Subject: macvlan: advertise link netns via netlink Assign rtnl_link_ops->get_link_net() callback so that IFLA_LINK_NETNSID is added to rtnetlink messages. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 612e0731142d..1df38bdae2ee 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1471,11 +1471,17 @@ int macvlan_link_register(struct rtnl_link_ops *ops) }; EXPORT_SYMBOL_GPL(macvlan_link_register); +static struct net *macvlan_get_link_net(const struct net_device *dev) +{ + return dev_net(macvlan_dev_real_dev(dev)); +} + static struct rtnl_link_ops macvlan_link_ops = { .kind = "macvlan", .setup = macvlan_setup, .newlink = macvlan_newlink, .dellink = macvlan_dellink, + .get_link_net = macvlan_get_link_net, }; static int macvlan_device_event(struct notifier_block *unused, -- cgit v1.2.1 From e5f4e7b9ff331c6995af826b222681528de574b6 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 20 Jan 2015 15:15:46 +0100 Subject: veth: advertise link netns via netlink Assign rtnl_link_ops->get_link_net() callback so that IFLA_LINK_NETNSID is added to rtnetlink messages. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/veth.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 8ad596573d17..4cca36ebc4fb 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -469,6 +469,14 @@ static const struct nla_policy veth_policy[VETH_INFO_MAX + 1] = { [VETH_INFO_PEER] = { .len = sizeof(struct ifinfomsg) }, }; +static struct net *veth_get_link_net(const struct net_device *dev) +{ + struct veth_priv *priv = netdev_priv(dev); + struct net_device *peer = rtnl_dereference(priv->peer); + + return peer ? dev_net(peer) : dev_net(dev); +} + static struct rtnl_link_ops veth_link_ops = { .kind = DRV_NAME, .priv_size = sizeof(struct veth_priv), @@ -478,6 +486,7 @@ static struct rtnl_link_ops veth_link_ops = { .dellink = veth_dellink, .policy = veth_policy, .maxtype = VETH_INFO_MAX, + .get_link_net = veth_get_link_net, }; /* -- cgit v1.2.1 From 193523bf937309d57c6dd7839bcf34d7a029dbee Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 20 Jan 2015 15:15:47 +0100 Subject: vxlan: advertise netns of vxlan dev in fdb msg Netlink FDB messages are sent in the link netns. The header of these messages contains the ifindex (ndm_ifindex) of the netdevice, but this ifindex is unusable in case of x-netns vxlan. I named the new attribute NDA_NDM_IFINDEX_NETNSID, to avoid confusion with NDA_IFINDEX. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 0346eaa6d236..19d3664ab9dd 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -339,6 +339,11 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, ndm->ndm_flags = fdb->flags; ndm->ndm_type = RTN_UNICAST; + if (!net_eq(dev_net(vxlan->dev), vxlan->net) && + nla_put_s32(skb, NDA_NDM_IFINDEX_NETNSID, + peernet2id(vxlan->net, dev_net(vxlan->dev)))) + goto nla_put_failure; + if (send_eth && nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->eth_addr)) goto nla_put_failure; -- cgit v1.2.1 From 1650d5455bd2dc6b5ee134bd6fc1a3236c266b5b Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Tue, 20 Jan 2015 14:49:52 +0000 Subject: xen-netback: always fully coalesce guest Rx packets Always fully coalesce guest Rx packets into the minimum number of ring slots. Reducing the number of slots per packet has significant performance benefits when receiving off-host traffic. Results from XenServer's performance benchmarks: Baseline Full coalesce Interhost VM receive 7.2 Gb/s 11 Gb/s Interhost aggregate 24 Gb/s 24 Gb/s Intrahost single stream 14 Gb/s 14 Gb/s Intrahost aggregate 34 Gb/s 34 Gb/s However, this can increase the number of grant ops per packet which decreases performance of backend (dom0) to VM traffic (by ~10%) /unless/ grant copy has been optimized for adjacent ops with the same source or destination (see "grant-table: defer releasing pages acquired in a grant copy"[1] expected in Xen 4.6). [1] http://lists.xen.org/archives/html/xen-devel/2015-01/msg01118.html Signed-off-by: David Vrabel Acked-by: Ian Campbell Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 1 - drivers/net/xen-netback/netback.c | 107 ++------------------------------------ 2 files changed, 3 insertions(+), 105 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 5f1fda44882b..589fa256256b 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -251,7 +251,6 @@ struct xenvif { struct xenvif_rx_cb { unsigned long expires; int meta_slots_used; - bool full_coalesce; }; #define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 908e65e9b821..49322b6c32df 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -233,51 +233,6 @@ static void xenvif_rx_queue_drop_expired(struct xenvif_queue *queue) } } -/* - * Returns true if we should start a new receive buffer instead of - * adding 'size' bytes to a buffer which currently contains 'offset' - * bytes. - */ -static bool start_new_rx_buffer(int offset, unsigned long size, int head, - bool full_coalesce) -{ - /* simple case: we have completely filled the current buffer. */ - if (offset == MAX_BUFFER_OFFSET) - return true; - - /* - * complex case: start a fresh buffer if the current frag - * would overflow the current buffer but only if: - * (i) this frag would fit completely in the next buffer - * and (ii) there is already some data in the current buffer - * and (iii) this is not the head buffer. - * and (iv) there is no need to fully utilize the buffers - * - * Where: - * - (i) stops us splitting a frag into two copies - * unless the frag is too large for a single buffer. - * - (ii) stops us from leaving a buffer pointlessly empty. - * - (iii) stops us leaving the first buffer - * empty. Strictly speaking this is already covered - * by (ii) but is explicitly checked because - * netfront relies on the first buffer being - * non-empty and can crash otherwise. - * - (iv) is needed for skbs which can use up more than MAX_SKB_FRAGS - * slot - * - * This means we will effectively linearise small - * frags but do not needlessly split large buffers - * into multiple copies tend to give large frags their - * own buffers as before. - */ - BUG_ON(size > MAX_BUFFER_OFFSET); - if ((offset + size > MAX_BUFFER_OFFSET) && offset && !head && - !full_coalesce) - return true; - - return false; -} - struct netrx_pending_operations { unsigned copy_prod, copy_cons; unsigned meta_prod, meta_cons; @@ -336,24 +291,13 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb BUG_ON(offset >= PAGE_SIZE); BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET); - bytes = PAGE_SIZE - offset; + if (npo->copy_off == MAX_BUFFER_OFFSET) + meta = get_next_rx_buffer(queue, npo); + bytes = PAGE_SIZE - offset; if (bytes > size) bytes = size; - if (start_new_rx_buffer(npo->copy_off, - bytes, - *head, - XENVIF_RX_CB(skb)->full_coalesce)) { - /* - * Netfront requires there to be some data in the head - * buffer. - */ - BUG_ON(*head); - - meta = get_next_rx_buffer(queue, npo); - } - if (npo->copy_off + bytes > MAX_BUFFER_OFFSET) bytes = MAX_BUFFER_OFFSET - npo->copy_off; @@ -652,60 +596,15 @@ static void xenvif_rx_action(struct xenvif_queue *queue) while (xenvif_rx_ring_slots_available(queue, XEN_NETBK_RX_SLOTS_MAX) && (skb = xenvif_rx_dequeue(queue)) != NULL) { - RING_IDX max_slots_needed; RING_IDX old_req_cons; RING_IDX ring_slots_used; - int i; queue->last_rx_time = jiffies; - /* We need a cheap worse case estimate for the number of - * slots we'll use. - */ - - max_slots_needed = DIV_ROUND_UP(offset_in_page(skb->data) + - skb_headlen(skb), - PAGE_SIZE); - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - unsigned int size; - unsigned int offset; - - size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - offset = skb_shinfo(skb)->frags[i].page_offset; - - /* For a worse-case estimate we need to factor in - * the fragment page offset as this will affect the - * number of times xenvif_gop_frag_copy() will - * call start_new_rx_buffer(). - */ - max_slots_needed += DIV_ROUND_UP(offset + size, - PAGE_SIZE); - } - - /* To avoid the estimate becoming too pessimal for some - * frontends that limit posted rx requests, cap the estimate - * at MAX_SKB_FRAGS. In this case netback will fully coalesce - * the skb into the provided slots. - */ - if (max_slots_needed > MAX_SKB_FRAGS) { - max_slots_needed = MAX_SKB_FRAGS; - XENVIF_RX_CB(skb)->full_coalesce = true; - } else { - XENVIF_RX_CB(skb)->full_coalesce = false; - } - - /* We may need one more slot for GSO metadata */ - if (skb_is_gso(skb) && - (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 || - skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)) - max_slots_needed++; - old_req_cons = queue->rx.req_cons; XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo, queue); ring_slots_used = queue->rx.req_cons - old_req_cons; - BUG_ON(ring_slots_used > max_slots_needed); - __skb_queue_tail(&rxq, skb); } -- cgit v1.2.1 From 49216c1c170f07c138b043d67cd34c67d75a27cc Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 20 Jan 2015 12:02:20 +0530 Subject: cxgb4: Add debugfs entry to dump the contents of the flash Adds support to dump the contents of the flash in the adapter Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 3 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 73 +++++++++++++++++++++- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h | 3 + drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 28 ++++++++- drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 6 ++ 5 files changed, 110 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index e468f920892f..29c523294c0d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1008,7 +1008,10 @@ static inline int t4_memory_write(struct adapter *adap, int mtype, u32 addr, int t4_seeprom_wp(struct adapter *adapter, bool enable); int get_vpd_params(struct adapter *adapter, struct vpd_params *p); +int t4_read_flash(struct adapter *adapter, unsigned int addr, + unsigned int nwords, u32 *data, int byte_oriented); int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); +int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op); int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, const u8 *fw_data, unsigned int size, int force); unsigned int t4_flash_cfg_addr(struct adapter *adapter); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 6dabfe5ba44e..8b2e230beb99 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -434,6 +434,51 @@ static const struct file_operations devlog_fops = { .release = seq_release_private }; +static ssize_t flash_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + loff_t pos = *ppos; + loff_t avail = FILE_DATA(file)->i_size; + struct adapter *adap = file->private_data; + + if (pos < 0) + return -EINVAL; + if (pos >= avail) + return 0; + if (count > avail - pos) + count = avail - pos; + + while (count) { + size_t len; + int ret, ofst; + u8 data[256]; + + ofst = pos & 3; + len = min(count + ofst, sizeof(data)); + ret = t4_read_flash(adap, pos - ofst, (len + 3) / 4, + (u32 *)data, 1); + if (ret) + return ret; + + len -= ofst; + if (copy_to_user(buf, data + ofst, len)) + return -EFAULT; + + buf += len; + pos += len; + count -= len; + } + count = pos - *ppos; + *ppos = pos; + return count; +} + +static const struct file_operations flash_debugfs_fops = { + .owner = THIS_MODULE, + .open = mem_open, + .read = flash_read, +}; + static inline void tcamxy2valmask(u64 x, u64 y, u8 *addr, u64 *mask) { *mask = x | y; @@ -579,6 +624,21 @@ static const struct file_operations clip_tbl_debugfs_fops = { }; #endif +int mem_open(struct inode *inode, struct file *file) +{ + unsigned int mem; + struct adapter *adap; + + file->private_data = inode->i_private; + + mem = (uintptr_t)file->private_data & 0x3; + adap = file->private_data - mem; + + (void)t4_fwcache(adap, FW_PARAM_DEV_FWCACHE_FLUSH); + + return 0; +} + static ssize_t mem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -616,7 +676,6 @@ static ssize_t mem_read(struct file *file, char __user *buf, size_t count, *ppos = pos + count; return count; } - static const struct file_operations mem_debugfs_fops = { .owner = THIS_MODULE, .open = simple_open, @@ -624,6 +683,12 @@ static const struct file_operations mem_debugfs_fops = { .llseek = default_llseek, }; +static void set_debugfs_file_size(struct dentry *de, loff_t size) +{ + if (!IS_ERR(de) && de->d_inode) + de->d_inode->i_size = size; +} + static void add_debugfs_mem(struct adapter *adap, const char *name, unsigned int idx, unsigned int size_mb) { @@ -655,6 +720,7 @@ int t4_setup_debugfs(struct adapter *adap) { int i; u32 size; + struct dentry *de; static struct t4_debugfs_entry t4_debugfs_files[] = { { "cim_la", &cim_la_fops, S_IRUSR, 0 }, @@ -697,5 +763,10 @@ int t4_setup_debugfs(struct adapter *adap) EXT_MEM1_SIZE_G(size)); } } + + de = debugfs_create_file("flash", S_IRUSR, adap->debugfs_root, adap, + &flash_debugfs_fops); + set_debugfs_file_size(de, adap->params.sf_size); + return 0; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h index 70fcbc930826..e162c611e089 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h @@ -37,6 +37,8 @@ #include +#define FILE_DATA(_file) ((_file)->f_path.dentry->d_inode) + struct t4_debugfs_entry { const char *name; const struct file_operations *ops; @@ -60,5 +62,6 @@ int t4_setup_debugfs(struct adapter *adap); void add_debugfs_files(struct adapter *adap, struct t4_debugfs_entry *files, unsigned int nfiles); +int mem_open(struct inode *inode, struct file *file); #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 734d33e3f53b..73da6f548fad 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -835,8 +835,8 @@ static int flash_wait_op(struct adapter *adapter, int attempts, int delay) * (i.e., big-endian), otherwise as 32-bit words in the platform's * natural endianess. */ -static int t4_read_flash(struct adapter *adapter, unsigned int addr, - unsigned int nwords, u32 *data, int byte_oriented) +int t4_read_flash(struct adapter *adapter, unsigned int addr, + unsigned int nwords, u32 *data, int byte_oriented) { int ret; @@ -1239,6 +1239,30 @@ out: return ret; } +/** + * t4_fwcache - firmware cache operation + * @adap: the adapter + * @op : the operation (flush or flush and invalidate) + */ +int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op) +{ + struct fw_params_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = + cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) | + FW_CMD_REQUEST_F | FW_CMD_WRITE_F | + FW_PARAMS_CMD_PFN_V(adap->fn) | + FW_PARAMS_CMD_VFN_V(0)); + c.retval_len16 = cpu_to_be32(FW_LEN16(c)); + c.param[0].mnem = + cpu_to_be32(FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FWCACHE)); + c.param[0].val = (__force __be32)op; + + return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL); +} + #define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \ FW_PORT_CAP_ANEG) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index de8283324f1f..1e72cda5eb1a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -1062,6 +1062,7 @@ enum fw_params_param_dev { FW_PARAMS_PARAM_DEV_MAXORDIRD_QP = 0x13, /* max supported QP IRD/ORD */ FW_PARAMS_PARAM_DEV_MAXIRD_ADAPTER = 0x14, /* max supported adap IRD */ FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17, + FW_PARAMS_PARAM_DEV_FWCACHE = 0x18, }; /* @@ -1121,6 +1122,11 @@ enum fw_params_param_dmaq { FW_PARAMS_PARAM_DMAQ_EQ_DCBPRIO_ETH = 0x13, }; +enum fw_params_param_dev_fwcache { + FW_PARAM_DEV_FWCACHE_FLUSH = 0x00, + FW_PARAM_DEV_FWCACHE_FLUSHINV = 0x01, +}; + #define FW_PARAMS_MNEM_S 24 #define FW_PARAMS_MNEM_V(x) ((x) << FW_PARAMS_MNEM_S) -- cgit v1.2.1 From 688ea5fe7f57272af0e26e271892cead098ef934 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 20 Jan 2015 12:02:21 +0530 Subject: cxgb4: Add debugfs options to dump the rss key, config for PF, VF, etc Adds support to dump the rss table, rss_config, rss_key, rss_pf_config and rss_vf_config Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 10 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 407 +++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h | 18 + drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 141 +++++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 402 ++++++++++++++++++++ 5 files changed, 978 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 29c523294c0d..24fc162ee57a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1038,6 +1038,16 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, int start, int n, const u16 *rspq, unsigned int nrspq); int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, unsigned int flags); +int t4_read_rss(struct adapter *adapter, u16 *entries); +void t4_read_rss_key(struct adapter *adapter, u32 *key); +void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx); +void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, + u32 *valp); +void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, + u32 *vfl, u32 *vfh); +u32 t4_read_rss_pf_map(struct adapter *adapter); +u32 t4_read_rss_pf_mask(struct adapter *adapter); + int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 8b2e230beb99..714cc70b97cc 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "cxgb4.h" #include "t4_regs.h" @@ -624,6 +625,407 @@ static const struct file_operations clip_tbl_debugfs_fops = { }; #endif +/*RSS Table. + */ + +static int rss_show(struct seq_file *seq, void *v, int idx) +{ + u16 *entry = v; + + seq_printf(seq, "%4d: %4u %4u %4u %4u %4u %4u %4u %4u\n", + idx * 8, entry[0], entry[1], entry[2], entry[3], entry[4], + entry[5], entry[6], entry[7]); + return 0; +} + +static int rss_open(struct inode *inode, struct file *file) +{ + int ret; + struct seq_tab *p; + struct adapter *adap = inode->i_private; + + p = seq_open_tab(file, RSS_NENTRIES / 8, 8 * sizeof(u16), 0, rss_show); + if (!p) + return -ENOMEM; + + ret = t4_read_rss(adap, (u16 *)p->data); + if (ret) + seq_release_private(inode, file); + + return ret; +} + +static const struct file_operations rss_debugfs_fops = { + .owner = THIS_MODULE, + .open = rss_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +/* RSS Configuration. + */ + +/* Small utility function to return the strings "yes" or "no" if the supplied + * argument is non-zero. + */ +static const char *yesno(int x) +{ + static const char *yes = "yes"; + static const char *no = "no"; + + return x ? yes : no; +} + +static int rss_config_show(struct seq_file *seq, void *v) +{ + struct adapter *adapter = seq->private; + static const char * const keymode[] = { + "global", + "global and per-VF scramble", + "per-PF and per-VF scramble", + "per-VF and per-VF scramble", + }; + u32 rssconf; + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_A); + seq_printf(seq, "TP_RSS_CONFIG: %#x\n", rssconf); + seq_printf(seq, " Tnl4TupEnIpv6: %3s\n", yesno(rssconf & + TNL4TUPENIPV6_F)); + seq_printf(seq, " Tnl2TupEnIpv6: %3s\n", yesno(rssconf & + TNL2TUPENIPV6_F)); + seq_printf(seq, " Tnl4TupEnIpv4: %3s\n", yesno(rssconf & + TNL4TUPENIPV4_F)); + seq_printf(seq, " Tnl2TupEnIpv4: %3s\n", yesno(rssconf & + TNL2TUPENIPV4_F)); + seq_printf(seq, " TnlTcpSel: %3s\n", yesno(rssconf & TNLTCPSEL_F)); + seq_printf(seq, " TnlIp6Sel: %3s\n", yesno(rssconf & TNLIP6SEL_F)); + seq_printf(seq, " TnlVrtSel: %3s\n", yesno(rssconf & TNLVRTSEL_F)); + seq_printf(seq, " TnlMapEn: %3s\n", yesno(rssconf & TNLMAPEN_F)); + seq_printf(seq, " OfdHashSave: %3s\n", yesno(rssconf & + OFDHASHSAVE_F)); + seq_printf(seq, " OfdVrtSel: %3s\n", yesno(rssconf & OFDVRTSEL_F)); + seq_printf(seq, " OfdMapEn: %3s\n", yesno(rssconf & OFDMAPEN_F)); + seq_printf(seq, " OfdLkpEn: %3s\n", yesno(rssconf & OFDLKPEN_F)); + seq_printf(seq, " Syn4TupEnIpv6: %3s\n", yesno(rssconf & + SYN4TUPENIPV6_F)); + seq_printf(seq, " Syn2TupEnIpv6: %3s\n", yesno(rssconf & + SYN2TUPENIPV6_F)); + seq_printf(seq, " Syn4TupEnIpv4: %3s\n", yesno(rssconf & + SYN4TUPENIPV4_F)); + seq_printf(seq, " Syn2TupEnIpv4: %3s\n", yesno(rssconf & + SYN2TUPENIPV4_F)); + seq_printf(seq, " Syn4TupEnIpv6: %3s\n", yesno(rssconf & + SYN4TUPENIPV6_F)); + seq_printf(seq, " SynIp6Sel: %3s\n", yesno(rssconf & SYNIP6SEL_F)); + seq_printf(seq, " SynVrt6Sel: %3s\n", yesno(rssconf & SYNVRTSEL_F)); + seq_printf(seq, " SynMapEn: %3s\n", yesno(rssconf & SYNMAPEN_F)); + seq_printf(seq, " SynLkpEn: %3s\n", yesno(rssconf & SYNLKPEN_F)); + seq_printf(seq, " ChnEn: %3s\n", yesno(rssconf & + CHANNELENABLE_F)); + seq_printf(seq, " PrtEn: %3s\n", yesno(rssconf & + PORTENABLE_F)); + seq_printf(seq, " TnlAllLkp: %3s\n", yesno(rssconf & + TNLALLLOOKUP_F)); + seq_printf(seq, " VrtEn: %3s\n", yesno(rssconf & + VIRTENABLE_F)); + seq_printf(seq, " CngEn: %3s\n", yesno(rssconf & + CONGESTIONENABLE_F)); + seq_printf(seq, " HashToeplitz: %3s\n", yesno(rssconf & + HASHTOEPLITZ_F)); + seq_printf(seq, " Udp4En: %3s\n", yesno(rssconf & UDPENABLE_F)); + seq_printf(seq, " Disable: %3s\n", yesno(rssconf & DISABLE_F)); + + seq_puts(seq, "\n"); + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_TNL_A); + seq_printf(seq, "TP_RSS_CONFIG_TNL: %#x\n", rssconf); + seq_printf(seq, " MaskSize: %3d\n", MASKSIZE_G(rssconf)); + seq_printf(seq, " MaskFilter: %3d\n", MASKFILTER_G(rssconf)); + if (CHELSIO_CHIP_VERSION(adapter->params.chip) > CHELSIO_T5) { + seq_printf(seq, " HashAll: %3s\n", + yesno(rssconf & HASHALL_F)); + seq_printf(seq, " HashEth: %3s\n", + yesno(rssconf & HASHETH_F)); + } + seq_printf(seq, " UseWireCh: %3s\n", yesno(rssconf & USEWIRECH_F)); + + seq_puts(seq, "\n"); + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_OFD_A); + seq_printf(seq, "TP_RSS_CONFIG_OFD: %#x\n", rssconf); + seq_printf(seq, " MaskSize: %3d\n", MASKSIZE_G(rssconf)); + seq_printf(seq, " RRCplMapEn: %3s\n", yesno(rssconf & + RRCPLMAPEN_F)); + seq_printf(seq, " RRCplQueWidth: %3d\n", RRCPLQUEWIDTH_G(rssconf)); + + seq_puts(seq, "\n"); + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_SYN_A); + seq_printf(seq, "TP_RSS_CONFIG_SYN: %#x\n", rssconf); + seq_printf(seq, " MaskSize: %3d\n", MASKSIZE_G(rssconf)); + seq_printf(seq, " UseWireCh: %3s\n", yesno(rssconf & USEWIRECH_F)); + + seq_puts(seq, "\n"); + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_VRT_A); + seq_printf(seq, "TP_RSS_CONFIG_VRT: %#x\n", rssconf); + if (CHELSIO_CHIP_VERSION(adapter->params.chip) > CHELSIO_T5) { + seq_printf(seq, " KeyWrAddrX: %3d\n", + KEYWRADDRX_G(rssconf)); + seq_printf(seq, " KeyExtend: %3s\n", + yesno(rssconf & KEYEXTEND_F)); + } + seq_printf(seq, " VfRdRg: %3s\n", yesno(rssconf & VFRDRG_F)); + seq_printf(seq, " VfRdEn: %3s\n", yesno(rssconf & VFRDEN_F)); + seq_printf(seq, " VfPerrEn: %3s\n", yesno(rssconf & VFPERREN_F)); + seq_printf(seq, " KeyPerrEn: %3s\n", yesno(rssconf & KEYPERREN_F)); + seq_printf(seq, " DisVfVlan: %3s\n", yesno(rssconf & + DISABLEVLAN_F)); + seq_printf(seq, " EnUpSwt: %3s\n", yesno(rssconf & ENABLEUP0_F)); + seq_printf(seq, " HashDelay: %3d\n", HASHDELAY_G(rssconf)); + if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) + seq_printf(seq, " VfWrAddr: %3d\n", VFWRADDR_G(rssconf)); + seq_printf(seq, " KeyMode: %s\n", keymode[KEYMODE_G(rssconf)]); + seq_printf(seq, " VfWrEn: %3s\n", yesno(rssconf & VFWREN_F)); + seq_printf(seq, " KeyWrEn: %3s\n", yesno(rssconf & KEYWREN_F)); + seq_printf(seq, " KeyWrAddr: %3d\n", KEYWRADDR_G(rssconf)); + + seq_puts(seq, "\n"); + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_CNG_A); + seq_printf(seq, "TP_RSS_CONFIG_CNG: %#x\n", rssconf); + seq_printf(seq, " ChnCount3: %3s\n", yesno(rssconf & CHNCOUNT3_F)); + seq_printf(seq, " ChnCount2: %3s\n", yesno(rssconf & CHNCOUNT2_F)); + seq_printf(seq, " ChnCount1: %3s\n", yesno(rssconf & CHNCOUNT1_F)); + seq_printf(seq, " ChnCount0: %3s\n", yesno(rssconf & CHNCOUNT0_F)); + seq_printf(seq, " ChnUndFlow3: %3s\n", yesno(rssconf & + CHNUNDFLOW3_F)); + seq_printf(seq, " ChnUndFlow2: %3s\n", yesno(rssconf & + CHNUNDFLOW2_F)); + seq_printf(seq, " ChnUndFlow1: %3s\n", yesno(rssconf & + CHNUNDFLOW1_F)); + seq_printf(seq, " ChnUndFlow0: %3s\n", yesno(rssconf & + CHNUNDFLOW0_F)); + seq_printf(seq, " RstChn3: %3s\n", yesno(rssconf & RSTCHN3_F)); + seq_printf(seq, " RstChn2: %3s\n", yesno(rssconf & RSTCHN2_F)); + seq_printf(seq, " RstChn1: %3s\n", yesno(rssconf & RSTCHN1_F)); + seq_printf(seq, " RstChn0: %3s\n", yesno(rssconf & RSTCHN0_F)); + seq_printf(seq, " UpdVld: %3s\n", yesno(rssconf & UPDVLD_F)); + seq_printf(seq, " Xoff: %3s\n", yesno(rssconf & XOFF_F)); + seq_printf(seq, " UpdChn3: %3s\n", yesno(rssconf & UPDCHN3_F)); + seq_printf(seq, " UpdChn2: %3s\n", yesno(rssconf & UPDCHN2_F)); + seq_printf(seq, " UpdChn1: %3s\n", yesno(rssconf & UPDCHN1_F)); + seq_printf(seq, " UpdChn0: %3s\n", yesno(rssconf & UPDCHN0_F)); + seq_printf(seq, " Queue: %3d\n", QUEUE_G(rssconf)); + + return 0; +} + +DEFINE_SIMPLE_DEBUGFS_FILE(rss_config); + +/* RSS Secret Key. + */ + +static int rss_key_show(struct seq_file *seq, void *v) +{ + u32 key[10]; + + t4_read_rss_key(seq->private, key); + seq_printf(seq, "%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x\n", + key[9], key[8], key[7], key[6], key[5], key[4], key[3], + key[2], key[1], key[0]); + return 0; +} + +static int rss_key_open(struct inode *inode, struct file *file) +{ + return single_open(file, rss_key_show, inode->i_private); +} + +static ssize_t rss_key_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + int i, j; + u32 key[10]; + char s[100], *p; + struct adapter *adap = FILE_DATA(file)->i_private; + + if (count > sizeof(s) - 1) + return -EINVAL; + if (copy_from_user(s, buf, count)) + return -EFAULT; + for (i = count; i > 0 && isspace(s[i - 1]); i--) + ; + s[i] = '\0'; + + for (p = s, i = 9; i >= 0; i--) { + key[i] = 0; + for (j = 0; j < 8; j++, p++) { + if (!isxdigit(*p)) + return -EINVAL; + key[i] = (key[i] << 4) | hex2val(*p); + } + } + + t4_write_rss_key(adap, key, -1); + return count; +} + +static const struct file_operations rss_key_debugfs_fops = { + .owner = THIS_MODULE, + .open = rss_key_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = rss_key_write +}; + +/* PF RSS Configuration. + */ + +struct rss_pf_conf { + u32 rss_pf_map; + u32 rss_pf_mask; + u32 rss_pf_config; +}; + +static int rss_pf_config_show(struct seq_file *seq, void *v, int idx) +{ + struct rss_pf_conf *pfconf; + + if (v == SEQ_START_TOKEN) { + /* use the 0th entry to dump the PF Map Index Size */ + pfconf = seq->private + offsetof(struct seq_tab, data); + seq_printf(seq, "PF Map Index Size = %d\n\n", + LKPIDXSIZE_G(pfconf->rss_pf_map)); + + seq_puts(seq, " RSS PF VF Hash Tuple Enable Default\n"); + seq_puts(seq, " Enable IPF Mask Mask IPv6 IPv4 UDP Queue\n"); + seq_puts(seq, " PF Map Chn Prt Map Size Size Four Two Four Two Four Ch1 Ch0\n"); + } else { + #define G_PFnLKPIDX(map, n) \ + (((map) >> PF1LKPIDX_S*(n)) & PF0LKPIDX_M) + #define G_PFnMSKSIZE(mask, n) \ + (((mask) >> PF1MSKSIZE_S*(n)) & PF1MSKSIZE_M) + + pfconf = v; + seq_printf(seq, "%3d %3s %3s %3s %3d %3d %3d %3s %3s %3s %3s %3s %3d %3d\n", + idx, + yesno(pfconf->rss_pf_config & MAPENABLE_F), + yesno(pfconf->rss_pf_config & CHNENABLE_F), + yesno(pfconf->rss_pf_config & PRTENABLE_F), + G_PFnLKPIDX(pfconf->rss_pf_map, idx), + G_PFnMSKSIZE(pfconf->rss_pf_mask, idx), + IVFWIDTH_G(pfconf->rss_pf_config), + yesno(pfconf->rss_pf_config & IP6FOURTUPEN_F), + yesno(pfconf->rss_pf_config & IP6TWOTUPEN_F), + yesno(pfconf->rss_pf_config & IP4FOURTUPEN_F), + yesno(pfconf->rss_pf_config & IP4TWOTUPEN_F), + yesno(pfconf->rss_pf_config & UDPFOURTUPEN_F), + CH1DEFAULTQUEUE_G(pfconf->rss_pf_config), + CH0DEFAULTQUEUE_G(pfconf->rss_pf_config)); + + #undef G_PFnLKPIDX + #undef G_PFnMSKSIZE + } + return 0; +} + +static int rss_pf_config_open(struct inode *inode, struct file *file) +{ + struct adapter *adapter = inode->i_private; + struct seq_tab *p; + u32 rss_pf_map, rss_pf_mask; + struct rss_pf_conf *pfconf; + int pf; + + p = seq_open_tab(file, 8, sizeof(*pfconf), 1, rss_pf_config_show); + if (!p) + return -ENOMEM; + + pfconf = (struct rss_pf_conf *)p->data; + rss_pf_map = t4_read_rss_pf_map(adapter); + rss_pf_mask = t4_read_rss_pf_mask(adapter); + for (pf = 0; pf < 8; pf++) { + pfconf[pf].rss_pf_map = rss_pf_map; + pfconf[pf].rss_pf_mask = rss_pf_mask; + t4_read_rss_pf_config(adapter, pf, &pfconf[pf].rss_pf_config); + } + return 0; +} + +static const struct file_operations rss_pf_config_debugfs_fops = { + .owner = THIS_MODULE, + .open = rss_pf_config_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +/* VF RSS Configuration. + */ + +struct rss_vf_conf { + u32 rss_vf_vfl; + u32 rss_vf_vfh; +}; + +static int rss_vf_config_show(struct seq_file *seq, void *v, int idx) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, " RSS Hash Tuple Enable\n"); + seq_puts(seq, " Enable IVF Dis Enb IPv6 IPv4 UDP Def Secret Key\n"); + seq_puts(seq, " VF Chn Prt Map VLAN uP Four Two Four Two Four Que Idx Hash\n"); + } else { + struct rss_vf_conf *vfconf = v; + + seq_printf(seq, "%3d %3s %3s %3d %3s %3s %3s %3s %3s %3s %3s %4d %3d %#10x\n", + idx, + yesno(vfconf->rss_vf_vfh & VFCHNEN_F), + yesno(vfconf->rss_vf_vfh & VFPRTEN_F), + VFLKPIDX_G(vfconf->rss_vf_vfh), + yesno(vfconf->rss_vf_vfh & VFVLNEX_F), + yesno(vfconf->rss_vf_vfh & VFUPEN_F), + yesno(vfconf->rss_vf_vfh & VFIP4FOURTUPEN_F), + yesno(vfconf->rss_vf_vfh & VFIP6TWOTUPEN_F), + yesno(vfconf->rss_vf_vfh & VFIP4FOURTUPEN_F), + yesno(vfconf->rss_vf_vfh & VFIP4TWOTUPEN_F), + yesno(vfconf->rss_vf_vfh & ENABLEUDPHASH_F), + DEFAULTQUEUE_G(vfconf->rss_vf_vfh), + KEYINDEX_G(vfconf->rss_vf_vfh), + vfconf->rss_vf_vfl); + } + return 0; +} + +static int rss_vf_config_open(struct inode *inode, struct file *file) +{ + struct adapter *adapter = inode->i_private; + struct seq_tab *p; + struct rss_vf_conf *vfconf; + int vf; + + p = seq_open_tab(file, 128, sizeof(*vfconf), 1, rss_vf_config_show); + if (!p) + return -ENOMEM; + + vfconf = (struct rss_vf_conf *)p->data; + for (vf = 0; vf < 128; vf++) { + t4_read_rss_vf_config(adapter, vf, &vfconf[vf].rss_vf_vfl, + &vfconf[vf].rss_vf_vfh); + } + return 0; +} + +static const struct file_operations rss_vf_config_debugfs_fops = { + .owner = THIS_MODULE, + .open = rss_vf_config_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + int mem_open(struct inode *inode, struct file *file) { unsigned int mem; @@ -728,6 +1130,11 @@ int t4_setup_debugfs(struct adapter *adap) { "devlog", &devlog_fops, S_IRUSR, 0 }, { "l2t", &t4_l2t_fops, S_IRUSR, 0}, { "mps_tcam", &mps_tcam_debugfs_fops, S_IRUSR, 0 }, + { "rss", &rss_debugfs_fops, S_IRUSR, 0 }, + { "rss_config", &rss_config_debugfs_fops, S_IRUSR, 0 }, + { "rss_key", &rss_key_debugfs_fops, S_IRUSR, 0 }, + { "rss_pf_config", &rss_pf_config_debugfs_fops, S_IRUSR, 0 }, + { "rss_vf_config", &rss_vf_config_debugfs_fops, S_IRUSR, 0 }, #if IS_ENABLED(CONFIG_IPV6) { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 }, #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h index e162c611e089..b63cfee2d963 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h @@ -39,6 +39,19 @@ #define FILE_DATA(_file) ((_file)->f_path.dentry->d_inode) +#define DEFINE_SIMPLE_DEBUGFS_FILE(name) \ +static int name##_open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, name##_show, inode->i_private); \ +} \ +static const struct file_operations name##_debugfs_fops = { \ + .owner = THIS_MODULE, \ + .open = name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release \ +} + struct t4_debugfs_entry { const char *name; const struct file_operations *ops; @@ -54,6 +67,11 @@ struct seq_tab { char data[0]; /* the table data */ }; +static inline unsigned int hex2val(char c) +{ + return isdigit(c) ? c - '0' : tolower(c) - 'a' + 10; +} + struct seq_tab *seq_open_tab(struct file *f, unsigned int rows, unsigned int width, unsigned int have_header, int (*show)(struct seq_file *seq, void *v, int i)); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 73da6f548fad..8f99878a4913 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -2200,6 +2200,147 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); } +/* Read an RSS table row */ +static int rd_rss_row(struct adapter *adap, int row, u32 *val) +{ + t4_write_reg(adap, TP_RSS_LKP_TABLE_A, 0xfff00000 | row); + return t4_wait_op_done_val(adap, TP_RSS_LKP_TABLE_A, LKPTBLROWVLD_F, 1, + 5, 0, val); +} + +/** + * t4_read_rss - read the contents of the RSS mapping table + * @adapter: the adapter + * @map: holds the contents of the RSS mapping table + * + * Reads the contents of the RSS hash->queue mapping table. + */ +int t4_read_rss(struct adapter *adapter, u16 *map) +{ + u32 val; + int i, ret; + + for (i = 0; i < RSS_NENTRIES / 2; ++i) { + ret = rd_rss_row(adapter, i, &val); + if (ret) + return ret; + *map++ = LKPTBLQUEUE0_G(val); + *map++ = LKPTBLQUEUE1_G(val); + } + return 0; +} + +/** + * t4_read_rss_key - read the global RSS key + * @adap: the adapter + * @key: 10-entry array holding the 320-bit RSS key + * + * Reads the global 320-bit RSS key. + */ +void t4_read_rss_key(struct adapter *adap, u32 *key) +{ + t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10, + TP_RSS_SECRET_KEY0_A); +} + +/** + * t4_write_rss_key - program one of the RSS keys + * @adap: the adapter + * @key: 10-entry array holding the 320-bit RSS key + * @idx: which RSS key to write + * + * Writes one of the RSS keys with the given 320-bit value. If @idx is + * 0..15 the corresponding entry in the RSS key table is written, + * otherwise the global RSS key is written. + */ +void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx) +{ + t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10, + TP_RSS_SECRET_KEY0_A); + if (idx >= 0 && idx < 16) + t4_write_reg(adap, TP_RSS_CONFIG_VRT_A, + KEYWRADDR_V(idx) | KEYWREN_F); +} + +/** + * t4_read_rss_pf_config - read PF RSS Configuration Table + * @adapter: the adapter + * @index: the entry in the PF RSS table to read + * @valp: where to store the returned value + * + * Reads the PF RSS Configuration Table at the specified index and returns + * the value found there. + */ +void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, + u32 *valp) +{ + t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + valp, 1, TP_RSS_PF0_CONFIG_A + index); +} + +/** + * t4_read_rss_vf_config - read VF RSS Configuration Table + * @adapter: the adapter + * @index: the entry in the VF RSS table to read + * @vfl: where to store the returned VFL + * @vfh: where to store the returned VFH + * + * Reads the VF RSS Configuration Table at the specified index and returns + * the (VFL, VFH) values found there. + */ +void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, + u32 *vfl, u32 *vfh) +{ + u32 vrt, mask, data; + + mask = VFWRADDR_V(VFWRADDR_M); + data = VFWRADDR_V(index); + + /* Request that the index'th VF Table values be read into VFL/VFH. + */ + vrt = t4_read_reg(adapter, TP_RSS_CONFIG_VRT_A); + vrt &= ~(VFRDRG_F | VFWREN_F | KEYWREN_F | mask); + vrt |= data | VFRDEN_F; + t4_write_reg(adapter, TP_RSS_CONFIG_VRT_A, vrt); + + /* Grab the VFL/VFH values ... + */ + t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + vfl, 1, TP_RSS_VFL_CONFIG_A); + t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + vfh, 1, TP_RSS_VFH_CONFIG_A); +} + +/** + * t4_read_rss_pf_map - read PF RSS Map + * @adapter: the adapter + * + * Reads the PF RSS Map register and returns its value. + */ +u32 t4_read_rss_pf_map(struct adapter *adapter) +{ + u32 pfmap; + + t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + &pfmap, 1, TP_RSS_PF_MAP_A); + return pfmap; +} + +/** + * t4_read_rss_pf_mask - read PF RSS Mask + * @adapter: the adapter + * + * Reads the PF RSS Mask register and returns its value. + */ +u32 t4_read_rss_pf_mask(struct adapter *adapter) +{ + u32 pfmask; + + t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + &pfmask, 1, TP_RSS_PF_MSK_A); + return pfmask; +} + /** * t4_tp_get_tcp_stats - read TP's TCP MIB counters * @adap: the adapter diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 7ce55f9be9d4..e036b563bf3c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1678,6 +1678,408 @@ #define QUEUENUMBER_S 0 #define QUEUENUMBER_V(x) ((x) << QUEUENUMBER_S) +#define TP_RSS_CONFIG_A 0x7df0 + +#define TNL4TUPENIPV6_S 31 +#define TNL4TUPENIPV6_V(x) ((x) << TNL4TUPENIPV6_S) +#define TNL4TUPENIPV6_F TNL4TUPENIPV6_V(1U) + +#define TNL2TUPENIPV6_S 30 +#define TNL2TUPENIPV6_V(x) ((x) << TNL2TUPENIPV6_S) +#define TNL2TUPENIPV6_F TNL2TUPENIPV6_V(1U) + +#define TNL4TUPENIPV4_S 29 +#define TNL4TUPENIPV4_V(x) ((x) << TNL4TUPENIPV4_S) +#define TNL4TUPENIPV4_F TNL4TUPENIPV4_V(1U) + +#define TNL2TUPENIPV4_S 28 +#define TNL2TUPENIPV4_V(x) ((x) << TNL2TUPENIPV4_S) +#define TNL2TUPENIPV4_F TNL2TUPENIPV4_V(1U) + +#define TNLTCPSEL_S 27 +#define TNLTCPSEL_V(x) ((x) << TNLTCPSEL_S) +#define TNLTCPSEL_F TNLTCPSEL_V(1U) + +#define TNLIP6SEL_S 26 +#define TNLIP6SEL_V(x) ((x) << TNLIP6SEL_S) +#define TNLIP6SEL_F TNLIP6SEL_V(1U) + +#define TNLVRTSEL_S 25 +#define TNLVRTSEL_V(x) ((x) << TNLVRTSEL_S) +#define TNLVRTSEL_F TNLVRTSEL_V(1U) + +#define TNLMAPEN_S 24 +#define TNLMAPEN_V(x) ((x) << TNLMAPEN_S) +#define TNLMAPEN_F TNLMAPEN_V(1U) + +#define OFDHASHSAVE_S 19 +#define OFDHASHSAVE_V(x) ((x) << OFDHASHSAVE_S) +#define OFDHASHSAVE_F OFDHASHSAVE_V(1U) + +#define OFDVRTSEL_S 18 +#define OFDVRTSEL_V(x) ((x) << OFDVRTSEL_S) +#define OFDVRTSEL_F OFDVRTSEL_V(1U) + +#define OFDMAPEN_S 17 +#define OFDMAPEN_V(x) ((x) << OFDMAPEN_S) +#define OFDMAPEN_F OFDMAPEN_V(1U) + +#define OFDLKPEN_S 16 +#define OFDLKPEN_V(x) ((x) << OFDLKPEN_S) +#define OFDLKPEN_F OFDLKPEN_V(1U) + +#define SYN4TUPENIPV6_S 15 +#define SYN4TUPENIPV6_V(x) ((x) << SYN4TUPENIPV6_S) +#define SYN4TUPENIPV6_F SYN4TUPENIPV6_V(1U) + +#define SYN2TUPENIPV6_S 14 +#define SYN2TUPENIPV6_V(x) ((x) << SYN2TUPENIPV6_S) +#define SYN2TUPENIPV6_F SYN2TUPENIPV6_V(1U) + +#define SYN4TUPENIPV4_S 13 +#define SYN4TUPENIPV4_V(x) ((x) << SYN4TUPENIPV4_S) +#define SYN4TUPENIPV4_F SYN4TUPENIPV4_V(1U) + +#define SYN2TUPENIPV4_S 12 +#define SYN2TUPENIPV4_V(x) ((x) << SYN2TUPENIPV4_S) +#define SYN2TUPENIPV4_F SYN2TUPENIPV4_V(1U) + +#define SYNIP6SEL_S 11 +#define SYNIP6SEL_V(x) ((x) << SYNIP6SEL_S) +#define SYNIP6SEL_F SYNIP6SEL_V(1U) + +#define SYNVRTSEL_S 10 +#define SYNVRTSEL_V(x) ((x) << SYNVRTSEL_S) +#define SYNVRTSEL_F SYNVRTSEL_V(1U) + +#define SYNMAPEN_S 9 +#define SYNMAPEN_V(x) ((x) << SYNMAPEN_S) +#define SYNMAPEN_F SYNMAPEN_V(1U) + +#define SYNLKPEN_S 8 +#define SYNLKPEN_V(x) ((x) << SYNLKPEN_S) +#define SYNLKPEN_F SYNLKPEN_V(1U) + +#define CHANNELENABLE_S 7 +#define CHANNELENABLE_V(x) ((x) << CHANNELENABLE_S) +#define CHANNELENABLE_F CHANNELENABLE_V(1U) + +#define PORTENABLE_S 6 +#define PORTENABLE_V(x) ((x) << PORTENABLE_S) +#define PORTENABLE_F PORTENABLE_V(1U) + +#define TNLALLLOOKUP_S 5 +#define TNLALLLOOKUP_V(x) ((x) << TNLALLLOOKUP_S) +#define TNLALLLOOKUP_F TNLALLLOOKUP_V(1U) + +#define VIRTENABLE_S 4 +#define VIRTENABLE_V(x) ((x) << VIRTENABLE_S) +#define VIRTENABLE_F VIRTENABLE_V(1U) + +#define CONGESTIONENABLE_S 3 +#define CONGESTIONENABLE_V(x) ((x) << CONGESTIONENABLE_S) +#define CONGESTIONENABLE_F CONGESTIONENABLE_V(1U) + +#define HASHTOEPLITZ_S 2 +#define HASHTOEPLITZ_V(x) ((x) << HASHTOEPLITZ_S) +#define HASHTOEPLITZ_F HASHTOEPLITZ_V(1U) + +#define UDPENABLE_S 1 +#define UDPENABLE_V(x) ((x) << UDPENABLE_S) +#define UDPENABLE_F UDPENABLE_V(1U) + +#define DISABLE_S 0 +#define DISABLE_V(x) ((x) << DISABLE_S) +#define DISABLE_F DISABLE_V(1U) + +#define TP_RSS_CONFIG_TNL_A 0x7df4 + +#define MASKSIZE_S 28 +#define MASKSIZE_M 0xfU +#define MASKSIZE_V(x) ((x) << MASKSIZE_S) +#define MASKSIZE_G(x) (((x) >> MASKSIZE_S) & MASKSIZE_M) + +#define MASKFILTER_S 16 +#define MASKFILTER_M 0x7ffU +#define MASKFILTER_V(x) ((x) << MASKFILTER_S) +#define MASKFILTER_G(x) (((x) >> MASKFILTER_S) & MASKFILTER_M) + +#define USEWIRECH_S 0 +#define USEWIRECH_V(x) ((x) << USEWIRECH_S) +#define USEWIRECH_F USEWIRECH_V(1U) + +#define HASHALL_S 2 +#define HASHALL_V(x) ((x) << HASHALL_S) +#define HASHALL_F HASHALL_V(1U) + +#define HASHETH_S 1 +#define HASHETH_V(x) ((x) << HASHETH_S) +#define HASHETH_F HASHETH_V(1U) + +#define TP_RSS_CONFIG_OFD_A 0x7df8 + +#define RRCPLMAPEN_S 20 +#define RRCPLMAPEN_V(x) ((x) << RRCPLMAPEN_S) +#define RRCPLMAPEN_F RRCPLMAPEN_V(1U) + +#define RRCPLQUEWIDTH_S 16 +#define RRCPLQUEWIDTH_M 0xfU +#define RRCPLQUEWIDTH_V(x) ((x) << RRCPLQUEWIDTH_S) +#define RRCPLQUEWIDTH_G(x) (((x) >> RRCPLQUEWIDTH_S) & RRCPLQUEWIDTH_M) + +#define TP_RSS_CONFIG_SYN_A 0x7dfc +#define TP_RSS_CONFIG_VRT_A 0x7e00 + +#define VFRDRG_S 25 +#define VFRDRG_V(x) ((x) << VFRDRG_S) +#define VFRDRG_F VFRDRG_V(1U) + +#define VFRDEN_S 24 +#define VFRDEN_V(x) ((x) << VFRDEN_S) +#define VFRDEN_F VFRDEN_V(1U) + +#define VFPERREN_S 23 +#define VFPERREN_V(x) ((x) << VFPERREN_S) +#define VFPERREN_F VFPERREN_V(1U) + +#define KEYPERREN_S 22 +#define KEYPERREN_V(x) ((x) << KEYPERREN_S) +#define KEYPERREN_F KEYPERREN_V(1U) + +#define DISABLEVLAN_S 21 +#define DISABLEVLAN_V(x) ((x) << DISABLEVLAN_S) +#define DISABLEVLAN_F DISABLEVLAN_V(1U) + +#define ENABLEUP0_S 20 +#define ENABLEUP0_V(x) ((x) << ENABLEUP0_S) +#define ENABLEUP0_F ENABLEUP0_V(1U) + +#define HASHDELAY_S 16 +#define HASHDELAY_M 0xfU +#define HASHDELAY_V(x) ((x) << HASHDELAY_S) +#define HASHDELAY_G(x) (((x) >> HASHDELAY_S) & HASHDELAY_M) + +#define VFWRADDR_S 8 +#define VFWRADDR_M 0x7fU +#define VFWRADDR_V(x) ((x) << VFWRADDR_S) +#define VFWRADDR_G(x) (((x) >> VFWRADDR_S) & VFWRADDR_M) + +#define KEYMODE_S 6 +#define KEYMODE_M 0x3U +#define KEYMODE_V(x) ((x) << KEYMODE_S) +#define KEYMODE_G(x) (((x) >> KEYMODE_S) & KEYMODE_M) + +#define VFWREN_S 5 +#define VFWREN_V(x) ((x) << VFWREN_S) +#define VFWREN_F VFWREN_V(1U) + +#define KEYWREN_S 4 +#define KEYWREN_V(x) ((x) << KEYWREN_S) +#define KEYWREN_F KEYWREN_V(1U) + +#define KEYWRADDR_S 0 +#define KEYWRADDR_M 0xfU +#define KEYWRADDR_V(x) ((x) << KEYWRADDR_S) +#define KEYWRADDR_G(x) (((x) >> KEYWRADDR_S) & KEYWRADDR_M) + +#define KEYWRADDRX_S 30 +#define KEYWRADDRX_M 0x3U +#define KEYWRADDRX_V(x) ((x) << KEYWRADDRX_S) +#define KEYWRADDRX_G(x) (((x) >> KEYWRADDRX_S) & KEYWRADDRX_M) + +#define KEYEXTEND_S 26 +#define KEYEXTEND_V(x) ((x) << KEYEXTEND_S) +#define KEYEXTEND_F KEYEXTEND_V(1U) + +#define LKPIDXSIZE_S 24 +#define LKPIDXSIZE_M 0x3U +#define LKPIDXSIZE_V(x) ((x) << LKPIDXSIZE_S) +#define LKPIDXSIZE_G(x) (((x) >> LKPIDXSIZE_S) & LKPIDXSIZE_M) + +#define TP_RSS_VFL_CONFIG_A 0x3a +#define TP_RSS_VFH_CONFIG_A 0x3b + +#define ENABLEUDPHASH_S 31 +#define ENABLEUDPHASH_V(x) ((x) << ENABLEUDPHASH_S) +#define ENABLEUDPHASH_F ENABLEUDPHASH_V(1U) + +#define VFUPEN_S 30 +#define VFUPEN_V(x) ((x) << VFUPEN_S) +#define VFUPEN_F VFUPEN_V(1U) + +#define VFVLNEX_S 28 +#define VFVLNEX_V(x) ((x) << VFVLNEX_S) +#define VFVLNEX_F VFVLNEX_V(1U) + +#define VFPRTEN_S 27 +#define VFPRTEN_V(x) ((x) << VFPRTEN_S) +#define VFPRTEN_F VFPRTEN_V(1U) + +#define VFCHNEN_S 26 +#define VFCHNEN_V(x) ((x) << VFCHNEN_S) +#define VFCHNEN_F VFCHNEN_V(1U) + +#define DEFAULTQUEUE_S 16 +#define DEFAULTQUEUE_M 0x3ffU +#define DEFAULTQUEUE_G(x) (((x) >> DEFAULTQUEUE_S) & DEFAULTQUEUE_M) + +#define VFIP6TWOTUPEN_S 6 +#define VFIP6TWOTUPEN_V(x) ((x) << VFIP6TWOTUPEN_S) +#define VFIP6TWOTUPEN_F VFIP6TWOTUPEN_V(1U) + +#define VFIP4FOURTUPEN_S 5 +#define VFIP4FOURTUPEN_V(x) ((x) << VFIP4FOURTUPEN_S) +#define VFIP4FOURTUPEN_F VFIP4FOURTUPEN_V(1U) + +#define VFIP4TWOTUPEN_S 4 +#define VFIP4TWOTUPEN_V(x) ((x) << VFIP4TWOTUPEN_S) +#define VFIP4TWOTUPEN_F VFIP4TWOTUPEN_V(1U) + +#define KEYINDEX_S 0 +#define KEYINDEX_M 0xfU +#define KEYINDEX_G(x) (((x) >> KEYINDEX_S) & KEYINDEX_M) + +#define MAPENABLE_S 31 +#define MAPENABLE_V(x) ((x) << MAPENABLE_S) +#define MAPENABLE_F MAPENABLE_V(1U) + +#define CHNENABLE_S 30 +#define CHNENABLE_V(x) ((x) << CHNENABLE_S) +#define CHNENABLE_F CHNENABLE_V(1U) + +#define PRTENABLE_S 29 +#define PRTENABLE_V(x) ((x) << PRTENABLE_S) +#define PRTENABLE_F PRTENABLE_V(1U) + +#define UDPFOURTUPEN_S 28 +#define UDPFOURTUPEN_V(x) ((x) << UDPFOURTUPEN_S) +#define UDPFOURTUPEN_F UDPFOURTUPEN_V(1U) + +#define IP6FOURTUPEN_S 27 +#define IP6FOURTUPEN_V(x) ((x) << IP6FOURTUPEN_S) +#define IP6FOURTUPEN_F IP6FOURTUPEN_V(1U) + +#define IP6TWOTUPEN_S 26 +#define IP6TWOTUPEN_V(x) ((x) << IP6TWOTUPEN_S) +#define IP6TWOTUPEN_F IP6TWOTUPEN_V(1U) + +#define IP4FOURTUPEN_S 25 +#define IP4FOURTUPEN_V(x) ((x) << IP4FOURTUPEN_S) +#define IP4FOURTUPEN_F IP4FOURTUPEN_V(1U) + +#define IP4TWOTUPEN_S 24 +#define IP4TWOTUPEN_V(x) ((x) << IP4TWOTUPEN_S) +#define IP4TWOTUPEN_F IP4TWOTUPEN_V(1U) + +#define IVFWIDTH_S 20 +#define IVFWIDTH_M 0xfU +#define IVFWIDTH_V(x) ((x) << IVFWIDTH_S) +#define IVFWIDTH_G(x) (((x) >> IVFWIDTH_S) & IVFWIDTH_M) + +#define CH1DEFAULTQUEUE_S 10 +#define CH1DEFAULTQUEUE_M 0x3ffU +#define CH1DEFAULTQUEUE_V(x) ((x) << CH1DEFAULTQUEUE_S) +#define CH1DEFAULTQUEUE_G(x) (((x) >> CH1DEFAULTQUEUE_S) & CH1DEFAULTQUEUE_M) + +#define CH0DEFAULTQUEUE_S 0 +#define CH0DEFAULTQUEUE_M 0x3ffU +#define CH0DEFAULTQUEUE_V(x) ((x) << CH0DEFAULTQUEUE_S) +#define CH0DEFAULTQUEUE_G(x) (((x) >> CH0DEFAULTQUEUE_S) & CH0DEFAULTQUEUE_M) + +#define VFLKPIDX_S 8 +#define VFLKPIDX_M 0xffU +#define VFLKPIDX_G(x) (((x) >> VFLKPIDX_S) & VFLKPIDX_M) + +#define TP_RSS_CONFIG_CNG_A 0x7e04 +#define TP_RSS_SECRET_KEY0_A 0x40 +#define TP_RSS_PF0_CONFIG_A 0x30 +#define TP_RSS_PF_MAP_A 0x38 +#define TP_RSS_PF_MSK_A 0x39 + +#define PF1LKPIDX_S 3 + +#define PF0LKPIDX_M 0x7U + +#define PF1MSKSIZE_S 4 +#define PF1MSKSIZE_M 0xfU + +#define CHNCOUNT3_S 31 +#define CHNCOUNT3_V(x) ((x) << CHNCOUNT3_S) +#define CHNCOUNT3_F CHNCOUNT3_V(1U) + +#define CHNCOUNT2_S 30 +#define CHNCOUNT2_V(x) ((x) << CHNCOUNT2_S) +#define CHNCOUNT2_F CHNCOUNT2_V(1U) + +#define CHNCOUNT1_S 29 +#define CHNCOUNT1_V(x) ((x) << CHNCOUNT1_S) +#define CHNCOUNT1_F CHNCOUNT1_V(1U) + +#define CHNCOUNT0_S 28 +#define CHNCOUNT0_V(x) ((x) << CHNCOUNT0_S) +#define CHNCOUNT0_F CHNCOUNT0_V(1U) + +#define CHNUNDFLOW3_S 27 +#define CHNUNDFLOW3_V(x) ((x) << CHNUNDFLOW3_S) +#define CHNUNDFLOW3_F CHNUNDFLOW3_V(1U) + +#define CHNUNDFLOW2_S 26 +#define CHNUNDFLOW2_V(x) ((x) << CHNUNDFLOW2_S) +#define CHNUNDFLOW2_F CHNUNDFLOW2_V(1U) + +#define CHNUNDFLOW1_S 25 +#define CHNUNDFLOW1_V(x) ((x) << CHNUNDFLOW1_S) +#define CHNUNDFLOW1_F CHNUNDFLOW1_V(1U) + +#define CHNUNDFLOW0_S 24 +#define CHNUNDFLOW0_V(x) ((x) << CHNUNDFLOW0_S) +#define CHNUNDFLOW0_F CHNUNDFLOW0_V(1U) + +#define RSTCHN3_S 19 +#define RSTCHN3_V(x) ((x) << RSTCHN3_S) +#define RSTCHN3_F RSTCHN3_V(1U) + +#define RSTCHN2_S 18 +#define RSTCHN2_V(x) ((x) << RSTCHN2_S) +#define RSTCHN2_F RSTCHN2_V(1U) + +#define RSTCHN1_S 17 +#define RSTCHN1_V(x) ((x) << RSTCHN1_S) +#define RSTCHN1_F RSTCHN1_V(1U) + +#define RSTCHN0_S 16 +#define RSTCHN0_V(x) ((x) << RSTCHN0_S) +#define RSTCHN0_F RSTCHN0_V(1U) + +#define UPDVLD_S 15 +#define UPDVLD_V(x) ((x) << UPDVLD_S) +#define UPDVLD_F UPDVLD_V(1U) + +#define XOFF_S 14 +#define XOFF_V(x) ((x) << XOFF_S) +#define XOFF_F XOFF_V(1U) + +#define UPDCHN3_S 13 +#define UPDCHN3_V(x) ((x) << UPDCHN3_S) +#define UPDCHN3_F UPDCHN3_V(1U) + +#define UPDCHN2_S 12 +#define UPDCHN2_V(x) ((x) << UPDCHN2_S) +#define UPDCHN2_F UPDCHN2_V(1U) + +#define UPDCHN1_S 11 +#define UPDCHN1_V(x) ((x) << UPDCHN1_S) +#define UPDCHN1_F UPDCHN1_V(1U) + +#define UPDCHN0_S 10 +#define UPDCHN0_V(x) ((x) << UPDCHN0_S) +#define UPDCHN0_F UPDCHN0_V(1U) + +#define QUEUE_S 0 +#define QUEUE_M 0x3ffU +#define QUEUE_V(x) ((x) << QUEUE_S) +#define QUEUE_G(x) (((x) >> QUEUE_S) & QUEUE_M) + #define MPS_TRC_INT_CAUSE_A 0x985c #define MISCPERR_S 8 -- cgit v1.2.1 From 4cc8bfb912d29f596c1ae9ea9414d768896ba28f Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Tue, 20 Jan 2015 07:09:37 +0000 Subject: net: stmmac: dwmac-rk: Don't set the regulator voltage for phy from the driver As these settings can be directly expressed from devicetree for both fixed regulators and pmic-integrated regulators, it is more standard to set them from dts and let the regulator framework use the right voltage informations when it is used in the driver. Signed-off-by: Romain Perier Tested-by: Heiko Stuebner Reviewed-by: Heiko Stuebner Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 35f9b86bc9e5..06e163706c04 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -303,7 +303,6 @@ static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable) } else { if (enable) { if (!regulator_is_enabled(ldo)) { - regulator_set_voltage(ldo, 3300000, 3300000); ret = regulator_enable(ldo); if (ret != 0) dev_err(dev, "%s: fail to enable %s\n", -- cgit v1.2.1 From 2e12f536635f88454fe6344cf9dad092ad7c2d77 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Tue, 20 Jan 2015 07:09:39 +0000 Subject: net: stmmac: dwmac-rk: Use standard devicetree property for phy regulator Currently, dwmac-rk uses a custom propety "phy_regulator" to get the name of the right regulator to use to power on or power off the phy. This commit converts the driver to use phy-supply devicetree property and the corresponding API, it cleans the code a bit and make it simpler to maintain. This also replaces the property phy_regulator by the standard property phy-supply in rk3288-evb-rk808.dts. Signed-off-by: Romain Perier Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 63 +++++++++----------------- 1 file changed, 21 insertions(+), 42 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 06e163706c04..6249a4ec08f0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -32,7 +32,7 @@ struct rk_priv_data { struct platform_device *pdev; int phy_iface; - char regulator[32]; + struct regulator *regulator; bool clk_enabled; bool clock_input; @@ -287,46 +287,25 @@ static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable) static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable) { - struct regulator *ldo; - char *ldostr = bsp_priv->regulator; + struct regulator *ldo = bsp_priv->regulator; int ret; struct device *dev = &bsp_priv->pdev->dev; - if (!ldostr) { - dev_err(dev, "%s: no ldo found\n", __func__); + if (!ldo) { + dev_err(dev, "%s: no regulator found\n", __func__); return -1; } - ldo = regulator_get(NULL, ldostr); - if (!ldo) { - dev_err(dev, "\n%s get ldo %s failed\n", __func__, ldostr); + if (enable) { + ret = regulator_enable(ldo); + if (ret) + dev_err(dev, "%s: fail to enable phy-supply\n", + __func__); } else { - if (enable) { - if (!regulator_is_enabled(ldo)) { - ret = regulator_enable(ldo); - if (ret != 0) - dev_err(dev, "%s: fail to enable %s\n", - __func__, ldostr); - else - dev_info(dev, "turn on ldo done.\n"); - } else { - dev_warn(dev, "%s is enabled before enable", - ldostr); - } - } else { - if (regulator_is_enabled(ldo)) { - ret = regulator_disable(ldo); - if (ret != 0) - dev_err(dev, "%s: fail to disable %s\n", - __func__, ldostr); - else - dev_info(dev, "turn off ldo done.\n"); - } else { - dev_warn(dev, "%s is disabled before disable", - ldostr); - } - } - regulator_put(ldo); + ret = regulator_disable(ldo); + if (ret) + dev_err(dev, "%s: fail to disable phy-supply\n", + __func__); } return 0; @@ -346,14 +325,14 @@ static void *rk_gmac_setup(struct platform_device *pdev) bsp_priv->phy_iface = of_get_phy_mode(dev->of_node); - ret = of_property_read_string(dev->of_node, "phy_regulator", &strings); - if (ret) { - dev_warn(dev, "%s: Can not read property: phy_regulator.\n", - __func__); - } else { - dev_info(dev, "%s: PHY power controlled by regulator(%s).\n", - __func__, strings); - strcpy(bsp_priv->regulator, strings); + bsp_priv->regulator = devm_regulator_get_optional(dev, "phy"); + if (IS_ERR(bsp_priv->regulator)) { + if (PTR_ERR(bsp_priv->regulator) == -EPROBE_DEFER) { + dev_err(dev, "phy regulator is not available yet, deferred probing\n"); + return ERR_PTR(-EPROBE_DEFER); + } + dev_err(dev, "no regulator found\n"); + bsp_priv->regulator = NULL; } ret = of_property_read_string(dev->of_node, "clock_in_out", &strings); -- cgit v1.2.1 From 0700d8161ec9d3809238c703ad8d37c02e658c15 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Tue, 20 Jan 2015 03:51:43 -0500 Subject: be2net: move interface create code to a separate routine This removes a bit of duplication of code that initializes the en_flags. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 49 +++++++++++++++++------------ 1 file changed, 29 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index ed46610e5453..c40d7efa24c2 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3183,13 +3183,32 @@ static int be_clear(struct be_adapter *adapter) return 0; } +static int be_if_create(struct be_adapter *adapter, u32 *if_handle, + u32 cap_flags, u32 vf) +{ + u32 en_flags; + int status; + + en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | + BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS | + BE_IF_FLAGS_RSS; + + en_flags &= cap_flags; + + status = be_cmd_if_create(adapter, cap_flags, en_flags, + if_handle, vf); + + return status; +} + static int be_vfs_if_create(struct be_adapter *adapter) { struct be_resources res = {0}; struct be_vf_cfg *vf_cfg; - u32 cap_flags, en_flags, vf; - int status = 0; + u32 cap_flags, vf; + int status; + /* If a FW profile exists, then cap_flags are updated */ cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_MULTICAST; @@ -3201,18 +3220,13 @@ static int be_vfs_if_create(struct be_adapter *adapter) cap_flags = res.if_cap_flags; } - /* If a FW profile exists, then cap_flags are updated */ - en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED | - BE_IF_FLAGS_BROADCAST | - BE_IF_FLAGS_MULTICAST); - status = - be_cmd_if_create(adapter, cap_flags, en_flags, - &vf_cfg->if_handle, vf + 1); + status = be_if_create(adapter, &vf_cfg->if_handle, + cap_flags, vf + 1); if (status) - goto err; + return status; } -err: - return status; + + return 0; } static int be_vf_setup_init(struct be_adapter *adapter) @@ -3653,7 +3667,7 @@ int be_update_queues(struct be_adapter *adapter) static int be_setup(struct be_adapter *adapter) { struct device *dev = &adapter->pdev->dev; - u32 tx_fc, rx_fc, en_flags; + u32 tx_fc, rx_fc; int status; be_setup_init(adapter); @@ -3669,13 +3683,8 @@ static int be_setup(struct be_adapter *adapter) if (status) goto err; - en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | - BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS; - if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) - en_flags |= BE_IF_FLAGS_RSS; - en_flags = en_flags & be_if_cap_flags(adapter); - status = be_cmd_if_create(adapter, be_if_cap_flags(adapter), en_flags, - &adapter->if_handle, 0); + status = be_if_create(adapter, &adapter->if_handle, + be_if_cap_flags(adapter), 0); if (status) goto err; -- cgit v1.2.1 From 00d594c3da568647ccbae506da12d3186600b377 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Tue, 20 Jan 2015 03:51:44 -0500 Subject: be2net: fix failure case in setting flow control When the FW cmd to set flow control fails, the adapter state must simply reflect the old values. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_ethtool.c | 14 ++++++++------ drivers/net/ethernet/emulex/benet/be_main.c | 12 +++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 32c53bc0e07a..4d2de4700769 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -705,15 +705,17 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) if (ecmd->autoneg != adapter->phy.fc_autoneg) return -EINVAL; - adapter->tx_fc = ecmd->tx_pause; - adapter->rx_fc = ecmd->rx_pause; - status = be_cmd_set_flow_control(adapter, - adapter->tx_fc, adapter->rx_fc); - if (status) + status = be_cmd_set_flow_control(adapter, ecmd->tx_pause, + ecmd->rx_pause); + if (status) { dev_warn(&adapter->pdev->dev, "Pause param set failed\n"); + return be_cmd_status(status); + } - return be_cmd_status(status); + adapter->tx_fc = ecmd->tx_pause; + adapter->rx_fc = ecmd->rx_pause; + return 0; } static int be_set_phys_id(struct net_device *netdev, diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index c40d7efa24c2..f5ac35ccc57e 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3667,7 +3667,6 @@ int be_update_queues(struct be_adapter *adapter) static int be_setup(struct be_adapter *adapter) { struct device *dev = &adapter->pdev->dev; - u32 tx_fc, rx_fc; int status; be_setup_init(adapter); @@ -3717,11 +3716,14 @@ static int be_setup(struct be_adapter *adapter) be_cmd_get_acpi_wol_cap(adapter); - be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc); + status = be_cmd_set_flow_control(adapter, adapter->tx_fc, + adapter->rx_fc); + if (status) + be_cmd_get_flow_control(adapter, &adapter->tx_fc, + &adapter->rx_fc); - if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) - be_cmd_set_flow_control(adapter, adapter->tx_fc, - adapter->rx_fc); + dev_info(&adapter->pdev->dev, "HW Flow control - TX:%d RX:%d\n", + adapter->tx_fc, adapter->rx_fc); if (be_physfn(adapter)) be_cmd_set_logical_link_config(adapter, -- cgit v1.2.1 From 18fd602564d3827125aa5c7a4eab6b42da3650d1 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Tue, 20 Jan 2015 03:51:45 -0500 Subject: be2net: fail VF link config change via ndo_set_vf_link_state() on BE3/Lancer The support for this exists only in skyhawk FW. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index fead5c65a4f0..9772f49a4837 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -4092,7 +4092,7 @@ int be_cmd_set_logical_link_config(struct be_adapter *adapter, int status; if (BEx_chip(adapter) || lancer_chip(adapter)) - return 0; + return -EOPNOTSUPP; spin_lock_bh(&adapter->mcc_lock); -- cgit v1.2.1 From e673244af1b32c6ffb5c886f841321b98cbbcc9b Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Tue, 20 Jan 2015 03:51:46 -0500 Subject: be2net: add a log message for POST timeout in Lancer This patch adds a log message in case of POST timeout in Lancer to help debugging failure cases. It also logs sliport_status register value in case of POST timeout. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 9772f49a4837..2021eb067b54 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -573,7 +573,7 @@ static int lancer_wait_ready(struct be_adapter *adapter) { #define SLIPORT_READY_TIMEOUT 30 u32 sliport_status; - int status = 0, i; + int i; for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) { sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); @@ -584,9 +584,9 @@ static int lancer_wait_ready(struct be_adapter *adapter) } if (i == SLIPORT_READY_TIMEOUT) - status = -1; + return sliport_status ? : -1; - return status; + return 0; } static bool lancer_provisioning_error(struct be_adapter *adapter) @@ -624,7 +624,7 @@ int lancer_test_and_set_rdy_state(struct be_adapter *adapter) iowrite32(SLI_PORT_CONTROL_IP_MASK, adapter->db + SLIPORT_CONTROL_OFFSET); - /* check adapter has corrected the error */ + /* check if adapter has corrected the error */ status = lancer_wait_ready(adapter); sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); @@ -655,7 +655,11 @@ int be_fw_wait_ready(struct be_adapter *adapter) if (lancer_chip(adapter)) { status = lancer_wait_ready(adapter); - return status; + if (status) { + stage = status; + goto err; + } + return 0; } do { @@ -671,7 +675,8 @@ int be_fw_wait_ready(struct be_adapter *adapter) timeout += 2; } while (timeout < 60); - dev_err(dev, "POST timeout; stage=0x%x\n", stage); +err: + dev_err(dev, "POST timeout; stage=%#x\n", stage); return -1; } -- cgit v1.2.1 From 9a6d73d9f297fd1bf7514bf2b1dc2f4b48c638b9 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Tue, 20 Jan 2015 03:51:47 -0500 Subject: be2net: issue function reset cmd in resume path The Lancer FW is picky about requiring a function reset FW cmd as a part of the initialization sequence. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index f5ac35ccc57e..0b0482b4606d 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -5071,6 +5071,10 @@ static int be_resume(struct pci_dev *pdev) if (status) return status; + status = be_cmd_reset_function(adapter); + if (status) + return status; + be_intr_set(adapter, true); /* tell fw we're ready to fire cmds */ status = be_cmd_fw_init(adapter); -- cgit v1.2.1 From e02cfd96a2726a06d29c5b44e0f0375048ae9da1 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Tue, 20 Jan 2015 03:51:48 -0500 Subject: be2net: move definitions related to FW cmdsfrom be_hw.h to be_cmds.h Some FW cmd related definitions were included in be_hw.h Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.h | 175 ++++++++++++++++++++++ drivers/net/ethernet/emulex/benet/be_hw.h | 223 ---------------------------- drivers/net/ethernet/emulex/benet/be_main.c | 2 +- 3 files changed, 176 insertions(+), 224 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index eb5085d6794f..c2701ccd0a1d 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1161,7 +1161,167 @@ struct be_cmd_resp_get_beacon_state { u8 rsvd0[3]; } __packed; +/* Flashrom related descriptors */ +#define MAX_FLASH_COMP 32 + +#define OPTYPE_ISCSI_ACTIVE 0 +#define OPTYPE_REDBOOT 1 +#define OPTYPE_BIOS 2 +#define OPTYPE_PXE_BIOS 3 +#define OPTYPE_FCOE_BIOS 8 +#define OPTYPE_ISCSI_BACKUP 9 +#define OPTYPE_FCOE_FW_ACTIVE 10 +#define OPTYPE_FCOE_FW_BACKUP 11 +#define OPTYPE_NCSI_FW 13 +#define OPTYPE_REDBOOT_DIR 18 +#define OPTYPE_REDBOOT_CONFIG 19 +#define OPTYPE_SH_PHY_FW 21 +#define OPTYPE_FLASHISM_JUMPVECTOR 22 +#define OPTYPE_UFI_DIR 23 +#define OPTYPE_PHY_FW 99 + +#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 262144 /* Max OPTION ROM image sz */ +#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 262144 /* Max Redboot image sz */ +#define FLASH_IMAGE_MAX_SIZE_g2 1310720 /* Max firmware image size */ + +#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 262144 +#define FLASH_PHY_FW_IMAGE_MAX_SIZE_g3 262144 +#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 524288 /* Max OPTION ROM image sz */ +#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 1048576 /* Max Redboot image sz */ +#define FLASH_IMAGE_MAX_SIZE_g3 2097152 /* Max firmware image size */ + +/* Offsets for components on Flash. */ +#define FLASH_REDBOOT_START_g2 0 +#define FLASH_FCoE_BIOS_START_g2 524288 +#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 1048576 +#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 2359296 +#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 3670016 +#define FLASH_FCoE_BACKUP_IMAGE_START_g2 4980736 +#define FLASH_iSCSI_BIOS_START_g2 7340032 +#define FLASH_PXE_BIOS_START_g2 7864320 + +#define FLASH_REDBOOT_START_g3 262144 +#define FLASH_PHY_FW_START_g3 1310720 +#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 2097152 +#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 4194304 +#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 6291456 +#define FLASH_FCoE_BACKUP_IMAGE_START_g3 8388608 +#define FLASH_iSCSI_BIOS_START_g3 12582912 +#define FLASH_PXE_BIOS_START_g3 13107200 +#define FLASH_FCoE_BIOS_START_g3 13631488 +#define FLASH_NCSI_START_g3 15990784 + +#define IMAGE_NCSI 16 +#define IMAGE_OPTION_ROM_PXE 32 +#define IMAGE_OPTION_ROM_FCoE 33 +#define IMAGE_OPTION_ROM_ISCSI 34 +#define IMAGE_FLASHISM_JUMPVECTOR 48 +#define IMAGE_FIRMWARE_iSCSI 160 +#define IMAGE_FIRMWARE_FCoE 162 +#define IMAGE_FIRMWARE_BACKUP_iSCSI 176 +#define IMAGE_FIRMWARE_BACKUP_FCoE 178 +#define IMAGE_FIRMWARE_PHY 192 +#define IMAGE_REDBOOT_DIR 208 +#define IMAGE_REDBOOT_CONFIG 209 +#define IMAGE_UFI_DIR 210 +#define IMAGE_BOOT_CODE 224 + +struct controller_id { + u32 vendor; + u32 device; + u32 subvendor; + u32 subdevice; +}; + +struct flash_comp { + unsigned long offset; + int optype; + int size; + int img_type; +}; + +struct image_hdr { + u32 imageid; + u32 imageoffset; + u32 imagelength; + u32 image_checksum; + u8 image_version[32]; +}; + +struct flash_file_hdr_g2 { + u8 sign[32]; + u32 cksum; + u32 antidote; + struct controller_id cont_id; + u32 file_len; + u32 chunk_num; + u32 total_chunks; + u32 num_imgs; + u8 build[24]; +}; + +struct flash_file_hdr_g3 { + u8 sign[52]; + u8 ufi_version[4]; + u32 file_len; + u32 cksum; + u32 antidote; + u32 num_imgs; + u8 build[24]; + u8 asic_type_rev; + u8 rsvd[31]; +}; + +struct flash_section_hdr { + u32 format_rev; + u32 cksum; + u32 antidote; + u32 num_images; + u8 id_string[128]; + u32 rsvd[4]; +} __packed; + +struct flash_section_hdr_g2 { + u32 format_rev; + u32 cksum; + u32 antidote; + u32 build_num; + u8 id_string[128]; + u32 rsvd[8]; +} __packed; + +struct flash_section_entry { + u32 type; + u32 offset; + u32 pad_size; + u32 image_size; + u32 cksum; + u32 entry_point; + u16 optype; + u16 rsvd0; + u32 rsvd1; + u8 ver_data[32]; +} __packed; + +struct flash_section_info { + u8 cookie[32]; + struct flash_section_hdr fsec_hdr; + struct flash_section_entry fsec_entry[32]; +} __packed; + +struct flash_section_info_g2 { + u8 cookie[32]; + struct flash_section_hdr_g2 fsec_hdr; + struct flash_section_entry fsec_entry[32]; +} __packed; + /****************** Firmware Flash ******************/ +#define FLASHROM_OPER_FLASH 1 +#define FLASHROM_OPER_SAVE 2 +#define FLASHROM_OPER_REPORT 4 +#define FLASHROM_OPER_PHY_FLASH 9 +#define FLASHROM_OPER_PHY_SAVE 10 + struct flashrom_params { u32 op_code; u32 op_type; @@ -1366,6 +1526,7 @@ enum { PHY_TYPE_QSFP, PHY_TYPE_KR4_40GB, PHY_TYPE_KR2_20GB, + PHY_TYPE_TN_8022, PHY_TYPE_DISABLED = 255 }; @@ -1429,6 +1590,20 @@ struct be_cmd_req_set_qos { }; /*********************** Controller Attributes ***********************/ +struct mgmt_hba_attribs { + u32 rsvd0[24]; + u8 controller_model_number[32]; + u32 rsvd1[79]; + u8 rsvd2[3]; + u8 phy_port; + u32 rsvd3[13]; +} __packed; + +struct mgmt_controller_attrib { + struct mgmt_hba_attribs hba_attribs; + u32 rsvd0[10]; +} __packed; + struct be_cmd_req_cntl_attribs { struct be_cmd_req_hdr hdr; }; diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index 6d7b3a4d3cff..8e91ae851a7c 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -171,94 +171,6 @@ #define RETRIEVE_FAT 0 #define QUERY_FAT 1 -/* Flashrom related descriptors */ -#define MAX_FLASH_COMP 32 -#define IMAGE_TYPE_FIRMWARE 160 -#define IMAGE_TYPE_BOOTCODE 224 -#define IMAGE_TYPE_OPTIONROM 32 - -#define NUM_FLASHDIR_ENTRIES 32 - -#define OPTYPE_ISCSI_ACTIVE 0 -#define OPTYPE_REDBOOT 1 -#define OPTYPE_BIOS 2 -#define OPTYPE_PXE_BIOS 3 -#define OPTYPE_FCOE_BIOS 8 -#define OPTYPE_ISCSI_BACKUP 9 -#define OPTYPE_FCOE_FW_ACTIVE 10 -#define OPTYPE_FCOE_FW_BACKUP 11 -#define OPTYPE_NCSI_FW 13 -#define OPTYPE_REDBOOT_DIR 18 -#define OPTYPE_REDBOOT_CONFIG 19 -#define OPTYPE_SH_PHY_FW 21 -#define OPTYPE_FLASHISM_JUMPVECTOR 22 -#define OPTYPE_UFI_DIR 23 -#define OPTYPE_PHY_FW 99 -#define TN_8022 13 - -#define FLASHROM_OPER_PHY_FLASH 9 -#define FLASHROM_OPER_PHY_SAVE 10 -#define FLASHROM_OPER_FLASH 1 -#define FLASHROM_OPER_SAVE 2 -#define FLASHROM_OPER_REPORT 4 - -#define FLASH_IMAGE_MAX_SIZE_g2 (1310720) /* Max firmware image size */ -#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 (262144) /* Max OPTION ROM image sz */ -#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 (262144) /* Max Redboot image sz */ -#define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max firmware image size */ -#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM image sz */ -#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */ -#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 (262144) -#define FLASH_PHY_FW_IMAGE_MAX_SIZE_g3 262144 - -#define FLASH_NCSI_MAGIC (0x16032009) -#define FLASH_NCSI_DISABLED (0) -#define FLASH_NCSI_ENABLED (1) - -#define FLASH_NCSI_BITFILE_HDR_OFFSET (0x600000) - -/* Offsets for components on Flash. */ -#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 (1048576) -#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 (2359296) -#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 (3670016) -#define FLASH_FCoE_BACKUP_IMAGE_START_g2 (4980736) -#define FLASH_iSCSI_BIOS_START_g2 (7340032) -#define FLASH_PXE_BIOS_START_g2 (7864320) -#define FLASH_FCoE_BIOS_START_g2 (524288) -#define FLASH_REDBOOT_START_g2 (0) - -#define FLASH_NCSI_START_g3 (15990784) -#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 (2097152) -#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 (4194304) -#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 (6291456) -#define FLASH_FCoE_BACKUP_IMAGE_START_g3 (8388608) -#define FLASH_iSCSI_BIOS_START_g3 (12582912) -#define FLASH_PXE_BIOS_START_g3 (13107200) -#define FLASH_FCoE_BIOS_START_g3 (13631488) -#define FLASH_REDBOOT_START_g3 (262144) -#define FLASH_PHY_FW_START_g3 1310720 - -#define IMAGE_NCSI 16 -#define IMAGE_OPTION_ROM_PXE 32 -#define IMAGE_OPTION_ROM_FCoE 33 -#define IMAGE_OPTION_ROM_ISCSI 34 -#define IMAGE_FLASHISM_JUMPVECTOR 48 -#define IMAGE_FLASH_ISM 49 -#define IMAGE_JUMP_VECTOR 50 -#define IMAGE_FIRMWARE_iSCSI 160 -#define IMAGE_FIRMWARE_COMP_iSCSI 161 -#define IMAGE_FIRMWARE_FCoE 162 -#define IMAGE_FIRMWARE_COMP_FCoE 163 -#define IMAGE_FIRMWARE_BACKUP_iSCSI 176 -#define IMAGE_FIRMWARE_BACKUP_COMP_iSCSI 177 -#define IMAGE_FIRMWARE_BACKUP_FCoE 178 -#define IMAGE_FIRMWARE_BACKUP_COMP_FCoE 179 -#define IMAGE_FIRMWARE_PHY 192 -#define IMAGE_REDBOOT_DIR 208 -#define IMAGE_REDBOOT_CONFIG 209 -#define IMAGE_UFI_DIR 210 -#define IMAGE_BOOT_CODE 224 - /************* Rx Packet Type Encoding **************/ #define BE_UNICAST_PACKET 0 #define BE_MULTICAST_PACKET 1 @@ -440,138 +352,3 @@ struct amap_eth_rx_compl_v1 { struct be_eth_rx_compl { u32 dw[4]; }; - -struct mgmt_hba_attribs { - u8 flashrom_version_string[32]; - u8 manufacturer_name[32]; - u32 supported_modes; - u32 rsvd0[3]; - u8 ncsi_ver_string[12]; - u32 default_extended_timeout; - u8 controller_model_number[32]; - u8 controller_description[64]; - u8 controller_serial_number[32]; - u8 ip_version_string[32]; - u8 firmware_version_string[32]; - u8 bios_version_string[32]; - u8 redboot_version_string[32]; - u8 driver_version_string[32]; - u8 fw_on_flash_version_string[32]; - u32 functionalities_supported; - u16 max_cdblength; - u8 asic_revision; - u8 generational_guid[16]; - u8 hba_port_count; - u16 default_link_down_timeout; - u8 iscsi_ver_min_max; - u8 multifunction_device; - u8 cache_valid; - u8 hba_status; - u8 max_domains_supported; - u8 phy_port; - u32 firmware_post_status; - u32 hba_mtu[8]; - u32 rsvd1[4]; -}; - -struct mgmt_controller_attrib { - struct mgmt_hba_attribs hba_attribs; - u16 pci_vendor_id; - u16 pci_device_id; - u16 pci_sub_vendor_id; - u16 pci_sub_system_id; - u8 pci_bus_number; - u8 pci_device_number; - u8 pci_function_number; - u8 interface_type; - u64 unique_identifier; - u32 rsvd0[5]; -}; - -struct controller_id { - u32 vendor; - u32 device; - u32 subvendor; - u32 subdevice; -}; - -struct flash_comp { - unsigned long offset; - int optype; - int size; - int img_type; -}; - -struct image_hdr { - u32 imageid; - u32 imageoffset; - u32 imagelength; - u32 image_checksum; - u8 image_version[32]; -}; -struct flash_file_hdr_g2 { - u8 sign[32]; - u32 cksum; - u32 antidote; - struct controller_id cont_id; - u32 file_len; - u32 chunk_num; - u32 total_chunks; - u32 num_imgs; - u8 build[24]; -}; - -struct flash_file_hdr_g3 { - u8 sign[52]; - u8 ufi_version[4]; - u32 file_len; - u32 cksum; - u32 antidote; - u32 num_imgs; - u8 build[24]; - u8 asic_type_rev; - u8 rsvd[31]; -}; - -struct flash_section_hdr { - u32 format_rev; - u32 cksum; - u32 antidote; - u32 num_images; - u8 id_string[128]; - u32 rsvd[4]; -} __packed; - -struct flash_section_hdr_g2 { - u32 format_rev; - u32 cksum; - u32 antidote; - u32 build_num; - u8 id_string[128]; - u32 rsvd[8]; -} __packed; - -struct flash_section_entry { - u32 type; - u32 offset; - u32 pad_size; - u32 image_size; - u32 cksum; - u32 entry_point; - u16 optype; - u16 rsvd0; - u32 rsvd1; - u8 ver_data[32]; -} __packed; - -struct flash_section_info { - u8 cookie[32]; - struct flash_section_hdr fsec_hdr; - struct flash_section_entry fsec_entry[32]; -} __packed; - -struct flash_section_info_g2 { - u8 cookie[32]; - struct flash_section_hdr_g2 fsec_hdr; - struct flash_section_entry fsec_entry[32]; -} __packed; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 0b0482b4606d..6c10fece1245 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3762,7 +3762,7 @@ static char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "}; static bool phy_flashing_required(struct be_adapter *adapter) { - return (adapter->phy.phy_type == TN_8022 && + return (adapter->phy.phy_type == PHY_TYPE_TN_8022 && adapter->phy.interface_type == PHY_TYPE_BASET_10GB); } -- cgit v1.2.1 From 58bdeaa666152b2e03bb6e0d754d8186120fc103 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Tue, 20 Jan 2015 03:51:49 -0500 Subject: be2net: Fix TX rate limiting on Lancer/Skyhawk-R VFs When max_tx_rate is set via bw_max in the NIC resource desc, bw_min must be set to 0. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 2021eb067b54..4bd425ea3421 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -3756,6 +3756,7 @@ int be_cmd_config_qos(struct be_adapter *adapter, u32 max_rate, u16 link_speed, be_reset_nic_desc(&nic_desc); nic_desc.pf_num = adapter->pf_number; nic_desc.vf_num = domain; + nic_desc.bw_min = 0; if (lancer_chip(adapter)) { nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V0; nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V0; -- cgit v1.2.1 From 2b995f63987013bacde99168218f9c7b252bdcf1 Mon Sep 17 00:00:00 2001 From: Nimrod Andy Date: Tue, 20 Jan 2015 14:10:35 +0800 Subject: net: fec: fix the warning found by dma debug Enable kernel config "CONFIG_HAVE_DMA_API_DEBUG", FEC have kernel warning: [ 6.650444] fec 2188000.ethernet: DMA-API: device driver tries to free DMA memory it has not allocated [ 6.664289] Modules linked in: [ 6.667378] CPU: 0 PID: 3 Comm: ksoftirqd/0 Not tainted 3.19.0-rc4-00688-g8834016-dirty #150 [ 6.675841] Hardware name: Freescale i.MX6 SoloX (Device Tree) [ 6.681698] Backtrace: [ 6.684189] [<80011e3c>] (dump_backtrace) from [<80011fdc>] (show_stack+0x18/0x1c) [ 6.691789] r6:80890154 r5:00000000 r4:00000000 r3:00000000 [ 6.697533] [<80011fc4>] (show_stack) from [<806d2d88>] (dump_stack+0x80/0x9c) [ 6.704799] [<806d2d08>] (dump_stack) from [<8002a4e4>] (warn_slowpath_common+0x7c/0xb4) [ 6.712917] r5:00000445 r4:00000000 [ 6.716544] [<8002a468>] (warn_slowpath_common) from [<8002a5c0>] (warn_slowpath_fmt+0x38/0x40) [ 6.725265] r8:809a2ee8 r7:00000000 r6:00000000 r5:00000000 r4:00000042 [ 6.732087] [<8002a58c>] (warn_slowpath_fmt) from [<802d6268>] (check_unmap+0x86c/0x98c) [ 6.740202] r3:808c79bc r2:8089060c [ 6.743826] [<802d59fc>] (check_unmap) from [<802d65e4>] (debug_dma_unmap_page+0x80/0x88) [ 6.752029] r10:00000000 r9:00000000 r8:00000000 r7:00000001 r6:be12a410 r5:00000000 [ 6.759967] r4:00000042 [ 6.762538] [<802d6564>] (debug_dma_unmap_page) from [<80440248>] (fec_enet_rx_napi+0x7ec/0xb9c) [ 6.771345] r7:00000400 r6:be3e4000 r5:bf08fa20 r4:be036000 [ 6.777094] [<8043fa5c>] (fec_enet_rx_napi) from [<8056ae24>] (net_rx_action+0x134/0x324) [ 6.785297] r10:be089e60 r9:80998180 r8:ffff8d68 r7:0000012c r6:00000040 r5:00000001 [ 6.793239] r4:be036718 [ 6.795801] [<8056acf0>] (net_rx_action) from [<8002db24>] (__do_softirq+0x138/0x2d0) [ 6.803655] r10:00000003 r9:00000003 r8:80996378 r7:8099c080 r6:00000100 r5:8099c08c [ 6.811593] r4:00000000 [ 6.814157] [<8002d9ec>] (__do_softirq) from [<8002dd00>] (run_ksoftirqd+0x44/0x5c) [ 6.821836] r10:00000000 r9:00000000 r8:809b133c r7:00000000 r6:00000001 r5:00000000 [ 6.829775] r4:be027e80 [ 6.832346] [<8002dcbc>] (run_ksoftirqd) from [<80048290>] (smpboot_thread_fn+0x154/0x1c4) [ 6.840649] [<8004813c>] (smpboot_thread_fn) from [<80044780>] (kthread+0xdc/0xf8) [ 6.848224] r10:00000000 r8:00000000 r7:8004813c r6:be027e80 r5:be027ec0 r4:00000000 [ 6.856179] [<800446a4>] (kthread) from [<8000ebc8>] (ret_from_fork+0x14/0x2c) [ 6.863425] r7:00000000 r6:00000000 r5:800446a4 r4:be027ec0 [ 6.869156] ---[ end trace 861cf914d2461a8b ]--- There have one bug in .fec_enet_tx_queue() function to unmap the DMA memory: For SG or TSO, get one buffer descriptor and then unmap the related DMA memory, and then get the next buffer descriptor, loop to while() to check "TX_READY". If "TX_READY" bit still __IS__ existed in the BD (The next fraglist or next TSO packet is not transmited complitely), exit the current clean work. When the next work is triggered, it still repeat above step with the same BD. The potential issue is that unmap the same DMA memory for multiple times. The patch fix the clean work for SG and TSO packet. Reported-by: Anand Moon Reported-by: Christian Gmeiner Signed-off-by: Fugang Duan Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 34 +++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 1c7a7e43dd9c..58cabee00abf 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1189,12 +1189,13 @@ static void fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) { struct fec_enet_private *fep; - struct bufdesc *bdp; + struct bufdesc *bdp, *bdp_t; unsigned short status; struct sk_buff *skb; struct fec_enet_priv_tx_q *txq; struct netdev_queue *nq; int index = 0; + int i, bdnum; int entries_free; fep = netdev_priv(ndev); @@ -1215,18 +1216,29 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) if (bdp == txq->cur_tx) break; - index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep); - + bdp_t = bdp; + bdnum = 1; + index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep); skb = txq->tx_skbuff[index]; - txq->tx_skbuff[index] = NULL; - if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr)) - dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, - bdp->cbd_datlen, DMA_TO_DEVICE); - bdp->cbd_bufaddr = 0; - if (!skb) { - bdp = fec_enet_get_nextdesc(bdp, fep, queue_id); - continue; + while (!skb) { + bdp_t = fec_enet_get_nextdesc(bdp_t, fep, queue_id); + index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep); + skb = txq->tx_skbuff[index]; + bdnum++; } + if (skb_shinfo(skb)->nr_frags && + (status = bdp_t->cbd_sc) & BD_ENET_TX_READY) + break; + + for (i = 0; i < bdnum; i++) { + if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr)) + dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, + bdp->cbd_datlen, DMA_TO_DEVICE); + bdp->cbd_bufaddr = 0; + if (i < bdnum - 1) + bdp = fec_enet_get_nextdesc(bdp, fep, queue_id); + } + txq->tx_skbuff[index] = NULL; /* Check for errors. */ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | -- cgit v1.2.1 From d998f8efa47221405ceae129aa93fa6d4ac8510d Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 20 Jan 2015 11:23:04 -0800 Subject: udp: Do not require sock in udp_tunnel_xmit_skb The UDP tunnel transmit functions udp_tunnel_xmit_skb and udp_tunnel6_xmit_skb include a socket argument. The socket being passed to the functions (from VXLAN) is a UDP created for receive side. The only thing that the socket is used for in the transmit functions is to get the setting for checksum (enabled or zero). This patch removes the argument and and adds a nocheck argument for checksum setting. This eliminates the unnecessary dependency on a UDP socket for UDP tunnel transmit. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 19d3664ab9dd..a288ceab502e 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1769,8 +1769,9 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio, - ttl, src_port, dst_port); + udp_tunnel6_xmit_skb(dst, skb, dev, saddr, daddr, prio, + ttl, src_port, dst_port, + udp_get_no_check6_tx(vs->sock->sk)); return 0; err: dst_release(dst); @@ -1848,8 +1849,9 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos, - ttl, df, src_port, dst_port, xnet); + return udp_tunnel_xmit_skb(rt, skb, src, dst, tos, + ttl, df, src_port, dst_port, xnet, + vs->sock->sk->sk_no_check_tx); } EXPORT_SYMBOL_GPL(vxlan_xmit_skb); -- cgit v1.2.1 From af33c1adae1e095e90d14fe35501256ebb07aabf Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 20 Jan 2015 11:23:05 -0800 Subject: vxlan: Eliminate dependency on UDP socket in transmit path In the vxlan transmit path there is no need to reference the socket for a tunnel which is needed for the receive side. We do, however, need the vxlan_dev flags. This patch eliminate references to the socket in the transmit path, and changes VXLAN_F_UNSHAREABLE to be VXLAN_F_RCV_FLAGS. This mask is used to store the flags applicable to receive (GBP, CSUM6_RX, and REMCSUM_RX) in the vxlan_sock flags. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 60 +++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index a288ceab502e..87736e65cd15 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -270,12 +270,13 @@ static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family, __be16 port, u32 flags) { struct vxlan_sock *vs; - u32 match_flags = flags & VXLAN_F_UNSHAREABLE; + + flags &= VXLAN_F_RCV_FLAGS; hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) { if (inet_sk(vs->sock->sk)->inet_sport == port && inet_sk(vs->sock->sk)->sk.sk_family == family && - (vs->flags & VXLAN_F_UNSHAREABLE) == match_flags) + vs->flags == flags) return vs; } return NULL; @@ -1674,7 +1675,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) return false; } -static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, struct vxlan_sock *vs, +static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags, struct vxlan_metadata *md) { struct vxlanhdr_gbp *gbp; @@ -1692,21 +1693,20 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, struct vxlan_sock *vs, } #if IS_ENABLED(CONFIG_IPV6) -static int vxlan6_xmit_skb(struct vxlan_sock *vs, - struct dst_entry *dst, struct sk_buff *skb, +static int vxlan6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, __be16 src_port, __be16 dst_port, - struct vxlan_metadata *md, bool xnet) + struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; int min_headroom; int err; - bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk); + bool udp_sum = !(vxflags & VXLAN_F_UDP_ZERO_CSUM6_TX); int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; u16 hdrlen = sizeof(struct vxlanhdr); - if ((vs->flags & VXLAN_F_REMCSUM_TX) && + if ((vxflags & VXLAN_F_REMCSUM_TX) && skb->ip_summed == CHECKSUM_PARTIAL) { int csum_start = skb_checksum_start_offset(skb); @@ -1764,14 +1764,14 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, } } - if (vs->flags & VXLAN_F_GBP) - vxlan_build_gbp_hdr(vxh, vs, md); + if (vxflags & VXLAN_F_GBP) + vxlan_build_gbp_hdr(vxh, vxflags, md); skb_set_inner_protocol(skb, htons(ETH_P_TEB)); udp_tunnel6_xmit_skb(dst, skb, dev, saddr, daddr, prio, ttl, src_port, dst_port, - udp_get_no_check6_tx(vs->sock->sk)); + !!(vxflags & VXLAN_F_UDP_ZERO_CSUM6_TX)); return 0; err: dst_release(dst); @@ -1779,20 +1779,19 @@ err: } #endif -int vxlan_xmit_skb(struct vxlan_sock *vs, - struct rtable *rt, struct sk_buff *skb, +int vxlan_xmit_skb(struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, - struct vxlan_metadata *md, bool xnet) + struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; int min_headroom; int err; - bool udp_sum = !vs->sock->sk->sk_no_check_tx; + bool udp_sum = !!(vxflags & VXLAN_F_UDP_CSUM); int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; u16 hdrlen = sizeof(struct vxlanhdr); - if ((vs->flags & VXLAN_F_REMCSUM_TX) && + if ((vxflags & VXLAN_F_REMCSUM_TX) && skb->ip_summed == CHECKSUM_PARTIAL) { int csum_start = skb_checksum_start_offset(skb); @@ -1844,14 +1843,14 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, } } - if (vs->flags & VXLAN_F_GBP) - vxlan_build_gbp_hdr(vxh, vs, md); + if (vxflags & VXLAN_F_GBP) + vxlan_build_gbp_hdr(vxh, vxflags, md); skb_set_inner_protocol(skb, htons(ETH_P_TEB)); return udp_tunnel_xmit_skb(rt, skb, src, dst, tos, ttl, df, src_port, dst_port, xnet, - vs->sock->sk->sk_no_check_tx); + !(vxflags & VXLAN_F_UDP_CSUM)); } EXPORT_SYMBOL_GPL(vxlan_xmit_skb); @@ -1983,10 +1982,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, md.vni = htonl(vni << 8); md.gbp = skb->mark; - err = vxlan_xmit_skb(vxlan->vn_sock, rt, skb, - fl4.saddr, dst->sin.sin_addr.s_addr, - tos, ttl, df, src_port, dst_port, &md, - !net_eq(vxlan->net, dev_net(vxlan->dev))); + err = vxlan_xmit_skb(rt, skb, fl4.saddr, + dst->sin.sin_addr.s_addr, tos, ttl, df, + src_port, dst_port, &md, + !net_eq(vxlan->net, dev_net(vxlan->dev)), + vxlan->flags); if (err < 0) { /* skb is already freed. */ skb = NULL; @@ -2042,10 +2042,10 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, md.vni = htonl(vni << 8); md.gbp = skb->mark; - err = vxlan6_xmit_skb(vxlan->vn_sock, ndst, skb, - dev, &fl6.saddr, &fl6.daddr, 0, ttl, - src_port, dst_port, &md, - !net_eq(vxlan->net, dev_net(vxlan->dev))); + err = vxlan6_xmit_skb(ndst, skb, dev, &fl6.saddr, &fl6.daddr, + 0, ttl, src_port, dst_port, &md, + !net_eq(vxlan->net, dev_net(vxlan->dev)), + vxlan->flags); #endif } @@ -2517,15 +2517,11 @@ static struct socket *vxlan_create_sock(struct net *net, bool ipv6, if (ipv6) { udp_conf.family = AF_INET6; - udp_conf.use_udp6_tx_checksums = - !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX); udp_conf.use_udp6_rx_checksums = !(flags & VXLAN_F_UDP_ZERO_CSUM6_RX); } else { udp_conf.family = AF_INET; udp_conf.local_ip.s_addr = INADDR_ANY; - udp_conf.use_udp_checksums = - !!(flags & VXLAN_F_UDP_CSUM); } udp_conf.local_udp_port = port; @@ -2569,7 +2565,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, atomic_set(&vs->refcnt, 1); vs->rcv = rcv; vs->data = data; - vs->flags = flags; + vs->flags = (flags & VXLAN_F_RCV_FLAGS); /* Initialize the vxlan udp offloads structure */ vs->udp_offloads.port = port; -- cgit v1.2.1 From c774905d98badddbeb4ad1bc653aedbd7ab024e4 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 25 Jan 2015 10:03:17 +0200 Subject: iwlwifi: mvm: check IWL_UCODE_TLV_API_SCD_CFG in API and not in capa IWL_UCODE_TLV_API_SCD_CFG is a new API and hence, check if enabled in the correct field. Fixes: 0294d9eece86 ("iwlwifi: mvm: let the firmware configure the scheduler") Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 979ac23522f2..7773ffc4ca62 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -874,7 +874,7 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) { - return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_API_SCD_CFG; + return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG; } extern const u8 iwl_mvm_ac_to_tx_fifo[]; -- cgit v1.2.1 From 51487ae736fecf41e8c58cf668934babe9700363 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 22 Jan 2015 23:27:12 +0200 Subject: usbnet: re-use native hex2bin() Call hex2bin() library function, instead of doing conversion here. Signed-off-by: Andy Shevchenko Acked-by: Oliver Neukum Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 3a6770a65d78..449835f4331e 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -160,20 +160,19 @@ EXPORT_SYMBOL_GPL(usbnet_get_endpoints); int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress) { - int tmp, i; + int tmp = -1, ret; unsigned char buf [13]; - tmp = usb_string(dev->udev, iMACAddress, buf, sizeof buf); - if (tmp != 12) { + ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf); + if (ret == 12) + tmp = hex2bin(dev->net->dev_addr, buf, 6); + if (tmp < 0) { dev_dbg(&dev->udev->dev, "bad MAC string %d fetch, %d\n", iMACAddress, tmp); - if (tmp >= 0) - tmp = -EINVAL; - return tmp; + if (ret >= 0) + ret = -EINVAL; + return ret; } - for (i = tmp = 0; i < 6; i++, tmp += 2) - dev->net->dev_addr [i] = - (hex_to_bin(buf[tmp]) << 4) + hex_to_bin(buf[tmp + 1]); return 0; } EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr); -- cgit v1.2.1 From 7aee42c6764bae75d0eb2f674f0874193de90c05 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 22 Jan 2015 23:37:39 +0200 Subject: cxgb3: re-use native hex2bin() Call hex2bin() library function instead of doing conversion here. Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb3/t3_hw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c index c74a898fcd4f..184a8d545ac4 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c @@ -727,9 +727,9 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16); } - for (i = 0; i < 6; i++) - p->eth_base[i] = hex_to_bin(vpd.na_data[2 * i]) * 16 + - hex_to_bin(vpd.na_data[2 * i + 1]); + ret = hex2bin(p->eth_base, vpd.na_data, 6); + if (ret < 0) + return -EINVAL; return 0; } -- cgit v1.2.1 From 872bf2fb69d90e3619befee842fc26db39d8e475 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Sun, 25 Jan 2015 16:59:35 +0200 Subject: net/mlx4_core: Maintain a persistent memory for mlx4 device Maintain a persistent memory that should survive reset flow/PCI error. This comes as a preparation for coming series to support above flows. Signed-off-by: Yishai Hadas Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/alloc.c | 15 +-- drivers/net/ethernet/mellanox/mlx4/catas.c | 13 +-- drivers/net/ethernet/mellanox/mlx4/cmd.c | 46 +++++---- drivers/net/ethernet/mellanox/mlx4/en_cq.c | 4 +- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_main.c | 4 +- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 4 +- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 4 +- drivers/net/ethernet/mellanox/mlx4/eq.c | 42 ++++---- drivers/net/ethernet/mellanox/mlx4/icm.c | 11 ++- drivers/net/ethernet/mellanox/mlx4/main.c | 106 +++++++++++++-------- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 9 +- drivers/net/ethernet/mellanox/mlx4/mr.c | 8 +- drivers/net/ethernet/mellanox/mlx4/pd.c | 6 +- drivers/net/ethernet/mellanox/mlx4/port.c | 17 ++-- drivers/net/ethernet/mellanox/mlx4/reset.c | 23 +++-- .../net/ethernet/mellanox/mlx4/resource_tracker.c | 36 ++++--- 18 files changed, 206 insertions(+), 146 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c index 963dd7e6d547..a716c26e0d99 100644 --- a/drivers/net/ethernet/mellanox/mlx4/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c @@ -592,7 +592,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, buf->nbufs = 1; buf->npages = 1; buf->page_shift = get_order(size) + PAGE_SHIFT; - buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev, + buf->direct.buf = dma_alloc_coherent(&dev->persist->pdev->dev, size, &t, gfp); if (!buf->direct.buf) return -ENOMEM; @@ -619,7 +619,8 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, for (i = 0; i < buf->nbufs; ++i) { buf->page_list[i].buf = - dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, + dma_alloc_coherent(&dev->persist->pdev->dev, + PAGE_SIZE, &t, gfp); if (!buf->page_list[i].buf) goto err_free; @@ -657,7 +658,8 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf) int i; if (buf->nbufs == 1) - dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf, + dma_free_coherent(&dev->persist->pdev->dev, size, + buf->direct.buf, buf->direct.map); else { if (BITS_PER_LONG == 64 && buf->direct.buf) @@ -665,7 +667,8 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf) for (i = 0; i < buf->nbufs; ++i) if (buf->page_list[i].buf) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + dma_free_coherent(&dev->persist->pdev->dev, + PAGE_SIZE, buf->page_list[i].buf, buf->page_list[i].map); kfree(buf->page_list); @@ -738,7 +741,7 @@ int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order, gfp_t gfp if (!mlx4_alloc_db_from_pgdir(pgdir, db, order)) goto out; - pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev), gfp); + pgdir = mlx4_alloc_db_pgdir(&dev->persist->pdev->dev, gfp); if (!pgdir) { ret = -ENOMEM; goto out; @@ -775,7 +778,7 @@ void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db) set_bit(i, db->u.pgdir->bits[o]); if (bitmap_full(db->u.pgdir->order1, MLX4_DB_PER_PAGE / 2)) { - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, + dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, db->u.pgdir->db_page, db->u.pgdir->db_dma); list_del(&db->u.pgdir->list); kfree(db->u.pgdir); diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 9c656fe4983d..1a102c9bac99 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -70,7 +70,7 @@ static void poll_catas(unsigned long dev_ptr) if (readl(priv->catas_err.map)) { /* If the device is off-line, we cannot try to recover it */ - if (pci_channel_offline(dev->pdev)) + if (pci_channel_offline(dev->persist->pdev)) mod_timer(&priv->catas_err.timer, round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); else { @@ -94,6 +94,7 @@ static void catas_reset(struct work_struct *work) { struct mlx4_priv *priv, *tmppriv; struct mlx4_dev *dev; + struct mlx4_dev_persistent *persist; LIST_HEAD(tlist); int ret; @@ -103,20 +104,20 @@ static void catas_reset(struct work_struct *work) spin_unlock_irq(&catas_lock); list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) { - struct pci_dev *pdev = priv->dev.pdev; + struct pci_dev *pdev = priv->dev.persist->pdev; /* If the device is off-line, we cannot reset it */ if (pci_channel_offline(pdev)) continue; - ret = mlx4_restart_one(priv->dev.pdev); + ret = mlx4_restart_one(priv->dev.persist->pdev); /* 'priv' now is not valid */ if (ret) pr_err("mlx4 %s: Reset failed (%d)\n", pci_name(pdev), ret); else { - dev = pci_get_drvdata(pdev); - mlx4_dbg(dev, "Reset succeeded\n"); + persist = pci_get_drvdata(pdev); + mlx4_dbg(persist->dev, "Reset succeeded\n"); } } } @@ -134,7 +135,7 @@ void mlx4_start_catas_poll(struct mlx4_dev *dev) init_timer(&priv->catas_err.timer); priv->catas_err.map = NULL; - addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) + + addr = pci_resource_start(dev->persist->pdev, priv->fw.catas_bar) + priv->fw.catas_offset; priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 5c93d1451c44..7cd90e6a4272 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -307,7 +307,7 @@ static int cmd_pending(struct mlx4_dev *dev) { u32 status; - if (pci_channel_offline(dev->pdev)) + if (pci_channel_offline(dev->persist->pdev)) return -EIO; status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); @@ -328,7 +328,7 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, mutex_lock(&cmd->hcr_mutex); - if (pci_channel_offline(dev->pdev)) { + if (pci_channel_offline(dev->persist->pdev)) { /* * Device is going through error recovery * and cannot accept commands. @@ -342,7 +342,7 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); while (cmd_pending(dev)) { - if (pci_channel_offline(dev->pdev)) { + if (pci_channel_offline(dev->persist->pdev)) { /* * Device is going through error recovery * and cannot accept commands. @@ -464,7 +464,7 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, down(&priv->cmd.poll_sem); - if (pci_channel_offline(dev->pdev)) { + if (pci_channel_offline(dev->persist->pdev)) { /* * Device is going through error recovery * and cannot accept commands. @@ -487,7 +487,7 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, end = msecs_to_jiffies(timeout) + jiffies; while (cmd_pending(dev) && time_before(jiffies, end)) { - if (pci_channel_offline(dev->pdev)) { + if (pci_channel_offline(dev->persist->pdev)) { /* * Device is going through error recovery * and cannot accept commands. @@ -612,7 +612,7 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, int out_is_imm, u32 in_modifier, u8 op_modifier, u16 op, unsigned long timeout, int native) { - if (pci_channel_offline(dev->pdev)) + if (pci_channel_offline(dev->persist->pdev)) return -EIO; if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { @@ -1997,11 +1997,12 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) if (mlx4_is_master(dev)) priv->mfunc.comm = - ioremap(pci_resource_start(dev->pdev, priv->fw.comm_bar) + + ioremap(pci_resource_start(dev->persist->pdev, + priv->fw.comm_bar) + priv->fw.comm_base, MLX4_COMM_PAGESIZE); else priv->mfunc.comm = - ioremap(pci_resource_start(dev->pdev, 2) + + ioremap(pci_resource_start(dev->persist->pdev, 2) + MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE); if (!priv->mfunc.comm) { mlx4_err(dev, "Couldn't map communication vector\n"); @@ -2107,9 +2108,9 @@ err_comm_admin: err_comm: iounmap(priv->mfunc.comm); err_vhcr: - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, - priv->mfunc.vhcr, - priv->mfunc.vhcr_dma); + dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, + priv->mfunc.vhcr, + priv->mfunc.vhcr_dma); priv->mfunc.vhcr = NULL; return -ENOMEM; } @@ -2130,8 +2131,8 @@ int mlx4_cmd_init(struct mlx4_dev *dev) } if (!mlx4_is_slave(dev) && !priv->cmd.hcr) { - priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + - MLX4_HCR_BASE, MLX4_HCR_SIZE); + priv->cmd.hcr = ioremap(pci_resource_start(dev->persist->pdev, + 0) + MLX4_HCR_BASE, MLX4_HCR_SIZE); if (!priv->cmd.hcr) { mlx4_err(dev, "Couldn't map command register\n"); goto err; @@ -2140,7 +2141,8 @@ int mlx4_cmd_init(struct mlx4_dev *dev) } if (mlx4_is_mfunc(dev) && !priv->mfunc.vhcr) { - priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE, + priv->mfunc.vhcr = dma_alloc_coherent(&dev->persist->pdev->dev, + PAGE_SIZE, &priv->mfunc.vhcr_dma, GFP_KERNEL); if (!priv->mfunc.vhcr) @@ -2150,7 +2152,8 @@ int mlx4_cmd_init(struct mlx4_dev *dev) } if (!priv->cmd.pool) { - priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, + priv->cmd.pool = pci_pool_create("mlx4_cmd", + dev->persist->pdev, MLX4_MAILBOX_SIZE, MLX4_MAILBOX_SIZE, 0); if (!priv->cmd.pool) @@ -2202,7 +2205,7 @@ void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask) } if (mlx4_is_mfunc(dev) && priv->mfunc.vhcr && (cleanup_mask & MLX4_CMD_CLEANUP_VHCR)) { - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, + dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, priv->mfunc.vhcr, priv->mfunc.vhcr_dma); priv->mfunc.vhcr = NULL; } @@ -2306,8 +2309,9 @@ u32 mlx4_comm_get_version(void) static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf) { - if ((vf < 0) || (vf >= dev->num_vfs)) { - mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", vf, dev->num_vfs); + if ((vf < 0) || (vf >= dev->persist->num_vfs)) { + mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", + vf, dev->persist->num_vfs); return -EINVAL; } @@ -2316,7 +2320,7 @@ static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf) int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave) { - if (slave < 1 || slave > dev->num_vfs) { + if (slave < 1 || slave > dev->persist->num_vfs) { mlx4_err(dev, "Bad slave number:%d (number of activated slaves: %lu)\n", slave, dev->num_slaves); @@ -2388,7 +2392,7 @@ struct mlx4_slaves_pport mlx4_phys_to_slaves_pport(struct mlx4_dev *dev, if (port <= 0 || port > dev->caps.num_ports) return slaves_pport; - for (i = 0; i < dev->num_vfs + 1; i++) { + for (i = 0; i < dev->persist->num_vfs + 1; i++) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, i); if (test_bit(port - 1, actv_ports.ports)) @@ -2408,7 +2412,7 @@ struct mlx4_slaves_pport mlx4_phys_to_slaves_pport_actv( bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX); - for (i = 0; i < dev->num_vfs + 1; i++) { + for (i = 0; i < dev->persist->num_vfs + 1; i++) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, i); if (bitmap_equal(crit_ports->ports, actv_ports.ports, diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 82322b1c8411..22da4d0d0f05 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -70,10 +70,10 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, /* Allocate HW buffers on provided NUMA node. * dev->numa_node is used in mtt range allocation flow. */ - set_dev_node(&mdev->dev->pdev->dev, node); + set_dev_node(&mdev->dev->persist->pdev->dev, node); err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres, cq->buf_size, 2 * PAGE_SIZE); - set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node); + set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node); if (err) goto err_cq; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 90e0f045a6bc..569eda9e83d6 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -92,7 +92,7 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) (u16) (mdev->dev->caps.fw_ver >> 32), (u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff), (u16) (mdev->dev->caps.fw_ver & 0xffff)); - strlcpy(drvinfo->bus_info, pci_name(mdev->dev->pdev), + strlcpy(drvinfo->bus_info, pci_name(mdev->dev->persist->pdev), sizeof(drvinfo->bus_info)); drvinfo->n_stats = 0; drvinfo->regdump_len = 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index 9f16f754137b..c643d2bbb7b9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -241,8 +241,8 @@ static void *mlx4_en_add(struct mlx4_dev *dev) spin_lock_init(&mdev->uar_lock); mdev->dev = dev; - mdev->dma_device = &(dev->pdev->dev); - mdev->pdev = dev->pdev; + mdev->dma_device = &dev->persist->pdev->dev; + mdev->pdev = dev->persist->pdev; mdev->device_up = false; mdev->LSO_support = !!(dev->caps.flags & (1 << 15)); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index d0d6dc1b8e46..43a3f9822f74 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2457,7 +2457,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, netif_set_real_num_tx_queues(dev, prof->tx_ring_num); netif_set_real_num_rx_queues(dev, prof->rx_ring_num); - SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev); + SET_NETDEV_DEV(dev, &mdev->dev->persist->pdev->dev); dev->dev_port = port - 1; /* diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index a0474eb94aa3..2ba5d368edce 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -387,10 +387,10 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, ring->rx_info, tmp); /* Allocate HW buffers on provided NUMA node */ - set_dev_node(&mdev->dev->pdev->dev, node); + set_dev_node(&mdev->dev->persist->pdev->dev, node); err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size, 2 * PAGE_SIZE); - set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node); + set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node); if (err) goto err_info; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 359bb1286eb5..55f9f5c5344e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -91,10 +91,10 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, ring->buf_size = ALIGN(size * ring->stride, MLX4_EN_PAGE_SIZE); /* Allocate HW buffers on provided NUMA node */ - set_dev_node(&mdev->dev->pdev->dev, node); + set_dev_node(&mdev->dev->persist->pdev->dev, node); err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size, 2 * PAGE_SIZE); - set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node); + set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node); if (err) { en_err(priv, "Failed allocating hwq resources\n"); goto err_bounce; diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 3d275fbaf0eb..7538c9ce98a9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -237,7 +237,7 @@ int mlx4_gen_guid_change_eqe(struct mlx4_dev *dev, int slave, u8 port) struct mlx4_eqe eqe; /*don't send if we don't have the that slave */ - if (dev->num_vfs < slave) + if (dev->persist->num_vfs < slave) return 0; memset(&eqe, 0, sizeof eqe); @@ -255,7 +255,7 @@ int mlx4_gen_port_state_change_eqe(struct mlx4_dev *dev, int slave, u8 port, struct mlx4_eqe eqe; /*don't send if we don't have the that slave */ - if (dev->num_vfs < slave) + if (dev->persist->num_vfs < slave) return 0; memset(&eqe, 0, sizeof eqe); @@ -310,7 +310,7 @@ static void set_all_slave_state(struct mlx4_dev *dev, u8 port, int event) struct mlx4_slaves_pport slaves_pport = mlx4_phys_to_slaves_pport(dev, port); - for (i = 0; i < dev->num_vfs + 1; i++) + for (i = 0; i < dev->persist->num_vfs + 1; i++) if (test_bit(i, slaves_pport.slaves)) set_and_calc_slave_port_state(dev, i, port, event, &gen_event); @@ -560,7 +560,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) mlx4_priv(dev)->sense.do_sense_port[port] = 1; if (!mlx4_is_master(dev)) break; - for (i = 0; i < dev->num_vfs + 1; i++) { + for (i = 0; i < dev->persist->num_vfs + 1; + i++) { if (!test_bit(i, slaves_port.slaves)) continue; if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) { @@ -596,7 +597,9 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) if (!mlx4_is_master(dev)) break; if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) - for (i = 0; i < dev->num_vfs + 1; i++) { + for (i = 0; + i < dev->persist->num_vfs + 1; + i++) { if (!test_bit(i, slaves_port.slaves)) continue; if (i == mlx4_master_func_num(dev)) @@ -865,7 +868,7 @@ static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) if (!priv->eq_table.uar_map[index]) { priv->eq_table.uar_map[index] = - ioremap(pci_resource_start(dev->pdev, 2) + + ioremap(pci_resource_start(dev->persist->pdev, 2) + ((eq->eqn / 4) << PAGE_SHIFT), PAGE_SIZE); if (!priv->eq_table.uar_map[index]) { @@ -928,8 +931,10 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent, eq_context = mailbox->buf; for (i = 0; i < npages; ++i) { - eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev, - PAGE_SIZE, &t, GFP_KERNEL); + eq->page_list[i].buf = dma_alloc_coherent(&dev->persist-> + pdev->dev, + PAGE_SIZE, &t, + GFP_KERNEL); if (!eq->page_list[i].buf) goto err_out_free_pages; @@ -995,7 +1000,7 @@ err_out_free_eq: err_out_free_pages: for (i = 0; i < npages; ++i) if (eq->page_list[i].buf) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, eq->page_list[i].buf, eq->page_list[i].map); @@ -1044,9 +1049,9 @@ static void mlx4_free_eq(struct mlx4_dev *dev, mlx4_mtt_cleanup(dev, &eq->mtt); for (i = 0; i < npages; ++i) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, - eq->page_list[i].buf, - eq->page_list[i].map); + dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, + eq->page_list[i].buf, + eq->page_list[i].map); kfree(eq->page_list); mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn, MLX4_USE_RR); @@ -1060,7 +1065,7 @@ static void mlx4_free_irqs(struct mlx4_dev *dev) int i, vec; if (eq_table->have_irq) - free_irq(dev->pdev->irq, dev); + free_irq(dev->persist->pdev->irq, dev); for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) if (eq_table->eq[i].have_irq) { @@ -1089,7 +1094,8 @@ static int mlx4_map_clr_int(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); - priv->clr_base = ioremap(pci_resource_start(dev->pdev, priv->fw.clr_int_bar) + + priv->clr_base = ioremap(pci_resource_start(dev->persist->pdev, + priv->fw.clr_int_bar) + priv->fw.clr_int_base, MLX4_CLR_INT_SIZE); if (!priv->clr_base) { mlx4_err(dev, "Couldn't map interrupt clear register, aborting\n"); @@ -1212,13 +1218,13 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) i * MLX4_IRQNAME_SIZE, MLX4_IRQNAME_SIZE, "mlx4-comp-%d@pci:%s", i, - pci_name(dev->pdev)); + pci_name(dev->persist->pdev)); } else { snprintf(priv->eq_table.irq_names + i * MLX4_IRQNAME_SIZE, MLX4_IRQNAME_SIZE, "mlx4-async@pci:%s", - pci_name(dev->pdev)); + pci_name(dev->persist->pdev)); } eq_name = priv->eq_table.irq_names + @@ -1235,8 +1241,8 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) snprintf(priv->eq_table.irq_names, MLX4_IRQNAME_SIZE, DRV_NAME "@pci:%s", - pci_name(dev->pdev)); - err = request_irq(dev->pdev->irq, mlx4_interrupt, + pci_name(dev->persist->pdev)); + err = request_irq(dev->persist->pdev->irq, mlx4_interrupt, IRQF_SHARED, priv->eq_table.irq_names, dev); if (err) goto err_out_async; diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c index 97c9b1db1d27..2a9dd460a95f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.c +++ b/drivers/net/ethernet/mellanox/mlx4/icm.c @@ -56,7 +56,7 @@ static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chu int i; if (chunk->nsg > 0) - pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, + pci_unmap_sg(dev->persist->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); for (i = 0; i < chunk->npages; ++i) @@ -69,7 +69,8 @@ static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk * int i; for (i = 0; i < chunk->npages; ++i) - dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length, + dma_free_coherent(&dev->persist->pdev->dev, + chunk->mem[i].length, lowmem_page_address(sg_page(&chunk->mem[i])), sg_dma_address(&chunk->mem[i])); } @@ -173,7 +174,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, --cur_order; if (coherent) - ret = mlx4_alloc_icm_coherent(&dev->pdev->dev, + ret = mlx4_alloc_icm_coherent(&dev->persist->pdev->dev, &chunk->mem[chunk->npages], cur_order, gfp_mask); else @@ -193,7 +194,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, if (coherent) ++chunk->nsg; else if (chunk->npages == MLX4_ICM_CHUNK_LEN) { - chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, + chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); @@ -208,7 +209,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, } if (!coherent && chunk) { - chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, + chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 03e9eb0dc761..abcee61f8a47 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -318,10 +318,11 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) return -ENODEV; } - if (dev_cap->uar_size > pci_resource_len(dev->pdev, 2)) { + if (dev_cap->uar_size > pci_resource_len(dev->persist->pdev, 2)) { mlx4_err(dev, "HCA reported UAR size of 0x%x bigger than PCI resource 2 size of 0x%llx, aborting\n", dev_cap->uar_size, - (unsigned long long) pci_resource_len(dev->pdev, 2)); + (unsigned long long) + pci_resource_len(dev->persist->pdev, 2)); return -ENODEV; } @@ -541,8 +542,10 @@ static int mlx4_get_pcie_dev_link_caps(struct mlx4_dev *dev, *speed = PCI_SPEED_UNKNOWN; *width = PCIE_LNK_WIDTH_UNKNOWN; - err1 = pcie_capability_read_dword(dev->pdev, PCI_EXP_LNKCAP, &lnkcap1); - err2 = pcie_capability_read_dword(dev->pdev, PCI_EXP_LNKCAP2, &lnkcap2); + err1 = pcie_capability_read_dword(dev->persist->pdev, PCI_EXP_LNKCAP, + &lnkcap1); + err2 = pcie_capability_read_dword(dev->persist->pdev, PCI_EXP_LNKCAP2, + &lnkcap2); if (!err2 && lnkcap2) { /* PCIe r3.0-compliant */ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) *speed = PCIE_SPEED_8_0GT; @@ -587,7 +590,7 @@ static void mlx4_check_pcie_caps(struct mlx4_dev *dev) return; } - err = pcie_get_minimum_link(dev->pdev, &speed, &width); + err = pcie_get_minimum_link(dev->persist->pdev, &speed, &width); if (err || speed == PCI_SPEED_UNKNOWN || width == PCIE_LNK_WIDTH_UNKNOWN) { mlx4_warn(dev, @@ -837,10 +840,12 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) if (dev->caps.uar_page_size * (dev->caps.num_uars - dev->caps.reserved_uars) > - pci_resource_len(dev->pdev, 2)) { + pci_resource_len(dev->persist->pdev, + 2)) { mlx4_err(dev, "HCA reported UAR region size of 0x%x bigger than PCI resource 2 size of 0x%llx, aborting\n", dev->caps.uar_page_size * dev->caps.num_uars, - (unsigned long long) pci_resource_len(dev->pdev, 2)); + (unsigned long long) + pci_resource_len(dev->persist->pdev, 2)); goto err_mem; } @@ -1492,9 +1497,9 @@ static int map_bf_area(struct mlx4_dev *dev) if (!dev->caps.bf_reg_size) return -ENXIO; - bf_start = pci_resource_start(dev->pdev, 2) + + bf_start = pci_resource_start(dev->persist->pdev, 2) + (dev->caps.num_uars << PAGE_SHIFT); - bf_len = pci_resource_len(dev->pdev, 2) - + bf_len = pci_resource_len(dev->persist->pdev, 2) - (dev->caps.num_uars << PAGE_SHIFT); priv->bf_mapping = io_mapping_create_wc(bf_start, bf_len); if (!priv->bf_mapping) @@ -1536,7 +1541,8 @@ static int map_internal_clock(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); priv->clock_mapping = - ioremap(pci_resource_start(dev->pdev, priv->fw.clock_bar) + + ioremap(pci_resource_start(dev->persist->pdev, + priv->fw.clock_bar) + priv->fw.clock_offset, MLX4_CLOCK_SIZE); if (!priv->clock_mapping) @@ -1705,7 +1711,8 @@ static void choose_steering_mode(struct mlx4_dev *dev, if (mlx4_log_num_mgm_entry_size <= 0 && dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN && (!mlx4_is_mfunc(dev) || - (dev_cap->fs_max_num_qp_per_entry >= (dev->num_vfs + 1))) && + (dev_cap->fs_max_num_qp_per_entry >= + (dev->persist->num_vfs + 1))) && choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry) >= MLX4_MIN_MGM_LOG_ENTRY_SIZE) { dev->oper_log_mgm_entry_size = @@ -2288,7 +2295,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) for (i = 0; i < nreq; ++i) entries[i].entry = i; - nreq = pci_enable_msix_range(dev->pdev, entries, 2, nreq); + nreq = pci_enable_msix_range(dev->persist->pdev, entries, 2, + nreq); if (nreq < 0) { kfree(entries); @@ -2316,7 +2324,7 @@ no_msi: dev->caps.comp_pool = 0; for (i = 0; i < 2; ++i) - priv->eq_table.eq[i].irq = dev->pdev->irq; + priv->eq_table.eq[i].irq = dev->persist->pdev->irq; } static int mlx4_init_port_info(struct mlx4_dev *dev, int port) @@ -2344,7 +2352,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) info->port_attr.show = show_port_type; sysfs_attr_init(&info->port_attr.attr); - err = device_create_file(&dev->pdev->dev, &info->port_attr); + err = device_create_file(&dev->persist->pdev->dev, &info->port_attr); if (err) { mlx4_err(dev, "Failed to create file for port %d\n", port); info->port = -1; @@ -2361,10 +2369,12 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) info->port_mtu_attr.show = show_port_ib_mtu; sysfs_attr_init(&info->port_mtu_attr.attr); - err = device_create_file(&dev->pdev->dev, &info->port_mtu_attr); + err = device_create_file(&dev->persist->pdev->dev, + &info->port_mtu_attr); if (err) { mlx4_err(dev, "Failed to create mtu file for port %d\n", port); - device_remove_file(&info->dev->pdev->dev, &info->port_attr); + device_remove_file(&info->dev->persist->pdev->dev, + &info->port_attr); info->port = -1; } @@ -2376,8 +2386,9 @@ static void mlx4_cleanup_port_info(struct mlx4_port_info *info) if (info->port < 0) return; - device_remove_file(&info->dev->pdev->dev, &info->port_attr); - device_remove_file(&info->dev->pdev->dev, &info->port_mtu_attr); + device_remove_file(&info->dev->persist->pdev->dev, &info->port_attr); + device_remove_file(&info->dev->persist->pdev->dev, + &info->port_mtu_attr); } static int mlx4_init_steering(struct mlx4_dev *dev) @@ -2444,10 +2455,11 @@ static int mlx4_get_ownership(struct mlx4_dev *dev) void __iomem *owner; u32 ret; - if (pci_channel_offline(dev->pdev)) + if (pci_channel_offline(dev->persist->pdev)) return -EIO; - owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, + owner = ioremap(pci_resource_start(dev->persist->pdev, 0) + + MLX4_OWNER_BASE, MLX4_OWNER_SIZE); if (!owner) { mlx4_err(dev, "Failed to obtain ownership bit\n"); @@ -2463,10 +2475,11 @@ static void mlx4_free_ownership(struct mlx4_dev *dev) { void __iomem *owner; - if (pci_channel_offline(dev->pdev)) + if (pci_channel_offline(dev->persist->pdev)) return; - owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, + owner = ioremap(pci_resource_start(dev->persist->pdev, 0) + + MLX4_OWNER_BASE, MLX4_OWNER_SIZE); if (!owner) { mlx4_err(dev, "Failed to obtain ownership bit\n"); @@ -2514,13 +2527,13 @@ static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev, dev_flags |= MLX4_FLAG_SRIOV | MLX4_FLAG_MASTER; dev_flags &= ~MLX4_FLAG_SLAVE; - dev->num_vfs = total_vfs; + dev->persist->num_vfs = total_vfs; } return dev_flags; disable_sriov: atomic_dec(&pf_loading); - dev->num_vfs = 0; + dev->persist->num_vfs = 0; kfree(dev->dev_vfs); return dev_flags & ~MLX4_FLAG_MASTER; } @@ -2607,7 +2620,7 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data, existing_vfs = pci_num_vf(pdev); if (existing_vfs) dev->flags |= MLX4_FLAG_SRIOV; - dev->num_vfs = total_vfs; + dev->persist->num_vfs = total_vfs; } } @@ -2771,12 +2784,14 @@ slave_start: dev->caps.num_ports); goto err_close; } - memcpy(dev->nvfs, nvfs, sizeof(dev->nvfs)); + memcpy(dev->persist->nvfs, nvfs, sizeof(dev->persist->nvfs)); - for (i = 0; i < sizeof(dev->nvfs)/sizeof(dev->nvfs[0]); i++) { + for (i = 0; + i < sizeof(dev->persist->nvfs)/ + sizeof(dev->persist->nvfs[0]); i++) { unsigned j; - for (j = 0; j < dev->nvfs[i]; ++sum, ++j) { + for (j = 0; j < dev->persist->nvfs[i]; ++sum, ++j) { dev->dev_vfs[sum].min_port = i < 2 ? i + 1 : 1; dev->dev_vfs[sum].n_ports = i < 2 ? 1 : dev->caps.num_ports; @@ -2846,7 +2861,7 @@ slave_start: priv->removed = 0; - if (mlx4_is_master(dev) && dev->num_vfs) + if (mlx4_is_master(dev) && dev->persist->num_vfs) atomic_dec(&pf_loading); kfree(dev_cap); @@ -2908,7 +2923,7 @@ err_sriov: if (dev->flags & MLX4_FLAG_SRIOV && !existing_vfs) pci_disable_sriov(pdev); - if (mlx4_is_master(dev) && dev->num_vfs) + if (mlx4_is_master(dev) && dev->persist->num_vfs) atomic_dec(&pf_loading); kfree(priv->dev.dev_vfs); @@ -3076,20 +3091,28 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM; dev = &priv->dev; - dev->pdev = pdev; - pci_set_drvdata(pdev, dev); + dev->persist = kzalloc(sizeof(*dev->persist), GFP_KERNEL); + if (!dev->persist) { + kfree(priv); + return -ENOMEM; + } + dev->persist->pdev = pdev; + dev->persist->dev = dev; + pci_set_drvdata(pdev, dev->persist); priv->pci_dev_data = id->driver_data; ret = __mlx4_init_one(pdev, id->driver_data, priv); - if (ret) + if (ret) { + kfree(dev->persist); kfree(priv); - + } return ret; } static void mlx4_unload_one(struct pci_dev *pdev) { - struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); int pci_dev_data; int p; @@ -3155,7 +3178,7 @@ static void mlx4_unload_one(struct pci_dev *pdev) mlx4_warn(dev, "Disabling SR-IOV\n"); pci_disable_sriov(pdev); dev->flags &= ~MLX4_FLAG_SRIOV; - dev->num_vfs = 0; + dev->persist->num_vfs = 0; } if (!mlx4_is_slave(dev)) @@ -3175,26 +3198,29 @@ static void mlx4_unload_one(struct pci_dev *pdev) static void mlx4_remove_one(struct pci_dev *pdev) { - struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); mlx4_unload_one(pdev); pci_release_regions(pdev); pci_disable_device(pdev); + kfree(dev->persist); kfree(priv); pci_set_drvdata(pdev, NULL); } int mlx4_restart_one(struct pci_dev *pdev) { - struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); int nvfs[MLX4_MAX_PORTS + 1] = {0, 0, 0}; int pci_dev_data, err, total_vfs; pci_dev_data = priv->pci_dev_data; - total_vfs = dev->num_vfs; - memcpy(nvfs, dev->nvfs, sizeof(dev->nvfs)); + total_vfs = dev->persist->num_vfs; + memcpy(nvfs, dev->persist->nvfs, sizeof(dev->persist->nvfs)); mlx4_unload_one(pdev); err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index bdd4eea2247c..faa37ab75a9d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -221,16 +221,17 @@ extern int mlx4_debug_level; #define mlx4_dbg(mdev, format, ...) \ do { \ if (mlx4_debug_level) \ - dev_printk(KERN_DEBUG, &(mdev)->pdev->dev, format, \ + dev_printk(KERN_DEBUG, \ + &(mdev)->persist->pdev->dev, format, \ ##__VA_ARGS__); \ } while (0) #define mlx4_err(mdev, format, ...) \ - dev_err(&(mdev)->pdev->dev, format, ##__VA_ARGS__) + dev_err(&(mdev)->persist->pdev->dev, format, ##__VA_ARGS__) #define mlx4_info(mdev, format, ...) \ - dev_info(&(mdev)->pdev->dev, format, ##__VA_ARGS__) + dev_info(&(mdev)->persist->pdev->dev, format, ##__VA_ARGS__) #define mlx4_warn(mdev, format, ...) \ - dev_warn(&(mdev)->pdev->dev, format, ##__VA_ARGS__) + dev_warn(&(mdev)->persist->pdev->dev, format, ##__VA_ARGS__) extern int mlx4_log_num_mgm_entry_size; extern int log_mtts_per_seg; diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index 7094a9c70fd5..8dbdf1d29357 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -708,13 +708,13 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, if (!mtts) return -ENOMEM; - dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle, + dma_sync_single_for_cpu(&dev->persist->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); for (i = 0; i < npages; ++i) mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - dma_sync_single_for_device(&dev->pdev->dev, dma_handle, + dma_sync_single_for_device(&dev->persist->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); return 0; @@ -1020,13 +1020,13 @@ int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list /* Make sure MPT status is visible before writing MTT entries */ wmb(); - dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle, + dma_sync_single_for_cpu(&dev->persist->pdev->dev, fmr->dma_handle, npages * sizeof(u64), DMA_TO_DEVICE); for (i = 0; i < npages; ++i) fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - dma_sync_single_for_device(&dev->pdev->dev, fmr->dma_handle, + dma_sync_single_for_device(&dev->persist->pdev->dev, fmr->dma_handle, npages * sizeof(u64), DMA_TO_DEVICE); fmr->mpt->key = cpu_to_be32(key); diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c index 74216071201f..a42b4c0a9ed9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/pd.c +++ b/drivers/net/ethernet/mellanox/mlx4/pd.c @@ -151,11 +151,13 @@ int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) return -ENOMEM; if (mlx4_is_slave(dev)) - offset = uar->index % ((int) pci_resource_len(dev->pdev, 2) / + offset = uar->index % ((int)pci_resource_len(dev->persist->pdev, + 2) / dev->caps.uar_page_size); else offset = uar->index; - uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + offset; + uar->pfn = (pci_resource_start(dev->persist->pdev, 2) >> PAGE_SHIFT) + + offset; uar->map = NULL; return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 30eb1ead0fe6..9f268f05290a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -553,9 +553,9 @@ int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port) slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( dev, &exclusive_ports); slave_gid -= bitmap_weight(slaves_pport_actv.slaves, - dev->num_vfs + 1); + dev->persist->num_vfs + 1); } - vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; + vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs)) return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1; return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs; @@ -590,10 +590,10 @@ int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port) slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( dev, &exclusive_ports); slave_gid -= bitmap_weight(slaves_pport_actv.slaves, - dev->num_vfs + 1); + dev->persist->num_vfs + 1); } gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; - vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; + vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; if (slave_gid <= gids % vfs) return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1); @@ -644,7 +644,7 @@ void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave) int num_eth_ports, err; int i; - if (slave < 0 || slave > dev->num_vfs) + if (slave < 0 || slave > dev->persist->num_vfs) return; actv_ports = mlx4_get_active_ports(dev, slave); @@ -1214,7 +1214,8 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, return -EINVAL; slaves_pport = mlx4_phys_to_slaves_pport(dev, port); - num_vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; + num_vfs = bitmap_weight(slaves_pport.slaves, + dev->persist->num_vfs + 1) - 1; for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid, @@ -1258,7 +1259,7 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, dev, &exclusive_ports); num_vfs_before += bitmap_weight( slaves_pport_actv.slaves, - dev->num_vfs + 1); + dev->persist->num_vfs + 1); } /* candidate_slave_gid isn't necessarily the correct slave, but @@ -1288,7 +1289,7 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, dev, &exclusive_ports); slave_gid += bitmap_weight( slaves_pport_actv.slaves, - dev->num_vfs + 1); + dev->persist->num_vfs + 1); } } *slave_id = slave_gid; diff --git a/drivers/net/ethernet/mellanox/mlx4/reset.c b/drivers/net/ethernet/mellanox/mlx4/reset.c index ea1c6d092145..0076d88587ca 100644 --- a/drivers/net/ethernet/mellanox/mlx4/reset.c +++ b/drivers/net/ethernet/mellanox/mlx4/reset.c @@ -76,19 +76,21 @@ int mlx4_reset(struct mlx4_dev *dev) goto out; } - pcie_cap = pci_pcie_cap(dev->pdev); + pcie_cap = pci_pcie_cap(dev->persist->pdev); for (i = 0; i < 64; ++i) { if (i == 22 || i == 23) continue; - if (pci_read_config_dword(dev->pdev, i * 4, hca_header + i)) { + if (pci_read_config_dword(dev->persist->pdev, i * 4, + hca_header + i)) { err = -ENODEV; mlx4_err(dev, "Couldn't save HCA PCI header, aborting\n"); goto out; } } - reset = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_RESET_BASE, + reset = ioremap(pci_resource_start(dev->persist->pdev, 0) + + MLX4_RESET_BASE, MLX4_RESET_SIZE); if (!reset) { err = -ENOMEM; @@ -122,8 +124,8 @@ int mlx4_reset(struct mlx4_dev *dev) end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES; do { - if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) && - vendor != 0xffff) + if (!pci_read_config_word(dev->persist->pdev, PCI_VENDOR_ID, + &vendor) && vendor != 0xffff) break; msleep(1); @@ -138,14 +140,16 @@ int mlx4_reset(struct mlx4_dev *dev) /* Now restore the PCI headers */ if (pcie_cap) { devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4]; - if (pcie_capability_write_word(dev->pdev, PCI_EXP_DEVCTL, + if (pcie_capability_write_word(dev->persist->pdev, + PCI_EXP_DEVCTL, devctl)) { err = -ENODEV; mlx4_err(dev, "Couldn't restore HCA PCI Express Device Control register, aborting\n"); goto out; } linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4]; - if (pcie_capability_write_word(dev->pdev, PCI_EXP_LNKCTL, + if (pcie_capability_write_word(dev->persist->pdev, + PCI_EXP_LNKCTL, linkctl)) { err = -ENODEV; mlx4_err(dev, "Couldn't restore HCA PCI Express Link control register, aborting\n"); @@ -157,7 +161,8 @@ int mlx4_reset(struct mlx4_dev *dev) if (i * 4 == PCI_COMMAND) continue; - if (pci_write_config_dword(dev->pdev, i * 4, hca_header[i])) { + if (pci_write_config_dword(dev->persist->pdev, i * 4, + hca_header[i])) { err = -ENODEV; mlx4_err(dev, "Couldn't restore HCA reg %x, aborting\n", i); @@ -165,7 +170,7 @@ int mlx4_reset(struct mlx4_dev *dev) } } - if (pci_write_config_dword(dev->pdev, PCI_COMMAND, + if (pci_write_config_dword(dev->persist->pdev, PCI_COMMAND, hca_header[PCI_COMMAND / 4])) { err = -ENODEV; mlx4_err(dev, "Couldn't restore HCA COMMAND, aborting\n"); diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 4efbd1eca611..3e93879bccce 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -309,12 +309,13 @@ static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, int allocated, free, reserved, guaranteed, from_free; int from_rsvd; - if (slave > dev->num_vfs) + if (slave > dev->persist->num_vfs) return -EINVAL; spin_lock(&res_alloc->alloc_lock); allocated = (port > 0) ? - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] : + res_alloc->allocated[(port - 1) * + (dev->persist->num_vfs + 1) + slave] : res_alloc->allocated[slave]; free = (port > 0) ? res_alloc->res_port_free[port - 1] : res_alloc->res_free; @@ -352,7 +353,8 @@ static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, if (!err) { /* grant the request */ if (port > 0) { - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] += count; + res_alloc->allocated[(port - 1) * + (dev->persist->num_vfs + 1) + slave] += count; res_alloc->res_port_free[port - 1] -= count; res_alloc->res_port_rsvd[port - 1] -= from_rsvd; } else { @@ -376,13 +378,14 @@ static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave, &priv->mfunc.master.res_tracker.res_alloc[res_type]; int allocated, guaranteed, from_rsvd; - if (slave > dev->num_vfs) + if (slave > dev->persist->num_vfs) return; spin_lock(&res_alloc->alloc_lock); allocated = (port > 0) ? - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] : + res_alloc->allocated[(port - 1) * + (dev->persist->num_vfs + 1) + slave] : res_alloc->allocated[slave]; guaranteed = res_alloc->guaranteed[slave]; @@ -397,7 +400,8 @@ static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave, } if (port > 0) { - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] -= count; + res_alloc->allocated[(port - 1) * + (dev->persist->num_vfs + 1) + slave] -= count; res_alloc->res_port_free[port - 1] += count; res_alloc->res_port_rsvd[port - 1] += from_rsvd; } else { @@ -415,7 +419,8 @@ static inline void initialize_res_quotas(struct mlx4_dev *dev, enum mlx4_resource res_type, int vf, int num_instances) { - res_alloc->guaranteed[vf] = num_instances / (2 * (dev->num_vfs + 1)); + res_alloc->guaranteed[vf] = num_instances / + (2 * (dev->persist->num_vfs + 1)); res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf]; if (vf == mlx4_master_func_num(dev)) { res_alloc->res_free = num_instances; @@ -486,21 +491,26 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev) for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { struct resource_allocator *res_alloc = &priv->mfunc.master.res_tracker.res_alloc[i]; - res_alloc->quota = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); - res_alloc->guaranteed = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); + res_alloc->quota = kmalloc((dev->persist->num_vfs + 1) * + sizeof(int), GFP_KERNEL); + res_alloc->guaranteed = kmalloc((dev->persist->num_vfs + 1) * + sizeof(int), GFP_KERNEL); if (i == RES_MAC || i == RES_VLAN) res_alloc->allocated = kzalloc(MLX4_MAX_PORTS * - (dev->num_vfs + 1) * sizeof(int), - GFP_KERNEL); + (dev->persist->num_vfs + + 1) * + sizeof(int), GFP_KERNEL); else - res_alloc->allocated = kzalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); + res_alloc->allocated = kzalloc((dev->persist-> + num_vfs + 1) * + sizeof(int), GFP_KERNEL); if (!res_alloc->quota || !res_alloc->guaranteed || !res_alloc->allocated) goto no_mem_err; spin_lock_init(&res_alloc->alloc_lock); - for (t = 0; t < dev->num_vfs + 1; t++) { + for (t = 0; t < dev->persist->num_vfs + 1; t++) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, t); switch (i) { -- cgit v1.2.1 From dd0eefe3abbf47442db296bf68f27eb2860c1cdf Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Sun, 25 Jan 2015 16:59:36 +0200 Subject: net/mlx4_core: Set device configuration data to be persistent across reset When an HCA enters an internal error state, this is detected by the driver. The driver then should reset the HCA and restart the software stack. Keep ports information and some SRIOV configuration in a persistent area to have it valid across reset. Signed-off-by: Yishai Hadas Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 45 +++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index abcee61f8a47..2c5a555dff89 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -3109,18 +3109,34 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ret; } +static void mlx4_clean_dev(struct mlx4_dev *dev) +{ + struct mlx4_dev_persistent *persist = dev->persist; + struct mlx4_priv *priv = mlx4_priv(dev); + + memset(priv, 0, sizeof(*priv)); + priv->dev.persist = persist; +} + static void mlx4_unload_one(struct pci_dev *pdev) { struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); int pci_dev_data; - int p; + int p, i; int active_vfs = 0; if (priv->removed) return; + /* saving current ports type for further use */ + for (i = 0; i < dev->caps.num_ports; i++) { + dev->persist->curr_port_type[i] = dev->caps.port_type[i + 1]; + dev->persist->curr_port_poss_type[i] = dev->caps. + possible_type[i + 1]; + } + pci_dev_data = priv->pci_dev_data; /* Disabling SR-IOV is not allowed while there are active vf's */ @@ -3191,7 +3207,7 @@ static void mlx4_unload_one(struct pci_dev *pdev) kfree(dev->caps.qp1_proxy); kfree(dev->dev_vfs); - memset(priv, 0, sizeof(*priv)); + mlx4_clean_dev(dev); priv->pci_dev_data = pci_dev_data; priv->removed = 1; } @@ -3210,6 +3226,25 @@ static void mlx4_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +static int restore_current_port_types(struct mlx4_dev *dev, + enum mlx4_port_type *types, + enum mlx4_port_type *poss_types) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err, i; + + mlx4_stop_sense(dev); + + mutex_lock(&priv->port_mutex); + for (i = 0; i < dev->caps.num_ports; i++) + dev->caps.possible_type[i + 1] = poss_types[i]; + err = mlx4_change_port_types(dev, types); + mlx4_start_sense(dev); + mutex_unlock(&priv->port_mutex); + + return err; +} + int mlx4_restart_one(struct pci_dev *pdev) { struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); @@ -3230,6 +3265,12 @@ int mlx4_restart_one(struct pci_dev *pdev) return err; } + err = restore_current_port_types(dev, dev->persist->curr_port_type, + dev->persist->curr_port_poss_type); + if (err) + mlx4_err(dev, "could not restore original port types (%d)\n", + err); + return err; } -- cgit v1.2.1 From ad9a0bf08ffbf32b8f292c3bb78ca0f24bb8f6b2 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Sun, 25 Jan 2015 16:59:37 +0200 Subject: net/mlx4_core: Refactor the catas flow to work per device Using a WQ per device instead of a single global WQ, this allows independent reset handling per device even when SRIOV is used. This comes as a pre-patch for supporting chip reset for both native and SRIOV. Signed-off-by: Yishai Hadas Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/catas.c | 75 ++++++++++++++---------------- drivers/net/ethernet/mellanox/mlx4/main.c | 12 ++++- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 3 +- 3 files changed, 46 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 1a102c9bac99..5bb9aa6e281d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -40,10 +40,7 @@ enum { MLX4_CATAS_POLL_INTERVAL = 5 * HZ, }; -static DEFINE_SPINLOCK(catas_lock); -static LIST_HEAD(catas_list); -static struct work_struct catas_work; static int internal_err_reset = 1; module_param(internal_err_reset, int, 0644); @@ -77,13 +74,9 @@ static void poll_catas(unsigned long dev_ptr) dump_err_buf(dev); mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); - if (internal_err_reset) { - spin_lock(&catas_lock); - list_add(&priv->catas_err.list, &catas_list); - spin_unlock(&catas_lock); - - queue_work(mlx4_wq, &catas_work); - } + if (internal_err_reset) + queue_work(dev->persist->catas_wq, + &dev->persist->catas_work); } } else mod_timer(&priv->catas_err.timer, @@ -92,34 +85,23 @@ static void poll_catas(unsigned long dev_ptr) static void catas_reset(struct work_struct *work) { - struct mlx4_priv *priv, *tmppriv; - struct mlx4_dev *dev; - struct mlx4_dev_persistent *persist; - - LIST_HEAD(tlist); + struct mlx4_dev_persistent *persist = + container_of(work, struct mlx4_dev_persistent, + catas_work); + struct pci_dev *pdev = persist->pdev; int ret; - spin_lock_irq(&catas_lock); - list_splice_init(&catas_list, &tlist); - spin_unlock_irq(&catas_lock); - - list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) { - struct pci_dev *pdev = priv->dev.persist->pdev; - - /* If the device is off-line, we cannot reset it */ - if (pci_channel_offline(pdev)) - continue; + /* If the device is off-line, we cannot reset it */ + if (pci_channel_offline(pdev)) + return; - ret = mlx4_restart_one(priv->dev.persist->pdev); - /* 'priv' now is not valid */ - if (ret) - pr_err("mlx4 %s: Reset failed (%d)\n", - pci_name(pdev), ret); - else { - persist = pci_get_drvdata(pdev); - mlx4_dbg(persist->dev, "Reset succeeded\n"); - } - } + ret = mlx4_restart_one(pdev); + /* 'priv' now is not valid */ + if (ret) + pr_err("mlx4 %s: Reset failed (%d)\n", + pci_name(pdev), ret); + else + mlx4_dbg(persist->dev, "Reset succeeded\n"); } void mlx4_start_catas_poll(struct mlx4_dev *dev) @@ -158,15 +140,26 @@ void mlx4_stop_catas_poll(struct mlx4_dev *dev) del_timer_sync(&priv->catas_err.timer); - if (priv->catas_err.map) + if (priv->catas_err.map) { iounmap(priv->catas_err.map); + priv->catas_err.map = NULL; + } +} - spin_lock_irq(&catas_lock); - list_del(&priv->catas_err.list); - spin_unlock_irq(&catas_lock); +int mlx4_catas_init(struct mlx4_dev *dev) +{ + INIT_WORK(&dev->persist->catas_work, catas_reset); + dev->persist->catas_wq = create_singlethread_workqueue("mlx4_health"); + if (!dev->persist->catas_wq) + return -ENOMEM; + + return 0; } -void __init mlx4_catas_init(void) +void mlx4_catas_end(struct mlx4_dev *dev) { - INIT_WORK(&catas_work, catas_reset); + if (dev->persist->catas_wq) { + destroy_workqueue(dev->persist->catas_wq); + dev->persist->catas_wq = NULL; + } } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 2c5a555dff89..a61694cc1476 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -3064,11 +3064,19 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data, } } - err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv); + err = mlx4_catas_init(&priv->dev); if (err) goto err_release_regions; + + err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv); + if (err) + goto err_catas; + return 0; +err_catas: + mlx4_catas_end(&priv->dev); + err_release_regions: pci_release_regions(pdev); @@ -3219,6 +3227,7 @@ static void mlx4_remove_one(struct pci_dev *pdev) struct mlx4_priv *priv = mlx4_priv(dev); mlx4_unload_one(pdev); + mlx4_catas_end(dev); pci_release_regions(pdev); pci_disable_device(pdev); kfree(dev->persist); @@ -3403,7 +3412,6 @@ static int __init mlx4_init(void) if (mlx4_verify_params()) return -EINVAL; - mlx4_catas_init(); mlx4_wq = create_singlethread_workqueue("mlx4"); if (!mlx4_wq) diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index faa37ab75a9d..d41af84f965b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -995,7 +995,8 @@ void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn); void mlx4_start_catas_poll(struct mlx4_dev *dev); void mlx4_stop_catas_poll(struct mlx4_dev *dev); -void mlx4_catas_init(void); +int mlx4_catas_init(struct mlx4_dev *dev); +void mlx4_catas_end(struct mlx4_dev *dev); int mlx4_restart_one(struct pci_dev *pdev); int mlx4_register_device(struct mlx4_dev *dev); void mlx4_unregister_device(struct mlx4_dev *dev); -- cgit v1.2.1 From f6bc11e42646e661e699a5593cbd1e9dba7191d0 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Sun, 25 Jan 2015 16:59:38 +0200 Subject: net/mlx4_core: Enhance the catas flow to support device reset This includes: - resetting the chip when a fatal error is detected (the current code does not do this). - exposing the ability to enter error state from outside the catas code by calling its functionality. (E.g. FW Command timeout, AER error). - managing a persistent device state. This is needed to sync between reset flow cases. Signed-off-by: Yishai Hadas Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/catas.c | 122 ++++++++++++++++++++++------- drivers/net/ethernet/mellanox/mlx4/main.c | 6 ++ drivers/net/ethernet/mellanox/mlx4/mlx4.h | 2 +- 3 files changed, 101 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 5bb9aa6e281d..588d6b5e1211 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -48,6 +48,83 @@ MODULE_PARM_DESC(internal_err_reset, "Reset device on internal errors if non-zero" " (default 1, in SRIOV mode default is 0)"); +static int read_vendor_id(struct mlx4_dev *dev) +{ + u16 vendor_id = 0; + int ret; + + ret = pci_read_config_word(dev->persist->pdev, 0, &vendor_id); + if (ret) { + mlx4_err(dev, "Failed to read vendor ID, ret=%d\n", ret); + return ret; + } + + if (vendor_id == 0xffff) { + mlx4_err(dev, "PCI can't be accessed to read vendor id\n"); + return -EINVAL; + } + + return 0; +} + +static int mlx4_reset_master(struct mlx4_dev *dev) +{ + int err = 0; + + if (!pci_channel_offline(dev->persist->pdev)) { + err = read_vendor_id(dev); + /* If PCI can't be accessed to read vendor ID we assume that its + * link was disabled and chip was already reset. + */ + if (err) + return 0; + + err = mlx4_reset(dev); + if (err) + mlx4_err(dev, "Fail to reset HCA\n"); + } + + return err; +} + +void mlx4_enter_error_state(struct mlx4_dev_persistent *persist) +{ + int err; + struct mlx4_dev *dev; + + if (!internal_err_reset) + return; + + mutex_lock(&persist->device_state_mutex); + if (persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + goto out; + + dev = persist->dev; + mlx4_err(dev, "device is going to be reset\n"); + err = mlx4_reset_master(dev); + BUG_ON(err != 0); + + dev->persist->state |= MLX4_DEVICE_STATE_INTERNAL_ERROR; + mlx4_err(dev, "device was reset successfully\n"); + mutex_unlock(&persist->device_state_mutex); + + /* At that step HW was already reset, now notify clients */ + mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); + return; + +out: + mutex_unlock(&persist->device_state_mutex); +} + +static void mlx4_handle_error_state(struct mlx4_dev_persistent *persist) +{ + int err = 0; + + mlx4_enter_error_state(persist); + err = mlx4_restart_one(persist->pdev); + mlx4_info(persist->dev, "mlx4_restart_one was ended, ret=%d\n", err); +} + static void dump_err_buf(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -66,21 +143,22 @@ static void poll_catas(unsigned long dev_ptr) struct mlx4_priv *priv = mlx4_priv(dev); if (readl(priv->catas_err.map)) { - /* If the device is off-line, we cannot try to recover it */ - if (pci_channel_offline(dev->persist->pdev)) - mod_timer(&priv->catas_err.timer, - round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); - else { - dump_err_buf(dev); - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); - - if (internal_err_reset) - queue_work(dev->persist->catas_wq, - &dev->persist->catas_work); - } - } else - mod_timer(&priv->catas_err.timer, - round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); + dump_err_buf(dev); + goto internal_err; + } + + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { + mlx4_warn(dev, "Internal error mark was detected on device\n"); + goto internal_err; + } + + mod_timer(&priv->catas_err.timer, + round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); + return; + +internal_err: + if (internal_err_reset) + queue_work(dev->persist->catas_wq, &dev->persist->catas_work); } static void catas_reset(struct work_struct *work) @@ -88,20 +166,8 @@ static void catas_reset(struct work_struct *work) struct mlx4_dev_persistent *persist = container_of(work, struct mlx4_dev_persistent, catas_work); - struct pci_dev *pdev = persist->pdev; - int ret; - - /* If the device is off-line, we cannot reset it */ - if (pci_channel_offline(pdev)) - return; - ret = mlx4_restart_one(pdev); - /* 'priv' now is not valid */ - if (ret) - pr_err("mlx4 %s: Reset failed (%d)\n", - pci_name(pdev), ret); - else - mlx4_dbg(persist->dev, "Reset succeeded\n"); + mlx4_handle_error_state(persist); } void mlx4_start_catas_poll(struct mlx4_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index a61694cc1476..dc2d910fcc88 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2624,6 +2624,11 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data, } } + /* on load remove any previous indication of internal error, + * device is up. + */ + dev->persist->state = MLX4_DEVICE_STATE_UP; + slave_start: err = mlx4_cmd_init(dev); if (err) { @@ -3108,6 +3113,7 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) dev->persist->dev = dev; pci_set_drvdata(pdev, dev->persist); priv->pci_dev_data = id->driver_data; + mutex_init(&dev->persist->device_state_mutex); ret = __mlx4_init_one(pdev, id->driver_data, priv); if (ret) { diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index d41af84f965b..aa1ecbc5a606 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -1178,7 +1178,7 @@ void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type); void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type); -void mlx4_handle_catas_err(struct mlx4_dev *dev); +void mlx4_enter_error_state(struct mlx4_dev_persistent *persist); int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, enum mlx4_port_type *type); -- cgit v1.2.1 From f5aef5aa35063f2b45c3605871cd525d0cb7fb7a Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Sun, 25 Jan 2015 16:59:39 +0200 Subject: net/mlx4_core: Activate reset flow upon fatal command cases We activate reset flow upon command fatal errors, when the device enters an erroneous state, and must be reset. The cases below are assumed to be fatal: FW command timed-out, an error from FW on closing commands, pci is offline when posting/pending a command. In those cases we place the device into an error state: chip is reset, pending commands are awakened and completed immediately. Subsequent commands will return immediately. The return code in the above cases will depend on the command. Commands which free and close resources will return success (because the chip was reset, so callers may safely free their kernel resources). Other commands will return -EIO. Since the device's state was marked as error, the catas poller will detect this and restart the device's software stack (as is done when a FW internal error is directly detected). The device state is protected by a persistent mutex lives on its mlx4_dev, as such no need any more for the hcr_mutex which is removed. Signed-off-by: Yishai Hadas Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/catas.c | 11 +- drivers/net/ethernet/mellanox/mlx4/cmd.c | 163 +++++++++++++++++++++++++---- drivers/net/ethernet/mellanox/mlx4/mcg.c | 3 + drivers/net/ethernet/mellanox/mlx4/mlx4.h | 2 +- 4 files changed, 152 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 588d6b5e1211..63f14ffcc906 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -42,8 +42,8 @@ enum { -static int internal_err_reset = 1; -module_param(internal_err_reset, int, 0644); +int mlx4_internal_err_reset = 1; +module_param_named(internal_err_reset, mlx4_internal_err_reset, int, 0644); MODULE_PARM_DESC(internal_err_reset, "Reset device on internal errors if non-zero" " (default 1, in SRIOV mode default is 0)"); @@ -92,7 +92,7 @@ void mlx4_enter_error_state(struct mlx4_dev_persistent *persist) int err; struct mlx4_dev *dev; - if (!internal_err_reset) + if (!mlx4_internal_err_reset) return; mutex_lock(&persist->device_state_mutex); @@ -110,6 +110,7 @@ void mlx4_enter_error_state(struct mlx4_dev_persistent *persist) /* At that step HW was already reset, now notify clients */ mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); + mlx4_cmd_wake_completions(dev); return; out: @@ -157,7 +158,7 @@ static void poll_catas(unsigned long dev_ptr) return; internal_err: - if (internal_err_reset) + if (mlx4_internal_err_reset) queue_work(dev->persist->catas_wq, &dev->persist->catas_work); } @@ -177,7 +178,7 @@ void mlx4_start_catas_poll(struct mlx4_dev *dev) /*If we are in SRIOV the default of the module param must be 0*/ if (mlx4_is_mfunc(dev)) - internal_err_reset = 0; + mlx4_internal_err_reset = 0; INIT_LIST_HEAD(&priv->catas_err.list); init_timer(&priv->catas_err.timer); diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 7cd90e6a4272..3895b2b5fc92 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -182,6 +182,72 @@ static u8 mlx4_errno_to_status(int errno) } } +static int mlx4_internal_err_ret_value(struct mlx4_dev *dev, u16 op, + u8 op_modifier) +{ + switch (op) { + case MLX4_CMD_UNMAP_ICM: + case MLX4_CMD_UNMAP_ICM_AUX: + case MLX4_CMD_UNMAP_FA: + case MLX4_CMD_2RST_QP: + case MLX4_CMD_HW2SW_EQ: + case MLX4_CMD_HW2SW_CQ: + case MLX4_CMD_HW2SW_SRQ: + case MLX4_CMD_HW2SW_MPT: + case MLX4_CMD_CLOSE_HCA: + case MLX4_QP_FLOW_STEERING_DETACH: + case MLX4_CMD_FREE_RES: + case MLX4_CMD_CLOSE_PORT: + return CMD_STAT_OK; + + case MLX4_CMD_QP_ATTACH: + /* On Detach case return success */ + if (op_modifier == 0) + return CMD_STAT_OK; + return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + + default: + return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + } +} + +static int mlx4_closing_cmd_fatal_error(u16 op, u8 fw_status) +{ + /* Any error during the closing commands below is considered fatal */ + if (op == MLX4_CMD_CLOSE_HCA || + op == MLX4_CMD_HW2SW_EQ || + op == MLX4_CMD_HW2SW_CQ || + op == MLX4_CMD_2RST_QP || + op == MLX4_CMD_HW2SW_SRQ || + op == MLX4_CMD_SYNC_TPT || + op == MLX4_CMD_UNMAP_ICM || + op == MLX4_CMD_UNMAP_ICM_AUX || + op == MLX4_CMD_UNMAP_FA) + return 1; + /* Error on MLX4_CMD_HW2SW_MPT is fatal except when fw status equals + * CMD_STAT_REG_BOUND. + * This status indicates that memory region has memory windows bound to it + * which may result from invalid user space usage and is not fatal. + */ + if (op == MLX4_CMD_HW2SW_MPT && fw_status != CMD_STAT_REG_BOUND) + return 1; + return 0; +} + +static int mlx4_cmd_reset_flow(struct mlx4_dev *dev, u16 op, u8 op_modifier, + int err) +{ + /* Only if reset flow is really active return code is based on + * command, otherwise current error code is returned. + */ + if (mlx4_internal_err_reset) { + mlx4_enter_error_state(dev->persist); + err = mlx4_internal_err_ret_value(dev, op, op_modifier); + } + + return err; +} + static int comm_pending(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -258,7 +324,7 @@ static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, cmd->free_head = context->next; spin_unlock(&cmd->context_lock); - init_completion(&context->done); + reinit_completion(&context->done); mlx4_comm_cmd_post(dev, op, param); @@ -323,17 +389,21 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, { struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; u32 __iomem *hcr = cmd->hcr; - int ret = -EAGAIN; + int ret = -EIO; unsigned long end; - mutex_lock(&cmd->hcr_mutex); - - if (pci_channel_offline(dev->persist->pdev)) { + mutex_lock(&dev->persist->device_state_mutex); + /* To avoid writing to unknown addresses after the device state was + * changed to internal error and the chip was reset, + * check the INTERNAL_ERROR flag which is updated under + * device_state_mutex lock. + */ + if (pci_channel_offline(dev->persist->pdev) || + (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { /* * Device is going through error recovery * and cannot accept commands. */ - ret = -EIO; goto out; } @@ -347,7 +417,6 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, * Device is going through error recovery * and cannot accept commands. */ - ret = -EIO; goto out; } @@ -391,7 +460,11 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, ret = 0; out: - mutex_unlock(&cmd->hcr_mutex); + if (ret) + mlx4_warn(dev, "Could not post command 0x%x: ret=%d, in_param=0x%llx, in_mod=0x%x, op_mod=0x%x\n", + op, ret, in_param, in_modifier, op_modifier); + mutex_unlock(&dev->persist->device_state_mutex); + return ret; } @@ -464,12 +537,12 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, down(&priv->cmd.poll_sem); - if (pci_channel_offline(dev->persist->pdev)) { + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { /* * Device is going through error recovery * and cannot accept commands. */ - err = -EIO; + err = mlx4_internal_err_ret_value(dev, op, op_modifier); goto out; } @@ -483,7 +556,7 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); if (err) - goto out; + goto out_reset; end = msecs_to_jiffies(timeout) + jiffies; while (cmd_pending(dev) && time_before(jiffies, end)) { @@ -493,6 +566,11 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, * and cannot accept commands. */ err = -EIO; + goto out_reset; + } + + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { + err = mlx4_internal_err_ret_value(dev, op, op_modifier); goto out; } @@ -502,8 +580,8 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, if (cmd_pending(dev)) { mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", op); - err = -ETIMEDOUT; - goto out; + err = -EIO; + goto out_reset; } if (out_is_imm) @@ -515,10 +593,17 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, stat = be32_to_cpu((__force __be32) __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24; err = mlx4_status_to_errno(stat); - if (err) + if (err) { mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", op, stat); + if (mlx4_closing_cmd_fatal_error(op, stat)) + goto out_reset; + goto out; + } +out_reset: + if (err) + err = mlx4_cmd_reset_flow(dev, op, op_modifier, err); out: up(&priv->cmd.poll_sem); return err; @@ -565,17 +650,19 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, goto out; } - init_completion(&context->done); + reinit_completion(&context->done); - mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, - in_modifier, op_modifier, op, context->token, 1); + err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, + in_modifier, op_modifier, op, context->token, 1); + if (err) + goto out_reset; if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) { mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", op); - err = -EBUSY; - goto out; + err = -EIO; + goto out_reset; } err = context->result; @@ -592,12 +679,20 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, else mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", op, context->fw_status); + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + err = mlx4_internal_err_ret_value(dev, op, op_modifier); + else if (mlx4_closing_cmd_fatal_error(op, context->fw_status)) + goto out_reset; + goto out; } if (out_is_imm) *out_param = context->out_param; +out_reset: + if (err) + err = mlx4_cmd_reset_flow(dev, op, op_modifier, err); out: spin_lock(&cmd->context_lock); context->next = cmd->free_head; @@ -613,9 +708,12 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, u16 op, unsigned long timeout, int native) { if (pci_channel_offline(dev->persist->pdev)) - return -EIO; + return mlx4_cmd_reset_flow(dev, op, op_modifier, -EIO); if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + return mlx4_internal_err_ret_value(dev, op, + op_modifier); if (mlx4_priv(dev)->cmd.use_events) return mlx4_cmd_wait(dev, in_param, out_param, out_is_imm, in_modifier, @@ -2121,7 +2219,6 @@ int mlx4_cmd_init(struct mlx4_dev *dev) int flags = 0; if (!priv->cmd.initialized) { - mutex_init(&priv->cmd.hcr_mutex); mutex_init(&priv->cmd.slave_cmd_mutex); sema_init(&priv->cmd.poll_sem, 1); priv->cmd.use_events = 0; @@ -2232,6 +2329,11 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev) for (i = 0; i < priv->cmd.max_cmds; ++i) { priv->cmd.context[i].token = i; priv->cmd.context[i].next = i + 1; + /* To support fatal error flow, initialize all + * cmd contexts to allow simulating completions + * with complete() at any time. + */ + init_completion(&priv->cmd.context[i].done); } priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; @@ -2329,6 +2431,25 @@ int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave) return slave - 1; } +void mlx4_cmd_wake_completions(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_context *context; + int i; + + spin_lock(&priv->cmd.context_lock); + if (priv->cmd.context) { + for (i = 0; i < priv->cmd.max_cmds; ++i) { + context = &priv->cmd.context[i]; + context->fw_status = CMD_STAT_INTERNAL_ERR; + context->result = + mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + complete(&context->done); + } + } + spin_unlock(&priv->cmd.context_lock); +} + struct mlx4_active_ports mlx4_get_active_ports(struct mlx4_dev *dev, int slave) { struct mlx4_active_ports actv_ports; diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index a3867e7ef885..d22d9283d2cd 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -1318,6 +1318,9 @@ out: mutex_unlock(&priv->mcg_table.mutex); mlx4_free_cmd_mailbox(dev, mailbox); + if (err && dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + /* In case device is under an error, return success as a closing command */ + err = 0; return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index aa1ecbc5a606..5c772ea4473b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -235,6 +235,7 @@ do { \ extern int mlx4_log_num_mgm_entry_size; extern int log_mtts_per_seg; +extern int mlx4_internal_err_reset; #define MLX4_MAX_NUM_SLAVES (MLX4_MAX_NUM_PF + MLX4_MAX_NUM_VF) #define ALL_SLAVES 0xff @@ -607,7 +608,6 @@ struct mlx4_mgm { struct mlx4_cmd { struct pci_pool *pool; void __iomem *hcr; - struct mutex hcr_mutex; struct mutex slave_cmd_mutex; struct semaphore poll_sem; struct semaphore event_sem; -- cgit v1.2.1 From c69453e294c9f16da977b68e658a8028b854c209 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Sun, 25 Jan 2015 16:59:40 +0200 Subject: net/mlx4_core: Manage interface state for Reset flow cases We need to manage interface state to sync between reset flow and some other relative cases such as remove_one. This has to be done to prevent certain races. For example in case software stack is down as a result of unload call, the remove_one should skip the unload phase. Implement the remove_one case, handling AER and other cases comes next. The interface can be up/down, upon remove_one, the state will include an extra bit indicating that the device is cleaned-up, forcing other tasks to finish before the final cleanup. Signed-off-by: Yishai Hadas Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/catas.c | 13 +++++++++++-- drivers/net/ethernet/mellanox/mlx4/intf.c | 2 ++ drivers/net/ethernet/mellanox/mlx4/main.c | 13 ++++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 63f14ffcc906..3fcf3cfaedfc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -122,8 +122,14 @@ static void mlx4_handle_error_state(struct mlx4_dev_persistent *persist) int err = 0; mlx4_enter_error_state(persist); - err = mlx4_restart_one(persist->pdev); - mlx4_info(persist->dev, "mlx4_restart_one was ended, ret=%d\n", err); + mutex_lock(&persist->interface_state_mutex); + if (persist->interface_state & MLX4_INTERFACE_STATE_UP && + !(persist->interface_state & MLX4_INTERFACE_STATE_DELETION)) { + err = mlx4_restart_one(persist->pdev); + mlx4_info(persist->dev, "mlx4_restart_one was ended, ret=%d\n", + err); + } + mutex_unlock(&persist->interface_state_mutex); } static void dump_err_buf(struct mlx4_dev *dev) @@ -211,6 +217,9 @@ void mlx4_stop_catas_poll(struct mlx4_dev *dev) iounmap(priv->catas_err.map); priv->catas_err.map = NULL; } + + if (dev->persist->interface_state & MLX4_INTERFACE_STATE_DELETION) + flush_workqueue(dev->persist->catas_wq); } int mlx4_catas_init(struct mlx4_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c index 116895ac8b35..fba0b96a6f28 100644 --- a/drivers/net/ethernet/mellanox/mlx4/intf.c +++ b/drivers/net/ethernet/mellanox/mlx4/intf.c @@ -138,6 +138,7 @@ int mlx4_register_device(struct mlx4_dev *dev) mutex_lock(&intf_mutex); + dev->persist->interface_state |= MLX4_INTERFACE_STATE_UP; list_add_tail(&priv->dev_list, &dev_list); list_for_each_entry(intf, &intf_list, list) mlx4_add_device(intf, priv); @@ -162,6 +163,7 @@ void mlx4_unregister_device(struct mlx4_dev *dev) mlx4_remove_device(intf, priv); list_del(&priv->dev_list); + dev->persist->interface_state &= ~MLX4_INTERFACE_STATE_UP; mutex_unlock(&intf_mutex); } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index dc2d910fcc88..d59cae5da3f0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -3114,6 +3114,7 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, dev->persist); priv->pci_dev_data = id->driver_data; mutex_init(&dev->persist->device_state_mutex); + mutex_init(&dev->persist->interface_state_mutex); ret = __mlx4_init_one(pdev, id->driver_data, priv); if (ret) { @@ -3232,7 +3233,17 @@ static void mlx4_remove_one(struct pci_dev *pdev) struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); - mlx4_unload_one(pdev); + mutex_lock(&persist->interface_state_mutex); + persist->interface_state |= MLX4_INTERFACE_STATE_DELETION; + mutex_unlock(&persist->interface_state_mutex); + + /* device marked to be under deletion running now without the lock + * letting other tasks to be terminated + */ + if (persist->interface_state & MLX4_INTERFACE_STATE_UP) + mlx4_unload_one(pdev); + else + mlx4_info(dev, "%s: interface is down\n", __func__); mlx4_catas_end(dev); pci_release_regions(pdev); pci_disable_device(pdev); -- cgit v1.2.1 From 2ba5fbd62b2534335f4e3b844ecc7860115525a3 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Sun, 25 Jan 2015 16:59:41 +0200 Subject: net/mlx4_core: Handle AER flow properly Fix AER callbacks to work properly, it includes: - Refractoring AER to be aligned with Reset flow support. - Sync with concurrent catas flow. In addition, fix the shutdown PCI callback to sync with concurrent catas flow. Signed-off-by: Yishai Hadas Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 71 ++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index d59cae5da3f0..6bb0fca137cd 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -3120,7 +3120,10 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) { kfree(dev->persist); kfree(priv); + } else { + pci_save_state(pdev); } + return ret; } @@ -3351,23 +3354,79 @@ MODULE_DEVICE_TABLE(pci, mlx4_pci_table); static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev, pci_channel_state_t state) { - mlx4_unload_one(pdev); + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + + mlx4_err(persist->dev, "mlx4_pci_err_detected was called\n"); + mlx4_enter_error_state(persist); - return state == pci_channel_io_perm_failure ? - PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; + mutex_lock(&persist->interface_state_mutex); + if (persist->interface_state & MLX4_INTERFACE_STATE_UP) + mlx4_unload_one(pdev); + + mutex_unlock(&persist->interface_state_mutex); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + pci_disable_device(pdev); + return PCI_ERS_RESULT_NEED_RESET; } static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev) { - struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); int ret; + int nvfs[MLX4_MAX_PORTS + 1] = {0, 0, 0}; + int total_vfs; - ret = __mlx4_init_one(pdev, priv->pci_dev_data, priv); + mlx4_err(dev, "mlx4_pci_slot_reset was called\n"); + ret = pci_enable_device(pdev); + if (ret) { + mlx4_err(dev, "Can not re-enable device, ret=%d\n", ret); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + pci_restore_state(pdev); + pci_save_state(pdev); + + total_vfs = dev->persist->num_vfs; + memcpy(nvfs, dev->persist->nvfs, sizeof(dev->persist->nvfs)); + + mutex_lock(&persist->interface_state_mutex); + if (!(persist->interface_state & MLX4_INTERFACE_STATE_UP)) { + ret = mlx4_load_one(pdev, priv->pci_dev_data, total_vfs, nvfs, + priv); + if (ret) { + mlx4_err(dev, "%s: mlx4_load_one failed, ret=%d\n", + __func__, ret); + goto end; + } + + ret = restore_current_port_types(dev, dev->persist-> + curr_port_type, dev->persist-> + curr_port_poss_type); + if (ret) + mlx4_err(dev, "could not restore original port types (%d)\n", ret); + } +end: + mutex_unlock(&persist->interface_state_mutex); return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; } +static void mlx4_shutdown(struct pci_dev *pdev) +{ + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + + mlx4_info(persist->dev, "mlx4_shutdown was called\n"); + mutex_lock(&persist->interface_state_mutex); + if (persist->interface_state & MLX4_INTERFACE_STATE_UP) + mlx4_unload_one(pdev); + mutex_unlock(&persist->interface_state_mutex); +} + static const struct pci_error_handlers mlx4_err_handler = { .error_detected = mlx4_pci_err_detected, .slot_reset = mlx4_pci_slot_reset, @@ -3377,7 +3436,7 @@ static struct pci_driver mlx4_driver = { .name = DRV_NAME, .id_table = mlx4_pci_table, .probe = mlx4_init_one, - .shutdown = mlx4_unload_one, + .shutdown = mlx4_shutdown, .remove = mlx4_remove_one, .err_handler = &mlx4_err_handler, }; -- cgit v1.2.1 From 55ad359225b2232b9b8f04a0dfa169bd3a7d86d2 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Sun, 25 Jan 2015 16:59:42 +0200 Subject: net/mlx4_core: Enable device recovery flow with SRIOV In SRIOV, both the PF and the VF may attempt device recovery whenever they assume that the device is not functioning. When the PF driver resets the device, the VF should detect this and attempt to reinitialize itself. The VF must be able to reset itself under all circumstances, even if the PF is not responsive. The VF shall reset itself in the following cases: 1. Commands are not processed within reasonable time over the communication channel. This is done considering device state and the correct return code based on the command as was done in the native mode, done in the next patch. 2. The VF driver receives an internal error event reported by the PF on the communication channel. This occurs when the PF driver resets the device or when VF is out of sync with the PF. Add 'VF reset' capability, which allows the VF to reinitialize itself even when the PF is not responsive. As PF and VF may run their reset flow simulantanisly, there are several cases that are handled: - Prevent freeing VF resources upon FLR, when PF is in its unloading stage. - Prevent PF getting VF commands before it has finished initializing its resources. - Upon VF startup, check that comm-channel is online before sending commands to the PF and getting timed-out. Signed-off-by: Yishai Hadas Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/catas.c | 120 +++++++++++++++++++++---- drivers/net/ethernet/mellanox/mlx4/cmd.c | 77 ++++++++++++---- drivers/net/ethernet/mellanox/mlx4/eq.c | 10 ++- drivers/net/ethernet/mellanox/mlx4/intf.c | 6 +- drivers/net/ethernet/mellanox/mlx4/main.c | 135 +++++++++++++++++++++++------ drivers/net/ethernet/mellanox/mlx4/mlx4.h | 7 +- 6 files changed, 285 insertions(+), 70 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 3fcf3cfaedfc..715de8affcc9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -45,8 +45,7 @@ enum { int mlx4_internal_err_reset = 1; module_param_named(internal_err_reset, mlx4_internal_err_reset, int, 0644); MODULE_PARM_DESC(internal_err_reset, - "Reset device on internal errors if non-zero" - " (default 1, in SRIOV mode default is 0)"); + "Reset device on internal errors if non-zero (default 1)"); static int read_vendor_id(struct mlx4_dev *dev) { @@ -71,6 +70,9 @@ static int mlx4_reset_master(struct mlx4_dev *dev) { int err = 0; + if (mlx4_is_master(dev)) + mlx4_report_internal_err_comm_event(dev); + if (!pci_channel_offline(dev->persist->pdev)) { err = read_vendor_id(dev); /* If PCI can't be accessed to read vendor ID we assume that its @@ -87,6 +89,81 @@ static int mlx4_reset_master(struct mlx4_dev *dev) return err; } +static int mlx4_reset_slave(struct mlx4_dev *dev) +{ +#define COM_CHAN_RST_REQ_OFFSET 0x10 +#define COM_CHAN_RST_ACK_OFFSET 0x08 + + u32 comm_flags; + u32 rst_req; + u32 rst_ack; + unsigned long end; + struct mlx4_priv *priv = mlx4_priv(dev); + + if (pci_channel_offline(dev->persist->pdev)) + return 0; + + comm_flags = swab32(readl((__iomem char *)priv->mfunc.comm + + MLX4_COMM_CHAN_FLAGS)); + if (comm_flags == 0xffffffff) { + mlx4_err(dev, "VF reset is not needed\n"); + return 0; + } + + if (!(dev->caps.vf_caps & MLX4_VF_CAP_FLAG_RESET)) { + mlx4_err(dev, "VF reset is not supported\n"); + return -EOPNOTSUPP; + } + + rst_req = (comm_flags & (u32)(1 << COM_CHAN_RST_REQ_OFFSET)) >> + COM_CHAN_RST_REQ_OFFSET; + rst_ack = (comm_flags & (u32)(1 << COM_CHAN_RST_ACK_OFFSET)) >> + COM_CHAN_RST_ACK_OFFSET; + if (rst_req != rst_ack) { + mlx4_err(dev, "Communication channel isn't sync, fail to send reset\n"); + return -EIO; + } + + rst_req ^= 1; + mlx4_warn(dev, "VF is sending reset request to Firmware\n"); + comm_flags = rst_req << COM_CHAN_RST_REQ_OFFSET; + __raw_writel((__force u32)cpu_to_be32(comm_flags), + (__iomem char *)priv->mfunc.comm + MLX4_COMM_CHAN_FLAGS); + /* Make sure that our comm channel write doesn't + * get mixed in with writes from another CPU. + */ + mmiowb(); + + end = msecs_to_jiffies(MLX4_COMM_TIME) + jiffies; + while (time_before(jiffies, end)) { + comm_flags = swab32(readl((__iomem char *)priv->mfunc.comm + + MLX4_COMM_CHAN_FLAGS)); + rst_ack = (comm_flags & (u32)(1 << COM_CHAN_RST_ACK_OFFSET)) >> + COM_CHAN_RST_ACK_OFFSET; + + /* Reading rst_req again since the communication channel can + * be reset at any time by the PF and all its bits will be + * set to zero. + */ + rst_req = (comm_flags & (u32)(1 << COM_CHAN_RST_REQ_OFFSET)) >> + COM_CHAN_RST_REQ_OFFSET; + + if (rst_ack == rst_req) { + mlx4_warn(dev, "VF Reset succeed\n"); + return 0; + } + cond_resched(); + } + mlx4_err(dev, "Fail to send reset over the communication channel\n"); + return -ETIMEDOUT; +} + +static int mlx4_comm_internal_err(u32 slave_read) +{ + return (u32)COMM_CHAN_EVENT_INTERNAL_ERR == + (slave_read & (u32)COMM_CHAN_EVENT_INTERNAL_ERR) ? 1 : 0; +} + void mlx4_enter_error_state(struct mlx4_dev_persistent *persist) { int err; @@ -101,7 +178,10 @@ void mlx4_enter_error_state(struct mlx4_dev_persistent *persist) dev = persist->dev; mlx4_err(dev, "device is going to be reset\n"); - err = mlx4_reset_master(dev); + if (mlx4_is_slave(dev)) + err = mlx4_reset_slave(dev); + else + err = mlx4_reset_master(dev); BUG_ON(err != 0); dev->persist->state |= MLX4_DEVICE_STATE_INTERNAL_ERROR; @@ -148,8 +228,15 @@ static void poll_catas(unsigned long dev_ptr) { struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr; struct mlx4_priv *priv = mlx4_priv(dev); - - if (readl(priv->catas_err.map)) { + u32 slave_read; + + if (mlx4_is_slave(dev)) { + slave_read = swab32(readl(&priv->mfunc.comm->slave_read)); + if (mlx4_comm_internal_err(slave_read)) { + mlx4_warn(dev, "Internal error detected on the communication channel\n"); + goto internal_err; + } + } else if (readl(priv->catas_err.map)) { dump_err_buf(dev); goto internal_err; } @@ -182,22 +269,21 @@ void mlx4_start_catas_poll(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); phys_addr_t addr; - /*If we are in SRIOV the default of the module param must be 0*/ - if (mlx4_is_mfunc(dev)) - mlx4_internal_err_reset = 0; - INIT_LIST_HEAD(&priv->catas_err.list); init_timer(&priv->catas_err.timer); priv->catas_err.map = NULL; - addr = pci_resource_start(dev->persist->pdev, priv->fw.catas_bar) + - priv->fw.catas_offset; - - priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); - if (!priv->catas_err.map) { - mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n", - (unsigned long long) addr); - return; + if (!mlx4_is_slave(dev)) { + addr = pci_resource_start(dev->persist->pdev, + priv->fw.catas_bar) + + priv->fw.catas_offset; + + priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); + if (!priv->catas_err.map) { + mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n", + (unsigned long long)addr); + return; + } } priv->catas_err.timer.data = (unsigned long) dev; diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 3895b2b5fc92..7652eed4bbc8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -729,7 +730,7 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, EXPORT_SYMBOL_GPL(__mlx4_cmd); -static int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) +int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) { return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL, MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); @@ -1945,8 +1946,11 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, break; case MLX4_COMM_CMD_VHCR_POST: if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && - (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) + (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) { + mlx4_warn(dev, "slave:%d is out of sync, cmd=0x%x, last command=0x%x, reset is needed\n", + slave, cmd, slave_state[slave].last_cmd); goto reset_slave; + } mutex_lock(&priv->cmd.slave_cmd_mutex); if (mlx4_master_process_vhcr(dev, slave, NULL)) { @@ -1980,7 +1984,18 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, reset_slave: /* cleanup any slave resources */ - mlx4_delete_all_resources_for_slave(dev, slave); + if (dev->persist->interface_state & MLX4_INTERFACE_STATE_UP) + mlx4_delete_all_resources_for_slave(dev, slave); + + if (cmd != MLX4_COMM_CMD_RESET) { + mlx4_warn(dev, "Turn on internal error to force reset, slave=%d, cmd=0x%x\n", + slave, cmd); + /* Turn on internal error letting slave reset itself immeditaly, + * otherwise it might take till timeout on command is passed + */ + reply |= ((u32)COMM_CHAN_EVENT_INTERNAL_ERR); + } + spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); if (!slave_state[slave].is_slave_going_down) slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; @@ -2056,17 +2071,28 @@ void mlx4_master_comm_channel(struct work_struct *work) static int sync_toggles(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); - int wr_toggle; - int rd_toggle; + u32 wr_toggle; + u32 rd_toggle; unsigned long end; - wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)) >> 31; - end = jiffies + msecs_to_jiffies(5000); + wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)); + if (wr_toggle == 0xffffffff) + end = jiffies + msecs_to_jiffies(30000); + else + end = jiffies + msecs_to_jiffies(5000); while (time_before(jiffies, end)) { - rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)) >> 31; - if (rd_toggle == wr_toggle) { - priv->cmd.comm_toggle = rd_toggle; + rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)); + if (wr_toggle == 0xffffffff || rd_toggle == 0xffffffff) { + /* PCI might be offline */ + msleep(100); + wr_toggle = swab32(readl(&priv->mfunc.comm-> + slave_write)); + continue; + } + + if (rd_toggle >> 31 == wr_toggle >> 31) { + priv->cmd.comm_toggle = rd_toggle >> 31; return 0; } @@ -2172,13 +2198,6 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) if (mlx4_init_resource_tracker(dev)) goto err_thread; - err = mlx4_ARM_COMM_CHANNEL(dev); - if (err) { - mlx4_err(dev, " Failed to arm comm channel eq: %x\n", - err); - goto err_resource; - } - } else { err = sync_toggles(dev); if (err) { @@ -2188,8 +2207,6 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) } return 0; -err_resource: - mlx4_free_resource_tracker(dev, RES_TR_FREE_ALL); err_thread: flush_workqueue(priv->mfunc.master.comm_wq); destroy_workqueue(priv->mfunc.master.comm_wq); @@ -2266,6 +2283,27 @@ err: return -ENOMEM; } +void mlx4_report_internal_err_comm_event(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int slave; + u32 slave_read; + + /* Report an internal error event to all + * communication channels. + */ + for (slave = 0; slave < dev->num_slaves; slave++) { + slave_read = swab32(readl(&priv->mfunc.comm[slave].slave_read)); + slave_read |= (u32)COMM_CHAN_EVENT_INTERNAL_ERR; + __raw_writel((__force u32)cpu_to_be32(slave_read), + &priv->mfunc.comm[slave].slave_read); + /* Make sure that our comm channel write doesn't + * get mixed in with writes from another CPU. + */ + mmiowb(); + } +} + void mlx4_multi_func_cleanup(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -2281,6 +2319,7 @@ void mlx4_multi_func_cleanup(struct mlx4_dev *dev) kfree(priv->mfunc.master.slave_state); kfree(priv->mfunc.master.vf_admin); kfree(priv->mfunc.master.vf_oper); + dev->num_slaves = 0; } iounmap(priv->mfunc.comm); diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 7538c9ce98a9..2f2e6067426d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -429,8 +429,14 @@ void mlx4_master_handle_slave_flr(struct work_struct *work) if (MLX4_COMM_CMD_FLR == slave_state[i].last_cmd) { mlx4_dbg(dev, "mlx4_handle_slave_flr: clean slave: %d\n", i); - - mlx4_delete_all_resources_for_slave(dev, i); + /* In case of 'Reset flow' FLR can be generated for + * a slave before mlx4_load_one is done. + * make sure interface is up before trying to delete + * slave resources which weren't allocated yet. + */ + if (dev->persist->interface_state & + MLX4_INTERFACE_STATE_UP) + mlx4_delete_all_resources_for_slave(dev, i); /*return the slave to running mode*/ spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); slave_state[i].last_cmd = MLX4_COMM_CMD_RESET; diff --git a/drivers/net/ethernet/mellanox/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c index fba0b96a6f28..68d2bad325d5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/intf.c +++ b/drivers/net/ethernet/mellanox/mlx4/intf.c @@ -144,8 +144,7 @@ int mlx4_register_device(struct mlx4_dev *dev) mlx4_add_device(intf, priv); mutex_unlock(&intf_mutex); - if (!mlx4_is_slave(dev)) - mlx4_start_catas_poll(dev); + mlx4_start_catas_poll(dev); return 0; } @@ -155,8 +154,7 @@ void mlx4_unregister_device(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_interface *intf; - if (!mlx4_is_slave(dev)) - mlx4_stop_catas_poll(dev); + mlx4_stop_catas_poll(dev); mutex_lock(&intf_mutex); list_for_each_entry(intf, &intf_list, list) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 6bb0fca137cd..1baf1f1e2866 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -108,6 +108,8 @@ MODULE_PARM_DESC(enable_64b_cqe_eqe, MLX4_FUNC_CAP_EQE_CQE_STRIDE | \ MLX4_FUNC_CAP_DMFS_A0_STATIC) +#define RESET_PERSIST_MASK_FLAGS (MLX4_FLAG_SRIOV) + static char mlx4_version[] = DRV_NAME ": Mellanox ConnectX core driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; @@ -1579,6 +1581,50 @@ static void mlx4_close_fw(struct mlx4_dev *dev) } } +static int mlx4_comm_check_offline(struct mlx4_dev *dev) +{ +#define COMM_CHAN_OFFLINE_OFFSET 0x09 + + u32 comm_flags; + u32 offline_bit; + unsigned long end; + struct mlx4_priv *priv = mlx4_priv(dev); + + end = msecs_to_jiffies(MLX4_COMM_OFFLINE_TIME_OUT) + jiffies; + while (time_before(jiffies, end)) { + comm_flags = swab32(readl((__iomem char *)priv->mfunc.comm + + MLX4_COMM_CHAN_FLAGS)); + offline_bit = (comm_flags & + (u32)(1 << COMM_CHAN_OFFLINE_OFFSET)); + if (!offline_bit) + return 0; + /* There are cases as part of AER/Reset flow that PF needs + * around 100 msec to load. We therefore sleep for 100 msec + * to allow other tasks to make use of that CPU during this + * time interval. + */ + msleep(100); + } + mlx4_err(dev, "Communication channel is offline.\n"); + return -EIO; +} + +static void mlx4_reset_vf_support(struct mlx4_dev *dev) +{ +#define COMM_CHAN_RST_OFFSET 0x1e + + struct mlx4_priv *priv = mlx4_priv(dev); + u32 comm_rst; + u32 comm_caps; + + comm_caps = swab32(readl((__iomem char *)priv->mfunc.comm + + MLX4_COMM_CHAN_CAPS)); + comm_rst = (comm_caps & (u32)(1 << COMM_CHAN_RST_OFFSET)); + + if (comm_rst) + dev->caps.vf_caps |= MLX4_VF_CAP_FLAG_RESET; +} + static int mlx4_init_slave(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -1594,6 +1640,12 @@ static int mlx4_init_slave(struct mlx4_dev *dev) mutex_lock(&priv->cmd.slave_cmd_mutex); priv->cmd.max_cmds = 1; + if (mlx4_comm_check_offline(dev)) { + mlx4_err(dev, "PF is not responsive, skipping initialization\n"); + goto err_offline; + } + + mlx4_reset_vf_support(dev); mlx4_warn(dev, "Sending reset\n"); ret_from_reset = mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_TIME); @@ -1637,6 +1689,7 @@ static int mlx4_init_slave(struct mlx4_dev *dev) err: mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, 0); +err_offline: mutex_unlock(&priv->cmd.slave_cmd_mutex); return -EIO; } @@ -2494,11 +2547,19 @@ static void mlx4_free_ownership(struct mlx4_dev *dev) !!((flags) & MLX4_FLAG_MASTER)) static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev, - u8 total_vfs, int existing_vfs) + u8 total_vfs, int existing_vfs, int reset_flow) { u64 dev_flags = dev->flags; int err = 0; + if (reset_flow) { + dev->dev_vfs = kcalloc(total_vfs, sizeof(*dev->dev_vfs), + GFP_KERNEL); + if (!dev->dev_vfs) + goto free_mem; + return dev_flags; + } + atomic_inc(&pf_loading); if (dev->flags & MLX4_FLAG_SRIOV) { if (existing_vfs != total_vfs) { @@ -2533,6 +2594,7 @@ static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev, disable_sriov: atomic_dec(&pf_loading); +free_mem: dev->persist->num_vfs = 0; kfree(dev->dev_vfs); return dev_flags & ~MLX4_FLAG_MASTER; @@ -2557,7 +2619,8 @@ static int mlx4_check_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap } static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data, - int total_vfs, int *nvfs, struct mlx4_priv *priv) + int total_vfs, int *nvfs, struct mlx4_priv *priv, + int reset_flow) { struct mlx4_dev *dev; unsigned sum = 0; @@ -2679,8 +2742,10 @@ slave_start: goto err_fw; if (!(dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS)) { - u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs, - existing_vfs); + u64 dev_flags = mlx4_enable_sriov(dev, pdev, + total_vfs, + existing_vfs, + reset_flow); mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL); dev->flags = dev_flags; @@ -2722,7 +2787,7 @@ slave_start: if (dev->flags & MLX4_FLAG_SRIOV) { if (!existing_vfs) pci_disable_sriov(pdev); - if (mlx4_is_master(dev)) + if (mlx4_is_master(dev) && !reset_flow) atomic_dec(&pf_loading); dev->flags &= ~MLX4_FLAG_SRIOV; } @@ -2736,7 +2801,8 @@ slave_start: } if (mlx4_is_master(dev) && (dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS)) { - u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs, existing_vfs); + u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs, + existing_vfs, reset_flow); if ((dev->flags ^ dev_flags) & (MLX4_FLAG_MASTER | MLX4_FLAG_SLAVE)) { mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_VHCR); @@ -2848,6 +2914,17 @@ slave_start: goto err_steer; mlx4_init_quotas(dev); + /* When PF resources are ready arm its comm channel to enable + * getting commands + */ + if (mlx4_is_master(dev)) { + err = mlx4_ARM_COMM_CHANNEL(dev); + if (err) { + mlx4_err(dev, " Failed to arm comm channel eq: %x\n", + err); + goto err_steer; + } + } for (port = 1; port <= dev->caps.num_ports; port++) { err = mlx4_init_port_info(dev, port); @@ -2866,7 +2943,7 @@ slave_start: priv->removed = 0; - if (mlx4_is_master(dev) && dev->persist->num_vfs) + if (mlx4_is_master(dev) && dev->persist->num_vfs && !reset_flow) atomic_dec(&pf_loading); kfree(dev_cap); @@ -2925,10 +3002,12 @@ err_cmd: mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL); err_sriov: - if (dev->flags & MLX4_FLAG_SRIOV && !existing_vfs) + if (dev->flags & MLX4_FLAG_SRIOV && !existing_vfs) { pci_disable_sriov(pdev); + dev->flags &= ~MLX4_FLAG_SRIOV; + } - if (mlx4_is_master(dev) && dev->persist->num_vfs) + if (mlx4_is_master(dev) && dev->persist->num_vfs && !reset_flow) atomic_dec(&pf_loading); kfree(priv->dev.dev_vfs); @@ -3073,7 +3152,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data, if (err) goto err_release_regions; - err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv); + err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv, 0); if (err) goto err_catas; @@ -3131,9 +3210,11 @@ static void mlx4_clean_dev(struct mlx4_dev *dev) { struct mlx4_dev_persistent *persist = dev->persist; struct mlx4_priv *priv = mlx4_priv(dev); + unsigned long flags = (dev->flags & RESET_PERSIST_MASK_FLAGS); memset(priv, 0, sizeof(*priv)); priv->dev.persist = persist; + priv->dev.flags = flags; } static void mlx4_unload_one(struct pci_dev *pdev) @@ -3143,7 +3224,6 @@ static void mlx4_unload_one(struct pci_dev *pdev) struct mlx4_priv *priv = mlx4_priv(dev); int pci_dev_data; int p, i; - int active_vfs = 0; if (priv->removed) return; @@ -3157,14 +3237,6 @@ static void mlx4_unload_one(struct pci_dev *pdev) pci_dev_data = priv->pci_dev_data; - /* Disabling SR-IOV is not allowed while there are active vf's */ - if (mlx4_is_master(dev)) { - active_vfs = mlx4_how_many_lives_vf(dev); - if (active_vfs) { - pr_warn("Removing PF when there are active VF's !!\n"); - pr_warn("Will not disable SR-IOV.\n"); - } - } mlx4_stop_sense(dev); mlx4_unregister_device(dev); @@ -3208,12 +3280,6 @@ static void mlx4_unload_one(struct pci_dev *pdev) if (dev->flags & MLX4_FLAG_MSI_X) pci_disable_msix(pdev); - if (dev->flags & MLX4_FLAG_SRIOV && !active_vfs) { - mlx4_warn(dev, "Disabling SR-IOV\n"); - pci_disable_sriov(pdev); - dev->flags &= ~MLX4_FLAG_SRIOV; - dev->persist->num_vfs = 0; - } if (!mlx4_is_slave(dev)) mlx4_free_ownership(dev); @@ -3235,11 +3301,21 @@ static void mlx4_remove_one(struct pci_dev *pdev) struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); + int active_vfs = 0; mutex_lock(&persist->interface_state_mutex); persist->interface_state |= MLX4_INTERFACE_STATE_DELETION; mutex_unlock(&persist->interface_state_mutex); + /* Disabling SR-IOV is not allowed while there are active vf's */ + if (mlx4_is_master(dev) && dev->flags & MLX4_FLAG_SRIOV) { + active_vfs = mlx4_how_many_lives_vf(dev); + if (active_vfs) { + pr_warn("Removing PF when there are active VF's !!\n"); + pr_warn("Will not disable SR-IOV.\n"); + } + } + /* device marked to be under deletion running now without the lock * letting other tasks to be terminated */ @@ -3248,6 +3324,11 @@ static void mlx4_remove_one(struct pci_dev *pdev) else mlx4_info(dev, "%s: interface is down\n", __func__); mlx4_catas_end(dev); + if (dev->flags & MLX4_FLAG_SRIOV && !active_vfs) { + mlx4_warn(dev, "Disabling SR-IOV\n"); + pci_disable_sriov(pdev); + } + pci_release_regions(pdev); pci_disable_device(pdev); kfree(dev->persist); @@ -3287,7 +3368,7 @@ int mlx4_restart_one(struct pci_dev *pdev) memcpy(nvfs, dev->persist->nvfs, sizeof(dev->persist->nvfs)); mlx4_unload_one(pdev); - err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv); + err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv, 1); if (err) { mlx4_err(dev, "%s: ERROR: mlx4_load_one failed, pci_name=%s, err=%d\n", __func__, pci_name(pdev), err); @@ -3397,7 +3478,7 @@ static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev) mutex_lock(&persist->interface_state_mutex); if (!(persist->interface_state & MLX4_INTERFACE_STATE_UP)) { ret = mlx4_load_one(pdev, priv->pci_dev_data, total_vfs, nvfs, - priv); + priv, 1); if (ret) { mlx4_err(dev, "%s: mlx4_load_one failed, ret=%d\n", __func__, ret); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 5c772ea4473b..2a15b8248e77 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -85,7 +85,9 @@ enum { MLX4_CLR_INT_SIZE = 0x00008, MLX4_SLAVE_COMM_BASE = 0x0, MLX4_COMM_PAGESIZE = 0x1000, - MLX4_CLOCK_SIZE = 0x00008 + MLX4_CLOCK_SIZE = 0x00008, + MLX4_COMM_CHAN_CAPS = 0x8, + MLX4_COMM_CHAN_FLAGS = 0xc }; enum { @@ -120,6 +122,8 @@ enum mlx4_mpt_state { }; #define MLX4_COMM_TIME 10000 +#define MLX4_COMM_OFFLINE_TIME_OUT 30000 + enum { MLX4_COMM_CMD_RESET, MLX4_COMM_CMD_VHCR0, @@ -1162,6 +1166,7 @@ enum { int mlx4_cmd_init(struct mlx4_dev *dev); void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask); int mlx4_multi_func_init(struct mlx4_dev *dev); +int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev); void mlx4_multi_func_cleanup(struct mlx4_dev *dev); void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param); int mlx4_cmd_use_events(struct mlx4_dev *dev); -- cgit v1.2.1 From 0cd9302734111abc0b5912b695336f2ee63cb22b Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Sun, 25 Jan 2015 16:59:43 +0200 Subject: net/mlx4_core: Reset flow activation upon SRIOV fatal command cases When SRIOV commands are executed over the comm-channel and get a fatal error (e.g. timeout, closing command failure) the VF enters into error state and reset flow is activated. To be able to recognize whether the failure was on a closing command, the operational code for the given VHCR command is used. Once the device entered into an error state we prevent redundant error messages from being printed. Signed-off-by: Yishai Hadas Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 125 ++++++++++++++++++++++-------- drivers/net/ethernet/mellanox/mlx4/main.c | 16 ++-- drivers/net/ethernet/mellanox/mlx4/mcg.c | 3 + drivers/net/ethernet/mellanox/mlx4/mlx4.h | 4 +- 4 files changed, 107 insertions(+), 41 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 7652eed4bbc8..2b48932855e7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -257,16 +257,30 @@ static int comm_pending(struct mlx4_dev *dev) return (swab32(status) >> 31) != priv->cmd.comm_toggle; } -static void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) +static int mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) { struct mlx4_priv *priv = mlx4_priv(dev); u32 val; + /* To avoid writing to unknown addresses after the device state was + * changed to internal error and the function was rest, + * check the INTERNAL_ERROR flag which is updated under + * device_state_mutex lock. + */ + mutex_lock(&dev->persist->device_state_mutex); + + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { + mutex_unlock(&dev->persist->device_state_mutex); + return -EIO; + } + priv->cmd.comm_toggle ^= 1; val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31); __raw_writel((__force u32) cpu_to_be32(val), &priv->mfunc.comm->slave_write); mmiowb(); + mutex_unlock(&dev->persist->device_state_mutex); + return 0; } static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, @@ -286,7 +300,13 @@ static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, /* Write command */ down(&priv->cmd.poll_sem); - mlx4_comm_cmd_post(dev, cmd, param); + if (mlx4_comm_cmd_post(dev, cmd, param)) { + /* Only in case the device state is INTERNAL_ERROR, + * mlx4_comm_cmd_post returns with an error + */ + err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + goto out; + } end = msecs_to_jiffies(timeout) + jiffies; while (comm_pending(dev) && time_before(jiffies, end)) @@ -298,18 +318,23 @@ static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, * is MLX4_DELAY_RESET_SLAVE*/ if ((MLX4_COMM_CMD_RESET == cmd)) { err = MLX4_DELAY_RESET_SLAVE; + goto out; } else { - mlx4_warn(dev, "Communication channel timed out\n"); - err = -ETIMEDOUT; + mlx4_warn(dev, "Communication channel command 0x%x timed out\n", + cmd); + err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); } } + if (err) + mlx4_enter_error_state(dev->persist); +out: up(&priv->cmd.poll_sem); return err; } -static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, - u16 param, unsigned long timeout) +static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 vhcr_cmd, + u16 param, u16 op, unsigned long timeout) { struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; struct mlx4_cmd_context *context; @@ -327,32 +352,47 @@ static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, reinit_completion(&context->done); - mlx4_comm_cmd_post(dev, op, param); + if (mlx4_comm_cmd_post(dev, vhcr_cmd, param)) { + /* Only in case the device state is INTERNAL_ERROR, + * mlx4_comm_cmd_post returns with an error + */ + err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + goto out; + } if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) { - mlx4_warn(dev, "communication channel command 0x%x timed out\n", - op); - err = -EBUSY; - goto out; + mlx4_warn(dev, "communication channel command 0x%x (op=0x%x) timed out\n", + vhcr_cmd, op); + goto out_reset; } err = context->result; if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) { mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", - op, context->fw_status); - goto out; + vhcr_cmd, context->fw_status); + if (mlx4_closing_cmd_fatal_error(op, context->fw_status)) + goto out_reset; } -out: /* wait for comm channel ready * this is necessary for prevention the race * when switching between event to polling mode + * Skipping this section in case the device is in FATAL_ERROR state, + * In this state, no commands are sent via the comm channel until + * the device has returned from reset. */ - end = msecs_to_jiffies(timeout) + jiffies; - while (comm_pending(dev) && time_before(jiffies, end)) - cond_resched(); + if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { + end = msecs_to_jiffies(timeout) + jiffies; + while (comm_pending(dev) && time_before(jiffies, end)) + cond_resched(); + } + goto out; +out_reset: + err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + mlx4_enter_error_state(dev->persist); +out: spin_lock(&cmd->context_lock); context->next = cmd->free_head; cmd->free_head = context - cmd->context; @@ -363,10 +403,13 @@ out: } int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, - unsigned long timeout) + u16 op, unsigned long timeout) { + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + if (mlx4_priv(dev)->cmd.use_events) - return mlx4_comm_cmd_wait(dev, cmd, param, timeout); + return mlx4_comm_cmd_wait(dev, cmd, param, op, timeout); return mlx4_comm_cmd_poll(dev, cmd, param, timeout); } @@ -502,8 +545,11 @@ static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, } ret = mlx4_status_to_errno(vhcr->status); } + if (ret && + dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + ret = mlx4_internal_err_ret_value(dev, op, op_modifier); } else { - ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, + ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, op, MLX4_COMM_TIME + timeout); if (!ret) { if (out_is_imm) { @@ -517,9 +563,14 @@ static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, } } ret = mlx4_status_to_errno(vhcr->status); - } else - mlx4_err(dev, "failed execution of VHCR_POST command opcode 0x%x\n", - op); + } else { + if (dev->persist->state & + MLX4_DEVICE_STATE_INTERNAL_ERROR) + ret = mlx4_internal_err_ret_value(dev, op, + op_modifier); + else + mlx4_err(dev, "failed execution of VHCR_POST command opcode 0x%x\n", op); + } } mutex_unlock(&priv->cmd.slave_cmd_mutex); @@ -1559,8 +1610,10 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, ALIGN(sizeof(struct mlx4_vhcr_cmd), MLX4_ACCESS_MEM_ALIGN), 1); if (ret) { - mlx4_err(dev, "%s: Failed reading vhcr ret: 0x%x\n", - __func__, ret); + if (!(dev->persist->state & + MLX4_DEVICE_STATE_INTERNAL_ERROR)) + mlx4_err(dev, "%s: Failed reading vhcr ret: 0x%x\n", + __func__, ret); kfree(vhcr); return ret; } @@ -1599,11 +1652,14 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, goto out_status; } - if (mlx4_ACCESS_MEM(dev, inbox->dma, slave, - vhcr->in_param, - MLX4_MAILBOX_SIZE, 1)) { - mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n", - __func__, cmd->opcode); + ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave, + vhcr->in_param, + MLX4_MAILBOX_SIZE, 1); + if (ret) { + if (!(dev->persist->state & + MLX4_DEVICE_STATE_INTERNAL_ERROR)) + mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n", + __func__, cmd->opcode); vhcr_cmd->status = CMD_STAT_INTERNAL_ERR; goto out_status; } @@ -1651,8 +1707,9 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, } if (err) { - mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n", - vhcr->op, slave, vhcr->errno, err); + if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) + mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n", + vhcr->op, slave, vhcr->errno, err); vhcr_cmd->status = mlx4_errno_to_status(err); goto out_status; } @@ -1667,7 +1724,9 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, /* If we failed to write back the outbox after the *command was successfully executed, we must fail this * slave, as it is now in undefined state */ - mlx4_err(dev, "%s:Failed writing outbox\n", __func__); + if (!(dev->persist->state & + MLX4_DEVICE_STATE_INTERNAL_ERROR)) + mlx4_err(dev, "%s:Failed writing outbox\n", __func__); goto out; } } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 1baf1f1e2866..9c7ef0bffb52 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -1484,7 +1484,8 @@ static void mlx4_slave_exit(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); mutex_lock(&priv->cmd.slave_cmd_mutex); - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_TIME)) + if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_CMD_NA_OP, + MLX4_COMM_TIME)) mlx4_warn(dev, "Failed to close slave function\n"); mutex_unlock(&priv->cmd.slave_cmd_mutex); } @@ -1648,7 +1649,7 @@ static int mlx4_init_slave(struct mlx4_dev *dev) mlx4_reset_vf_support(dev); mlx4_warn(dev, "Sending reset\n"); ret_from_reset = mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, - MLX4_COMM_TIME); + MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME); /* if we are in the middle of flr the slave will try * NUM_OF_RESET_RETRIES times before leaving.*/ if (ret_from_reset) { @@ -1673,22 +1674,23 @@ static int mlx4_init_slave(struct mlx4_dev *dev) mlx4_warn(dev, "Sending vhcr0\n"); if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR0, dma >> 48, - MLX4_COMM_TIME)) + MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME)) goto err; if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR1, dma >> 32, - MLX4_COMM_TIME)) + MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME)) goto err; if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR2, dma >> 16, - MLX4_COMM_TIME)) + MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME)) goto err; - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma, MLX4_COMM_TIME)) + if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma, + MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME)) goto err; mutex_unlock(&priv->cmd.slave_cmd_mutex); return 0; err: - mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, 0); + mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_CMD_NA_OP, 0); err_offline: mutex_unlock(&priv->cmd.slave_cmd_mutex); return -EIO; diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index d22d9283d2cd..bd9ea0d01aae 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -1350,6 +1350,9 @@ static int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp, MLX4_CMD_WRAPPED); mlx4_free_cmd_mailbox(dev, mailbox); + if (err && !attach && + dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + err = 0; return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 2a15b8248e77..096a81c16a9b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -123,6 +123,8 @@ enum mlx4_mpt_state { #define MLX4_COMM_TIME 10000 #define MLX4_COMM_OFFLINE_TIME_OUT 30000 +#define MLX4_COMM_CMD_NA_OP 0x0 + enum { MLX4_COMM_CMD_RESET, @@ -1173,7 +1175,7 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev); void mlx4_cmd_use_polling(struct mlx4_dev *dev); int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, - unsigned long timeout); + u16 op, unsigned long timeout); void mlx4_cq_tasklet_cb(unsigned long data); void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn); -- cgit v1.2.1 From 799d44442c4821dec65fc59baa4ddc6783a25c54 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 20 Jan 2015 16:41:59 -0800 Subject: net: phy: fixed: allow setting no update_link callback fixed_phy_set_link_update() contains an early check against a NULL callback pointer, which basically prevents us from removing any previous callback we may have set. The users of the fp->link_update callback deal with a NULL callback just fine, so we really want to allow "removing" a link_update callback to avoid dangling callback pointers during e.g: module removal. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/fixed_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 3ad0e6e16c39..a08a3c78ba97 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -168,7 +168,7 @@ int fixed_phy_set_link_update(struct phy_device *phydev, struct fixed_mdio_bus *fmb = &platform_fmb; struct fixed_phy *fp; - if (!link_update || !phydev || !phydev->bus) + if (!phydev || !phydev->bus) return -EINVAL; list_for_each_entry(fp, &fmb->phys, node) { -- cgit v1.2.1 From 691c9a8fdcbbb27682f151a23e36df35fc250c03 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 20 Jan 2015 16:42:00 -0800 Subject: net: dsa: bcm_sf2: factor interrupt disabling in a function Factor the interrupt disabling in a function: bcm_sf2_intr_disable() since we are doing the same thing in the setup and suspend paths. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index feb29c4526f7..09f6b3cc1f66 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -400,6 +400,16 @@ static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv) return 0; } +static void bcm_sf2_intr_disable(struct bcm_sf2_priv *priv) +{ + intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); + intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); + intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); + intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); + intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); +} + static int bcm_sf2_sw_setup(struct dsa_switch *ds) { const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME; @@ -440,12 +450,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) } /* Disable all interrupts and request them */ - intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); - intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); - intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); - intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); - intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); - intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + bcm_sf2_intr_disable(priv); ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0, "switch_0", priv); @@ -747,12 +752,7 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds) struct bcm_sf2_priv *priv = ds_to_priv(ds); unsigned int port; - intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); - intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); - intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); - intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); - intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); - intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + bcm_sf2_intr_disable(priv); /* Disable all ports physically present including the IMP * port, the other ones have already been disabled during -- cgit v1.2.1 From 24f87d4ce1c548ed702820060c237787b3efae33 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 25 Jan 2015 23:27:14 -0800 Subject: bonding: handle more gso types In commit 5a7baa78851b ("bonding: Advertize vxlan offload features when supported"), Or Gerlitz added support conditional vxlan offload. In this patch I also add support for all kind of tunnels, but we allow a bonding device to not require segmentation, as it is always better to make this segmentation at the very last stage, if a particular slave device requires it. Tested: Setup a GRE tunnel, on a physical NIC not having tx-gre-segmentation. Results on bnx2x are even better, as we no longer have to segment in software. ethtool -K bond0 tx-gre-segmentation off super_netperf 50 --google-pacing-rate 30000000 -H 10.7.8.152 -l 15 7538.32 ethtool -K bond0 tx-gre-segmentation on super_netperf 50 --google-pacing-rate 30000000 -H 10.7.8.152 -l 15 10200.5 Signed-off-by: Eric Dumazet Cc: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 0dceba1a2ba1..f47bc433407a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -998,7 +998,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, NETIF_F_HIGHDMA | NETIF_F_LRO) #define BOND_ENC_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_RXCSUM |\ - NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL) + NETIF_F_TSO) static void bond_compute_features(struct bonding *bond) { @@ -1034,7 +1034,7 @@ static void bond_compute_features(struct bonding *bond) done: bond_dev->vlan_features = vlan_features; - bond_dev->hw_enc_features = enc_features; + bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL; bond_dev->hard_header_len = max_hard_header_len; bond_dev->gso_max_segs = gso_max_segs; netif_set_gso_max_size(bond_dev, gso_max_size); @@ -4010,7 +4010,7 @@ void bond_setup(struct net_device *bond_dev) NETIF_F_HW_VLAN_CTAG_FILTER; bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM); - bond_dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL; + bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL; bond_dev->features |= bond_dev->hw_features; } -- cgit v1.2.1 From ca43e58ca2fb9f8d09578e190d664332e0111ed4 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Wed, 21 Jan 2015 19:07:49 +0800 Subject: net/fsl: drop in_be32() & out_be32() in xgmac_mdio Use ioread32be() & iowrite32be() instead. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/xgmac_mdio.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index 3a76e235fff6..ab9a6bfcae77 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -56,7 +56,7 @@ static int xgmac_wait_until_free(struct device *dev, /* Wait till the bus is free */ status = spin_event_timeout( - !((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY), TIMEOUT, 0); + !((ioread32be(®s->mdio_stat)) & MDIO_STAT_BSY), TIMEOUT, 0); if (!status) { dev_err(dev, "timeout waiting for bus to be free\n"); return -ETIMEDOUT; @@ -75,7 +75,7 @@ static int xgmac_wait_until_done(struct device *dev, /* Wait till the MDIO write is complete */ status = spin_event_timeout( - !((in_be32(®s->mdio_data)) & MDIO_DATA_BSY), TIMEOUT, 0); + !((ioread32be(®s->mdio_data)) & MDIO_DATA_BSY), TIMEOUT, 0); if (!status) { dev_err(dev, "timeout waiting for operation to complete\n"); return -ETIMEDOUT; @@ -96,7 +96,7 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 val u32 mdio_ctl, mdio_stat; int ret; - mdio_stat = in_be32(®s->mdio_stat); + mdio_stat = ioread32be(®s->mdio_stat); if (regnum & MII_ADDR_C45) { /* Clause 45 (ie 10G) */ dev_addr = (regnum >> 16) & 0x1f; @@ -107,7 +107,7 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 val mdio_stat &= ~MDIO_STAT_ENC; } - out_be32(®s->mdio_stat, mdio_stat); + iowrite32be(mdio_stat, ®s->mdio_stat); ret = xgmac_wait_until_free(&bus->dev, regs); if (ret) @@ -115,11 +115,11 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 val /* Set the port and dev addr */ mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); - out_be32(®s->mdio_ctl, mdio_ctl); + iowrite32be(mdio_ctl, ®s->mdio_ctl); /* Set the register address */ if (regnum & MII_ADDR_C45) { - out_be32(®s->mdio_addr, regnum & 0xffff); + iowrite32be(regnum & 0xffff, ®s->mdio_addr); ret = xgmac_wait_until_free(&bus->dev, regs); if (ret) @@ -127,7 +127,7 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 val } /* Write the value to the register */ - out_be32(®s->mdio_data, MDIO_DATA(value)); + iowrite32be(MDIO_DATA(value), ®s->mdio_data); ret = xgmac_wait_until_done(&bus->dev, regs); if (ret) @@ -150,7 +150,7 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) uint16_t value; int ret; - mdio_stat = in_be32(®s->mdio_stat); + mdio_stat = ioread32be(®s->mdio_stat); if (regnum & MII_ADDR_C45) { dev_addr = (regnum >> 16) & 0x1f; mdio_stat |= MDIO_STAT_ENC; @@ -159,7 +159,7 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) mdio_stat &= ~MDIO_STAT_ENC; } - out_be32(®s->mdio_stat, mdio_stat); + iowrite32be(mdio_stat, ®s->mdio_stat); ret = xgmac_wait_until_free(&bus->dev, regs); if (ret) @@ -167,11 +167,11 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) /* Set the Port and Device Addrs */ mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); - out_be32(®s->mdio_ctl, mdio_ctl); + iowrite32be(mdio_ctl, ®s->mdio_ctl); /* Set the register address */ if (regnum & MII_ADDR_C45) { - out_be32(®s->mdio_addr, regnum & 0xffff); + iowrite32be(regnum & 0xffff, ®s->mdio_addr); ret = xgmac_wait_until_free(&bus->dev, regs); if (ret) @@ -179,21 +179,21 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) } /* Initiate the read */ - out_be32(®s->mdio_ctl, mdio_ctl | MDIO_CTL_READ); + iowrite32be(mdio_ctl | MDIO_CTL_READ, ®s->mdio_ctl); ret = xgmac_wait_until_done(&bus->dev, regs); if (ret) return ret; /* Return all Fs if nothing was there */ - if (in_be32(®s->mdio_stat) & MDIO_STAT_RD_ER) { + if (ioread32be(®s->mdio_stat) & MDIO_STAT_RD_ER) { dev_err(&bus->dev, "Error while reading PHY%d reg at %d.%hhu\n", phy_id, dev_addr, regnum); return 0xffff; } - value = in_be32(®s->mdio_data) & 0xffff; + value = ioread32be(®s->mdio_data) & 0xffff; dev_dbg(&bus->dev, "read %04x\n", value); return value; -- cgit v1.2.1 From 22f6bba77fc4aa80ffea31f4c1009993f98aa020 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Wed, 21 Jan 2015 19:08:32 +0800 Subject: net/fsl: Replace spin_event_timeout() with arch independent in xgmac_mdio spin_event_timeout() is PPC dependent, use an arch independent equivalent instead. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/xgmac_mdio.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index ab9a6bfcae77..3a83bc2c613c 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -52,12 +52,16 @@ struct tgec_mdio_controller { static int xgmac_wait_until_free(struct device *dev, struct tgec_mdio_controller __iomem *regs) { - uint32_t status; + unsigned int timeout; /* Wait till the bus is free */ - status = spin_event_timeout( - !((ioread32be(®s->mdio_stat)) & MDIO_STAT_BSY), TIMEOUT, 0); - if (!status) { + timeout = TIMEOUT; + while ((ioread32be(®s->mdio_stat) & MDIO_STAT_BSY) && timeout) { + cpu_relax(); + timeout--; + } + + if (!timeout) { dev_err(dev, "timeout waiting for bus to be free\n"); return -ETIMEDOUT; } @@ -71,12 +75,16 @@ static int xgmac_wait_until_free(struct device *dev, static int xgmac_wait_until_done(struct device *dev, struct tgec_mdio_controller __iomem *regs) { - uint32_t status; + unsigned int timeout; /* Wait till the MDIO write is complete */ - status = spin_event_timeout( - !((ioread32be(®s->mdio_data)) & MDIO_DATA_BSY), TIMEOUT, 0); - if (!status) { + timeout = TIMEOUT; + while ((ioread32be(®s->mdio_data) & MDIO_DATA_BSY) && timeout) { + cpu_relax(); + timeout--; + } + + if (!timeout) { dev_err(dev, "timeout waiting for operation to complete\n"); return -ETIMEDOUT; } -- cgit v1.2.1 From 1793c798c34b03ba033d3905fe0f87b88c48b504 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 21 Jan 2015 20:57:52 +0530 Subject: cxgb4: Fixes cxgb4_inet6addr_notifier unregister call commit b5a02f503caa0837 ("cxgb4 : Update ipv6 address handling api") introduced a regression where unregister cxgb4_inet6addr_notifier wasn't getting called during module_exit. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 1147e1e88314..12c1a3fbf296 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -6290,7 +6290,7 @@ static int __init cxgb4_init_module(void) static void __exit cxgb4_cleanup_module(void) { #if IS_ENABLED(CONFIG_IPV6) - if (inet6addr_registered && list_empty(&adapter_list)) { + if (inet6addr_registered) { unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier); inet6addr_registered = false; } -- cgit v1.2.1 From 3897957494d979ad592a00a6ced4b6c9410e9452 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 21 Jan 2015 19:07:27 +0100 Subject: net: stmmac: add BQL support Add support for Byte Queue Limits to the STMicro MAC driver. Tested on a Amlogic S802 quad Cortex-A9 board, where the use of BQL decreases the latency of a high priority ping from ~12ms to ~1ms when the 100Mbit link is saturated by 20 TCP streams. Signed-off-by: Beniamino Galvani Reviewed-by: Eric Dumazet Acked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 8c6b7c1651e5..d7fc2b5a1408 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1097,6 +1097,7 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags) priv->dirty_tx = 0; priv->cur_tx = 0; + netdev_reset_queue(priv->dev); stmmac_clear_descriptors(priv); @@ -1300,6 +1301,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) static void stmmac_tx_clean(struct stmmac_priv *priv) { unsigned int txsize = priv->dma_tx_size; + unsigned int bytes_compl = 0, pkts_compl = 0; spin_lock(&priv->tx_lock); @@ -1356,6 +1358,8 @@ static void stmmac_tx_clean(struct stmmac_priv *priv) priv->hw->mode->clean_desc3(priv, p); if (likely(skb != NULL)) { + pkts_compl++; + bytes_compl += skb->len; dev_consume_skb_any(skb); priv->tx_skbuff[entry] = NULL; } @@ -1364,6 +1368,9 @@ static void stmmac_tx_clean(struct stmmac_priv *priv) priv->dirty_tx++; } + + netdev_completed_queue(priv->dev, pkts_compl, bytes_compl); + if (unlikely(netif_queue_stopped(priv->dev) && stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) { netif_tx_lock(priv->dev); @@ -1418,6 +1425,7 @@ static void stmmac_tx_err(struct stmmac_priv *priv) (i == txsize - 1)); priv->dirty_tx = 0; priv->cur_tx = 0; + netdev_reset_queue(priv->dev); priv->hw->dma->start_tx(priv->ioaddr); priv->dev->stats.tx_errors++; @@ -2050,6 +2058,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) if (!priv->hwts_tx_en) skb_tx_timestamp(skb); + netdev_sent_queue(dev, skb->len); priv->hw->dma->enable_dma_transmission(priv->ioaddr); spin_unlock(&priv->tx_lock); -- cgit v1.2.1 From e7d7e89846d53e27d6e48a746c5c69e69c22aaaa Mon Sep 17 00:00:00 2001 From: Mikhail Ulyanov Date: Thu, 22 Jan 2015 01:18:44 +0300 Subject: sh_eth: use SET_RUNTIME_PM_OPS() Use SET_RUNTIME_PM_OPS() macro to initialize the runtime PM method pointers in the 'struct dev_pm_ops'. Signed-off-by: Mikhail Ulyanov [Sergei: renamed, added the changelog.] Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 167737fa59de..96219de153e1 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2960,8 +2960,7 @@ static int sh_eth_runtime_nop(struct device *dev) } static const struct dev_pm_ops sh_eth_dev_pm_ops = { - .runtime_suspend = sh_eth_runtime_nop, - .runtime_resume = sh_eth_runtime_nop, + SET_RUNTIME_PM_OPS(sh_eth_runtime_nop, sh_eth_runtime_nop, NULL) }; #define SH_ETH_PM_OPS (&sh_eth_dev_pm_ops) #else -- cgit v1.2.1 From b71af04676e9cfea6be49a8f40db36785017e944 Mon Sep 17 00:00:00 2001 From: Mikhail Ulyanov Date: Thu, 22 Jan 2015 01:19:48 +0300 Subject: sh_eth: add more PM methods Add sh_eth_{suspend|resume}() implementing {suspend|resume|freeze|thaw|poweroff| restore}() PM methods to make it possible to restore from hibernation not only in Linux but also in e.g. U-Boot and to have more determined state on resume/ restore. Signed-off-by: Mikhail Ulyanov [Sergei: moved sh_eth_{suspend|resume}() before sh_eth_runtime_nop(), enclosed them with #ifdef CONFIG_PM_SLEEP, reordered the local variables, got rid of *goto* and label, reordered macro invocations, renamed, modified the changelog.] Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 96219de153e1..fe0277a35507 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2947,6 +2947,36 @@ static int sh_eth_drv_remove(struct platform_device *pdev) } #ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP +static int sh_eth_suspend(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + int ret = 0; + + if (netif_running(ndev)) { + netif_device_detach(ndev); + ret = sh_eth_close(ndev); + } + + return ret; +} + +static int sh_eth_resume(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + int ret = 0; + + if (netif_running(ndev)) { + ret = sh_eth_open(ndev); + if (ret < 0) + return ret; + netif_device_attach(ndev); + } + + return ret; +} +#endif + static int sh_eth_runtime_nop(struct device *dev) { /* Runtime PM callback shared between ->runtime_suspend() @@ -2960,6 +2990,7 @@ static int sh_eth_runtime_nop(struct device *dev) } static const struct dev_pm_ops sh_eth_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sh_eth_suspend, sh_eth_resume) SET_RUNTIME_PM_OPS(sh_eth_runtime_nop, sh_eth_runtime_nop, NULL) }; #define SH_ETH_PM_OPS (&sh_eth_dev_pm_ops) -- cgit v1.2.1 From c405abe2e0623b7841a88d43add2c7c9bc3e74a9 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 22 Jan 2015 14:55:56 +0800 Subject: stmmac: if force_thresh_dma_mode is set, pass tc to both txmode and rxmode in tx_hard_error_bump_tc interrupt Dont' pass SF_DMA_MODE to rxmode in this case. Signed-off-by: Sonic Zhang Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index d7fc2b5a1408..6e2a8fa07da5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1454,7 +1454,11 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv) /* Try to bump up the dma threshold on this failure */ if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { tc += 64; - priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); + if (priv->plat->force_thresh_dma_mode) + priv->hw->dma->dma_mode(priv->ioaddr, tc, tc); + else + priv->hw->dma->dma_mode(priv->ioaddr, tc, + SF_DMA_MODE); priv->xstats.threshold = tc; } } else if (unlikely(status == tx_hard_error)) -- cgit v1.2.1 From dec2165ff38a99f937fe61875d102c6c8596c815 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 22 Jan 2015 14:55:57 +0800 Subject: stmmac: hardware TX COE doesn't work when force_thresh_dma_mode is set Clear the TX COE bit when force_thresh_dma_mode is set even hardware dma capability says support. Tested on BF609. Signed-off-by: Sonic Zhang Acked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 6e2a8fa07da5..5ef493aa5387 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2755,7 +2755,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv) priv->plat->enh_desc = priv->dma_cap.enh_desc; priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up; - priv->plat->tx_coe = priv->dma_cap.tx_coe; + /* TXCOE doesn't work in thresh DMA mode */ + if (priv->plat->force_thresh_dma_mode) + priv->plat->tx_coe = 0; + else + priv->plat->tx_coe = priv->dma_cap.tx_coe; if (priv->dma_cap.rx_coe_type2) priv->plat->rx_coe = STMMAC_RX_COE_TYPE2; -- cgit v1.2.1 From fa067467d84b9ebf6886383fe79715f3df90f255 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 22 Jan 2015 14:55:58 +0800 Subject: stmmac: Add an optional device tree property "snps,burst_len" This property define the AXI bug lenth. Signed-off-by: Sonic Zhang Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 879e29f48a89..fb846ebba1d9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -235,6 +235,9 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, of_property_read_bool(np, "snps,fixed-burst"); dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst"); + of_property_read_u32(np, "snps,burst_len", &dma_cfg->burst_len); + if (dma_cfg->burst_len < 0 || dma_cfg->burst_len > 256) + dma_cfg->burst_len = 0; } plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode"); if (plat->force_thresh_dma_mode) { -- cgit v1.2.1 From 9e86d7667c507c0d6d20a15ebab0340b07389be4 Mon Sep 17 00:00:00 2001 From: Nicolae Rosia Date: Thu, 22 Jan 2015 17:31:05 +0000 Subject: net: macb: allow deffered probe of the driver The driver is trying to acquire clocks which maybe are not available yet. Allow the driver to request deffered probe by providing a probe function and registering it with module_platform_driver. [1] This patch is based on 3.19-rc5. [1] https://lkml.org/lkml/2013/9/23/118 Signed-off-by: Nicolae Rosia Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index f2f9ca00567b..873aa4edd447 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2205,7 +2205,7 @@ static void macb_probe_queues(void __iomem *mem, (*num_queues)++; } -static int __init macb_probe(struct platform_device *pdev) +static int macb_probe(struct platform_device *pdev) { struct macb_platform_data *pdata; struct resource *regs; @@ -2444,7 +2444,7 @@ err_out: return err; } -static int __exit macb_remove(struct platform_device *pdev) +static int macb_remove(struct platform_device *pdev) { struct net_device *dev; struct macb *bp; @@ -2507,7 +2507,8 @@ static int macb_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume); static struct platform_driver macb_driver = { - .remove = __exit_p(macb_remove), + .probe = macb_probe, + .remove = macb_remove, .driver = { .name = "macb", .of_match_table = of_match_ptr(macb_dt_ids), @@ -2515,7 +2516,7 @@ static struct platform_driver macb_driver = { }, }; -module_platform_driver_probe(macb_driver, macb_probe); +module_platform_driver(macb_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver"); -- cgit v1.2.1 From d23823dd61516b279f75356a34b5b93397bc33b0 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 23 Jan 2015 09:36:03 +0100 Subject: net: macb: Remove CONFIG_PM ifdef because of compilation warning Fix compilation warning: drivers/net/ethernet/cadence/macb.c:2415:12: warning: 'macb_suspend' defined but not used [-Wunused-function] static int macb_suspend(struct device *dev) drivers/net/ethernet/cadence/macb.c:2432:12: warning: 'macb_resume' defined but not used [-Wunused-function] static int macb_resume(struct device *dev) when CONFIG_PM=y, CONFIG_PM_SLEEP=n are used. Signed-off-by: Michal Simek Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 873aa4edd447..4f7bd13796b8 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2469,8 +2469,7 @@ static int macb_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int macb_suspend(struct device *dev) +static int __maybe_unused macb_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *netdev = platform_get_drvdata(pdev); @@ -2487,7 +2486,7 @@ static int macb_suspend(struct device *dev) return 0; } -static int macb_resume(struct device *dev) +static int __maybe_unused macb_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *netdev = platform_get_drvdata(pdev); @@ -2502,7 +2501,6 @@ static int macb_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume); -- cgit v1.2.1 From bb92ea5e352db0674dec77491ad44d81d7d9b2e2 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 23 Jan 2015 16:10:36 -0500 Subject: net: dsa/mv88e6xxx: add reg read and write debug This commit adds debug messages for the generic mv88e6xxx read and write routines. The output is similar to this: mdio-gpio mdio-gpio.0: <- addr: 0x1b reg: 0x05 val: 0x4000 mdio-gpio mdio-gpio.0: -> addr: 0x1b reg: 0x07 val: 0x3113 mdio-gpio mdio-gpio.0: -> addr: 0x1b reg: 0x08 val: 0x0330 mdio-gpio mdio-gpio.0: -> addr: 0x1b reg: 0x09 val: 0x0000 This is convenient to dynamically debug operations through debugfs with: echo file mv88e6xxx.c +p > /dynamic_debug/control Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index cd6807c6b4ed..3e7e31a6abb7 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -85,6 +85,12 @@ int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg) ret = __mv88e6xxx_reg_read(bus, ds->pd->sw_addr, addr, reg); mutex_unlock(&ps->smi_mutex); + if (ret < 0) + return ret; + + dev_dbg(ds->master_dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", + addr, reg, ret); + return ret; } @@ -128,6 +134,9 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val) if (bus == NULL) return -EINVAL; + dev_dbg(ds->master_dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", + addr, reg, val); + mutex_lock(&ps->smi_mutex); ret = __mv88e6xxx_reg_write(bus, ds->pd->sw_addr, addr, reg, val); mutex_unlock(&ps->smi_mutex); -- cgit v1.2.1 From b8665c6c16fee59540b14ef145363971dc6cb6c8 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 23 Jan 2015 18:34:41 -0500 Subject: net: dsa/mv88e6352: make mv88e6352_wait generic Some busy bits are available in the global register 1, such as the ATU Busy bit. We may want to use this function to wait for them to change, so add a new parameter to mv88e6352_wait() instead of hard-coding REG_GLOBAL2. In the meantime, since the REG_READ() macro already checks for error, remove the redundant check for ret < 0. Signed-off-by: Vivien Didelot Acked-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6352.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 258d9ef5ef25..e13adc7b3dda 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -22,17 +22,14 @@ #include #include "mv88e6xxx.h" -static int mv88e6352_wait(struct dsa_switch *ds, int reg, u16 mask) +static int mv88e6352_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) { unsigned long timeout = jiffies + HZ / 10; while (time_before(jiffies, timeout)) { int ret; - ret = REG_READ(REG_GLOBAL2, reg); - if (ret < 0) - return ret; - + ret = REG_READ(reg, offset); if (!(ret & mask)) return 0; @@ -43,17 +40,17 @@ static int mv88e6352_wait(struct dsa_switch *ds, int reg, u16 mask) static inline int mv88e6352_phy_wait(struct dsa_switch *ds) { - return mv88e6352_wait(ds, 0x18, 0x8000); + return mv88e6352_wait(ds, REG_GLOBAL2, 0x18, 0x8000); } static inline int mv88e6352_eeprom_load_wait(struct dsa_switch *ds) { - return mv88e6352_wait(ds, 0x14, 0x0800); + return mv88e6352_wait(ds, REG_GLOBAL2, 0x14, 0x0800); } static inline int mv88e6352_eeprom_busy_wait(struct dsa_switch *ds) { - return mv88e6352_wait(ds, 0x14, 0x8000); + return mv88e6352_wait(ds, REG_GLOBAL2, 0x14, 0x8000); } static int __mv88e6352_phy_read(struct dsa_switch *ds, int addr, int regnum) -- cgit v1.2.1 From dc9daab226aaacc2402d46af79a8a4a1765ca53a Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 27 Jan 2015 13:47:45 +0530 Subject: cxgb4: Added support in debugfs to dump sge_qinfo Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 211 +++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 4 +- 3 files changed, 215 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 24fc162ee57a..533a69106513 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1029,6 +1029,8 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter, u64 *pbar2_qoffset, unsigned int *pbar2_qid); +unsigned int qtimer_val(const struct adapter *adap, + const struct sge_rspq *q); int t4_init_sge_params(struct adapter *adapter); int t4_init_tp_params(struct adapter *adap); int t4_filter_field_shift(const struct adapter *adap, int filter_sel); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 714cc70b97cc..eb420e182084 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -1026,6 +1026,216 @@ static const struct file_operations rss_vf_config_debugfs_fops = { .release = seq_release_private }; +static int sge_qinfo_show(struct seq_file *seq, void *v) +{ + struct adapter *adap = seq->private; + int eth_entries = DIV_ROUND_UP(adap->sge.ethqsets, 4); + int toe_entries = DIV_ROUND_UP(adap->sge.ofldqsets, 4); + int rdma_entries = DIV_ROUND_UP(adap->sge.rdmaqs, 4); + int ciq_entries = DIV_ROUND_UP(adap->sge.rdmaciqs, 4); + int ctrl_entries = DIV_ROUND_UP(MAX_CTRL_QUEUES, 4); + int i, r = (uintptr_t)v - 1; + int toe_idx = r - eth_entries; + int rdma_idx = toe_idx - toe_entries; + int ciq_idx = rdma_idx - rdma_entries; + int ctrl_idx = ciq_idx - ciq_entries; + int fq_idx = ctrl_idx - ctrl_entries; + + if (r) + seq_putc(seq, '\n'); + +#define S3(fmt_spec, s, v) \ +do { \ + seq_printf(seq, "%-12s", s); \ + for (i = 0; i < n; ++i) \ + seq_printf(seq, " %16" fmt_spec, v); \ + seq_putc(seq, '\n'); \ +} while (0) +#define S(s, v) S3("s", s, v) +#define T(s, v) S3("u", s, tx[i].v) +#define R(s, v) S3("u", s, rx[i].v) + + if (r < eth_entries) { + int base_qset = r * 4; + const struct sge_eth_rxq *rx = &adap->sge.ethrxq[base_qset]; + const struct sge_eth_txq *tx = &adap->sge.ethtxq[base_qset]; + int n = min(4, adap->sge.ethqsets - 4 * r); + + S("QType:", "Ethernet"); + S("Interface:", + rx[i].rspq.netdev ? rx[i].rspq.netdev->name : "N/A"); + T("TxQ ID:", q.cntxt_id); + T("TxQ size:", q.size); + T("TxQ inuse:", q.in_use); + T("TxQ CIDX:", q.cidx); + T("TxQ PIDX:", q.pidx); +#ifdef CONFIG_CXGB4_DCB + T("DCB Prio:", dcb_prio); + S3("u", "DCB PGID:", + (ethqset2pinfo(adap, base_qset + i)->dcb.pgid >> + 4*(7-tx[i].dcb_prio)) & 0xf); + S3("u", "DCB PFC:", + (ethqset2pinfo(adap, base_qset + i)->dcb.pfcen >> + 1*(7-tx[i].dcb_prio)) & 0x1); +#endif + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + R("RspQ CIDX:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq)); + S3("u", "Intr pktcnt:", + adap->sge.counter_val[rx[i].rspq.pktcnt_idx]); + R("FL ID:", fl.cntxt_id); + R("FL size:", fl.size - 8); + R("FL pend:", fl.pend_cred); + R("FL avail:", fl.avail); + R("FL PIDX:", fl.pidx); + R("FL CIDX:", fl.cidx); + } else if (toe_idx < toe_entries) { + const struct sge_ofld_rxq *rx = &adap->sge.ofldrxq[toe_idx * 4]; + const struct sge_ofld_txq *tx = &adap->sge.ofldtxq[toe_idx * 4]; + int n = min(4, adap->sge.ofldqsets - 4 * toe_idx); + + S("QType:", "TOE"); + T("TxQ ID:", q.cntxt_id); + T("TxQ size:", q.size); + T("TxQ inuse:", q.in_use); + T("TxQ CIDX:", q.cidx); + T("TxQ PIDX:", q.pidx); + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + R("RspQ CIDX:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq)); + S3("u", "Intr pktcnt:", + adap->sge.counter_val[rx[i].rspq.pktcnt_idx]); + R("FL ID:", fl.cntxt_id); + R("FL size:", fl.size - 8); + R("FL pend:", fl.pend_cred); + R("FL avail:", fl.avail); + R("FL PIDX:", fl.pidx); + R("FL CIDX:", fl.cidx); + } else if (rdma_idx < rdma_entries) { + const struct sge_ofld_rxq *rx = + &adap->sge.rdmarxq[rdma_idx * 4]; + int n = min(4, adap->sge.rdmaqs - 4 * rdma_idx); + + S("QType:", "RDMA-CPL"); + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + R("RspQ CIDX:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq)); + S3("u", "Intr pktcnt:", + adap->sge.counter_val[rx[i].rspq.pktcnt_idx]); + R("FL ID:", fl.cntxt_id); + R("FL size:", fl.size - 8); + R("FL pend:", fl.pend_cred); + R("FL avail:", fl.avail); + R("FL PIDX:", fl.pidx); + R("FL CIDX:", fl.cidx); + } else if (ciq_idx < ciq_entries) { + const struct sge_ofld_rxq *rx = &adap->sge.rdmaciq[ciq_idx * 4]; + int n = min(4, adap->sge.rdmaciqs - 4 * ciq_idx); + + S("QType:", "RDMA-CIQ"); + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + R("RspQ CIDX:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq)); + S3("u", "Intr pktcnt:", + adap->sge.counter_val[rx[i].rspq.pktcnt_idx]); + } else if (ctrl_idx < ctrl_entries) { + const struct sge_ctrl_txq *tx = &adap->sge.ctrlq[ctrl_idx * 4]; + int n = min(4, adap->params.nports - 4 * ctrl_idx); + + S("QType:", "Control"); + T("TxQ ID:", q.cntxt_id); + T("TxQ size:", q.size); + T("TxQ inuse:", q.in_use); + T("TxQ CIDX:", q.cidx); + T("TxQ PIDX:", q.pidx); + } else if (fq_idx == 0) { + const struct sge_rspq *evtq = &adap->sge.fw_evtq; + + seq_printf(seq, "%-12s %16s\n", "QType:", "FW event queue"); + seq_printf(seq, "%-12s %16u\n", "RspQ ID:", evtq->abs_id); + seq_printf(seq, "%-12s %16u\n", "RspQ size:", evtq->size); + seq_printf(seq, "%-12s %16u\n", "RspQE size:", evtq->iqe_len); + seq_printf(seq, "%-12s %16u\n", "RspQ CIDX:", evtq->cidx); + seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", evtq->gen); + seq_printf(seq, "%-12s %16u\n", "Intr delay:", + qtimer_val(adap, evtq)); + seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:", + adap->sge.counter_val[evtq->pktcnt_idx]); + } +#undef R +#undef T +#undef S +#undef S3 +return 0; +} + +static int sge_queue_entries(const struct adapter *adap) +{ + return DIV_ROUND_UP(adap->sge.ethqsets, 4) + + DIV_ROUND_UP(adap->sge.ofldqsets, 4) + + DIV_ROUND_UP(adap->sge.rdmaqs, 4) + + DIV_ROUND_UP(adap->sge.rdmaciqs, 4) + + DIV_ROUND_UP(MAX_CTRL_QUEUES, 4) + 1; +} + +static void *sge_queue_start(struct seq_file *seq, loff_t *pos) +{ + int entries = sge_queue_entries(seq->private); + + return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; +} + +static void sge_queue_stop(struct seq_file *seq, void *v) +{ +} + +static void *sge_queue_next(struct seq_file *seq, void *v, loff_t *pos) +{ + int entries = sge_queue_entries(seq->private); + + ++*pos; + return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; +} + +static const struct seq_operations sge_qinfo_seq_ops = { + .start = sge_queue_start, + .next = sge_queue_next, + .stop = sge_queue_stop, + .show = sge_qinfo_show +}; + +static int sge_qinfo_open(struct inode *inode, struct file *file) +{ + int res = seq_open(file, &sge_qinfo_seq_ops); + + if (!res) { + struct seq_file *seq = file->private_data; + + seq->private = inode->i_private; + } + return res; +} + +static const struct file_operations sge_qinfo_debugfs_fops = { + .owner = THIS_MODULE, + .open = sge_qinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + int mem_open(struct inode *inode, struct file *file) { unsigned int mem; @@ -1135,6 +1345,7 @@ int t4_setup_debugfs(struct adapter *adap) { "rss_key", &rss_key_debugfs_fops, S_IRUSR, 0 }, { "rss_pf_config", &rss_pf_config_debugfs_fops, S_IRUSR, 0 }, { "rss_vf_config", &rss_vf_config_debugfs_fops, S_IRUSR, 0 }, + { "sge_qinfo", &sge_qinfo_debugfs_fops, S_IRUSR, 0 }, #if IS_ENABLED(CONFIG_IPV6) { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 }, #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 12c1a3fbf296..c27dcd98ea33 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2500,8 +2500,8 @@ static int closest_thres(const struct sge *s, int thres) /* * Return a queue's interrupt hold-off time in us. 0 means no timer. */ -static unsigned int qtimer_val(const struct adapter *adap, - const struct sge_rspq *q) +unsigned int qtimer_val(const struct adapter *adap, + const struct sge_rspq *q) { unsigned int idx = q->intr_params >> 1; -- cgit v1.2.1 From e5f0e43bee31d38fa5a2e9f9c0fc288b2bca6c88 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 27 Jan 2015 13:47:46 +0530 Subject: cxgb4: Added support in debugfs to dump cim ingress bound queue contents Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 ++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 42 ++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 42 ++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 1 + drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 17 +++++++++ 5 files changed, 104 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 533a69106513..368b5ad20835 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1054,6 +1054,8 @@ int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); +int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, + size_t n); int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, unsigned int *valp); int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index eb420e182084..3f4b07ef580e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -239,6 +239,42 @@ static const struct file_operations cim_qcfg_fops = { .release = single_release, }; +static int cimq_show(struct seq_file *seq, void *v, int idx) +{ + const u32 *p = v; + + seq_printf(seq, "%#06x: %08x %08x %08x %08x\n", idx * 16, p[0], p[1], + p[2], p[3]); + return 0; +} + +static int cim_ibq_open(struct inode *inode, struct file *file) +{ + int ret; + struct seq_tab *p; + unsigned int qid = (uintptr_t)inode->i_private & 7; + struct adapter *adap = inode->i_private - qid; + + p = seq_open_tab(file, CIM_IBQ_SIZE, 4 * sizeof(u32), 0, cimq_show); + if (!p) + return -ENOMEM; + + ret = t4_read_cim_ibq(adap, qid, (u32 *)p->data, CIM_IBQ_SIZE * 4); + if (ret < 0) + seq_release_private(inode, file); + else + ret = 0; + return ret; +} + +static const struct file_operations cim_ibq_fops = { + .owner = THIS_MODULE, + .open = cim_ibq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + /* Firmware Device Log dump. */ static const char * const devlog_level_strings[] = { [FW_DEVLOG_LEVEL_EMERG] = "EMERG", @@ -1346,6 +1382,12 @@ int t4_setup_debugfs(struct adapter *adap) { "rss_pf_config", &rss_pf_config_debugfs_fops, S_IRUSR, 0 }, { "rss_vf_config", &rss_vf_config_debugfs_fops, S_IRUSR, 0 }, { "sge_qinfo", &sge_qinfo_debugfs_fops, S_IRUSR, 0 }, + { "ibq_tp0", &cim_ibq_fops, S_IRUSR, 0 }, + { "ibq_tp1", &cim_ibq_fops, S_IRUSR, 1 }, + { "ibq_ulp", &cim_ibq_fops, S_IRUSR, 2 }, + { "ibq_sge0", &cim_ibq_fops, S_IRUSR, 3 }, + { "ibq_sge1", &cim_ibq_fops, S_IRUSR, 4 }, + { "ibq_ncsi", &cim_ibq_fops, S_IRUSR, 5 }, #if IS_ENABLED(CONFIG_IPV6) { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 }, #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 8f99878a4913..4ea4a4a9c426 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -4525,6 +4525,48 @@ void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres) } } +/** + * t4_read_cim_ibq - read the contents of a CIM inbound queue + * @adap: the adapter + * @qid: the queue index + * @data: where to store the queue contents + * @n: capacity of @data in 32-bit words + * + * Reads the contents of the selected CIM queue starting at address 0 up + * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on + * error and the number of 32-bit words actually read on success. + */ +int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) +{ + int i, err, attempts; + unsigned int addr; + const unsigned int nwords = CIM_IBQ_SIZE * 4; + + if (qid > 5 || (n & 3)) + return -EINVAL; + + addr = qid * nwords; + if (n > nwords) + n = nwords; + + /* It might take 3-10ms before the IBQ debug read access is allowed. + * Wait for 1 Sec with a delay of 1 usec. + */ + attempts = 1000000; + + for (i = 0; i < n; i++, addr++) { + t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, IBQDBGADDR_V(addr) | + IBQDBGEN_F); + err = t4_wait_op_done(adap, CIM_IBQ_DBG_CFG_A, IBQDBGBUSY_F, 0, + attempts, 1); + if (err) + return err; + *data++ = t4_read_reg(adap, CIM_IBQ_DBG_DATA_A); + } + t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, 0); + return i; +} + /** * t4_cim_read - read a block from CIM internal address space * @adap: the adapter diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index f6b82da350e2..6581cd5949d1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -60,6 +60,7 @@ enum { CIM_NUM_OBQ = 6, /* # of CIM OBQs */ CIM_NUM_OBQ_T5 = 8, /* # of CIM OBQs for T5 adapter */ CIMLA_SIZE = 2048, /* # of 32-bit words in CIM LA */ + CIM_IBQ_SIZE = 128, /* # of 128-bit words in a CIM IBQ */ }; enum { diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index e036b563bf3c..39e4b7565a34 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -2538,6 +2538,23 @@ #define HOSTWRITE_V(x) ((x) << HOSTWRITE_S) #define HOSTWRITE_F HOSTWRITE_V(1U) +#define CIM_IBQ_DBG_CFG_A 0x7b60 + +#define IBQDBGADDR_S 16 +#define IBQDBGADDR_M 0xfffU +#define IBQDBGADDR_V(x) ((x) << IBQDBGADDR_S) +#define IBQDBGADDR_G(x) (((x) >> IBQDBGADDR_S) & IBQDBGADDR_M) + +#define IBQDBGBUSY_S 1 +#define IBQDBGBUSY_V(x) ((x) << IBQDBGBUSY_S) +#define IBQDBGBUSY_F IBQDBGBUSY_V(1U) + +#define IBQDBGEN_S 0 +#define IBQDBGEN_V(x) ((x) << IBQDBGEN_S) +#define IBQDBGEN_F IBQDBGEN_V(1U) + +#define CIM_IBQ_DBG_DATA_A 0x7b68 + #define UPDBGLARDEN_S 1 #define UPDBGLARDEN_V(x) ((x) << UPDBGLARDEN_S) #define UPDBGLARDEN_F UPDBGLARDEN_V(1U) -- cgit v1.2.1 From c778af7d18646247310b7bceaf3eacc6eeee1614 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 27 Jan 2015 13:47:47 +0530 Subject: cxgb4: Addded support in debugfs to dump CIM outbound queue content Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 57 ++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 43 ++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 1 + drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 16 ++++++ 5 files changed, 119 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 368b5ad20835..da94b9a2f347 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1056,6 +1056,8 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n); +int t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, + size_t n); int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, unsigned int *valp); int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 3f4b07ef580e..4619bb3ff990 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -104,6 +104,17 @@ struct seq_tab *seq_open_tab(struct file *f, unsigned int rows, return p; } +/* Trim the size of a seq_tab to the supplied number of rows. The operation is + * irreversible. + */ +static int seq_tab_trim(struct seq_tab *p, unsigned int new_rows) +{ + if (new_rows > p->rows) + return -EINVAL; + p->rows = new_rows; + return 0; +} + static int cim_la_show(struct seq_file *seq, void *v, int idx) { if (v == SEQ_START_TOKEN) @@ -275,6 +286,35 @@ static const struct file_operations cim_ibq_fops = { .release = seq_release_private }; +static int cim_obq_open(struct inode *inode, struct file *file) +{ + int ret; + struct seq_tab *p; + unsigned int qid = (uintptr_t)inode->i_private & 7; + struct adapter *adap = inode->i_private - qid; + + p = seq_open_tab(file, 6 * CIM_OBQ_SIZE, 4 * sizeof(u32), 0, cimq_show); + if (!p) + return -ENOMEM; + + ret = t4_read_cim_obq(adap, qid, (u32 *)p->data, 6 * CIM_OBQ_SIZE * 4); + if (ret < 0) { + seq_release_private(inode, file); + } else { + seq_tab_trim(p, ret / 4); + ret = 0; + } + return ret; +} + +static const struct file_operations cim_obq_fops = { + .owner = THIS_MODULE, + .open = cim_obq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + /* Firmware Device Log dump. */ static const char * const devlog_level_strings[] = { [FW_DEVLOG_LEVEL_EMERG] = "EMERG", @@ -1388,14 +1428,31 @@ int t4_setup_debugfs(struct adapter *adap) { "ibq_sge0", &cim_ibq_fops, S_IRUSR, 3 }, { "ibq_sge1", &cim_ibq_fops, S_IRUSR, 4 }, { "ibq_ncsi", &cim_ibq_fops, S_IRUSR, 5 }, + { "obq_ulp0", &cim_obq_fops, S_IRUSR, 0 }, + { "obq_ulp1", &cim_obq_fops, S_IRUSR, 1 }, + { "obq_ulp2", &cim_obq_fops, S_IRUSR, 2 }, + { "obq_ulp3", &cim_obq_fops, S_IRUSR, 3 }, + { "obq_sge", &cim_obq_fops, S_IRUSR, 4 }, + { "obq_ncsi", &cim_obq_fops, S_IRUSR, 5 }, #if IS_ENABLED(CONFIG_IPV6) { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 }, #endif }; + /* Debug FS nodes common to all T5 and later adapters. + */ + static struct t4_debugfs_entry t5_debugfs_files[] = { + { "obq_sge_rx_q0", &cim_obq_fops, S_IRUSR, 6 }, + { "obq_sge_rx_q1", &cim_obq_fops, S_IRUSR, 7 }, + }; + add_debugfs_files(adap, t4_debugfs_files, ARRAY_SIZE(t4_debugfs_files)); + if (!is_t4(adap->params.chip)) + add_debugfs_files(adap, + t5_debugfs_files, + ARRAY_SIZE(t5_debugfs_files)); i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A); if (i & EDRAM0_ENABLE_F) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 4ea4a4a9c426..a3d2f31439c4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -4567,6 +4567,49 @@ int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) return i; } +/** + * t4_read_cim_obq - read the contents of a CIM outbound queue + * @adap: the adapter + * @qid: the queue index + * @data: where to store the queue contents + * @n: capacity of @data in 32-bit words + * + * Reads the contents of the selected CIM queue starting at address 0 up + * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on + * error and the number of 32-bit words actually read on success. + */ +int t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) +{ + int i, err; + unsigned int addr, v, nwords; + int cim_num_obq = is_t4(adap->params.chip) ? + CIM_NUM_OBQ : CIM_NUM_OBQ_T5; + + if ((qid > (cim_num_obq - 1)) || (n & 3)) + return -EINVAL; + + t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F | + QUENUMSELECT_V(qid)); + v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); + + addr = CIMQBASE_G(v) * 64; /* muliple of 256 -> muliple of 4 */ + nwords = CIMQSIZE_G(v) * 64; /* same */ + if (n > nwords) + n = nwords; + + for (i = 0; i < n; i++, addr++) { + t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, OBQDBGADDR_V(addr) | + OBQDBGEN_F); + err = t4_wait_op_done(adap, CIM_OBQ_DBG_CFG_A, OBQDBGBUSY_F, 0, + 2, 1); + if (err) + return err; + *data++ = t4_read_reg(adap, CIM_OBQ_DBG_DATA_A); + } + t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, 0); + return i; +} + /** * t4_cim_read - read a block from CIM internal address space * @adap: the adapter diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index 6581cd5949d1..f9fb81e4826e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -61,6 +61,7 @@ enum { CIM_NUM_OBQ_T5 = 8, /* # of CIM OBQs for T5 adapter */ CIMLA_SIZE = 2048, /* # of 32-bit words in CIM LA */ CIM_IBQ_SIZE = 128, /* # of 128-bit words in a CIM IBQ */ + CIM_OBQ_SIZE = 128, /* # of 128-bit words in a CIM OBQ */ }; enum { diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 39e4b7565a34..1b1560acde2e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -2553,7 +2553,23 @@ #define IBQDBGEN_V(x) ((x) << IBQDBGEN_S) #define IBQDBGEN_F IBQDBGEN_V(1U) +#define CIM_OBQ_DBG_CFG_A 0x7b64 + +#define OBQDBGADDR_S 16 +#define OBQDBGADDR_M 0xfffU +#define OBQDBGADDR_V(x) ((x) << OBQDBGADDR_S) +#define OBQDBGADDR_G(x) (((x) >> OBQDBGADDR_S) & OBQDBGADDR_M) + +#define OBQDBGBUSY_S 1 +#define OBQDBGBUSY_V(x) ((x) << OBQDBGBUSY_S) +#define OBQDBGBUSY_F OBQDBGBUSY_V(1U) + +#define OBQDBGEN_S 0 +#define OBQDBGEN_V(x) ((x) << OBQDBGEN_S) +#define OBQDBGEN_F OBQDBGEN_V(1U) + #define CIM_IBQ_DBG_DATA_A 0x7b68 +#define CIM_OBQ_DBG_DATA_A 0x7b6c #define UPDBGLARDEN_S 1 #define UPDBGLARDEN_V(x) ((x) << UPDBGLARDEN_S) -- cgit v1.2.1 From b3bbe36a26d056cc0b64bb2ee72c9e34c4e8683a Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 27 Jan 2015 13:47:48 +0530 Subject: cxgb4: Added support in debugfs to dump PM module stats Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 66 ++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 54 ++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 1 + drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 12 ++++ 5 files changed, 135 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index da94b9a2f347..d98a44637896 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1054,6 +1054,8 @@ int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); +void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]); +void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]); int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n); int t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 4619bb3ff990..df90c78fb6cc 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -315,6 +315,71 @@ static const struct file_operations cim_obq_fops = { .release = seq_release_private }; +/* Show the PM memory stats. These stats include: + * + * TX: + * Read: memory read operation + * Write Bypass: cut-through + * Bypass + mem: cut-through and save copy + * + * RX: + * Read: memory read + * Write Bypass: cut-through + * Flush: payload trim or drop + */ +static int pm_stats_show(struct seq_file *seq, void *v) +{ + static const char * const tx_pm_stats[] = { + "Read:", "Write bypass:", "Write mem:", "Bypass + mem:" + }; + static const char * const rx_pm_stats[] = { + "Read:", "Write bypass:", "Write mem:", "Flush:" + }; + + int i; + u32 tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; + u64 tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; + struct adapter *adap = seq->private; + + t4_pmtx_get_stats(adap, tx_cnt, tx_cyc); + t4_pmrx_get_stats(adap, rx_cnt, rx_cyc); + + seq_printf(seq, "%13s %10s %20s\n", " ", "Tx pcmds", "Tx bytes"); + for (i = 0; i < PM_NSTATS - 1; i++) + seq_printf(seq, "%-13s %10u %20llu\n", + tx_pm_stats[i], tx_cnt[i], tx_cyc[i]); + + seq_printf(seq, "%13s %10s %20s\n", " ", "Rx pcmds", "Rx bytes"); + for (i = 0; i < PM_NSTATS - 1; i++) + seq_printf(seq, "%-13s %10u %20llu\n", + rx_pm_stats[i], rx_cnt[i], rx_cyc[i]); + return 0; +} + +static int pm_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, pm_stats_show, inode->i_private); +} + +static ssize_t pm_stats_clear(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + struct adapter *adap = FILE_DATA(file)->i_private; + + t4_write_reg(adap, PM_RX_STAT_CONFIG_A, 0); + t4_write_reg(adap, PM_TX_STAT_CONFIG_A, 0); + return count; +} + +static const struct file_operations pm_stats_debugfs_fops = { + .owner = THIS_MODULE, + .open = pm_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = pm_stats_clear +}; + /* Firmware Device Log dump. */ static const char * const devlog_level_strings[] = { [FW_DEVLOG_LEVEL_EMERG] = "EMERG", @@ -1434,6 +1499,7 @@ int t4_setup_debugfs(struct adapter *adap) { "obq_ulp3", &cim_obq_fops, S_IRUSR, 3 }, { "obq_sge", &cim_obq_fops, S_IRUSR, 4 }, { "obq_ncsi", &cim_obq_fops, S_IRUSR, 5 }, + { "pm_stats", &pm_stats_debugfs_fops, S_IRUSR, 0 }, #if IS_ENABLED(CONFIG_IPV6) { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 }, #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index a3d2f31439c4..ea16c623e8b2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -2511,6 +2511,60 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, } } +/** + * t4_pmtx_get_stats - returns the HW stats from PMTX + * @adap: the adapter + * @cnt: where to store the count statistics + * @cycles: where to store the cycle statistics + * + * Returns performance statistics from PMTX. + */ +void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) +{ + int i; + u32 data[2]; + + for (i = 0; i < PM_NSTATS; i++) { + t4_write_reg(adap, PM_TX_STAT_CONFIG_A, i + 1); + cnt[i] = t4_read_reg(adap, PM_TX_STAT_COUNT_A); + if (is_t4(adap->params.chip)) { + cycles[i] = t4_read_reg64(adap, PM_TX_STAT_LSB_A); + } else { + t4_read_indirect(adap, PM_TX_DBG_CTRL_A, + PM_TX_DBG_DATA_A, data, 2, + PM_TX_DBG_STAT_MSB_A); + cycles[i] = (((u64)data[0] << 32) | data[1]); + } + } +} + +/** + * t4_pmrx_get_stats - returns the HW stats from PMRX + * @adap: the adapter + * @cnt: where to store the count statistics + * @cycles: where to store the cycle statistics + * + * Returns performance statistics from PMRX. + */ +void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) +{ + int i; + u32 data[2]; + + for (i = 0; i < PM_NSTATS; i++) { + t4_write_reg(adap, PM_RX_STAT_CONFIG_A, i + 1); + cnt[i] = t4_read_reg(adap, PM_RX_STAT_COUNT_A); + if (is_t4(adap->params.chip)) { + cycles[i] = t4_read_reg64(adap, PM_RX_STAT_LSB_A); + } else { + t4_read_indirect(adap, PM_RX_DBG_CTRL_A, + PM_RX_DBG_DATA_A, data, 2, + PM_RX_DBG_STAT_MSB_A); + cycles[i] = (((u64)data[0] << 32) | data[1]); + } + } +} + /** * get_mps_bg_map - return the buffer groups associated with a port * @adap: the adapter diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index f9fb81e4826e..664375f290ee 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -48,6 +48,7 @@ enum { NMTUS = 16, /* size of MTU table */ NCCTRL_WIN = 32, /* # of congestion control windows */ L2T_SIZE = 4096, /* # of L2T entries */ + PM_NSTATS = 5, /* # of PM stats */ MBOX_LEN = 64, /* mailbox size in bytes */ TRACE_LEN = 112, /* length of trace data and mask */ FILTER_OPT_LEN = 36, /* filter tuple width for optional components */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 1b1560acde2e..7aa0db137df6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1380,6 +1380,12 @@ #define PBL_BOUND_ERR_CH0_F PBL_BOUND_ERR_CH0_V(1U) #define PM_RX_INT_CAUSE_A 0x8fdc +#define PM_RX_STAT_CONFIG_A 0x8fc8 +#define PM_RX_STAT_COUNT_A 0x8fcc +#define PM_RX_STAT_LSB_A 0x8fd0 +#define PM_RX_DBG_CTRL_A 0x8fd0 +#define PM_RX_DBG_DATA_A 0x8fd4 +#define PM_RX_DBG_STAT_MSB_A 0x10013 #define PMRX_FRAMING_ERROR_F 0x003ffff0U @@ -1404,6 +1410,12 @@ #define PMRX_E_PCMD_PAR_ERROR_F PMRX_E_PCMD_PAR_ERROR_V(1U) #define PM_TX_INT_CAUSE_A 0x8ffc +#define PM_TX_STAT_CONFIG_A 0x8fe8 +#define PM_TX_STAT_COUNT_A 0x8fec +#define PM_TX_STAT_LSB_A 0x8ff0 +#define PM_TX_DBG_CTRL_A 0x8ff0 +#define PM_TX_DBG_DATA_A 0x8ff4 +#define PM_TX_DBG_STAT_MSB_A 0x1001a #define PCMD_LEN_OVFL0_S 31 #define PCMD_LEN_OVFL0_V(x) ((x) << PCMD_LEN_OVFL0_S) -- cgit v1.2.1 From b58b667687b71e1f07190ba5faa66e80013eaac6 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 27 Jan 2015 13:47:49 +0530 Subject: cxgb4: Added support in debugfs to dump different timer and clock values of the adapter Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 63 ++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 23 ++++++++ 2 files changed, 86 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index df90c78fb6cc..47c0869f34ca 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -380,6 +380,68 @@ static const struct file_operations pm_stats_debugfs_fops = { .write = pm_stats_clear }; +/* Format a value in a unit that differs from the value's native unit by the + * given factor. + */ +static char *unit_conv(char *buf, size_t len, unsigned int val, + unsigned int factor) +{ + unsigned int rem = val % factor; + + if (rem == 0) { + snprintf(buf, len, "%u", val / factor); + } else { + while (rem % 10 == 0) + rem /= 10; + snprintf(buf, len, "%u.%u", val / factor, rem); + } + return buf; +} + +static int clk_show(struct seq_file *seq, void *v) +{ + char buf[32]; + struct adapter *adap = seq->private; + unsigned int cclk_ps = 1000000000 / adap->params.vpd.cclk; /* in ps */ + u32 res = t4_read_reg(adap, TP_TIMER_RESOLUTION_A); + unsigned int tre = TIMERRESOLUTION_G(res); + unsigned int dack_re = DELAYEDACKRESOLUTION_G(res); + unsigned long long tp_tick_us = (cclk_ps << tre) / 1000000; /* in us */ + + seq_printf(seq, "Core clock period: %s ns\n", + unit_conv(buf, sizeof(buf), cclk_ps, 1000)); + seq_printf(seq, "TP timer tick: %s us\n", + unit_conv(buf, sizeof(buf), (cclk_ps << tre), 1000000)); + seq_printf(seq, "TCP timestamp tick: %s us\n", + unit_conv(buf, sizeof(buf), + (cclk_ps << TIMESTAMPRESOLUTION_G(res)), 1000000)); + seq_printf(seq, "DACK tick: %s us\n", + unit_conv(buf, sizeof(buf), (cclk_ps << dack_re), 1000000)); + seq_printf(seq, "DACK timer: %u us\n", + ((cclk_ps << dack_re) / 1000000) * + t4_read_reg(adap, TP_DACK_TIMER_A)); + seq_printf(seq, "Retransmit min: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_RXT_MIN_A)); + seq_printf(seq, "Retransmit max: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_RXT_MAX_A)); + seq_printf(seq, "Persist timer min: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_PERS_MIN_A)); + seq_printf(seq, "Persist timer max: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_PERS_MAX_A)); + seq_printf(seq, "Keepalive idle timer: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_KEEP_IDLE_A)); + seq_printf(seq, "Keepalive interval: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_KEEP_INTVL_A)); + seq_printf(seq, "Initial SRTT: %llu us\n", + tp_tick_us * INITSRTT_G(t4_read_reg(adap, TP_INIT_SRTT_A))); + seq_printf(seq, "FINWAIT2 timer: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_FINWAIT2_TIMER_A)); + + return 0; +} + +DEFINE_SIMPLE_DEBUGFS_FILE(clk); + /* Firmware Device Log dump. */ static const char * const devlog_level_strings[] = { [FW_DEVLOG_LEVEL_EMERG] = "EMERG", @@ -1478,6 +1540,7 @@ int t4_setup_debugfs(struct adapter *adap) static struct t4_debugfs_entry t4_debugfs_files[] = { { "cim_la", &cim_la_fops, S_IRUSR, 0 }, { "cim_qcfg", &cim_qcfg_fops, S_IRUSR, 0 }, + { "clk", &clk_debugfs_fops, S_IRUSR, 0 }, { "devlog", &devlog_fops, S_IRUSR, 0 }, { "l2t", &t4_l2t_fops, S_IRUSR, 0}, { "mps_tcam", &mps_tcam_debugfs_fops, S_IRUSR, 0 }, diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 7aa0db137df6..940b56cd5caa 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1203,12 +1203,35 @@ #define TIMERRESOLUTION_M 0xffU #define TIMERRESOLUTION_G(x) (((x) >> TIMERRESOLUTION_S) & TIMERRESOLUTION_M) +#define TIMESTAMPRESOLUTION_S 8 +#define TIMESTAMPRESOLUTION_M 0xffU +#define TIMESTAMPRESOLUTION_G(x) \ + (((x) >> TIMESTAMPRESOLUTION_S) & TIMESTAMPRESOLUTION_M) + #define DELAYEDACKRESOLUTION_S 0 #define DELAYEDACKRESOLUTION_M 0xffU #define DELAYEDACKRESOLUTION_G(x) \ (((x) >> DELAYEDACKRESOLUTION_S) & DELAYEDACKRESOLUTION_M) #define TP_SHIFT_CNT_A 0x7dc0 +#define TP_RXT_MIN_A 0x7d98 +#define TP_RXT_MAX_A 0x7d9c +#define TP_PERS_MIN_A 0x7da0 +#define TP_PERS_MAX_A 0x7da4 +#define TP_KEEP_IDLE_A 0x7da8 +#define TP_KEEP_INTVL_A 0x7dac +#define TP_INIT_SRTT_A 0x7db0 +#define TP_DACK_TIMER_A 0x7db4 +#define TP_FINWAIT2_TIMER_A 0x7db8 + +#define INITSRTT_S 0 +#define INITSRTT_M 0xffffU +#define INITSRTT_G(x) (((x) >> INITSRTT_S) & INITSRTT_M) + +#define PERSMAX_S 0 +#define PERSMAX_M 0x3fffffffU +#define PERSMAX_V(x) ((x) << PERSMAX_S) +#define PERSMAX_G(x) (((x) >> PERSMAX_S) & PERSMAX_M) #define SYNSHIFTMAX_S 24 #define SYNSHIFTMAX_M 0xffU -- cgit v1.2.1 From 9272efa2036f3f06625effc3a709416044578a92 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 26 Jan 2015 22:05:37 -0800 Subject: net: phy: utilize phy_suspend and phy_resume phy_suspend and phy_resume are an abstraction on top of the PHY device driver suspend and resume callbacks, utilize those since they are the proper interface to suspending and resuming a PHY device. Acked-by: Fugang Duan Tested-by: Fugang Duan Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 50051f271b10..20447741893a 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -465,7 +465,6 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) static int mdio_bus_suspend(struct device *dev) { - struct phy_driver *phydrv = to_phy_driver(dev->driver); struct phy_device *phydev = to_phy_device(dev); /* We must stop the state machine manually, otherwise it stops out of @@ -479,19 +478,18 @@ static int mdio_bus_suspend(struct device *dev) if (!mdio_bus_phy_may_suspend(phydev)) return 0; - return phydrv->suspend(phydev); + return phy_suspend(phydev); } static int mdio_bus_resume(struct device *dev) { - struct phy_driver *phydrv = to_phy_driver(dev->driver); struct phy_device *phydev = to_phy_device(dev); int ret; if (!mdio_bus_phy_may_suspend(phydev)) goto no_resume; - ret = phydrv->resume(phydev); + ret = phy_resume(phydev); if (ret < 0) return ret; -- cgit v1.2.1 From 8a477a6fb6a33651adda772360b85fd813569743 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 26 Jan 2015 22:05:39 -0800 Subject: net: phy: keep track of the PHY suspend state In order to avoid double calls to phydev->drv->suspend and resume, keep track of whether the PHY has already been suspended as a consequence of a successful call to phy_suspend(). We will use this in our MDIO bus suspend/resume hooks to avoid a double suspend call. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 3fc91e89f5a5..bdfe51fc3a65 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -699,6 +699,7 @@ int phy_suspend(struct phy_device *phydev) { struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; + int ret = 0; /* If the device has WOL enabled, we cannot suspend the PHY */ phy_ethtool_get_wol(phydev, &wol); @@ -706,18 +707,31 @@ int phy_suspend(struct phy_device *phydev) return -EBUSY; if (phydrv->suspend) - return phydrv->suspend(phydev); - return 0; + ret = phydrv->suspend(phydev); + + if (ret) + return ret; + + phydev->suspended = true; + + return ret; } EXPORT_SYMBOL(phy_suspend); int phy_resume(struct phy_device *phydev) { struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); + int ret = 0; if (phydrv->resume) - return phydrv->resume(phydev); - return 0; + ret = phydrv->resume(phydev); + + if (ret) + return ret; + + phydev->suspended = false; + + return ret; } EXPORT_SYMBOL(phy_resume); -- cgit v1.2.1 From 803dd9c77ac3a08958535f2a1ad5890104e2c235 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 26 Jan 2015 22:05:40 -0800 Subject: net: phy: avoid suspending twice a PHY As part of a call to ndo_close() a netdevice driver may call phy_disconnect() -> phy_detach() -> phy_suspend(), such that the PHY is suspsended at this point and a netdevice driver may clock gate the backing peripheral providing MDIO bus accessses as well. Update mdio_bus_phy_may_suspend() to return whether a PHY is allowed to be suspended and conversely resumed if and only if it was not previously suspended before while it is currently in detached (netdev pointer is NULL) state. This fixes bus errors seen during S2/S3 suspend/resume cycles for netdevice drivers such as GENET which clock gates the entire Ethernet MAC, including the MDIO bus block. Acked-by: Fugang Duan Tested-by: Fugang Duan Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 20447741893a..095ef3fe369a 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -443,9 +443,13 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) if (!drv || !phydrv->suspend) return false; - /* PHY not attached? May suspend. */ + /* PHY not attached? May suspend if the PHY has not already been + * suspended as part of a prior call to phy_disconnect() -> + * phy_detach() -> phy_suspend() because the parent netdev might be the + * MDIO bus driver and clock gated at this point. + */ if (!netdev) - return true; + return !phydev->suspended; /* Don't suspend PHY if the attched netdev parent may wakeup. * The parent may point to a PCI device, as in tg3 driver. -- cgit v1.2.1 From 07ac3e7099b5788ee4b78233c96532c6209a304b Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Mon, 26 Jan 2015 15:54:35 -0500 Subject: sunvnet: free pending tx buffers before clearing ring data This patch moves the clearing of ring data in vnet_port_free_tx_bufs to after the freeing of pending buffers in the ring. Otherwise, this can result in dereferencing a NULL pointer. Reported-by: Sowmini Varadhan Signed-off-by: David L Stevens Signed-off-by: David S. Miller --- drivers/net/ethernet/sun/sunvnet.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index b5a1d3d7b0bf..fe044f31708e 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -1637,16 +1637,9 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port) int i; dr = &port->vio.drings[VIO_DRIVER_TX_RING]; - if (dr->base) { - ldc_free_exp_dring(port->vio.lp, dr->base, - (dr->entry_size * dr->num_entries), - dr->cookies, dr->ncookies); - dr->base = NULL; - dr->entry_size = 0; - dr->num_entries = 0; - dr->pending = 0; - dr->ncookies = 0; - } + + if (dr->base == NULL) + return; for (i = 0; i < VNET_TX_RING_SIZE; i++) { struct vio_net_desc *d; @@ -1666,6 +1659,14 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port) port->tx_bufs[i].skb = NULL; d->hdr.state = VIO_DESC_FREE; } + ldc_free_exp_dring(port->vio.lp, dr->base, + (dr->entry_size * dr->num_entries), + dr->cookies, dr->ncookies); + dr->base = NULL; + dr->entry_size = 0; + dr->num_entries = 0; + dr->pending = 0; + dr->ncookies = 0; } static int vnet_port_alloc_tx_ring(struct vnet_port *port) -- cgit v1.2.1 From 8e2b60cd18381a2f102dc6157ea2481a9ddd0001 Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Mon, 26 Jan 2015 15:54:27 -0500 Subject: sunvnet: improve error handling when a remote crashes If a remote machine crashes while there are pending transmit buffers, the sunvnet driver reallocates the ring descriptors giving us enries that have state VIO_DESC_FREE but also an allocated skb. This results in a BUG_ON() call when the remote reboots and we reach that point in the ring. This patch: 1) clears pending tx packets in the ring on port reset 2) changes a BUG_ON() to a pr_warn() when a remote host has given us an invalid descriptor state 3) collapses multiple active buffer frees in a ring to a single message per ring and adds the device name and remote MAC address This fixes the particular problem of not cleaning up pending buffers on a reset, but also prevents us from crashing if the remote handles descriptors out of order or sets an unexpected state for a descriptor. Signed-off-by: David L Stevens Signed-off-by: David S. Miller --- drivers/net/ethernet/sun/sunvnet.c | 62 +++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index fe044f31708e..2b719ccd6e7c 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -50,6 +50,7 @@ MODULE_VERSION(DRV_MODULE_VERSION); #define VNET_MAX_RETRIES 10 static int __vnet_tx_trigger(struct vnet_port *port, u32 start); +static void vnet_port_reset(struct vnet_port *port); /* Ordered from largest major to lowest */ static struct vio_version vnet_versions[] = { @@ -736,9 +737,7 @@ ldc_ctrl: vio_link_state_change(vio, event); if (event == LDC_EVENT_RESET) { - port->rmtu = 0; - port->tso = true; - port->tsolen = 0; + vnet_port_reset(port); vio_port_up(vio); } port->rx_event = 0; @@ -934,36 +933,36 @@ static struct sk_buff *vnet_clean_tx_ring(struct vnet_port *port, *pending = 0; - txi = dr->prod-1; - if (txi < 0) - txi = VNET_TX_RING_SIZE-1; - + txi = dr->prod; for (i = 0; i < VNET_TX_RING_SIZE; ++i) { struct vio_net_desc *d; - d = vio_dring_entry(dr, txi); - - if (d->hdr.state == VIO_DESC_DONE) { - if (port->tx_bufs[txi].skb) { - BUG_ON(port->tx_bufs[txi].skb->next); + --txi; + if (txi < 0) + txi = VNET_TX_RING_SIZE-1; - port->tx_bufs[txi].skb->next = skb; - skb = port->tx_bufs[txi].skb; - port->tx_bufs[txi].skb = NULL; + d = vio_dring_entry(dr, txi); - ldc_unmap(port->vio.lp, - port->tx_bufs[txi].cookies, - port->tx_bufs[txi].ncookies); - } - d->hdr.state = VIO_DESC_FREE; - } else if (d->hdr.state == VIO_DESC_READY) { + if (d->hdr.state == VIO_DESC_READY) { (*pending)++; - } else if (d->hdr.state == VIO_DESC_FREE) { - break; + continue; } - --txi; - if (txi < 0) - txi = VNET_TX_RING_SIZE-1; + if (port->tx_bufs[txi].skb) { + if (d->hdr.state != VIO_DESC_DONE) + pr_notice("invalid ring buffer state %d\n", + d->hdr.state); + BUG_ON(port->tx_bufs[txi].skb->next); + + port->tx_bufs[txi].skb->next = skb; + skb = port->tx_bufs[txi].skb; + port->tx_bufs[txi].skb = NULL; + + ldc_unmap(port->vio.lp, + port->tx_bufs[txi].cookies, + port->tx_bufs[txi].ncookies); + } else if (d->hdr.state == VIO_DESC_FREE) + break; + d->hdr.state = VIO_DESC_FREE; } return skb; } @@ -1649,8 +1648,6 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port) continue; d = vio_dring_entry(dr, i); - if (d->hdr.state == VIO_DESC_READY) - pr_warn("active transmit buffers freed\n"); ldc_unmap(port->vio.lp, port->tx_bufs[i].cookies, @@ -1669,6 +1666,15 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port) dr->ncookies = 0; } +static void vnet_port_reset(struct vnet_port *port) +{ + del_timer(&port->clean_timer); + vnet_port_free_tx_bufs(port); + port->rmtu = 0; + port->tso = true; + port->tsolen = 0; +} + static int vnet_port_alloc_tx_ring(struct vnet_port *port) { struct vio_dring_state *dr; -- cgit v1.2.1 From 9b3320ef702d1c7daf165d5c72c945f0be6b2bed Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 27 Jan 2015 00:58:15 +0000 Subject: net: phy: Invalidate LP advertising flags when restarting or disabling AN It is possible to see the old value of the LP advertising flags through ethtool after reconfiguring the PHY and before autonegotiation completes. If autonegotiation is turned off then the last value seen will persist indefinitely. Signed-off-by: Ben Hutchings Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 767cd110f496..cdcac6aa4260 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -439,6 +439,9 @@ int phy_start_aneg(struct phy_device *phydev) if (AUTONEG_DISABLE == phydev->autoneg) phy_sanitize_settings(phydev); + /* Invalidate LP advertising flags */ + phydev->lp_advertising = 0; + err = phydev->drv->config_aneg(phydev); if (err < 0) goto out_unlock; -- cgit v1.2.1 From 3cb10943fc60b4349a4d7865bdd579bc5c8eaf73 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 22 Jan 2015 21:38:45 +0100 Subject: ath10k: use IEEE80211_HW_SW_CRYPTO_CONTROL The ath10k driver only supports HW crypto (except for management frames or so - CMAC needs to be done in software). Make it use the new IEEE80211_HW_SW_CRYPTO_CONTROL flag to ensure mac80211 doesn't erroneously attempt to use software crypto. Taking through my tree after Kalle's ACK to avoid breaking the ath10k driver with the next crypto patches. Acked-by: Kalle Valo Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2619db1e3e74..bd950bb24087 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -74,6 +74,9 @@ static int ath10k_send_key(struct ath10k_vif *arvif, if (memcmp(macaddr, arvif->vif->addr, ETH_ALEN)) arg.key_flags = WMI_KEY_PAIRWISE; break; + case WLAN_CIPHER_SUITE_AES_CMAC: + /* this one needs to be done in software */ + return 1; default: ath10k_warn(ar, "cipher %d is not supported\n", key->cipher); return -EOPNOTSUPP; @@ -4958,6 +4961,13 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id) int ath10k_mac_register(struct ath10k *ar) { + static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, + }; struct ieee80211_supported_band *band; struct ieee80211_sta_vht_cap vht_cap; struct ieee80211_sta_ht_cap ht_cap; @@ -5030,7 +5040,8 @@ int ath10k_mac_register(struct ath10k *ar) IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_AP_LINK_PS | - IEEE80211_HW_SPECTRUM_MGMT; + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_SW_CRYPTO_CONTROL; ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; @@ -5094,6 +5105,9 @@ int ath10k_mac_register(struct ath10k *ar) goto err_free; } + ar->hw->wiphy->cipher_suites = cipher_suites; + ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + ret = ieee80211_register_hw(ar->hw); if (ret) { ath10k_err(ar, "failed to register ieee80211: %d\n", ret); -- cgit v1.2.1 From 04de6c6ce612ad159d44572b6ed566e57ecefcab Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:47 +0200 Subject: ath10k: implement diag data container event Some firmware revisions may report this event as part of their diagnostics. This avoids `unknown event` warnings and adds tracing for the event. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/trace.h | 41 +++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 68 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 19 +++++++++ 3 files changed, 128 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index b289378b6e3e..1c541f73370d 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -453,6 +453,47 @@ TRACE_EVENT(ath10k_htt_rx_desc, ) ); +TRACE_EVENT(ath10k_wmi_diag_container, + TP_PROTO(struct ath10k *ar, + u8 type, + u32 timestamp, + u32 code, + u16 len, + const void *data), + + TP_ARGS(ar, type, timestamp, code, len, data), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) + __string(driver, dev_driver_string(ar->dev)) + __field(u8, type) + __field(u32, timestamp) + __field(u32, code) + __field(u16, len) + __dynamic_array(u8, data, len) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ar->dev)); + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->type = type; + __entry->timestamp = timestamp; + __entry->code = code; + __entry->len = len; + memcpy(__get_dynamic_array(data), data, len); + ), + + TP_printk( + "%s %s diag container type %hhu timestamp %u code %u len %d", + __get_str(driver), + __get_str(device), + __entry->type, + __entry->timestamp, + __entry->code, + __entry->len + ) +); + #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ /* we don't want to use include/trace/events */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 6f34fc7d663e..56cd51d0ac93 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -60,6 +60,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { = { .min_len = sizeof(struct wmi_tlv_rdy_ev) }, [WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT] = { .min_len = sizeof(struct wmi_tlv_bcn_tx_status_ev) }, + [WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT] + = { .min_len = sizeof(struct wmi_tlv_diag_data_ev) }, }; static int @@ -203,6 +205,69 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar, return 0; } +static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_tlv_diag_data_ev *ev; + const struct wmi_tlv_diag_item *item; + const void *data; + int ret, num_items, len; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT]; + data = tb[WMI_TLV_TAG_ARRAY_BYTE]; + if (!ev || !data) { + kfree(tb); + return -EPROTO; + } + + num_items = __le32_to_cpu(ev->num_items); + len = ath10k_wmi_tlv_len(data); + + while (num_items--) { + if (len == 0) + break; + if (len < sizeof(*item)) { + ath10k_warn(ar, "failed to parse diag data: can't fit item header\n"); + break; + } + + item = data; + + if (len < sizeof(*item) + __le16_to_cpu(item->len)) { + ath10k_warn(ar, "failed to parse diag data: item is too long\n"); + break; + } + + trace_ath10k_wmi_diag_container(ar, + item->type, + __le32_to_cpu(item->timestamp), + __le32_to_cpu(item->code), + __le16_to_cpu(item->len), + item->payload); + + len -= sizeof(*item); + len -= roundup(__le16_to_cpu(item->len), 4); + + data += sizeof(*item); + data += roundup(__le16_to_cpu(item->len), 4); + } + + if (num_items != -1 || len != 0) + ath10k_warn(ar, "failed to parse diag data event: num_items %d len %d\n", + num_items, len); + + kfree(tb); + return 0; +} + /***********/ /* TLV ops */ /***********/ @@ -318,6 +383,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID: ath10k_wmi_tlv_event_bcn_tx_status(ar, skb); break; + case WMI_TLV_DIAG_DATA_CONTAINER_EVENTID: + ath10k_wmi_tlv_event_diag_data(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index eb02290075a7..87db762ac1a2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1409,6 +1409,25 @@ struct wmi_tlv_p2p_go_bcn_ie { __le32 ie_len; } __packed; +enum wmi_tlv_diag_item_type { + WMI_TLV_DIAG_ITEM_TYPE_FW_EVENT, + WMI_TLV_DIAG_ITEM_TYPE_FW_LOG, + WMI_TLV_DIAG_ITEM_TYPE_FW_DEBUG_MSG, +}; + +struct wmi_tlv_diag_item { + u8 type; + u8 reserved; + __le16 len; + __le32 timestamp; + __le32 code; + u8 payload[0]; +} __packed; + +struct wmi_tlv_diag_data_ev { + __le32 num_items; +} __packed; + void ath10k_wmi_tlv_attach(struct ath10k *ar); #endif -- cgit v1.2.1 From c3113c393e81feb2193e000794498625fe4a7d5d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:47 +0200 Subject: ath10k: implement diag event Some firmware revisions may report this event as part of their diagnostics. This avoids `unknown event` warnings and adds tracing for the event. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/trace.h | 27 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index 1c541f73370d..5407887380ab 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -494,6 +494,33 @@ TRACE_EVENT(ath10k_wmi_diag_container, ) ); +TRACE_EVENT(ath10k_wmi_diag, + TP_PROTO(struct ath10k *ar, const void *data, size_t len), + + TP_ARGS(ar, data, len), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) + __string(driver, dev_driver_string(ar->dev)) + __field(u16, len) + __dynamic_array(u8, data, len) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ar->dev)); + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->len = len; + memcpy(__get_dynamic_array(data), data, len); + ), + + TP_printk( + "%s %s tlv diag len %d", + __get_str(driver), + __get_str(device), + __entry->len + ) +); + #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ /* we don't want to use include/trace/events */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 56cd51d0ac93..a6c634a585dd 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -268,6 +268,34 @@ static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar, return 0; } +static int ath10k_wmi_tlv_event_diag(struct ath10k *ar, + struct sk_buff *skb) +{ + const void **tb; + const void *data; + int ret, len; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + data = tb[WMI_TLV_TAG_ARRAY_BYTE]; + if (!data) { + kfree(tb); + return -EPROTO; + } + len = ath10k_wmi_tlv_len(data); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv diag event len %d\n", len); + trace_ath10k_wmi_diag(ar, data, len); + + kfree(tb); + return 0; +} + /***********/ /* TLV ops */ /***********/ @@ -386,6 +414,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_DIAG_DATA_CONTAINER_EVENTID: ath10k_wmi_tlv_event_diag_data(ar, skb); break; + case WMI_TLV_DIAG_EVENTID: + ath10k_wmi_tlv_event_diag(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; -- cgit v1.2.1 From 8582bf3be70f35b6150da37eed9549a585498363 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:47 +0200 Subject: ath10k: introduce struct ath10k_skb_rxcb It doesn't make much sense to share the ath10k_skb_cb with Rx path. The Rx path doesn't need to keep any mac80211's data. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 10 ++++++++++ drivers/net/wireless/ath/ath10k/htt_rx.c | 10 +++++----- drivers/net/wireless/ath/ath10k/pci.c | 6 +++--- 3 files changed, 18 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index c5686122b140..739d9d69cf1c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -97,6 +97,10 @@ struct ath10k_skb_cb { } bcn; } __packed; +struct ath10k_skb_rxcb { + dma_addr_t paddr; +}; + static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) { BUILD_BUG_ON(sizeof(struct ath10k_skb_cb) > @@ -104,6 +108,12 @@ static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) return (struct ath10k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data; } +static inline struct ath10k_skb_rxcb *ATH10K_SKB_RXCB(struct sk_buff *skb) +{ + BUILD_BUG_ON(sizeof(struct ath10k_skb_rxcb) > sizeof(skb->cb)); + return (struct ath10k_skb_rxcb *)skb->cb; +} + static inline u32 host_interest_item_address(u32 item_offset) { return QCA988X_HOST_INTEREST_ADDRESS + item_offset; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index baa1c447a3b8..2e55ed7241ae 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -37,12 +37,12 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr); static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt) { struct sk_buff *skb; - struct ath10k_skb_cb *cb; + struct ath10k_skb_rxcb *cb; int i; for (i = 0; i < htt->rx_ring.fill_cnt; i++) { skb = htt->rx_ring.netbufs_ring[i]; - cb = ATH10K_SKB_CB(skb); + cb = ATH10K_SKB_RXCB(skb); dma_unmap_single(htt->ar->dev, cb->paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); @@ -86,7 +86,7 @@ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) goto fail; } - ATH10K_SKB_CB(skb)->paddr = paddr; + ATH10K_SKB_RXCB(skb)->paddr = paddr; htt->rx_ring.netbufs_ring[idx] = skb; htt->rx_ring.paddrs_ring[idx] = __cpu_to_le32(paddr); htt->rx_ring.fill_cnt++; @@ -168,7 +168,7 @@ static void ath10k_htt_rx_ring_clean_up(struct ath10k_htt *htt) if (!skb) continue; - dma_unmap_single(htt->ar->dev, ATH10K_SKB_CB(skb)->paddr, + dma_unmap_single(htt->ar->dev, ATH10K_SKB_RXCB(skb)->paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); dev_kfree_skb_any(skb); @@ -224,7 +224,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) htt->rx_ring.fill_cnt--; dma_unmap_single(htt->ar->dev, - ATH10K_SKB_CB(msdu)->paddr, + ATH10K_SKB_RXCB(msdu)->paddr, msdu->len + skb_tailroom(msdu), DMA_FROM_DEVICE); ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ", diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 3b40a86304bf..b98354c004f5 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -403,7 +403,7 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) return -EIO; } - ATH10K_SKB_CB(skb)->paddr = paddr; + ATH10K_SKB_RXCB(skb)->paddr = paddr; ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr); if (ret) { @@ -872,7 +872,7 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) &flags) == 0) { skb = transfer_context; max_nbytes = skb->len + skb_tailroom(skb); - dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, + dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, max_nbytes, DMA_FROM_DEVICE); if (unlikely(max_nbytes < nbytes)) { @@ -1238,7 +1238,7 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) ce_ring->per_transfer_context[i] = NULL; - dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, + dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); dev_kfree_skb_any(skb); -- cgit v1.2.1 From c545070e404bfb20e5b72ae725332fe512e5d22c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:48 +0200 Subject: ath10k: implement rx reorder support New firmware and firmware (qca6174 hw3.0+ and fw 266+) are capable of full aggregation rx reordering. If it's enabled then Rx is handled via a new, separate htt event. The rx ring behaviour is changed a little to support the new rx scheme. These changes shouldn't affect qca988x performance. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 12 + drivers/net/wireless/ath/ath10k/core.h | 4 + drivers/net/wireless/ath/ath10k/htt.h | 79 ++++++ drivers/net/wireless/ath/ath10k/htt_rx.c | 393 +++++++++++++++++++++++++++--- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 11 +- 5 files changed, 463 insertions(+), 36 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index a5465752a3ff..6860afbe68d9 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1061,6 +1061,18 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) goto err_hif_stop; } + /* If firmware indicates Full Rx Reorder support it must be used in a + * slightly different manner. Let HTT code know. + */ + ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, + ar->wmi.svc_map)); + + status = ath10k_htt_rx_ring_refill(ar); + if (status) { + ath10k_err(ar, "failed to refill htt rx ring: %d\n", status); + goto err_hif_stop; + } + /* we don't care about HTT in UTF mode */ if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { status = ath10k_htt_setup(&ar->htt); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 739d9d69cf1c..774d8ceb4053 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -99,6 +99,7 @@ struct ath10k_skb_cb { struct ath10k_skb_rxcb { dma_addr_t paddr; + struct hlist_node hlist; }; static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) @@ -114,6 +115,9 @@ static inline struct ath10k_skb_rxcb *ATH10K_SKB_RXCB(struct sk_buff *skb) return (struct ath10k_skb_rxcb *)skb->cb; } +#define ATH10K_RXCB_SKB(rxcb) \ + container_of((void *)rxcb, struct sk_buff, cb) + static inline u32 host_interest_item_address(u32 item_offset) { return QCA988X_HOST_INTEREST_ADDRESS + item_offset; diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 8809b37e1912..d1f6eb287a10 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "htc.h" @@ -286,7 +287,19 @@ enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc, HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd, HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION = 0xe, + HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf, + HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10, + HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11, + HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12, + /* 0x13 reservd */ + HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14, + + /* FIXME: Do not depend on this event id. Numbering of this event id is + * broken across different firmware revisions and HTT version fails to + * indicate this. + */ HTT_T2H_MSG_TYPE_TEST, + /* keep this last */ HTT_T2H_NUM_MSGS }; @@ -655,6 +668,53 @@ struct htt_rx_fragment_indication { #define HTT_RX_FRAG_IND_INFO1_FLUSH_SEQ_NUM_END_MASK 0x00000FC0 #define HTT_RX_FRAG_IND_INFO1_FLUSH_SEQ_NUM_END_LSB 6 +struct htt_rx_pn_ind { + __le16 peer_id; + u8 tid; + u8 seqno_start; + u8 seqno_end; + u8 pn_ie_count; + u8 reserved; + u8 pn_ies[0]; +} __packed; + +struct htt_rx_offload_msdu { + __le16 msdu_len; + __le16 peer_id; + u8 vdev_id; + u8 tid; + u8 fw_desc; + u8 payload[0]; +} __packed; + +struct htt_rx_offload_ind { + u8 reserved; + __le16 msdu_count; +} __packed; + +struct htt_rx_in_ord_msdu_desc { + __le32 msdu_paddr; + __le16 msdu_len; + u8 fw_desc; + u8 reserved; +} __packed; + +struct htt_rx_in_ord_ind { + u8 info; + __le16 peer_id; + u8 vdev_id; + u8 reserved; + __le16 msdu_count; + struct htt_rx_in_ord_msdu_desc msdu_descs[0]; +} __packed; + +#define HTT_RX_IN_ORD_IND_INFO_TID_MASK 0x0000001f +#define HTT_RX_IN_ORD_IND_INFO_TID_LSB 0 +#define HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK 0x00000020 +#define HTT_RX_IN_ORD_IND_INFO_OFFLOAD_LSB 5 +#define HTT_RX_IN_ORD_IND_INFO_FRAG_MASK 0x00000040 +#define HTT_RX_IN_ORD_IND_INFO_FRAG_LSB 6 + /* * target -> host test message definition * @@ -1150,6 +1210,9 @@ struct htt_resp { struct htt_rx_test rx_test; struct htt_pktlog_msg pktlog_msg; struct htt_stats_conf stats_conf; + struct htt_rx_pn_ind rx_pn_ind; + struct htt_rx_offload_ind rx_offload_ind; + struct htt_rx_in_ord_ind rx_in_ord_ind; }; } __packed; @@ -1197,6 +1260,20 @@ struct ath10k_htt { * filled. */ struct sk_buff **netbufs_ring; + + /* This is used only with firmware supporting IN_ORD_IND. + * + * With Full Rx Reorder the HTT Rx Ring is more of a temporary + * buffer ring from which buffer addresses are copied by the + * firmware to MAC Rx ring. Firmware then delivers IN_ORD_IND + * pointing to specific (re-ordered) buffers. + * + * FIXME: With kernel generic hashing functions there's a lot + * of hash collisions for sk_buffs. + */ + bool in_ord_rx; + DECLARE_HASHTABLE(skb_table, 4); + /* * Ring of buffer addresses - * This ring holds the "physical" device address of the @@ -1270,6 +1347,7 @@ struct ath10k_htt { struct tasklet_struct txrx_compl_task; struct sk_buff_head tx_compl_q; struct sk_buff_head rx_compl_q; + struct sk_buff_head rx_in_ord_compl_q; /* rx_status template */ struct ieee80211_rx_status rx_status; @@ -1333,6 +1411,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt); void ath10k_htt_tx_free(struct ath10k_htt *htt); int ath10k_htt_rx_alloc(struct ath10k_htt *htt); +int ath10k_htt_rx_ring_refill(struct ath10k *ar); void ath10k_htt_rx_free(struct ath10k_htt *htt); void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb); diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 2e55ed7241ae..661785fb9906 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -25,8 +25,8 @@ #include -#define HTT_RX_RING_SIZE 1024 -#define HTT_RX_RING_FILL_LEVEL 1000 +#define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX +#define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1) /* when under memory pressure rx ring refill may fail and needs a retry */ #define HTT_RX_RING_REFILL_RETRY_MS 50 @@ -34,31 +34,70 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb); static void ath10k_htt_txrx_compl_task(unsigned long ptr); +static struct sk_buff * +ath10k_htt_rx_find_skb_paddr(struct ath10k *ar, u32 paddr) +{ + struct ath10k_skb_rxcb *rxcb; + + hash_for_each_possible(ar->htt.rx_ring.skb_table, rxcb, hlist, paddr) + if (rxcb->paddr == paddr) + return ATH10K_RXCB_SKB(rxcb); + + WARN_ON_ONCE(1); + return NULL; +} + static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt) { struct sk_buff *skb; - struct ath10k_skb_rxcb *cb; + struct ath10k_skb_rxcb *rxcb; + struct hlist_node *n; int i; - for (i = 0; i < htt->rx_ring.fill_cnt; i++) { - skb = htt->rx_ring.netbufs_ring[i]; - cb = ATH10K_SKB_RXCB(skb); - dma_unmap_single(htt->ar->dev, cb->paddr, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); + if (htt->rx_ring.in_ord_rx) { + hash_for_each_safe(htt->rx_ring.skb_table, i, n, rxcb, hlist) { + skb = ATH10K_RXCB_SKB(rxcb); + dma_unmap_single(htt->ar->dev, rxcb->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + hash_del(&rxcb->hlist); + dev_kfree_skb_any(skb); + } + } else { + for (i = 0; i < htt->rx_ring.size; i++) { + skb = htt->rx_ring.netbufs_ring[i]; + if (!skb) + continue; + + rxcb = ATH10K_SKB_RXCB(skb); + dma_unmap_single(htt->ar->dev, rxcb->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + } } htt->rx_ring.fill_cnt = 0; + hash_init(htt->rx_ring.skb_table); + memset(htt->rx_ring.netbufs_ring, 0, + htt->rx_ring.size * sizeof(htt->rx_ring.netbufs_ring[0])); } static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) { struct htt_rx_desc *rx_desc; + struct ath10k_skb_rxcb *rxcb; struct sk_buff *skb; dma_addr_t paddr; int ret = 0, idx; + /* The Full Rx Reorder firmware has no way of telling the host + * implicitly when it copied HTT Rx Ring buffers to MAC Rx Ring. + * To keep things simple make sure ring is always half empty. This + * guarantees there'll be no replenishment overruns possible. + */ + BUILD_BUG_ON(HTT_RX_RING_FILL_LEVEL >= HTT_RX_RING_SIZE / 2); + idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr); while (num > 0) { skb = dev_alloc_skb(HTT_RX_BUF_SIZE + HTT_RX_DESC_ALIGN); @@ -86,11 +125,18 @@ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) goto fail; } - ATH10K_SKB_RXCB(skb)->paddr = paddr; + rxcb = ATH10K_SKB_RXCB(skb); + rxcb->paddr = paddr; htt->rx_ring.netbufs_ring[idx] = skb; htt->rx_ring.paddrs_ring[idx] = __cpu_to_le32(paddr); htt->rx_ring.fill_cnt++; + if (htt->rx_ring.in_ord_rx) { + hash_add(htt->rx_ring.skb_table, + &ATH10K_SKB_RXCB(skb)->hlist, + (u32)paddr); + } + num--; idx++; idx &= htt->rx_ring.size_mask; @@ -158,22 +204,20 @@ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg) ath10k_htt_rx_msdu_buff_replenish(htt); } -static void ath10k_htt_rx_ring_clean_up(struct ath10k_htt *htt) +int ath10k_htt_rx_ring_refill(struct ath10k *ar) { - struct sk_buff *skb; - int i; + struct ath10k_htt *htt = &ar->htt; + int ret; - for (i = 0; i < htt->rx_ring.size; i++) { - skb = htt->rx_ring.netbufs_ring[i]; - if (!skb) - continue; + spin_lock_bh(&htt->rx_ring.lock); + ret = ath10k_htt_rx_ring_fill_n(htt, (htt->rx_ring.fill_level - + htt->rx_ring.fill_cnt)); + spin_unlock_bh(&htt->rx_ring.lock); - dma_unmap_single(htt->ar->dev, ATH10K_SKB_RXCB(skb)->paddr, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); - htt->rx_ring.netbufs_ring[i] = NULL; - } + if (ret) + ath10k_htt_rx_ring_free(htt); + + return ret; } void ath10k_htt_rx_free(struct ath10k_htt *htt) @@ -184,8 +228,9 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt) skb_queue_purge(&htt->tx_compl_q); skb_queue_purge(&htt->rx_compl_q); + skb_queue_purge(&htt->rx_in_ord_compl_q); - ath10k_htt_rx_ring_clean_up(htt); + ath10k_htt_rx_ring_free(htt); dma_free_coherent(htt->ar->dev, (htt->rx_ring.size * @@ -217,6 +262,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) idx = htt->rx_ring.sw_rd_idx.msdu_payld; msdu = htt->rx_ring.netbufs_ring[idx]; htt->rx_ring.netbufs_ring[idx] = NULL; + htt->rx_ring.paddrs_ring[idx] = 0; idx++; idx &= htt->rx_ring.size_mask; @@ -384,6 +430,82 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr) ath10k_htt_rx_msdu_buff_replenish(htt); } +static struct sk_buff *ath10k_htt_rx_pop_paddr(struct ath10k_htt *htt, + u32 paddr) +{ + struct ath10k *ar = htt->ar; + struct ath10k_skb_rxcb *rxcb; + struct sk_buff *msdu; + + lockdep_assert_held(&htt->rx_ring.lock); + + msdu = ath10k_htt_rx_find_skb_paddr(ar, paddr); + if (!msdu) + return NULL; + + rxcb = ATH10K_SKB_RXCB(msdu); + hash_del(&rxcb->hlist); + htt->rx_ring.fill_cnt--; + + dma_unmap_single(htt->ar->dev, rxcb->paddr, + msdu->len + skb_tailroom(msdu), + DMA_FROM_DEVICE); + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ", + msdu->data, msdu->len + skb_tailroom(msdu)); + + return msdu; +} + +static int ath10k_htt_rx_pop_paddr_list(struct ath10k_htt *htt, + struct htt_rx_in_ord_ind *ev, + struct sk_buff_head *list) +{ + struct ath10k *ar = htt->ar; + struct htt_rx_in_ord_msdu_desc *msdu_desc = ev->msdu_descs; + struct htt_rx_desc *rxd; + struct sk_buff *msdu; + int msdu_count; + bool is_offload; + u32 paddr; + + lockdep_assert_held(&htt->rx_ring.lock); + + msdu_count = __le16_to_cpu(ev->msdu_count); + is_offload = !!(ev->info & HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK); + + while (msdu_count--) { + paddr = __le32_to_cpu(msdu_desc->msdu_paddr); + + msdu = ath10k_htt_rx_pop_paddr(htt, paddr); + if (!msdu) { + __skb_queue_purge(list); + return -ENOENT; + } + + __skb_queue_tail(list, msdu); + + if (!is_offload) { + rxd = (void *)msdu->data; + + trace_ath10k_htt_rx_desc(ar, rxd, sizeof(*rxd)); + + skb_put(msdu, sizeof(*rxd)); + skb_pull(msdu, sizeof(*rxd)); + skb_put(msdu, __le16_to_cpu(msdu_desc->msdu_len)); + + if (!(__le32_to_cpu(rxd->attention.flags) & + RX_ATTENTION_FLAGS_MSDU_DONE)) { + ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n"); + return -EIO; + } + } + + msdu_desc++; + } + + return 0; +} + int ath10k_htt_rx_alloc(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; @@ -429,7 +551,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) htt->rx_ring.alloc_idx.vaddr = vaddr; htt->rx_ring.alloc_idx.paddr = paddr; - htt->rx_ring.sw_rd_idx.msdu_payld = 0; + htt->rx_ring.sw_rd_idx.msdu_payld = htt->rx_ring.size_mask; *htt->rx_ring.alloc_idx.vaddr = 0; /* Initialize the Rx refill retry timer */ @@ -438,14 +560,15 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) spin_lock_init(&htt->rx_ring.lock); htt->rx_ring.fill_cnt = 0; - if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level)) - goto err_fill_ring; + htt->rx_ring.sw_rd_idx.msdu_payld = 0; + hash_init(htt->rx_ring.skb_table); tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task, (unsigned long)htt); skb_queue_head_init(&htt->tx_compl_q); skb_queue_head_init(&htt->rx_compl_q); + skb_queue_head_init(&htt->rx_in_ord_compl_q); tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task, (unsigned long)htt); @@ -454,12 +577,6 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) htt->rx_ring.size, htt->rx_ring.fill_level); return 0; -err_fill_ring: - ath10k_htt_rx_ring_free(htt); - dma_free_coherent(htt->ar->dev, - sizeof(*htt->rx_ring.alloc_idx.vaddr), - htt->rx_ring.alloc_idx.vaddr, - htt->rx_ring.alloc_idx.paddr); err_dma_idx: dma_free_coherent(htt->ar->dev, (htt->rx_ring.size * @@ -1583,6 +1700,194 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp) spin_unlock_bh(&ar->data_lock); } +static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list, + struct sk_buff_head *amsdu) +{ + struct sk_buff *msdu; + struct htt_rx_desc *rxd; + + if (skb_queue_empty(list)) + return -ENOBUFS; + + if (WARN_ON(!skb_queue_empty(amsdu))) + return -EINVAL; + + while ((msdu = __skb_dequeue(list))) { + __skb_queue_tail(amsdu, msdu); + + rxd = (void *)msdu->data - sizeof(*rxd); + if (rxd->msdu_end.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)) + break; + } + + msdu = skb_peek_tail(amsdu); + rxd = (void *)msdu->data - sizeof(*rxd); + if (!(rxd->msdu_end.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))) { + skb_queue_splice_init(amsdu, list); + return -EAGAIN; + } + + return 0; +} + +static void ath10k_htt_rx_h_rx_offload_prot(struct ieee80211_rx_status *status, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!ieee80211_has_protected(hdr->frame_control)) + return; + + /* Offloaded frames are already decrypted but firmware insists they are + * protected in the 802.11 header. Strip the flag. Otherwise mac80211 + * will drop the frame. + */ + + hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); + status->flag |= RX_FLAG_DECRYPTED | + RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED; +} + +static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar, + struct sk_buff_head *list) +{ + struct ath10k_htt *htt = &ar->htt; + struct ieee80211_rx_status *status = &htt->rx_status; + struct htt_rx_offload_msdu *rx; + struct sk_buff *msdu; + size_t offset; + + while ((msdu = __skb_dequeue(list))) { + /* Offloaded frames don't have Rx descriptor. Instead they have + * a short meta information header. + */ + + rx = (void *)msdu->data; + + skb_put(msdu, sizeof(*rx)); + skb_pull(msdu, sizeof(*rx)); + + if (skb_tailroom(msdu) < __le16_to_cpu(rx->msdu_len)) { + ath10k_warn(ar, "dropping frame: offloaded rx msdu is too long!\n"); + dev_kfree_skb_any(msdu); + continue; + } + + skb_put(msdu, __le16_to_cpu(rx->msdu_len)); + + /* Offloaded rx header length isn't multiple of 2 nor 4 so the + * actual payload is unaligned. Align the frame. Otherwise + * mac80211 complains. This shouldn't reduce performance much + * because these offloaded frames are rare. + */ + offset = 4 - ((unsigned long)msdu->data & 3); + skb_put(msdu, offset); + memmove(msdu->data + offset, msdu->data, msdu->len); + skb_pull(msdu, offset); + + /* FIXME: The frame is NWifi. Re-construct QoS Control + * if possible later. + */ + + memset(status, 0, sizeof(*status)); + status->flag |= RX_FLAG_NO_SIGNAL_VAL; + + ath10k_htt_rx_h_rx_offload_prot(status, msdu); + ath10k_htt_rx_h_channel(ar, status); + ath10k_process_rx(ar, status, msdu); + } +} + +static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) +{ + struct ath10k_htt *htt = &ar->htt; + struct htt_resp *resp = (void *)skb->data; + struct ieee80211_rx_status *status = &htt->rx_status; + struct sk_buff_head list; + struct sk_buff_head amsdu; + u16 peer_id; + u16 msdu_count; + u8 vdev_id; + u8 tid; + bool offload; + bool frag; + int ret; + + lockdep_assert_held(&htt->rx_ring.lock); + + if (htt->rx_confused) + return; + + skb_pull(skb, sizeof(resp->hdr)); + skb_pull(skb, sizeof(resp->rx_in_ord_ind)); + + peer_id = __le16_to_cpu(resp->rx_in_ord_ind.peer_id); + msdu_count = __le16_to_cpu(resp->rx_in_ord_ind.msdu_count); + vdev_id = resp->rx_in_ord_ind.vdev_id; + tid = SM(resp->rx_in_ord_ind.info, HTT_RX_IN_ORD_IND_INFO_TID); + offload = !!(resp->rx_in_ord_ind.info & + HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK); + frag = !!(resp->rx_in_ord_ind.info & HTT_RX_IN_ORD_IND_INFO_FRAG_MASK); + + ath10k_dbg(ar, ATH10K_DBG_HTT, + "htt rx in ord vdev %i peer %i tid %i offload %i frag %i msdu count %i\n", + vdev_id, peer_id, tid, offload, frag, msdu_count); + + if (skb->len < msdu_count * sizeof(*resp->rx_in_ord_ind.msdu_descs)) { + ath10k_warn(ar, "dropping invalid in order rx indication\n"); + return; + } + + /* The event can deliver more than 1 A-MSDU. Each A-MSDU is later + * extracted and processed. + */ + __skb_queue_head_init(&list); + ret = ath10k_htt_rx_pop_paddr_list(htt, &resp->rx_in_ord_ind, &list); + if (ret < 0) { + ath10k_warn(ar, "failed to pop paddr list: %d\n", ret); + htt->rx_confused = true; + return; + } + + /* Offloaded frames are very different and need to be handled + * separately. + */ + if (offload) + ath10k_htt_rx_h_rx_offload(ar, &list); + + while (!skb_queue_empty(&list)) { + __skb_queue_head_init(&amsdu); + ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu); + switch (ret) { + case 0: + /* Note: The in-order indication may report interleaved + * frames from different PPDUs meaning reported rx rate + * to mac80211 isn't accurate/reliable. It's still + * better to report something than nothing though. This + * should still give an idea about rx rate to the user. + */ + ath10k_htt_rx_h_ppdu(ar, &amsdu, status); + ath10k_htt_rx_h_filter(ar, &amsdu, status); + ath10k_htt_rx_h_mpdu(ar, &amsdu, status); + ath10k_htt_rx_h_deliver(ar, &amsdu, status); + break; + case -EAGAIN: + /* fall through */ + default: + /* Should not happen. */ + ath10k_warn(ar, "failed to extract amsdu: %d\n", ret); + htt->rx_confused = true; + __skb_queue_purge(&list); + return; + } + } + + tasklet_schedule(&htt->rx_replenish_task); +} + void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_htt *htt = &ar->htt; @@ -1705,6 +2010,20 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) */ break; } + case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: { + spin_lock_bh(&htt->rx_ring.lock); + __skb_queue_tail(&htt->rx_in_ord_compl_q, skb); + spin_unlock_bh(&htt->rx_ring.lock); + tasklet_schedule(&htt->txrx_compl_task); + return; + } + case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND: + /* FIXME: This WMI-TLV event is overlapping with 10.2 + * CHAN_CHANGE - both being 0xF. Neither is being used in + * practice so no immediate action is necessary. Nevertheless + * HTT may need an abstraction layer like WMI has one day. + */ + break; default: ath10k_warn(ar, "htt event (%d) not handled\n", resp->hdr.msg_type); @@ -1720,6 +2039,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) static void ath10k_htt_txrx_compl_task(unsigned long ptr) { struct ath10k_htt *htt = (struct ath10k_htt *)ptr; + struct ath10k *ar = htt->ar; struct htt_resp *resp; struct sk_buff *skb; @@ -1736,5 +2056,10 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) ath10k_htt_rx_handler(htt, &resp->rx_ind); dev_kfree_skb_any(skb); } + + while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) { + ath10k_htt_rx_in_ord_ind(ar, skb); + dev_kfree_skb_any(skb); + } spin_unlock_bh(&htt->rx_ring.lock); } diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index a6c634a585dd..35f519123752 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1052,8 +1052,15 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS); - cfg->num_offload_peers = __cpu_to_le32(0); - cfg->num_offload_reorder_bufs = __cpu_to_le32(0); + + if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) { + cfg->num_offload_peers = __cpu_to_le32(3); + cfg->num_offload_reorder_bufs = __cpu_to_le32(3); + } else { + cfg->num_offload_peers = __cpu_to_le32(0); + cfg->num_offload_reorder_bufs = __cpu_to_le32(0); + } + cfg->num_peer_keys = __cpu_to_le32(2); cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS); cfg->ast_skid_limit = __cpu_to_le32(0x10); -- cgit v1.2.1 From 1a7fecb766c83dace747f42b25bbb544b00a0163 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:48 +0200 Subject: ath10k: reset chip before reading chip_id in probe There are some very rare cases with some hardware configuration that the device doesn't init quickly enough in which case reading chip_id yielded 0. This caused driver to subsequently fail to setup the device. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index b98354c004f5..e0c9f4633a82 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2544,18 +2544,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_release; } - chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); - if (chip_id == 0xffffffff) { - ath10k_err(ar, "failed to get chip id\n"); - goto err_sleep; - } - - if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) { - ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", - pdev->device, chip_id); - goto err_sleep; - } - ret = ath10k_pci_alloc_pipes(ar); if (ret) { ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", @@ -2582,6 +2570,24 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_deinit_irq; } + ret = ath10k_pci_chip_reset(ar); + if (ret) { + ath10k_err(ar, "failed to reset chip: %d\n", ret); + goto err_free_irq; + } + + chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); + if (chip_id == 0xffffffff) { + ath10k_err(ar, "failed to get chip id\n"); + goto err_free_irq; + } + + if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) { + ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", + pdev->device, chip_id); + goto err_sleep; + } + ath10k_pci_sleep(ar); ret = ath10k_core_register(ar, chip_id); -- cgit v1.2.1 From 3ec79e3a75ed062cb0c13ceef0690929b777cf59 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:48 +0200 Subject: ath10k: add support for qca6174 Rx descriptors The QCA6174 chip has an extra 4 bytes in rx_ppdu_end structure which is used in htt_rx_desc and HTT Rx ring offset setup. This is necessary for correct Rx for QCA6174 (otherwise Rx descriptors are overwritten and corrupted). This means QCA988X will have an extra 4 byte padding in Rx descriptor layout which is harmless. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 +- drivers/net/wireless/ath/ath10k/rx_desc.h | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 661785fb9906..c1da44f65a4d 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -813,7 +813,7 @@ static void ath10k_htt_rx_h_mactime(struct ath10k *ar, * * FIXME: Can we get/compute 64bit TSF? */ - status->mactime = __le32_to_cpu(rxd->ppdu_end.tsf_timestamp); + status->mactime = __le32_to_cpu(rxd->ppdu_end.common.tsf_timestamp); status->flag |= RX_FLAG_MACTIME_END; } diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index e1ffdd57a18c..e9cc7787bf5f 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -850,7 +850,7 @@ struct rx_ppdu_start { #define RX_PPDU_END_INFO1_PPDU_DONE (1 << 15) -struct rx_ppdu_end { +struct rx_ppdu_end_common { __le32 evm_p0; __le32 evm_p1; __le32 evm_p2; @@ -873,10 +873,33 @@ struct rx_ppdu_end { u8 phy_err_code; __le16 flags; /* %RX_PPDU_END_FLAGS_ */ __le32 info0; /* %RX_PPDU_END_INFO0_ */ +} __packed; + +struct rx_ppdu_end_qca988x { __le16 bb_length; __le16 info1; /* %RX_PPDU_END_INFO1_ */ } __packed; +#define RX_PPDU_END_RTT_CORRELATION_VALUE_MASK 0x00ffffff +#define RX_PPDU_END_RTT_CORRELATION_VALUE_LSB 0 +#define RX_PPDU_END_RTT_UNUSED_MASK 0x7f000000 +#define RX_PPDU_END_RTT_UNUSED_LSB 24 +#define RX_PPDU_END_RTT_NORMAL_MODE BIT(31) + +struct rx_ppdu_end_qca6174 { + __le32 rtt; /* %RX_PPDU_END_RTT_ */ + __le16 bb_length; + __le16 info1; /* %RX_PPDU_END_INFO1_ */ +} __packed; + +struct rx_ppdu_end { + struct rx_ppdu_end_common common; + union { + struct rx_ppdu_end_qca988x qca988x; + struct rx_ppdu_end_qca6174 qca6174; + } __packed; +} __packed; + /* * evm_p0 * EVM for pilot 0. Contain EVM for streams: 0, 1, 2 and 3. -- cgit v1.2.1 From d63955b33b3bee45d784ffdfafeb93076c765660 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:49 +0200 Subject: ath10k: add support for qca6174 The QCA6174 in combination with new wmi-tlv firmware is capable of multi-channel, beamforming, tdls and other features. This patch just makes it possible to boot these devices and do some basic stuff like connect to an AP without encryption. Some things may not work or may be unreliable. New features will be implemented later. This will be addressed eventually with future patches. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Makefile | 3 +- drivers/net/wireless/ath/ath10k/ce.c | 12 ++-- drivers/net/wireless/ath/ath10k/ce.h | 2 +- drivers/net/wireless/ath/ath10k/core.c | 44 ++++++++++++ drivers/net/wireless/ath/ath10k/core.h | 6 +- drivers/net/wireless/ath/ath10k/hw.c | 58 +++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 102 ++++++++++++++++++++++----- drivers/net/wireless/ath/ath10k/pci.c | 105 ++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath10k/targaddrs.h | 5 ++ 9 files changed, 302 insertions(+), 35 deletions(-) create mode 100644 drivers/net/wireless/ath/ath10k/hw.c (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 6c0c23e79bda..f4dbb3e93bf8 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -9,7 +9,8 @@ ath10k_core-y += mac.o \ txrx.o \ wmi.o \ wmi-tlv.o \ - bmi.o + bmi.o \ + hw.o ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 42ec79327943..e508c65b6ba8 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -803,7 +803,7 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar) int ce_id; for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { - u32 ctrl_addr = ath10k_ce_base_address(ce_id); + u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); ath10k_ce_error_intr_disable(ar, ctrl_addr); @@ -832,7 +832,7 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; struct ath10k_ce_ring *src_ring = ce_state->src_ring; - u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); + u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); nentries = roundup_pow_of_two(attr->src_nentries); @@ -869,7 +869,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; - u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); + u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); nentries = roundup_pow_of_two(attr->dest_nentries); @@ -1051,7 +1051,7 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) { - u32 ctrl_addr = ath10k_ce_base_address(ce_id); + u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0); ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0); @@ -1061,7 +1061,7 @@ static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id) { - u32 ctrl_addr = ath10k_ce_base_address(ce_id); + u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0); ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0); @@ -1098,7 +1098,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, ce_state->ar = ar; ce_state->id = ce_id; - ce_state->ctrl_addr = ath10k_ce_base_address(ce_id); + ce_state->ctrl_addr = ath10k_ce_base_address(ar, ce_id); ce_state->attr_flags = attr->flags; ce_state->src_sz_max = attr->src_sz_max; diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 617a151e8ce4..c18647b87f71 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -394,7 +394,7 @@ struct ce_attr { #define DST_WATERMARK_HIGH_RESET 0 #define DST_WATERMARK_ADDRESS 0x0050 -static inline u32 ath10k_ce_base_address(unsigned int ce_id) +static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) { return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id; } diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 6860afbe68d9..5e9e1a6958f4 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -57,6 +57,34 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ, }, }, + { + .id = QCA6174_HW_2_1_VERSION, + .name = "qca6174 hw2.1", + .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, + .uart_pin = 6, + .fw = { + .dir = QCA6174_HW_2_1_FW_DIR, + .fw = QCA6174_HW_2_1_FW_FILE, + .otp = QCA6174_HW_2_1_OTP_FILE, + .board = QCA6174_HW_2_1_BOARD_DATA_FILE, + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, + }, + { + .id = QCA6174_HW_3_0_VERSION, + .name = "qca6174 hw3.0", + .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, + .uart_pin = 6, + .fw = { + .dir = QCA6174_HW_3_0_FW_DIR, + .fw = QCA6174_HW_3_0_FW_FILE, + .otp = QCA6174_HW_3_0_OTP_FILE, + .board = QCA6174_HW_3_0_BOARD_DATA_FILE, + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, + }, }; static void ath10k_send_suspend_complete(struct ath10k *ar) @@ -1308,6 +1336,7 @@ EXPORT_SYMBOL(ath10k_core_unregister); struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, enum ath10k_bus bus, + enum ath10k_hw_rev hw_rev, const struct ath10k_hif_ops *hif_ops) { struct ath10k *ar; @@ -1320,9 +1349,24 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ar->ath_common.priv = ar; ar->ath_common.hw = ar->hw; ar->dev = dev; + ar->hw_rev = hw_rev; ar->hif.ops = hif_ops; ar->hif.bus = bus; + switch (hw_rev) { + case ATH10K_HW_QCA988X: + ar->regs = &qca988x_regs; + break; + case ATH10K_HW_QCA6174: + ar->regs = &qca6174_regs; + break; + default: + ath10k_err(ar, "unsupported core hardware revision %d\n", + hw_rev); + ret = -ENOTSUPP; + goto err_free_mac; + } + init_completion(&ar->scan.started); init_completion(&ar->scan.completed); init_completion(&ar->scan.on_channel); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 774d8ceb4053..2d9f87143089 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -471,6 +471,7 @@ struct ath10k { struct device *dev; u8 mac_addr[ETH_ALEN]; + enum ath10k_hw_rev hw_rev; u32 chip_id; u32 target_version; u8 fw_version_major; @@ -486,9 +487,6 @@ struct ath10k { DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT); - struct targetdef *targetdef; - struct hostdef *hostdef; - bool p2p; struct { @@ -498,6 +496,7 @@ struct ath10k { struct completion target_suspend; + const struct ath10k_hw_regs *regs; struct ath10k_bmi bmi; struct ath10k_wmi wmi; struct ath10k_htc htc; @@ -662,6 +661,7 @@ struct ath10k { struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, enum ath10k_bus bus, + enum ath10k_hw_rev hw_rev, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c new file mode 100644 index 000000000000..839a8791fb9e --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "hw.h" + +const struct ath10k_hw_regs qca988x_regs = { + .rtc_state_cold_reset_mask = 0x00000400, + .rtc_soc_base_address = 0x00004000, + .rtc_wmac_base_address = 0x00005000, + .soc_core_base_address = 0x00009000, + .ce_wrapper_base_address = 0x00057000, + .ce0_base_address = 0x00057400, + .ce1_base_address = 0x00057800, + .ce2_base_address = 0x00057c00, + .ce3_base_address = 0x00058000, + .ce4_base_address = 0x00058400, + .ce5_base_address = 0x00058800, + .ce6_base_address = 0x00058c00, + .ce7_base_address = 0x00059000, + .soc_reset_control_si0_rst_mask = 0x00000001, + .soc_reset_control_ce_rst_mask = 0x00040000, + .soc_chip_id_address = 0x00ec, + .scratch_3_address = 0x0030, +}; + +const struct ath10k_hw_regs qca6174_regs = { + .rtc_state_cold_reset_mask = 0x00002000, + .rtc_soc_base_address = 0x00000800, + .rtc_wmac_base_address = 0x00001000, + .soc_core_base_address = 0x0003a000, + .ce_wrapper_base_address = 0x00034000, + .ce0_base_address = 0x00034400, + .ce1_base_address = 0x00034800, + .ce2_base_address = 0x00034c00, + .ce3_base_address = 0x00035000, + .ce4_base_address = 0x00035400, + .ce5_base_address = 0x00035800, + .ce6_base_address = 0x00035c00, + .ce7_base_address = 0x00036000, + .soc_reset_control_si0_rst_mask = 0x00000000, + .soc_reset_control_ce_rst_mask = 0x00000001, + .soc_chip_id_address = 0x000f0, + .scratch_3_address = 0x0028, +}; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 7b771ae7789f..577127844ec8 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -34,6 +34,43 @@ #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234 +/* QCA6174 target BMI version signatures */ +#define QCA6174_HW_1_0_VERSION 0x05000000 +#define QCA6174_HW_1_1_VERSION 0x05000001 +#define QCA6174_HW_1_3_VERSION 0x05000003 +#define QCA6174_HW_2_1_VERSION 0x05010000 +#define QCA6174_HW_3_0_VERSION 0x05020000 + +enum qca6174_pci_rev { + QCA6174_PCI_REV_1_1 = 0x11, + QCA6174_PCI_REV_1_3 = 0x13, + QCA6174_PCI_REV_2_0 = 0x20, + QCA6174_PCI_REV_3_0 = 0x30, +}; + +enum qca6174_chip_id_rev { + QCA6174_HW_1_0_CHIP_ID_REV = 0, + QCA6174_HW_1_1_CHIP_ID_REV = 1, + QCA6174_HW_1_3_CHIP_ID_REV = 2, + QCA6174_HW_2_1_CHIP_ID_REV = 4, + QCA6174_HW_2_2_CHIP_ID_REV = 5, + QCA6174_HW_3_0_CHIP_ID_REV = 8, + QCA6174_HW_3_1_CHIP_ID_REV = 9, + QCA6174_HW_3_2_CHIP_ID_REV = 10, +}; + +#define QCA6174_HW_2_1_FW_DIR "ath10k/QCA6174/hw2.1" +#define QCA6174_HW_2_1_FW_FILE "firmware.bin" +#define QCA6174_HW_2_1_OTP_FILE "otp.bin" +#define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin" +#define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234 + +#define QCA6174_HW_3_0_FW_DIR "ath10k/QCA6174/hw3.0" +#define QCA6174_HW_3_0_FW_FILE "firmware.bin" +#define QCA6174_HW_3_0_OTP_FILE "otp.bin" +#define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin" +#define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234 + #define ATH10K_FW_API2_FILE "firmware-2.bin" #define ATH10K_FW_API3_FILE "firmware-3.bin" @@ -81,6 +118,37 @@ enum ath10k_fw_wmi_op_version { ATH10K_FW_WMI_OP_VERSION_MAX, }; +enum ath10k_hw_rev { + ATH10K_HW_QCA988X, + ATH10K_HW_QCA6174, +}; + +struct ath10k_hw_regs { + u32 rtc_state_cold_reset_mask; + u32 rtc_soc_base_address; + u32 rtc_wmac_base_address; + u32 soc_core_base_address; + u32 ce_wrapper_base_address; + u32 ce0_base_address; + u32 ce1_base_address; + u32 ce2_base_address; + u32 ce3_base_address; + u32 ce4_base_address; + u32 ce5_base_address; + u32 ce6_base_address; + u32 ce7_base_address; + u32 soc_reset_control_si0_rst_mask; + u32 soc_reset_control_ce_rst_mask; + u32 soc_chip_id_address; + u32 scratch_3_address; +}; + +extern const struct ath10k_hw_regs qca988x_regs; +extern const struct ath10k_hw_regs qca6174_regs; + +#define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) +#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) + /* Known pecularities: * - current FW doesn't support raw rx mode (last tested v599) * - current FW dumps upon raw tx mode (last tested v599) @@ -225,7 +293,7 @@ struct ath10k_pktlog_hdr { /* as of IP3.7.1 */ #define RTC_STATE_V_ON 3 -#define RTC_STATE_COLD_RESET_MASK 0x00000400 +#define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask #define RTC_STATE_V_LSB 0 #define RTC_STATE_V_MASK 0x00000007 #define RTC_STATE_ADDRESS 0x0000 @@ -234,12 +302,12 @@ struct ath10k_pktlog_hdr { #define PCIE_SOC_WAKE_RESET 0x00000000 #define SOC_GLOBAL_RESET_ADDRESS 0x0008 -#define RTC_SOC_BASE_ADDRESS 0x00004000 -#define RTC_WMAC_BASE_ADDRESS 0x00005000 +#define RTC_SOC_BASE_ADDRESS ar->regs->rtc_soc_base_address +#define RTC_WMAC_BASE_ADDRESS ar->regs->rtc_wmac_base_address #define MAC_COEX_BASE_ADDRESS 0x00006000 #define BT_COEX_BASE_ADDRESS 0x00007000 #define SOC_PCIE_BASE_ADDRESS 0x00008000 -#define SOC_CORE_BASE_ADDRESS 0x00009000 +#define SOC_CORE_BASE_ADDRESS ar->regs->soc_core_base_address #define WLAN_UART_BASE_ADDRESS 0x0000c000 #define WLAN_SI_BASE_ADDRESS 0x00010000 #define WLAN_GPIO_BASE_ADDRESS 0x00014000 @@ -248,23 +316,23 @@ struct ath10k_pktlog_hdr { #define EFUSE_BASE_ADDRESS 0x00030000 #define FPGA_REG_BASE_ADDRESS 0x00039000 #define WLAN_UART2_BASE_ADDRESS 0x00054c00 -#define CE_WRAPPER_BASE_ADDRESS 0x00057000 -#define CE0_BASE_ADDRESS 0x00057400 -#define CE1_BASE_ADDRESS 0x00057800 -#define CE2_BASE_ADDRESS 0x00057c00 -#define CE3_BASE_ADDRESS 0x00058000 -#define CE4_BASE_ADDRESS 0x00058400 -#define CE5_BASE_ADDRESS 0x00058800 -#define CE6_BASE_ADDRESS 0x00058c00 -#define CE7_BASE_ADDRESS 0x00059000 +#define CE_WRAPPER_BASE_ADDRESS ar->regs->ce_wrapper_base_address +#define CE0_BASE_ADDRESS ar->regs->ce0_base_address +#define CE1_BASE_ADDRESS ar->regs->ce1_base_address +#define CE2_BASE_ADDRESS ar->regs->ce2_base_address +#define CE3_BASE_ADDRESS ar->regs->ce3_base_address +#define CE4_BASE_ADDRESS ar->regs->ce4_base_address +#define CE5_BASE_ADDRESS ar->regs->ce5_base_address +#define CE6_BASE_ADDRESS ar->regs->ce6_base_address +#define CE7_BASE_ADDRESS ar->regs->ce7_base_address #define DBI_BASE_ADDRESS 0x00060000 #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 #define PCIE_LOCAL_BASE_ADDRESS 0x00080000 #define SOC_RESET_CONTROL_ADDRESS 0x00000000 #define SOC_RESET_CONTROL_OFFSET 0x00000000 -#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 -#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000 +#define SOC_RESET_CONTROL_SI0_RST_MASK ar->regs->soc_reset_control_si0_rst_mask +#define SOC_RESET_CONTROL_CE_RST_MASK ar->regs->soc_reset_control_ce_rst_mask #define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 #define SOC_CPU_CLOCK_OFFSET 0x00000020 #define SOC_CPU_CLOCK_STANDARD_LSB 0 @@ -278,7 +346,7 @@ struct ath10k_pktlog_hdr { #define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 #define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 -#define SOC_CHIP_ID_ADDRESS 0x000000ec +#define SOC_CHIP_ID_ADDRESS ar->regs->soc_chip_id_address #define SOC_CHIP_ID_REV_LSB 8 #define SOC_CHIP_ID_REV_MASK 0x00000f00 @@ -334,7 +402,7 @@ struct ath10k_pktlog_hdr { #define PCIE_INTR_ENABLE_ADDRESS 0x0008 #define PCIE_INTR_CAUSE_ADDRESS 0x000c #define PCIE_INTR_CLR_ADDRESS 0x0014 -#define SCRATCH_3_ADDRESS 0x0030 +#define SCRATCH_3_ADDRESS ar->regs->scratch_3_address #define CPU_INTR_ADDRESS 0x0010 /* Firmware indications to the Host via SCRATCH_3 register. */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index e0c9f4633a82..a31746df7acc 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -58,9 +58,11 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); #define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3 #define QCA988X_2_0_DEVICE_ID (0x003c) +#define QCA6174_2_1_DEVICE_ID (0x003e) static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ + { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ {0} }; @@ -70,6 +72,11 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { * because of that. */ { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, }; static void ath10k_pci_buffer_cleanup(struct ath10k *ar); @@ -1506,6 +1513,35 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar) return 0; } +static int ath10k_pci_get_num_banks(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + switch (ar_pci->pdev->device) { + case QCA988X_2_0_DEVICE_ID: + return 1; + case QCA6174_2_1_DEVICE_ID: + switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) { + case QCA6174_HW_1_0_CHIP_ID_REV: + case QCA6174_HW_1_1_CHIP_ID_REV: + return 3; + case QCA6174_HW_1_3_CHIP_ID_REV: + return 2; + case QCA6174_HW_2_1_CHIP_ID_REV: + case QCA6174_HW_2_2_CHIP_ID_REV: + return 6; + case QCA6174_HW_3_0_CHIP_ID_REV: + case QCA6174_HW_3_1_CHIP_ID_REV: + case QCA6174_HW_3_2_CHIP_ID_REV: + return 9; + } + break; + } + + ath10k_warn(ar, "unknown number of banks, assuming 1\n"); + return 1; +} + static int ath10k_pci_init_config(struct ath10k *ar) { u32 interconnect_targ_addr; @@ -1616,7 +1652,8 @@ static int ath10k_pci_init_config(struct ath10k *ar) /* first bank is switched to IRAM */ ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) & HI_EARLY_ALLOC_MAGIC_MASK); - ealloc_value |= ((1 << HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) & + ealloc_value |= ((ath10k_pci_get_num_banks(ar) << + HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) & HI_EARLY_ALLOC_IRAM_BANKS_MASK); ret = ath10k_pci_diag_write32(ar, ealloc_targ_addr, ealloc_value); @@ -1812,12 +1849,12 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) return 0; } -static int ath10k_pci_chip_reset(struct ath10k *ar) +static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar) { int i, ret; u32 val; - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot 988x chip reset\n"); /* Some hardware revisions (e.g. CUS223v2) has issues with cold reset. * It is thus preferred to use warm reset which is safer but may not be @@ -1881,11 +1918,53 @@ static int ath10k_pci_chip_reset(struct ath10k *ar) return ret; } - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (cold)\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca988x chip reset complete (cold)\n"); + + return 0; +} + +static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset\n"); + + /* FIXME: QCA6174 requires cold + warm reset to work. */ + + ret = ath10k_pci_cold_reset(ar); + if (ret) { + ath10k_warn(ar, "failed to cold reset: %d\n", ret); + return ret; + } + + ret = ath10k_pci_wait_for_target_init(ar); + if (ret) { + ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", + ret); + return ret; + } + + ret = ath10k_pci_warm_reset(ar); + if (ret) { + ath10k_warn(ar, "failed to warm reset: %d\n", ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset complete (cold)\n"); return 0; } +static int ath10k_pci_chip_reset(struct ath10k *ar) +{ + if (QCA_REV_988X(ar)) + return ath10k_pci_qca988x_chip_reset(ar); + else if (QCA_REV_6174(ar)) + return ath10k_pci_qca6174_chip_reset(ar); + else + return -ENOTSUPP; +} + static int ath10k_pci_hif_power_up(struct ath10k *ar) { int ret; @@ -2511,11 +2590,23 @@ static int ath10k_pci_probe(struct pci_dev *pdev, int ret = 0; struct ath10k *ar; struct ath10k_pci *ar_pci; + enum ath10k_hw_rev hw_rev; u32 chip_id; - ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, - ATH10K_BUS_PCI, - &ath10k_pci_hif_ops); + switch (pci_dev->device) { + case QCA988X_2_0_DEVICE_ID: + hw_rev = ATH10K_HW_QCA988X; + break; + case QCA6174_2_1_DEVICE_ID: + hw_rev = ATH10K_HW_QCA6174; + break; + default: + WARN_ON(1); + return -ENOTSUPP; + } + + ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, ATH10K_BUS_PCI, + hw_rev, &ath10k_pci_hif_ops); if (!ar) { dev_err(&pdev->dev, "failed to allocate core\n"); return -ENOMEM; diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index 9d0ae30f9ff1..a417aae52623 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -18,6 +18,8 @@ #ifndef __TARGADDRS_H__ #define __TARGADDRS_H__ +#include "hw.h" + /* * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the * host_interest structure. It must match the address of the _host_interest @@ -445,4 +447,7 @@ Fw Mode/SubMode Mask #define QCA988X_BOARD_DATA_SZ 7168 #define QCA988X_BOARD_EXT_DATA_SZ 0 +#define QCA6174_BOARD_DATA_SZ 8192 +#define QCA6174_BOARD_EXT_DATA_SZ 0 + #endif /* __TARGADDRS_H__ */ -- cgit v1.2.1 From b91251fbe88c9db1a7af29cfe49ca50aa4da9cd2 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:49 +0200 Subject: ath10k: split fw pdev stats parsing This will make it easier to implement fw stats parsing for firmware 10.2. This also renames a few structures for consistency. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 117 +++++++++++++++++++--------------- drivers/net/wireless/ath/ath10k/wmi.h | 55 ++++++++++------ 2 files changed, 100 insertions(+), 72 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 5fe17e80bc6b..ce095dac5b44 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1680,12 +1680,9 @@ int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) return 0; } -void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src, - struct ath10k_fw_stats_pdev *dst) +void ath10k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src, + struct ath10k_fw_stats_pdev *dst) { - const struct wal_dbg_tx_stats *tx = &src->wal.tx; - const struct wal_dbg_rx_stats *rx = &src->wal.rx; - dst->ch_noise_floor = __le32_to_cpu(src->chan_nf); dst->tx_frame_count = __le32_to_cpu(src->tx_frame_count); dst->rx_frame_count = __le32_to_cpu(src->rx_frame_count); @@ -1693,44 +1690,63 @@ void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src, dst->cycle_count = __le32_to_cpu(src->cycle_count); dst->phy_err_count = __le32_to_cpu(src->phy_err_count); dst->chan_tx_power = __le32_to_cpu(src->chan_tx_pwr); +} - dst->comp_queued = __le32_to_cpu(tx->comp_queued); - dst->comp_delivered = __le32_to_cpu(tx->comp_delivered); - dst->msdu_enqued = __le32_to_cpu(tx->msdu_enqued); - dst->mpdu_enqued = __le32_to_cpu(tx->mpdu_enqued); - dst->wmm_drop = __le32_to_cpu(tx->wmm_drop); - dst->local_enqued = __le32_to_cpu(tx->local_enqued); - dst->local_freed = __le32_to_cpu(tx->local_freed); - dst->hw_queued = __le32_to_cpu(tx->hw_queued); - dst->hw_reaped = __le32_to_cpu(tx->hw_reaped); - dst->underrun = __le32_to_cpu(tx->underrun); - dst->tx_abort = __le32_to_cpu(tx->tx_abort); - dst->mpdus_requed = __le32_to_cpu(tx->mpdus_requed); - dst->tx_ko = __le32_to_cpu(tx->tx_ko); - dst->data_rc = __le32_to_cpu(tx->data_rc); - dst->self_triggers = __le32_to_cpu(tx->self_triggers); - dst->sw_retry_failure = __le32_to_cpu(tx->sw_retry_failure); - dst->illgl_rate_phy_err = __le32_to_cpu(tx->illgl_rate_phy_err); - dst->pdev_cont_xretry = __le32_to_cpu(tx->pdev_cont_xretry); - dst->pdev_tx_timeout = __le32_to_cpu(tx->pdev_tx_timeout); - dst->pdev_resets = __le32_to_cpu(tx->pdev_resets); - dst->phy_underrun = __le32_to_cpu(tx->phy_underrun); - dst->txop_ovf = __le32_to_cpu(tx->txop_ovf); - - dst->mid_ppdu_route_change = __le32_to_cpu(rx->mid_ppdu_route_change); - dst->status_rcvd = __le32_to_cpu(rx->status_rcvd); - dst->r0_frags = __le32_to_cpu(rx->r0_frags); - dst->r1_frags = __le32_to_cpu(rx->r1_frags); - dst->r2_frags = __le32_to_cpu(rx->r2_frags); - dst->r3_frags = __le32_to_cpu(rx->r3_frags); - dst->htt_msdus = __le32_to_cpu(rx->htt_msdus); - dst->htt_mpdus = __le32_to_cpu(rx->htt_mpdus); - dst->loc_msdus = __le32_to_cpu(rx->loc_msdus); - dst->loc_mpdus = __le32_to_cpu(rx->loc_mpdus); - dst->oversize_amsdu = __le32_to_cpu(rx->oversize_amsdu); - dst->phy_errs = __le32_to_cpu(rx->phy_errs); - dst->phy_err_drop = __le32_to_cpu(rx->phy_err_drop); - dst->mpdu_errs = __le32_to_cpu(rx->mpdu_errs); +void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src, + struct ath10k_fw_stats_pdev *dst) +{ + dst->comp_queued = __le32_to_cpu(src->comp_queued); + dst->comp_delivered = __le32_to_cpu(src->comp_delivered); + dst->msdu_enqued = __le32_to_cpu(src->msdu_enqued); + dst->mpdu_enqued = __le32_to_cpu(src->mpdu_enqued); + dst->wmm_drop = __le32_to_cpu(src->wmm_drop); + dst->local_enqued = __le32_to_cpu(src->local_enqued); + dst->local_freed = __le32_to_cpu(src->local_freed); + dst->hw_queued = __le32_to_cpu(src->hw_queued); + dst->hw_reaped = __le32_to_cpu(src->hw_reaped); + dst->underrun = __le32_to_cpu(src->underrun); + dst->tx_abort = __le32_to_cpu(src->tx_abort); + dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed); + dst->tx_ko = __le32_to_cpu(src->tx_ko); + dst->data_rc = __le32_to_cpu(src->data_rc); + dst->self_triggers = __le32_to_cpu(src->self_triggers); + dst->sw_retry_failure = __le32_to_cpu(src->sw_retry_failure); + dst->illgl_rate_phy_err = __le32_to_cpu(src->illgl_rate_phy_err); + dst->pdev_cont_xretry = __le32_to_cpu(src->pdev_cont_xretry); + dst->pdev_tx_timeout = __le32_to_cpu(src->pdev_tx_timeout); + dst->pdev_resets = __le32_to_cpu(src->pdev_resets); + dst->phy_underrun = __le32_to_cpu(src->phy_underrun); + dst->txop_ovf = __le32_to_cpu(src->txop_ovf); +} + +void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src, + struct ath10k_fw_stats_pdev *dst) +{ + dst->mid_ppdu_route_change = __le32_to_cpu(src->mid_ppdu_route_change); + dst->status_rcvd = __le32_to_cpu(src->status_rcvd); + dst->r0_frags = __le32_to_cpu(src->r0_frags); + dst->r1_frags = __le32_to_cpu(src->r1_frags); + dst->r2_frags = __le32_to_cpu(src->r2_frags); + dst->r3_frags = __le32_to_cpu(src->r3_frags); + dst->htt_msdus = __le32_to_cpu(src->htt_msdus); + dst->htt_mpdus = __le32_to_cpu(src->htt_mpdus); + dst->loc_msdus = __le32_to_cpu(src->loc_msdus); + dst->loc_mpdus = __le32_to_cpu(src->loc_mpdus); + dst->oversize_amsdu = __le32_to_cpu(src->oversize_amsdu); + dst->phy_errs = __le32_to_cpu(src->phy_errs); + dst->phy_err_drop = __le32_to_cpu(src->phy_err_drop); + dst->mpdu_errs = __le32_to_cpu(src->mpdu_errs); +} + +void ath10k_wmi_pull_pdev_stats_extra(const struct wmi_pdev_stats_extra *src, + struct ath10k_fw_stats_pdev *dst) +{ + dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad); + dst->rts_bad = __le32_to_cpu(src->rts_bad); + dst->rts_good = __le32_to_cpu(src->rts_good); + dst->fcs_bad = __le32_to_cpu(src->fcs_bad); + dst->no_beacons = __le32_to_cpu(src->no_beacons); + dst->mib_int_count = __le32_to_cpu(src->mib_int_count); } void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, @@ -1768,7 +1784,10 @@ static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar, if (!dst) continue; - ath10k_wmi_pull_pdev_stats(src, dst); + ath10k_wmi_pull_pdev_stats_base(&src->base, dst); + ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); + ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); + list_add_tail(&dst->list, &stats->pdevs); } @@ -1820,14 +1839,10 @@ static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar, if (!dst) continue; - ath10k_wmi_pull_pdev_stats(&src->old, dst); - - dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad); - dst->rts_bad = __le32_to_cpu(src->rts_bad); - dst->rts_good = __le32_to_cpu(src->rts_good); - dst->fcs_bad = __le32_to_cpu(src->fcs_bad); - dst->no_beacons = __le32_to_cpu(src->no_beacons); - dst->mib_int_count = __le32_to_cpu(src->mib_int_count); + ath10k_wmi_pull_pdev_stats_base(&src->base, dst); + ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); + ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); + ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst); list_add_tail(&dst->list, &stats->pdevs); } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index bd7f29a3a122..109ed623b82f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2946,7 +2946,7 @@ struct wmi_pdev_set_wmm_params_arg { struct wmi_wmm_params_arg ac_vo; }; -struct wal_dbg_tx_stats { +struct wmi_pdev_stats_tx { /* Num HTT cookies queued to dispatch list */ __le32 comp_queued; @@ -3016,7 +3016,7 @@ struct wal_dbg_tx_stats { __le32 txop_ovf; } __packed; -struct wal_dbg_rx_stats { +struct wmi_pdev_stats_rx { /* Cnts any change in ring routing mid-ppdu */ __le32 mid_ppdu_route_change; @@ -3050,17 +3050,11 @@ struct wal_dbg_rx_stats { __le32 mpdu_errs; } __packed; -struct wal_dbg_peer_stats { +struct wmi_pdev_stats_peer { /* REMOVE THIS ONCE REAL PEER STAT COUNTERS ARE ADDED */ __le32 dummy; } __packed; -struct wal_dbg_stats { - struct wal_dbg_tx_stats tx; - struct wal_dbg_rx_stats rx; - struct wal_dbg_peer_stats peer; -} __packed; - enum wmi_stats_id { WMI_REQUEST_PEER_STAT = 0x01, WMI_REQUEST_AP_STAT = 0x02 @@ -3131,19 +3125,24 @@ struct wmi_stats_event { * PDEV statistics * TODO: add all PDEV stats here */ +struct wmi_pdev_stats_base { + __le32 chan_nf; + __le32 tx_frame_count; + __le32 rx_frame_count; + __le32 rx_clear_count; + __le32 cycle_count; + __le32 phy_err_count; + __le32 chan_tx_pwr; +} __packed; + struct wmi_pdev_stats { - __le32 chan_nf; /* Channel noise floor */ - __le32 tx_frame_count; /* TX frame count */ - __le32 rx_frame_count; /* RX frame count */ - __le32 rx_clear_count; /* rx clear count */ - __le32 cycle_count; /* cycle count */ - __le32 phy_err_count; /* Phy error count */ - __le32 chan_tx_pwr; /* channel tx power */ - struct wal_dbg_stats wal; /* WAL dbg stats */ + struct wmi_pdev_stats_base base; + struct wmi_pdev_stats_tx tx; + struct wmi_pdev_stats_rx rx; + struct wmi_pdev_stats_peer peer; } __packed; -struct wmi_10x_pdev_stats { - struct wmi_pdev_stats old; +struct wmi_pdev_stats_extra { __le32 ack_rx_bad; __le32 rts_bad; __le32 rts_good; @@ -3152,6 +3151,14 @@ struct wmi_10x_pdev_stats { __le32 mib_int_count; } __packed; +struct wmi_10x_pdev_stats { + struct wmi_pdev_stats_base base; + struct wmi_pdev_stats_tx tx; + struct wmi_pdev_stats_rx rx; + struct wmi_pdev_stats_peer peer; + struct wmi_pdev_stats_extra extra; +} __packed; + /* * VDEV statistics * TODO: add all VDEV stats here @@ -4772,8 +4779,14 @@ int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); void ath10k_wmi_start_scan_init(struct ath10k *ar, struct wmi_start_scan_arg *); -void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src, - struct ath10k_fw_stats_pdev *dst); +void ath10k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src, + struct ath10k_fw_stats_pdev *dst); +void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src, + struct ath10k_fw_stats_pdev *dst); +void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src, + struct ath10k_fw_stats_pdev *dst); +void ath10k_wmi_pull_pdev_stats_extra(const struct wmi_pdev_stats_extra *src, + struct ath10k_fw_stats_pdev *dst); void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, struct ath10k_fw_stats_peer *dst); void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, -- cgit v1.2.1 From 20de2229c634382777eb3b8fc54a34be9669ff8a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:49 +0200 Subject: ath10k: fix 10.2 fw stats parsing Both 10.2 firmware binaries 10.2-00082-4 and 10.2.4.20 have introduced ABI changes to fw_stats each. This caused fw_stats to output wrong data. Define new structures and use them to parse the statistics correctly. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 162 +++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/wmi.h | 52 +++++++++++ 2 files changed, 212 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index ce095dac5b44..fb1e2d1f343c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1871,6 +1871,164 @@ static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar, return 0; } +static int ath10k_wmi_10_2_op_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) +{ + const struct wmi_10_2_stats_event *ev = (void *)skb->data; + u32 num_pdev_stats; + u32 num_pdev_ext_stats; + u32 num_vdev_stats; + u32 num_peer_stats; + int i; + + if (!skb_pull(skb, sizeof(*ev))) + return -EPROTO; + + num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); + num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats); + num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); + num_peer_stats = __le32_to_cpu(ev->num_peer_stats); + + for (i = 0; i < num_pdev_stats; i++) { + const struct wmi_10_2_pdev_stats *src; + struct ath10k_fw_stats_pdev *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_pdev_stats_base(&src->base, dst); + ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); + ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); + ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst); + /* FIXME: expose 10.2 specific values */ + + list_add_tail(&dst->list, &stats->pdevs); + } + + for (i = 0; i < num_pdev_ext_stats; i++) { + const struct wmi_10_2_pdev_ext_stats *src; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + /* FIXME: expose values to userspace + * + * Note: Even though this loop seems to do nothing it is + * required to parse following sub-structures properly. + */ + } + + /* fw doesn't implement vdev stats */ + + for (i = 0; i < num_peer_stats; i++) { + const struct wmi_10_2_peer_stats *src; + struct ath10k_fw_stats_peer *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_peer_stats(&src->old, dst); + + dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate); + /* FIXME: expose 10.2 specific values */ + + list_add_tail(&dst->list, &stats->peers); + } + + return 0; +} + +static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) +{ + const struct wmi_10_2_stats_event *ev = (void *)skb->data; + u32 num_pdev_stats; + u32 num_pdev_ext_stats; + u32 num_vdev_stats; + u32 num_peer_stats; + int i; + + if (!skb_pull(skb, sizeof(*ev))) + return -EPROTO; + + num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); + num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats); + num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); + num_peer_stats = __le32_to_cpu(ev->num_peer_stats); + + for (i = 0; i < num_pdev_stats; i++) { + const struct wmi_10_2_pdev_stats *src; + struct ath10k_fw_stats_pdev *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_pdev_stats_base(&src->base, dst); + ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); + ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); + ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst); + /* FIXME: expose 10.2 specific values */ + + list_add_tail(&dst->list, &stats->pdevs); + } + + for (i = 0; i < num_pdev_ext_stats; i++) { + const struct wmi_10_2_pdev_ext_stats *src; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + /* FIXME: expose values to userspace + * + * Note: Even though this loop seems to do nothing it is + * required to parse following sub-structures properly. + */ + } + + /* fw doesn't implement vdev stats */ + + for (i = 0; i < num_peer_stats; i++) { + const struct wmi_10_2_4_peer_stats *src; + struct ath10k_fw_stats_peer *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_peer_stats(&src->common.old, dst); + + dst->peer_rx_rate = __le32_to_cpu(src->common.peer_rx_rate); + /* FIXME: expose 10.2 specific values */ + + list_add_tail(&dst->list, &stats->peers); + } + + return 0; +} + void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n"); @@ -5121,6 +5279,7 @@ static const struct wmi_ops wmi_10_1_ops = { static const struct wmi_ops wmi_10_2_ops = { .rx = ath10k_wmi_10_2_op_rx, + .pull_fw_stats = ath10k_wmi_10_2_op_pull_fw_stats, .gen_init = ath10k_wmi_10_2_op_gen_init, .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, /* .gen_pdev_get_temperature not implemented */ @@ -5128,7 +5287,6 @@ static const struct wmi_ops wmi_10_2_ops = { /* shared with 10.1 */ .map_svc = wmi_10x_svc_map, .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, - .pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats, .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, @@ -5180,6 +5338,7 @@ static const struct wmi_ops wmi_10_2_ops = { static const struct wmi_ops wmi_10_2_4_ops = { .rx = ath10k_wmi_10_2_op_rx, + .pull_fw_stats = ath10k_wmi_10_2_4_op_pull_fw_stats, .gen_init = ath10k_wmi_10_2_op_gen_init, .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, .gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature, @@ -5187,7 +5346,6 @@ static const struct wmi_ops wmi_10_2_4_ops = { /* shared with 10.1 */ .map_svc = wmi_10x_svc_map, .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, - .pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats, .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 109ed623b82f..0514b1a525ff 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3121,6 +3121,16 @@ struct wmi_stats_event { u8 data[0]; } __packed; +struct wmi_10_2_stats_event { + __le32 stats_id; /* %WMI_REQUEST_ */ + __le32 num_pdev_stats; + __le32 num_pdev_ext_stats; + __le32 num_vdev_stats; + __le32 num_peer_stats; + __le32 num_bcnflt_stats; + u8 data[0]; +} __packed; + /* * PDEV statistics * TODO: add all PDEV stats here @@ -3159,6 +3169,22 @@ struct wmi_10x_pdev_stats { struct wmi_pdev_stats_extra extra; } __packed; +struct wmi_pdev_stats_mem { + __le32 dram_free; + __le32 iram_free; +} __packed; + +struct wmi_10_2_pdev_stats { + struct wmi_pdev_stats_base base; + struct wmi_pdev_stats_tx tx; + __le32 mc_drop; + struct wmi_pdev_stats_rx rx; + __le32 pdev_rx_timeout; + struct wmi_pdev_stats_mem mem; + struct wmi_pdev_stats_peer peer; + struct wmi_pdev_stats_extra extra; +} __packed; + /* * VDEV statistics * TODO: add all VDEV stats here @@ -3182,6 +3208,32 @@ struct wmi_10x_peer_stats { __le32 peer_rx_rate; } __packed; +struct wmi_10_2_peer_stats { + struct wmi_peer_stats old; + __le32 peer_rx_rate; + __le32 current_per; + __le32 retries; + __le32 tx_rate_count; + __le32 max_4ms_frame_len; + __le32 total_sub_frames; + __le32 tx_bytes; + __le32 num_pkt_loss_overflow[4]; + __le32 num_pkt_loss_excess_retry[4]; +} __packed; + +struct wmi_10_2_4_peer_stats { + struct wmi_10_2_peer_stats common; + __le32 unknown_value; /* FIXME: what is this word? */ +} __packed; + +struct wmi_10_2_pdev_ext_stats { + __le32 rx_rssi_comb; + __le32 rx_rssi[4]; + __le32 rx_mcs[10]; + __le32 tx_mcs[10]; + __le32 ack_rssi; +} __packed; + struct wmi_vdev_create_cmd { __le32 vdev_id; __le32 vdev_type; -- cgit v1.2.1 From 89d6d83565e9a18ae77f4542348d8a34c264c9b1 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:51 +0200 Subject: ath10k: use idr api for msdu_ids HTT Tx protocol uses arbitrary host assigned ids too associate with MSDUs when delivering completions. Instead of rolling out own id generation scheme use the tools provided in kernel. This should have little to no effect on performance. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 7 ++- drivers/net/wireless/ath/ath10k/htt_tx.c | 78 ++++++++++---------------------- drivers/net/wireless/ath/ath10k/txrx.c | 9 +++- 3 files changed, 35 insertions(+), 59 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index d1f6eb287a10..874bf44ff7a2 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1328,12 +1328,11 @@ struct ath10k_htt { unsigned int prefetch_len; - /* Protects access to %pending_tx, %used_msdu_ids */ + /* Protects access to pending_tx, num_pending_tx */ spinlock_t tx_lock; int max_num_pending_tx; int num_pending_tx; - struct sk_buff **pending_tx; - unsigned long *used_msdu_ids; /* bitmap */ + struct idr pending_tx; wait_queue_head_t empty_tx_wq; struct dma_pool *tx_pool; @@ -1424,7 +1423,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, u8 max_subfrms_amsdu); void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt); -int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt); +int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb); void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id); int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *); int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 5c64139161fc..2a8667e95c46 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -56,21 +56,18 @@ exit: return ret; } -int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt) +int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) { struct ath10k *ar = htt->ar; - int msdu_id; + int ret; lockdep_assert_held(&htt->tx_lock); - msdu_id = find_first_zero_bit(htt->used_msdu_ids, - htt->max_num_pending_tx); - if (msdu_id == htt->max_num_pending_tx) - return -ENOBUFS; + ret = idr_alloc(&htt->pending_tx, skb, 0, 0x10000, GFP_ATOMIC); + + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret); - ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id); - __set_bit(msdu_id, htt->used_msdu_ids); - return msdu_id; + return ret; } void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) @@ -79,74 +76,53 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) lockdep_assert_held(&htt->tx_lock); - if (!test_bit(msdu_id, htt->used_msdu_ids)) - ath10k_warn(ar, "trying to free unallocated msdu_id %d\n", - msdu_id); - ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id); - __clear_bit(msdu_id, htt->used_msdu_ids); + + idr_remove(&htt->pending_tx, msdu_id); } int ath10k_htt_tx_alloc(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; - spin_lock_init(&htt->tx_lock); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", htt->max_num_pending_tx); - htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) * - htt->max_num_pending_tx, GFP_KERNEL); - if (!htt->pending_tx) - return -ENOMEM; - - htt->used_msdu_ids = kzalloc(sizeof(unsigned long) * - BITS_TO_LONGS(htt->max_num_pending_tx), - GFP_KERNEL); - if (!htt->used_msdu_ids) { - kfree(htt->pending_tx); - return -ENOMEM; - } + spin_lock_init(&htt->tx_lock); + idr_init(&htt->pending_tx); htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev, sizeof(struct ath10k_htt_txbuf), 4, 0); if (!htt->tx_pool) { - kfree(htt->used_msdu_ids); - kfree(htt->pending_tx); + idr_destroy(&htt->pending_tx); return -ENOMEM; } return 0; } -static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt) +static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) { - struct ath10k *ar = htt->ar; + struct ath10k *ar = ctx; + struct ath10k_htt *htt = &ar->htt; struct htt_tx_done tx_done = {0}; - int msdu_id; - - spin_lock_bh(&htt->tx_lock); - for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) { - if (!test_bit(msdu_id, htt->used_msdu_ids)) - continue; - ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", - msdu_id); + ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", msdu_id); - tx_done.discard = 1; - tx_done.msdu_id = msdu_id; + tx_done.discard = 1; + tx_done.msdu_id = msdu_id; - ath10k_txrx_tx_unref(htt, &tx_done); - } + spin_lock_bh(&htt->tx_lock); + ath10k_txrx_tx_unref(htt, &tx_done); spin_unlock_bh(&htt->tx_lock); + + return 0; } void ath10k_htt_tx_free(struct ath10k_htt *htt) { - ath10k_htt_tx_free_pending(htt); - kfree(htt->pending_tx); - kfree(htt->used_msdu_ids); + idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); + idr_destroy(&htt->pending_tx); dma_pool_destroy(htt->tx_pool); } @@ -378,13 +354,12 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) len += sizeof(cmd->mgmt_tx); spin_lock_bh(&htt->tx_lock); - res = ath10k_htt_tx_alloc_msdu_id(htt); + res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); if (res < 0) { spin_unlock_bh(&htt->tx_lock); goto err_tx_dec; } msdu_id = res; - htt->pending_tx[msdu_id] = msdu; spin_unlock_bh(&htt->tx_lock); txdesc = ath10k_htc_alloc_skb(ar, len); @@ -423,7 +398,6 @@ err_free_txdesc: dev_kfree_skb_any(txdesc); err_free_msdu_id: spin_lock_bh(&htt->tx_lock); - htt->pending_tx[msdu_id] = NULL; ath10k_htt_tx_free_msdu_id(htt, msdu_id); spin_unlock_bh(&htt->tx_lock); err_tx_dec: @@ -455,13 +429,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) goto err; spin_lock_bh(&htt->tx_lock); - res = ath10k_htt_tx_alloc_msdu_id(htt); + res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); if (res < 0) { spin_unlock_bh(&htt->tx_lock); goto err_tx_dec; } msdu_id = res; - htt->pending_tx[msdu_id] = msdu; spin_unlock_bh(&htt->tx_lock); prefetch_len = min(htt->prefetch_len, msdu->len); @@ -595,7 +568,6 @@ err_free_txbuf: skb_cb->htt.txbuf_paddr); err_free_msdu_id: spin_lock_bh(&htt->tx_lock); - htt->pending_tx[msdu_id] = NULL; ath10k_htt_tx_free_msdu_id(htt, msdu_id); spin_unlock_bh(&htt->tx_lock); err_tx_dec: diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 7579de8e7a8c..3f00cec8aef5 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -64,7 +64,13 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, return; } - msdu = htt->pending_tx[tx_done->msdu_id]; + msdu = idr_find(&htt->pending_tx, tx_done->msdu_id); + if (!msdu) { + ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n", + tx_done->msdu_id); + return; + } + skb_cb = ATH10K_SKB_CB(msdu); dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); @@ -95,7 +101,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, /* we do not own the msdu anymore */ exit: - htt->pending_tx[tx_done->msdu_id] = NULL; ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); __ath10k_htt_tx_dec_pending(htt); if (htt->num_pending_tx == 0) -- cgit v1.2.1 From ba2479fe65025bc48d79f86bce74567016632c3a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:51 +0200 Subject: ath10k: fix dtim period with beacon templates Firmware supporting beacon templates (i.e. wmi-tlv for qca6174) doesn't implicitly take dtim period from the template. Instead it requires vdev param to be set accordingly. This fixes dtim period being stuck at 3. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 9524bc59997f..99af537598bb 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3435,7 +3435,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, arvif->vdev_id, ret); } - if (changed & BSS_CHANGED_BEACON_INFO) { + if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) { arvif->dtim_period = info->dtim_period; ath10k_dbg(ar, ATH10K_DBG_MAC, -- cgit v1.2.1 From bf0a26d31ba141b7f41976392ea393ce90ca64e3 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:51 +0200 Subject: ath10k: fix nullfunc workaround The workaround couldn't work correctly because the 802.11 header wasn't properly stripped of QoS Data bit so it wasn't recognized in the later parts of tx path as NullFunc frame and ended up in HTT Tx instead of HTT Mgmt Tx. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 99af537598bb..5331350d9dda 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2145,6 +2145,7 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb) * used only for CQM purposes (e.g. hostapd station keepalive ping) so * it is safe to downgrade to NullFunc. */ + hdr = (void *)skb->data; if (ieee80211_is_qos_nullfunc(hdr->frame_control)) { hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA); cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; -- cgit v1.2.1 From 0c7e477c666e767f231fafe08e117669c64e5e14 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Sat, 24 Jan 2015 12:14:52 +0200 Subject: ath10k: implement uapsd autotrigger command New wmi-tlv firmware for qca6174 has u-UAPSD autotrigger service. If it is enabled firmware generates trigger frames automatically as configured. Signed-off-by: Janusz Dziedzic Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 25 +++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 73 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 24 ++++++++++ 3 files changed, 122 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 0dd49a7a89f0..80bd28ac2ccb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -137,6 +137,10 @@ struct wmi_ops { struct sk_buff *bcn); struct sk_buff *(*gen_p2p_go_bcn_ie)(struct ath10k *ar, u32 vdev_id, const u8 *p2p_ie); + struct sk_buff *(*gen_vdev_sta_uapsd)(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], + const struct wmi_sta_uapsd_auto_trig_arg *args, + u32 num_ac); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -575,6 +579,27 @@ ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, return ath10k_wmi_cmd_send(ar, skb, cmd_id); } +static inline int +ath10k_wmi_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], + const struct wmi_sta_uapsd_auto_trig_arg *args, + u32 num_ac) +{ + struct sk_buff *skb; + u32 cmd_id; + + if (!ar->wmi.ops->gen_vdev_sta_uapsd) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_sta_uapsd(ar, vdev_id, peer_addr, args, + num_ac); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->sta_uapsd_auto_trig_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + static inline int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, const u8 peer_addr[ETH_ALEN]) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 35f519123752..d3cf91dc950b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1512,6 +1512,78 @@ ath10k_wmi_tlv_op_gen_vdev_install_key(struct ath10k *ar, return skb; } +static void *ath10k_wmi_tlv_put_uapsd_ac(struct ath10k *ar, void *ptr, + const struct wmi_sta_uapsd_auto_trig_arg *arg) +{ + struct wmi_sta_uapsd_auto_trig_param *ac; + struct wmi_tlv *tlv; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM); + tlv->len = __cpu_to_le16(sizeof(*ac)); + ac = (void *)tlv->value; + + ac->wmm_ac = __cpu_to_le32(arg->wmm_ac); + ac->user_priority = __cpu_to_le32(arg->user_priority); + ac->service_interval = __cpu_to_le32(arg->service_interval); + ac->suspend_interval = __cpu_to_le32(arg->suspend_interval); + ac->delay_interval = __cpu_to_le32(arg->delay_interval); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv vdev sta uapsd auto trigger ac %d prio %d svc int %d susp int %d delay int %d\n", + ac->wmm_ac, ac->user_priority, ac->service_interval, + ac->suspend_interval, ac->delay_interval); + + return ptr + sizeof(*tlv) + sizeof(*ac); +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], + const struct wmi_sta_uapsd_auto_trig_arg *args, + u32 num_ac) +{ + struct wmi_sta_uapsd_auto_trig_cmd_fixed_param *cmd; + struct wmi_sta_uapsd_auto_trig_param *ac; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + size_t ac_tlv_len; + void *ptr; + int i; + + ac_tlv_len = num_ac * (sizeof(*tlv) + sizeof(*ac)); + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + ac_tlv_len; + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->num_ac = __cpu_to_le32(num_ac); + ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(ac_tlv_len); + ac = (void *)tlv->value; + + ptr += sizeof(*tlv); + for (i = 0; i < num_ac; i++) + ptr = ath10k_wmi_tlv_put_uapsd_ac(ar, ptr, &args[i]); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev sta uapsd auto trigger\n"); + return skb; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, const u8 peer_addr[ETH_ALEN]) @@ -2523,6 +2595,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl, .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl, .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie, + .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd, }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 0514b1a525ff..34d8c44b90e8 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4119,6 +4119,30 @@ enum wmi_sta_ps_param_uapsd { WMI_STA_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7), }; +#define WMI_STA_UAPSD_MAX_INTERVAL_MSEC UINT_MAX + +struct wmi_sta_uapsd_auto_trig_param { + __le32 wmm_ac; + __le32 user_priority; + __le32 service_interval; + __le32 suspend_interval; + __le32 delay_interval; +}; + +struct wmi_sta_uapsd_auto_trig_cmd_fixed_param { + __le32 vdev_id; + struct wmi_mac_addr peer_macaddr; + __le32 num_ac; +}; + +struct wmi_sta_uapsd_auto_trig_arg { + u32 wmm_ac; + u32 user_priority; + u32 service_interval; + u32 suspend_interval; + u32 delay_interval; +}; + enum wmi_sta_powersave_param { /* * Controls how frames are retrievd from AP while STA is sleeping -- cgit v1.2.1 From b0e561549316f520a80dc15dd341923b57bd4500 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:52 +0200 Subject: ath10k: disable uapsd autotrigger Only userspace can make an educated decision when a trigger frame is required so make sure the autotrigger service is disabled. Signed-off-by: Janusz Dziedzic Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 5331350d9dda..e3a3bbd41966 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3988,6 +3988,8 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, u16 ac, bool enable) { struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + struct wmi_sta_uapsd_auto_trig_arg arg = {}; + u32 prio = 0, acc = 0; u32 value = 0; int ret = 0; @@ -4000,18 +4002,26 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, case IEEE80211_AC_VO: value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN | WMI_STA_PS_UAPSD_AC3_TRIGGER_EN; + prio = 7; + acc = 3; break; case IEEE80211_AC_VI: value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN | WMI_STA_PS_UAPSD_AC2_TRIGGER_EN; + prio = 5; + acc = 2; break; case IEEE80211_AC_BE: value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN | WMI_STA_PS_UAPSD_AC1_TRIGGER_EN; + prio = 2; + acc = 1; break; case IEEE80211_AC_BK: value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN | WMI_STA_PS_UAPSD_AC0_TRIGGER_EN; + prio = 0; + acc = 0; break; } @@ -4053,6 +4063,29 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, return ret; } + if (test_bit(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, ar->wmi.svc_map) || + test_bit(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, ar->wmi.svc_map)) { + /* Only userspace can make an educated decision when to send + * trigger frame. The following effectively disables u-UAPSD + * autotrigger in firmware (which is enabled by default + * provided the autotrigger service is available). + */ + + arg.wmm_ac = acc; + arg.user_priority = prio; + arg.service_interval = 0; + arg.suspend_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC; + arg.delay_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC; + + ret = ath10k_wmi_vdev_sta_uapsd(ar, arvif->vdev_id, + arvif->bssid, &arg, 1); + if (ret) { + ath10k_warn(ar, "failed to set uapsd auto trigger %d\n", + ret); + return ret; + } + } + exit: return ret; } -- cgit v1.2.1 From 6f3b7ff4e309031e15402b71891b57eb14951b7a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Sat, 24 Jan 2015 12:14:52 +0200 Subject: ath10k: disable irqs after fw crash It makes little sense to keep handling irqs if fw is dead. This prevents multiple fw register dumps upon crash on some devices (seen on QCA6174). Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index a31746df7acc..e6972b09333e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2126,6 +2126,7 @@ static void ath10k_msi_err_tasklet(unsigned long data) return; } + ath10k_pci_irq_disable(ar); ath10k_pci_fw_crashed_clear(ar); ath10k_pci_fw_crashed_dump(ar); } @@ -2195,6 +2196,7 @@ static void ath10k_pci_tasklet(unsigned long data) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); if (ath10k_pci_has_fw_crashed(ar)) { + ath10k_pci_irq_disable(ar); ath10k_pci_fw_crashed_clear(ar); ath10k_pci_fw_crashed_dump(ar); return; -- cgit v1.2.1 From e4e82e9af8f02f9f3e19d240170c8c4b68f28bd4 Mon Sep 17 00:00:00 2001 From: Marek Kwaczynski Date: Sat, 24 Jan 2015 12:14:53 +0200 Subject: ath10k: remove sw encryption for pmf Software encryption was never necessary. Tested with fw 636 and fw 10.x. Signed-off-by: Marek Kwaczynski Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e3a3bbd41966..02e2bfc04ccf 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -58,10 +58,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif, switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: arg.key_cipher = WMI_CIPHER_AES_CCM; - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; - else - key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; break; case WLAN_CIPHER_SUITE_TKIP: arg.key_cipher = WMI_CIPHER_TKIP; -- cgit v1.2.1 From eebc67fef3eed8c768b9c046273dff6467b22cf4 Mon Sep 17 00:00:00 2001 From: Marek Kwaczynski Date: Sat, 24 Jan 2015 12:14:53 +0200 Subject: ath10k: fix pmf for wmi-tlv on qca6174 New wmi-tlv firmware uses HTT 3.0 protocol which uses TX_FRM command for management frames (instead of a dedicated command). To support PMF it is necessary to provide explicit tailroom. Signed-off-by: Marek Kwaczynski Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_tx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 2a8667e95c46..c1961e77d58d 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -454,6 +454,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) } skb_cb->htt.txbuf_paddr = paddr; + if ((ieee80211_is_action(hdr->frame_control) || + ieee80211_is_deauth(hdr->frame_control) || + ieee80211_is_disassoc(hdr->frame_control)) && + ieee80211_has_protected(hdr->frame_control)) + skb_put(msdu, IEEE80211_CCMP_MIC_LEN); + skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, DMA_TO_DEVICE); res = dma_mapping_error(dev, skb_cb->paddr); -- cgit v1.2.1 From ea2325b89d16c0803714d48e28b116aec2ef5026 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jan 2015 15:54:36 +0530 Subject: mwifiex: set netif carrier off in ndo_open This patch adds fix to set carrier state off during ndo_open. Carrier should be set to ON when device is ready to send data. In case of station/adhoc interface device is able to transfer data after successful association/join operation. For AP this would be after bss_active event. Signed-off-by: Johannes Berg Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index d235adb82c94..9836df0eb1e7 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -562,7 +562,8 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) static int mwifiex_open(struct net_device *dev) { - netif_tx_start_all_queues(dev); + netif_carrier_off(dev); + return 0; } -- cgit v1.2.1 From 33511b157bbcebaef853cc1811992b664a2e5862 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Wed, 21 Jan 2015 16:58:19 +0900 Subject: rtlwifi: add support to send beacon frame. In AP mode, beacon frame is necessary to keep connection. this patch adds a sending beacon frame routine in initialization routine. Signed-off-by: Taehee Yoo Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index eb203163ed05..a31a12775f1a 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -1010,6 +1010,16 @@ static int rtl_op_conf_tx(struct ieee80211_hw *hw, return 0; } +static void send_beacon_frame(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + + if (skb) + rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, NULL); +} + static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1040,6 +1050,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, if (rtlpriv->cfg->ops->linked_set_reg) rtlpriv->cfg->ops->linked_set_reg(hw); + send_beacon_frame(hw, vif); } } if ((changed & BSS_CHANGED_BEACON_ENABLED && -- cgit v1.2.1 From 0b70dc273c13da02241b5b9e76fca5a714bd2965 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Fri, 23 Jan 2015 16:59:24 +0800 Subject: rtl8192cu: fix the mesh beaconing Patch "rtlwifi: add support to send beacon frame" allows the beaconing of rtl8192cu. But mesh beaconing is not working. Fix this. Signed-off-by: Chun-Yeow Yeoh Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 551321728ae0..e5a7c4f81ab8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1509,6 +1509,7 @@ void rtl92cu_set_beacon_related_registers(struct ieee80211_hw *hw) /* TODO: Modify later (Find the right parameters) * NOTE: Fix test chip's bug (about contention windows's randomness) */ if ((mac->opmode == NL80211_IFTYPE_ADHOC) || + (mac->opmode == NL80211_IFTYPE_MESH_POINT) || (mac->opmode == NL80211_IFTYPE_AP)) { rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x50); rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x50); -- cgit v1.2.1 From 0c8a1e43aa3a1cefe125fd9385057aba5b4b4873 Mon Sep 17 00:00:00 2001 From: Hong Xu Date: Sat, 24 Jan 2015 03:34:03 -0800 Subject: ath9k and ath9k_htc: rename variable "led_blink" ath9k and ath9k_htc use the variable name "led_blink" to indicate whether the module parameter "blink" is on. This name is easy to conflict with other variables, and has caused a compiler error found by kbuild test bot. The compiler error is as following: drivers/net/wireless/ath/ath9k/ath9k_htc.o:(.data+0x47c): multiple definition of `led_blink' drivers/net/wireless/ath/ath9k/ath9k.o:(.bss+0x20): first defined here Fixes: 3a939a671225 ("ath9k_htc: Add a module parameter to disable blink") Reported-by: kbuild test robot Signed-off-by: Hong Xu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/gpio.c | 2 +- drivers/net/wireless/ath/ath9k/htc.h | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_gpio.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 4 ++-- drivers/net/wireless/ath/ath9k/init.c | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1a9fe0983a6b..e84b5769deb0 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -34,7 +34,7 @@ struct ath_vif; extern struct ieee80211_ops ath9k_ops; extern int ath9k_modparam_nohwcrypt; -extern int led_blink; +extern int ath9k_led_blink; extern bool is_ath9k_unloaded; extern int ath9k_use_chanctx; diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 2fef7a480fec..da344b27326c 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -49,7 +49,7 @@ void ath_init_leds(struct ath_softc *sc) if (AR_SREV_9100(sc->sc_ah)) return; - if (!led_blink) + if (!ath9k_led_blink) sc->led_cdev.default_trigger = ieee80211_get_radio_led_name(sc->hw); diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index c43fec51b8ec..300d3671d0ef 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -45,7 +45,7 @@ extern struct ieee80211_ops ath9k_htc_ops; extern int htc_modparam_nohwcrypt; #ifdef CONFIG_MAC80211_LEDS -extern int led_blink; +extern int ath9k_htc_led_blink; #endif enum htc_phymode { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 998b558d4126..2aabcbdaba4e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -279,7 +279,7 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv) else priv->ah->led_pin = ATH_LED_PIN_DEF; - if (!led_blink) + if (!ath9k_htc_led_blink) priv->led_cdev.default_trigger = ieee80211_get_radio_led_name(priv->hw); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 947012757f81..fd229409f676 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -39,8 +39,8 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); #ifdef CONFIG_MAC80211_LEDS -int led_blink = 1; -module_param_named(blink, led_blink, int, 0444); +int ath9k_htc_led_blink = 1; +module_param_named(blink, ath9k_htc_led_blink, int, 0444); MODULE_PARM_DESC(blink, "Enable LED blink on activity"); static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index d1c39346b264..2aef14e47c39 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -45,8 +45,8 @@ int ath9k_modparam_nohwcrypt; module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); -int led_blink; -module_param_named(blink, led_blink, int, 0444); +int ath9k_led_blink; +module_param_named(blink, ath9k_led_blink, int, 0444); MODULE_PARM_DESC(blink, "Enable LED blink on activity"); static int ath9k_btcoex_enable; -- cgit v1.2.1 From 52bd3d2023d4740850a2e30c7f24f18f5fe9d462 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Fri, 23 Jan 2015 17:09:17 +0530 Subject: mwifiex: add support for SD8801 SD8801 is Marvell's 1x1 802.11bgn offering. This patch adds Device IDs for SD8801 and also defines card structure which has definition for register offsets, buffer sizes etc. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Avinash Patil Signed-off-by: Nishant Sarmukadam Signed-off-by: Cathy Luo Signed-off-by: Frank Huang Reviewed-by: James Cameron Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.c | 5 +++++ drivers/net/wireless/mwifiex/sdio.h | 15 +++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index a70f103359ea..cee107f36bc9 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -282,6 +282,9 @@ static int mwifiex_sdio_suspend(struct device *dev) #define SDIO_DEVICE_ID_MARVELL_8897 (0x912d) /* Device ID for SD8887 */ #define SDIO_DEVICE_ID_MARVELL_8887 (0x9135) +/* Device ID for SD8801 */ +#define SDIO_DEVICE_ID_MARVELL_8801 (0x9139) + /* WLAN IDs */ static const struct sdio_device_id mwifiex_ids[] = { @@ -295,6 +298,8 @@ static const struct sdio_device_id mwifiex_ids[] = { .driver_data = (unsigned long) &mwifiex_sdio_sd8897}, {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887), .driver_data = (unsigned long)&mwifiex_sdio_sd8887}, + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801), + .driver_data = (unsigned long)&mwifiex_sdio_sd8801}, {}, }; diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 895eea054c9e..a4bb0dbbe7b3 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -34,6 +34,7 @@ #define SD8797_DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin" #define SD8897_DEFAULT_FW_NAME "mrvl/sd8897_uapsta.bin" #define SD8887_DEFAULT_FW_NAME "mrvl/sd8887_uapsta.bin" +#define SD8801_DEFAULT_FW_NAME "mrvl/sd8801_uapsta.bin" #define BLOCK_MODE 1 #define BYTE_MODE 0 @@ -474,6 +475,20 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { .auto_tdls = true, }; +static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = { + .firmware = SD8801_DEFAULT_FW_NAME, + .reg = &mwifiex_reg_sd87xx, + .max_ports = 16, + .mp_agg_pkt_limit = 8, + .supports_sdio_new_mode = false, + .has_control_mask = true, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, + .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, + .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, + .supports_fw_dump = false, + .auto_tdls = false, +}; + /* * .cmdrsp_complete handler */ -- cgit v1.2.1 From eaa3d9fa08c55555aedd967d4bfe7fe03c41cfaf Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Fri, 23 Jan 2015 17:09:18 +0530 Subject: mwifiex: add support for USB8801 USB8801 is Marvell's 1x1 802.11bgn offering. Patch adds Device IDs support and defines TX buffer size. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Avinash Patil Signed-off-by: Nishant Sarmukadam Signed-off-by: Cathy Luo Signed-off-by: Frank Huang Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/usb.c | 13 +++++++++++++ drivers/net/wireless/mwifiex/usb.h | 4 ++++ 2 files changed, 17 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 6c62995028e6..50517b78d965 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -37,6 +37,11 @@ static struct usb_device_id mwifiex_usb_table[] = { {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8797_PID_2, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff)}, + /* 8801 */ + {USB_DEVICE(USB8XXX_VID, USB8801_PID_1)}, + {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8801_PID_2, + USB_CLASS_VENDOR_SPEC, + USB_SUBCLASS_VENDOR_SPEC, 0xff)}, /* 8897 */ {USB_DEVICE(USB8XXX_VID, USB8897_PID_1)}, {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8897_PID_2, @@ -361,11 +366,13 @@ static int mwifiex_usb_probe(struct usb_interface *intf, switch (id_product) { case USB8766_PID_1: case USB8797_PID_1: + case USB8801_PID_1: case USB8897_PID_1: card->usb_boot_state = USB8XXX_FW_DNLD; break; case USB8766_PID_2: case USB8797_PID_2: + case USB8801_PID_2: case USB8897_PID_2: card->usb_boot_state = USB8XXX_FW_READY; break; @@ -798,6 +805,11 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; strcpy(adapter->fw_name, USB8766_DEFAULT_FW_NAME); break; + case USB8801_PID_1: + case USB8801_PID_2: + adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + strcpy(adapter->fw_name, USB8801_DEFAULT_FW_NAME); + break; case USB8797_PID_1: case USB8797_PID_2: default: @@ -1083,4 +1095,5 @@ MODULE_VERSION(USB_VERSION); MODULE_LICENSE("GPL v2"); MODULE_FIRMWARE(USB8766_DEFAULT_FW_NAME); MODULE_FIRMWARE(USB8797_DEFAULT_FW_NAME); +MODULE_FIRMWARE(USB8801_DEFAULT_FW_NAME); MODULE_FIRMWARE(USB8897_DEFAULT_FW_NAME); diff --git a/drivers/net/wireless/mwifiex/usb.h b/drivers/net/wireless/mwifiex/usb.h index 0ad1bebc3f93..57e1a5736318 100644 --- a/drivers/net/wireless/mwifiex/usb.h +++ b/drivers/net/wireless/mwifiex/usb.h @@ -30,6 +30,9 @@ #define USB8797_PID_2 0x2044 #define USB8897_PID_1 0x2045 #define USB8897_PID_2 0x2046 +#define USB8801_PID_1 0x2049 +#define USB8801_PID_2 0x204a + #define USB8XXX_FW_DNLD 1 #define USB8XXX_FW_READY 2 @@ -41,6 +44,7 @@ #define USB8766_DEFAULT_FW_NAME "mrvl/usb8766_uapsta.bin" #define USB8797_DEFAULT_FW_NAME "mrvl/usb8797_uapsta.bin" +#define USB8801_DEFAULT_FW_NAME "mrvl/usb8801_uapsta.bin" #define USB8897_DEFAULT_FW_NAME "mrvl/usb8897_uapsta.bin" #define FW_DNLD_TX_BUF_SIZE 620 -- cgit v1.2.1 From 1fe192d8d63f32daf83c49a29c3acd9c062164ec Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 23 Jan 2015 17:09:19 +0530 Subject: mwifiex: selectively choose ext_scan support Some devices do not support extended scan. This patch adds support to enble ext_scan selectively. For SD/PCIe interfaces, deefine ext_scan_support as part of card structure and use it to initialize ext_scan in adapter during registering device. For USB interfaces, we initialize ext_scan during register_dev handler. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/init.c | 2 +- drivers/net/wireless/mwifiex/pcie.c | 2 ++ drivers/net/wireless/mwifiex/pcie.h | 3 +++ drivers/net/wireless/mwifiex/sdio.c | 2 ++ drivers/net/wireless/mwifiex/sdio.h | 8 ++++++++ drivers/net/wireless/mwifiex/usb.c | 3 +++ 6 files changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index b115e0f94dd7..8004d140ee01 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -294,7 +294,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); adapter->arp_filter_size = 0; adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; - adapter->ext_scan = true; + adapter->ext_scan = false; adapter->key_api_major_ver = 0; adapter->key_api_minor_ver = 0; diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index a460b0e6a151..a5828da59365 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -204,6 +204,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, card->pcie.blksz_fw_dl = data->blksz_fw_dl; card->pcie.tx_buf_size = data->tx_buf_size; card->pcie.supports_fw_dump = data->supports_fw_dump; + card->pcie.can_ext_scan = data->can_ext_scan; } if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, @@ -2563,6 +2564,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); strcpy(adapter->fw_name, card->pcie.firmware); + adapter->ext_scan = card->pcie.can_ext_scan; return 0; } diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index 200e8b0cb582..666d40e9dbc3 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -206,6 +206,7 @@ struct mwifiex_pcie_device { u16 blksz_fw_dl; u16 tx_buf_size; bool supports_fw_dump; + bool can_ext_scan; }; static const struct mwifiex_pcie_device mwifiex_pcie8766 = { @@ -214,6 +215,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8766 = { .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, .supports_fw_dump = false, + .can_ext_scan = true, }; static const struct mwifiex_pcie_device mwifiex_pcie8897 = { @@ -222,6 +224,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = { .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, .supports_fw_dump = true, + .can_ext_scan = true, }; struct mwifiex_evt_buf_desc { diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index cee107f36bc9..91e36cda9543 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -107,6 +107,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; card->supports_fw_dump = data->supports_fw_dump; card->auto_tdls = data->auto_tdls; + card->can_ext_scan = data->can_ext_scan; } sdio_claim_host(func); @@ -1887,6 +1888,7 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) } adapter->auto_tdls = card->auto_tdls; + adapter->ext_scan = card->can_ext_scan; return ret; } diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index a4bb0dbbe7b3..957cca246618 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -256,6 +256,7 @@ struct sdio_mmc_card { u8 *mp_regs; u8 auto_tdls; + bool can_ext_scan; struct mwifiex_sdio_mpa_tx mpa_tx; struct mwifiex_sdio_mpa_rx mpa_rx; @@ -273,6 +274,7 @@ struct mwifiex_sdio_device { u32 mp_tx_agg_buf_size; u32 mp_rx_agg_buf_size; u8 auto_tdls; + bool can_ext_scan; }; static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = { @@ -417,6 +419,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .supports_fw_dump = false, .auto_tdls = false, + .can_ext_scan = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { @@ -431,6 +434,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .supports_fw_dump = false, .auto_tdls = false, + .can_ext_scan = true, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { @@ -445,6 +449,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .supports_fw_dump = false, .auto_tdls = false, + .can_ext_scan = true, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { @@ -459,6 +464,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, .supports_fw_dump = true, .auto_tdls = false, + .can_ext_scan = true, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { @@ -473,6 +479,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, .supports_fw_dump = false, .auto_tdls = true, + .can_ext_scan = true, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = { @@ -487,6 +494,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .supports_fw_dump = false, .auto_tdls = false, + .can_ext_scan = true, }; /* diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 50517b78d965..223873022ffe 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -799,16 +799,19 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) case USB8897_PID_2: adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME); + adapter->ext_scan = true; break; case USB8766_PID_1: case USB8766_PID_2: adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; strcpy(adapter->fw_name, USB8766_DEFAULT_FW_NAME); + adapter->ext_scan = true; break; case USB8801_PID_1: case USB8801_PID_2: adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; strcpy(adapter->fw_name, USB8801_DEFAULT_FW_NAME); + adapter->ext_scan = false; break; case USB8797_PID_1: case USB8797_PID_2: -- cgit v1.2.1 From 314112e0023acddaae1b43d549bc03be29a146ce Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sat, 24 Jan 2015 20:55:40 +0900 Subject: rtlwifi: rtl8192cu: Set fw_ready flag After rtl8192cu download firmware routine, set fw_ready flag. Signed-off-by: Taehee Yoo Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index e5a7c4f81ab8..fe4b699a12f5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1000,6 +1000,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) local_save_flags(flags); local_irq_enable(); + rtlhal->fw_ready = false; rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU; err = _rtl92cu_init_mac(hw); if (err) { @@ -1013,6 +1014,8 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) err = 1; goto exit; } + + rtlhal->fw_ready = true; rtlhal->last_hmeboxnum = 0; /* h2c */ _rtl92cu_phy_param_tab_init(hw); rtl92cu_phy_mac_config(hw); -- cgit v1.2.1 From 7390fe9c9a7ffdb0947add66efe7dedbe6b1cb6f Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 25 Jan 2015 15:46:31 +0100 Subject: hyperv: netvsc.c: match wait_for_completion_timeout return type Signed-off-by: Nicholas Mc Guire Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 9f49c0129a78..d2af032ff225 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -217,7 +217,7 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device) static int netvsc_init_buf(struct hv_device *device) { int ret = 0; - int t; + unsigned long t; struct netvsc_device *net_device; struct nvsp_message *init_packet; struct net_device *ndev; @@ -409,7 +409,8 @@ static int negotiate_nvsp_ver(struct hv_device *device, struct nvsp_message *init_packet, u32 nvsp_ver) { - int ret, t; + int ret; + unsigned long t; memset(init_packet, 0, sizeof(struct nvsp_message)); init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; -- cgit v1.2.1 From 999028cc1ccd1cd3a1c0104c6423553d3f573197 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 25 Jan 2015 15:48:23 +0100 Subject: hyperv: match wait_for_completion_timeout return type return type of wait_for_completion_timeout is unsigned long not int, this patch just fixes up the declarations. Signed-off-by: Nicholas Mc Guire Signed-off-by: David S. Miller --- drivers/net/hyperv/rndis_filter.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index ec0c40a8f653..7bd83870b2a7 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -470,7 +470,7 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, struct rndis_query_request *query; struct rndis_query_complete *query_complete; int ret = 0; - int t; + unsigned long t; if (!result) return -EINVAL; @@ -560,7 +560,8 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac) char macstr[2*ETH_ALEN+1]; u32 extlen = sizeof(struct rndis_config_parameter_info) + 2*NWADR_STRLEN + 4*ETH_ALEN; - int ret, t; + int ret; + unsigned long t; request = get_rndis_request(rdev, RNDIS_MSG_SET, RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); @@ -634,7 +635,8 @@ int rndis_filter_set_offload_params(struct hv_device *hdev, struct ndis_offload_params *offload_params; struct rndis_set_complete *set_complete; u32 extlen = sizeof(struct ndis_offload_params); - int ret, t; + int ret; + unsigned long t; u32 vsp_version = nvdev->nvsp_version; if (vsp_version <= NVSP_PROTOCOL_VERSION_4) { @@ -708,7 +710,8 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue) struct ndis_recv_scale_param *rssp; u32 *itab; u8 *keyp; - int i, t, ret; + int i, ret; + unsigned long t; request = get_rndis_request( rdev, RNDIS_MSG_SET, @@ -792,7 +795,8 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) struct rndis_set_request *set; struct rndis_set_complete *set_complete; u32 status; - int ret, t; + int ret; + unsigned long t; struct net_device *ndev; ndev = dev->net_dev->ndev; @@ -848,7 +852,8 @@ static int rndis_filter_init_device(struct rndis_device *dev) struct rndis_initialize_request *init; struct rndis_initialize_complete *init_complete; u32 status; - int ret, t; + int ret; + unsigned long t; request = get_rndis_request(dev, RNDIS_MSG_INIT, RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); @@ -998,7 +1003,7 @@ int rndis_filter_device_add(struct hv_device *dev, struct netvsc_device_info *device_info = additional_info; struct ndis_offload_params offloads; struct nvsp_message *init_packet; - int t; + unsigned long t; struct ndis_recv_scale_cap rsscap; u32 rsscap_size = sizeof(struct ndis_recv_scale_cap); u32 mtu, size; -- cgit v1.2.1 From 2477bc9a3db53540c64687c79efae9a7f1f60cef Mon Sep 17 00:00:00 2001 From: Jonathan Toppins Date: Mon, 26 Jan 2015 01:16:57 -0500 Subject: bonding: update bond carrier state when min_links option changes Cc: Andy Gospodarek Signed-off-by: Jonathan Toppins Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 +- drivers/net/bonding/bond_options.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f47bc433407a..f83ace6bab2f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -334,7 +334,7 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, * * Returns zero if carrier state does not change, nonzero if it does. */ -static int bond_set_carrier(struct bonding *bond) +int bond_set_carrier(struct bonding *bond) { struct list_head *iter; struct slave *slave; diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 9bd538d4474b..4df28943d222 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -1181,6 +1181,7 @@ static int bond_option_min_links_set(struct bonding *bond, netdev_info(bond->dev, "Setting min links value to %llu\n", newval->value); bond->params.min_links = newval->value; + bond_set_carrier(bond); return 0; } -- cgit v1.2.1 From 8bbe71a5956f833ec0d940419d1d368de5f1b58b Mon Sep 17 00:00:00 2001 From: Wilson Kok Date: Mon, 26 Jan 2015 01:16:58 -0500 Subject: bonding: fix bond_open() don't always set slave active flag Mode 802.3ad, fix incorrect bond slave active state when slave is not in active aggregator. During bond_open(), the bonding driver always sets the slave active flag to true if the bond is not in active-backup, alb, or tlb modes. Bonding should let the aggregator selection logic set the active flag when in 802.3ad mode. Cc: Andy Gospodarek Reviewed-by: Nikolay Aleksandrov Signed-off-by: Wilson Kok Signed-off-by: Jonathan Toppins Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f83ace6bab2f..beff00e7e110 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3066,7 +3066,7 @@ static int bond_open(struct net_device *bond_dev) slave != rcu_access_pointer(bond->curr_active_slave)) { bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); - } else { + } else if (BOND_MODE(bond) != BOND_MODE_8023AD) { bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_NOW); } -- cgit v1.2.1 From 63b46242f707849a1df10b70e026281bfa40e849 Mon Sep 17 00:00:00 2001 From: Wilson Kok Date: Mon, 26 Jan 2015 01:16:59 -0500 Subject: bonding: fix incorrect lacp mux state when agg not active This patch attempts to fix the following problems when an actor or partner's aggregator is not active: 1. a slave's lacp port state is marked as AD_STATE_SYNCHRONIZATION even if it is attached to an inactive aggregator. LACP advertises this state to the partner, making the partner think he can move into COLLECTING_DISTRIBUTING state even though this link will not pass traffic on the local side 2. a slave goes into COLLECTING_DISTRIBUTING state without checking if the aggregator is actually active 3. when in COLLECTING_DISTRIBUTING state, the partner parameters may change, e.g. the partner_oper_port_state.SYNCHRONIZATION. The local mux machine is not reacting to the change and continue to keep the slave and bond up 4. When bond slave leaves an inactive aggregator and joins an active aggregator, the actor oper port state need to update to SYNC state. v2: * fix style issues in bond_3ad.c Cc: Andy Gospodarek Reviewed-by: Nikolay Aleksandrov Signed-off-by: Wilson Kok Signed-off-by: Jonathan Toppins Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 44 ++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 8baa87df1738..e3c96b216eb8 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -467,11 +467,14 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) /* set the partner sync. to on if the partner is sync, * and the port is matched */ - if ((port->sm_vars & AD_PORT_MATCHED) - && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) + if ((port->sm_vars & AD_PORT_MATCHED) && + (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) { partner->port_state |= AD_STATE_SYNCHRONIZATION; - else + pr_debug("%s partner sync=1\n", port->slave->dev->name); + } else { partner->port_state &= ~AD_STATE_SYNCHRONIZATION; + pr_debug("%s partner sync=0\n", port->slave->dev->name); + } } } @@ -726,6 +729,8 @@ static inline void __update_lacpdu_from_port(struct port *port) lacpdu->actor_port_priority = htons(port->actor_port_priority); lacpdu->actor_port = htons(port->actor_port_number); lacpdu->actor_state = port->actor_oper_port_state; + pr_debug("update lacpdu: %s, actor port state %x\n", + port->slave->dev->name, port->actor_oper_port_state); /* lacpdu->reserved_3_1 initialized * lacpdu->tlv_type_partner_info initialized @@ -898,7 +903,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) { - port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING; + if (port->aggregator->is_active) + port->sm_mux_state = + AD_MUX_COLLECTING_DISTRIBUTING; } else if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { /* if UNSELECTED or STANDBY */ @@ -910,12 +917,16 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) */ __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); port->sm_mux_state = AD_MUX_DETACHED; + } else if (port->aggregator->is_active) { + port->actor_oper_port_state |= + AD_STATE_SYNCHRONIZATION; } break; case AD_MUX_COLLECTING_DISTRIBUTING: if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY) || - !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION)) { + !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) || + !(port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) { port->sm_mux_state = AD_MUX_ATTACHED; } else { /* if port state hasn't changed make @@ -937,8 +948,10 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) /* check if the state machine was changed */ if (port->sm_mux_state != last_state) { - pr_debug("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", - port->actor_port_number, last_state, + pr_debug("Mux Machine: Port=%d (%s), Last State=%d, Curr State=%d\n", + port->actor_port_number, + port->slave->dev->name, + last_state, port->sm_mux_state); switch (port->sm_mux_state) { case AD_MUX_DETACHED: @@ -953,7 +966,12 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); break; case AD_MUX_ATTACHED: - port->actor_oper_port_state |= AD_STATE_SYNCHRONIZATION; + if (port->aggregator->is_active) + port->actor_oper_port_state |= + AD_STATE_SYNCHRONIZATION; + else + port->actor_oper_port_state &= + ~AD_STATE_SYNCHRONIZATION; port->actor_oper_port_state &= ~AD_STATE_COLLECTING; port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING; ad_disable_collecting_distributing(port, @@ -963,6 +981,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) case AD_MUX_COLLECTING_DISTRIBUTING: port->actor_oper_port_state |= AD_STATE_COLLECTING; port->actor_oper_port_state |= AD_STATE_DISTRIBUTING; + port->actor_oper_port_state |= AD_STATE_SYNCHRONIZATION; ad_enable_collecting_distributing(port, update_slave_arr); port->ntt = true; @@ -1044,8 +1063,10 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) /* check if the State machine was changed or new lacpdu arrived */ if ((port->sm_rx_state != last_state) || (lacpdu)) { - pr_debug("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", - port->actor_port_number, last_state, + pr_debug("Rx Machine: Port=%d (%s), Last State=%d, Curr State=%d\n", + port->actor_port_number, + port->slave->dev->name, + last_state, port->sm_rx_state); switch (port->sm_rx_state) { case AD_RX_INITIALIZE: @@ -1394,6 +1415,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) aggregator = __get_first_agg(port); ad_agg_selection_logic(aggregator, update_slave_arr); + + if (!port->aggregator->is_active) + port->actor_oper_port_state &= ~AD_STATE_SYNCHRONIZATION; } /* Decide if "agg" is a better choice for the new active aggregator that -- cgit v1.2.1 From 2f6373245a09e2a34f36df7d982f783291ec8fce Mon Sep 17 00:00:00 2001 From: Satish Ashok Date: Mon, 26 Jan 2015 01:17:00 -0500 Subject: bonding: fix LACP PDU not sent on slave port sometimes When a slave is added to a bond and it is not in full duplex mode, AD_PORT_LACP_ENABLED flag is cleared, due to this LACP PDU is not sent on slave. When the duplex is changed to full, the flag needs to be set to send LACP PDU. Cc: Andy Gospodarek Reviewed-by: Nikolay Aleksandrov Signed-off-by: Satish Ashok Signed-off-by: Jonathan Toppins Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index e3c96b216eb8..cfc4a9c1000a 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2219,8 +2219,10 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, switch (lacpdu->subtype) { case AD_TYPE_LACPDU: ret = RX_HANDLER_CONSUMED; - netdev_dbg(slave->bond->dev, "Received LACPDU on port %d\n", - port->actor_port_number); + netdev_dbg(slave->bond->dev, + "Received LACPDU on port %d slave %s\n", + port->actor_port_number, + slave->dev->name); /* Protect against concurrent state machines */ spin_lock(&slave->bond->mode_lock); ad_rx_machine(lacpdu, port); @@ -2312,7 +2314,10 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) port->actor_admin_port_key &= ~AD_DUPLEX_KEY_MASKS; port->actor_oper_port_key = port->actor_admin_port_key |= __get_duplex(port); - netdev_dbg(slave->bond->dev, "Port %d changed duplex\n", port->actor_port_number); + netdev_dbg(slave->bond->dev, "Port %d slave %s changed duplex\n", + port->actor_port_number, slave->dev->name); + if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) + port->sm_vars |= AD_PORT_LACP_ENABLED; /* there is no need to reselect a new aggregator, just signal the * state machines to reinitialize */ -- cgit v1.2.1 From 303691042d2fc996125f479cf01bd5ead8b90a16 Mon Sep 17 00:00:00 2001 From: Jonathan Toppins Date: Mon, 26 Jan 2015 01:17:01 -0500 Subject: bonding: cleanup and remove dead code fix sparse warning about non-static function drivers/net/bonding/bond_main.c:3737:5: warning: symbol 'bond_3ad_xor_xmit' was not declared. Should it be static? Reviewed-by: Nikolay Aleksandrov Signed-off-by: Jonathan Toppins Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index beff00e7e110..e229a8657de8 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3734,7 +3734,7 @@ out: * usable slave array is formed in the control path. The xmit function * just calculates hash and sends the packet out. */ -int bond_3ad_xor_xmit(struct sk_buff *skb, struct net_device *dev) +static int bond_3ad_xor_xmit(struct sk_buff *skb, struct net_device *dev) { struct bonding *bond = netdev_priv(dev); struct slave *slave; -- cgit v1.2.1 From 4967082b469320eeba54ffbca632af1962858fb7 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 26 Jan 2015 14:10:53 +0100 Subject: vxlan: advertise link netns in fdb messages Previous commit is based on a wrong assumption, fdb messages are always sent into the netns where the interface stands (see vxlan_fdb_notify()). These fdb messages doesn't embed the rtnl attribute IFLA_LINK_NETNSID, thus we need to add it (useful to interpret NDA_IFINDEX or NDA_DST for example). Note also that vxlan_nlmsg_size() was not updated. Fixes: 193523bf9373 ("vxlan: advertise netns of vxlan dev in fdb msg") Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 87736e65cd15..31bac2a21ce3 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -341,8 +341,8 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, ndm->ndm_type = RTN_UNICAST; if (!net_eq(dev_net(vxlan->dev), vxlan->net) && - nla_put_s32(skb, NDA_NDM_IFINDEX_NETNSID, - peernet2id(vxlan->net, dev_net(vxlan->dev)))) + nla_put_s32(skb, NDA_LINK_NETNSID, + peernet2id(dev_net(vxlan->dev), vxlan->net))) goto nla_put_failure; if (send_eth && nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->eth_addr)) @@ -385,6 +385,7 @@ static inline size_t vxlan_nlmsg_size(void) + nla_total_size(sizeof(__be16)) /* NDA_PORT */ + nla_total_size(sizeof(__be32)) /* NDA_VNI */ + nla_total_size(sizeof(__u32)) /* NDA_IFINDEX */ + + nla_total_size(sizeof(__s32)) /* NDA_LINK_NETNSID */ + nla_total_size(sizeof(struct nda_cacheinfo)); } -- cgit v1.2.1 From be6a6b43b597a37d96dbf74985f72045ccef0940 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 27 Jan 2015 15:57:59 +0200 Subject: net/mlx4_core: Add bad-cable event support If the firmware can detect a bad cable, allow it to generate an event, and print the problem in the log. Signed-off-by: Jack Morgenstein Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/eq.c | 22 ++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/fw.c | 9 ++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 2f2e6067426d..4df006d8afa4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -88,6 +88,8 @@ static u64 get_async_ev_mask(struct mlx4_dev *dev) u64 async_ev_mask = MLX4_ASYNC_EVENT_MASK; if (dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) async_ev_mask |= (1ull << MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT); + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT) + async_ev_mask |= (1ull << MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT); return async_ev_mask; } @@ -736,6 +738,26 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) (unsigned long) eqe); break; + case MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT: + switch (eqe->subtype) { + case MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_BAD_CABLE: + mlx4_warn(dev, "Bad cable detected on port %u\n", + eqe->event.bad_cable.port); + break; + case MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_UNSUPPORTED_CABLE: + mlx4_warn(dev, "Unsupported cable detected\n"); + break; + default: + mlx4_dbg(dev, + "Unhandled recoverable error event detected: %02x(%02x) on EQ %d at index %u. owner=%x, nent=0x%x, ownership=%s\n", + eqe->type, eqe->subtype, eq->eqn, + eq->cons_index, eqe->owner, eq->nent, + !!(eqe->owner & 0x80) ^ + !!(eq->cons_index & eq->nent) ? "HW" : "SW"); + break; + } + break; + case MLX4_EVENT_TYPE_EEC_CATAS_ERROR: case MLX4_EVENT_TYPE_ECC_DETECT: default: diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 982861d1df44..2eadc2882e4f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -145,7 +145,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) [16] = "CONFIG DEV support", [17] = "Asymmetric EQs support", [18] = "More than 80 VFs support", - [19] = "Performance optimized for limited rule configuration flow steering support" + [19] = "Performance optimized for limited rule configuration flow steering support", + [20] = "Recoverable error events support" }; int i; @@ -859,6 +860,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETH_BACKPL_OFFSET); if (field32 & (1 << 0)) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP; + if (field32 & (1 << 7)) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT; MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC); if (field & 1<<6) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN; @@ -1562,6 +1565,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) #define INIT_HCA_VXLAN_OFFSET 0x0c #define INIT_HCA_CACHELINE_SZ_OFFSET 0x0e #define INIT_HCA_FLAGS_OFFSET 0x014 +#define INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET 0x018 #define INIT_HCA_QPC_OFFSET 0x020 #define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10) #define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17) @@ -1668,6 +1672,9 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE; } + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT) + *(inbox + INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET / 4) |= cpu_to_be32(1 << 31); + /* QPC/EEC/CQC/EQC/RDMARC attributes */ MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); -- cgit v1.2.1 From f0ce0615082dd6a2aec7a4b7525286c7f7a7e91b Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 27 Jan 2015 15:58:00 +0200 Subject: net/mlx4_core: Add reserved lkey for VFs to QUERY_FUNC_CAP The reserved lKey is different for each VF. A base lkey value is returned in QUERY_DEV_CAP at offset 0x98. The reserved L_key value for a VF is: VF_lkey = base_lkey + (VF_number << 8). This VF L_key value should be returned in QUERY_FUNC_CAP (opcode-modifier = 0) at offset 0x48. To indicate that the lkey value at offset 0x48 is valid, the Hypervisor sets a flag bit in dword 0x0, offset 27 in the QUERY_FUNC_CAP wrapper function. When the VF calls QUERY_FUNC_CAP, it should check if this flag bit is set. If it is set, the VF should take the reserved lkey value at offset 0x48. If the bit is not set, the VF should not use a reserved lkey (i.e., should set its reserved lkey value to 0). Signed-off-by: Jack Morgenstein Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 19 +++++++++++++++++-- drivers/net/ethernet/mellanox/mlx4/fw.h | 1 + drivers/net/ethernet/mellanox/mlx4/main.c | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 2eadc2882e4f..2aa7c232d0b6 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -260,6 +260,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, #define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP 0x28 #define QUERY_FUNC_CAP_MAX_EQ_OFFSET 0x2c #define QUERY_FUNC_CAP_RESERVED_EQ_OFFSET 0x30 +#define QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET 0x48 #define QUERY_FUNC_CAP_QP_QUOTA_OFFSET 0x50 #define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET 0x54 @@ -274,6 +275,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, #define QUERY_FUNC_CAP_FLAG_RDMA 0x40 #define QUERY_FUNC_CAP_FLAG_ETH 0x80 #define QUERY_FUNC_CAP_FLAG_QUOTAS 0x10 +#define QUERY_FUNC_CAP_FLAG_RESD_LKEY 0x08 #define QUERY_FUNC_CAP_FLAG_VALID_MAILBOX 0x04 #define QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG (1UL << 31) @@ -345,9 +347,12 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, } else if (vhcr->op_modifier == 0) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave); - /* enable rdma and ethernet interfaces, and new quota locations */ + /* enable rdma and ethernet interfaces, new quota locations, + * and reserved lkey + */ field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA | - QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX); + QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX | + QUERY_FUNC_CAP_FLAG_RESD_LKEY); MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET); field = min( @@ -412,6 +417,9 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, size = QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG | QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG; MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET); + + size = dev->caps.reserved_lkey + ((slave << 8) & 0xFF00); + MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET); } else err = -EINVAL; @@ -504,6 +512,13 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port, MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET); func_cap->reserved_eq = size & 0xFFFFFF; + if (func_cap->flags & QUERY_FUNC_CAP_FLAG_RESD_LKEY) { + MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET); + func_cap->reserved_lkey = size; + } else { + func_cap->reserved_lkey = 0; + } + func_cap->extra_flags = 0; /* Mailbox data from 0x6c and onward should only be treated if diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h index 62562b60fa87..f44f7f6017ed 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw.h @@ -147,6 +147,7 @@ struct mlx4_func_cap { u32 qp0_proxy_qpn; u32 qp1_tunnel_qpn; u32 qp1_proxy_qpn; + u32 reserved_lkey; u8 physical_port; u8 port_flags; u8 flags1; diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index ff2fffeab4c7..51d5550bc17a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -797,6 +797,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) dev->caps.num_mpts = 1 << hca_param.log_mpt_sz; dev->caps.num_eqs = func_cap.max_eq; dev->caps.reserved_eqs = func_cap.reserved_eq; + dev->caps.reserved_lkey = func_cap.reserved_lkey; dev->caps.num_pds = MLX4_NUM_PDS; dev->caps.num_mgms = 0; dev->caps.num_amgms = 0; -- cgit v1.2.1 From 772103e6b1a0ceb4fb482fb9414e55ac9be27250 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 27 Jan 2015 15:58:01 +0200 Subject: net/mlx4_core: Fix mem leak in SRIOV mlx4_init_one error flow Structs allocated for the resource tracker must be freed in the error flow. Signed-off-by: Jack Morgenstein Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 51d5550bc17a..cc9f48439244 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2979,8 +2979,10 @@ err_free_eq: mlx4_free_eq_table(dev); err_master_mfunc: - if (mlx4_is_master(dev)) + if (mlx4_is_master(dev)) { + mlx4_free_resource_tracker(dev, RES_TR_FREE_STRUCTS_ONLY); mlx4_multi_func_cleanup(dev); + } if (mlx4_is_slave(dev)) { kfree(dev->caps.qp0_qkey); -- cgit v1.2.1 From 5a03108689c6f3e448a920b42af04e6d28401f80 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 27 Jan 2015 15:58:02 +0200 Subject: net/mlx4_core: Adjust command timeouts to conform to the firmware spec The firmware spec states that the timeout for all commands should be 60 seconds. In the past, the spec indicated that there were several classes of timeout (short, medium, and long). The driver has these different timeout classes. We leave the class differentiation in the driver as-is (to protect against any future spec changes), but set the timeout for all classes to be 60 seconds. In addition, we fix a few commands which had hard-coded numeric timeouts specified. Signed-off-by: Jack Morgenstein Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 19 ++++++++++--------- drivers/net/ethernet/mellanox/mlx4/mr.c | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 2aa7c232d0b6..0c90d1072e47 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -1774,8 +1774,8 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) MLX4_PUT(inbox, parser_params, INIT_HCA_VXLAN_OFFSET); } - err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000, - MLX4_CMD_NATIVE); + err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, + MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); if (err) mlx4_err(dev, "INIT_HCA returns %d\n", err); @@ -2029,7 +2029,7 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) { if (priv->mfunc.master.init_port_ref[port] == 1) { err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, - 1000, MLX4_CMD_NATIVE); + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); if (err) return err; } @@ -2040,7 +2040,7 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, if (!priv->mfunc.master.qp0_state[port].qp0_active && priv->mfunc.master.qp0_state[port].port_active) { err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, - 1000, MLX4_CMD_NATIVE); + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); if (err) return err; priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); @@ -2055,15 +2055,15 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port) { - return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 1000, - MLX4_CMD_WRAPPED); + return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); } EXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT); int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic) { - return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, 1000, - MLX4_CMD_NATIVE); + return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, + MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); } struct mlx4_config_dev { @@ -2202,7 +2202,8 @@ int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages) int mlx4_NOP(struct mlx4_dev *dev) { /* Input modifier of 0x1f means "finish as soon as possible." */ - return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100, MLX4_CMD_NATIVE); + return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, MLX4_CMD_TIME_CLASS_A, + MLX4_CMD_NATIVE); } int mlx4_get_phys_port_id(struct mlx4_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index 8dbdf1d29357..d21e884a0838 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -1155,7 +1155,7 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_free); int mlx4_SYNC_TPT(struct mlx4_dev *dev) { - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000, - MLX4_CMD_NATIVE); + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); } EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT); -- cgit v1.2.1 From 30a5da5b3301e386de99911fe6c1cd1aa37fb970 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 27 Jan 2015 15:58:03 +0200 Subject: net/mlx4_core: Fix HW2SW_EQ to conform to the firmware spec The driver incorrectly assigned an out-mailbox to this command, and used an opcode modifier = 0, which is a reserved value (it should use opcode modifier = 1). Signed-off-by: Jack Morgenstein Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 2 +- drivers/net/ethernet/mellanox/mlx4/eq.c | 26 ++++------------------ .../net/ethernet/mellanox/mlx4/resource_tracker.c | 16 ++++--------- 3 files changed, 9 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 2b48932855e7..928b7065732c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1221,7 +1221,7 @@ static struct mlx4_cmd_info cmd_info[] = { { .opcode = MLX4_CMD_HW2SW_EQ, .has_inbox = false, - .has_outbox = true, + .has_outbox = false, .out_is_imm = false, .encode_slave_id = true, .verify = NULL, diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 4df006d8afa4..264bc15c1ff2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -868,12 +868,10 @@ static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, MLX4_CMD_WRAPPED); } -static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int eq_num) +static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, int eq_num) { - return mlx4_cmd_box(dev, 0, mailbox->dma, eq_num, - 0, MLX4_CMD_HW2SW_EQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); + return mlx4_cmd(dev, 0, eq_num, 1, MLX4_CMD_HW2SW_EQ, + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); } static int mlx4_num_eq_uar(struct mlx4_dev *dev) @@ -1046,7 +1044,6 @@ static void mlx4_free_eq(struct mlx4_dev *dev, struct mlx4_eq *eq) { struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; int err; int i; /* CX3 is capable of extending the CQE/EQE from 32 to 64 bytes, with @@ -1054,24 +1051,10 @@ static void mlx4_free_eq(struct mlx4_dev *dev, */ int npages = PAGE_ALIGN(dev->caps.eqe_size * eq->nent) / PAGE_SIZE; - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return; - - err = mlx4_HW2SW_EQ(dev, mailbox, eq->eqn); + err = mlx4_HW2SW_EQ(dev, eq->eqn); if (err) mlx4_warn(dev, "HW2SW_EQ failed (%d)\n", err); - if (0) { - mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn); - for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) { - if (i % 4 == 0) - pr_cont("[%02x] ", i * 4); - pr_cont(" %08x", be32_to_cpup(mailbox->buf + i * 4)); - if ((i + 1) % 4 == 0) - pr_cont("\n"); - } - } synchronize_irq(eq->irq); tasklet_disable(&eq->tasklet_ctx.task); @@ -1083,7 +1066,6 @@ static void mlx4_free_eq(struct mlx4_dev *dev, kfree(eq->page_list); mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn, MLX4_USE_RR); - mlx4_free_cmd_mailbox(dev, mailbox); } static void mlx4_free_irqs(struct mlx4_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 3e93879bccce..79feeb6b0d87 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -4677,7 +4677,6 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave) int state; LIST_HEAD(tlist); int eqn; - struct mlx4_cmd_mailbox *mailbox; err = move_all_busy(dev, slave, RES_EQ); if (err) @@ -4703,20 +4702,13 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave) break; case RES_EQ_HW: - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - cond_resched(); - continue; - } - err = mlx4_cmd_box(dev, slave, 0, - eqn & 0xff, 0, - MLX4_CMD_HW2SW_EQ, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); + err = mlx4_cmd(dev, slave, eqn & 0xff, + 1, MLX4_CMD_HW2SW_EQ, + MLX4_CMD_TIME_CLASS_A, + MLX4_CMD_NATIVE); if (err) mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n", slave, eqn); - mlx4_free_cmd_mailbox(dev, mailbox); atomic_dec(&eq->mtt->ref_count); state = RES_EQ_RESERVED; break; -- cgit v1.2.1 From dc7d500451277fde0a6fe46bd45249978c8e697e Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 27 Jan 2015 15:58:04 +0200 Subject: net/mlx4_core: Fix struct mlx4_vhcr_cmd to make implicit padding explicit Struct mlx4_vhcr was implicitly padded by the gcc compiler on 64-bit architectures. This commit makes that padding explicit, to prevent issues with changing compilers and with incompatibilities between 32-bit architecture implicit padding and 64-bit architecture implicit padding. This structure is used in virtualization for communication between the Host and its Guests. The explicit padding allows 64-bit Hosts (old and new) to continue to interoperate with 64-bit Guests (old and new). However, without this fix, 64-bit Hosts could not interoperate with 32-bit Guests (since these did not insert the padding dword). With this fix, 32-bit Guests will be able to interoperate with 64-bit Hosts (since the structure offsets will be identical on both). Reported-by: Alexander Schmidt Signed-off-by: Jack Morgenstein Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 096a81c16a9b..148dc0945aab 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -196,6 +196,7 @@ struct mlx4_vhcr { struct mlx4_vhcr_cmd { __be64 in_param; __be32 in_modifier; + u32 reserved1; __be64 out_param; __be16 token; u16 reserved; -- cgit v1.2.1 From ef0223e693d66bc1edae342e7fe829c1092a653c Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 27 Jan 2015 15:58:05 +0200 Subject: net/mlx4_core: Remove duplicate code line from procedure mlx4_bf_alloc mlx4_bf_alloc had an unnecessary/duplicate code line. Did no harm, but not good practice. Reported by the Mellanox Beijing team. Signed-off-by: Jack Morgenstein Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/pd.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c index a42b4c0a9ed9..609c59dc854e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/pd.c +++ b/drivers/net/ethernet/mellanox/mlx4/pd.c @@ -214,7 +214,6 @@ int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node) list_add(&uar->bf_list, &priv->bf_list); } - bf->uar = uar; idx = ffz(uar->free_bf_bmap); uar->free_bf_bmap |= 1 << idx; bf->uar = uar; -- cgit v1.2.1 From 5a228c03d849c86c10ee69d9951695b0649f82ce Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Tue, 27 Jan 2015 15:58:06 +0200 Subject: net/mlx4_en: Use ethtool cmd->autoneg as a hint for ethtool set settings Use cmd->autoneg as a user hint to decide what to set in ethtool set settings callback. When cmd->autoneg == AUTONEG_ENABLE set according to ethtool->advertise otherwise, set according to ethtool->speed. Usage: - ethtool -s eth speed 56000 autoneg off - ethtool -s eth advertise 0x800000 autoneg on While we're here: - Move proto_admin masking outcome check to be adjacent to the operation. - Move en_warn("port reset..") print to "port reset" block. Fixes: 312df74 ("net/mlx4_en: mlx4_en_set_settings() always fails when autoneg is set") Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 569eda9e83d6..a7b58ba8492b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -770,22 +770,20 @@ static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return 0; } - proto_admin = cpu_to_be32(ptys_adv); - if (speed >= 0 && speed != priv->port_state.link_speed) - /* If speed was set then speed decides :-) */ - proto_admin = speed_set_ptys_admin(priv, speed, - ptys_reg.eth_proto_cap); + proto_admin = cmd->autoneg == AUTONEG_ENABLE ? + cpu_to_be32(ptys_adv) : + speed_set_ptys_admin(priv, speed, + ptys_reg.eth_proto_cap); proto_admin &= ptys_reg.eth_proto_cap; - - if (proto_admin == ptys_reg.eth_proto_admin) - return 0; /* Nothing to change */ - if (!proto_admin) { en_warn(priv, "Not supported link mode(s) requested, check supported link modes.\n"); return -EINVAL; /* nothing to change due to bad input */ } + if (proto_admin == ptys_reg.eth_proto_admin) + return 0; /* Nothing to change */ + en_dbg(DRV, priv, "mlx4_ACCESS_PTYS_REG SET: ptys_reg.eth_proto_admin = 0x%x\n", be32_to_cpu(proto_admin)); @@ -798,9 +796,9 @@ static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return ret; } - en_warn(priv, "Port link mode changed, restarting port...\n"); mutex_lock(&priv->mdev->state_lock); if (priv->port_up) { + en_warn(priv, "Port link mode changed, restarting port...\n"); mlx4_en_stop_port(dev, 1); if (mlx4_en_start_port(dev)) en_err(priv, "Failed restarting port %d\n", priv->port); -- cgit v1.2.1 From 19ab574f6271a2f912a449cfdea14a60098fba90 Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Tue, 27 Jan 2015 15:58:07 +0200 Subject: net/mlx4: Fix memory corruption in mlx4_MAD_IFC_wrapper Fix a memory corruption at mlx4_MAD_IFC_wrapper. A table of size dev->caps.pkey_table_len[port]*sizeof(*table) was allocated, but get_full_pkey_table() assumes that the number of entries in the table is a multiplication of 32 (which isn't always correct). Fixes: 0a9a018 ('mlx4: MAD_IFC paravirtualization') Signed-off-by: Matan Barak Signed-off-by: Or Gerlitz Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 928b7065732c..154effbfd8be 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -901,7 +901,9 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, index = be32_to_cpu(smp->attr_mod); if (port < 1 || port > dev->caps.num_ports) return -EINVAL; - table = kcalloc(dev->caps.pkey_table_len[port], sizeof *table, GFP_KERNEL); + table = kcalloc((dev->caps.pkey_table_len[port] / 32) + 1, + sizeof(*table) * 32, GFP_KERNEL); + if (!table) return -ENOMEM; /* need to get the full pkey table because the paravirtualized -- cgit v1.2.1 From cb2147a925895f843c1f2e8124878e3e60236063 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 27 Jan 2015 15:58:08 +0200 Subject: net/mlx4_core: Fix device capabilities dumping We are dumping device capabilities which are supported both by the firmware and the driver. Align the array that holds the capability strings with this practice. Reported-by: Yuval Shaia Signed-off-by: Or Gerlitz Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 0c90d1072e47..0ab81a930f33 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -84,13 +84,10 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) [ 1] = "UC transport", [ 2] = "UD transport", [ 3] = "XRC transport", - [ 4] = "reliable multicast", - [ 5] = "FCoIB support", [ 6] = "SRQ support", [ 7] = "IPoIB checksum offload", [ 8] = "P_Key violation counter", [ 9] = "Q_Key violation counter", - [10] = "VMM", [12] = "Dual Port Different Protocol (DPDP) support", [15] = "Big LSO headers", [16] = "MW support", @@ -99,12 +96,11 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) [19] = "Raw multicast support", [20] = "Address vector port checking support", [21] = "UD multicast support", - [24] = "Demand paging support", - [25] = "Router support", [30] = "IBoE support", [32] = "Unicast loopback support", [34] = "FCS header control", - [38] = "Wake On LAN support", + [37] = "Wake On LAN (port1) support", + [38] = "Wake On LAN (port2) support", [40] = "UDP RSS support", [41] = "Unicast VEP steering support", [42] = "Multicast VEP steering support", -- cgit v1.2.1 From 6d6e996c20f27091c09c813e2e73c507602839e3 Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Tue, 27 Jan 2015 15:58:09 +0200 Subject: net/mlx4_core: Update the HCA core clock frequency after INIT_PORT The firmware might change the hca core clock frequency after the driver issues the INIT_PORT command. Therefore we need to query the new value again and save in to the cached dev caps. Fixes: ddd8a6c1 ('net/mlx4_core: Read HCA frequency and map internal clock') Signed-off-by: Majd Dibbiny Signed-off-by: Or Gerlitz Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 0ab81a930f33..dbabfae3a3de 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -1897,6 +1897,36 @@ out: return err; } +static int mlx4_hca_core_clock_update(struct mlx4_dev *dev) +{ + struct mlx4_cmd_mailbox *mailbox; + __be32 *outbox; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + mlx4_warn(dev, "hca_core_clock mailbox allocation failed\n"); + return PTR_ERR(mailbox); + } + outbox = mailbox->buf; + + err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, + MLX4_CMD_QUERY_HCA, + MLX4_CMD_TIME_CLASS_B, + !mlx4_is_slave(dev)); + if (err) { + mlx4_warn(dev, "hca_core_clock update failed\n"); + goto out; + } + + MLX4_GET(dev->caps.hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET); + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + + return err; +} + /* for IB-type ports only in SRIOV mode. Checks that both proxy QP0 * and real QP0 are active, so that the paravirtualized QP0 is ready * to operate */ @@ -2001,6 +2031,9 @@ int mlx4_INIT_PORT(struct mlx4_dev *dev, int port) err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); + if (!err) + mlx4_hca_core_clock_update(dev); + return err; } EXPORT_SYMBOL_GPL(mlx4_INIT_PORT); -- cgit v1.2.1 From cd6c2f12ecbdc24100cda00ff110058a7cd502d2 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 27 Jan 2015 20:12:52 +0530 Subject: cxgb4: Move firmware version MACRO to t4fw_version.h Move firmware version MACRO to a new t4fw_version.h file so that csiostor driver can also use it. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 10 ----- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 1 + drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h | 48 +++++++++++++++++++++++ 3 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index d98a44637896..fb6980a09981 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -49,16 +49,6 @@ #include #include "cxgb4_uld.h" -#define T4FW_VERSION_MAJOR 0x01 -#define T4FW_VERSION_MINOR 0x0C -#define T4FW_VERSION_MICRO 0x19 -#define T4FW_VERSION_BUILD 0x00 - -#define T5FW_VERSION_MAJOR 0x01 -#define T5FW_VERSION_MINOR 0x0C -#define T5FW_VERSION_MICRO 0x19 -#define T5FW_VERSION_BUILD 0x00 - #define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__) enum { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index c27dcd98ea33..5bf490a781aa 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -70,6 +70,7 @@ #include "t4_values.h" #include "t4_msg.h" #include "t4fw_api.h" +#include "t4fw_version.h" #include "cxgb4_dcb.h" #include "cxgb4_debugfs.h" #include "clip_tbl.h" diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h new file mode 100644 index 000000000000..e2bd3f747858 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h @@ -0,0 +1,48 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4FW_VERSION_H__ +#define __T4FW_VERSION_H__ + +#define T4FW_VERSION_MAJOR 0x01 +#define T4FW_VERSION_MINOR 0x0C +#define T4FW_VERSION_MICRO 0x19 +#define T4FW_VERSION_BUILD 0x00 + +#define T5FW_VERSION_MAJOR 0x01 +#define T5FW_VERSION_MINOR 0x0C +#define T5FW_VERSION_MICRO 0x19 +#define T5FW_VERSION_BUILD 0x00 + +#endif -- cgit v1.2.1 From 488327c6ef2a2f39adc6d9f017745921c8b747e5 Mon Sep 17 00:00:00 2001 From: "Karicheri, Muralidharan" Date: Tue, 27 Jan 2015 09:49:54 -0500 Subject: net: netcp: remove unused kconfig option and code Currently CPTS is built into the netcp driver even though there is no call out to the CPTS driver. This patch removes the dependency in Kconfig and remove cpts.o from the Makefile for NetCP. Signed-off-by: Murali Karicheri Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/Kconfig | 1 - drivers/net/ethernet/ti/Makefile | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index e11bcfa69f52..4ea1663f3dea 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -73,7 +73,6 @@ config TI_CPSW config TI_CPTS boolean "TI Common Platform Time Sync (CPTS) Support" depends on TI_CPSW - depends on TI_CPSW || TI_KEYSTONE_NET select PTP_1588_CLOCK ---help--- This driver supports the Common Platform Time Sync unit of diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 465d03ddf441..0a9813bc0451 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -13,4 +13,4 @@ ti_cpsw-y := cpsw_ale.o cpsw.o cpts.o obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o keystone_netcp-y := netcp_core.o netcp_ethss.o netcp_sgmii.o \ - netcp_xgbepcsr.o cpsw_ale.o cpts.o + netcp_xgbepcsr.o cpsw_ale.o -- cgit v1.2.1 From 5b99a6b6cc563e29265502b2b3df39c872022c22 Mon Sep 17 00:00:00 2001 From: "Kweh, Hock Leong" Date: Tue, 27 Jan 2015 21:44:47 +0200 Subject: stmmac: pci: add support for Intel Quark X1000 The Intel Quark SoC X1000 provides two 10/100 Mbps Ethernet MAC controllers which may or may not be connected to PHY on board. This MAC controller only supports RMII PHY. This patch add Quark PCI ID as well as Quark default platform data info to this driver. Signed-off-by: Kweh, Hock Leong Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 51 +++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 054520d67de4..a316187967ea 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -26,6 +26,12 @@ #include #include "stmmac.h" +struct stmmac_pci_info { + struct pci_dev *pdev; + int (*setup)(struct plat_stmmacenet_data *plat, + struct stmmac_pci_info *info); +}; + static void stmmac_default_data(struct plat_stmmacenet_data *plat) { plat->bus_id = 1; @@ -48,6 +54,38 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat) plat->unicast_filter_entries = 1; } +static int quark_default_data(struct plat_stmmacenet_data *plat, + struct stmmac_pci_info *info) +{ + struct pci_dev *pdev = info->pdev; + + plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn); + plat->phy_addr = 1; + plat->interface = PHY_INTERFACE_MODE_RMII; + plat->clk_csr = 2; + plat->has_gmac = 1; + plat->force_sf_dma_mode = 1; + + plat->mdio_bus_data->phy_reset = NULL; + plat->mdio_bus_data->phy_mask = 0; + + plat->dma_cfg->pbl = 16; + plat->dma_cfg->burst_len = DMA_AXI_BLEN_256; + plat->dma_cfg->fixed_burst = 1; + + /* Set default value for multicast hash bins */ + plat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat->unicast_filter_entries = 1; + + return 0; +} + +static struct stmmac_pci_info quark_pci_info = { + .setup = quark_default_data, +}; + /** * stmmac_pci_probe * @@ -63,6 +101,7 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat) static int stmmac_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data; struct plat_stmmacenet_data *plat; struct stmmac_priv *priv; int i; @@ -103,7 +142,15 @@ static int stmmac_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); - stmmac_default_data(plat); + if (info) { + info->pdev = pdev; + if (info->setup) { + ret = info->setup(plat, info); + if (ret) + return ret; + } + } else + stmmac_default_data(plat); priv = stmmac_dvr_probe(&pdev->dev, plat, pcim_iomap_table(pdev)[i]); if (IS_ERR(priv)) { @@ -155,11 +202,13 @@ static int stmmac_pci_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume); #define STMMAC_VENDOR_ID 0x700 +#define STMMAC_QUARK_ID 0x0937 #define STMMAC_DEVICE_ID 0x1108 static const struct pci_device_id stmmac_id_table[] = { {PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)}, + {PCI_VDEVICE(INTEL, STMMAC_QUARK_ID), (kernel_ulong_t)&quark_pci_info}, {} }; -- cgit v1.2.1 From 0763d955b46e9b4c875cf1a7ab8576fb79fd1398 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 27 Jan 2015 21:44:48 +0200 Subject: stmmac: pci: introduce Intel Quark X1000 runtime detection This patch introduces run-time board detection through DMI and MAC-PHY configuration function used by quark_default_data() during initialization. It fills up the phy_addr for Galileo and Galileo Gen2 boards to indicate that the Ethernet MAC controller is or is not connected to any PHY. The implementation takes into consideration for future expansion in Quark series boards that may have different PHY address that is linked to its MAC controllers. This piece of work is derived from Bryan O'Donoghue's initial work for Quark X1000 enabling. Signed-off-by: Kweh, Hock Leong Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 62 +++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index a316187967ea..50f3c50852fb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -24,14 +24,50 @@ *******************************************************************************/ #include +#include + #include "stmmac.h" +/* + * This struct is used to associate PCI Function of MAC controller on a board, + * discovered via DMI, with the address of PHY connected to the MAC. The + * negative value of the address means that MAC controller is not connected + * with PHY. + */ +struct stmmac_pci_dmi_data { + const char *name; + unsigned int func; + int phy_addr; +}; + struct stmmac_pci_info { struct pci_dev *pdev; int (*setup)(struct plat_stmmacenet_data *plat, struct stmmac_pci_info *info); + struct stmmac_pci_dmi_data *dmi; }; +static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info) +{ + const char *name = dmi_get_system_info(DMI_BOARD_NAME); + unsigned int func = PCI_FUNC(info->pdev->devfn); + struct stmmac_pci_dmi_data *dmi; + + /* + * Galileo boards with old firmware don't support DMI. We always return + * 1 here, so at least first found MAC controller would be probed. + */ + if (!name) + return 1; + + for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) { + if (!strcmp(dmi->name, name) && dmi->func == func) + return dmi->phy_addr; + } + + return -ENODEV; +} + static void stmmac_default_data(struct plat_stmmacenet_data *plat) { plat->bus_id = 1; @@ -58,9 +94,18 @@ static int quark_default_data(struct plat_stmmacenet_data *plat, struct stmmac_pci_info *info) { struct pci_dev *pdev = info->pdev; + int ret; + + /* + * Refuse to load the driver and register net device if MAC controller + * does not connect to any PHY interface. + */ + ret = stmmac_pci_find_phy_addr(info); + if (ret < 0) + return ret; plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn); - plat->phy_addr = 1; + plat->phy_addr = ret; plat->interface = PHY_INTERFACE_MODE_RMII; plat->clk_csr = 2; plat->has_gmac = 1; @@ -82,8 +127,23 @@ static int quark_default_data(struct plat_stmmacenet_data *plat, return 0; } +static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = { + { + .name = "Galileo", + .func = 6, + .phy_addr = 1, + }, + { + .name = "GalileoGen2", + .func = 6, + .phy_addr = 1, + }, + {} +}; + static struct stmmac_pci_info quark_pci_info = { .setup = quark_default_data, + .dmi = quark_pci_dmi_data, }; /** -- cgit v1.2.1 From d2a029bde37b4c2e2d8b26e7457bb2c58afbbadd Mon Sep 17 00:00:00 2001 From: "Kweh, Hock Leong" Date: Tue, 27 Jan 2015 21:44:49 +0200 Subject: stmmac: pci: add MSI support for Intel Quark X1000 In Intel Quark SoC X1000, both of the Ethernet controllers support MSI interrupt handling. This patch enables them to use MSI interrupt servicing in stmmac_pci for Intel Quark X1000. Signed-off-by: Kweh, Hock Leong Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 50f3c50852fb..3bca908716e2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -212,6 +212,8 @@ static int stmmac_pci_probe(struct pci_dev *pdev, } else stmmac_default_data(plat); + pci_enable_msi(pdev); + priv = stmmac_dvr_probe(&pdev->dev, plat, pcim_iomap_table(pdev)[i]); if (IS_ERR(priv)) { dev_err(&pdev->dev, "%s: main driver probe failed\n", __func__); -- cgit v1.2.1 From 3b07a444ee48a8081d2ed3f0abeeabd038404ac1 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Mon, 26 Jan 2015 07:27:19 +0200 Subject: can: kvaser_usb: Update interface state before exiting on OOM Update all of the can interface's state and error counters before trying any skb allocation that can actually fail with -ENOMEM. Suggested-by: Marc Kleine-Budde Signed-off-by: Ahmed S. Darwish Acked-by: Andri Yngvason Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/kvaser_usb.c | 181 +++++++++++++++++++++++---------------- 1 file changed, 105 insertions(+), 76 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 7af379ca861b..f57ce556c678 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -273,6 +273,10 @@ struct kvaser_msg { } u; } __packed; +struct kvaser_usb_error_summary { + u8 channel, status, txerr, rxerr, error_factor; +}; + struct kvaser_usb_tx_urb_context { struct kvaser_usb_net_priv *priv; u32 echo_index; @@ -615,6 +619,54 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index = MAX_TX_URBS; } +static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *priv, + const struct kvaser_usb_error_summary *es) +{ + struct net_device_stats *stats; + enum can_state new_state; + + stats = &priv->netdev->stats; + new_state = priv->can.state; + + netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status); + + if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { + priv->can.can_stats.bus_off++; + new_state = CAN_STATE_BUS_OFF; + } else if (es->status & M16C_STATE_BUS_PASSIVE) { + if (priv->can.state != CAN_STATE_ERROR_PASSIVE) + priv->can.can_stats.error_passive++; + new_state = CAN_STATE_ERROR_PASSIVE; + } else if (es->status & M16C_STATE_BUS_ERROR) { + if ((priv->can.state < CAN_STATE_ERROR_WARNING) && + ((es->txerr >= 96) || (es->rxerr >= 96))) { + priv->can.can_stats.error_warning++; + new_state = CAN_STATE_ERROR_WARNING; + } else if ((priv->can.state > CAN_STATE_ERROR_ACTIVE) && + ((es->txerr < 96) && (es->rxerr < 96))) { + new_state = CAN_STATE_ERROR_ACTIVE; + } + } + + if (!es->status) + new_state = CAN_STATE_ERROR_ACTIVE; + + if (priv->can.restart_ms && + (priv->can.state >= CAN_STATE_BUS_OFF) && + (new_state < CAN_STATE_BUS_OFF)) { + priv->can.can_stats.restarts++; + } + + if (es->error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + } + + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; + priv->can.state = new_state; +} + static void kvaser_usb_rx_error(const struct kvaser_usb *dev, const struct kvaser_msg *msg) { @@ -622,30 +674,30 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, struct sk_buff *skb; struct net_device_stats *stats; struct kvaser_usb_net_priv *priv; - unsigned int new_state; - u8 channel, status, txerr, rxerr, error_factor; + struct kvaser_usb_error_summary es = { }; + enum can_state old_state; switch (msg->id) { case CMD_CAN_ERROR_EVENT: - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; + es.channel = msg->u.error_event.channel; + es.status = msg->u.error_event.status; + es.txerr = msg->u.error_event.tx_errors_count; + es.rxerr = msg->u.error_event.rx_errors_count; + es.error_factor = msg->u.error_event.error_factor; break; case CMD_LOG_MESSAGE: - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0]; - txerr = msg->u.log_message.data[2]; - rxerr = msg->u.log_message.data[3]; - error_factor = msg->u.log_message.data[1]; + es.channel = msg->u.log_message.channel; + es.status = msg->u.log_message.data[0]; + es.txerr = msg->u.log_message.data[2]; + es.rxerr = msg->u.log_message.data[3]; + es.error_factor = msg->u.log_message.data[1]; break; case CMD_CHIP_STATE_EVENT: - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor = 0; + es.channel = msg->u.chip_state_event.channel; + es.status = msg->u.chip_state_event.status; + es.txerr = msg->u.chip_state_event.tx_errors_count; + es.rxerr = msg->u.chip_state_event.rx_errors_count; + es.error_factor = 0; break; default: dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", @@ -653,116 +705,93 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, return; } - if (channel >= dev->nchannels) { + if (es.channel >= dev->nchannels) { dev_err(dev->udev->dev.parent, - "Invalid channel number (%d)\n", channel); + "Invalid channel number (%d)\n", es.channel); return; } - priv = dev->nets[channel]; + priv = dev->nets[es.channel]; stats = &priv->netdev->stats; + /* Update all of the can interface's state and error counters before + * trying any skb allocation that can actually fail with -ENOMEM. + */ + old_state = priv->can.state; + kvaser_usb_rx_error_update_can_state(priv, &es); + skb = alloc_can_err_skb(priv->netdev, &cf); if (!skb) { stats->rx_dropped++; return; } - new_state = priv->can.state; - - netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status); - - if (status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { + if (es.status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { cf->can_id |= CAN_ERR_BUSOFF; - priv->can.can_stats.bus_off++; if (!priv->can.restart_ms) kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP); - netif_carrier_off(priv->netdev); - - new_state = CAN_STATE_BUS_OFF; - } else if (status & M16C_STATE_BUS_PASSIVE) { - if (priv->can.state != CAN_STATE_ERROR_PASSIVE) { + } else if (es.status & M16C_STATE_BUS_PASSIVE) { + if (old_state != CAN_STATE_ERROR_PASSIVE) { cf->can_id |= CAN_ERR_CRTL; - if (txerr || rxerr) - cf->data[1] = (txerr > rxerr) + if (es.txerr || es.rxerr) + cf->data[1] = (es.txerr > es.rxerr) ? CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE; else cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE | CAN_ERR_CRTL_RX_PASSIVE; - - priv->can.can_stats.error_passive++; } - - new_state = CAN_STATE_ERROR_PASSIVE; - } else if (status & M16C_STATE_BUS_ERROR) { - if ((priv->can.state < CAN_STATE_ERROR_WARNING) && - ((txerr >= 96) || (rxerr >= 96))) { + } else if (es.status & M16C_STATE_BUS_ERROR) { + if ((old_state < CAN_STATE_ERROR_WARNING) && + ((es.txerr >= 96) || (es.rxerr >= 96))) { cf->can_id |= CAN_ERR_CRTL; - cf->data[1] = (txerr > rxerr) + cf->data[1] = (es.txerr > es.rxerr) ? CAN_ERR_CRTL_TX_WARNING : CAN_ERR_CRTL_RX_WARNING; - - priv->can.can_stats.error_warning++; - new_state = CAN_STATE_ERROR_WARNING; - } else if ((priv->can.state > CAN_STATE_ERROR_ACTIVE) && - ((txerr < 96) && (rxerr < 96))) { + } else if ((old_state > CAN_STATE_ERROR_ACTIVE) && + ((es.txerr < 96) && (es.rxerr < 96))) { cf->can_id |= CAN_ERR_PROT; cf->data[2] = CAN_ERR_PROT_ACTIVE; - - new_state = CAN_STATE_ERROR_ACTIVE; } } - if (!status) { + if (!es.status) { cf->can_id |= CAN_ERR_PROT; cf->data[2] = CAN_ERR_PROT_ACTIVE; - - new_state = CAN_STATE_ERROR_ACTIVE; } if (priv->can.restart_ms && - (priv->can.state >= CAN_STATE_BUS_OFF) && - (new_state < CAN_STATE_BUS_OFF)) { + (old_state >= CAN_STATE_BUS_OFF) && + (priv->can.state < CAN_STATE_BUS_OFF)) { cf->can_id |= CAN_ERR_RESTARTED; netif_carrier_on(priv->netdev); - - priv->can.can_stats.restarts++; } - if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - + if (es.error_factor) { cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; - if (error_factor & M16C_EF_ACKE) + if (es.error_factor & M16C_EF_ACKE) cf->data[3] |= (CAN_ERR_PROT_LOC_ACK); - if (error_factor & M16C_EF_CRCE) + if (es.error_factor & M16C_EF_CRCE) cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | CAN_ERR_PROT_LOC_CRC_DEL); - if (error_factor & M16C_EF_FORME) + if (es.error_factor & M16C_EF_FORME) cf->data[2] |= CAN_ERR_PROT_FORM; - if (error_factor & M16C_EF_STFE) + if (es.error_factor & M16C_EF_STFE) cf->data[2] |= CAN_ERR_PROT_STUFF; - if (error_factor & M16C_EF_BITE0) + if (es.error_factor & M16C_EF_BITE0) cf->data[2] |= CAN_ERR_PROT_BIT0; - if (error_factor & M16C_EF_BITE1) + if (es.error_factor & M16C_EF_BITE1) cf->data[2] |= CAN_ERR_PROT_BIT1; - if (error_factor & M16C_EF_TRE) + if (es.error_factor & M16C_EF_TRE) cf->data[2] |= CAN_ERR_PROT_TX; } - cf->data[6] = txerr; - cf->data[7] = rxerr; - - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; - - priv->can.state = new_state; + cf->data[6] = es.txerr; + cf->data[7] = es.rxerr; stats->rx_packets++; stats->rx_bytes += cf->can_dlc; @@ -786,6 +815,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, } if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) { + stats->rx_over_errors++; + stats->rx_errors++; + skb = alloc_can_err_skb(priv->netdev, &cf); if (!skb) { stats->rx_dropped++; @@ -795,9 +827,6 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; - stats->rx_over_errors++; - stats->rx_errors++; - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; netif_rx(skb); -- cgit v1.2.1 From 96d7f10634e66b27e23854c774fbcc0a2a654e82 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Mon, 26 Jan 2015 07:29:15 +0200 Subject: can: kvaser_usb: Consolidate and unify state change handling Replace most of the can interface's state and error counters handling with the new can-dev can_change_state() mechanism. Suggested-by: Andri Yngvason Signed-off-by: Ahmed S. Darwish Acked-by: Andri Yngvason Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/kvaser_usb.c | 113 +++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 64 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index f57ce556c678..ddc29549aded 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -620,39 +620,44 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) } static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *priv, - const struct kvaser_usb_error_summary *es) + const struct kvaser_usb_error_summary *es, + struct can_frame *cf) { struct net_device_stats *stats; - enum can_state new_state; - - stats = &priv->netdev->stats; - new_state = priv->can.state; + enum can_state cur_state, new_state, tx_state, rx_state; netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status); - if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { - priv->can.can_stats.bus_off++; + stats = &priv->netdev->stats; + new_state = cur_state = priv->can.state; + + if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) new_state = CAN_STATE_BUS_OFF; - } else if (es->status & M16C_STATE_BUS_PASSIVE) { - if (priv->can.state != CAN_STATE_ERROR_PASSIVE) - priv->can.can_stats.error_passive++; + else if (es->status & M16C_STATE_BUS_PASSIVE) new_state = CAN_STATE_ERROR_PASSIVE; - } else if (es->status & M16C_STATE_BUS_ERROR) { - if ((priv->can.state < CAN_STATE_ERROR_WARNING) && - ((es->txerr >= 96) || (es->rxerr >= 96))) { - priv->can.can_stats.error_warning++; + else if (es->status & M16C_STATE_BUS_ERROR) { + if ((es->txerr >= 256) || (es->rxerr >= 256)) + new_state = CAN_STATE_BUS_OFF; + else if ((es->txerr >= 128) || (es->rxerr >= 128)) + new_state = CAN_STATE_ERROR_PASSIVE; + else if ((es->txerr >= 96) || (es->rxerr >= 96)) new_state = CAN_STATE_ERROR_WARNING; - } else if ((priv->can.state > CAN_STATE_ERROR_ACTIVE) && - ((es->txerr < 96) && (es->rxerr < 96))) { + else if (cur_state > CAN_STATE_ERROR_ACTIVE) new_state = CAN_STATE_ERROR_ACTIVE; - } } if (!es->status) new_state = CAN_STATE_ERROR_ACTIVE; + if (new_state != cur_state) { + tx_state = (es->txerr >= es->rxerr) ? new_state : 0; + rx_state = (es->txerr <= es->rxerr) ? new_state : 0; + + can_change_state(priv->netdev, cf, tx_state, rx_state); + } + if (priv->can.restart_ms && - (priv->can.state >= CAN_STATE_BUS_OFF) && + (cur_state >= CAN_STATE_BUS_OFF) && (new_state < CAN_STATE_BUS_OFF)) { priv->can.can_stats.restarts++; } @@ -664,18 +669,17 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri priv->bec.txerr = es->txerr; priv->bec.rxerr = es->rxerr; - priv->can.state = new_state; } static void kvaser_usb_rx_error(const struct kvaser_usb *dev, const struct kvaser_msg *msg) { - struct can_frame *cf; + struct can_frame *cf, tmp_cf = { .can_id = CAN_ERR_FLAG, .can_dlc = CAN_ERR_DLC }; struct sk_buff *skb; struct net_device_stats *stats; struct kvaser_usb_net_priv *priv; struct kvaser_usb_error_summary es = { }; - enum can_state old_state; + enum can_state old_state, new_state; switch (msg->id) { case CMD_CAN_ERROR_EVENT: @@ -715,59 +719,40 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, stats = &priv->netdev->stats; /* Update all of the can interface's state and error counters before - * trying any skb allocation that can actually fail with -ENOMEM. + * trying any memory allocation that can actually fail with -ENOMEM. + * + * We send a temporary stack-allocated error can frame to + * can_change_state() for the very same reason. + * + * TODO: Split can_change_state() responsibility between updating the + * can interface's state and counters, and the setting up of can error + * frame ID and data to userspace. Remove stack allocation afterwards. */ old_state = priv->can.state; - kvaser_usb_rx_error_update_can_state(priv, &es); + kvaser_usb_rx_error_update_can_state(priv, &es, &tmp_cf); + new_state = priv->can.state; skb = alloc_can_err_skb(priv->netdev, &cf); if (!skb) { stats->rx_dropped++; return; } - - if (es.status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { - cf->can_id |= CAN_ERR_BUSOFF; - - if (!priv->can.restart_ms) - kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP); - netif_carrier_off(priv->netdev); - } else if (es.status & M16C_STATE_BUS_PASSIVE) { - if (old_state != CAN_STATE_ERROR_PASSIVE) { - cf->can_id |= CAN_ERR_CRTL; - - if (es.txerr || es.rxerr) - cf->data[1] = (es.txerr > es.rxerr) - ? CAN_ERR_CRTL_TX_PASSIVE - : CAN_ERR_CRTL_RX_PASSIVE; - else - cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE | - CAN_ERR_CRTL_RX_PASSIVE; - } - } else if (es.status & M16C_STATE_BUS_ERROR) { - if ((old_state < CAN_STATE_ERROR_WARNING) && - ((es.txerr >= 96) || (es.rxerr >= 96))) { - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] = (es.txerr > es.rxerr) - ? CAN_ERR_CRTL_TX_WARNING - : CAN_ERR_CRTL_RX_WARNING; - } else if ((old_state > CAN_STATE_ERROR_ACTIVE) && - ((es.txerr < 96) && (es.rxerr < 96))) { - cf->can_id |= CAN_ERR_PROT; - cf->data[2] = CAN_ERR_PROT_ACTIVE; + memcpy(cf, &tmp_cf, sizeof(*cf)); + + if (new_state != old_state) { + if (es.status & + (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { + if (!priv->can.restart_ms) + kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP); + netif_carrier_off(priv->netdev); } - } - - if (!es.status) { - cf->can_id |= CAN_ERR_PROT; - cf->data[2] = CAN_ERR_PROT_ACTIVE; - } - if (priv->can.restart_ms && - (old_state >= CAN_STATE_BUS_OFF) && - (priv->can.state < CAN_STATE_BUS_OFF)) { - cf->can_id |= CAN_ERR_RESTARTED; - netif_carrier_on(priv->netdev); + if (priv->can.restart_ms && + (old_state >= CAN_STATE_BUS_OFF) && + (new_state < CAN_STATE_BUS_OFF)) { + cf->can_id |= CAN_ERR_RESTARTED; + netif_carrier_on(priv->netdev); + } } if (es.error_factor) { -- cgit v1.2.1 From f5d4abea3ce0747ba2b5061dbc99c6f3149c4ba4 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Mon, 26 Jan 2015 07:33:10 +0200 Subject: can: kvaser_usb: Add support for the USBcan-II family CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'USBcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion. This patch adds support for the USBcanII family of devices to the current Kvaser Leaf-only driver. CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category. List of new devices supported by this driver update: - Kvaser USBcan II HS/HS - Kvaser USBcan II HS/LS - Kvaser USBcan Rugged ("USBcan Rev B") - Kvaser Memorator HS/HS - Kvaser Memorator HS/LS - Scania VCI2 (if you have the Kvaser logo on top) Signed-off-by: Ahmed S. Darwish Acked-by: Andri Yngvason Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/Kconfig | 8 +- drivers/net/can/usb/kvaser_usb.c | 590 +++++++++++++++++++++++++++++++-------- 2 files changed, 474 insertions(+), 124 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index a77db919363c..f6f55004fe2b 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -25,7 +25,7 @@ config CAN_KVASER_USB tristate "Kvaser CAN/USB interface" ---help--- This driver adds support for Kvaser CAN/USB devices like Kvaser - Leaf Light. + Leaf Light and Kvaser USBcan II. The driver provides support for the following devices: - Kvaser Leaf Light @@ -46,6 +46,12 @@ config CAN_KVASER_USB - Kvaser USBcan R - Kvaser Leaf Light v2 - Kvaser Mini PCI Express HS + - Kvaser USBcan II HS/HS + - Kvaser USBcan II HS/LS + - Kvaser USBcan Rugged ("USBcan Rev B") + - Kvaser Memorator HS/HS + - Kvaser Memorator HS/LS + - Scania VCI2 (if you have the Kvaser logo on top) If unsure, say N. diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index ddc29549aded..17d28d7dd412 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -6,10 +6,12 @@ * Parts of this driver are based on the following: * - Kvaser linux leaf driver (version 4.78) * - CAN driver for esd CAN-USB/2 + * - Kvaser linux usbcanII driver (version 5.3) * * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs , esd gmbh * Copyright (C) 2012 Olivier Sobrie + * Copyright (C) 2015 Valeo A.S. */ #include @@ -30,8 +32,9 @@ #define RX_BUFFER_SIZE 3072 #define CAN_USB_CLOCK 8000000 #define MAX_NET_DEVICES 3 +#define MAX_USBCAN_NET_DEVICES 2 -/* Kvaser USB devices */ +/* Kvaser Leaf USB devices */ #define KVASER_VENDOR_ID 0x0bfd #define USB_LEAF_DEVEL_PRODUCT_ID 10 #define USB_LEAF_LITE_PRODUCT_ID 11 @@ -56,6 +59,24 @@ #define USB_LEAF_LITE_V2_PRODUCT_ID 288 #define USB_MINI_PCIE_HS_PRODUCT_ID 289 +static inline bool kvaser_is_leaf(const struct usb_device_id *id) +{ + return id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID && + id->idProduct <= USB_MINI_PCIE_HS_PRODUCT_ID; +} + +/* Kvaser USBCan-II devices */ +#define USB_USBCAN_REVB_PRODUCT_ID 2 +#define USB_VCI2_PRODUCT_ID 3 +#define USB_USBCAN2_PRODUCT_ID 4 +#define USB_MEMORATOR_PRODUCT_ID 5 + +static inline bool kvaser_is_usbcan(const struct usb_device_id *id) +{ + return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID && + id->idProduct <= USB_MEMORATOR_PRODUCT_ID; +} + /* USB devices features */ #define KVASER_HAS_SILENT_MODE BIT(0) #define KVASER_HAS_TXRX_ERRORS BIT(1) @@ -73,7 +94,7 @@ #define MSG_FLAG_TX_ACK BIT(6) #define MSG_FLAG_TX_REQUEST BIT(7) -/* Can states */ +/* Can states (M16C CxSTRH register) */ #define M16C_STATE_BUS_RESET BIT(0) #define M16C_STATE_BUS_ERROR BIT(4) #define M16C_STATE_BUS_PASSIVE BIT(5) @@ -98,7 +119,11 @@ #define CMD_START_CHIP_REPLY 27 #define CMD_STOP_CHIP 28 #define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 + +#define CMD_LEAF_GET_CARD_INFO2 32 +#define CMD_USBCAN_RESET_CLOCK 32 +#define CMD_USBCAN_CLOCK_OVERFLOW_EVENT 33 + #define CMD_GET_CARD_INFO 34 #define CMD_GET_CARD_INFO_REPLY 35 #define CMD_GET_SOFTWARE_INFO 38 @@ -108,8 +133,9 @@ #define CMD_RESET_ERROR_COUNTER 49 #define CMD_TX_ACKNOWLEDGE 50 #define CMD_CAN_ERROR_EVENT 51 -#define CMD_USB_THROTTLE 77 -#define CMD_LOG_MESSAGE 106 + +#define CMD_LEAF_USB_THROTTLE 77 +#define CMD_LEAF_LOG_MESSAGE 106 /* error factors */ #define M16C_EF_ACKE BIT(0) @@ -121,6 +147,14 @@ #define M16C_EF_RCVE BIT(6) #define M16C_EF_TRE BIT(7) +/* Only Leaf-based devices can report M16C error factors, + * thus define our own error status flags for USBCANII + */ +#define USBCAN_ERROR_STATE_NONE 0 +#define USBCAN_ERROR_STATE_TX_ERROR BIT(0) +#define USBCAN_ERROR_STATE_RX_ERROR BIT(1) +#define USBCAN_ERROR_STATE_BUSERROR BIT(2) + /* bittiming parameters */ #define KVASER_USB_TSEG1_MIN 1 #define KVASER_USB_TSEG1_MAX 16 @@ -137,9 +171,18 @@ #define KVASER_CTRL_MODE_SELFRECEPTION 3 #define KVASER_CTRL_MODE_OFF 4 -/* log message */ +/* Extended CAN identifier flag */ #define KVASER_EXTENDED_FRAME BIT(31) +/* Kvaser USB CAN dongles are divided into two major families: + * - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' + * - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' + */ +enum kvaser_usb_family { + KVASER_LEAF, + KVASER_USBCAN, +}; + struct kvaser_msg_simple { u8 tid; u8 channel; @@ -148,30 +191,55 @@ struct kvaser_msg_simple { struct kvaser_msg_cardinfo { u8 tid; u8 nchannels; - __le32 serial_number; - __le32 padding; + union { + struct { + __le32 serial_number; + __le32 padding; + } __packed leaf0; + struct { + __le32 serial_number_low; + __le32 serial_number_high; + } __packed usbcan0; + } __packed; __le32 clock_resolution; __le32 mfgdate; u8 ean[8]; u8 hw_revision; - u8 usb_hs_mode; - __le16 padding2; + union { + struct { + u8 usb_hs_mode; + } __packed leaf1; + struct { + u8 padding; + } __packed usbcan1; + } __packed; + __le16 padding; } __packed; struct kvaser_msg_cardinfo2 { u8 tid; - u8 channel; + u8 reserved; u8 pcb_id[24]; __le32 oem_unlock_code; } __packed; -struct kvaser_msg_softinfo { +struct leaf_msg_softinfo { u8 tid; - u8 channel; + u8 padding0; __le32 sw_options; __le32 fw_version; __le16 max_outstanding_tx; - __le16 padding[9]; + __le16 padding1[9]; +} __packed; + +struct usbcan_msg_softinfo { + u8 tid; + u8 fw_name[5]; + __le16 max_outstanding_tx; + u8 padding[6]; + __le32 fw_version; + __le16 checksum; + __le16 sw_options; } __packed; struct kvaser_msg_busparams { @@ -188,36 +256,86 @@ struct kvaser_msg_tx_can { u8 channel; u8 tid; u8 msg[14]; - u8 padding; - u8 flags; + union { + struct { + u8 padding; + u8 flags; + } __packed leaf; + struct { + u8 flags; + u8 padding; + } __packed usbcan; + } __packed; +} __packed; + +struct kvaser_msg_rx_can_header { + u8 channel; + u8 flag; } __packed; -struct kvaser_msg_rx_can { +struct leaf_msg_rx_can { u8 channel; u8 flag; + __le16 time[3]; u8 msg[14]; } __packed; -struct kvaser_msg_chip_state_event { +struct usbcan_msg_rx_can { + u8 channel; + u8 flag; + + u8 msg[14]; + __le16 time; +} __packed; + +struct leaf_msg_chip_state_event { u8 tid; u8 channel; + __le16 time[3]; u8 tx_errors_count; u8 rx_errors_count; + + u8 status; + u8 padding[3]; +} __packed; + +struct usbcan_msg_chip_state_event { + u8 tid; + u8 channel; + + u8 tx_errors_count; + u8 rx_errors_count; + __le16 time; + u8 status; u8 padding[3]; } __packed; -struct kvaser_msg_tx_acknowledge { +struct kvaser_msg_tx_acknowledge_header { u8 channel; u8 tid; +} __packed; + +struct leaf_msg_tx_acknowledge { + u8 channel; + u8 tid; + __le16 time[3]; u8 flags; u8 time_offset; } __packed; -struct kvaser_msg_error_event { +struct usbcan_msg_tx_acknowledge { + u8 channel; + u8 tid; + + __le16 time; + __le16 padding; +} __packed; + +struct leaf_msg_error_event { u8 tid; u8 flags; __le16 time[3]; @@ -229,6 +347,18 @@ struct kvaser_msg_error_event { u8 error_factor; } __packed; +struct usbcan_msg_error_event { + u8 tid; + u8 padding; + u8 tx_errors_count_ch0; + u8 rx_errors_count_ch0; + u8 tx_errors_count_ch1; + u8 rx_errors_count_ch1; + u8 status_ch0; + u8 status_ch1; + __le16 time; +} __packed; + struct kvaser_msg_ctrl_mode { u8 tid; u8 channel; @@ -243,7 +373,7 @@ struct kvaser_msg_flush_queue { u8 padding[3]; } __packed; -struct kvaser_msg_log_message { +struct leaf_msg_log_message { u8 channel; u8 flags; __le16 time[3]; @@ -260,21 +390,55 @@ struct kvaser_msg { struct kvaser_msg_simple simple; struct kvaser_msg_cardinfo cardinfo; struct kvaser_msg_cardinfo2 cardinfo2; - struct kvaser_msg_softinfo softinfo; struct kvaser_msg_busparams busparams; + + struct kvaser_msg_rx_can_header rx_can_header; + struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header; + + union { + struct leaf_msg_softinfo softinfo; + struct leaf_msg_rx_can rx_can; + struct leaf_msg_chip_state_event chip_state_event; + struct leaf_msg_tx_acknowledge tx_acknowledge; + struct leaf_msg_error_event error_event; + struct leaf_msg_log_message log_message; + } __packed leaf; + + union { + struct usbcan_msg_softinfo softinfo; + struct usbcan_msg_rx_can rx_can; + struct usbcan_msg_chip_state_event chip_state_event; + struct usbcan_msg_tx_acknowledge tx_acknowledge; + struct usbcan_msg_error_event error_event; + } __packed usbcan; + struct kvaser_msg_tx_can tx_can; - struct kvaser_msg_rx_can rx_can; - struct kvaser_msg_chip_state_event chip_state_event; - struct kvaser_msg_tx_acknowledge tx_acknowledge; - struct kvaser_msg_error_event error_event; struct kvaser_msg_ctrl_mode ctrl_mode; struct kvaser_msg_flush_queue flush_queue; - struct kvaser_msg_log_message log_message; } u; } __packed; +/* Summary of a kvaser error event, for a unified Leaf/Usbcan error + * handling. Some discrepancies between the two families exist: + * + * - USBCAN firmware does not report M16C "error factors" + * - USBCAN controllers has difficulties reporting if the raised error + * event is for ch0 or ch1. They leave such arbitration to the OS + * driver by letting it compare error counters with previous values + * and decide the error event's channel. Thus for USBCAN, the channel + * field is only advisory. + */ struct kvaser_usb_error_summary { - u8 channel, status, txerr, rxerr, error_factor; + u8 channel, status, txerr, rxerr; + union { + struct { + u8 error_factor; + } leaf; + struct { + u8 other_ch_status; + u8 error_state; + } usbcan; + }; }; struct kvaser_usb_tx_urb_context { @@ -292,6 +456,7 @@ struct kvaser_usb { u32 fw_version; unsigned int nchannels; + enum kvaser_usb_family family; bool rxinitdone; void *rxbuf[MAX_RX_URBS]; @@ -315,6 +480,7 @@ struct kvaser_usb_net_priv { }; static const struct usb_device_id kvaser_usb_table[] = { + /* Leaf family IDs */ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID), @@ -364,6 +530,17 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = KVASER_HAS_TXRX_ERRORS }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, + + /* USBCANII family IDs */ + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { } }; MODULE_DEVICE_TABLE(usb, kvaser_usb_table); @@ -467,7 +644,14 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev) if (err) return err; - dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version); + switch (dev->family) { + case KVASER_LEAF: + dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version); + break; + case KVASER_USBCAN: + dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version); + break; + } return 0; } @@ -486,7 +670,9 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev) return err; dev->nchannels = msg.u.cardinfo.nchannels; - if (dev->nchannels > MAX_NET_DEVICES) + if ((dev->nchannels > MAX_NET_DEVICES) || + (dev->family == KVASER_USBCAN && + dev->nchannels > MAX_USBCAN_NET_DEVICES)) return -EINVAL; return 0; @@ -500,8 +686,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, struct kvaser_usb_net_priv *priv; struct sk_buff *skb; struct can_frame *cf; - u8 channel = msg->u.tx_acknowledge.channel; - u8 tid = msg->u.tx_acknowledge.tid; + u8 channel, tid; + + channel = msg->u.tx_acknowledge_header.channel; + tid = msg->u.tx_acknowledge_header.tid; if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent, @@ -623,12 +811,12 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri const struct kvaser_usb_error_summary *es, struct can_frame *cf) { - struct net_device_stats *stats; + struct kvaser_usb *dev = priv->dev; + struct net_device_stats *stats = &priv->netdev->stats; enum can_state cur_state, new_state, tx_state, rx_state; netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status); - stats = &priv->netdev->stats; new_state = cur_state = priv->can.state; if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) @@ -662,9 +850,22 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri priv->can.can_stats.restarts++; } - if (es->error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; + switch (dev->family) { + case KVASER_LEAF: + if (es->leaf.error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + } + break; + case KVASER_USBCAN: + if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR) + stats->tx_errors++; + if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR) + stats->rx_errors++; + if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) { + priv->can.can_stats.bus_error++; + } + break; } priv->bec.txerr = es->txerr; @@ -672,50 +873,21 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri } static void kvaser_usb_rx_error(const struct kvaser_usb *dev, - const struct kvaser_msg *msg) + const struct kvaser_usb_error_summary *es) { struct can_frame *cf, tmp_cf = { .can_id = CAN_ERR_FLAG, .can_dlc = CAN_ERR_DLC }; struct sk_buff *skb; struct net_device_stats *stats; struct kvaser_usb_net_priv *priv; - struct kvaser_usb_error_summary es = { }; enum can_state old_state, new_state; - switch (msg->id) { - case CMD_CAN_ERROR_EVENT: - es.channel = msg->u.error_event.channel; - es.status = msg->u.error_event.status; - es.txerr = msg->u.error_event.tx_errors_count; - es.rxerr = msg->u.error_event.rx_errors_count; - es.error_factor = msg->u.error_event.error_factor; - break; - case CMD_LOG_MESSAGE: - es.channel = msg->u.log_message.channel; - es.status = msg->u.log_message.data[0]; - es.txerr = msg->u.log_message.data[2]; - es.rxerr = msg->u.log_message.data[3]; - es.error_factor = msg->u.log_message.data[1]; - break; - case CMD_CHIP_STATE_EVENT: - es.channel = msg->u.chip_state_event.channel; - es.status = msg->u.chip_state_event.status; - es.txerr = msg->u.chip_state_event.tx_errors_count; - es.rxerr = msg->u.chip_state_event.rx_errors_count; - es.error_factor = 0; - break; - default: - dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", - msg->id); - return; - } - - if (es.channel >= dev->nchannels) { + if (es->channel >= dev->nchannels) { dev_err(dev->udev->dev.parent, - "Invalid channel number (%d)\n", es.channel); + "Invalid channel number (%d)\n", es->channel); return; } - priv = dev->nets[es.channel]; + priv = dev->nets[es->channel]; stats = &priv->netdev->stats; /* Update all of the can interface's state and error counters before @@ -729,7 +901,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, * frame ID and data to userspace. Remove stack allocation afterwards. */ old_state = priv->can.state; - kvaser_usb_rx_error_update_can_state(priv, &es, &tmp_cf); + kvaser_usb_rx_error_update_can_state(priv, es, &tmp_cf); new_state = priv->can.state; skb = alloc_can_err_skb(priv->netdev, &cf); @@ -740,7 +912,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, memcpy(cf, &tmp_cf, sizeof(*cf)); if (new_state != old_state) { - if (es.status & + if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { if (!priv->can.restart_ms) kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP); @@ -755,34 +927,161 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } } - if (es.error_factor) { - cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; - - if (es.error_factor & M16C_EF_ACKE) - cf->data[3] |= (CAN_ERR_PROT_LOC_ACK); - if (es.error_factor & M16C_EF_CRCE) - cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL); - if (es.error_factor & M16C_EF_FORME) - cf->data[2] |= CAN_ERR_PROT_FORM; - if (es.error_factor & M16C_EF_STFE) - cf->data[2] |= CAN_ERR_PROT_STUFF; - if (es.error_factor & M16C_EF_BITE0) - cf->data[2] |= CAN_ERR_PROT_BIT0; - if (es.error_factor & M16C_EF_BITE1) - cf->data[2] |= CAN_ERR_PROT_BIT1; - if (es.error_factor & M16C_EF_TRE) - cf->data[2] |= CAN_ERR_PROT_TX; + switch (dev->family) { + case KVASER_LEAF: + if (es->leaf.error_factor) { + cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; + + if (es->leaf.error_factor & M16C_EF_ACKE) + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK); + if (es->leaf.error_factor & M16C_EF_CRCE) + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | + CAN_ERR_PROT_LOC_CRC_DEL); + if (es->leaf.error_factor & M16C_EF_FORME) + cf->data[2] |= CAN_ERR_PROT_FORM; + if (es->leaf.error_factor & M16C_EF_STFE) + cf->data[2] |= CAN_ERR_PROT_STUFF; + if (es->leaf.error_factor & M16C_EF_BITE0) + cf->data[2] |= CAN_ERR_PROT_BIT0; + if (es->leaf.error_factor & M16C_EF_BITE1) + cf->data[2] |= CAN_ERR_PROT_BIT1; + if (es->leaf.error_factor & M16C_EF_TRE) + cf->data[2] |= CAN_ERR_PROT_TX; + } + break; + case KVASER_USBCAN: + if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) { + cf->can_id |= CAN_ERR_BUSERROR; + } + break; } - cf->data[6] = es.txerr; - cf->data[7] = es.rxerr; + cf->data[6] = es->txerr; + cf->data[7] = es->rxerr; stats->rx_packets++; stats->rx_bytes += cf->can_dlc; netif_rx(skb); } +/* For USBCAN, report error to userspace iff the channels's errors counter + * has changed, or we're the only channel seeing a bus error state. + */ +static void kvaser_usbcan_conditionally_rx_error(const struct kvaser_usb *dev, + struct kvaser_usb_error_summary *es) +{ + struct kvaser_usb_net_priv *priv; + int channel; + bool report_error; + + channel = es->channel; + if (channel >= dev->nchannels) { + dev_err(dev->udev->dev.parent, + "Invalid channel number (%d)\n", channel); + return; + } + + priv = dev->nets[channel]; + report_error = false; + + if (es->txerr != priv->bec.txerr) { + es->usbcan.error_state |= USBCAN_ERROR_STATE_TX_ERROR; + report_error = true; + } + if (es->rxerr != priv->bec.rxerr) { + es->usbcan.error_state |= USBCAN_ERROR_STATE_RX_ERROR; + report_error = true; + } + if ((es->status & M16C_STATE_BUS_ERROR) && + !(es->usbcan.other_ch_status & M16C_STATE_BUS_ERROR)) { + es->usbcan.error_state |= USBCAN_ERROR_STATE_BUSERROR; + report_error = true; + } + + if (report_error) + kvaser_usb_rx_error(dev, es); +} + +static void kvaser_usbcan_rx_error(const struct kvaser_usb *dev, + const struct kvaser_msg *msg) +{ + struct kvaser_usb_error_summary es = { }; + + switch (msg->id) { + /* Sometimes errors are sent as unsolicited chip state events */ + case CMD_CHIP_STATE_EVENT: + es.channel = msg->u.usbcan.chip_state_event.channel; + es.status = msg->u.usbcan.chip_state_event.status; + es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count; + es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count; + kvaser_usbcan_conditionally_rx_error(dev, &es); + break; + + case CMD_CAN_ERROR_EVENT: + es.channel = 0; + es.status = msg->u.usbcan.error_event.status_ch0; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch1; + kvaser_usbcan_conditionally_rx_error(dev, &es); + + /* The USBCAN firmware supports up to 2 channels. + * Now that ch0 was checked, check if ch1 has any errors. + */ + if (dev->nchannels == MAX_USBCAN_NET_DEVICES) { + es.channel = 1; + es.status = msg->u.usbcan.error_event.status_ch1; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch0; + kvaser_usbcan_conditionally_rx_error(dev, &es); + } + break; + + default: + dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", + msg->id); + } +} + +static void kvaser_leaf_rx_error(const struct kvaser_usb *dev, + const struct kvaser_msg *msg) +{ + struct kvaser_usb_error_summary es = { }; + + switch (msg->id) { + case CMD_CAN_ERROR_EVENT: + es.channel = msg->u.leaf.error_event.channel; + es.status = msg->u.leaf.error_event.status; + es.txerr = msg->u.leaf.error_event.tx_errors_count; + es.rxerr = msg->u.leaf.error_event.rx_errors_count; + es.leaf.error_factor = msg->u.leaf.error_event.error_factor; + break; + case CMD_LEAF_LOG_MESSAGE: + es.channel = msg->u.leaf.log_message.channel; + es.status = msg->u.leaf.log_message.data[0]; + es.txerr = msg->u.leaf.log_message.data[2]; + es.rxerr = msg->u.leaf.log_message.data[3]; + es.leaf.error_factor = msg->u.leaf.log_message.data[1]; + break; + case CMD_CHIP_STATE_EVENT: + es.channel = msg->u.leaf.chip_state_event.channel; + es.status = msg->u.leaf.chip_state_event.status; + es.txerr = msg->u.leaf.chip_state_event.tx_errors_count; + es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count; + es.leaf.error_factor = 0; + break; + default: + dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", + msg->id); + return; + } + + kvaser_usb_rx_error(dev, &es); +} + static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, const struct kvaser_msg *msg) { @@ -790,16 +1089,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, struct sk_buff *skb; struct net_device_stats *stats = &priv->netdev->stats; - if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | + if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | MSG_FLAG_NERR)) { netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n", - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); stats->rx_errors++; return; } - if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) { + if (msg->u.rx_can_header.flag & MSG_FLAG_OVERRUN) { stats->rx_over_errors++; stats->rx_errors++; @@ -825,7 +1124,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, struct can_frame *cf; struct sk_buff *skb; struct net_device_stats *stats; - u8 channel = msg->u.rx_can.channel; + u8 channel = msg->u.rx_can_header.channel; + const u8 *rx_msg = NULL; /* GCC */ if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent, @@ -836,60 +1136,68 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; - if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) && - (msg->id == CMD_LOG_MESSAGE)) { - kvaser_usb_rx_error(dev, msg); + if ((msg->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) && + (dev->family == KVASER_LEAF && msg->id == CMD_LEAF_LOG_MESSAGE)) { + kvaser_leaf_rx_error(dev, msg); return; - } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | - MSG_FLAG_NERR | - MSG_FLAG_OVERRUN)) { + } else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | + MSG_FLAG_NERR | + MSG_FLAG_OVERRUN)) { kvaser_usb_rx_can_err(priv, msg); return; - } else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) { + } else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME) { netdev_warn(priv->netdev, "Unhandled frame (flags: 0x%02x)", - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); return; } + switch (dev->family) { + case KVASER_LEAF: + rx_msg = msg->u.leaf.rx_can.msg; + break; + case KVASER_USBCAN: + rx_msg = msg->u.usbcan.rx_can.msg; + break; + } + skb = alloc_can_skb(priv->netdev, &cf); if (!skb) { stats->tx_dropped++; return; } - if (msg->id == CMD_LOG_MESSAGE) { - cf->can_id = le32_to_cpu(msg->u.log_message.id); + if (dev->family == KVASER_LEAF && msg->id == CMD_LEAF_LOG_MESSAGE) { + cf->can_id = le32_to_cpu(msg->u.leaf.log_message.id); if (cf->can_id & KVASER_EXTENDED_FRAME) cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG; else cf->can_id &= CAN_SFF_MASK; - cf->can_dlc = get_can_dlc(msg->u.log_message.dlc); + cf->can_dlc = get_can_dlc(msg->u.leaf.log_message.dlc); - if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME) + if (msg->u.leaf.log_message.flags & MSG_FLAG_REMOTE_FRAME) cf->can_id |= CAN_RTR_FLAG; else - memcpy(cf->data, &msg->u.log_message.data, + memcpy(cf->data, &msg->u.leaf.log_message.data, cf->can_dlc); } else { - cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) | - (msg->u.rx_can.msg[1] & 0x3f); + cf->can_id = ((rx_msg[0] & 0x1f) << 6) | (rx_msg[1] & 0x3f); if (msg->id == CMD_RX_EXT_MESSAGE) { cf->can_id <<= 18; - cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) | - ((msg->u.rx_can.msg[3] & 0xff) << 6) | - (msg->u.rx_can.msg[4] & 0x3f); + cf->can_id |= ((rx_msg[2] & 0x0f) << 14) | + ((rx_msg[3] & 0xff) << 6) | + (rx_msg[4] & 0x3f); cf->can_id |= CAN_EFF_FLAG; } - cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]); + cf->can_dlc = get_can_dlc(rx_msg[5]); - if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME) + if (msg->u.rx_can_header.flag & MSG_FLAG_REMOTE_FRAME) cf->can_id |= CAN_RTR_FLAG; else - memcpy(cf->data, &msg->u.rx_can.msg[6], + memcpy(cf->data, &rx_msg[6], cf->can_dlc); } @@ -952,21 +1260,35 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev, case CMD_RX_STD_MESSAGE: case CMD_RX_EXT_MESSAGE: - case CMD_LOG_MESSAGE: + kvaser_usb_rx_can_msg(dev, msg); + break; + + case CMD_LEAF_LOG_MESSAGE: + if (dev->family != KVASER_LEAF) + goto warn; kvaser_usb_rx_can_msg(dev, msg); break; case CMD_CHIP_STATE_EVENT: case CMD_CAN_ERROR_EVENT: - kvaser_usb_rx_error(dev, msg); + if (dev->family == KVASER_LEAF) + kvaser_leaf_rx_error(dev, msg); + else + kvaser_usbcan_rx_error(dev, msg); break; case CMD_TX_ACKNOWLEDGE: kvaser_usb_tx_acknowledge(dev, msg); break; + /* Ignored messages */ + case CMD_USBCAN_CLOCK_OVERFLOW_EVENT: + if (dev->family != KVASER_USBCAN) + goto warn; + break; + default: - dev_warn(dev->udev->dev.parent, +warn: dev_warn(dev->udev->dev.parent, "Unhandled message (%d)\n", msg->id); break; } @@ -1186,7 +1508,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) dev->rxbuf[i], dev->rxbuf_dma[i]); - for (i = 0; i < MAX_NET_DEVICES; i++) { + for (i = 0; i < dev->nchannels; i++) { struct kvaser_usb_net_priv *priv = dev->nets[i]; if (priv) @@ -1294,6 +1616,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, struct kvaser_msg *msg; int i, err; int ret = NETDEV_TX_OK; + u8 *msg_tx_can_flags = NULL; /* GCC */ if (can_dropped_invalid_skb(netdev, skb)) return NETDEV_TX_OK; @@ -1315,9 +1638,19 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, msg = buf; msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can); - msg->u.tx_can.flags = 0; msg->u.tx_can.channel = priv->channel; + switch (dev->family) { + case KVASER_LEAF: + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; + break; + case KVASER_USBCAN: + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; + break; + } + + *msg_tx_can_flags = 0; + if (cf->can_id & CAN_EFF_FLAG) { msg->id = CMD_TX_EXT_MESSAGE; msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f; @@ -1335,7 +1668,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc); if (cf->can_id & CAN_RTR_FLAG) - msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME; + *msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME; for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) { if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { @@ -1604,6 +1937,17 @@ static int kvaser_usb_probe(struct usb_interface *intf, if (!dev) return -ENOMEM; + if (kvaser_is_leaf(id)) { + dev->family = KVASER_LEAF; + } else if (kvaser_is_usbcan(id)) { + dev->family = KVASER_USBCAN; + } else { + dev_err(&intf->dev, + "Product ID (%d) does not belong to any known Kvaser USB family", + id->idProduct); + return -ENODEV; + } + err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out); if (err) { dev_err(&intf->dev, "Cannot get usb endpoint(s)"); -- cgit v1.2.1 From 0adfd7335b622ca3cac94810487db470f57892fc Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 27 Jan 2015 16:58:17 +0100 Subject: can: peak_usb: use ARRAY_SIZE instead of NULL termination for peak_usb_adapters_list This patch converts the list "static struct peak_usb_adapter *peak_usb_adapters_list[]" to be used with ARRAY_SIZE not with a NULL termination, as the size is known during compile time. Acked-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index c62f48a1161d..26c0cc3ce3b2 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -46,7 +46,6 @@ MODULE_DEVICE_TABLE(usb, peak_usb_table); static struct peak_usb_adapter *peak_usb_adapters_list[] = { &pcan_usb, &pcan_usb_pro, - NULL, }; /* @@ -857,17 +856,18 @@ static int peak_usb_probe(struct usb_interface *intf, { struct usb_device *usb_dev = interface_to_usbdev(intf); const u16 usb_id_product = le16_to_cpu(usb_dev->descriptor.idProduct); - struct peak_usb_adapter *peak_usb_adapter, **pp; + struct peak_usb_adapter *peak_usb_adapter = NULL; int i, err = -ENOMEM; usb_dev = interface_to_usbdev(intf); /* get corresponding PCAN-USB adapter */ - for (pp = peak_usb_adapters_list; *pp; pp++) - if ((*pp)->device_id == usb_id_product) + for (i = 0; i < ARRAY_SIZE(peak_usb_adapters_list); i++) + if (peak_usb_adapters_list[i]->device_id == usb_id_product) { + peak_usb_adapter = peak_usb_adapters_list[i]; break; + } - peak_usb_adapter = *pp; if (!peak_usb_adapter) { /* should never come except device_id bad usage in this file */ pr_err("%s: didn't find device id. 0x%x in devices list\n", -- cgit v1.2.1 From d6b5f30d9886a4f1e00c9bf355af2a95cabafa09 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 27 Jan 2015 17:15:39 +0100 Subject: can: peak_usb: constify struct peak_usb_adapter A "struct peak_usb_adapter" describes a certain USB adapter, as this doesn't change during runtime, this patch marks all USB adapter definitions as const. Acked-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb.c | 2 +- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 8 ++++---- drivers/net/can/usb/peak_usb/pcan_usb_core.h | 10 +++++----- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 2a1c9ce53fae..d57d3f64a5bf 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -855,7 +855,7 @@ static int pcan_usb_probe(struct usb_interface *intf) /* * describe the PCAN-USB adapter */ -struct peak_usb_adapter pcan_usb = { +const struct peak_usb_adapter pcan_usb = { .name = "PCAN-USB", .device_id = PCAN_USB_PRODUCT_ID, .ctrl_count = 1, diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 26c0cc3ce3b2..729b80d78322 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -43,7 +43,7 @@ static struct usb_device_id peak_usb_table[] = { MODULE_DEVICE_TABLE(usb, peak_usb_table); /* List of supported PCAN-USB adapters (NULL terminated list) */ -static struct peak_usb_adapter *peak_usb_adapters_list[] = { +static const struct peak_usb_adapter *const peak_usb_adapters_list[] = { &pcan_usb, &pcan_usb_pro, }; @@ -64,7 +64,7 @@ void pcan_dump_mem(char *prompt, void *p, int l) * initialize a time_ref object with usb adapter own settings */ void peak_usb_init_time_ref(struct peak_time_ref *time_ref, - struct peak_usb_adapter *adapter) + const struct peak_usb_adapter *adapter) { if (time_ref) { memset(time_ref, 0, sizeof(struct peak_time_ref)); @@ -708,7 +708,7 @@ static const struct net_device_ops peak_usb_netdev_ops = { * create one device which is attached to CAN controller #ctrl_idx of the * usb adapter. */ -static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, +static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, struct usb_interface *intf, int ctrl_idx) { struct usb_device *usb_dev = interface_to_usbdev(intf); @@ -856,7 +856,7 @@ static int peak_usb_probe(struct usb_interface *intf, { struct usb_device *usb_dev = interface_to_usbdev(intf); const u16 usb_id_product = le16_to_cpu(usb_dev->descriptor.idProduct); - struct peak_usb_adapter *peak_usb_adapter = NULL; + const struct peak_usb_adapter *peak_usb_adapter = NULL; int i, err = -ENOMEM; usb_dev = interface_to_usbdev(intf); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 073b47ff8eee..10f2fcac7c13 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -78,15 +78,15 @@ struct peak_usb_adapter { int sizeof_dev_private; }; -extern struct peak_usb_adapter pcan_usb; -extern struct peak_usb_adapter pcan_usb_pro; +extern const struct peak_usb_adapter pcan_usb; +extern const struct peak_usb_adapter pcan_usb_pro; struct peak_time_ref { struct timeval tv_host_0, tv_host; u32 ts_dev_1, ts_dev_2; u64 ts_total; u32 tick_count; - struct peak_usb_adapter *adapter; + const struct peak_usb_adapter *adapter; }; struct peak_tx_urb_context { @@ -102,7 +102,7 @@ struct peak_tx_urb_context { /* PEAK-System USB device */ struct peak_usb_device { struct can_priv can; - struct peak_usb_adapter *adapter; + const struct peak_usb_adapter *adapter; unsigned int ctrl_idx; u32 state; @@ -134,7 +134,7 @@ void pcan_dump_mem(char *prompt, void *p, int l); /* common timestamp management */ void peak_usb_init_time_ref(struct peak_time_ref *time_ref, - struct peak_usb_adapter *adapter); + const struct peak_usb_adapter *adapter); void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now); void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now); void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts, diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 145fa87c31b9..56855b2b1fa1 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -1012,7 +1012,7 @@ static int pcan_usb_pro_probe(struct usb_interface *intf) /* * describe the PCAN-USB Pro adapter */ -struct peak_usb_adapter pcan_usb_pro = { +const struct peak_usb_adapter pcan_usb_pro = { .name = "PCAN-USB Pro", .device_id = PCAN_USBPRO_PRODUCT_ID, .ctrl_count = PCAN_USBPRO_CHANNEL_COUNT, -- cgit v1.2.1 From e3c5ea60b474f9ba7e99542325416ca6d833cba9 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 23 Jan 2015 11:31:19 +0100 Subject: can: peak_usb: export ctrlmode_supported to adapter specific definition Export the ctrlmode_supported value from the core file to each adapter specific file. This has been mandatory for supporting the new CANFD extension. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb.c | 1 + drivers/net/can/usb/peak_usb/pcan_usb_core.c | 3 +-- drivers/net/can/usb/peak_usb/pcan_usb_core.h | 1 + drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index d57d3f64a5bf..72427f21edff 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -859,6 +859,7 @@ const struct peak_usb_adapter pcan_usb = { .name = "PCAN-USB", .device_id = PCAN_USB_PRODUCT_ID, .ctrl_count = 1, + .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, .clock = { .freq = PCAN_USB_CRYSTAL_HZ / 2 , }, diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 729b80d78322..2768399a52fa 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -750,8 +750,7 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, dev->can.bittiming_const = &peak_usb_adapter->bittiming_const; dev->can.do_set_bittiming = peak_usb_set_bittiming; dev->can.do_set_mode = peak_usb_set_mode; - dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | - CAN_CTRLMODE_LISTENONLY; + dev->can.ctrlmode_supported = peak_usb_adapter->ctrlmode_supported; netdev->netdev_ops = &peak_usb_netdev_ops; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 10f2fcac7c13..54fdb5978a05 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -44,6 +44,7 @@ struct peak_usb_device; struct peak_usb_adapter { char *name; u32 device_id; + u32 ctrlmode_supported; struct can_clock clock; const struct can_bittiming_const bittiming_const; unsigned int ctrl_count; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 56855b2b1fa1..03f517160a67 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -1016,6 +1016,7 @@ const struct peak_usb_adapter pcan_usb_pro = { .name = "PCAN-USB Pro", .device_id = PCAN_USBPRO_PRODUCT_ID, .ctrl_count = PCAN_USBPRO_CHANNEL_COUNT, + .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, .clock = { .freq = PCAN_USBPRO_CRYSTAL_HZ, }, -- cgit v1.2.1 From e3629f5657e653c413b2970a91e5f9ea123b36dc Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 23 Jan 2015 11:31:20 +0100 Subject: can: peak_usb: add adapter BEC callback definition Add the definition of a new callback that enable any PEAK-System CAN USB adapter to grant read access to its Bus Error Counters value. This ability is not supported by all the PEAK-System adapters, thus, for those, the callback pointer will be initiaized to NULL, which is correct regarding the linux-can device driver specs. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 1 + drivers/net/can/usb/peak_usb/pcan_usb_core.h | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 2768399a52fa..38634323ec51 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -750,6 +750,7 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, dev->can.bittiming_const = &peak_usb_adapter->bittiming_const; dev->can.do_set_bittiming = peak_usb_set_bittiming; dev->can.do_set_mode = peak_usb_set_mode; + dev->can.do_get_berr_counter = peak_usb_adapter->do_get_berr_counter; dev->can.ctrlmode_supported = peak_usb_adapter->ctrlmode_supported; netdev->netdev_ops = &peak_usb_netdev_ops; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 54fdb5978a05..739a344427a2 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -67,6 +67,8 @@ struct peak_usb_adapter { int (*dev_stop)(struct peak_usb_device *dev); int (*dev_restart_async)(struct peak_usb_device *dev, struct urb *urb, u8 *buf); + int (*do_get_berr_counter)(const struct net_device *netdev, + struct can_berr_counter *bec); u8 ep_msg_in; u8 ep_msg_out[PCAN_USB_MAX_CHANNEL]; u8 ts_used_bits; -- cgit v1.2.1 From b9f2cc1be77ef2bcf1470b69bfb015447cd3fa9a Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 23 Jan 2015 11:31:21 +0100 Subject: can: peak_usb: upgrade core to data bittiming specs Upgrade PEAK-System USB adapters core to the new data structures (names) and callbacks added for the support of the CANFD extension. This specific patch does the mandatory changes to support new data bittiming specs. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 36 ++++++++++++++++++++++++---- drivers/net/can/usb/peak_usb/pcan_usb_core.h | 3 +++ 2 files changed, 34 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 38634323ec51..10553ffc453f 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -678,19 +678,43 @@ static int peak_usb_set_mode(struct net_device *netdev, enum can_mode mode) } /* - * candev callback used to set device bitrate. + * candev callback used to set device nominal/arbitration bitrate. */ static int peak_usb_set_bittiming(struct net_device *netdev) { struct peak_usb_device *dev = netdev_priv(netdev); - struct can_bittiming *bt = &dev->can.bittiming; + const struct peak_usb_adapter *pa = dev->adapter; - if (dev->adapter->dev_set_bittiming) { - int err = dev->adapter->dev_set_bittiming(dev, bt); + if (pa->dev_set_bittiming) { + struct can_bittiming *bt = &dev->can.bittiming; + int err = pa->dev_set_bittiming(dev, bt); if (err) netdev_info(netdev, "couldn't set bitrate (err %d)\n", - err); + err); + return err; + } + + return 0; +} + +/* + * candev callback used to set device data bitrate. + */ +static int peak_usb_set_data_bittiming(struct net_device *netdev) +{ + struct peak_usb_device *dev = netdev_priv(netdev); + const struct peak_usb_adapter *pa = dev->adapter; + + if (pa->dev_set_data_bittiming) { + struct can_bittiming *bt = &dev->can.data_bittiming; + int err = pa->dev_set_data_bittiming(dev, bt); + + if (err) + netdev_info(netdev, + "couldn't set data bitrate (err %d)\n", + err); + return err; } @@ -749,6 +773,8 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, dev->can.clock = peak_usb_adapter->clock; dev->can.bittiming_const = &peak_usb_adapter->bittiming_const; dev->can.do_set_bittiming = peak_usb_set_bittiming; + dev->can.data_bittiming_const = &peak_usb_adapter->data_bittiming_const; + dev->can.do_set_data_bittiming = peak_usb_set_data_bittiming; dev->can.do_set_mode = peak_usb_set_mode; dev->can.do_get_berr_counter = peak_usb_adapter->do_get_berr_counter; dev->can.ctrlmode_supported = peak_usb_adapter->ctrlmode_supported; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 739a344427a2..c0e8dfaef526 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -47,6 +47,7 @@ struct peak_usb_adapter { u32 ctrlmode_supported; struct can_clock clock; const struct can_bittiming_const bittiming_const; + const struct can_bittiming_const data_bittiming_const; unsigned int ctrl_count; int (*intf_probe)(struct usb_interface *intf); @@ -58,6 +59,8 @@ struct peak_usb_adapter { int (*dev_close)(struct peak_usb_device *dev); int (*dev_set_bittiming)(struct peak_usb_device *dev, struct can_bittiming *bt); + int (*dev_set_data_bittiming)(struct peak_usb_device *dev, + struct can_bittiming *bt); int (*dev_set_bus)(struct peak_usb_device *dev, u8 onoff); int (*dev_get_device_id)(struct peak_usb_device *dev, u32 *device_id); int (*dev_decode_buf)(struct peak_usb_device *dev, struct urb *urb); -- cgit v1.2.1 From 2b0861e8cb51a6ace26da466d04eb5d535263cd4 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 23 Jan 2015 11:31:22 +0100 Subject: can: peak_usb: upgrade core to new struct canfd_frame Upgrade PEAK-System USB adapters core to the new data structures (names) and callbacks added for the support of the CANFD extension. This specific patch includes changes that deal with the new struct canfd_frame. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 8 +++++--- drivers/net/can/usb/peak_usb/pcan_usb_core.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 10553ffc453f..ae8c448fd4d0 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -252,7 +252,7 @@ static void peak_usb_write_bulk_callback(struct urb *urb) case 0: /* transmission complete */ netdev->stats.tx_packets++; - netdev->stats.tx_bytes += context->dlc; + netdev->stats.tx_bytes += context->data_len; /* prevent tx timeout */ netdev->trans_start = jiffies; @@ -288,7 +288,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb, struct peak_usb_device *dev = netdev_priv(netdev); struct peak_tx_urb_context *context = NULL; struct net_device_stats *stats = &netdev->stats; - struct can_frame *cf = (struct can_frame *)skb->data; + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; struct urb *urb; u8 *obuf; int i, err; @@ -321,7 +321,9 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb, } context->echo_index = i; - context->dlc = cf->can_dlc; + + /* Note: this works with CANFD frames too */ + context->data_len = cfd->len; usb_anchor_urb(urb, &dev->tx_submitted); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index c0e8dfaef526..e8038b30bab5 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -98,7 +98,7 @@ struct peak_time_ref { struct peak_tx_urb_context { struct peak_usb_device *dev; u32 echo_index; - u8 dlc; + u8 data_len; struct urb *urb; }; -- cgit v1.2.1 From 1114be1e5ca43d465e2da95a2118672f7d4110fb Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 23 Jan 2015 11:31:23 +0100 Subject: can: peak_usb: export pcan_usb_pro functions Add support for the following new PEAK-System technik CANFD USB adapters: PCAN-USB FD single CANFD channel USB adapter PCAN-USB Pro FD dual CANFD channels USB adapter The communication protocol has been developed using some mechanisms that did exist in the PCAN-USB Pro, thus, this patch also changes some previously static functions and data into global ones. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 16 ++++------------ drivers/net/can/usb/peak_usb/pcan_usb_pro.h | 13 +++++++++++++ 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 03f517160a67..dec51717635e 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -27,14 +27,6 @@ MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro adapter"); -/* PCAN-USB Pro Endpoints */ -#define PCAN_USBPRO_EP_CMDOUT 1 -#define PCAN_USBPRO_EP_CMDIN (PCAN_USBPRO_EP_CMDOUT | USB_DIR_IN) -#define PCAN_USBPRO_EP_MSGOUT_0 2 -#define PCAN_USBPRO_EP_MSGIN (PCAN_USBPRO_EP_MSGOUT_0 | USB_DIR_IN) -#define PCAN_USBPRO_EP_MSGOUT_1 3 -#define PCAN_USBPRO_EP_UNUSED (PCAN_USBPRO_EP_MSGOUT_1 | USB_DIR_IN) - #define PCAN_USBPRO_CHANNEL_COUNT 2 /* PCAN-USB Pro adapter internal clock (MHz) */ @@ -322,8 +314,8 @@ static int pcan_usb_pro_wait_rsp(struct peak_usb_device *dev, return (i >= PCAN_USBPRO_RSP_SUBMIT_MAX) ? -ERANGE : err; } -static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, - int req_value, void *req_addr, int req_size) +int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, + int req_value, void *req_addr, int req_size) { int err; u8 req_type; @@ -475,7 +467,7 @@ static int pcan_usb_pro_set_bittiming(struct peak_usb_device *dev, return pcan_usb_pro_set_bitrate(dev, ccbt); } -static void pcan_usb_pro_restart_complete(struct urb *urb) +void pcan_usb_pro_restart_complete(struct urb *urb) { /* can delete usb resources */ peak_usb_async_complete(urb); @@ -978,7 +970,7 @@ static void pcan_usb_pro_free(struct peak_usb_device *dev) /* * probe function for new PCAN-USB Pro usb interface */ -static int pcan_usb_pro_probe(struct usb_interface *intf) +int pcan_usb_pro_probe(struct usb_interface *intf) { struct usb_host_interface *if_desc; int i; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h index 837cee267132..a62f7ab8980f 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h @@ -27,6 +27,14 @@ #define PCAN_USBPRO_INFO_BL 0 #define PCAN_USBPRO_INFO_FW 1 +/* PCAN-USB Pro (FD) Endpoints */ +#define PCAN_USBPRO_EP_CMDOUT 1 +#define PCAN_USBPRO_EP_CMDIN (PCAN_USBPRO_EP_CMDOUT | USB_DIR_IN) +#define PCAN_USBPRO_EP_MSGOUT_0 2 +#define PCAN_USBPRO_EP_MSGIN (PCAN_USBPRO_EP_MSGOUT_0 | USB_DIR_IN) +#define PCAN_USBPRO_EP_MSGOUT_1 3 +#define PCAN_USBPRO_EP_UNUSED (PCAN_USBPRO_EP_MSGOUT_1 | USB_DIR_IN) + /* Vendor Request value for XXX_FCT */ #define PCAN_USBPRO_FCT_DRVLD 5 /* tell device driver is loaded */ #define PCAN_USBPRO_FCT_DRVLD_REQ_LEN 16 @@ -176,4 +184,9 @@ union pcan_usb_pro_rec { struct pcan_usb_pro_txmsg tx_msg; }; +int pcan_usb_pro_probe(struct usb_interface *intf); +int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, + int req_value, void *req_addr, int req_size); +void pcan_usb_pro_restart_complete(struct urb *urb); + #endif -- cgit v1.2.1 From faa233d902bb97ac034fa2580e6e0934ccf98cf3 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 23 Jan 2015 11:31:24 +0100 Subject: can: peak_usb: add peak_usb_netif_rx() new function Add a common function that pushes the skb in the network queue with adding timestamps information, converted from time values read from the PEAK USB adapters. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 15 +++++++++++++++ drivers/net/can/usb/peak_usb/pcan_usb_core.h | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index ae8c448fd4d0..7587337a3b42 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -163,6 +163,21 @@ void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts, } } +/* + * post received skb after having set any hw timestamp + */ +int peak_usb_netif_rx(struct sk_buff *skb, + struct peak_time_ref *time_ref, u32 ts_low, u32 ts_high) +{ + struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb); + struct timeval tv; + + peak_usb_get_ts_tv(time_ref, ts_low, &tv); + hwts->hwtstamp = timeval_to_ktime(tv); + + return netif_rx(skb); +} + /* * callback for bulk Rx urb */ diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index e8038b30bab5..0e76b84fb786 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -145,7 +145,9 @@ void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now); void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now); void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts, struct timeval *tv); - +int peak_usb_netif_rx(struct sk_buff *skb, + struct peak_time_ref *time_ref, u32 ts_low, u32 ts_high); void peak_usb_async_complete(struct urb *urb); void peak_usb_restart_complete(struct peak_usb_device *dev); + #endif -- cgit v1.2.1 From 0a25e1f4f18566b750ebd3ae995af64e23111e63 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 23 Jan 2015 11:31:25 +0100 Subject: can: peak_usb: add support for PEAK new CANFD USB adapters Add support for the following new PEAK-System technik CANFD USB adapters: PCAN-USB FD single CANFD channel USB adapter PCAN-USB Pro FD dual CANFD channels USB adapter Signed-off-by: Stephane Grosjean Signed-off-by: Oliver Hartkopp Acked-by: Andri Yngvason Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/Kconfig | 14 +- drivers/net/can/usb/peak_usb/Makefile | 2 +- drivers/net/can/usb/peak_usb/pcan_ucan.h | 222 ++++++ drivers/net/can/usb/peak_usb/pcan_usb_core.c | 4 + drivers/net/can/usb/peak_usb/pcan_usb_core.h | 4 + drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 1095 ++++++++++++++++++++++++++ 6 files changed, 1337 insertions(+), 4 deletions(-) create mode 100644 drivers/net/can/usb/peak_usb/pcan_ucan.h create mode 100644 drivers/net/can/usb/peak_usb/pcan_usb_fd.c (limited to 'drivers/net') diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index f6f55004fe2b..bcb272f6c68a 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -59,10 +59,18 @@ config CAN_KVASER_USB module will be called kvaser_usb. config CAN_PEAK_USB - tristate "PEAK PCAN-USB/USB Pro interfaces" + tristate "PEAK PCAN-USB/USB Pro interfaces for CAN 2.0b/CAN-FD" ---help--- - This driver supports the PCAN-USB and PCAN-USB Pro adapters - from PEAK-System Technik (http://www.peak-system.com). + This driver supports the PEAK-System Technik USB adapters that enable + access to the CAN bus, with repect to the CAN 2.0b and/or CAN-FD + standards, that is: + + PCAN-USB single CAN 2.0b channel USB adapter + PCAN-USB Pro dual CAN 2.0b channels USB adapter + PCAN-USB FD single CAN-FD channel USB adapter + PCAN-USB Pro FD dual CAN-FD channels USB adapter + + (see also http://www.peak-system.com). config CAN_8DEV_USB tristate "8 devices USB2CAN interface" diff --git a/drivers/net/can/usb/peak_usb/Makefile b/drivers/net/can/usb/peak_usb/Makefile index 1aefbc88d643..1839e9ca62e7 100644 --- a/drivers/net/can/usb/peak_usb/Makefile +++ b/drivers/net/can/usb/peak_usb/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_CAN_PEAK_USB) += peak_usb.o -peak_usb-y = pcan_usb_core.o pcan_usb.o pcan_usb_pro.o +peak_usb-y = pcan_usb_core.o pcan_usb.o pcan_usb_pro.o pcan_usb_fd.o diff --git a/drivers/net/can/usb/peak_usb/pcan_ucan.h b/drivers/net/can/usb/peak_usb/pcan_ucan.h new file mode 100644 index 000000000000..1ba7c25002e1 --- /dev/null +++ b/drivers/net/can/usb/peak_usb/pcan_ucan.h @@ -0,0 +1,222 @@ +/* + * CAN driver for PEAK System micro-CAN based adapters + * + * Copyright (C) 2003-2011 PEAK System-Technik GmbH + * Copyright (C) 2011-2013 Stephane Grosjean + * + * 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; version 2 of the License. + * + * 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. + */ +#ifndef PUCAN_H +#define PUCAN_H + +/* uCAN commands opcodes list (low-order 10 bits) */ +#define PUCAN_CMD_NOP 0x000 +#define PUCAN_CMD_RESET_MODE 0x001 +#define PUCAN_CMD_NORMAL_MODE 0x002 +#define PUCAN_CMD_LISTEN_ONLY_MODE 0x003 +#define PUCAN_CMD_TIMING_SLOW 0x004 +#define PUCAN_CMD_TIMING_FAST 0x005 +#define PUCAN_CMD_FILTER_STD 0x008 +#define PUCAN_CMD_TX_ABORT 0x009 +#define PUCAN_CMD_WR_ERR_CNT 0x00a +#define PUCAN_CMD_RX_FRAME_ENABLE 0x00b +#define PUCAN_CMD_RX_FRAME_DISABLE 0x00c +#define PUCAN_CMD_END_OF_COLLECTION 0x3ff + +/* uCAN received messages list */ +#define PUCAN_MSG_CAN_RX 0x0001 +#define PUCAN_MSG_ERROR 0x0002 +#define PUCAN_MSG_STATUS 0x0003 +#define PUCAN_MSG_BUSLOAD 0x0004 +#define PUCAN_MSG_CAN_TX 0x1000 + +/* uCAN command common header */ +struct __packed pucan_command { + __le16 opcode_channel; + u16 args[3]; +}; + +/* uCAN TIMING_SLOW command fields */ +#define PUCAN_TSLOW_SJW_T(s, t) (((s) & 0xf) | ((!!(t)) << 7)) +#define PUCAN_TSLOW_TSEG2(t) ((t) & 0xf) +#define PUCAN_TSLOW_TSEG1(t) ((t) & 0x3f) +#define PUCAN_TSLOW_BRP(b) ((b) & 0x3ff) + +struct __packed pucan_timing_slow { + __le16 opcode_channel; + + u8 ewl; /* Error Warning limit */ + u8 sjw_t; /* Sync Jump Width + Triple sampling */ + u8 tseg2; /* Timing SEGment 2 */ + u8 tseg1; /* Timing SEGment 1 */ + + __le16 brp; /* BaudRate Prescaler */ +}; + +/* uCAN TIMING_FAST command fields */ +#define PUCAN_TFAST_SJW(s) ((s) & 0x3) +#define PUCAN_TFAST_TSEG2(t) ((t) & 0x7) +#define PUCAN_TFAST_TSEG1(t) ((t) & 0xf) +#define PUCAN_TFAST_BRP(b) ((b) & 0x3ff) + +struct __packed pucan_timing_fast { + __le16 opcode_channel; + + u8 unused; + u8 sjw; /* Sync Jump Width */ + u8 tseg2; /* Timing SEGment 2 */ + u8 tseg1; /* Timing SEGment 1 */ + + __le16 brp; /* BaudRate Prescaler */ +}; + +/* uCAN FILTER_STD command fields */ +#define PUCAN_FLTSTD_ROW_IDX_BITS 6 + +struct __packed pucan_filter_std { + __le16 opcode_channel; + + __le16 idx; + __le32 mask; /* CAN-ID bitmask in idx range */ +}; + +/* uCAN WR_ERR_CNT command fields */ +#define PUCAN_WRERRCNT_TE 0x4000 /* Tx error cntr write Enable */ +#define PUCAN_WRERRCNT_RE 0x8000 /* Rx error cntr write Enable */ + +struct __packed pucan_wr_err_cnt { + __le16 opcode_channel; + + __le16 sel_mask; + u8 tx_counter; /* Tx error counter new value */ + u8 rx_counter; /* Rx error counter new value */ + + u16 unused; +}; + +/* uCAN RX_FRAME_ENABLE command fields */ +#define PUCAN_FLTEXT_ERROR 0x0001 +#define PUCAN_FLTEXT_BUSLOAD 0x0002 + +struct __packed pucan_filter_ext { + __le16 opcode_channel; + + __le16 ext_mask; + u32 unused; +}; + +/* uCAN received messages global format */ +struct __packed pucan_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; +}; + +/* uCAN flags for CAN/CANFD messages */ +#define PUCAN_MSG_SELF_RECEIVE 0x80 +#define PUCAN_MSG_ERROR_STATE_IND 0x40 /* error state indicator */ +#define PUCAN_MSG_BITRATE_SWITCH 0x20 /* bitrate switch */ +#define PUCAN_MSG_EXT_DATA_LEN 0x10 /* extended data length */ +#define PUCAN_MSG_SINGLE_SHOT 0x08 +#define PUCAN_MSG_LOOPED_BACK 0x04 +#define PUCAN_MSG_EXT_ID 0x02 +#define PUCAN_MSG_RTR 0x01 + +struct __packed pucan_rx_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; + __le32 tag_low; + __le32 tag_high; + u8 channel_dlc; + u8 client; + __le16 flags; + __le32 can_id; + u8 d[0]; +}; + +/* uCAN error types */ +#define PUCAN_ERMSG_BIT_ERROR 0 +#define PUCAN_ERMSG_FORM_ERROR 1 +#define PUCAN_ERMSG_STUFF_ERROR 2 +#define PUCAN_ERMSG_OTHER_ERROR 3 +#define PUCAN_ERMSG_ERR_CNT_DEC 4 + +struct __packed pucan_error_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; + u8 channel_type_d; + u8 code_g; + u8 tx_err_cnt; + u8 rx_err_cnt; +}; + +#define PUCAN_BUS_PASSIVE 0x20 +#define PUCAN_BUS_WARNING 0x40 +#define PUCAN_BUS_BUSOFF 0x80 + +struct __packed pucan_status_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; + u8 channel_p_w_b; + u8 unused[3]; +}; + +/* uCAN transmitted message format */ +#define PUCAN_MSG_CHANNEL_DLC(c, d) (((c) & 0xf) | ((d) << 4)) + +struct __packed pucan_tx_msg { + __le16 size; + __le16 type; + __le32 tag_low; + __le32 tag_high; + u8 channel_dlc; + u8 client; + __le16 flags; + __le32 can_id; + u8 d[0]; +}; + +/* build the cmd opcode_channel field with respect to the correct endianness */ +static inline __le16 pucan_cmd_opcode_channel(struct peak_usb_device *dev, + int opcode) +{ + return cpu_to_le16(((dev->ctrl_idx) << 12) | ((opcode) & 0x3ff)); +} + +/* return the channel number part from any received message channel_dlc field */ +static inline int pucan_msg_get_channel(struct pucan_rx_msg *rm) +{ + return rm->channel_dlc & 0xf; +} + +/* return the dlc value from any received message channel_dlc field */ +static inline int pucan_msg_get_dlc(struct pucan_rx_msg *rm) +{ + return rm->channel_dlc >> 4; +} + +static inline int pucan_ermsg_get_channel(struct pucan_error_msg *em) +{ + return em->channel_type_d & 0x0f; +} + +static inline int pucan_stmsg_get_channel(struct pucan_status_msg *sm) +{ + return sm->channel_p_w_b & 0x0f; +} + +#endif diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 7587337a3b42..7921cff93a63 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -37,6 +37,8 @@ MODULE_LICENSE("GPL v2"); static struct usb_device_id peak_usb_table[] = { {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID)}, {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID)}, + {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBFD_PRODUCT_ID)}, + {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPROFD_PRODUCT_ID)}, {} /* Terminating entry */ }; @@ -46,6 +48,8 @@ MODULE_DEVICE_TABLE(usb, peak_usb_table); static const struct peak_usb_adapter *const peak_usb_adapters_list[] = { &pcan_usb, &pcan_usb_pro, + &pcan_usb_fd, + &pcan_usb_pro_fd, }; /* diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 0e76b84fb786..9e624f05ad4d 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -25,6 +25,8 @@ /* supported device ids. */ #define PCAN_USB_PRODUCT_ID 0x000c #define PCAN_USBPRO_PRODUCT_ID 0x000d +#define PCAN_USBPROFD_PRODUCT_ID 0x0011 +#define PCAN_USBFD_PRODUCT_ID 0x0012 #define PCAN_USB_DRIVER_NAME "peak_usb" @@ -86,6 +88,8 @@ struct peak_usb_adapter { extern const struct peak_usb_adapter pcan_usb; extern const struct peak_usb_adapter pcan_usb_pro; +extern const struct peak_usb_adapter pcan_usb_fd; +extern const struct peak_usb_adapter pcan_usb_pro_fd; struct peak_time_ref { struct timeval tv_host_0, tv_host; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c new file mode 100644 index 000000000000..962c3f027383 --- /dev/null +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -0,0 +1,1095 @@ +/* + * CAN driver for PEAK System PCAN-USB FD / PCAN-USB Pro FD adapter + * + * Copyright (C) 2013-2014 Stephane Grosjean + * + * 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; version 2 of the License. + * + * 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. + */ +#include +#include +#include + +#include +#include +#include + +#include "pcan_usb_core.h" +#include "pcan_usb_pro.h" +#include "pcan_ucan.h" + +MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB FD adapter"); +MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro FD adapter"); + +#define PCAN_USBPROFD_CHANNEL_COUNT 2 +#define PCAN_USBFD_CHANNEL_COUNT 1 + +/* PCAN-USB Pro FD adapter internal clock (Hz) */ +#define PCAN_UFD_CRYSTAL_HZ 80000000 + +#define PCAN_UFD_CMD_BUFFER_SIZE 512 +#define PCAN_UFD_LOSPD_PKT_SIZE 64 + +/* PCAN-USB Pro FD command timeout (ms.) */ +#define PCAN_UFD_CMD_TIMEOUT_MS 1000 + +/* PCAN-USB Pro FD rx/tx buffers size */ +#define PCAN_UFD_RX_BUFFER_SIZE 2048 +#define PCAN_UFD_TX_BUFFER_SIZE 512 + +/* read some versions info from the hw devcie */ +struct __packed pcan_ufd_fw_info { + __le16 size_of; /* sizeof this */ + __le16 type; /* type of this structure */ + u8 hw_type; /* Type of hardware (HW_TYPE_xxx) */ + u8 bl_version[3]; /* Bootloader version */ + u8 hw_version; /* Hardware version (PCB) */ + u8 fw_version[3]; /* Firmware version */ + __le32 dev_id[2]; /* "device id" per CAN */ + __le32 ser_no; /* S/N */ + __le32 flags; /* special functions */ +}; + +/* handle device specific info used by the netdevices */ +struct pcan_usb_fd_if { + struct peak_usb_device *dev[PCAN_USB_MAX_CHANNEL]; + struct pcan_ufd_fw_info fw_info; + struct peak_time_ref time_ref; + int cm_ignore_count; + int dev_opened_count; +}; + +/* device information */ +struct pcan_usb_fd_device { + struct peak_usb_device dev; + struct can_berr_counter bec; + struct pcan_usb_fd_if *usb_if; + u8 *cmd_buffer_addr; +}; + +/* Extended USB commands (non uCAN commands) */ + +/* Clock Modes command */ +#define PCAN_UFD_CMD_CLK_SET 0x80 + +#define PCAN_UFD_CLK_80MHZ 0x0 +#define PCAN_UFD_CLK_60MHZ 0x1 +#define PCAN_UFD_CLK_40MHZ 0x2 +#define PCAN_UFD_CLK_30MHZ 0x3 +#define PCAN_UFD_CLK_24MHZ 0x4 +#define PCAN_UFD_CLK_20MHZ 0x5 +#define PCAN_UFD_CLK_DEF PCAN_UFD_CLK_80MHZ + +struct __packed pcan_ufd_clock { + __le16 opcode_channel; + + u8 mode; + u8 unused[5]; +}; + +/* LED control command */ +#define PCAN_UFD_CMD_LED_SET 0x86 + +#define PCAN_UFD_LED_DEV 0x00 +#define PCAN_UFD_LED_FAST 0x01 +#define PCAN_UFD_LED_SLOW 0x02 +#define PCAN_UFD_LED_ON 0x03 +#define PCAN_UFD_LED_OFF 0x04 +#define PCAN_UFD_LED_DEF PCAN_UFD_LED_DEV + +struct __packed pcan_ufd_led { + __le16 opcode_channel; + + u8 mode; + u8 unused[5]; +}; + +/* Extended usage of uCAN commands CMD_RX_FRAME_xxxABLE for PCAN-USB Pro FD */ +#define PCAN_UFD_FLTEXT_CALIBRATION 0x8000 + +struct __packed pcan_ufd_filter_ext { + __le16 opcode_channel; + + __le16 ext_mask; + u16 unused; + __le16 usb_mask; +}; + +/* Extended usage of uCAN messages for PCAN-USB Pro FD */ +#define PCAN_UFD_MSG_CALIBRATION 0x100 + +struct __packed pcan_ufd_ts_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; + __le16 usb_frame_index; + u16 unused; +}; + +#define PCAN_UFD_MSG_OVERRUN 0x101 + +#define PCAN_UFD_OVMSG_CHANNEL(o) ((o)->channel & 0xf) + +struct __packed pcan_ufd_ovr_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; + u8 channel; + u8 unused[3]; +}; + +static inline int pufd_omsg_get_channel(struct pcan_ufd_ovr_msg *om) +{ + return om->channel & 0xf; +} + +/* Clock mode frequency values */ +static const u32 pcan_usb_fd_clk_freq[6] = { + [PCAN_UFD_CLK_80MHZ] = 80000000, + [PCAN_UFD_CLK_60MHZ] = 60000000, + [PCAN_UFD_CLK_40MHZ] = 40000000, + [PCAN_UFD_CLK_30MHZ] = 30000000, + [PCAN_UFD_CLK_24MHZ] = 24000000, + [PCAN_UFD_CLK_20MHZ] = 20000000 +}; + +/* return a device USB interface */ +static inline +struct pcan_usb_fd_if *pcan_usb_fd_dev_if(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + return pdev->usb_if; +} + +/* return a device USB commands buffer */ +static inline void *pcan_usb_fd_cmd_buffer(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + return pdev->cmd_buffer_addr; +} + +/* send PCAN-USB Pro FD commands synchronously */ +static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail) +{ + void *cmd_head = pcan_usb_fd_cmd_buffer(dev); + int err; + u8 *packet_ptr; + int i, n = 1, packet_len; + ptrdiff_t cmd_len; + + /* usb device unregistered? */ + if (!(dev->state & PCAN_USB_STATE_CONNECTED)) + return 0; + + /* if a packet is not filled completely by commands, the command list + * is terminated with an "end of collection" record. + */ + cmd_len = cmd_tail - cmd_head; + if (cmd_len <= (PCAN_UFD_CMD_BUFFER_SIZE - sizeof(u64))) { + memset(cmd_tail, 0xff, sizeof(u64)); + cmd_len += sizeof(u64); + } + + packet_ptr = cmd_head; + + /* firmware is not able to re-assemble 512 bytes buffer in full-speed */ + if ((dev->udev->speed != USB_SPEED_HIGH) && + (cmd_len > PCAN_UFD_LOSPD_PKT_SIZE)) { + packet_len = PCAN_UFD_LOSPD_PKT_SIZE; + n += cmd_len / packet_len; + } else { + packet_len = cmd_len; + } + + for (i = 0; i < n; i++) { + err = usb_bulk_msg(dev->udev, + usb_sndbulkpipe(dev->udev, + PCAN_USBPRO_EP_CMDOUT), + packet_ptr, packet_len, + NULL, PCAN_UFD_CMD_TIMEOUT_MS); + if (err) { + netdev_err(dev->netdev, + "sending command failure: %d\n", err); + break; + } + + packet_ptr += packet_len; + } + + return err; +} + +/* build the commands list in the given buffer, to enter operational mode */ +static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf) +{ + struct pucan_wr_err_cnt *prc; + struct pucan_command *cmd; + u8 *pc = buf; + + /* 1st, reset error counters: */ + prc = (struct pucan_wr_err_cnt *)pc; + prc->opcode_channel = pucan_cmd_opcode_channel(dev, + PUCAN_CMD_WR_ERR_CNT); + + /* select both counters */ + prc->sel_mask = cpu_to_le16(PUCAN_WRERRCNT_TE|PUCAN_WRERRCNT_RE); + + /* and reset their values */ + prc->tx_counter = 0; + prc->rx_counter = 0; + + /* moves the pointer forward */ + pc += sizeof(struct pucan_wr_err_cnt); + + /* next, go back to operational mode */ + cmd = (struct pucan_command *)pc; + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + (dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) ? + PUCAN_CMD_LISTEN_ONLY_MODE : + PUCAN_CMD_NORMAL_MODE); + pc += sizeof(struct pucan_command); + + return pc - buf; +} + +/* set CAN bus on/off */ +static int pcan_usb_fd_set_bus(struct peak_usb_device *dev, u8 onoff) +{ + u8 *pc = pcan_usb_fd_cmd_buffer(dev); + int l; + + if (onoff) { + /* build the cmds list to enter operational mode */ + l = pcan_usb_fd_build_restart_cmd(dev, pc); + } else { + struct pucan_command *cmd = (struct pucan_command *)pc; + + /* build cmd to go back to reset mode */ + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PUCAN_CMD_RESET_MODE); + l = sizeof(struct pucan_command); + } + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, pc + l); +} + +/* set filtering masks: + * + * idx in range [0..63] selects a row #idx, all rows otherwise + * mask in range [0..0xffffffff] defines up to 32 CANIDs in the row(s) + * + * Each bit of this 64 x 32 bits array defines a CANID value: + * + * bit[i,j] = 1 implies that CANID=(i x 32)+j will be received, while + * bit[i,j] = 0 implies that CANID=(i x 32)+j will be discarded. + */ +static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx, + u32 mask) +{ + struct pucan_filter_std *cmd = pcan_usb_fd_cmd_buffer(dev); + int i, n; + + /* select all rows when idx is out of range [0..63] */ + if ((idx < 0) || (idx >= (1 << PUCAN_FLTSTD_ROW_IDX_BITS))) { + n = 1 << PUCAN_FLTSTD_ROW_IDX_BITS; + idx = 0; + + /* select the row (and only the row) otherwise */ + } else { + n = idx + 1; + } + + for (i = idx; i < n; i++, cmd++) { + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PUCAN_CMD_FILTER_STD); + cmd->idx = cpu_to_le16(i); + cmd->mask = cpu_to_le32(mask); + } + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, cmd); +} + +/* set/unset notifications filter: + * + * onoff sets(1)/unset(0) notifications + * mask each bit defines a kind of notification to set/unset + */ +static int pcan_usb_fd_set_filter_ext(struct peak_usb_device *dev, + bool onoff, u16 ext_mask, u16 usb_mask) +{ + struct pcan_ufd_filter_ext *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + (onoff) ? PUCAN_CMD_RX_FRAME_ENABLE : + PUCAN_CMD_RX_FRAME_DISABLE); + + cmd->ext_mask = cpu_to_le16(ext_mask); + cmd->usb_mask = cpu_to_le16(usb_mask); + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + +/* setup LED control */ +static int pcan_usb_fd_set_can_led(struct peak_usb_device *dev, u8 led_mode) +{ + struct pcan_ufd_led *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PCAN_UFD_CMD_LED_SET); + cmd->mode = led_mode; + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + +/* set CAN clock domain */ +static int pcan_usb_fd_set_clock_domain(struct peak_usb_device *dev, + u8 clk_mode) +{ + struct pcan_ufd_clock *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PCAN_UFD_CMD_CLK_SET); + cmd->mode = clk_mode; + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + +/* set bittiming for CAN and CAN-FD header */ +static int pcan_usb_fd_set_bittiming_slow(struct peak_usb_device *dev, + struct can_bittiming *bt) +{ + struct pucan_timing_slow *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PUCAN_CMD_TIMING_SLOW); + cmd->sjw_t = PUCAN_TSLOW_SJW_T(bt->sjw - 1, + dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES); + + cmd->tseg2 = PUCAN_TSLOW_TSEG2(bt->phase_seg2 - 1); + cmd->tseg1 = PUCAN_TSLOW_TSEG1(bt->prop_seg + bt->phase_seg1 - 1); + cmd->brp = cpu_to_le16(PUCAN_TSLOW_BRP(bt->brp - 1)); + + cmd->ewl = 96; /* default */ + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + +/* set CAN-FD bittiming for data */ +static int pcan_usb_fd_set_bittiming_fast(struct peak_usb_device *dev, + struct can_bittiming *bt) +{ + struct pucan_timing_fast *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PUCAN_CMD_TIMING_FAST); + cmd->sjw = PUCAN_TFAST_SJW(bt->sjw - 1); + cmd->tseg2 = PUCAN_TFAST_TSEG2(bt->phase_seg2 - 1); + cmd->tseg1 = PUCAN_TFAST_TSEG1(bt->prop_seg + bt->phase_seg1 - 1); + cmd->brp = cpu_to_le16(PUCAN_TFAST_BRP(bt->brp - 1)); + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + +/* handle restart but in asynchronously way + * (uses PCAN-USB Pro code to complete asynchronous request) + */ +static int pcan_usb_fd_restart_async(struct peak_usb_device *dev, + struct urb *urb, u8 *buf) +{ + u8 *pc = buf; + + /* build the entire cmds list in the provided buffer, to go back into + * operational mode. + */ + pc += pcan_usb_fd_build_restart_cmd(dev, pc); + + /* add EOC */ + memset(pc, 0xff, sizeof(struct pucan_command)); + pc += sizeof(struct pucan_command); + + /* complete the URB */ + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDOUT), + buf, pc - buf, + pcan_usb_pro_restart_complete, dev); + + /* and submit it. */ + return usb_submit_urb(urb, GFP_ATOMIC); +} + +static int pcan_usb_fd_drv_loaded(struct peak_usb_device *dev, bool loaded) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + pdev->cmd_buffer_addr[0] = 0; + pdev->cmd_buffer_addr[1] = !!loaded; + + return pcan_usb_pro_send_req(dev, + PCAN_USBPRO_REQ_FCT, + PCAN_USBPRO_FCT_DRVLD, + pdev->cmd_buffer_addr, + PCAN_USBPRO_FCT_DRVLD_REQ_LEN); +} + +static int pcan_usb_fd_decode_canmsg(struct pcan_usb_fd_if *usb_if, + struct pucan_msg *rx_msg) +{ + struct pucan_rx_msg *rm = (struct pucan_rx_msg *)rx_msg; + struct peak_usb_device *dev = usb_if->dev[pucan_msg_get_channel(rm)]; + struct net_device *netdev = dev->netdev; + struct canfd_frame *cfd; + struct sk_buff *skb; + const u16 rx_msg_flags = le16_to_cpu(rm->flags); + + if (rx_msg_flags & PUCAN_MSG_EXT_DATA_LEN) { + /* CANFD frame case */ + skb = alloc_canfd_skb(netdev, &cfd); + if (!skb) + return -ENOMEM; + + if (rx_msg_flags & PUCAN_MSG_BITRATE_SWITCH) + cfd->flags |= CANFD_BRS; + + if (rx_msg_flags & PUCAN_MSG_ERROR_STATE_IND) + cfd->flags |= CANFD_ESI; + + cfd->len = can_dlc2len(get_canfd_dlc(pucan_msg_get_dlc(rm))); + } else { + /* CAN 2.0 frame case */ + skb = alloc_can_skb(netdev, (struct can_frame **)&cfd); + if (!skb) + return -ENOMEM; + + cfd->len = get_can_dlc(pucan_msg_get_dlc(rm)); + } + + cfd->can_id = le32_to_cpu(rm->can_id); + + if (rx_msg_flags & PUCAN_MSG_EXT_ID) + cfd->can_id |= CAN_EFF_FLAG; + + if (rx_msg_flags & PUCAN_MSG_RTR) + cfd->can_id |= CAN_RTR_FLAG; + else + memcpy(cfd->data, rm->d, cfd->len); + + peak_usb_netif_rx(skb, &usb_if->time_ref, + le32_to_cpu(rm->ts_low), le32_to_cpu(rm->ts_high)); + + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += cfd->len; + + return 0; +} + +/* handle uCAN status message */ +static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if, + struct pucan_msg *rx_msg) +{ + struct pucan_status_msg *sm = (struct pucan_status_msg *)rx_msg; + struct peak_usb_device *dev = usb_if->dev[pucan_stmsg_get_channel(sm)]; + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + enum can_state new_state = CAN_STATE_ERROR_ACTIVE; + enum can_state rx_state, tx_state; + struct net_device *netdev = dev->netdev; + struct can_frame *cf; + struct sk_buff *skb; + + /* nothing should be sent while in BUS_OFF state */ + if (dev->can.state == CAN_STATE_BUS_OFF) + return 0; + + if (sm->channel_p_w_b & PUCAN_BUS_BUSOFF) { + new_state = CAN_STATE_BUS_OFF; + } else if (sm->channel_p_w_b & PUCAN_BUS_PASSIVE) { + new_state = CAN_STATE_ERROR_PASSIVE; + } else if (sm->channel_p_w_b & PUCAN_BUS_WARNING) { + new_state = CAN_STATE_ERROR_WARNING; + } else { + /* no error bit (so, no error skb, back to active state) */ + dev->can.state = CAN_STATE_ERROR_ACTIVE; + pdev->bec.txerr = 0; + pdev->bec.rxerr = 0; + return 0; + } + + /* state hasn't changed */ + if (new_state == dev->can.state) + return 0; + + /* handle bus state change */ + tx_state = (pdev->bec.txerr >= pdev->bec.rxerr) ? new_state : 0; + rx_state = (pdev->bec.txerr <= pdev->bec.rxerr) ? new_state : 0; + + /* allocate an skb to store the error frame */ + skb = alloc_can_err_skb(netdev, &cf); + if (skb) + can_change_state(netdev, cf, tx_state, rx_state); + + /* things must be done even in case of OOM */ + if (new_state == CAN_STATE_BUS_OFF) + can_bus_off(netdev); + + if (!skb) + return -ENOMEM; + + peak_usb_netif_rx(skb, &usb_if->time_ref, + le32_to_cpu(sm->ts_low), le32_to_cpu(sm->ts_high)); + + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += cf->can_dlc; + + return 0; +} + +/* handle uCAN error message */ +static int pcan_usb_fd_decode_error(struct pcan_usb_fd_if *usb_if, + struct pucan_msg *rx_msg) +{ + struct pucan_error_msg *er = (struct pucan_error_msg *)rx_msg; + struct peak_usb_device *dev = usb_if->dev[pucan_ermsg_get_channel(er)]; + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + /* keep a trace of tx and rx error counters for later use */ + pdev->bec.txerr = er->tx_err_cnt; + pdev->bec.rxerr = er->rx_err_cnt; + + return 0; +} + +/* handle uCAN overrun message */ +static int pcan_usb_fd_decode_overrun(struct pcan_usb_fd_if *usb_if, + struct pucan_msg *rx_msg) +{ + struct pcan_ufd_ovr_msg *ov = (struct pcan_ufd_ovr_msg *)rx_msg; + struct peak_usb_device *dev = usb_if->dev[pufd_omsg_get_channel(ov)]; + struct net_device *netdev = dev->netdev; + struct can_frame *cf; + struct sk_buff *skb; + + /* allocate an skb to store the error frame */ + skb = alloc_can_err_skb(netdev, &cf); + if (!skb) + return -ENOMEM; + + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; + + peak_usb_netif_rx(skb, &usb_if->time_ref, + le32_to_cpu(ov->ts_low), le32_to_cpu(ov->ts_high)); + + netdev->stats.rx_over_errors++; + netdev->stats.rx_errors++; + + return 0; +} + +/* handle USB calibration message */ +static void pcan_usb_fd_decode_ts(struct pcan_usb_fd_if *usb_if, + struct pucan_msg *rx_msg) +{ + struct pcan_ufd_ts_msg *ts = (struct pcan_ufd_ts_msg *)rx_msg; + + /* should wait until clock is stabilized */ + if (usb_if->cm_ignore_count > 0) + usb_if->cm_ignore_count--; + else + peak_usb_set_ts_now(&usb_if->time_ref, le32_to_cpu(ts->ts_low)); +} + +/* callback for bulk IN urb */ +static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb) +{ + struct pcan_usb_fd_if *usb_if = pcan_usb_fd_dev_if(dev); + struct net_device *netdev = dev->netdev; + struct pucan_msg *rx_msg; + u8 *msg_ptr, *msg_end; + int err = 0; + + /* loop reading all the records from the incoming message */ + msg_ptr = urb->transfer_buffer; + msg_end = urb->transfer_buffer + urb->actual_length; + for (; msg_ptr < msg_end;) { + u16 rx_msg_type, rx_msg_size; + + rx_msg = (struct pucan_msg *)msg_ptr; + if (!rx_msg->size) { + /* null packet found: end of list */ + break; + } + + rx_msg_size = le16_to_cpu(rx_msg->size); + rx_msg_type = le16_to_cpu(rx_msg->type); + + /* check if the record goes out of current packet */ + if (msg_ptr + rx_msg_size > msg_end) { + netdev_err(netdev, + "got frag rec: should inc usb rx buf sze\n"); + err = -EBADMSG; + break; + } + + switch (rx_msg_type) { + case PUCAN_MSG_CAN_RX: + err = pcan_usb_fd_decode_canmsg(usb_if, rx_msg); + if (err < 0) + goto fail; + break; + + case PCAN_UFD_MSG_CALIBRATION: + pcan_usb_fd_decode_ts(usb_if, rx_msg); + break; + + case PUCAN_MSG_ERROR: + err = pcan_usb_fd_decode_error(usb_if, rx_msg); + if (err < 0) + goto fail; + break; + + case PUCAN_MSG_STATUS: + err = pcan_usb_fd_decode_status(usb_if, rx_msg); + if (err < 0) + goto fail; + break; + + case PCAN_UFD_MSG_OVERRUN: + err = pcan_usb_fd_decode_overrun(usb_if, rx_msg); + if (err < 0) + goto fail; + break; + + default: + netdev_err(netdev, + "unhandled msg type 0x%02x (%d): ignored\n", + rx_msg_type, rx_msg_type); + break; + } + + msg_ptr += rx_msg_size; + } + +fail: + if (err) + pcan_dump_mem("received msg", + urb->transfer_buffer, urb->actual_length); + return err; +} + +/* CAN/CANFD frames encoding callback */ +static int pcan_usb_fd_encode_msg(struct peak_usb_device *dev, + struct sk_buff *skb, u8 *obuf, size_t *size) +{ + struct pucan_tx_msg *tx_msg = (struct pucan_tx_msg *)obuf; + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; + u16 tx_msg_size, tx_msg_flags; + u8 can_dlc; + + tx_msg_size = ALIGN(sizeof(struct pucan_tx_msg) + cfd->len, 4); + tx_msg->size = cpu_to_le16(tx_msg_size); + tx_msg->type = cpu_to_le16(PUCAN_MSG_CAN_TX); + + tx_msg_flags = 0; + if (cfd->can_id & CAN_EFF_FLAG) { + tx_msg_flags |= PUCAN_MSG_EXT_ID; + tx_msg->can_id = cpu_to_le32(cfd->can_id & CAN_EFF_MASK); + } else { + tx_msg->can_id = cpu_to_le32(cfd->can_id & CAN_SFF_MASK); + } + + if (can_is_canfd_skb(skb)) { + /* considering a CANFD frame */ + can_dlc = can_len2dlc(cfd->len); + + tx_msg_flags |= PUCAN_MSG_EXT_DATA_LEN; + + if (cfd->flags & CANFD_BRS) + tx_msg_flags |= PUCAN_MSG_BITRATE_SWITCH; + + if (cfd->flags & CANFD_ESI) + tx_msg_flags |= PUCAN_MSG_ERROR_STATE_IND; + } else { + /* CAND 2.0 frames */ + can_dlc = cfd->len; + + if (cfd->can_id & CAN_RTR_FLAG) + tx_msg_flags |= PUCAN_MSG_RTR; + } + + tx_msg->flags = cpu_to_le16(tx_msg_flags); + tx_msg->channel_dlc = PUCAN_MSG_CHANNEL_DLC(dev->ctrl_idx, can_dlc); + memcpy(tx_msg->d, cfd->data, cfd->len); + + /* add null size message to tag the end (messages are 32-bits aligned) + */ + tx_msg = (struct pucan_tx_msg *)(obuf + tx_msg_size); + + tx_msg->size = 0; + + /* set the whole size of the USB packet to send */ + *size = tx_msg_size + sizeof(u32); + + return 0; +} + +/* start the interface (last chance before set bus on) */ +static int pcan_usb_fd_start(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + int err; + + /* set filter mode: all acceptance */ + err = pcan_usb_fd_set_filter_std(dev, -1, 0xffffffff); + if (err) + return err; + + /* opening first device: */ + if (pdev->usb_if->dev_opened_count == 0) { + /* reset time_ref */ + peak_usb_init_time_ref(&pdev->usb_if->time_ref, + &pcan_usb_pro_fd); + + /* enable USB calibration messages */ + err = pcan_usb_fd_set_filter_ext(dev, 1, + PUCAN_FLTEXT_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); + } + + pdev->usb_if->dev_opened_count++; + + /* reset cached error counters */ + pdev->bec.txerr = 0; + pdev->bec.rxerr = 0; + + return err; +} + +/* socket callback used to copy berr counters values receieved through USB */ +static int pcan_usb_fd_get_berr_counter(const struct net_device *netdev, + struct can_berr_counter *bec) +{ + struct peak_usb_device *dev = netdev_priv(netdev); + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + *bec = pdev->bec; + + /* must return 0 */ + return 0; +} + +/* stop interface (last chance before set bus off) */ +static int pcan_usb_fd_stop(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + /* turn off special msgs for that interface if no other dev opened */ + if (pdev->usb_if->dev_opened_count == 1) + pcan_usb_fd_set_filter_ext(dev, 0, + PUCAN_FLTEXT_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); + pdev->usb_if->dev_opened_count--; + + return 0; +} + +/* called when probing, to initialize a device object */ +static int pcan_usb_fd_init(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + int i, err = -ENOMEM; + + /* do this for 1st channel only */ + if (!dev->prev_siblings) { + /* allocate netdevices common structure attached to first one */ + pdev->usb_if = kzalloc(sizeof(*pdev->usb_if), GFP_KERNEL); + if (!pdev->usb_if) + goto err_out; + + /* allocate command buffer once for all for the interface */ + pdev->cmd_buffer_addr = kmalloc(PCAN_UFD_CMD_BUFFER_SIZE, + GFP_KERNEL); + if (!pdev->cmd_buffer_addr) + goto err_out_1; + + /* number of ts msgs to ignore before taking one into account */ + pdev->usb_if->cm_ignore_count = 5; + + err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO, + PCAN_USBPRO_INFO_FW, + &pdev->usb_if->fw_info, + sizeof(pdev->usb_if->fw_info)); + if (err) { + dev_err(dev->netdev->dev.parent, + "unable to read %s firmware info (err %d)\n", + dev->adapter->name, err); + goto err_out_2; + } + + /* explicit use of dev_xxx() instead of netdev_xxx() here: + * information displayed are related to the device itself, not + * to the canx (channel) device. + */ + dev_info(dev->netdev->dev.parent, + "PEAK-System %s v%u fw v%u.%u.%u (%u channels)\n", + dev->adapter->name, pdev->usb_if->fw_info.hw_version, + pdev->usb_if->fw_info.fw_version[0], + pdev->usb_if->fw_info.fw_version[1], + pdev->usb_if->fw_info.fw_version[2], + dev->adapter->ctrl_count); + + /* the currently supported hw is non-ISO */ + dev->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO; + + /* tell the hardware the can driver is running */ + err = pcan_usb_fd_drv_loaded(dev, 1); + if (err) { + dev_err(dev->netdev->dev.parent, + "unable to tell %s driver is loaded (err %d)\n", + dev->adapter->name, err); + goto err_out_2; + } + } else { + /* otherwise, simply copy previous sibling's values */ + struct pcan_usb_fd_device *ppdev = + container_of(dev->prev_siblings, + struct pcan_usb_fd_device, dev); + + pdev->usb_if = ppdev->usb_if; + pdev->cmd_buffer_addr = ppdev->cmd_buffer_addr; + } + + pdev->usb_if->dev[dev->ctrl_idx] = dev; + dev->device_number = + le32_to_cpu(pdev->usb_if->fw_info.dev_id[dev->ctrl_idx]); + + /* set clock domain */ + for (i = 0; i < ARRAY_SIZE(pcan_usb_fd_clk_freq); i++) + if (dev->adapter->clock.freq == pcan_usb_fd_clk_freq[i]) + break; + + if (i >= ARRAY_SIZE(pcan_usb_fd_clk_freq)) { + dev_warn(dev->netdev->dev.parent, + "incompatible clock frequencies\n"); + err = -EINVAL; + goto err_out_2; + } + + pcan_usb_fd_set_clock_domain(dev, i); + + /* set LED in default state (end of init phase) */ + pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_DEF); + + return 0; + +err_out_2: + kfree(pdev->cmd_buffer_addr); +err_out_1: + kfree(pdev->usb_if); +err_out: + return err; +} + +/* called when driver module is being unloaded */ +static void pcan_usb_fd_exit(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + /* when rmmod called before unplug and if down, should reset things + * before leaving + */ + if (dev->can.state != CAN_STATE_STOPPED) { + /* set bus off on the corresponding channel */ + pcan_usb_fd_set_bus(dev, 0); + } + + /* switch off corresponding CAN LEDs */ + pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_OFF); + + /* if channel #0 (only) */ + if (dev->ctrl_idx == 0) { + /* turn off calibration message if any device were opened */ + if (pdev->usb_if->dev_opened_count > 0) + pcan_usb_fd_set_filter_ext(dev, 0, + PUCAN_FLTEXT_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); + + /* tell USB adapter that the driver is being unloaded */ + pcan_usb_fd_drv_loaded(dev, 0); + } +} + +/* called when the USB adapter is unplugged */ +static void pcan_usb_fd_free(struct peak_usb_device *dev) +{ + /* last device: can free shared objects now */ + if (!dev->prev_siblings && !dev->next_siblings) { + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + /* free commands buffer */ + kfree(pdev->cmd_buffer_addr); + + /* free usb interface object */ + kfree(pdev->usb_if); + } +} + +/* describes the PCAN-USB FD adapter */ +const struct peak_usb_adapter pcan_usb_fd = { + .name = "PCAN-USB FD", + .device_id = PCAN_USBFD_PRODUCT_ID, + .ctrl_count = PCAN_USBFD_CHANNEL_COUNT, + .ctrlmode_supported = CAN_CTRLMODE_FD | + CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, + .clock = { + .freq = PCAN_UFD_CRYSTAL_HZ, + }, + .bittiming_const = { + .name = "pcan_usb_fd", + .tseg1_min = 1, + .tseg1_max = 64, + .tseg2_min = 1, + .tseg2_max = 16, + .sjw_max = 16, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, + }, + .data_bittiming_const = { + .name = "pcan_usb_fd", + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, + }, + + /* size of device private data */ + .sizeof_dev_private = sizeof(struct pcan_usb_fd_device), + + /* timestamps usage */ + .ts_used_bits = 32, + .ts_period = 1000000, /* calibration period in ts. */ + .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */ + .us_per_ts_shift = 0, + + /* give here messages in/out endpoints */ + .ep_msg_in = PCAN_USBPRO_EP_MSGIN, + .ep_msg_out = {PCAN_USBPRO_EP_MSGOUT_0}, + + /* size of rx/tx usb buffers */ + .rx_buffer_size = PCAN_UFD_RX_BUFFER_SIZE, + .tx_buffer_size = PCAN_UFD_TX_BUFFER_SIZE, + + /* device callbacks */ + .intf_probe = pcan_usb_pro_probe, /* same as PCAN-USB Pro */ + .dev_init = pcan_usb_fd_init, + + .dev_exit = pcan_usb_fd_exit, + .dev_free = pcan_usb_fd_free, + .dev_set_bus = pcan_usb_fd_set_bus, + .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, + .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, + .dev_decode_buf = pcan_usb_fd_decode_buf, + .dev_start = pcan_usb_fd_start, + .dev_stop = pcan_usb_fd_stop, + .dev_restart_async = pcan_usb_fd_restart_async, + .dev_encode_msg = pcan_usb_fd_encode_msg, + + .do_get_berr_counter = pcan_usb_fd_get_berr_counter, +}; + +/* describes the PCAN-USB Pro FD adapter */ +const struct peak_usb_adapter pcan_usb_pro_fd = { + .name = "PCAN-USB Pro FD", + .device_id = PCAN_USBPROFD_PRODUCT_ID, + .ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT, + .ctrlmode_supported = CAN_CTRLMODE_FD | + CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, + .clock = { + .freq = PCAN_UFD_CRYSTAL_HZ, + }, + .bittiming_const = { + .name = "pcan_usb_pro_fd", + .tseg1_min = 1, + .tseg1_max = 64, + .tseg2_min = 1, + .tseg2_max = 16, + .sjw_max = 16, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, + }, + .data_bittiming_const = { + .name = "pcan_usb_pro_fd", + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, + }, + + /* size of device private data */ + .sizeof_dev_private = sizeof(struct pcan_usb_fd_device), + + /* timestamps usage */ + .ts_used_bits = 32, + .ts_period = 1000000, /* calibration period in ts. */ + .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */ + .us_per_ts_shift = 0, + + /* give here messages in/out endpoints */ + .ep_msg_in = PCAN_USBPRO_EP_MSGIN, + .ep_msg_out = {PCAN_USBPRO_EP_MSGOUT_0, PCAN_USBPRO_EP_MSGOUT_1}, + + /* size of rx/tx usb buffers */ + .rx_buffer_size = PCAN_UFD_RX_BUFFER_SIZE, + .tx_buffer_size = PCAN_UFD_TX_BUFFER_SIZE, + + /* device callbacks */ + .intf_probe = pcan_usb_pro_probe, /* same as PCAN-USB Pro */ + .dev_init = pcan_usb_fd_init, + + .dev_exit = pcan_usb_fd_exit, + .dev_free = pcan_usb_fd_free, + .dev_set_bus = pcan_usb_fd_set_bus, + .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, + .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, + .dev_decode_buf = pcan_usb_fd_decode_buf, + .dev_start = pcan_usb_fd_start, + .dev_stop = pcan_usb_fd_stop, + .dev_restart_async = pcan_usb_fd_restart_async, + .dev_encode_msg = pcan_usb_fd_encode_msg, + + .do_get_berr_counter = pcan_usb_fd_get_berr_counter, +}; -- cgit v1.2.1 From a154e6f6efdd13d7254679b5a99d9b912017621f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 28 Jan 2015 21:58:33 +0300 Subject: hisilicon: add some missing curly braces The if block was supposed to have curly braces. In the current code we complain about dropped rx packets when we shouldn't. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hip04_eth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index 525214ef5984..c02b81bcfffb 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -567,10 +567,11 @@ static irqreturn_t hip04_mac_interrupt(int irq, void *dev_id) writel_relaxed(DEF_INT_MASK, priv->base + PPE_RINT); if (unlikely(ists & DEF_INT_ERR)) { - if (ists & (RCV_NOBUF | RCV_DROP)) + if (ists & (RCV_NOBUF | RCV_DROP)) { stats->rx_errors++; stats->rx_dropped++; netdev_err(ndev, "rx drop\n"); + } if (ists & TX_DROP) { stats->tx_dropped++; netdev_err(ndev, "tx drop\n"); -- cgit v1.2.1 From 8c6796758f0abd8ee2b4d7e8c6ca5f7adf737ee6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 25 Jan 2015 10:52:42 +0200 Subject: wil6210: sync WMI with firmware Incorporate changes from firmware. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 15 +++++---- drivers/net/wireless/ath/wil6210/wmi.h | 58 ++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index b2b0fe1faa96..097d78bca2f0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1133,12 +1133,13 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) return rc; } -int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) +int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) { int rc; struct wmi_temp_sense_cmd cmd = { - .measure_marlon_m_en = cpu_to_le32(!!t_m), - .measure_marlon_r_en = cpu_to_le32(!!t_r), + .measure_baseband_en = cpu_to_le32(!!t_bb), + .measure_rf_en = cpu_to_le32(!!t_rf), + .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW), }; struct { struct wil6210_mbox_hdr_wmi wmi; @@ -1150,10 +1151,10 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) if (rc) return rc; - if (t_m) - *t_m = le32_to_cpu(reply.evt.marlon_m_t1000); - if (t_r) - *t_r = le32_to_cpu(reply.evt.marlon_r_t1000); + if (t_bb) + *t_bb = le32_to_cpu(reply.evt.baseband_t1000); + if (t_rf) + *t_rf = le32_to_cpu(reply.evt.rf_t1000); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index b5102f0b97f4..8a4af613e191 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -29,8 +29,10 @@ /* General */ #define WILOCITY_MAX_ASSOC_STA (8) +#define WILOCITY_DEFAULT_ASSOC_STA (1) #define WMI_MAC_LEN (6) #define WMI_PROX_RANGE_NUM (3) +#define WMI_MAX_LOSS_DMG_BEACONS (32) /* List of Commands */ enum wmi_command_id { @@ -48,7 +50,7 @@ enum wmi_command_id { WMI_SET_WSC_STATUS_CMDID = 0x0041, WMI_PXMT_RANGE_CFG_CMDID = 0x0042, WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043, - WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, +/* WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, */ WMI_MEM_READ_CMDID = 0x0800, WMI_MEM_WR_CMDID = 0x0801, WMI_ECHO_CMDID = 0x0803, @@ -102,6 +104,8 @@ enum wmi_command_id { WMI_MAINTAIN_RESUME_CMDID = 0x0851, WMI_RS_MGMT_CMDID = 0x0852, WMI_RF_MGMT_CMDID = 0x0853, + WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x0854, + WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x0855, /* Performance monitoring commands */ WMI_BF_CTRL_CMDID = 0x0862, WMI_NOTIFY_REQ_CMDID = 0x0863, @@ -136,6 +140,7 @@ enum wmi_command_id { WMI_EAPOL_TX_CMDID = 0xf04c, WMI_MAC_ADDR_REQ_CMDID = 0xf04d, WMI_FW_VER_CMDID = 0xf04e, + WMI_PMC_CMDID = 0xf04f, }; /* @@ -283,8 +288,8 @@ enum wmi_scan_type { WMI_LONG_SCAN = 0, WMI_SHORT_SCAN = 1, WMI_PBC_SCAN = 2, - WMI_ACTIVE_SCAN = 3, - WMI_DIRECT_SCAN = 4, + WMI_DIRECT_SCAN = 3, + WMI_ACTIVE_SCAN = 4, }; struct wmi_start_scan_cmd { @@ -374,6 +379,17 @@ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; } __packed; +/* + * WMI_THERMAL_THROTTLING_CTRL_CMDID + */ +#define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH (0xFFFFFFFF) + +struct wmi_thermal_throttling_ctrl_cmd { + __le32 time_on_usec; + __le32 time_off_usec; + __le32 max_txop_length_usec; +} __packed; + /* * WMI_RF_RX_TEST_CMDID */ @@ -648,6 +664,7 @@ enum wmi_cfg_rx_chain_cmd_action { enum wmi_cfg_rx_chain_cmd_decap_trans_type { WMI_DECAP_TYPE_802_3 = 0, WMI_DECAP_TYPE_NATIVE_WIFI = 1, + WMI_DECAP_TYPE_NONE = 2, }; enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type { @@ -785,9 +802,17 @@ struct wmi_echo_cmd { * * Measure MAC and radio temperatures */ + +/* Possible modes for temperature measurement */ +enum wmi_temperature_measure_mode { + TEMPERATURE_USE_OLD_VALUE = 0x1, + TEMPERATURE_MEASURE_NOW = 0x2, +}; + struct wmi_temp_sense_cmd { - __le32 measure_marlon_m_en; - __le32 measure_marlon_r_en; + __le32 measure_baseband_en; + __le32 measure_rf_en; + __le32 measure_mode; } __packed; /* @@ -843,6 +868,7 @@ enum wmi_event_id { WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, WMI_RS_MGMT_DONE_EVENTID = 0x1852, WMI_RF_MGMT_STATUS_EVENTID = 0x1853, + WMI_THERMAL_THROTTLING_STATUS_EVENTID = 0x1855, WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, WMI_RX_MGMT_PACKET_EVENTID = 0x1840, WMI_TX_MGMT_PACKET_EVENTID = 0x1841, @@ -859,6 +885,7 @@ enum wmi_event_id { WMI_FLASH_READ_DONE_EVENTID = 0x1902, WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, /*P2P*/ + WMI_P2P_CFG_DONE_EVENTID = 0x1910, WMI_PORT_ALLOCATED_EVENTID = 0x1911, WMI_PORT_DELETED_EVENTID = 0x1912, WMI_LISTEN_STARTED_EVENTID = 0x1914, @@ -898,6 +925,15 @@ struct wmi_rf_mgmt_status_event { __le32 rf_status; } __packed; +/* + * WMI_THERMAL_THROTTLING_STATUS_EVENTID + */ +struct wmi_thermal_throttling_status_event { + __le32 time_on_usec; + __le32 time_off_usec; + __le32 max_txop_length_usec; +} __packed; + /* * WMI_GET_STATUS_DONE_EVENTID */ @@ -1154,6 +1190,14 @@ struct wmi_get_pcp_channel_event { u8 reserved[3]; } __packed; +/* + * WMI_P2P_CFG_DONE_EVENTID + */ +struct wmi_p2p_cfg_done_event { + u8 status; /* wmi_fw_status */ + u8 reserved[3]; +} __packed; + /* * WMI_PORT_ALLOCATED_EVENTID */ @@ -1282,8 +1326,8 @@ struct wmi_echo_event { * Measure MAC and radio temperatures */ struct wmi_temp_sense_done_event { - __le32 marlon_m_t1000; - __le32 marlon_r_t1000; + __le32 baseband_t1000; + __le32 rf_t1000; } __packed; #endif /* __WILOCITY_WMI_H__ */ -- cgit v1.2.1 From c5e96c91fa8f98ddceac16f410fc741648585401 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Sun, 25 Jan 2015 10:52:43 +0200 Subject: wil6210: fix timing of netif_carrier_on indication netif_carrier_on indication was too late. In case Rx packet received before netif_carrier_on indication, upper layers could not send Tx packet back. The fix is to indicate netif_carrier_on earlier: for STA, indicate netif_carrier_on when association starts. for AP/PCP, indicate netif_carrier_on upon starting AP/PCP. Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 8 +++++--- drivers/net/wireless/ath/wil6210/main.c | 30 ++++++----------------------- drivers/net/wireless/ath/wil6210/netdev.c | 4 +--- drivers/net/wireless/ath/wil6210/wil6210.h | 2 -- drivers/net/wireless/ath/wil6210/wmi.c | 2 -- 5 files changed, 12 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index bd013fdb86dc..553aa2e2257a 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -454,6 +454,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); if (rc == 0) { + netif_carrier_on(ndev); /* Connect can take lots of time */ mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); @@ -757,12 +758,12 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil->secure_pcp = info->privacy; + netif_carrier_on(ndev); + rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) - goto out; - - netif_carrier_on(ndev); + netif_carrier_off(ndev); out: mutex_unlock(&wil->mutex); @@ -777,6 +778,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wil_dbg_misc(wil, "%s()\n", __func__); + netif_carrier_off(ndev); wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 62dc24189bd3..00c9b0f87c9b 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -248,7 +248,9 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - wil_link_off(wil); + netif_tx_stop_all_queues(ndev); + netif_carrier_off(ndev); + if (test_bit(wil_status_fwconnected, wil->status)) { clear_bit(wil_status_fwconnected, wil->status); cfg80211_disconnected(ndev, reason_code, @@ -395,6 +397,8 @@ static void wil_connect_worker(struct work_struct *work) int rc; struct wil6210_priv *wil = container_of(work, struct wil6210_priv, connect_worker); + struct net_device *ndev = wil_to_ndev(wil); + int cid = wil->pending_connect_cid; int ringid = wil_find_free_vring(wil); @@ -409,7 +413,7 @@ static void wil_connect_worker(struct work_struct *work) wil->pending_connect_cid = -1; if (rc == 0) { wil->sta[cid].status = wil_sta_connected; - wil_link_on(wil); + netif_tx_wake_all_queues(ndev); } else { wil->sta[cid].status = wil_sta_unused; } @@ -741,28 +745,6 @@ void wil_fw_error_recovery(struct wil6210_priv *wil) schedule_work(&wil->fw_error_worker); } -void wil_link_on(struct wil6210_priv *wil) -{ - struct net_device *ndev = wil_to_ndev(wil); - - wil_dbg_misc(wil, "%s()\n", __func__); - - netif_carrier_on(ndev); - wil_dbg_misc(wil, "netif_tx_wake : link on\n"); - netif_tx_wake_all_queues(ndev); -} - -void wil_link_off(struct wil6210_priv *wil) -{ - struct net_device *ndev = wil_to_ndev(wil); - - wil_dbg_misc(wil, "%s()\n", __func__); - - netif_tx_stop_all_queues(ndev); - wil_dbg_misc(wil, "netif_tx_stop : link off\n"); - netif_carrier_off(ndev); -} - int __wil_up(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index e81703ca7701..f1f9e510bfe9 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -174,7 +174,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx, WIL6210_NAPI_BUDGET); - wil_link_off(wil); + netif_tx_stop_all_queues(ndev); return wil; @@ -217,8 +217,6 @@ int wil_if_add(struct wil6210_priv *wil) return rc; } - wil_link_off(wil); - return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index da3fe7853d63..b4404e71cfca 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -649,8 +649,6 @@ void wil_priv_deinit(struct wil6210_priv *wil); int wil_reset(struct wil6210_priv *wil); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); -void wil_link_on(struct wil6210_priv *wil); -void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); int __wil_up(struct wil6210_priv *wil); int wil_down(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 097d78bca2f0..0f3e4334c8e3 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -566,7 +566,6 @@ static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize) static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) { - struct net_device *ndev = wil_to_ndev(wil); struct wmi_data_port_open_event *evt = d; u8 cid = evt->cid; @@ -580,7 +579,6 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) wil->sta[cid].data_port_open = true; if (agg_wsize >= 0) wil_addba_tx_cid(wil, cid, agg_wsize); - netif_carrier_on(ndev); } static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len) -- cgit v1.2.1 From 32a20d46b3dcb2f96ffcd5f967616cc599bdf542 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Sun, 25 Jan 2015 10:52:44 +0200 Subject: wil6210: ignore firmware failure to gracefully stop AP upon cfg80211_stop_ap, a graceful AP shutdown is requested from firmware followed by firmware reset. In case graceful request failed, error was returned to cfg80211. The change is to return success in this scenario, because firmware reset will anyhow shutdown the AP. Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 553aa2e2257a..6b7664d20d2e 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -773,7 +773,6 @@ out: static int wil_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { - int rc, rc1; struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s()\n", __func__); @@ -783,14 +782,17 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, mutex_lock(&wil->mutex); - rc = wmi_pcp_stop(wil); + wmi_pcp_stop(wil); __wil_down(wil); - rc1 = __wil_up(wil); + __wil_up(wil); mutex_unlock(&wil->mutex); - return min(rc, rc1); + /* some functions above might fail (e.g. __wil_up). Nevertheless, we + * return success because AP has stopped + */ + return 0; } static int wil_cfg80211_del_station(struct wiphy *wiphy, -- cgit v1.2.1 From f1871cd95067eb695ae126d43c12bc738627a90e Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Sun, 25 Jan 2015 10:52:45 +0200 Subject: wil6210: Add Tx queue len configuration Tx queue was hard-coded to 1000 in ether_setup. Add wil_dev_setup function which configures tx queue len to chosen default value after calling ether_setup. Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/netdev.c | 11 ++++++++--- drivers/net/wireless/ath/wil6210/wil6210.h | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index f1f9e510bfe9..ace30c1b5c64 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,7 +15,6 @@ */ #include - #include "wil6210.h" #include "txrx.h" @@ -122,6 +121,12 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) return min(tx_done, budget); } +static void wil_dev_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT; +} + void *wil_if_alloc(struct device *dev, void __iomem *csr) { struct net_device *ndev; @@ -153,7 +158,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); - ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup); + ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup); if (!ndev) { dev_err(dev, "alloc_netdev_mqs failed\n"); rc = -ENOMEM; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index b4404e71cfca..fc196bf54742 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -44,6 +44,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MEM_SIZE (2*1024*1024UL) +#define WIL_TX_Q_LEN_DEFAULT (4000) #define WIL_RX_RING_SIZE_ORDER_DEFAULT (9) #define WIL_TX_RING_SIZE_ORDER_DEFAULT (9) /* limit ring size in range [32..32k] */ -- cgit v1.2.1 From 3baedd9167c2e3a3593c20769256b700aba929da Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Sun, 25 Jan 2015 10:52:46 +0200 Subject: wil6210: tuning rings size Tuning rings size for performance optimization. Increasing Tx ring size, allows buffering more packets for HW, thus eliminating idle periods which were observed with smaller ring at high throughput, because HW was fetching packets faster than driver was filling them into the TX ring. Rx ring was similarly increased to avoid same problems in Rx. Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wil6210.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index fc196bf54742..2521ba1eebe9 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -45,8 +45,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MEM_SIZE (2*1024*1024UL) #define WIL_TX_Q_LEN_DEFAULT (4000) -#define WIL_RX_RING_SIZE_ORDER_DEFAULT (9) -#define WIL_TX_RING_SIZE_ORDER_DEFAULT (9) +#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) +#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10) /* limit ring size in range [32..32k] */ #define WIL_RING_SIZE_ORDER_MIN (5) #define WIL_RING_SIZE_ORDER_MAX (15) -- cgit v1.2.1 From 918465a3c2f7f28926821500152d89511d82166a Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Sun, 25 Jan 2015 10:52:47 +0200 Subject: wil6210: interrupt moderation configuration update Due to HW limitation, inter-packet gap timeout max value is 13 usec. Update of current thresholds from 15 to 13 usec. Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wil6210.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 2521ba1eebe9..3575b5d424a4 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -78,8 +78,8 @@ static inline u32 wil_mtu2macbuf(u32 mtu) #define WIL_MAX_ETH_MTU (IEEE80211_MAX_DATA_LEN_DMG - 8) /* Max supported by wil6210 value for interrupt threshold is 5sec. */ #define WIL6210_ITR_TRSH_MAX (5000000) -#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */ -#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */ +#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */ +#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */ #define WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT (500) /* usec */ #define WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT (500) /* usec */ #define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */ -- cgit v1.2.1 From 1f80af2e38f7a1f66b75c63ba83f968da62f5985 Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Sun, 25 Jan 2015 10:52:48 +0200 Subject: wil6210: remove unnecessary interrupt moderation module parameters Interrupt moderation parameters will never be passed as module parameters. For product, they will be hard-coded after lab testing, and for debugging, they can be altered via debugfs. Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 38 +++++---------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 00c9b0f87c9b..d25941696026 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,34 +33,6 @@ static bool no_fw_load = true; module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash."); -static unsigned int tx_interframe_timeout = - WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT; - -module_param(tx_interframe_timeout, uint, S_IRUGO); -MODULE_PARM_DESC(tx_interframe_timeout, - " Interrupt moderation TX interframe timeout, usecs."); - -static unsigned int rx_interframe_timeout = - WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT; - -module_param(rx_interframe_timeout, uint, S_IRUGO); -MODULE_PARM_DESC(rx_interframe_timeout, - " Interrupt moderation RX interframe timeout, usecs."); - -static unsigned int tx_max_burst_duration = - WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT; - -module_param(tx_max_burst_duration, uint, S_IRUGO); -MODULE_PARM_DESC(tx_max_burst_duration, - " Interrupt moderation TX max burst duration, usecs."); - -static unsigned int rx_max_burst_duration = - WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT; - -module_param(rx_max_burst_duration, uint, S_IRUGO); -MODULE_PARM_DESC(rx_max_burst_duration, - " Interrupt moderation RX max burst duration, usecs."); - /* if not set via modparam, will be set to default value of 1/8 of * rx ring size during init flow */ @@ -463,10 +435,10 @@ int wil_priv_init(struct wil6210_priv *wil) goto out_wmi_wq; wil->last_fw_recovery = jiffies; - wil->tx_interframe_timeout = tx_interframe_timeout; - wil->rx_interframe_timeout = rx_interframe_timeout; - wil->tx_max_burst_duration = tx_max_burst_duration; - wil->rx_max_burst_duration = rx_max_burst_duration; + wil->tx_interframe_timeout = WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT; + wil->rx_interframe_timeout = WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT; + wil->tx_max_burst_duration = WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT; + wil->rx_max_burst_duration = WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT; if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT) rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT; -- cgit v1.2.1 From 713c8a29e4d869f7ca4cadc8a6ac2c12de532ed9 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 25 Jan 2015 10:52:49 +0200 Subject: wil6210: implement skb Tx status reporting Implement Tx status reporting using skb_complete_wifi_ack(). Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 1 + drivers/net/wireless/ath/wil6210/txrx.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 6b7664d20d2e..f65da91e1af8 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -858,6 +858,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->cipher_suites = wil_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); wiphy->mgmt_stypes = wil_mgmt_stypes; + wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; } struct wireless_dev *wil_cfg80211_init(struct device *dev) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index b58ee52e1860..0499ebcdeff5 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1121,6 +1121,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NET_XMIT_DROP; } +static inline bool wil_need_txstat(struct sk_buff *skb) +{ + struct ethhdr *eth = (void *)skb->data; + + return is_unicast_ether_addr(eth->h_dest) && skb->sk && + (skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS); +} + +static inline void wil_consume_skb(struct sk_buff *skb, bool acked) +{ + if (unlikely(wil_need_txstat(skb))) + skb_complete_wifi_ack(skb, acked); + else + acked ? dev_consume_skb_any(skb) : dev_kfree_skb_any(skb); +} + /** * Clean up transmitted skb's from the Tx VRING * @@ -1199,8 +1215,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) ndev->stats.tx_errors++; stats->tx_errors++; } - - dev_kfree_skb_any(skb); + wil_consume_skb(skb, d->dma.error == 0); } memset(ctx, 0, sizeof(*ctx)); /* There is no need to touch HW descriptor: -- cgit v1.2.1 From 40822a901e3c07e50fe9f6a0cbbe77cba9fbc898 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 25 Jan 2015 10:52:50 +0200 Subject: wil6210: implement cfg80211 probe_client() op Access point require this API to check peer alive status. Assume peer is alive when it is connected, because firmware implements keep alive checks and will disconnect peer if it is not alive. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 91 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/wil6210/main.c | 5 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 12 ++++ 3 files changed, 108 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index f65da91e1af8..e758f430ed82 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -808,6 +808,96 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy, return 0; } +/* probe_client handling */ +static void wil_probe_client_handle(struct wil6210_priv *wil, + struct wil_probe_client_req *req) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct wil_sta_info *sta = &wil->sta[req->cid]; + /* assume STA is alive if it is still connected, + * else FW will disconnect it + */ + bool alive = (sta->status == wil_sta_connected); + + cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL); +} + +static struct list_head *next_probe_client(struct wil6210_priv *wil) +{ + struct list_head *ret = NULL; + + mutex_lock(&wil->probe_client_mutex); + + if (!list_empty(&wil->probe_client_pending)) { + ret = wil->probe_client_pending.next; + list_del(ret); + } + + mutex_unlock(&wil->probe_client_mutex); + + return ret; +} + +void wil_probe_client_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, struct wil6210_priv, + probe_client_worker); + struct wil_probe_client_req *req; + struct list_head *lh; + + while ((lh = next_probe_client(wil)) != NULL) { + req = list_entry(lh, struct wil_probe_client_req, list); + + wil_probe_client_handle(wil, req); + kfree(req); + } +} + +void wil_probe_client_flush(struct wil6210_priv *wil) +{ + struct wil_probe_client_req *req, *t; + + wil_dbg_misc(wil, "%s()\n", __func__); + + mutex_lock(&wil->probe_client_mutex); + + list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) { + list_del(&req->list); + kfree(req); + } + + mutex_unlock(&wil->probe_client_mutex); +} + +static int wil_cfg80211_probe_client(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u64 *cookie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil_probe_client_req *req; + int cid = wil_find_cid(wil, peer); + + wil_dbg_misc(wil, "%s(%pM => CID %d)\n", __func__, peer, cid); + + if (cid < 0) + return -ENOLINK; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->cid = cid; + req->cookie = cid; + + mutex_lock(&wil->probe_client_mutex); + list_add_tail(&req->list, &wil->probe_client_pending); + mutex_unlock(&wil->probe_client_mutex); + + *cookie = req->cookie; + queue_work(wil->wq_service, &wil->probe_client_worker); + return 0; +} + static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, @@ -827,6 +917,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { .start_ap = wil_cfg80211_start_ap, .stop_ap = wil_cfg80211_stop_ap, .del_station = wil_cfg80211_del_station, + .probe_client = wil_cfg80211_probe_client, }; static void wil_wiphy_init(struct wiphy *wiphy) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index d25941696026..b04e0afdcb21 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -405,6 +405,7 @@ int wil_priv_init(struct wil6210_priv *wil) mutex_init(&wil->wmi_mutex); mutex_init(&wil->back_rx_mutex); mutex_init(&wil->back_tx_mutex); + mutex_init(&wil->probe_client_mutex); init_completion(&wil->wmi_ready); init_completion(&wil->wmi_call); @@ -419,10 +420,12 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker); INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker); + INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); INIT_LIST_HEAD(&wil->back_rx_pending); INIT_LIST_HEAD(&wil->back_tx_pending); + INIT_LIST_HEAD(&wil->probe_client_pending); spin_lock_init(&wil->wmi_ev_lock); init_waitqueue_head(&wil->wq); @@ -485,6 +488,8 @@ void wil_priv_deinit(struct wil6210_priv *wil) cancel_work_sync(&wil->back_rx_worker); wil_back_tx_flush(wil); cancel_work_sync(&wil->back_tx_worker); + wil_probe_client_flush(wil); + cancel_work_sync(&wil->probe_client_worker); destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wmi_wq); } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 3575b5d424a4..90dc24fb60f8 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -504,6 +504,12 @@ struct wil_back_tx { u16 agg_timeout; }; +struct wil_probe_client_req { + struct list_head list; + u64 cookie; + u8 cid; +}; + struct wil6210_priv { struct pci_dev *pdev; int n_msi; @@ -564,6 +570,10 @@ struct wil6210_priv { struct list_head back_tx_pending; struct mutex back_tx_mutex; /* protect @back_tx_pending */ struct work_struct back_tx_worker; + /* keep alive */ + struct list_head probe_client_pending; + struct mutex probe_client_mutex; /* protect @probe_client_pending */ + struct work_struct probe_client_worker; /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; @@ -722,6 +732,8 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); int wmi_pcp_stop(struct wil6210_priv *wil); void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, u16 reason_code, bool from_event); +void wil_probe_client_flush(struct wil6210_priv *wil); +void wil_probe_client_worker(struct work_struct *work); int wil_rx_init(struct wil6210_priv *wil, u16 size); void wil_rx_fini(struct wil6210_priv *wil); -- cgit v1.2.1 From 382afc3d055b9ac4d175a4b5b9352128fc091aa3 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 25 Jan 2015 10:52:51 +0200 Subject: wil6210: move Rx reorder buffer allocation out of spinlock This fixes issue reported by Dan Carpenter: The patch 3277213feb1b: "wil6210: ADDBA/DELBA flows" from Dec 23, 2014, leads to the following static checker warning: drivers/net/wireless/ath/wil6210/rx_reorder.c:205 wil_tid_ampdu_rx_alloc() error: scheduling with locks held: 'spin_lock:tid_rx_lock' drivers/net/wireless/ath/wil6210/rx_reorder.c 202 struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, 203 int size, u16 ssn) 204 { 205 struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL); ^^^^^^^^^^ 206 207 if (!r) 208 return NULL; 209 210 r->reorder_buf = 211 kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); ^^^^^^^^^^^ 212 r->reorder_time = 213 kcalloc(size, sizeof(unsigned long), GFP_KERNEL); ^^^^^^^^^^^ 214 if (!r->reorder_buf || !r->reorder_time) { 215 kfree(r->reorder_buf); 216 kfree(r->reorder_time); 217 kfree(r); 218 return NULL; 219 } 220 [ snip ] 331 spin_lock_bh(&sta->tid_rx_lock); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ spin lock held. 332 333 wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); 334 sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function called with the lock held. 335 336 spin_unlock_bh(&sta->tid_rx_lock); Reported-by: Dan Carpenter Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/rx_reorder.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 552209227de9..ca10dcf0986e 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -292,6 +292,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) u16 agg_timeout = req->ba_timeout; u16 status = WLAN_STATUS_SUCCESS; u16 ssn = req->ba_seq_ctrl >> 4; + struct wil_tid_ampdu_rx *r; int rc; might_sleep(); @@ -328,11 +329,10 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) return; /* apply */ + r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); spin_lock_bh(&sta->tid_rx_lock); - wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); - sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); - + sta->tid_rx[tid] = r; spin_unlock_bh(&sta->tid_rx_lock); } -- cgit v1.2.1 From 5ef1e604194ee629c5d9fd6b9a4d3c424cfd2a84 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sun, 25 Jan 2015 20:31:30 +0100 Subject: brcmfmac: Relax scheduling of msgbuf worker on high throughput. On every tx the flow worker is triggered. When running high throughput data this causes an excessive amount of times the worker gets activated. This patch starts scheduling the worker more relaxed once outstanding tx has reached a certain depth. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/brcm80211/brcmfmac/commonring.h | 2 ++ drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | 30 +++++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h index 002336e35764..3d404016a92e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h @@ -37,6 +37,8 @@ struct brcmf_commonring { unsigned long flags; bool inited; bool was_full; + + atomic_t outstanding_tx; }; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index ee147f5c706a..6262612dec45 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -73,6 +73,8 @@ #define BRCMF_MSGBUF_TX_FLUSH_CNT1 32 #define BRCMF_MSGBUF_TX_FLUSH_CNT2 96 +#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 64 +#define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 32 struct msgbuf_common_hdr { u8 msgtype; @@ -749,6 +751,7 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid) tx_msghdr->metadata_buf_len = 0; tx_msghdr->metadata_buf_addr.high_addr = 0; tx_msghdr->metadata_buf_addr.low_addr = 0; + atomic_inc(&commonring->outstanding_tx); if (count >= BRCMF_MSGBUF_TX_FLUSH_CNT2) { brcmf_commonring_write_complete(commonring); count = 0; @@ -773,10 +776,16 @@ static void brcmf_msgbuf_txflow_worker(struct work_struct *worker) } -static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid) +static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid, + bool force) { + struct brcmf_commonring *commonring; + set_bit(flowid, msgbuf->flow_map); - queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work); + commonring = msgbuf->flowrings[flowid]; + if ((force) || (atomic_read(&commonring->outstanding_tx) < + BRCMF_MSGBUF_DELAY_TXWORKER_THRS)) + queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work); return 0; } @@ -797,7 +806,7 @@ static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx, return -ENOMEM; } brcmf_flowring_enqueue(flow, flowid, skb); - brcmf_msgbuf_schedule_txdata(msgbuf, flowid); + brcmf_msgbuf_schedule_txdata(msgbuf, flowid, false); return 0; } @@ -854,6 +863,7 @@ brcmf_msgbuf_process_ioctl_complete(struct brcmf_msgbuf *msgbuf, void *buf) static void brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf) { + struct brcmf_commonring *commonring; struct msgbuf_tx_status *tx_status; u32 idx; struct sk_buff *skb; @@ -871,6 +881,8 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf) } set_bit(flowid, msgbuf->txstatus_done_map); + commonring = msgbuf->flowrings[flowid]; + atomic_dec(&commonring->outstanding_tx); brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true); } @@ -1181,7 +1193,7 @@ brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf, brcmf_flowring_open(msgbuf->flow, flowid); - brcmf_msgbuf_schedule_txdata(msgbuf, flowid); + brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true); } @@ -1280,8 +1292,10 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + struct brcmf_commonring *commonring; void *buf; u32 flowid; + int qlen; buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE]; brcmf_msgbuf_process_rx(msgbuf, buf); @@ -1293,8 +1307,12 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev) for_each_set_bit(flowid, msgbuf->txstatus_done_map, msgbuf->nrof_flowrings) { clear_bit(flowid, msgbuf->txstatus_done_map); - if (brcmf_flowring_qlen(msgbuf->flow, flowid)) - brcmf_msgbuf_schedule_txdata(msgbuf, flowid); + commonring = msgbuf->flowrings[flowid]; + qlen = brcmf_flowring_qlen(msgbuf->flow, flowid); + if ((qlen > BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) || + ((qlen) && (atomic_read(&commonring->outstanding_tx) < + BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS))) + brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true); } return 0; -- cgit v1.2.1 From 69d03ee0b709a282f81e9f81c1359cffe1edcd2b Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sun, 25 Jan 2015 20:31:31 +0100 Subject: brcmfmac: prevent possible deadlock on resuming SDIO device. When the system is resumed a deadlock can occur when DPC gets entered before resume is complete. This patch fixes this by properly checking the suspend state outside the claim_host code block. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 33 ------------------------ drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 18 +++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/sdio.h | 2 -- 3 files changed, 18 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 00ba90b89455..8ba60f6f4915 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -97,25 +97,6 @@ static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func) { } -static bool brcmf_sdiod_pm_resume_error(struct brcmf_sdio_dev *sdiodev) -{ - bool is_err = false; -#ifdef CONFIG_PM_SLEEP - is_err = atomic_read(&sdiodev->suspend); -#endif - return is_err; -} - -static void brcmf_sdiod_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, - wait_queue_head_t *wq) -{ -#ifdef CONFIG_PM_SLEEP - int retry = 0; - while (atomic_read(&sdiodev->suspend) && retry++ != 30) - wait_event_timeout(*wq, false, HZ/100); -#endif -} - int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) { int ret = 0; @@ -244,10 +225,6 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn, brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", write, fn, addr, regsz); - brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); - if (brcmf_sdiod_pm_resume_error(sdiodev)) - return -EIO; - /* only allow byte access on F0 */ if (WARN_ON(regsz > 1 && !fn)) return -EINVAL; @@ -462,10 +439,6 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn, unsigned int req_sz; int err; - brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); - if (brcmf_sdiod_pm_resume_error(sdiodev)) - return -EIO; - /* Single skb use the standard mmc interface */ req_sz = pkt->len + 3; req_sz &= (uint)~3; @@ -516,10 +489,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, if (!pktlist->qlen) return -EINVAL; - brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); - if (brcmf_sdiod_pm_resume_error(sdiodev)) - return -EIO; - target_list = pktlist; /* for host with broken sg support, prepare a page aligned list */ __skb_queue_head_init(&local_list); @@ -1077,8 +1046,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, #endif atomic_set(&sdiodev->suspend, false); - init_waitqueue_head(&sdiodev->request_word_wait); - init_waitqueue_head(&sdiodev->request_buffer_wait); brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n"); err = brcmf_sdiod_probe(sdiodev); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 99a37765888d..2c4f0ccd3b70 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -2609,6 +2609,21 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) return ret; } +static int brcmf_sdio_pm_resume_wait(struct brcmf_sdio_dev *sdiodev) +{ +#ifdef CONFIG_PM_SLEEP + int retry; + + /* Wait for possible resume to complete */ + retry = 0; + while ((atomic_read(&sdiodev->suspend)) && (retry++ != 50)) + msleep(20); + if (atomic_read(&sdiodev->suspend)) + return -EIO; +#endif + return 0; +} + static void brcmf_sdio_dpc(struct brcmf_sdio *bus) { u32 newstatus = 0; @@ -2619,6 +2634,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_dbg(TRACE, "Enter\n"); + if (brcmf_sdio_pm_resume_wait(bus->sdiodev)) + return; + sdio_claim_host(bus->sdiodev->func[1]); /* If waiting for HTAVAIL, check status */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h index 8eb42620129c..82494df541d4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h @@ -169,8 +169,6 @@ struct brcmf_sdio_dev { u32 sbwad; /* Save backplane window address */ struct brcmf_sdio *bus; atomic_t suspend; /* suspend flag */ - wait_queue_head_t request_word_wait; - wait_queue_head_t request_buffer_wait; struct device *dev; struct brcmf_bus *bus_if; struct brcmfmac_sdio_platform_data *pdata; -- cgit v1.2.1 From 4dd8b26a40acf8450835d27bf922be145f7bd206 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sun, 25 Jan 2015 20:31:32 +0100 Subject: brcmfmac: use SDIO DPC for control frames. Control frames are normally handled outside DPC, but sometimes within DPC. To simplify code always handle control within DPC. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 87 ++++++++++---------------- 1 file changed, 33 insertions(+), 54 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 2c4f0ccd3b70..b4f5fe5d99a6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -44,7 +44,8 @@ #include "chip.h" #include "firmware.h" -#define DCMD_RESP_TIMEOUT 2000 /* In milli second */ +#define DCMD_RESP_TIMEOUT 2000 /* In milli second */ +#define CTL_DONE_TIMEOUT 2000 /* In milli second */ #ifdef DEBUG @@ -495,9 +496,9 @@ struct brcmf_sdio { u8 *ctrl_frame_buf; u16 ctrl_frame_len; bool ctrl_frame_stat; + int ctrl_frame_err; spinlock_t txq_lock; /* protect bus->txq */ - struct semaphore tx_seq_lock; /* protect bus->tx_seq */ wait_queue_head_t ctrl_wait; wait_queue_head_t dcmd_resp_wait; @@ -2376,8 +2377,6 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) /* Send frames until the limit or some other event */ for (cnt = 0; (cnt < maxframes) && data_ok(bus);) { pkt_num = 1; - if (down_interruptible(&bus->tx_seq_lock)) - return cnt; if (bus->txglom) pkt_num = min_t(u8, bus->tx_max - bus->tx_seq, bus->sdiodev->txglomsz); @@ -2393,13 +2392,10 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) __skb_queue_tail(&pktq, pkt); } spin_unlock_bh(&bus->txq_lock); - if (i == 0) { - up(&bus->tx_seq_lock); + if (i == 0) break; - } ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL); - up(&bus->tx_seq_lock); cnt += i; @@ -2743,17 +2739,14 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_sdio_clrintr(bus); if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && - (down_interruptible(&bus->tx_seq_lock) == 0)) { - if (data_ok(bus)) { - sdio_claim_host(bus->sdiodev->func[1]); - err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, - bus->ctrl_frame_len); - sdio_release_host(bus->sdiodev->func[1]); - - bus->ctrl_frame_stat = false; - brcmf_sdio_wait_event_wakeup(bus); - } - up(&bus->tx_seq_lock); + data_ok(bus)) { + sdio_claim_host(bus->sdiodev->func[1]); + err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, + bus->ctrl_frame_len); + sdio_release_host(bus->sdiodev->func[1]); + bus->ctrl_frame_err = err; + bus->ctrl_frame_stat = false; + brcmf_sdio_wait_event_wakeup(bus); } /* Send queued frames (limit 1 if rx may still be pending) */ if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && @@ -2965,43 +2958,30 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; - int ret = -1; + int ret; brcmf_dbg(TRACE, "Enter\n"); - if (down_interruptible(&bus->tx_seq_lock)) - return -EINTR; - - if (!data_ok(bus)) { - brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", - bus->tx_max, bus->tx_seq); - up(&bus->tx_seq_lock); - /* Send from dpc */ - bus->ctrl_frame_buf = msg; - bus->ctrl_frame_len = msglen; - bus->ctrl_frame_stat = true; - - wait_event_interruptible_timeout(bus->ctrl_wait, - !bus->ctrl_frame_stat, - msecs_to_jiffies(2000)); - - if (!bus->ctrl_frame_stat) { - brcmf_dbg(SDIO, "ctrl_frame_stat == false\n"); - ret = 0; - } else { - brcmf_dbg(SDIO, "ctrl_frame_stat == true\n"); - bus->ctrl_frame_stat = false; - if (down_interruptible(&bus->tx_seq_lock)) - return -EINTR; - ret = -1; - } + /* Send from dpc */ + bus->ctrl_frame_buf = msg; + bus->ctrl_frame_len = msglen; + bus->ctrl_frame_stat = true; + if (atomic_read(&bus->dpc_tskcnt) == 0) { + atomic_inc(&bus->dpc_tskcnt); + queue_work(bus->brcmf_wq, &bus->datawork); } - if (ret == -1) { - sdio_claim_host(bus->sdiodev->func[1]); - brcmf_sdio_bus_sleep(bus, false, false); - ret = brcmf_sdio_tx_ctrlframe(bus, msg, msglen); - sdio_release_host(bus->sdiodev->func[1]); - up(&bus->tx_seq_lock); + + wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat, + msecs_to_jiffies(CTL_DONE_TIMEOUT)); + + if (!bus->ctrl_frame_stat) { + brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n", + bus->ctrl_frame_err); + ret = bus->ctrl_frame_err; + } else { + brcmf_dbg(SDIO, "ctrl_frame timeout\n"); + bus->ctrl_frame_stat = false; + ret = -ETIMEDOUT; } if (ret) @@ -3009,7 +2989,7 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) else bus->sdcnt.tx_ctlpkts++; - return ret ? -EIO : 0; + return ret; } #ifdef DEBUG @@ -4165,7 +4145,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) spin_lock_init(&bus->rxctl_lock); spin_lock_init(&bus->txq_lock); - sema_init(&bus->tx_seq_lock, 1); init_waitqueue_head(&bus->ctrl_wait); init_waitqueue_head(&bus->dcmd_resp_wait); -- cgit v1.2.1 From 9b7a0ddc6073909bc61399ca3b8126ef886d5e8a Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 25 Jan 2015 20:31:33 +0100 Subject: brcmfmac: pass DEAUTH/DISASSOC reason code to user-space The driver always called cfg80211_disconnected() with reason parameter set to zero, ie. unknown. However, firmware does provide a valid 802.11 reason code in DEAUTH and DISASSOC event message to the driver. This patch passes the reason code to cfg80211_disconnected(). Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 31 +++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 5eba81bfc6ed..b59b8c6c42ab 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -1229,7 +1229,25 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) memset(prof, 0, sizeof(*prof)); } -static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) +static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e) +{ + u16 reason; + + switch (e->event_code) { + case BRCMF_E_DEAUTH: + case BRCMF_E_DEAUTH_IND: + case BRCMF_E_DISASSOC_IND: + reason = e->reason; + break; + case BRCMF_E_LINK: + default: + reason = 0; + break; + } + return reason; +} + +static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); s32 err = 0; @@ -1244,7 +1262,8 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) brcmf_err("WLC_DISASSOC failed (%d)\n", err); } clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state); - cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL); + cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0, + GFP_KERNEL); } clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); @@ -1414,7 +1433,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) if (!check_vif_up(ifp->vif)) return -EIO; - brcmf_link_down(ifp->vif); + brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING); brcmf_dbg(TRACE, "Exit\n"); @@ -3041,7 +3060,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, * disassociate from AP to save power while system is * in suspended state */ - brcmf_link_down(vif); + brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED); /* Make sure WPA_Supplicant receives all the event * generated due to DISASSOC call to the fw to keep * the state fw and WPA_Supplicant state consistent @@ -4927,7 +4946,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, if (!brcmf_is_ibssmode(ifp->vif)) { brcmf_bss_connect_done(cfg, ndev, e, false); } - brcmf_link_down(ifp->vif); + brcmf_link_down(ifp->vif, brcmf_map_fw_linkdown_reason(e)); brcmf_init_prof(ndev_to_prof(ndev)); if (ndev != cfg_to_ndev(cfg)) complete(&cfg->vif_disabled); @@ -5868,7 +5887,7 @@ static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp) * from AP to save power */ if (check_vif_up(ifp->vif)) { - brcmf_link_down(ifp->vif); + brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED); /* Make sure WPA_Supplicant receives all the event generated due to DISASSOC call to the fw to keep -- cgit v1.2.1 From 8982cd40ace9b7f109ac8c63e6763409e39feb55 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 25 Jan 2015 20:31:34 +0100 Subject: brcmfmac: wait for driver to go idle during suspend Before going in suspend state the watchdog thread needs to put the device in bus sleep state, which assures it can go in deep-sleep state during D3 state. Reviewed-by: Hante Meuleman Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 20 +++++++++++++++----- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 18 ++++++++---------- drivers/net/wireless/brcm80211/brcmfmac/sdio.h | 2 ++ 3 files changed, 25 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 8ba60f6f4915..9afaeb6d2af5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -1045,7 +1045,9 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, bus_if->wowl_supported = true; #endif + sdiodev->sleeping = false; atomic_set(&sdiodev->suspend, false); + init_waitqueue_head(&sdiodev->idle_wait); brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n"); err = brcmf_sdiod_probe(sdiodev); @@ -1107,12 +1109,23 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled) #ifdef CONFIG_PM_SLEEP static int brcmf_ops_sdio_suspend(struct device *dev) { - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + struct brcmf_bus *bus_if; + struct brcmf_sdio_dev *sdiodev; mmc_pm_flag_t sdio_flags; brcmf_dbg(SDIO, "Enter\n"); + bus_if = dev_get_drvdata(dev); + sdiodev = bus_if->bus_priv.sdio; + + /* wait for watchdog to go idle */ + if (wait_event_timeout(sdiodev->idle_wait, sdiodev->sleeping, + msecs_to_jiffies(3 * BRCMF_WD_POLL_MS)) == 0) { + brcmf_err("bus still active\n"); + return -EBUSY; + } + /* disable watchdog */ + brcmf_sdio_wd_timer(sdiodev->bus, 0); atomic_set(&sdiodev->suspend, true); if (sdiodev->wowl_enabled) { @@ -1124,9 +1137,6 @@ static int brcmf_ops_sdio_suspend(struct device *dev) if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags)) brcmf_err("Failed to set pm_flags %x\n", sdio_flags); } - - brcmf_sdio_wd_timer(sdiodev->bus, 0); - return 0; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index b4f5fe5d99a6..488a0f648e18 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -515,7 +515,6 @@ struct brcmf_sdio { bool txoff; /* Transmit flow-controlled */ struct brcmf_sdio_count sdcnt; bool sr_enabled; /* SaveRestore enabled */ - bool sleeping; /* SDIO bus sleeping */ u8 tx_hdrlen; /* sdio bus header length for tx packet */ bool txglom; /* host tx glomming enable flag */ @@ -1014,12 +1013,12 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) brcmf_dbg(SDIO, "Enter: request %s currently %s\n", (sleep ? "SLEEP" : "WAKE"), - (bus->sleeping ? "SLEEP" : "WAKE")); + (bus->sdiodev->sleeping ? "SLEEP" : "WAKE")); /* If SR is enabled control bus state with KSO */ if (bus->sr_enabled) { /* Done if we're already in the requested state */ - if (sleep == bus->sleeping) + if (sleep == bus->sdiodev->sleeping) goto end; /* Going to sleep */ @@ -1051,12 +1050,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) bus->idlecount = 0; err = brcmf_sdio_kso_control(bus, true); } - if (!err) { - /* Change state */ - bus->sleeping = sleep; - brcmf_dbg(SDIO, "new state %s\n", - (sleep ? "SLEEP" : "WAKE")); - } else { + if (err) { brcmf_err("error while changing bus sleep state %d\n", err); goto done; @@ -1071,6 +1065,11 @@ end: } else { brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok); } + bus->sdiodev->sleeping = sleep; + if (sleep) + wake_up(&bus->sdiodev->idle_wait); + brcmf_dbg(SDIO, "new state %s\n", + (sleep ? "SLEEP" : "WAKE")); done: brcmf_dbg(SDIO, "Exit: err=%d\n", err); return err; @@ -4215,7 +4214,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) bus->idleclock = BRCMF_IDLE_ACTIVE; /* SR state */ - bus->sleeping = false; bus->sr_enabled = false; brcmf_sdio_debugfs_create(bus); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h index 82494df541d4..9c5d42d20b48 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h @@ -169,6 +169,8 @@ struct brcmf_sdio_dev { u32 sbwad; /* Save backplane window address */ struct brcmf_sdio *bus; atomic_t suspend; /* suspend flag */ + bool sleeping; + wait_queue_head_t idle_wait; struct device *dev; struct brcmf_bus *bus_if; struct brcmfmac_sdio_platform_data *pdata; -- cgit v1.2.1 From a1cee865c3e79b71c10cd6a3de03d0dd73f7bdd9 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sun, 25 Jan 2015 20:31:35 +0100 Subject: brcmfmac: SDIO: avoid using bus state for private states. Each bus driver is maintaing an exported bus state indicating if upper layers can or cannot send data. SDIO is using this state also for more private states. This makes handling the states and state changes complex. This patch minimises the exposed states and makes SDIO keep track of an internal state where necessary. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 17 +++++---- drivers/net/wireless/brcm80211/brcmfmac/bus.h | 14 +------- drivers/net/wireless/brcm80211/brcmfmac/core.c | 6 ++-- drivers/net/wireless/brcm80211/brcmfmac/fwil.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/pcie.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 45 +++++++++--------------- drivers/net/wireless/brcm80211/brcmfmac/sdio.h | 8 +++++ drivers/net/wireless/brcm80211/brcmfmac/usb.c | 2 +- 8 files changed, 43 insertions(+), 53 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 9afaeb6d2af5..7944224e3fc9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -269,6 +269,12 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn, return ret; } +static void brcmf_sdiod_nomedium_state(struct brcmf_sdio_dev *sdiodev) +{ + sdiodev->state = BRCMF_STATE_NOMEDIUM; + brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN); +} + static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 regsz, void *data, bool write) { @@ -276,7 +282,7 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, s32 retry = 0; int ret; - if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM) + if (sdiodev->state == BRCMF_STATE_NOMEDIUM) return -ENOMEDIUM; /* @@ -302,7 +308,7 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); if (ret == -ENOMEDIUM) - brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM); + brcmf_sdiod_nomedium_state(sdiodev); else if (ret != 0) { /* * SleepCSR register access can fail when @@ -325,7 +331,7 @@ brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address) int err = 0, i; u8 addr[3]; - if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM) + if (sdiodev->state == BRCMF_STATE_NOMEDIUM) return -ENOMEDIUM; addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK; @@ -454,7 +460,7 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn, err = sdio_readsb(sdiodev->func[fn], ((u8 *)(pkt->data)), addr, req_sz); if (err == -ENOMEDIUM) - brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM); + brcmf_sdiod_nomedium_state(sdiodev); return err; } @@ -589,8 +595,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error; if (ret == -ENOMEDIUM) { - brcmf_bus_change_state(sdiodev->bus_if, - BRCMF_BUS_NOMEDIUM); + brcmf_sdiod_nomedium_state(sdiodev); break; } else if (ret != 0) { brcmf_err("CMD53 sg block %s failed %d\n", diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/brcm80211/brcmfmac/bus.h index ef344e47218a..55d36ff5439d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h @@ -33,11 +33,8 @@ /* The level of bus communication with the dongle */ enum brcmf_bus_state { - BRCMF_BUS_UNKNOWN, /* Not determined yet */ - BRCMF_BUS_NOMEDIUM, /* No medium access to dongle */ BRCMF_BUS_DOWN, /* Not ready for frame transfers */ - BRCMF_BUS_LOAD, /* Download access only (CPU reset) */ - BRCMF_BUS_DATA /* Ready for frame transfers */ + BRCMF_BUS_UP /* Ready for frame transfers */ }; /* The level of bus communication with the dongle */ @@ -188,18 +185,9 @@ void brcmf_bus_wowl_config(struct brcmf_bus *bus, bool enabled) bus->ops->wowl_config(bus->dev, enabled); } -static inline bool brcmf_bus_ready(struct brcmf_bus *bus) -{ - return bus->state == BRCMF_BUS_LOAD || bus->state == BRCMF_BUS_DATA; -} - static inline void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state new_state) { - /* NOMEDIUM is permanent */ - if (bus->state == BRCMF_BUS_NOMEDIUM) - return; - brcmf_dbg(TRACE, "%d -> %d\n", bus->state, new_state); bus->state = new_state; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index e2a9e33f71ab..ff8c97ba4bc5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c @@ -197,7 +197,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx); /* Can the device send data? */ - if (drvr->bus_if->state != BRCMF_BUS_DATA) { + if (drvr->bus_if->state != BRCMF_BUS_UP) { brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state); netif_stop_queue(ndev); dev_kfree_skb(skb); @@ -637,7 +637,7 @@ static int brcmf_netdev_open(struct net_device *ndev) brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); /* If bus is not ready, can't continue */ - if (bus_if->state != BRCMF_BUS_DATA) { + if (bus_if->state != BRCMF_BUS_UP) { brcmf_err("failed bus is not ready\n"); return -EAGAIN; } @@ -964,7 +964,7 @@ int brcmf_bus_start(struct device *dev) p2p_ifp = NULL; /* signal bus ready */ - brcmf_bus_change_state(bus_if, BRCMF_BUS_DATA); + brcmf_bus_change_state(bus_if, BRCMF_BUS_UP); /* Bus is ready, do any initialization */ ret = brcmf_c_preinit_dcmds(ifp); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 03f2c406a17b..dcfa0bb149ce 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -109,7 +109,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) struct brcmf_pub *drvr = ifp->drvr; s32 err; - if (drvr->bus_if->state != BRCMF_BUS_DATA) { + if (drvr->bus_if->state != BRCMF_BUS_UP) { brcmf_err("bus is down. we have nothing to do.\n"); return -EIO; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index e91fa9a2c885..61c053a729be 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -1828,7 +1828,7 @@ static int brcmf_pcie_resume(struct pci_dev *pdev) goto cleanup; brcmf_dbg(PCIE, "Hot resume, continue....\n"); brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); - brcmf_bus_change_state(bus, BRCMF_BUS_DATA); + brcmf_bus_change_state(bus, BRCMF_BUS_UP); brcmf_pcie_intr_enable(devinfo); return 0; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 488a0f648e18..5e9d20853bbb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -1909,7 +1909,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) bus->rxpending = true; for (rd->seq_num = bus->rx_seq, rxleft = maxframes; - !bus->rxskip && rxleft && brcmf_bus_ready(bus->sdiodev->bus_if); + !bus->rxskip && rxleft && bus->sdiodev->state == BRCMF_STATE_DATA; rd->seq_num++, rxleft--) { /* Handle glomming separately */ @@ -2415,7 +2415,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) } /* Deflow-control stack if needed */ - if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && + if ((bus->sdiodev->state == BRCMF_STATE_DATA) && bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { bus->txoff = false; brcmf_txflowblock(bus->sdiodev->dev, false); @@ -2503,7 +2503,7 @@ static void brcmf_sdio_bus_stop(struct device *dev) bus->watchdog_tsk = NULL; } - if (bus_if->state == BRCMF_BUS_DOWN) { + if (sdiodev->state != BRCMF_STATE_NOMEDIUM) { sdio_claim_host(sdiodev->func[1]); /* Enable clock for device interrupts */ @@ -2756,7 +2756,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_sdio_sendfromq(bus, framecnt); } - if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) { + if ((bus->sdiodev->state != BRCMF_STATE_DATA) || (err != 0)) { brcmf_err("failed backplane access over SDIO, halting operation\n"); atomic_set(&bus->intstatus, 0); } else if (atomic_read(&bus->intstatus) || @@ -3411,8 +3411,8 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, goto err; } - /* Allow HT Clock now that the ARM is running. */ - brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_LOAD); + /* Allow full data communication using DPC from now on. */ + bus->sdiodev->state = BRCMF_STATE_DATA; bcmerror = 0; err: @@ -3558,7 +3558,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus) return; } - if (!brcmf_bus_ready(bus->sdiodev->bus_if)) { + if (bus->sdiodev->state != BRCMF_STATE_DATA) { brcmf_err("bus is down. we have nothing to do\n"); return; } @@ -3581,10 +3581,6 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus) static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) { -#ifdef DEBUG - struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev); -#endif /* DEBUG */ - brcmf_dbg(TIMER, "Enter\n"); /* Poll period: check device if appropriate. */ @@ -3628,7 +3624,7 @@ static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) } #ifdef DEBUG /* Poll for console output periodically */ - if (bus_if && bus_if->state == BRCMF_BUS_DATA && + if (bus->sdiodev->state == BRCMF_STATE_DATA && bus->console_interval != 0) { bus->console.count += BRCMF_WD_POLL_MS; if (bus->console.count >= bus->console_interval) { @@ -3869,11 +3865,6 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) goto fail; } - /* SDIO register access works so moving - * state from UNKNOWN to DOWN. - */ - brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN); - bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops); if (IS_ERR(bus->ci)) { brcmf_err("brcmf_chip_attach failed!\n"); @@ -4007,18 +3998,16 @@ static void brcmf_sdio_firmware_callback(struct device *dev, brcmf_dbg(TRACE, "Enter: dev=%s\n", dev_name(dev)); - /* try to download image and nvram to the dongle */ - if (bus_if->state == BRCMF_BUS_DOWN) { - bus->alp_only = true; - err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len); - if (err) - goto fail; - bus->alp_only = false; - } - if (!bus_if->drvr) return; + /* try to download image and nvram to the dongle */ + bus->alp_only = true; + err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len); + if (err) + goto fail; + bus->alp_only = false; + /* Start the watchdog timer */ bus->sdcnt.tickcnt = 0; brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); @@ -4254,7 +4243,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) destroy_workqueue(bus->brcmf_wq); if (bus->ci) { - if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { + if (bus->sdiodev->state != BRCMF_STATE_NOMEDIUM) { sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdio_clkctl(bus, CLK_AVAIL, false); /* Leave the device in state where it is @@ -4289,7 +4278,7 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick) } /* don't start the wd until fw is loaded */ - if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA) + if (bus->sdiodev->state != BRCMF_STATE_DATA) return; if (wdtick) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h index 9c5d42d20b48..ec2586a8425c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h @@ -155,6 +155,13 @@ /* watchdog polling interval in ms */ #define BRCMF_WD_POLL_MS 10 +/* The state of the bus */ +enum brcmf_sdio_state { + BRCMF_STATE_DOWN, /* Device available, still initialising */ + BRCMF_STATE_DATA, /* Ready for data transfers, DPC enabled */ + BRCMF_STATE_NOMEDIUM /* No medium access to dongle possible */ +}; + struct brcmf_sdreg { int func; int offset; @@ -187,6 +194,7 @@ struct brcmf_sdio_dev { char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; bool wowl_enabled; + enum brcmf_sdio_state state; }; /* sdio core registers */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 4572defc280f..7e0c9e2fa7f6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -576,7 +576,7 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state) brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DOWN); } else if (state == BRCMFMAC_USB_STATE_UP) { brcmf_dbg(USB, "DBUS is up\n"); - brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DATA); + brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_UP); } else { brcmf_dbg(USB, "DBUS current state=%d\n", state); } -- cgit v1.2.1 From 649f38ae9e482098da94d30f7f802621e66c6b74 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sun, 25 Jan 2015 20:31:36 +0100 Subject: brcmfmac: Reopen netdev queue on bus state data. During suspend the bus state is put in the down state. When data is being transmitted during this state then the netdev queue will be close. This patch will wake the queue on state data if the queue was closed. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/bus.h | 10 +++------- drivers/net/wireless/brcm80211/brcmfmac/core.c | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/brcm80211/brcmfmac/bus.h index 55d36ff5439d..89e6a4dc105e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h @@ -185,13 +185,6 @@ void brcmf_bus_wowl_config(struct brcmf_bus *bus, bool enabled) bus->ops->wowl_config(bus->dev, enabled); } -static inline void brcmf_bus_change_state(struct brcmf_bus *bus, - enum brcmf_bus_state new_state) -{ - brcmf_dbg(TRACE, "%d -> %d\n", bus->state, new_state); - bus->state = new_state; -} - /* * interface functions from common layer */ @@ -214,6 +207,9 @@ void brcmf_txflowblock(struct device *dev, bool state); /* Notify the bus has transferred the tx packet to firmware */ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success); +/* Configure the "global" bus state used by upper layers */ +void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state); + int brcmf_bus_start(struct device *dev); s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len); void brcmf_bus_add_txhdrlen(struct device *dev, uint len); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index ff8c97ba4bc5..b8520c30af7c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c @@ -1106,6 +1106,27 @@ int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp) return !err; } +void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state) +{ + struct brcmf_pub *drvr = bus->drvr; + struct net_device *ndev; + int ifidx; + + brcmf_dbg(TRACE, "%d -> %d\n", bus->state, state); + bus->state = state; + + if (state == BRCMF_BUS_UP) { + for (ifidx = 0; ifidx < BRCMF_MAX_IFS; ifidx++) { + if ((drvr->iflist[ifidx]) && + (drvr->iflist[ifidx]->ndev)) { + ndev = drvr->iflist[ifidx]->ndev; + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + } + } + } +} + static void brcmf_driver_register(struct work_struct *work) { #ifdef CONFIG_BRCMFMAC_SDIO -- cgit v1.2.1 From 86fec35e17c15f466ebf3f942b60d35d47929444 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 25 Jan 2015 20:31:37 +0100 Subject: brcmfmac: do not load firmware when device is already running In brcmf_usb_probe_cb() the device is checked to determine whether it is already running firmware. However, when no firmware download is needed it still continues to request the firmware files. This is fixed by returning after successful setup. Reviewed-by: Hante Meuleman Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 7e0c9e2fa7f6..1b9572988c77 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -1263,6 +1263,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) ret = brcmf_usb_bus_setup(devinfo); if (ret) goto fail; + /* we are done */ + return 0; } bus->chip = bus_pub->devid; bus->chiprev = bus_pub->chiprev; -- cgit v1.2.1 From 31fc436f184dc4219d837d4ffc97ad7c2ca0954d Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 25 Jan 2015 20:31:38 +0100 Subject: brcmutil: use define for boardrev string function Introducing a define that the caller of brcmu_boardrev_str() can use to allocate enough room for buffer passed to the function. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmsmac/debug.c | 2 +- drivers/net/wireless/brcm80211/brcmutil/utils.c | 5 +++-- drivers/net/wireless/brcm80211/include/brcmu_utils.h | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c index c9a8b9360ab1..7a1fbb2e3a71 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/debug.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.c @@ -78,7 +78,7 @@ int brcms_debugfs_hardware_read(struct seq_file *s, void *data) struct brcms_hardware *hw = drvr->wlc->hw; struct bcma_device *core = hw->d11core; struct bcma_bus *bus = core->bus; - char boardrev[10]; + char boardrev[BRCMU_BOARDREV_LEN]; seq_printf(s, "chipnum 0x%x\n" "chiprev 0x%x\n" diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c index 906e89ddf319..34937d8e1395 100644 --- a/drivers/net/wireless/brcm80211/brcmutil/utils.c +++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c @@ -267,10 +267,11 @@ char *brcmu_boardrev_str(u32 brev, char *buf) char c; if (brev < 0x100) { - snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); + snprintf(buf, BRCMU_BOARDREV_LEN, "%d.%d", + (brev & 0xf0) >> 4, brev & 0xf); } else { c = (brev & 0xf000) == 0x1000 ? 'P' : 'A'; - snprintf(buf, 8, "%c%03x", c, brev & 0xfff); + snprintf(buf, BRCMU_BOARDREV_LEN, "%c%03x", c, brev & 0xfff); } return buf; } diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h index a043e29f07e2..197317b3fa70 100644 --- a/drivers/net/wireless/brcm80211/include/brcmu_utils.h +++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h @@ -218,6 +218,8 @@ void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...) } #endif +#define BRCMU_BOARDREV_LEN 8 + char *brcmu_boardrev_str(u32 brev, char *buf); #endif /* _BRCMU_UTILS_H_ */ -- cgit v1.2.1 From 9b1933a3bd7c4568edc4d906bf1cc0e901ce1ec4 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 25 Jan 2015 20:31:39 +0100 Subject: brcmfmac: determine chip info when not provided by bus layer In some scenarios the chip number and revision may not be provided by the bus layer. If the chip number is not filled, the common layer will ask the firmware for this information. Reviewed-by: Hante Meuleman Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/core.c | 15 ++++++++ drivers/net/wireless/brcm80211/brcmfmac/fwil.h | 1 + .../net/wireless/brcm80211/brcmfmac/fwil_types.h | 41 ++++++++++++++++++++++ 3 files changed, 57 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index b8520c30af7c..5f16a7e75d93 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c @@ -948,6 +948,7 @@ int brcmf_bus_start(struct device *dev) struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_if *ifp; struct brcmf_if *p2p_ifp; + struct brcmf_rev_info_le revinfo; brcmf_dbg(TRACE, "\n"); @@ -971,6 +972,20 @@ int brcmf_bus_start(struct device *dev) if (ret < 0) goto fail; + /* assure we have chipid before feature attach */ + if (!bus_if->chip) { + ret = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO, &revinfo, + sizeof(revinfo)); + if (ret < 0) { + brcmf_err("no chipid determined - device may malfunction\n"); + } else { + bus_if->chip = le32_to_cpu(revinfo.chipnum); + bus_if->chiprev = le32_to_cpu(revinfo.chiprev); + brcmf_dbg(INFO, "firmware revinfo: chip %x (%d) rev %d\n", + bus_if->chip, bus_if->chip, + bus_if->chiprev); + } + } brcmf_feat_attach(drvr); ret = brcmf_fws_init(drvr); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h index 37345e7b873d..5434dcf64f7d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h @@ -59,6 +59,7 @@ #define BRCMF_C_SET_COUNTRY 84 #define BRCMF_C_GET_PM 85 #define BRCMF_C_SET_PM 86 +#define BRCMF_C_GET_REVINFO 98 #define BRCMF_C_GET_CURR_RATESET 114 #define BRCMF_C_GET_AP 117 #define BRCMF_C_SET_AP 118 diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index 619669bbdb83..374920965108 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h @@ -539,4 +539,45 @@ struct brcmf_fil_country_le { char ccode[BRCMF_COUNTRY_BUF_SZ]; }; +/** + * struct brcmf_rev_info_le - device revision info. + * + * @vendorid: PCI vendor id. + * @deviceid: device id of chip. + * @radiorev: radio revision. + * @chiprev: chip revision. + * @corerev: core revision. + * @boardid: board identifier (usu. PCI sub-device id). + * @boardvendor: board vendor (usu. PCI sub-vendor id). + * @boardrev: board revision. + * @driverrev: driver version. + * @ucoderev: microcode version. + * @bus: bus type. + * @chipnum: chip number. + * @phytype: phy type. + * @phyrev: phy revision. + * @anarev: anacore rev. + * @chippkg: chip package info. + * @nvramrev: nvram revision number. + */ +struct brcmf_rev_info_le { + __le32 vendorid; + __le32 deviceid; + __le32 radiorev; + __le32 chiprev; + __le32 corerev; + __le32 boardid; + __le32 boardvendor; + __le32 boardrev; + __le32 driverrev; + __le32 ucoderev; + __le32 bus; + __le32 chipnum; + __le32 phytype; + __le32 phyrev; + __le32 anarev; + __le32 chippkg; + __le32 nvramrev; +}; + #endif /* FWIL_TYPES_H_ */ -- cgit v1.2.1 From 4862290319ade31237ea9e5d61fae5d01b76c28f Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 25 Jan 2015 20:31:40 +0100 Subject: brcmfmac: always obtain device revision info upon intialization Obtain device revision information and store it. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/common.c | 30 ++++++++++++++++++++++-- drivers/net/wireless/brcm80211/brcmfmac/core.c | 16 ++++--------- drivers/net/wireless/brcm80211/brcmfmac/core.h | 22 +++++++++++++++++ 3 files changed, 54 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/common.c b/drivers/net/wireless/brcm80211/brcmfmac/common.c index ddf05af13d44..91213a650017 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/common.c @@ -41,6 +41,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) s8 eventmask[BRCMF_EVENTING_MASK_LEN]; u8 buf[BRCMF_DCMD_SMLEN]; struct brcmf_join_pref_params join_pref_params[2]; + struct brcmf_rev_info_le revinfo; + struct brcmf_rev_info *ri; char *ptr; s32 err; @@ -48,12 +50,36 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr, sizeof(ifp->mac_addr)); if (err < 0) { - brcmf_err("Retreiving cur_etheraddr failed, %d\n", - err); + brcmf_err("Retreiving cur_etheraddr failed, %d\n", err); goto done; } memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac)); + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO, + &revinfo, sizeof(revinfo)); + if (err < 0) { + brcmf_err("retrieving revision info failed, %d\n", err); + } else { + ri = &ifp->drvr->revinfo; + ri->vendorid = le32_to_cpu(revinfo.vendorid); + ri->deviceid = le32_to_cpu(revinfo.deviceid); + ri->radiorev = le32_to_cpu(revinfo.radiorev); + ri->chiprev = le32_to_cpu(revinfo.chiprev); + ri->corerev = le32_to_cpu(revinfo.corerev); + ri->boardid = le32_to_cpu(revinfo.boardid); + ri->boardvendor = le32_to_cpu(revinfo.boardvendor); + ri->boardrev = le32_to_cpu(revinfo.boardrev); + ri->driverrev = le32_to_cpu(revinfo.driverrev); + ri->ucoderev = le32_to_cpu(revinfo.ucoderev); + ri->bus = le32_to_cpu(revinfo.bus); + ri->chipnum = le32_to_cpu(revinfo.chipnum); + ri->phytype = le32_to_cpu(revinfo.phytype); + ri->phyrev = le32_to_cpu(revinfo.phyrev); + ri->anarev = le32_to_cpu(revinfo.anarev); + ri->chippkg = le32_to_cpu(revinfo.chippkg); + ri->nvramrev = le32_to_cpu(revinfo.nvramrev); + } + /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); strcpy(buf, "ver"); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index 5f16a7e75d93..6406f95af0d3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c @@ -948,7 +948,6 @@ int brcmf_bus_start(struct device *dev) struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_if *ifp; struct brcmf_if *p2p_ifp; - struct brcmf_rev_info_le revinfo; brcmf_dbg(TRACE, "\n"); @@ -974,17 +973,10 @@ int brcmf_bus_start(struct device *dev) /* assure we have chipid before feature attach */ if (!bus_if->chip) { - ret = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO, &revinfo, - sizeof(revinfo)); - if (ret < 0) { - brcmf_err("no chipid determined - device may malfunction\n"); - } else { - bus_if->chip = le32_to_cpu(revinfo.chipnum); - bus_if->chiprev = le32_to_cpu(revinfo.chiprev); - brcmf_dbg(INFO, "firmware revinfo: chip %x (%d) rev %d\n", - bus_if->chip, bus_if->chip, - bus_if->chiprev); - } + bus_if->chip = drvr->revinfo.chipnum; + bus_if->chiprev = drvr->revinfo.chiprev; + brcmf_dbg(INFO, "firmware revinfo: chip %x (%d) rev %d\n", + bus_if->chip, bus_if->chip, bus_if->chiprev); } brcmf_feat_attach(drvr); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index f2f7d3d1a8ef..db7f35f141e7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h @@ -71,6 +71,27 @@ struct brcmf_proto; /* device communication protocol info */ struct brcmf_cfg80211_dev; /* cfg80211 device info */ struct brcmf_fws_info; /* firmware signalling info */ +/* see struct brcmf_rev_info_le in fwil_types.h */ +struct brcmf_rev_info { + u32 vendorid; + u32 deviceid; + u32 radiorev; + u32 chiprev; + u32 corerev; + u32 boardid; + u32 boardvendor; + u32 boardrev; + u32 driverrev; + u32 ucoderev; + u32 bus; + u32 chipnum; + u32 phytype; + u32 phyrev; + u32 anarev; + u32 chippkg; + u32 nvramrev; +}; + /* Common structure for module and instance linkage */ struct brcmf_pub { /* Linkage ponters */ @@ -104,6 +125,7 @@ struct brcmf_pub { u32 feat_flags; u32 chip_quirks; + struct brcmf_rev_info revinfo; #ifdef DEBUG struct dentry *dbgfs_dir; #endif -- cgit v1.2.1 From e749c7d49c2093d05d6f546f1a1a228cf3088e54 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 25 Jan 2015 20:31:41 +0100 Subject: brcmfmac: show firmware release info in ethtool driver info The ethtool driver info already contained the unique firmware identifier. This patch adds the firmware release version. $ ethtool -i wlan4 driver: brcmfmac version: 6.10.224.22 firmware-version: 01-32bd010f Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/core.c | 4 +++- drivers/net/wireless/brcm80211/brcmutil/utils.c | 27 ++++++++++++++++++++++ .../net/wireless/brcm80211/include/brcmu_utils.h | 2 ++ 3 files changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index 6406f95af0d3..8d03588b54bb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c @@ -601,9 +601,11 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; + char drev[BRCMU_DOTREV_LEN]; strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - snprintf(info->version, sizeof(info->version), "n/a"); + strlcpy(info->version, brcmu_dotrev_str(drvr->revinfo.driverrev, drev), + sizeof(info->version)); strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version)); strlcpy(info->bus_info, dev_name(drvr->bus_if->dev), sizeof(info->bus_info)); diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c index 34937d8e1395..0543607002fd 100644 --- a/drivers/net/wireless/brcm80211/brcmutil/utils.c +++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c @@ -277,6 +277,33 @@ char *brcmu_boardrev_str(u32 brev, char *buf) } EXPORT_SYMBOL(brcmu_boardrev_str); +char *brcmu_dotrev_str(u32 dotrev, char *buf) +{ + u8 dotval[4]; + + if (!dotrev) { + snprintf(buf, BRCMU_DOTREV_LEN, "unknown"); + return buf; + } + dotval[0] = (dotrev >> 24) & 0xFF; + dotval[1] = (dotrev >> 16) & 0xFF; + dotval[2] = (dotrev >> 8) & 0xFF; + dotval[3] = dotrev & 0xFF; + + if (dotval[3]) + snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d.%d.%d", dotval[0], + dotval[1], dotval[2], dotval[3]); + else if (dotval[2]) + snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d.%d", dotval[0], + dotval[1], dotval[2]); + else + snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d", dotval[0], + dotval[1]); + + return buf; +} +EXPORT_SYMBOL(brcmu_dotrev_str); + #if defined(DEBUG) /* pretty hex print a pkt buffer chain */ void brcmu_prpkt(const char *msg, struct sk_buff *p0) diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h index 197317b3fa70..41969527b459 100644 --- a/drivers/net/wireless/brcm80211/include/brcmu_utils.h +++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h @@ -219,7 +219,9 @@ void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...) #endif #define BRCMU_BOARDREV_LEN 8 +#define BRCMU_DOTREV_LEN 16 char *brcmu_boardrev_str(u32 brev, char *buf); +char *brcmu_dotrev_str(u32 dotrev, char *buf); #endif /* _BRCMU_UTILS_H_ */ -- cgit v1.2.1 From 7f52c81d02a27943e0c45103d7d10f629b0b58ae Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 25 Jan 2015 20:31:42 +0100 Subject: brcmfmac: store revinfo retrieval result When revinfo retrieval fails we can not show the firmware version in ethtool driver info. Store the result to be used when handling ethtool driver info callback. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/common.c | 3 ++- drivers/net/wireless/brcm80211/brcmfmac/core.c | 7 ++++--- drivers/net/wireless/brcm80211/brcmfmac/core.h | 10 +++++++++- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/common.c b/drivers/net/wireless/brcm80211/brcmfmac/common.c index 91213a650017..fe54844c75e0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/common.c @@ -57,10 +57,10 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO, &revinfo, sizeof(revinfo)); + ri = &ifp->drvr->revinfo; if (err < 0) { brcmf_err("retrieving revision info failed, %d\n", err); } else { - ri = &ifp->drvr->revinfo; ri->vendorid = le32_to_cpu(revinfo.vendorid); ri->deviceid = le32_to_cpu(revinfo.deviceid); ri->radiorev = le32_to_cpu(revinfo.radiorev); @@ -79,6 +79,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) ri->chippkg = le32_to_cpu(revinfo.chippkg); ri->nvramrev = le32_to_cpu(revinfo.nvramrev); } + ri->result = err; /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index 8d03588b54bb..2d6e2cc1b12c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c @@ -601,11 +601,12 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; - char drev[BRCMU_DOTREV_LEN]; + char drev[BRCMU_DOTREV_LEN] = "n/a"; + if (drvr->revinfo.result == 0) + brcmu_dotrev_str(drvr->revinfo.driverrev, drev); strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - strlcpy(info->version, brcmu_dotrev_str(drvr->revinfo.driverrev, drev), - sizeof(info->version)); + strlcpy(info->version, drev, sizeof(info->version)); strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version)); strlcpy(info->bus_info, dev_name(drvr->bus_if->dev), sizeof(info->bus_info)); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index db7f35f141e7..fd74a9c6e9ac 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h @@ -71,8 +71,16 @@ struct brcmf_proto; /* device communication protocol info */ struct brcmf_cfg80211_dev; /* cfg80211 device info */ struct brcmf_fws_info; /* firmware signalling info */ -/* see struct brcmf_rev_info_le in fwil_types.h */ +/* + * struct brcmf_rev_info + * + * The result field stores the error code of the + * revision info request from firmware. For the + * other fields see struct brcmf_rev_info_le in + * fwil_types.h + */ struct brcmf_rev_info { + int result; u32 vendorid; u32 deviceid; u32 radiorev; -- cgit v1.2.1 From 4165fe9a9287aa9c8e7e4152c21ee179d49d129e Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 25 Jan 2015 20:31:43 +0100 Subject: brcmfmac: fix nvram processing The nvram file can hold a key=value combination in which the value may have spaces, ie. 'RAW1=80 02 fe ff'. The parsing functionality did not deal with this so it gives an error message: [621746.311635] brcmfmac: brcmf_nvram_handle_key warning: ln=90:col=11: '=' expected, skip invalid key entry because RAW1=80 is being considerd as key=value pair and it expects '=' sign after '02' for next key=value pair. This entry can be completely ignored as firmware does not need it. Reviewed-by: Hante Meuleman Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/firmware.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c index 1ff787d1a36b..9cb99152ad17 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c @@ -103,7 +103,11 @@ static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp) c = nvp->fwnv->data[nvp->pos]; if (c == '=') { - st = VALUE; + /* ignore RAW1 by treating as comment */ + if (strncmp(&nvp->fwnv->data[nvp->entry], "RAW1", 4) == 0) + st = COMMENT; + else + st = VALUE; } else if (!is_nvram_char(c)) { brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n", nvp->line, nvp->column); -- cgit v1.2.1 From e52a85d383d505ee7654ba993a6a31eeee79f232 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:41:58 +0530 Subject: mwifiex: remove redundant nick_name variable This is not used anywhere execpt initialization. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.c | 1 - drivers/net/wireless/mwifiex/main.h | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 9836df0eb1e7..99cd3604b3f3 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -968,7 +968,6 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, /* Initialize private structure */ priv->current_key_index = 0; priv->media_connected = false; - memset(&priv->nick_name, 0, sizeof(priv->nick_name)); memset(priv->mgmt_ie, 0, sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX); priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 55273eefb785..99792b885b79 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -553,7 +553,6 @@ struct mwifiex_private { #ifdef CONFIG_DEBUG_FS struct dentry *dfs_dev_dir; #endif - u8 nick_name[16]; u16 current_key_index; struct semaphore async_sem; struct cfg80211_scan_request *scan_request; -- cgit v1.2.1 From 09f63ae65f907a7fadf7fcf408f80909cbf2af4b Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:41:59 +0530 Subject: mwifiex: set wiphy params only once RTS threshold, fragmentation threshold are per device properties. Setting them on any interface would be reflected for all other interfaces as well. This patch removes unnesessary command download per interface. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 111 ++++++++++++++------------------ 1 file changed, 48 insertions(+), 63 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 7be1e9b83fd0..dd0e410559f8 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -590,77 +590,62 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; struct mwifiex_uap_bss_param *bss_cfg; - int ret, bss_started, i; - - for (i = 0; i < adapter->priv_num; i++) { - priv = adapter->priv[i]; - - switch (priv->bss_role) { - case MWIFIEX_BSS_ROLE_UAP: - bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), - GFP_KERNEL); - if (!bss_cfg) - return -ENOMEM; - - mwifiex_set_sys_config_invalid_data(bss_cfg); - - if (changed & WIPHY_PARAM_RTS_THRESHOLD) - bss_cfg->rts_threshold = wiphy->rts_threshold; - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) - bss_cfg->frag_threshold = wiphy->frag_threshold; - if (changed & WIPHY_PARAM_RETRY_LONG) - bss_cfg->retry_limit = wiphy->retry_long; - - bss_started = priv->bss_started; - - ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, - HostCmd_ACT_GEN_SET, 0, - NULL, true); - if (ret) { - wiphy_err(wiphy, "Failed to stop the BSS\n"); - kfree(bss_cfg); - return ret; - } + int ret; - ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, - HostCmd_ACT_GEN_SET, - UAP_BSS_PARAMS_I, bss_cfg, - false); + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - kfree(bss_cfg); + switch (priv->bss_role) { + case MWIFIEX_BSS_ROLE_UAP: + if (priv->bss_started) { + dev_err(adapter->dev, + "cannot change wiphy params when bss started"); + return -EINVAL; + } - if (ret) { - wiphy_err(wiphy, "Failed to set bss config\n"); - return ret; - } + bss_cfg = kzalloc(sizeof(*bss_cfg), GFP_KERNEL); + if (!bss_cfg) + return -ENOMEM; - if (!bss_started) - break; + mwifiex_set_sys_config_invalid_data(bss_cfg); - ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, - HostCmd_ACT_GEN_SET, 0, - NULL, false); - if (ret) { - wiphy_err(wiphy, "Failed to start BSS\n"); - return ret; - } + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + bss_cfg->rts_threshold = wiphy->rts_threshold; + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + bss_cfg->frag_threshold = wiphy->frag_threshold; + if (changed & WIPHY_PARAM_RETRY_LONG) + bss_cfg->retry_limit = wiphy->retry_long; + + ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg, + false); + + kfree(bss_cfg); + if (ret) { + wiphy_err(wiphy, "Failed to set wiphy phy params\n"); + return ret; + } + break; - break; case MWIFIEX_BSS_ROLE_STA: - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - ret = mwifiex_set_rts(priv, - wiphy->rts_threshold); - if (ret) - return ret; - } - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { - ret = mwifiex_set_frag(priv, - wiphy->frag_threshold); - if (ret) - return ret; - } - break; + if (priv->media_connected) { + dev_err(adapter->dev, + "cannot change wiphy params when connected"); + return -EINVAL; + } + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + ret = mwifiex_set_rts(priv, + wiphy->rts_threshold); + if (ret) + return ret; } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + ret = mwifiex_set_frag(priv, + wiphy->frag_threshold); + if (ret) + return ret; + } + break; } return 0; -- cgit v1.2.1 From 4facc34a1f1d6ba8fafc9afdb84f9c6ed4334c4c Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:42:00 +0530 Subject: mwifiex: do not declare wdev as pointer wdev is used even after del_virtual_interface handler in cfg80211 in nl80211_post_doit. Since we have freed wdev in handling of del_virtual_intf, this can result into crash while deleting interface. Avoid this be not declaring wdev which part of mwifiex_private structure but struct wireless_dev type. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11h.c | 2 +- drivers/net/wireless/mwifiex/11n.c | 4 +- drivers/net/wireless/mwifiex/11n_rxreorder.c | 2 +- drivers/net/wireless/mwifiex/cfg80211.c | 70 ++++++++++------------------ drivers/net/wireless/mwifiex/cfp.c | 4 +- drivers/net/wireless/mwifiex/main.c | 5 +- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/scan.c | 10 ++-- drivers/net/wireless/mwifiex/sta_event.c | 2 +- drivers/net/wireless/mwifiex/sta_ioctl.c | 2 +- drivers/net/wireless/mwifiex/txrx.c | 2 +- drivers/net/wireless/mwifiex/util.c | 2 +- 12 files changed, 44 insertions(+), 63 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c index 2668e83afbb6..f23b647a1411 100644 --- a/drivers/net/wireless/mwifiex/11h.c +++ b/drivers/net/wireless/mwifiex/11h.c @@ -39,7 +39,7 @@ mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer, return; radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); - sband = priv->wdev->wiphy->bands[radio_type]; + sband = priv->wdev.wiphy->bands[radio_type]; cap = (struct mwifiex_ie_types_pwr_capability *)*buffer; cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY); diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index c5c83cf664d8..543148d27b01 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -39,7 +39,7 @@ int mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, { uint16_t ht_ext_cap = le16_to_cpu(ht_cap->extended_ht_cap_info); struct ieee80211_supported_band *sband = - priv->wdev->wiphy->bands[radio_type]; + priv->wdev.wiphy->bands[radio_type]; if (WARN_ON_ONCE(!sband)) { dev_err(priv->adapter->dev, "Invalid radio type!\n"); @@ -314,7 +314,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, return ret_len; radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); - sband = priv->wdev->wiphy->bands[radio_type]; + sband = priv->wdev.wiphy->bands[radio_type]; if (bss_desc->bcn_ht_cap) { ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index c7ca5b734875..a2e8817b56d8 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv, skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length)); ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, - priv->wdev->iftype, 0, false); + priv->wdev.iftype, 0, false); while (!skb_queue_empty(&list)) { rx_skb = __skb_dequeue(&list); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index dd0e410559f8..9710b23f65a9 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1590,15 +1590,15 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) ie_len = ie_buf[1] + sizeof(struct ieee_types_header); band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); - chan = __ieee80211_get_channel(priv->wdev->wiphy, + chan = __ieee80211_get_channel(priv->wdev.wiphy, ieee80211_channel_to_frequency(bss_info.bss_chan, band)); - bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, + bss = cfg80211_inform_bss(priv->wdev.wiphy, chan, CFG80211_BSS_FTYPE_UNKNOWN, bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, 0, ie_buf, ie_len, 0, GFP_KERNEL); - cfg80211_put_bss(priv->wdev->wiphy, bss); + cfg80211_put_bss(priv->wdev.wiphy, bss); memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); return 0; @@ -1719,12 +1719,12 @@ done: /* Find the BSS we want using available scan results */ if (mode == NL80211_IFTYPE_ADHOC) - bss = cfg80211_get_bss(priv->wdev->wiphy, channel, + bss = cfg80211_get_bss(priv->wdev.wiphy, channel, bssid, ssid, ssid_len, WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); else - bss = cfg80211_get_bss(priv->wdev->wiphy, channel, + bss = cfg80211_get_bss(priv->wdev.wiphy, channel, bssid, ssid, ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); @@ -1781,7 +1781,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } - if (priv->wdev && priv->wdev->current_bss) { + if (priv->wdev.current_bss) { wiphy_warn(wiphy, "%s: already connected\n", dev->name); return -EALREADY; } @@ -1839,7 +1839,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, static int mwifiex_set_ibss_params(struct mwifiex_private *priv, struct cfg80211_ibss_params *params) { - struct wiphy *wiphy = priv->wdev->wiphy; + struct wiphy *wiphy = priv->wdev.wiphy; struct mwifiex_adapter *adapter = priv->adapter; int index = 0, i; u8 config_bands = 0; @@ -2177,7 +2177,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, struct mwifiex_private *priv; struct net_device *dev; void *mdev_priv; - struct wireless_dev *wdev; if (!adapter) return ERR_PTR(-EFAULT); @@ -2193,13 +2192,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-EINVAL); } - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); - if (!wdev) - return ERR_PTR(-ENOMEM); - - wdev->wiphy = wiphy; - priv->wdev = wdev; - wdev->iftype = NL80211_IFTYPE_STATION; + priv->wdev.wiphy = wiphy; + priv->wdev.iftype = NL80211_IFTYPE_STATION; if (type == NL80211_IFTYPE_UNSPECIFIED) priv->bss_mode = NL80211_IFTYPE_STATION; @@ -2221,13 +2215,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-EINVAL); } - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); - if (!wdev) - return ERR_PTR(-ENOMEM); - - priv->wdev = wdev; - wdev->wiphy = wiphy; - wdev->iftype = NL80211_IFTYPE_AP; + priv->wdev.wiphy = wiphy; + priv->wdev.iftype = NL80211_IFTYPE_AP; priv->bss_type = MWIFIEX_BSS_TYPE_UAP; priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; @@ -2246,17 +2235,12 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-EINVAL); } - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); - if (!wdev) - return ERR_PTR(-ENOMEM); - - priv->wdev = wdev; - wdev->wiphy = wiphy; + priv->wdev.wiphy = wiphy; /* At start-up, wpa_supplicant tries to change the interface * to NL80211_IFTYPE_STATION if it is not managed mode. */ - wdev->iftype = NL80211_IFTYPE_P2P_CLIENT; + priv->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT; priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT; /* Setting bss_type to P2P tells firmware that this interface @@ -2272,8 +2256,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->bss_num = 0; if (mwifiex_cfg80211_init_p2p_client(priv)) { - wdev = ERR_PTR(-EFAULT); - goto done; + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-EFAULT); } break; @@ -2287,9 +2272,10 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, IEEE80211_NUM_ACS, 1); if (!dev) { wiphy_err(wiphy, "no memory available for netdevice\n"); + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - wdev = ERR_PTR(-ENOMEM); - goto done; + return ERR_PTR(-ENOMEM); } mwifiex_init_priv_params(priv, dev); @@ -2309,7 +2295,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, &wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv); dev_net_set(dev, wiphy_net(wiphy)); - dev->ieee80211_ptr = priv->wdev; + dev->ieee80211_ptr = &priv->wdev; dev->ieee80211_ptr->iftype = priv->bss_mode; memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); @@ -2330,8 +2316,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, free_netdev(dev); priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; priv->netdev = NULL; - wdev = ERR_PTR(-EFAULT); - goto done; + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-EFAULT); } sema_init(&priv->async_sem, 1); @@ -2342,13 +2329,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, mwifiex_dev_debugfs_init(priv); #endif -done: - if (IS_ERR(wdev)) { - kfree(priv->wdev); - priv->wdev = NULL; - } - - return wdev; + return &priv->wdev; } EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); @@ -2374,8 +2355,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) /* Clear the priv in adapter */ priv->netdev->ieee80211_ptr = NULL; priv->netdev = NULL; - kfree(wdev); - priv->wdev = NULL; + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; priv->media_connected = false; diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index f494fc7eeb62..e9df8826f124 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -322,9 +322,9 @@ mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq) return cfp; if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) - sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; + sband = priv->wdev.wiphy->bands[IEEE80211_BAND_2GHZ]; else - sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; + sband = priv->wdev.wiphy->bands[IEEE80211_BAND_5GHZ]; if (!sband) { dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d\n", diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 99cd3604b3f3..49dec6b4dc96 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -1203,8 +1203,9 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) continue; rtnl_lock(); - if (priv->wdev && priv->netdev) - mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); + if (priv->netdev && + priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) + mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); rtnl_unlock(); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 99792b885b79..a560179cdb7b 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -547,7 +547,7 @@ struct mwifiex_private { u32 curr_bcn_size; /* spin lock for beacon buffer */ spinlock_t curr_bcn_buf_lock; - struct wireless_dev *wdev; + struct wireless_dev wdev; struct mwifiex_chan_freq_power cfp; char version_str[128]; #ifdef CONFIG_DEBUG_FS diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index e304f0731647..0ffdb7c5afd2 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -496,10 +496,10 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) { - if (!priv->wdev->wiphy->bands[band]) + if (!priv->wdev.wiphy->bands[band]) continue; - sband = priv->wdev->wiphy->bands[band]; + sband = priv->wdev.wiphy->bands[band]; for (i = 0; (i < sband->n_channels) ; i++) { ch = &sband->channels[i]; @@ -1733,10 +1733,10 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, freq = cfp ? cfp->freq : 0; - chan = ieee80211_get_channel(priv->wdev->wiphy, freq); + chan = ieee80211_get_channel(priv->wdev.wiphy, freq); if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { - bss = cfg80211_inform_bss(priv->wdev->wiphy, + bss = cfg80211_inform_bss(priv->wdev.wiphy, chan, CFG80211_BSS_FTYPE_UNKNOWN, bssid, timestamp, cap_info_bitmap, beacon_period, @@ -1748,7 +1748,7 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, !memcmp(bssid, priv->curr_bss_params.bss_descriptor .mac_address, ETH_ALEN)) mwifiex_update_curr_bss_params(priv, bss); - cfg80211_put_bss(priv->wdev->wiphy, bss); + cfg80211_put_bss(priv->wdev.wiphy, bss); } } else { dev_dbg(adapter->dev, "missing BSS channel IE\n"); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 419e35f1dbf3..c37e8cb2dd32 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -487,7 +487,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_REMAIN_ON_CHAN_EXPIRED: dev_dbg(adapter->dev, "event: Remain on channel expired\n"); - cfg80211_remain_on_channel_expired(priv->wdev, + cfg80211_remain_on_channel_expired(&priv->wdev, priv->roc_cfg.cookie, &priv->roc_cfg.chan, GFP_ATOMIC); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index fb9c5fc83e5d..329cd515316c 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -219,7 +219,7 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv, if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) { rcu_read_unlock(); - wiphy_dbg(priv->wdev->wiphy, + wiphy_dbg(priv->wdev.wiphy, "11D: skip setting domain info in FW\n"); return 0; } diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 6ae133333363..ac93557cbdc9 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -227,7 +227,7 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, /* consumes ack_skb */ skb_complete_wifi_ack(ack_skb, !tx_status->status); } else { - cfg80211_mgmt_tx_status(priv->wdev, tx_info->cookie, + cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie, ack_skb->data, ack_skb->len, !tx_status->status, GFP_ATOMIC); dev_kfree_skb_any(ack_skb); diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 707319799942..308550611f22 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -387,7 +387,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, pkt_len -= ETH_ALEN + sizeof(pkt_len); rx_pd->rx_pkt_length = cpu_to_le16(pkt_len); - cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq, + cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq, CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len, 0); -- cgit v1.2.1 From 8d05eb222074169c22c9d2707f607cf762f8d027 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:42:01 +0530 Subject: mwifiex: store permanant mac address in adapter structure This would be used to set mac address while changing virtual interface to different types. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 2 +- drivers/net/wireless/mwifiex/cmdevt.c | 4 +--- drivers/net/wireless/mwifiex/init.c | 1 + drivers/net/wireless/mwifiex/main.c | 1 + drivers/net/wireless/mwifiex/main.h | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 9710b23f65a9..85f5019306b5 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2974,7 +2974,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->cipher_suites = mwifiex_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); - memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN); + ether_addr_copy(wiphy->perm_addr, adapter->perm_addr); wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 946a2f7a172f..00586b22c61a 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1582,9 +1582,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, le16_to_cpu(hw_spec->hw_if_version), le16_to_cpu(hw_spec->version)); - if (priv->curr_addr[0] == 0xff) - memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN); - + ether_addr_copy(priv->adapter->perm_addr, hw_spec->permanent_addr); adapter->region_code = le16_to_cpu(hw_spec->region_code); for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++) diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 8004d140ee01..44babc329fda 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -297,6 +297,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->ext_scan = false; adapter->key_api_major_ver = 0; adapter->key_api_minor_ver = 0; + memset(adapter->perm_addr, 0xff, ETH_ALEN); setup_timer(&adapter->wakeup_timer, wakeup_timer_fn, (unsigned long)adapter); diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 49dec6b4dc96..cb9cab2b0ec0 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -975,6 +975,7 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK; priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; priv->num_tx_timeout = 0; + ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr); memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index a560179cdb7b..45b40af9797b 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -737,6 +737,7 @@ struct mwifiex_adapter { int winner; struct device *dev; struct wiphy *wiphy; + u8 perm_addr[ETH_ALEN]; bool surprise_removed; u32 fw_release_number; u16 init_wait_q_woken; -- cgit v1.2.1 From 1247cc1f43905441821faa56d9a815e852afe235 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:42:02 +0530 Subject: mwifiex: add init parameter to init command routine FW initialization routine can also be called while changing virtual interface types. This patch adds bool parameter "init" to init command routine so as to differentiate between initialization during driver load and change virtual interface handler. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/init.c | 3 ++- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/sta_cmd.c | 13 ++++++++----- drivers/net/wireless/mwifiex/sta_ioctl.c | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 44babc329fda..2975b5154c39 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -552,7 +552,8 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { - ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta); + ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta, + true); if (ret == -1) return -1; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 45b40af9797b..9686bd8603c8 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -989,7 +989,7 @@ void mwifiex_wmm_del_peer_ra_list(struct mwifiex_private *priv, const u8 *ra_addr); void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); void *mwifiex_process_uap_txpd(struct mwifiex_private *, struct sk_buff *skb); -int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); +int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta, bool init); int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, struct mwifiex_scan_cmd_config *scan_cfg); void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index f7b920d7a95a..92a66e8b6636 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1911,6 +1911,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, * * This is called after firmware download to bring the card to * working state. + * Function is also called during reinitialization of virtual + * interfaces. * * The following commands are issued sequentially - * - Set PCI-Express host buffer configuration (PCIE only) @@ -1925,7 +1927,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, * - Set 11d control * - Set MAC control (this must be the last command to initialize firmware) */ -int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) +int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) { struct mwifiex_adapter *adapter = priv->adapter; int ret; @@ -2059,9 +2061,6 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) "11D: failed to enable 11D\n"); } - /* set last_init_cmd before sending the command */ - priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG; - /* Send cmd to FW to configure 11n specific configuration * (Short GI, Channel BW, Green field support etc.) for transmit */ @@ -2069,7 +2068,11 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_CFG, HostCmd_ACT_GEN_SET, 0, &tx_cfg, true); - ret = -EINPROGRESS; + if (init) { + /* set last_init_cmd before sending the command */ + priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG; + ret = -EINPROGRESS; + } return ret; } diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 329cd515316c..2faa5174fe73 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -1162,7 +1162,7 @@ mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role) mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, HostCmd_ACT_GEN_SET, 0, NULL, true); - return mwifiex_sta_init_cmd(priv, false); + return mwifiex_sta_init_cmd(priv, false, false); } /* -- cgit v1.2.1 From cf0523350c6f12bdffb06c7000326edb296ec450 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:42:03 +0530 Subject: mwifiex: manage virtual interface limits efficiently Currently interface limits are checked by seeing if bss_mode for particular priv is set. If bss_mode is not set, interface creation is allowed. This patch adds framework to initializes maximum virtual interfaces supported during load time and check current number of interfaces created agains allowed interface limit during new virtual interface creation. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 80 ++++++++++++++++++++++++++++----- drivers/net/wireless/mwifiex/decl.h | 10 +++++ drivers/net/wireless/mwifiex/init.c | 3 ++ drivers/net/wireless/mwifiex/main.h | 21 +++++++++ 4 files changed, 102 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 85f5019306b5..a0221b5eff93 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2185,13 +2185,20 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: - priv = adapter->priv[MWIFIEX_BSS_TYPE_STA]; - if (priv->bss_mode) { + if (adapter->curr_iface_comb.sta_intf == + adapter->iface_limit.sta_intf) { wiphy_err(wiphy, "cannot create multiple sta/adhoc ifaces\n"); return ERR_PTR(-EINVAL); } + priv = mwifiex_get_unused_priv(adapter); + if (!priv) { + wiphy_err(wiphy, + "could not get free private struct\n"); + return ERR_PTR(-EFAULT); + } + priv->wdev.wiphy = wiphy; priv->wdev.iftype = NL80211_IFTYPE_STATION; @@ -2208,13 +2215,20 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, break; case NL80211_IFTYPE_AP: - priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP]; - - if (priv->bss_mode) { - wiphy_err(wiphy, "Can't create multiple AP interfaces"); + if (adapter->curr_iface_comb.uap_intf == + adapter->iface_limit.uap_intf) { + wiphy_err(wiphy, + "cannot create multiple AP ifaces\n"); return ERR_PTR(-EINVAL); } + priv = mwifiex_get_unused_priv(adapter); + if (!priv) { + wiphy_err(wiphy, + "could not get free private struct\n"); + return ERR_PTR(-EFAULT); + } + priv->wdev.wiphy = wiphy; priv->wdev.iftype = NL80211_IFTYPE_AP; @@ -2228,15 +2242,21 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, break; case NL80211_IFTYPE_P2P_CLIENT: - priv = adapter->priv[MWIFIEX_BSS_TYPE_P2P]; - - if (priv->bss_mode) { - wiphy_err(wiphy, "Can't create multiple P2P ifaces"); + if (adapter->curr_iface_comb.p2p_intf == + adapter->iface_limit.p2p_intf) { + wiphy_err(wiphy, + "cannot create multiple P2P ifaces\n"); return ERR_PTR(-EINVAL); } - priv->wdev.wiphy = wiphy; + priv = mwifiex_get_unused_priv(adapter); + if (!priv) { + wiphy_err(wiphy, + "could not get free private struct\n"); + return ERR_PTR(-EFAULT); + } + priv->wdev.wiphy = wiphy; /* At start-up, wpa_supplicant tries to change the interface * to NL80211_IFTYPE_STATION if it is not managed mode. */ @@ -2329,6 +2349,23 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, mwifiex_dev_debugfs_init(priv); #endif + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + adapter->curr_iface_comb.sta_intf++; + break; + case NL80211_IFTYPE_AP: + adapter->curr_iface_comb.uap_intf++; + break; + case NL80211_IFTYPE_P2P_CLIENT: + adapter->curr_iface_comb.p2p_intf++; + break; + default: + wiphy_err(wiphy, "type not supported\n"); + return ERR_PTR(-EINVAL); + } + return &priv->wdev; } EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); @@ -2339,12 +2376,13 @@ EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); + struct mwifiex_adapter *adapter = priv->adapter; #ifdef CONFIG_DEBUG_FS mwifiex_dev_debugfs_remove(priv); #endif - mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); @@ -2359,6 +2397,24 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) priv->media_connected = false; + switch (priv->bss_mode) { + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + adapter->curr_iface_comb.sta_intf++; + break; + case NL80211_IFTYPE_AP: + adapter->curr_iface_comb.uap_intf++; + break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + adapter->curr_iface_comb.p2p_intf++; + break; + default: + dev_err(adapter->dev, "del_virtual_intf: type not supported\n"); + break; + } + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 7aa988e1dc7a..4481ac40c3eb 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -104,6 +104,10 @@ /* Rate index for OFDM 0 */ #define MWIFIEX_RATE_INDEX_OFDM0 4 +#define MWIFIEX_MAX_STA_NUM 1 +#define MWIFIEX_MAX_UAP_NUM 1 +#define MWIFIEX_MAX_P2P_NUM 1 + enum mwifiex_bss_type { MWIFIEX_BSS_TYPE_STA = 0, MWIFIEX_BSS_TYPE_UAP = 1, @@ -232,4 +236,10 @@ struct mwifiex_histogram_data { atomic_t num_samples; }; +struct mwifiex_iface_comb { + u8 sta_intf; + u8 uap_intf; + u8 p2p_intf; +}; + #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 2975b5154c39..1d1c3c8e516e 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -298,6 +298,9 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->key_api_major_ver = 0; adapter->key_api_minor_ver = 0; memset(adapter->perm_addr, 0xff, ETH_ALEN); + adapter->iface_limit.sta_intf = MWIFIEX_MAX_STA_NUM; + adapter->iface_limit.uap_intf = MWIFIEX_MAX_UAP_NUM; + adapter->iface_limit.p2p_intf = MWIFIEX_MAX_P2P_NUM; setup_timer(&adapter->wakeup_timer, wakeup_timer_fn, (unsigned long)adapter); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 9686bd8603c8..78304a714512 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -730,6 +730,8 @@ struct mwifiex_if_ops { struct mwifiex_adapter { u8 iface_type; + struct mwifiex_iface_comb iface_limit; + struct mwifiex_iface_comb curr_iface_comb; struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; u8 priv_num; const struct firmware *firmware; @@ -1149,6 +1151,25 @@ mwifiex_get_priv(struct mwifiex_adapter *adapter, return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); } +/* + * This function returns the first available unused private structure pointer. + */ +static inline struct mwifiex_private * +mwifiex_get_unused_priv(struct mwifiex_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + if (adapter->priv[i]->bss_mode == + NL80211_IFTYPE_UNSPECIFIED) + break; + } + } + + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + /* * This function returns the driver private structure of a network device. */ -- cgit v1.2.1 From 76c504ca1e7de8555cbf18a0ef08d29ee462c8eb Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:42:04 +0530 Subject: mwifiex: handle PS events on AP interface as well This patch adds support to handle PS events on AP interface as well. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 36 ++++++++++++----------------- drivers/net/wireless/mwifiex/uap_event.c | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 00586b22c61a..c5a14ff7eb82 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -315,22 +315,19 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++; return -1; } - if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY)) - == MWIFIEX_BSS_ROLE_STA) { - if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl)) - /* Response is not needed for sleep - confirm command */ - adapter->ps_state = PS_STATE_SLEEP; - else - adapter->ps_state = PS_STATE_SLEEP_CFM; - - if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl) && - (adapter->is_hs_configured && - !adapter->sleep_period.period)) { - adapter->pm_wakeup_card_req = true; - mwifiex_hs_activated_event(mwifiex_get_priv - (adapter, MWIFIEX_BSS_ROLE_STA), true); - } + + if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl)) + /* Response is not needed for sleep confirm command */ + adapter->ps_state = PS_STATE_SLEEP; + else + adapter->ps_state = PS_STATE_SLEEP_CFM; + + if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl) && + (adapter->is_hs_configured && + !adapter->sleep_period.period)) { + adapter->pm_wakeup_card_req = true; + mwifiex_hs_activated_event(mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), true); } return ret; @@ -450,6 +447,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) EVENT_GET_BSS_TYPE(eventcause)); if (!priv) priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + /* Clear BSS_NO_BITS from event */ eventcause &= EVENT_ID_MASK; adapter->event_cause = eventcause; @@ -462,12 +460,6 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) } dev_dbg(adapter->dev, "EVENT: cause: %#x\n", eventcause); - if (eventcause == EVENT_PS_SLEEP || eventcause == EVENT_PS_AWAKE) { - /* Handle PS_SLEEP/AWAKE events on STA */ - priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); - if (!priv) - priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - } if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) ret = mwifiex_process_uap_event(priv); diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 96ff39722f8f..9b4ca6ff7931 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -177,6 +177,45 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) case EVENT_TX_STATUS_REPORT: dev_dbg(adapter->dev, "event: TX_STATUS Report\n"); mwifiex_parse_tx_status_event(priv, adapter->event_body); + break; + case EVENT_PS_SLEEP: + dev_dbg(adapter->dev, "info: EVENT: SLEEP\n"); + + adapter->ps_state = PS_STATE_PRE_SLEEP; + + mwifiex_check_ps_cond(adapter); + break; + + case EVENT_PS_AWAKE: + dev_dbg(adapter->dev, "info: EVENT: AWAKE\n"); + if (!adapter->pps_uapsd_mode && + priv->media_connected && adapter->sleep_period.period) { + adapter->pps_uapsd_mode = true; + dev_dbg(adapter->dev, + "event: PPS/UAPSD mode activated\n"); + } + adapter->tx_lock_flag = false; + if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) { + if (mwifiex_check_last_packet_indication(priv)) { + if (adapter->data_sent) { + adapter->ps_state = PS_STATE_AWAKE; + adapter->pm_wakeup_card_req = false; + adapter->pm_wakeup_fw_try = false; + break; + } + if (!mwifiex_send_null_packet + (priv, + MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) + adapter->ps_state = + PS_STATE_SLEEP; + return 0; + } + } + adapter->ps_state = PS_STATE_AWAKE; + adapter->pm_wakeup_card_req = false; + adapter->pm_wakeup_fw_try = false; + break; default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", -- cgit v1.2.1 From 047eaaf64503c2902d1e054d5b944de18d14b28c Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:42:05 +0530 Subject: mwifiex: support conversion to any virtual interface type Currently, we support virtual interface type change from station<=>adhoc or station <=> p2p client/GO. This patch adds support to change virtual interface type to any of the type advertised in interface combinations. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 331 ++++++++++++++++++++++++++++--- drivers/net/wireless/mwifiex/main.c | 2 +- drivers/net/wireless/mwifiex/main.h | 2 - drivers/net/wireless/mwifiex/sta_ioctl.c | 30 --- 4 files changed, 301 insertions(+), 64 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index a0221b5eff93..30ea94a1767c 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -656,9 +656,6 @@ mwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv) { u16 mode = P2P_MODE_DISABLE; - if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) - mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA); - if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, HostCmd_ACT_GEN_SET, 0, &mode, true)) return -1; @@ -715,12 +712,249 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv) HostCmd_ACT_GEN_SET, 0, &mode, true)) return -1; - if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) - mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_UAP); + return 0; +} + +static int mwifiex_deinit_priv_params(struct mwifiex_private *priv) +{ + priv->mgmt_frame_mask = 0; + if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, + HostCmd_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask, false)) { + dev_warn(priv->adapter->dev, + "could not unregister mgmt frame rx\n"); + return -1; + } + + mwifiex_deauthenticate(priv, NULL); + mwifiex_free_priv(priv); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; + + return 0; +} + +static int +mwifiex_init_new_priv_params(struct mwifiex_private *priv, + struct net_device *dev, + enum nl80211_iftype type) +{ + mwifiex_init_priv(priv); + + priv->bss_mode = type; + priv->wdev.iftype = type; + + mwifiex_init_priv_params(priv, priv->netdev); + priv->bss_started = 0; + + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + priv->bss_role = MWIFIEX_BSS_ROLE_STA; + priv->bss_type = MWIFIEX_BSS_TYPE_STA; + break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + priv->bss_role = MWIFIEX_BSS_ROLE_STA; + priv->bss_type = MWIFIEX_BSS_TYPE_P2P; + break; + case NL80211_IFTYPE_AP: + priv->bss_type = MWIFIEX_BSS_TYPE_UAP; + priv->bss_role = MWIFIEX_BSS_ROLE_UAP; + break; + default: + dev_err(priv->adapter->dev, + "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } + + return 0; +} + +static int +mwifiex_change_vif_to_p2p(struct net_device *dev, + enum nl80211_iftype curr_iftype, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct mwifiex_private *priv; + struct mwifiex_adapter *adapter; + + priv = mwifiex_netdev_get_priv(dev); + + if (!priv) + return -1; + + adapter = priv->adapter; + + if (adapter->curr_iface_comb.p2p_intf == + adapter->iface_limit.p2p_intf) { + dev_err(adapter->dev, + "cannot create multiple P2P ifaces\n"); + return -1; + } + + dev_dbg(priv->adapter->dev, "%s: changing role to p2p\n", dev->name); + + if (mwifiex_deinit_priv_params(priv)) + return -1; + if (mwifiex_init_new_priv_params(priv, dev, type)) + return -1; + + switch (type) { + case NL80211_IFTYPE_P2P_CLIENT: + if (mwifiex_cfg80211_init_p2p_client(priv)) + return -EFAULT; + break; + case NL80211_IFTYPE_P2P_GO: + if (mwifiex_cfg80211_init_p2p_go(priv)) + return -EFAULT; + break; + default: + dev_err(priv->adapter->dev, + "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } + + if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, true)) + return -1; + + if (mwifiex_sta_init_cmd(priv, false, false)) + return -1; + + switch (curr_iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + adapter->curr_iface_comb.sta_intf--; + break; + case NL80211_IFTYPE_AP: + adapter->curr_iface_comb.uap_intf--; + break; + default: + break; + } + + adapter->curr_iface_comb.p2p_intf++; + dev->ieee80211_ptr->iftype = type; return 0; } +static int +mwifiex_change_vif_to_sta_adhoc(struct net_device *dev, + enum nl80211_iftype curr_iftype, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct mwifiex_private *priv; + struct mwifiex_adapter *adapter; + + priv = mwifiex_netdev_get_priv(dev); + + if (!priv) + return -1; + + adapter = priv->adapter; + + if ((curr_iftype != NL80211_IFTYPE_P2P_CLIENT && + curr_iftype != NL80211_IFTYPE_P2P_GO) && + (adapter->curr_iface_comb.sta_intf == + adapter->iface_limit.sta_intf)) { + dev_err(adapter->dev, + "cannot create multiple station/adhoc ifaces\n"); + return -1; + } + + if (type == NL80211_IFTYPE_STATION) + dev_notice(adapter->dev, + "%s: changing role to station\n", dev->name); + else + dev_notice(adapter->dev, + "%s: changing role to adhoc\n", dev->name); + + if (mwifiex_deinit_priv_params(priv)) + return -1; + if (mwifiex_init_new_priv_params(priv, dev, type)) + return -1; + if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, true)) + return -1; + if (mwifiex_sta_init_cmd(priv, false, false)) + return -1; + + switch (curr_iftype) { + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + adapter->curr_iface_comb.p2p_intf--; + break; + case NL80211_IFTYPE_AP: + adapter->curr_iface_comb.uap_intf--; + break; + default: + break; + } + + adapter->curr_iface_comb.sta_intf++; + dev->ieee80211_ptr->iftype = type; + return 0; +} + +static int +mwifiex_change_vif_to_ap(struct net_device *dev, + enum nl80211_iftype curr_iftype, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct mwifiex_private *priv; + struct mwifiex_adapter *adapter; + + priv = mwifiex_netdev_get_priv(dev); + + if (!priv) + return -1; + + adapter = priv->adapter; + + if (adapter->curr_iface_comb.uap_intf == + adapter->iface_limit.uap_intf) { + dev_err(adapter->dev, + "cannot create multiple AP ifaces\n"); + return -1; + } + + dev_notice(adapter->dev, "%s: changing role to AP\n", dev->name); + + if (mwifiex_deinit_priv_params(priv)) + return -1; + if (mwifiex_init_new_priv_params(priv, dev, type)) + return -1; + if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, true)) + return -1; + if (mwifiex_sta_init_cmd(priv, false, false)) + return -1; + + switch (curr_iftype) { + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + adapter->curr_iface_comb.p2p_intf--; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + adapter->curr_iface_comb.sta_intf--; + break; + default: + break; + } + + adapter->curr_iface_comb.uap_intf++; + dev->ieee80211_ptr->iftype = type; + return 0; +} /* * CFG802.11 operation handler to change interface type. */ @@ -730,19 +964,32 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - int ret; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + enum nl80211_iftype curr_iftype = dev->ieee80211_ptr->iftype; - switch (dev->ieee80211_ptr->iftype) { + switch (curr_iftype) { case NL80211_IFTYPE_ADHOC: switch (type) { case NL80211_IFTYPE_STATION: - break; + priv->bss_mode = type; + priv->sec_info.authentication_mode = + NL80211_AUTHTYPE_OPEN_SYSTEM; + dev->ieee80211_ptr->iftype = type; + mwifiex_deauthenticate(priv, NULL); + return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, + true); + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + return mwifiex_change_vif_to_p2p(dev, curr_iftype, + type, flags, params); + case NL80211_IFTYPE_AP: + return mwifiex_change_vif_to_ap(dev, curr_iftype, type, + flags, params); case NL80211_IFTYPE_UNSPECIFIED: wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name); case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */ return 0; - case NL80211_IFTYPE_AP: default: wiphy_err(wiphy, "%s: changing to %d not supported\n", dev->name, type); @@ -752,22 +999,25 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_STATION: switch (type) { case NL80211_IFTYPE_ADHOC: - break; - case NL80211_IFTYPE_P2P_CLIENT: - if (mwifiex_cfg80211_init_p2p_client(priv)) - return -EFAULT; + priv->bss_mode = type; + priv->sec_info.authentication_mode = + NL80211_AUTHTYPE_OPEN_SYSTEM; dev->ieee80211_ptr->iftype = type; - return 0; + mwifiex_deauthenticate(priv, NULL); + return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, + true); + case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: - if (mwifiex_cfg80211_init_p2p_go(priv)) - return -EFAULT; - dev->ieee80211_ptr->iftype = type; - return 0; + return mwifiex_change_vif_to_p2p(dev, curr_iftype, + type, flags, params); + case NL80211_IFTYPE_AP: + return mwifiex_change_vif_to_ap(dev, curr_iftype, type, + flags, params); case NL80211_IFTYPE_UNSPECIFIED: wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name); case NL80211_IFTYPE_STATION: /* This shouldn't happen */ return 0; - case NL80211_IFTYPE_AP: default: wiphy_err(wiphy, "%s: changing to %d not supported\n", dev->name, type); @@ -776,12 +1026,20 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, break; case NL80211_IFTYPE_AP: switch (type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, + type, flags, + params); + break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + return mwifiex_change_vif_to_p2p(dev, curr_iftype, + type, flags, params); case NL80211_IFTYPE_UNSPECIFIED: wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name); case NL80211_IFTYPE_AP: /* This shouldn't happen */ return 0; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_STATION: default: wiphy_err(wiphy, "%s: changing to %d not supported\n", dev->name, type); @@ -792,11 +1050,30 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_P2P_GO: switch (type) { case NL80211_IFTYPE_STATION: - if (mwifiex_cfg80211_deinit_p2p(priv)) + if (mwifiex_cfg80211_init_p2p_client(priv)) return -EFAULT; dev->ieee80211_ptr->iftype = type; + break; + case NL80211_IFTYPE_ADHOC: + if (mwifiex_cfg80211_deinit_p2p(priv)) + return -EFAULT; + return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, + type, flags, + params); + break; + case NL80211_IFTYPE_AP: + if (mwifiex_cfg80211_deinit_p2p(priv)) + return -EFAULT; + return mwifiex_change_vif_to_ap(dev, curr_iftype, type, + flags, params); + case NL80211_IFTYPE_UNSPECIFIED: + wiphy_warn(wiphy, "%s: kept type as P2P\n", dev->name); + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: return 0; default: + wiphy_err(wiphy, "%s: changing to %d not supported\n", + dev->name, type); return -EOPNOTSUPP; } break; @@ -806,16 +1083,8 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, return -EOPNOTSUPP; } - dev->ieee80211_ptr->iftype = type; - priv->bss_mode = type; - mwifiex_deauthenticate(priv, NULL); - - priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; - - ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, - HostCmd_ACT_GEN_SET, 0, NULL, true); - return ret; + return 0; } static void diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index cb9cab2b0ec0..30e519369ba6 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -961,7 +961,7 @@ static const struct net_device_ops mwifiex_netdev_ops = { * In addition, the CFG80211 work queue is also created. */ void mwifiex_init_priv_params(struct mwifiex_private *priv, - struct net_device *dev) + struct net_device *dev) { dev->netdev_ops = &mwifiex_netdev_ops; dev->destructor = free_netdev; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 78304a714512..9e839cd64505 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1261,8 +1261,6 @@ int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, struct ieee80211_channel *chan, unsigned int duration); -int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role); - int mwifiex_get_stats_info(struct mwifiex_private *priv, struct mwifiex_ds_get_stats *log); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 2faa5174fe73..0599e41e253c 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -1135,36 +1135,6 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, return roc_cfg.status; } -int -mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role) -{ - if (GET_BSS_ROLE(priv) == bss_role) { - dev_dbg(priv->adapter->dev, - "info: already in the desired role.\n"); - return 0; - } - - mwifiex_free_priv(priv); - mwifiex_init_priv(priv); - - priv->bss_role = bss_role; - switch (bss_role) { - case MWIFIEX_BSS_ROLE_UAP: - priv->bss_mode = NL80211_IFTYPE_AP; - break; - case MWIFIEX_BSS_ROLE_STA: - case MWIFIEX_BSS_ROLE_ANY: - default: - priv->bss_mode = NL80211_IFTYPE_STATION; - break; - } - - mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, - HostCmd_ACT_GEN_SET, 0, NULL, true); - - return mwifiex_sta_init_cmd(priv, false, false); -} - /* * Sends IOCTL request to get statistics information. * -- cgit v1.2.1 From 6144369f8b4bb8a74a1b0dbe06340df2a69b79c1 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:54:16 +0530 Subject: mwifiex: do not send regulatory update while starting AP When regulatory domain changes, cfg80211 already issues request to change regulatory domain to driver via reg_notifier. There is no need to set regulatory again during start_ap. Signed-off-by: Avinash Patil Signed-off-by: Qingshui Gao Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 30ea94a1767c..1acccc5658b5 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1739,7 +1739,6 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, priv->adapter->config_bands = config_bands; mwifiex_set_uap_rates(bss_cfg, params); - mwifiex_send_domain_info_cmd_fw(wiphy); if (mwifiex_set_secure_params(priv, bss_cfg, params)) { kfree(bss_cfg); -- cgit v1.2.1 From 35c739b50d78a2e2e5b08c53b3143d2c94d50412 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:54:17 +0530 Subject: mwifiex: store AP configuration in private structure Store AP configuration in private structure so that we know current AP configuration. Signed-off-by: Avinash Patil Signed-off-by: Qingshui Gao Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 2 ++ drivers/net/wireless/mwifiex/main.h | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 1acccc5658b5..8e0756473527 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1655,6 +1655,7 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); priv->ap_11n_enabled = 0; + memset(&priv->bss_cfg, 0, sizeof(priv->bss_cfg)); if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, HostCmd_ACT_GEN_SET, 0, NULL, true)) { @@ -1782,6 +1783,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, return -1; } + memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg)); kfree(bss_cfg); if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 9e839cd64505..673252a32cd9 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -577,6 +577,7 @@ struct mwifiex_private { unsigned long csa_expire_time; u8 del_list_idx; bool hs2_enabled; + struct mwifiex_uap_bss_param bss_cfg; struct station_parameters *sta_params; struct sk_buff_head tdls_txq; u8 check_tdls_tx; -- cgit v1.2.1 From b0d4c5ec9730f7544772f50f84dc0dc730b1d551 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:54:18 +0530 Subject: mwifiex: update IEs after AP has started This patch moves IE management routine to end of start_ap handler. IEs now would be updated after AP has started. Signed-off-by: Avinash Patil Signed-off-by: Qingshui Gao Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 8e0756473527..ceeaeac45007 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1681,8 +1681,6 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) return -1; - if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) - return -1; bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); if (!bss_cfg) @@ -1783,6 +1781,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, return -1; } + if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) + return -1; + memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg)); kfree(bss_cfg); -- cgit v1.2.1 From b654ca182a2f54c3e3ce682420045f7dd79c8187 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:54:19 +0530 Subject: mwifiex: refactor start_ap handler Refactor mwifiex_cfg80211_start_ap by creating separate function to set AP channel and another for configuring other AP parameters and starting AP. Signed-off-by: Avinash Patil Signed-off-by: Qingshui Gao Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 68 ++++----------------------------- drivers/net/wireless/mwifiex/main.h | 4 ++ drivers/net/wireless/mwifiex/uap_cmd.c | 65 +++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 60 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ceeaeac45007..2e0834ca1cc0 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1677,7 +1677,6 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, { struct mwifiex_uap_bss_param *bss_cfg; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - u8 config_bands = 0; if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) return -1; @@ -1697,6 +1696,11 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); bss_cfg->ssid.ssid_len = params->ssid_len; } + if (params->inactivity_timeout > 0) { + /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ + bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout; + bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout; + } switch (params->hidden_ssid) { case NL80211_HIDDEN_SSID_NOT_IN_USE: @@ -1712,31 +1716,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } - bss_cfg->channel = ieee80211_frequency_to_channel( - params->chandef.chan->center_freq); - - /* Set appropriate bands */ - if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) { - bss_cfg->band_cfg = BAND_CONFIG_BG; - config_bands = BAND_B | BAND_G; - - if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT) - config_bands |= BAND_GN; - } else { - bss_cfg->band_cfg = BAND_CONFIG_A; - config_bands = BAND_A; - - if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT) - config_bands |= BAND_AN; - - if (params->chandef.width > NL80211_CHAN_WIDTH_40) - config_bands |= BAND_AAC; - } - - if (!((config_bands | priv->adapter->fw_bands) & - ~priv->adapter->fw_bands)) - priv->adapter->config_bands = config_bands; - + mwifiex_uap_set_channel(bss_cfg, params->chandef); mwifiex_set_uap_rates(bss_cfg, params); if (mwifiex_set_secure_params(priv, bss_cfg, params)) { @@ -1760,23 +1740,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, mwifiex_set_wmm_params(priv, bss_cfg, params); - if (params->inactivity_timeout > 0) { - /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ - bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout; - bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout; - } - - if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, - HostCmd_ACT_GEN_SET, 0, NULL, true)) { - wiphy_err(wiphy, "Failed to stop the BSS\n"); - kfree(bss_cfg); - return -1; - } - - if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, - HostCmd_ACT_GEN_SET, - UAP_BSS_PARAMS_I, bss_cfg, false)) { - wiphy_err(wiphy, "Failed to set the SSID\n"); + if (mwifiex_config_start_uap(priv, bss_cfg)) { + wiphy_err(wiphy, "Failed to start AP\n"); kfree(bss_cfg); return -1; } @@ -1786,23 +1751,6 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg)); kfree(bss_cfg); - - if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, - HostCmd_ACT_GEN_SET, 0, NULL, false)) { - wiphy_err(wiphy, "Failed to start the BSS\n"); - return -1; - } - - if (priv->sec_info.wep_enabled) - priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; - else - priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; - - if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, 0, - &priv->curr_pkt_filter, true)) - return -1; - return 0; } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 673252a32cd9..0c75eff23e8b 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1321,6 +1321,10 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, struct cfg80211_beacon_data *data); int mwifiex_del_mgmt_ies(struct mwifiex_private *priv); u8 *mwifiex_11d_code_2_region(u8 code); +void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_chan_def chandef); +int mwifiex_config_start_uap(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg); void mwifiex_uap_del_sta_data(struct mwifiex_private *priv, struct mwifiex_sta_node *node); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index 0f347fdefa0a..baf53145207e 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -769,3 +769,68 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, return 0; } + +void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_chan_def chandef) +{ + u8 config_bands = 0; + + bss_cfg->channel = ieee80211_frequency_to_channel( + chandef.chan->center_freq); + + /* Set appropriate bands */ + if (chandef.chan->band == IEEE80211_BAND_2GHZ) { + bss_cfg->band_cfg = BAND_CONFIG_BG; + config_bands = BAND_B | BAND_G; + + if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT) + config_bands |= BAND_GN; + } else { + bss_cfg->band_cfg = BAND_CONFIG_A; + config_bands = BAND_A; + + if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT) + config_bands |= BAND_AN; + + if (chandef.width > NL80211_CHAN_WIDTH_40) + config_bands |= BAND_AAC; + } +} + +int mwifiex_config_start_uap(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg) +{ + if (mwifiex_del_mgmt_ies(priv)) + dev_err(priv->adapter->dev, "Failed to delete mgmt IEs!\n"); + + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, NULL, true)) { + dev_err(priv->adapter->dev, "Failed to stop the BSS\n"); + return -1; + } + + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg, false)) { + dev_err(priv->adapter->dev, "Failed to set the SSID\n"); + return -1; + } + + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, + HostCmd_ACT_GEN_SET, 0, NULL, false)) { + dev_err(priv->adapter->dev, "Failed to start the BSS\n"); + return -1; + } + + if (priv->sec_info.wep_enabled) + priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; + else + priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; + + if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter, true)) + return -1; + + return 0; +} -- cgit v1.2.1 From 2ade5667e2e0244549818f16e2520141661e8bcd Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:54:20 +0530 Subject: mwifiex: separate function for parsing head and tail IEs Head & Tail IEs are supposed to be added to beacon and probe response. This patch adds separate function for parsing head and tail IEs from cfg80211_beacon_data and sets them to FW. Signed-off-by: Avinash Patil Signed-off-by: Qingshui Gao Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/ie.c | 81 +++++++++++++++++++++---------------- drivers/net/wireless/mwifiex/main.c | 2 +- drivers/net/wireless/mwifiex/main.h | 2 +- 3 files changed, 48 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index b933794758b7..a6af7b88bf05 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -317,27 +317,26 @@ done: return ret; } -/* This function parses different IEs-tail IEs, beacon IEs, probe response IEs, - * association response IEs from cfg80211_ap_settings function and sets these IE - * to FW. +/* This function parses head and tail IEs, from cfg80211_beacon_data and sets + * these IE to FW. */ -int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, - struct cfg80211_beacon_data *info) +static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv, + struct cfg80211_beacon_data *info) { struct mwifiex_ie *gen_ie; - struct ieee_types_header *rsn_ie, *wpa_ie = NULL; - u16 rsn_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; + struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL; + u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; const u8 *vendor_ie; - if (info->tail && info->tail_len) { - gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); - if (!gen_ie) - return -ENOMEM; - gen_ie->ie_index = cpu_to_le16(rsn_idx); - gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | - MGMT_MASK_PROBE_RESP | - MGMT_MASK_ASSOC_RESP); + gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL); + if (!gen_ie) + return -ENOMEM; + gen_ie->ie_index = cpu_to_le16(gen_idx); + gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | + MGMT_MASK_PROBE_RESP | + MGMT_MASK_ASSOC_RESP); + if (info->tail && info->tail_len) { rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, info->tail, info->tail_len); if (rsn_ie) { @@ -357,20 +356,33 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, ie_len += wpa_ie->len + 2; gen_ie->ie_length = cpu_to_le16(ie_len); } + } - if (rsn_ie || wpa_ie) { - if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx, - NULL, NULL, - NULL, NULL)) { - kfree(gen_ie); - return -1; - } - priv->rsn_idx = rsn_idx; + if (rsn_ie || wpa_ie) { + if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, + NULL, NULL, NULL)) { + kfree(gen_ie); + return -1; } - - kfree(gen_ie); + priv->gen_idx = gen_idx; } + kfree(gen_ie); + return 0; +} + +/* This function parses different IEs-head & tail IEs, beacon IEs, + * probe response IEs, association response IEs from cfg80211_ap_settings + * function and sets these IE to FW. + */ +int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, + struct cfg80211_beacon_data *info) +{ + int ret; + + ret = mwifiex_uap_set_head_tail_ies(priv, info); + return ret; + return mwifiex_set_mgmt_beacon_data_ies(priv, info); } @@ -378,25 +390,25 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, int mwifiex_del_mgmt_ies(struct mwifiex_private *priv) { struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL; - struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL; + struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL; int ret = 0; - if (priv->rsn_idx != MWIFIEX_AUTO_IDX_MASK) { - rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); - if (!rsn_ie) + if (priv->gen_idx != MWIFIEX_AUTO_IDX_MASK) { + gen_ie = kmalloc(sizeof(*gen_ie), GFP_KERNEL); + if (!gen_ie) return -ENOMEM; - rsn_ie->ie_index = cpu_to_le16(priv->rsn_idx); - rsn_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK); - rsn_ie->ie_length = 0; - if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &priv->rsn_idx, + gen_ie->ie_index = cpu_to_le16(priv->gen_idx); + gen_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK); + gen_ie->ie_length = 0; + if (mwifiex_update_uap_custom_ie(priv, gen_ie, &priv->gen_idx, NULL, &priv->proberesp_idx, NULL, &priv->assocresp_idx)) { ret = -1; goto done; } - priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; + priv->gen_idx = MWIFIEX_AUTO_IDX_MASK; } if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) { @@ -440,7 +452,6 @@ done: kfree(beacon_ie); kfree(pr_ie); kfree(ar_ie); - kfree(rsn_ie); return ret; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 30e519369ba6..7e74b4fccddd 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -973,7 +973,7 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK; priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK; priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK; - priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; + priv->gen_idx = MWIFIEX_AUTO_IDX_MASK; priv->num_tx_timeout = 0; ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr); memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 0c75eff23e8b..c5ac20da273c 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -567,7 +567,7 @@ struct mwifiex_private { u16 beacon_idx; u16 proberesp_idx; u16 assocresp_idx; - u16 rsn_idx; + u16 gen_idx; u8 ap_11n_enabled; u8 ap_11ac_enabled; u32 mgmt_frame_mask; -- cgit v1.2.1 From 85afb18621be393f925ed85f96a80d52e3706578 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:54:21 +0530 Subject: mwifiex: add cfg80211 start_radar_detection handler This patch adds support for cfg80211 start_radar_detection handler. Upon reception of start_radar_detection, driver prepares radar detect command to FW. Delayed work is queued for CAC time which sends radar detection finished event to cfg80211. Signed-off-by: Avinash Patil Signed-off-by: Qingshui Gao Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11h.c | 66 ++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/cfg80211.c | 59 ++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/decl.h | 6 +++ drivers/net/wireless/mwifiex/fw.h | 13 ++++++ drivers/net/wireless/mwifiex/init.c | 1 + drivers/net/wireless/mwifiex/main.h | 10 +++++ drivers/net/wireless/mwifiex/sta_cmd.c | 4 ++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 + drivers/net/wireless/mwifiex/uap_cmd.c | 5 +++ 9 files changed, 166 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c index f23b647a1411..8832c83816ee 100644 --- a/drivers/net/wireless/mwifiex/11h.c +++ b/drivers/net/wireless/mwifiex/11h.c @@ -99,3 +99,69 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer, bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT; } } + +/* This is DFS CAC work queue function. + * This delayed work emits CAC finished event for cfg80211 if + * CAC was started earlier. + */ +void mwifiex_dfs_cac_work_queue(struct work_struct *work) +{ + struct cfg80211_chan_def chandef; + struct delayed_work *delayed_work = + container_of(work, struct delayed_work, work); + struct mwifiex_private *priv = + container_of(delayed_work, struct mwifiex_private, + dfs_cac_work); + + if (WARN_ON(!priv)) + return; + + chandef = priv->dfs_chandef; + if (priv->wdev.cac_started) { + dev_dbg(priv->adapter->dev, + "CAC timer finished; No radar detected\n"); + cfg80211_cac_event(priv->netdev, &chandef, + NL80211_RADAR_CAC_FINISHED, + GFP_KERNEL); + } +} + +/* This function prepares channel report request command to FW for + * starting radar detection. + */ +int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_chan_rpt_req *cr_req = &cmd->params.chan_rpt_req; + struct mwifiex_radar_params *radar_params = (void *)data_buf; + + cmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REPORT_REQUEST); + cmd->size = cpu_to_le16(S_DS_GEN); + le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_chan_rpt_req)); + + cr_req->chan_desc.start_freq = cpu_to_le16(MWIFIEX_A_BAND_START_FREQ); + cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value; + cr_req->chan_desc.chan_width = radar_params->chandef->width; + cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms); + + dev_dbg(priv->adapter->dev, + "11h: issuing DFS Radar check for channel=%d\n", + radar_params->chandef->chan->hw_value); + + return 0; +} + +/* This function is to abort ongoing CAC upon stopping AP operations + * or during unload. + */ +void mwifiex_abort_cac(struct mwifiex_private *priv) +{ + if (priv->wdev.cac_started) { + dev_dbg(priv->adapter->dev, + "Aborting delayed work for CAC.\n"); + cancel_delayed_work_sync(&priv->dfs_cac_work); + cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, + NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); + } +} diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 2e0834ca1cc0..7a969fd2f0cd 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1651,6 +1651,8 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + mwifiex_abort_cac(priv); + if (mwifiex_del_mgmt_ies(priv)) wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); @@ -2383,6 +2385,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } +#define MWIFIEX_MAX_WQ_LEN 30 /* * create a new virtual interface with the given name */ @@ -2396,6 +2399,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, struct mwifiex_private *priv; struct net_device *dev; void *mdev_priv; + char dfs_cac_str[MWIFIEX_MAX_WQ_LEN]; if (!adapter) return ERR_PTR(-EFAULT); @@ -2560,6 +2564,24 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-EFAULT); } + strcpy(dfs_cac_str, "MWIFIEX_DFS_CAC"); + strcat(dfs_cac_str, name); + priv->dfs_cac_workqueue = alloc_workqueue(dfs_cac_str, + WQ_HIGHPRI | + WQ_MEM_RECLAIM | + WQ_UNBOUND, 1); + if (!priv->dfs_cac_workqueue) { + wiphy_err(wiphy, "cannot register virtual network device\n"); + free_netdev(dev); + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + priv->netdev = NULL; + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-ENOMEM); + } + + INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue); + sema_init(&priv->async_sem, 1); dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); @@ -2609,6 +2631,12 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) if (wdev->netdev->reg_state == NETREG_REGISTERED) unregister_netdevice(wdev->netdev); + if (priv->dfs_cac_workqueue) { + flush_workqueue(priv->dfs_cac_workqueue); + destroy_workqueue(priv->dfs_cac_workqueue); + priv->dfs_cac_workqueue = NULL; + } + /* Clear the priv in adapter */ priv->netdev->ieee80211_ptr = NULL; priv->netdev = NULL; @@ -3087,6 +3115,36 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK); } +static int +mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + u32 cac_time_ms) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_radar_params radar_params; + + if (priv->adapter->scan_processing) { + dev_err(priv->adapter->dev, + "radar detection: scan already in process...\n"); + return -EBUSY; + } + + memset(&radar_params, 0, sizeof(struct mwifiex_radar_params)); + radar_params.chandef = chandef; + radar_params.cac_time_ms = cac_time_ms; + + memcpy(&priv->dfs_chandef, chandef, sizeof(priv->dfs_chandef)); + + if (mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST, + HostCmd_ACT_GEN_SET, 0, &radar_params, true)) + return -1; + + queue_delayed_work(priv->dfs_cac_workqueue, &priv->dfs_cac_work, + msecs_to_jiffies(cac_time_ms)); + return 0; +} + static int mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac, @@ -3151,6 +3209,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .tdls_oper = mwifiex_cfg80211_tdls_oper, .add_station = mwifiex_cfg80211_add_station, .change_station = mwifiex_cfg80211_change_station, + .start_radar_detection = mwifiex_cfg80211_start_radar_detection, }; #ifdef CONFIG_PM diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 4481ac40c3eb..68aed4e5ad83 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -108,6 +108,8 @@ #define MWIFIEX_MAX_UAP_NUM 1 #define MWIFIEX_MAX_P2P_NUM 1 +#define MWIFIEX_A_BAND_START_FREQ 5000 + enum mwifiex_bss_type { MWIFIEX_BSS_TYPE_STA = 0, MWIFIEX_BSS_TYPE_UAP = 1, @@ -242,4 +244,8 @@ struct mwifiex_iface_comb { u8 p2p_intf; }; +struct mwifiex_radar_params { + struct cfg80211_chan_def *chandef; + u32 cac_time_ms; +} __packed; #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 15ad776ae08e..739151c13f15 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -336,6 +336,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_11N_ADDBA_RSP 0x00cf #define HostCmd_CMD_11N_DELBA 0x00d0 #define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9 +#define HostCmd_CMD_CHAN_REPORT_REQUEST 0x00dd #define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df #define HostCmd_CMD_TXPWR_CFG 0x00d1 #define HostCmd_CMD_TX_RATE_CFG 0x00d6 @@ -1216,6 +1217,17 @@ struct host_cmd_ds_tdls_oper { u8 peer_mac[ETH_ALEN]; } __packed; +struct mwifiex_chan_desc { + __le16 start_freq; + u8 chan_width; + u8 chan_num; +} __packed; + +struct host_cmd_ds_chan_rpt_req { + struct mwifiex_chan_desc chan_desc; + __le32 msec_dwell_time; +} __packed; + struct mwifiex_fixed_bcn_param { __le64 timestamp; __le16 beacon_period; @@ -1904,6 +1916,7 @@ struct host_cmd_ds_command { struct host_cmd_11ac_vht_cfg vht_cfg; struct host_cmd_ds_coalesce_cfg coalesce_cfg; struct host_cmd_ds_tdls_oper tdls_oper; + struct host_cmd_ds_chan_rpt_req chan_rpt_req; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 1d1c3c8e516e..aa239a8826bc 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -681,6 +681,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) priv = adapter->priv[i]; mwifiex_clean_auto_tdls(priv); + mwifiex_abort_cac(priv); mwifiex_clean_txrx(priv); mwifiex_delete_bss_prio_tbl(priv); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index c5ac20da273c..e266d99ac2b2 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -588,6 +588,9 @@ struct mwifiex_private { spinlock_t ack_status_lock; /** rx histogram data */ struct mwifiex_histogram_data *hist_data; + struct cfg80211_chan_def dfs_chandef; + struct workqueue_struct *dfs_cac_workqueue; + struct delayed_work dfs_cac_work; }; enum mwifiex_ba_status { @@ -754,6 +757,8 @@ struct mwifiex_adapter { struct work_struct main_work; struct workqueue_struct *rx_workqueue; struct work_struct rx_work; + struct workqueue_struct *dfs_workqueue; + struct work_struct dfs_work; bool rx_work_enabled; bool rx_processing; bool delay_main_work; @@ -1376,6 +1381,9 @@ void mwifiex_check_auto_tdls(unsigned long context); void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac); void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv); void mwifiex_clean_auto_tdls(struct mwifiex_private *priv); +int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, void *event_body); @@ -1383,6 +1391,8 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, struct sk_buff * mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, struct sk_buff *skb, u8 flag, u64 *cookie); +void mwifiex_dfs_cac_work_queue(struct work_struct *work); +void mwifiex_abort_cac(struct mwifiex_private *priv); void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, s8 nflr); diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 92a66e8b6636..f7d204ffd6e9 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1897,6 +1897,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_TDLS_OPER: ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf); break; + case HostCmd_CMD_CHAN_REPORT_REQUEST: + ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr, + data_buf); + break; default: dev_err(priv->adapter->dev, "PREP_CMD: unknown cmd- %#x\n", cmd_no); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 65d10a33eab5..39f31766812f 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -1119,6 +1119,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_TDLS_OPER: ret = mwifiex_ret_tdls_oper(priv, resp); break; + case HostCmd_CMD_CHAN_REPORT_REQUEST: + break; default: dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", resp->command); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index baf53145207e..f5c2af01ba0a 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -761,6 +761,11 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, if (mwifiex_cmd_uap_sta_deauth(priv, cmd, data_buf)) return -1; break; + case HostCmd_CMD_CHAN_REPORT_REQUEST: + if (mwifiex_cmd_issue_chan_report_request(priv, cmd_buf, + data_buf)) + return -1; + break; default: dev_err(priv->adapter->dev, "PREP_CMD: unknown cmd %#x\n", cmd_no); -- cgit v1.2.1 From 0a694d68651b16b307d5ad64acac90d604146bcc Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:54:22 +0530 Subject: mwifiex: support for channel report for radar detection This patch adds support for channel report enabling. Channel report event happens if radar is detected on specified channel after driver has issued radar detect command within CAC time. Driver in turn sends RADAR_DETECTED event to cfg80211 to tell radar was detected within CAC time. Signed-off-by: Avinash Patil Signed-off-by: Qingshui Gao Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11h.c | 51 ++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/fw.h | 23 ++++++++++++++ drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/sta_event.c | 5 ++++ drivers/net/wireless/mwifiex/uap_event.c | 4 +++ 5 files changed, 85 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c index 8832c83816ee..e44cac72712e 100644 --- a/drivers/net/wireless/mwifiex/11h.c +++ b/drivers/net/wireless/mwifiex/11h.c @@ -165,3 +165,54 @@ void mwifiex_abort_cac(struct mwifiex_private *priv) NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); } } + +/* This function handles channel report event from FW during CAC period. + * If radar is detected during CAC, driver indicates the same to cfg80211 + * and also cancels ongoing delayed work. + */ +int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct host_cmd_ds_chan_rpt_event *rpt_event; + struct mwifiex_ie_types_chan_rpt_data *rpt; + u8 *evt_buf; + u16 event_len, tlv_len; + + rpt_event = (void *)(skb->data + sizeof(u32)); + event_len = skb->len - (sizeof(struct host_cmd_ds_chan_rpt_event)+ + sizeof(u32)); + + if (le32_to_cpu(rpt_event->result) != HostCmd_RESULT_OK) { + dev_err(priv->adapter->dev, "Error in channel report event\n"); + return -1; + } + + evt_buf = (void *)&rpt_event->tlvbuf; + + while (event_len >= sizeof(struct mwifiex_ie_types_header)) { + rpt = (void *)&rpt_event->tlvbuf; + tlv_len = le16_to_cpu(rpt->header.len); + + switch (le16_to_cpu(rpt->header.type)) { + case TLV_TYPE_CHANRPT_11H_BASIC: + if (rpt->map.radar) { + dev_notice(priv->adapter->dev, + "RADAR Detected on channel %d!\n", + priv->dfs_chandef.chan->hw_value); + cancel_delayed_work_sync(&priv->dfs_cac_work); + cfg80211_cac_event(priv->netdev, + &priv->dfs_chandef, + NL80211_RADAR_DETECTED, + GFP_KERNEL); + } + break; + default: + break; + } + + evt_buf += (tlv_len + sizeof(rpt->header)); + event_len -= (tlv_len + sizeof(rpt->header)); + } + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 739151c13f15..324ef298bea6 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -158,6 +158,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) #define TLV_TYPE_BSS_SCAN_RSP (PROPRIETARY_TLV_BASE_ID + 86) #define TLV_TYPE_BSS_SCAN_INFO (PROPRIETARY_TLV_BASE_ID + 87) +#define TLV_TYPE_CHANRPT_11H_BASIC (PROPRIETARY_TLV_BASE_ID + 91) #define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 93) #define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94) #define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 104) @@ -494,6 +495,7 @@ enum P2P_MODES { #define EVENT_HOSTWAKE_STAIE 0x0000004d #define EVENT_CHANNEL_SWITCH_ANN 0x00000050 #define EVENT_TDLS_GENERIC_EVENT 0x00000052 +#define EVENT_CHANNEL_REPORT_RDY 0x00000054 #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f #define EVENT_TX_STATUS_REPORT 0x00000074 @@ -1228,6 +1230,13 @@ struct host_cmd_ds_chan_rpt_req { __le32 msec_dwell_time; } __packed; +struct host_cmd_ds_chan_rpt_event { + __le32 result; + __le64 start_tsf; + __le32 duration; + u8 tlvbuf[0]; +} __packed; + struct mwifiex_fixed_bcn_param { __le64 timestamp; __le16 beacon_period; @@ -1804,6 +1813,20 @@ struct mwifiex_ie_types_rssi_threshold { u8 evt_freq; } __packed; +struct meas_rpt_map { + u8 rssi:3; + u8 unmeasured:1; + u8 radar:1; + u8 unidentified_sig:1; + u8 ofdm_preamble:1; + u8 bss:1; +} __packed; + +struct mwifiex_ie_types_chan_rpt_data { + struct mwifiex_ie_types_header header; + struct meas_rpt_map map; +} __packed; + struct host_cmd_ds_802_11_subsc_evt { __le16 action; __le16 events; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index e266d99ac2b2..281a30a8d857 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1384,6 +1384,8 @@ void mwifiex_clean_auto_tdls(struct mwifiex_private *priv); int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf); +int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv, + struct sk_buff *skb); void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, void *event_body); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index c37e8cb2dd32..ad5c5e0deac0 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -516,6 +516,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) mwifiex_parse_tx_status_event(priv, adapter->event_body); break; + case EVENT_CHANNEL_REPORT_RDY: + dev_dbg(adapter->dev, "event: Channel Report\n"); + ret = mwifiex_11h_handle_chanrpt_ready(priv, + adapter->event_skb); + break; default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 9b4ca6ff7931..e0bdf6a79916 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -215,7 +215,11 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; + break; + case EVENT_CHANNEL_REPORT_RDY: + dev_dbg(adapter->dev, "event: Channel Report\n"); + mwifiex_11h_handle_chanrpt_ready(priv, adapter->event_skb); break; default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", -- cgit v1.2.1 From 3b57c1a713a9dd3b8da74b6df9f16ce1f8f9144b Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:54:23 +0530 Subject: mwifiex: handle radar detect event from FW This patch adds support for radar_detected event from FW. Driver in turn would stop netdev queues to stop TX traffic and issue RADAR_DETECT event to cfg80211. Signed-off-by: Avinash Patil Signed-off-by: Qingshui Gao Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11h.c | 24 ++++++++++++++++++++++++ drivers/net/wireless/mwifiex/fw.h | 20 ++++++++++++++++++++ drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/sta_event.c | 5 +++++ drivers/net/wireless/mwifiex/uap_event.c | 4 ++++ 5 files changed, 55 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c index e44cac72712e..08c12aece9ae 100644 --- a/drivers/net/wireless/mwifiex/11h.c +++ b/drivers/net/wireless/mwifiex/11h.c @@ -216,3 +216,27 @@ int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv, return 0; } + +/* Handler for radar detected event from FW.*/ +int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct mwifiex_radar_det_event *rdr_event; + + rdr_event = (void *)(skb->data + sizeof(u32)); + + if (le32_to_cpu(rdr_event->passed)) { + dev_notice(priv->adapter->dev, + "radar detected; indicating kernel\n"); + cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef, + GFP_KERNEL); + dev_dbg(priv->adapter->dev, "regdomain: %d\n", + rdr_event->reg_domain); + dev_dbg(priv->adapter->dev, "radar detection type: %d\n", + rdr_event->det_type); + } else { + dev_dbg(priv->adapter->dev, "false radar detection event!\n"); + } + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 324ef298bea6..6d433227e273 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -495,6 +495,7 @@ enum P2P_MODES { #define EVENT_HOSTWAKE_STAIE 0x0000004d #define EVENT_CHANNEL_SWITCH_ANN 0x00000050 #define EVENT_TDLS_GENERIC_EVENT 0x00000052 +#define EVENT_RADAR_DETECTED 0x00000053 #define EVENT_CHANNEL_REPORT_RDY 0x00000054 #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f @@ -1813,6 +1814,25 @@ struct mwifiex_ie_types_rssi_threshold { u8 evt_freq; } __packed; +#define MWIFIEX_DFS_REC_HDR_LEN 8 +#define MWIFIEX_DFS_REC_HDR_NUM 10 +#define MWIFIEX_BIN_COUNTER_LEN 7 + +struct mwifiex_radar_det_event { + __le32 detect_count; + u8 reg_domain; /*1=fcc, 2=etsi, 3=mic*/ + u8 det_type; /*0=none, 1=pw(chirp), 2=pri(radar)*/ + __le16 pw_chirp_type; + u8 pw_chirp_idx; + u8 pw_value; + u8 pri_radar_type; + u8 pri_bincnt; + u8 bin_counter[MWIFIEX_BIN_COUNTER_LEN]; + u8 num_dfs_records; + u8 dfs_record_hdr[MWIFIEX_DFS_REC_HDR_NUM][MWIFIEX_DFS_REC_HDR_LEN]; + __le32 passed; +} __packed; + struct meas_rpt_map { u8 rssi:3; u8 unmeasured:1; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 281a30a8d857..ad9d679c3eed 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1395,6 +1395,8 @@ mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, struct sk_buff *skb, u8 flag, u64 *cookie); void mwifiex_dfs_cac_work_queue(struct work_struct *work); void mwifiex_abort_cac(struct mwifiex_private *priv); +int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, + struct sk_buff *skb); void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, s8 nflr); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index ad5c5e0deac0..c03b82c2fe1c 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -521,6 +521,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) ret = mwifiex_11h_handle_chanrpt_ready(priv, adapter->event_skb); break; + case EVENT_RADAR_DETECTED: + dev_dbg(adapter->dev, "event: Radar detected\n"); + ret = mwifiex_11h_handle_radar_detected(priv, + adapter->event_skb); + break; default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index e0bdf6a79916..f4794cdc36d2 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -221,6 +221,10 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) dev_dbg(adapter->dev, "event: Channel Report\n"); mwifiex_11h_handle_chanrpt_ready(priv, adapter->event_skb); break; + case EVENT_RADAR_DETECTED: + dev_dbg(adapter->dev, "event: Radar detected\n"); + mwifiex_11h_handle_radar_detected(priv, adapter->event_skb); + break; default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", eventcause); -- cgit v1.2.1 From 7d652034d1a08bd240c98727bbd55901a174c245 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:54:24 +0530 Subject: mwifiex: channel switch support for mwifiex This patch adds cfg80211 channel_switch support for mwifiex. Upon receiving channel switch request, driver would parse channel switch announcement IE from beacon_data. If TX is blocked, netdev queues are stopped. IEs from csa_beacon are then parsed and set to FW. Signed-off-by: Avinash Patil Signed-off-by: Qingshui Gao Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11h.c | 37 ++++++++++++++ drivers/net/wireless/mwifiex/cfg80211.c | 85 ++++++++++++++++++++++++++++++++- drivers/net/wireless/mwifiex/ie.c | 12 ++++- drivers/net/wireless/mwifiex/main.h | 5 ++ 4 files changed, 136 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c index 08c12aece9ae..d794686e31d6 100644 --- a/drivers/net/wireless/mwifiex/11h.c +++ b/drivers/net/wireless/mwifiex/11h.c @@ -240,3 +240,40 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, return 0; } + +/* This is work queue function for channel switch handling. + * This function takes care of updating new channel definitin to + * bss config structure, restart AP and indicate channel switch success + * to cfg80211. + */ +void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) +{ + struct mwifiex_uap_bss_param *bss_cfg; + struct delayed_work *delayed_work = + container_of(work, struct delayed_work, work); + struct mwifiex_private *priv = + container_of(delayed_work, struct mwifiex_private, + dfs_chan_sw_work); + + if (WARN_ON(!priv)) + return; + + bss_cfg = &priv->bss_cfg; + if (!bss_cfg->beacon_period) { + dev_err(priv->adapter->dev, + "channel switch: AP already stopped\n"); + return; + } + + mwifiex_uap_set_channel(bss_cfg, priv->dfs_chandef); + + if (mwifiex_config_start_uap(priv, bss_cfg)) { + dev_dbg(priv->adapter->dev, + "Failed to start AP after channel switch\n"); + return; + } + + dev_notice(priv->adapter->dev, + "indicating channel switch completion to kernel\n"); + cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef); +} diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 7a969fd2f0cd..2d1ea938e08e 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2399,7 +2399,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, struct mwifiex_private *priv; struct net_device *dev; void *mdev_priv; - char dfs_cac_str[MWIFIEX_MAX_WQ_LEN]; + char dfs_cac_str[MWIFIEX_MAX_WQ_LEN], dfs_chsw_str[MWIFIEX_MAX_WQ_LEN]; if (!adapter) return ERR_PTR(-EFAULT); @@ -2582,6 +2582,24 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue); + strcpy(dfs_chsw_str, "MWIFIEX_DFS_CHSW"); + strcat(dfs_chsw_str, name); + priv->dfs_chan_sw_workqueue = alloc_workqueue(dfs_chsw_str, + WQ_HIGHPRI | WQ_UNBOUND | + WQ_MEM_RECLAIM, 1); + if (!priv->dfs_chan_sw_workqueue) { + wiphy_err(wiphy, "cannot register virtual network device\n"); + free_netdev(dev); + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + priv->netdev = NULL; + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-ENOMEM); + } + + INIT_DELAYED_WORK(&priv->dfs_chan_sw_work, + mwifiex_dfs_chan_sw_work_queue); + sema_init(&priv->async_sem, 1); dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); @@ -2637,6 +2655,11 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) priv->dfs_cac_workqueue = NULL; } + if (priv->dfs_chan_sw_workqueue) { + flush_workqueue(priv->dfs_chan_sw_workqueue); + destroy_workqueue(priv->dfs_chan_sw_workqueue); + priv->dfs_chan_sw_workqueue = NULL; + } /* Clear the priv in adapter */ priv->netdev->ieee80211_ptr = NULL; priv->netdev = NULL; @@ -3115,6 +3138,62 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK); } +static int +mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_csa_settings *params) +{ + struct ieee_types_header *chsw_ie; + struct ieee80211_channel_sw_ie *channel_sw; + int chsw_msec; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->adapter->scan_processing) { + dev_err(priv->adapter->dev, + "radar detection: scan in process...\n"); + return -EBUSY; + } + + if (priv->wdev.cac_started) + return -EBUSY; + + if (cfg80211_chandef_identical(¶ms->chandef, + &priv->dfs_chandef)) + return -EINVAL; + + chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH, + params->beacon_csa.tail, + params->beacon_csa.tail_len); + if (!chsw_ie) { + dev_err(priv->adapter->dev, + "Could not parse channel switch announcement IE\n"); + return -EINVAL; + } + + channel_sw = (void *)(chsw_ie + 1); + if (channel_sw->mode) { + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); + } + + if (mwifiex_del_mgmt_ies(priv)) + wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); + + if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon_csa)) { + wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__); + return -EFAULT; + } + + memcpy(&priv->dfs_chandef, ¶ms->chandef, sizeof(priv->dfs_chandef)); + memcpy(&priv->beacon_after, ¶ms->beacon_after, + sizeof(priv->beacon_after)); + + chsw_msec = max(channel_sw->count * priv->bss_cfg.beacon_period, 100); + queue_delayed_work(priv->dfs_chan_sw_workqueue, &priv->dfs_chan_sw_work, + msecs_to_jiffies(chsw_msec)); + return 0; +} + static int mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy, struct net_device *dev, @@ -3210,6 +3289,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .add_station = mwifiex_cfg80211_add_station, .change_station = mwifiex_cfg80211_change_station, .start_radar_detection = mwifiex_cfg80211_start_radar_detection, + .channel_switch = mwifiex_cfg80211_channel_switch, }; #ifdef CONFIG_PM @@ -3313,7 +3393,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_UAPSD | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_HAS_CHANNEL_SWITCH; if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index a6af7b88bf05..f3b6ed249403 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -325,6 +325,7 @@ static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv, { struct mwifiex_ie *gen_ie; struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL; + struct ieee_types_header *chsw_ie = NULL; u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; const u8 *vendor_ie; @@ -356,9 +357,18 @@ static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv, ie_len += wpa_ie->len + 2; gen_ie->ie_length = cpu_to_le16(ie_len); } + + chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH, + info->tail, info->tail_len); + if (chsw_ie) { + memcpy(gen_ie->ie_buffer + ie_len, + chsw_ie, chsw_ie->len + 2); + ie_len += chsw_ie->len + 2; + gen_ie->ie_length = cpu_to_le16(ie_len); + } } - if (rsn_ie || wpa_ie) { + if (rsn_ie || wpa_ie || chsw_ie) { if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL, NULL, NULL)) { kfree(gen_ie); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index ad9d679c3eed..599698c6b627 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -591,6 +591,10 @@ struct mwifiex_private { struct cfg80211_chan_def dfs_chandef; struct workqueue_struct *dfs_cac_workqueue; struct delayed_work dfs_cac_work; + struct timer_list dfs_chan_switch_timer; + struct workqueue_struct *dfs_chan_sw_workqueue; + struct delayed_work dfs_chan_sw_work; + struct cfg80211_beacon_data beacon_after; }; enum mwifiex_ba_status { @@ -1394,6 +1398,7 @@ struct sk_buff * mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, struct sk_buff *skb, u8 flag, u64 *cookie); void mwifiex_dfs_cac_work_queue(struct work_struct *work); +void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work); void mwifiex_abort_cac(struct mwifiex_private *priv); int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, struct sk_buff *skb); -- cgit v1.2.1 From cf075eac9ca94ec54b5ae0c0ec798839f962be55 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 28 Jan 2015 15:54:25 +0530 Subject: mwifiex: 11h handling for AP interface This patch enables 11h extensions in FW upon detecting DFS channel in start radar detection/channel switch handlers. Patch also takes care of disabling 11h when non DFS channels are to be set during start_ap handler. Signed-off-by: Avinash Patil Signed-off-by: Qingshui Gao Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11h.c | 18 +++++++++++++++++- drivers/net/wireless/mwifiex/cfg80211.c | 22 ++++++++++++++++++++++ drivers/net/wireless/mwifiex/decl.h | 5 +++++ drivers/net/wireless/mwifiex/fw.h | 2 ++ drivers/net/wireless/mwifiex/init.c | 2 ++ drivers/net/wireless/mwifiex/main.h | 5 +++++ 6 files changed, 53 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c index d794686e31d6..3ab87a855122 100644 --- a/drivers/net/wireless/mwifiex/11h.c +++ b/drivers/net/wireless/mwifiex/11h.c @@ -21,6 +21,16 @@ #include "fw.h" +void mwifiex_init_11h_params(struct mwifiex_private *priv) +{ + priv->state_11h.is_11h_enabled = true; + priv->state_11h.is_11h_active = false; +} + +inline int mwifiex_is_11h_active(struct mwifiex_private *priv) +{ + return priv->state_11h.is_11h_active; +} /* This function appends 11h info to a buffer while joining an * infrastructure BSS */ @@ -69,10 +79,14 @@ mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer, } /* Enable or disable the 11h extensions in the firmware */ -static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag) +int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag) { u32 enable = flag; + /* enable master mode radar detection on AP interface */ + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && enable) + enable |= MWIFIEX_MASTER_RADAR_DET_MASK; + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_SET, DOT11H_I, &enable, true); } @@ -91,11 +105,13 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer, * bit */ mwifiex_11h_activate(priv, true); + priv->state_11h.is_11h_active = true; bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT; mwifiex_11h_process_infra_join(priv, buffer, bss_desc); } else { /* Deactivate 11h functions in the firmware */ mwifiex_11h_activate(priv, false); + priv->state_11h.is_11h_active = false; bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT; } } diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 2d1ea938e08e..41c8e25df954 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1742,6 +1742,18 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, mwifiex_set_wmm_params(priv, bss_cfg, params); + if (mwifiex_is_11h_active(priv) && + !cfg80211_chandef_dfs_required(wiphy, ¶ms->chandef, + priv->bss_mode)) { + dev_dbg(priv->adapter->dev, "Disable 11h extensions in FW\n"); + if (mwifiex_11h_activate(priv, false)) { + dev_err(priv->adapter->dev, + "Failed to disable 11h extensions!!"); + return -1; + } + priv->state_11h.is_11h_active = true; + } + if (mwifiex_config_start_uap(priv, bss_cfg)) { wiphy_err(wiphy, "Failed to start AP\n"); kfree(bss_cfg); @@ -3209,6 +3221,16 @@ mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy, return -EBUSY; } + if (!mwifiex_is_11h_active(priv)) { + dev_dbg(priv->adapter->dev, "Enable 11h extensions in FW\n"); + if (mwifiex_11h_activate(priv, true)) { + dev_err(priv->adapter->dev, + "Failed to activate 11h extensions!!"); + return -1; + } + priv->state_11h.is_11h_active = true; + } + memset(&radar_params, 0, sizeof(struct mwifiex_radar_params)); radar_params.chandef = chandef; radar_params.cac_time_ms = cac_time_ms; diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 68aed4e5ad83..88d0eade6bb1 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -248,4 +248,9 @@ struct mwifiex_radar_params { struct cfg80211_chan_def *chandef; u32 cac_time_ms; } __packed; + +struct mwifiex_11h_intf_state { + bool is_11h_enabled; + bool is_11h_active; +} __packed; #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 6d433227e273..df553e86a0ad 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -534,6 +534,8 @@ enum P2P_MODES { #define MWIFIEX_FW_V15 15 +#define MWIFIEX_MASTER_RADAR_DET_MASK BIT(1) + struct mwifiex_ie_types_header { __le16 type; __le16 len; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index aa239a8826bc..b77ba743e1c4 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -152,6 +152,8 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->check_tdls_tx = false; memcpy(priv->tos_to_tid_inv, tos_to_tid_inv, MAX_NUM_TID); + mwifiex_init_11h_params(priv); + return mwifiex_add_bss_prio_tbl(priv); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 599698c6b627..f0a6af179af0 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -595,6 +595,7 @@ struct mwifiex_private { struct workqueue_struct *dfs_chan_sw_workqueue; struct delayed_work dfs_chan_sw_work; struct cfg80211_beacon_data beacon_after; + struct mwifiex_11h_intf_state state_11h; }; enum mwifiex_ba_status { @@ -1337,6 +1338,10 @@ int mwifiex_config_start_uap(struct mwifiex_private *priv, void mwifiex_uap_del_sta_data(struct mwifiex_private *priv, struct mwifiex_sta_node *node); +void mwifiex_init_11h_params(struct mwifiex_private *priv); +int mwifiex_is_11h_active(struct mwifiex_private *priv); +int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag); + void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer, struct mwifiex_bssdescriptor *bss_desc); int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv); -- cgit v1.2.1 From a75d46a4f405eb19ff780410b968c8092af3fb1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Mon, 26 Jan 2015 18:26:17 +0100 Subject: b43: Fix locking FIXME in beacon update top half b43 has a FIXME about locking in the mac80211 set-beacon-int callback for a long time. As it turns out there actually is a tiny race window that could result in a use-after-free bug of the 'current_beacon' memory. Nobody ever reported this, so it probably never happened. Fix this by adding a spin lock that protects the current_beacon access. We must not be in atomic context while accessing hardware (due to SDIO), so the beacon update bottom half has to clone the skb and release the lock before writing it to hardware. Let's all hope that this stops the troll who is trying to submit incorrect fixes for this issue repeatedly. And let's hope that I'm not a troll, too, who just hides even more evil code in an even more complex attempt to fix the issue. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/b43/b43.h | 1 + drivers/net/wireless/b43/main.c | 43 ++++++++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index bb12586cd7cd..65b2dd80ecd5 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -941,6 +941,7 @@ struct b43_wl { bool beacon1_uploaded; bool beacon_templates_virgin; /* Never wrote the templates? */ struct work_struct beacon_update_trigger; + spinlock_t beacon_lock; /* The current QOS parameters for the 4 queues. */ struct b43_qos_params qos_params[B43_QOS_QUEUE_NUM]; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 58a2e88631fb..d1c397162a6a 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1601,12 +1601,26 @@ static void b43_write_beacon_template(struct b43_wldev *dev, unsigned int rate; u16 ctl; int antenna; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon); + struct ieee80211_tx_info *info; + unsigned long flags; + struct sk_buff *beacon_skb; - bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); - len = min_t(size_t, dev->wl->current_beacon->len, - 0x200 - sizeof(struct b43_plcp_hdr6)); + spin_lock_irqsave(&dev->wl->beacon_lock, flags); + info = IEEE80211_SKB_CB(dev->wl->current_beacon); rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; + /* Clone the beacon, so it cannot go away, while we write it to hw. */ + beacon_skb = skb_clone(dev->wl->current_beacon, GFP_ATOMIC); + spin_unlock_irqrestore(&dev->wl->beacon_lock, flags); + + if (!beacon_skb) { + b43dbg(dev->wl, "Could not upload beacon. " + "Failed to clone beacon skb."); + return; + } + + bcn = (const struct ieee80211_mgmt *)(beacon_skb->data); + len = min_t(size_t, beacon_skb->len, + 0x200 - sizeof(struct b43_plcp_hdr6)); b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); @@ -1674,6 +1688,8 @@ static void b43_write_beacon_template(struct b43_wldev *dev, B43_SHM_SH_DTIMPER, 0); } b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset); + + dev_kfree_skb_any(beacon_skb); } static void b43_upload_beacon0(struct b43_wldev *dev) @@ -1790,13 +1806,13 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) mutex_unlock(&wl->mutex); } -/* Asynchronously update the packet templates in template RAM. - * Locking: Requires wl->mutex to be locked. */ +/* Asynchronously update the packet templates in template RAM. */ static void b43_update_templates(struct b43_wl *wl) { - struct sk_buff *beacon; + struct sk_buff *beacon, *old_beacon; + unsigned long flags; - /* This is the top half of the ansynchronous beacon update. + /* This is the top half of the asynchronous beacon update. * The bottom half is the beacon IRQ. * Beacon update must be asynchronous to avoid sending an * invalid beacon. This can happen for example, if the firmware @@ -1810,12 +1826,17 @@ static void b43_update_templates(struct b43_wl *wl) if (unlikely(!beacon)) return; - if (wl->current_beacon) - dev_kfree_skb_any(wl->current_beacon); + spin_lock_irqsave(&wl->beacon_lock, flags); + old_beacon = wl->current_beacon; wl->current_beacon = beacon; wl->beacon0_uploaded = false; wl->beacon1_uploaded = false; + spin_unlock_irqrestore(&wl->beacon_lock, flags); + ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger); + + if (old_beacon) + dev_kfree_skb_any(old_beacon); } static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) @@ -5095,7 +5116,6 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); - /* FIXME: add locking */ b43_update_templates(wl); return 0; @@ -5585,6 +5605,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) wl->hw = hw; mutex_init(&wl->mutex); spin_lock_init(&wl->hardirq_lock); + spin_lock_init(&wl->beacon_lock); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); INIT_WORK(&wl->tx_work, b43_tx_work); -- cgit v1.2.1 From 14c5932805eb7b5a04e771d48065b4d2080750b2 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Jan 2015 17:54:21 +0530 Subject: ath9k: Update QCA953x initvals This patch disables HW peak detect calibration for QCA953x, since it is problematic on a few boards. Instead, manual calibration will be done in the driver. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar953x_initvals.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h index 159cc6fd2362..6fc0d07e5ec6 100644 --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -358,7 +358,7 @@ static const u32 qca953x_1p0_baseband_postamble[][5] = { {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10820, 0xcfa10820}, {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -378,7 +378,7 @@ static const u32 qca953x_1p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18}, {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, -- cgit v1.2.1 From 4f6f952b9cdd096f38d2a7dc6f560c630c91b627 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Jan 2015 17:54:22 +0530 Subject: ath9k: Update AR955x initvals This patch disables HW peak detect calibration for AR955x, since it is problematic on a few boards. Instead, manual calibration will be done in the driver. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h index fd6a84ccd49e..148562addd38 100644 --- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h @@ -63,7 +63,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = { {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10820, 0xcfa10820}, {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -83,7 +83,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18}, {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, -- cgit v1.2.1 From f49c90db4d2351f354c4f6902f6718637cd23393 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Jan 2015 17:54:23 +0530 Subject: ath9k: Add a macro to identify PCOEM chips This can be used if we need to apply register settings for all PCOEM solutions (in the AR9003 family). Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/reg.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index eb2bb0db297f..3c0b1807bb2b 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -900,10 +900,13 @@ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) #define AR_SREV_9565(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565)) +#define AR_SREV_9003_PCOEM(_ah) \ + (AR_SREV_9462(_ah) || AR_SREV_9485(_ah) || AR_SREV_9565(_ah)) #else #define AR_SREV_9462(_ah) 0 #define AR_SREV_9485(_ah) 0 #define AR_SREV_9565(_ah) 0 +#define AR_SREV_9003_PCOEM(_ah) 0 #endif #define AR_SREV_9485_11_OR_LATER(_ah) \ -- cgit v1.2.1 From 7a722ebc596a572a9b24cfe1466642faa6a8988a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Jan 2015 17:54:24 +0530 Subject: ath9k: Fix manual peak calibration initialization The LNA gain setting override needs to be done only for AR9330 and PCOEM chips. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 38 +++++++++++++++++++++------ 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 06ab71db6e80..374aef1d9008 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1205,22 +1205,34 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) int offset[8] = {0}, total = 0, test; int agc_out, i; + /* + * Turn off LNA/SW. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0); - if (is_2g) - REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), - AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0); - else - REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), - AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0); + if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9330_11(ah)) { + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0); + } + + /* + * Turn off RXON. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), AR_PHY_65NM_RXTX2_RXON_OVR, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), AR_PHY_65NM_RXTX2_RXON, 0x0); + /* + * Turn on AGC for cal. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), @@ -1228,10 +1240,11 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1); - if (AR_SREV_9330_11(ah)) { + if (AR_SREV_9330_11(ah)) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0); - } else { + + if (AR_SREV_9003_PCOEM(ah)) { if (is_2g) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0); @@ -1266,10 +1279,19 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total); + /* + * Turn on LNA. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0); + /* + * Turn off RXON. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), AR_PHY_65NM_RXTX2_RXON_OVR, 0); + /* + * Turn off peak detect calibration. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0); } -- cgit v1.2.1 From e4e292f3c7df753926ecb411788057e15154189e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Jan 2015 17:54:25 +0530 Subject: ath9k: Set correct peak detect threshold The value is different for PCOEM cards and AR955x/AR953x. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 374aef1d9008..91130c0e31d3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1203,7 +1203,12 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah) static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) { int offset[8] = {0}, total = 0, test; - int agc_out, i; + int agc_out, i, peak_detect_threshold; + + if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) + peak_detect_threshold = 8; + else + peak_detect_threshold = 0; /* * Turn off LNA/SW. @@ -1244,13 +1249,15 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0); - if (AR_SREV_9003_PCOEM(ah)) { + if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) { if (is_2g) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), - AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0); + AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, + peak_detect_threshold); else REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), - AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0); + AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, + peak_detect_threshold); } for (i = 6; i > 0; i--) { -- cgit v1.2.1 From cfbed87b304a517af27c22a7caf2cb345cb063f9 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Jan 2015 17:54:26 +0530 Subject: ath9k: Enable manual peak detect calibration On some AR955x/QCA953x boards, noise floor calibration gets stuck and the cause is a hardware/BB issue. To fix this, peak detect calibration in the HW is disabled and is done in the driver instead. There a few differences with the calibration routine for older chips like AR9331. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 91130c0e31d3..174442beb952 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1640,8 +1640,14 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, skip_tx_iqcal: if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { - if (AR_SREV_9330_11(ah)) - ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan)); + if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->rxchainmask & (1 << i))) + continue; + ar9003_hw_manual_peak_cal(ah, i, + IS_CHAN_2GHZ(chan)); + } + } /* * For non-AR9550 chips, we just trigger AGC calibration -- cgit v1.2.1 From 86144b01a25185ec092b9301e340ca4f7a8c0d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 25 Jan 2015 14:39:34 +0100 Subject: b43: support bcma core reset on AC-PHY hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AC-PHY hardware includes new control 0x3 bits that need to be set to the 0x1 by default. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/b43/b43.h | 2 ++ drivers/net/wireless/b43/main.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 65b2dd80ecd5..036552439816 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -500,6 +500,8 @@ enum { #define B43_BCMA_IOCTL_PHY_BW_10MHZ 0x00000000 /* 10 MHz bandwidth, 40 MHz PHY */ #define B43_BCMA_IOCTL_PHY_BW_20MHZ 0x00000040 /* 20 MHz bandwidth, 80 MHz PHY */ #define B43_BCMA_IOCTL_PHY_BW_40MHZ 0x00000080 /* 40 MHz bandwidth, 160 MHz PHY */ +#define B43_BCMA_IOCTL_PHY_BW_80MHZ 0x000000C0 /* 80 MHz bandwidth */ +#define B43_BCMA_IOCTL_DAC 0x00000300 /* Highspeed DAC mode control field */ #define B43_BCMA_IOCTL_GMODE 0x00002000 /* G Mode Enable */ /* BCMA 802.11 core specific IO status (BCMA_IOST) flags */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index d1c397162a6a..1784933573e4 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1262,6 +1262,23 @@ static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode) flags |= B43_BCMA_IOCTL_GMODE; b43_device_enable(dev, flags); + if (dev->phy.type == B43_PHYTYPE_AC) { + u16 tmp; + + tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); + tmp &= ~B43_BCMA_IOCTL_DAC; + tmp |= 0x100; + bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); + + tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); + tmp &= ~B43_BCMA_IOCTL_PHY_CLKEN; + bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); + + tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); + tmp |= B43_BCMA_IOCTL_PHY_CLKEN; + bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); + } + bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST); b43_bcma_phy_reset(dev); bcma_core_pll_ctl(dev->dev->bdev, req, status, true); -- cgit v1.2.1 From 3f7bb3f34cc880bc35f6c278be16cd8afee7c524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 25 Jan 2015 18:01:37 +0100 Subject: b43: AC-PHY: prepare place for developing new PHY support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are new (not anymore?) Broadcom 802.11ac wireless cards based on chipsets like BCM4352 and BCM4360. They use a new PHY type (called simply AC) that will require new specific code. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/b43/Kconfig | 9 ++++ drivers/net/wireless/b43/Makefile | 1 + drivers/net/wireless/b43/main.c | 10 ++++ drivers/net/wireless/b43/phy_ac.c | 92 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/b43/phy_ac.h | 38 +++++++++++++++ drivers/net/wireless/b43/phy_common.c | 9 +++- drivers/net/wireless/b43/phy_common.h | 2 + 7 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/b43/phy_ac.c create mode 100644 drivers/net/wireless/b43/phy_ac.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 64a5b672e30a..759fb8d41fc9 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -166,6 +166,15 @@ config B43_PHY_LCN Say N, this is BROKEN and crashes driver. +config B43_PHY_AC + bool "Support for AC-PHY (802.11ac) devices (BROKEN)" + depends on B43 && B43_BCMA && BROKEN + ---help--- + This PHY type can be found in the following chipsets: + PCI: BCM4352, BCM4360 + + Say N, this is BROKEN and crashes driver. + # This config option automatically enables b43 LEDS support, # if it's possible. config B43_LEDS diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 9f7965aae93d..c624d4d90e4f 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -13,6 +13,7 @@ b43-$(CONFIG_B43_PHY_HT) += phy_ht.o b43-$(CONFIG_B43_PHY_HT) += tables_phy_ht.o b43-$(CONFIG_B43_PHY_HT) += radio_2059.o b43-$(CONFIG_B43_PHY_LCN) += phy_lcn.o tables_phy_lcn.o +b43-$(CONFIG_B43_PHY_AC) += phy_ac.o b43-y += sysfs.o b43-y += xmit.o b43-y += dma.o diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1784933573e4..2c9088633ec6 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4543,6 +4543,12 @@ static int b43_phy_versioning(struct b43_wldev *dev) if (phy_rev > 1) unsupported = 1; break; +#endif +#ifdef CONFIG_B43_PHY_AC + case B43_PHYTYPE_AC: + if (phy_rev > 1) + unsupported = 1; + break; #endif default: unsupported = 1; @@ -4640,6 +4646,10 @@ static int b43_phy_versioning(struct b43_wldev *dev) if (radio_id != 0x2064) unsupported = 1; break; + case B43_PHYTYPE_AC: + if (radio_id != 0x2069) + unsupported = 1; + break; default: B43_WARN_ON(1); } diff --git a/drivers/net/wireless/b43/phy_ac.c b/drivers/net/wireless/b43/phy_ac.c new file mode 100644 index 000000000000..e75633d67938 --- /dev/null +++ b/drivers/net/wireless/b43/phy_ac.c @@ -0,0 +1,92 @@ +/* + * Broadcom B43 wireless driver + * IEEE 802.11ac AC-PHY support + * + * Copyright (c) 2015 RafaÅ‚ MiÅ‚ecki + * + * 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. + */ + +#include "b43.h" +#include "phy_ac.h" + +/************************************************** + * Basic PHY ops + **************************************************/ + +static int b43_phy_ac_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_ac *phy_ac; + + phy_ac = kzalloc(sizeof(*phy_ac), GFP_KERNEL); + if (!phy_ac) + return -ENOMEM; + dev->phy.ac = phy_ac; + + return 0; +} + +static void b43_phy_ac_op_free(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_ac *phy_ac = phy->ac; + + kfree(phy_ac); + phy->ac = NULL; +} + +static void b43_phy_ac_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, + u16 set) +{ + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, + (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set); +} + +static u16 b43_phy_ac_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO24_DATA); +} + +static void b43_phy_ac_op_radio_write(struct b43_wldev *dev, u16 reg, + u16 value) +{ + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO24_DATA, value); +} + +static unsigned int b43_phy_ac_op_get_default_chan(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + return 11; + return 36; +} + +static enum b43_txpwr_result +b43_phy_ac_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi) +{ + return B43_TXPWR_RES_DONE; +} + +static void b43_phy_ac_op_adjust_txpower(struct b43_wldev *dev) +{ +} + +/************************************************** + * PHY ops struct + **************************************************/ + +const struct b43_phy_operations b43_phyops_ac = { + .allocate = b43_phy_ac_op_allocate, + .free = b43_phy_ac_op_free, + .phy_maskset = b43_phy_ac_op_maskset, + .radio_read = b43_phy_ac_op_radio_read, + .radio_write = b43_phy_ac_op_radio_write, + .get_default_chan = b43_phy_ac_op_get_default_chan, + .recalc_txpower = b43_phy_ac_op_recalc_txpower, + .adjust_txpower = b43_phy_ac_op_adjust_txpower, +}; diff --git a/drivers/net/wireless/b43/phy_ac.h b/drivers/net/wireless/b43/phy_ac.h new file mode 100644 index 000000000000..d1ca79e0eb24 --- /dev/null +++ b/drivers/net/wireless/b43/phy_ac.h @@ -0,0 +1,38 @@ +#ifndef B43_PHY_AC_H_ +#define B43_PHY_AC_H_ + +#include "phy_common.h" + +#define B43_PHY_AC_BBCFG 0x001 +#define B43_PHY_AC_BBCFG_RSTCCA 0x4000 /* Reset CCA */ +#define B43_PHY_AC_BANDCTL 0x003 /* Band control */ +#define B43_PHY_AC_BANDCTL_5GHZ 0x0001 +#define B43_PHY_AC_TABLE_ID 0x00d +#define B43_PHY_AC_TABLE_OFFSET 0x00e +#define B43_PHY_AC_TABLE_DATA1 0x00f +#define B43_PHY_AC_TABLE_DATA2 0x010 +#define B43_PHY_AC_TABLE_DATA3 0x011 +#define B43_PHY_AC_CLASSCTL 0x140 /* Classifier control */ +#define B43_PHY_AC_CLASSCTL_CCKEN 0x0001 /* CCK enable */ +#define B43_PHY_AC_CLASSCTL_OFDMEN 0x0002 /* OFDM enable */ +#define B43_PHY_AC_CLASSCTL_WAITEDEN 0x0004 /* Waited enable */ +#define B43_PHY_AC_BW1A 0x371 +#define B43_PHY_AC_BW2 0x372 +#define B43_PHY_AC_BW3 0x373 +#define B43_PHY_AC_BW4 0x374 +#define B43_PHY_AC_BW5 0x375 +#define B43_PHY_AC_BW6 0x376 +#define B43_PHY_AC_RFCTL_CMD 0x408 +#define B43_PHY_AC_C1_CLIP 0x6d4 +#define B43_PHY_AC_C1_CLIP_DIS 0x4000 +#define B43_PHY_AC_C2_CLIP 0x8d4 +#define B43_PHY_AC_C2_CLIP_DIS 0x4000 +#define B43_PHY_AC_C3_CLIP 0xad4 +#define B43_PHY_AC_C3_CLIP_DIS 0x4000 + +struct b43_phy_ac { +}; + +extern const struct b43_phy_operations b43_phyops_ac; + +#endif /* B43_PHY_AC_H_ */ diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index ee27b06074e1..ec2b9c577b90 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -33,6 +33,7 @@ #include "phy_lp.h" #include "phy_ht.h" #include "phy_lcn.h" +#include "phy_ac.h" #include "b43.h" #include "main.h" @@ -68,6 +69,11 @@ int b43_phy_allocate(struct b43_wldev *dev) case B43_PHYTYPE_LCN: #ifdef CONFIG_B43_PHY_LCN phy->ops = &b43_phyops_lcn; +#endif + break; + case B43_PHYTYPE_AC: +#ifdef CONFIG_B43_PHY_AC + phy->ops = &b43_phyops_ac; #endif break; } @@ -572,7 +578,8 @@ void b43_phy_force_clock(struct b43_wldev *dev, bool force) u32 tmp; WARN_ON(dev->phy.type != B43_PHYTYPE_N && - dev->phy.type != B43_PHYTYPE_HT); + dev->phy.type != B43_PHYTYPE_HT && + dev->phy.type != B43_PHYTYPE_AC); switch (dev->dev->bus_type) { #ifdef CONFIG_B43_BCMA diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 3912274f71e3..78d86526799e 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -222,6 +222,8 @@ struct b43_phy { struct b43_phy_ht *ht; /* LCN-PHY specific information */ struct b43_phy_lcn *lcn; + /* AC-PHY specific information */ + struct b43_phy_ac *ac; }; /* Band support flags. */ -- cgit v1.2.1 From 5e752e42f6773c8e4d360b35c72dc1ef73240583 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 19 Jan 2015 09:53:41 +0100 Subject: ath10k: move wmm param storage to vif mac80211 already requests WMM per vif but firmware wasn't able to handle this until now. However new wmi-tlv firmware for qca6174 is capable of this. This prepares per-vif WMM param setup. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 11 ++++++----- drivers/net/wireless/ath/ath10k/wmi-ops.h | 4 ++-- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 32 +++++++++++++++---------------- drivers/net/wireless/ath/ath10k/wmi.c | 14 +++++++------- drivers/net/wireless/ath/ath10k/wmi.h | 6 +++--- 6 files changed, 35 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 2d9f87143089..abb32037c3f7 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -315,6 +315,7 @@ struct ath10k_vif { bool use_cts_prot; int num_legacy_stations; int txpower; + struct wmi_wmm_params_all_arg wmm_params; }; struct ath10k_vif_iter { @@ -577,7 +578,6 @@ struct ath10k { u8 cfg_tx_chainmask; u8 cfg_rx_chainmask; - struct wmi_pdev_set_wmm_params_arg wmm_params; struct completion install_key_done; struct completion vdev_setup_done; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 02e2bfc04ccf..62e8adc492cb 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4092,6 +4092,7 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, const struct ieee80211_tx_queue_params *params) { struct ath10k *ar = hw->priv; + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct wmi_wmm_params_arg *p = NULL; int ret; @@ -4099,16 +4100,16 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, switch (ac) { case IEEE80211_AC_VO: - p = &ar->wmm_params.ac_vo; + p = &arvif->wmm_params.ac_vo; break; case IEEE80211_AC_VI: - p = &ar->wmm_params.ac_vi; + p = &arvif->wmm_params.ac_vi; break; case IEEE80211_AC_BE: - p = &ar->wmm_params.ac_be; + p = &arvif->wmm_params.ac_be; break; case IEEE80211_AC_BK: - p = &ar->wmm_params.ac_bk; + p = &arvif->wmm_params.ac_bk; break; } @@ -4129,7 +4130,7 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, p->txop = params->txop * 32; /* FIXME: FW accepts wmm params per hw, not per vif */ - ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params); + ret = ath10k_wmi_pdev_set_wmm_params(ar, &arvif->wmm_params); if (ret) { ath10k_warn(ar, "failed to set wmm params: %d\n", ret); goto exit; diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 80bd28ac2ccb..6e9e38412b54 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -104,7 +104,7 @@ struct wmi_ops { const struct wmi_scan_chan_list_arg *arg); struct sk_buff *(*gen_beacon_dma)(struct ath10k_vif *arvif); struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar, - const struct wmi_pdev_set_wmm_params_arg *arg); + const struct wmi_wmm_params_all_arg *arg); struct sk_buff *(*gen_request_stats)(struct ath10k *ar, enum wmi_stats_id stats_id); struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar, @@ -774,7 +774,7 @@ ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) static inline int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, - const struct wmi_pdev_set_wmm_params_arg *arg) + const struct wmi_wmm_params_all_arg *arg) { struct sk_buff *skb; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index d3cf91dc950b..23a376124de3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1584,6 +1584,21 @@ ath10k_wmi_tlv_op_gen_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id, return skb; } +static void *ath10k_wmi_tlv_put_wmm(void *ptr, + const struct wmi_wmm_params_arg *arg) +{ + struct wmi_wmm_params *wmm; + struct wmi_tlv *tlv; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WMM_PARAMS); + tlv->len = __cpu_to_le16(sizeof(*wmm)); + wmm = (void *)tlv->value; + ath10k_wmi_set_wmm_param(wmm, arg); + + return ptr + sizeof(*tlv) + sizeof(*wmm); +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, const u8 peer_addr[ETH_ALEN]) @@ -1944,24 +1959,9 @@ ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k_vif *arvif) return skb; } -static void *ath10k_wmi_tlv_put_wmm(void *ptr, - const struct wmi_wmm_params_arg *arg) -{ - struct wmi_wmm_params *wmm; - struct wmi_tlv *tlv; - - tlv = ptr; - tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WMM_PARAMS); - tlv->len = __cpu_to_le16(sizeof(*wmm)); - wmm = (void *)tlv->value; - ath10k_wmi_pdev_set_wmm_param(wmm, arg); - - return ptr + sizeof(*tlv) + sizeof(*wmm); -} - static struct sk_buff * ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar, - const struct wmi_pdev_set_wmm_params_arg *arg) + const struct wmi_wmm_params_all_arg *arg) { struct wmi_tlv_pdev_set_wmm_cmd *cmd; struct wmi_wmm_params *wmm; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index fb1e2d1f343c..050e5088acf2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4890,8 +4890,8 @@ ath10k_wmi_op_gen_beacon_dma(struct ath10k_vif *arvif) return skb; } -void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, - const struct wmi_wmm_params_arg *arg) +void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params, + const struct wmi_wmm_params_arg *arg) { params->cwmin = __cpu_to_le32(arg->cwmin); params->cwmax = __cpu_to_le32(arg->cwmax); @@ -4903,7 +4903,7 @@ void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, static struct sk_buff * ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar, - const struct wmi_pdev_set_wmm_params_arg *arg) + const struct wmi_wmm_params_all_arg *arg) { struct wmi_pdev_set_wmm_params *cmd; struct sk_buff *skb; @@ -4913,10 +4913,10 @@ ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar, return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_set_wmm_params *)skb->data; - ath10k_wmi_pdev_set_wmm_param(&cmd->ac_be, &arg->ac_be); - ath10k_wmi_pdev_set_wmm_param(&cmd->ac_bk, &arg->ac_bk); - ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi); - ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo); + ath10k_wmi_set_wmm_param(&cmd->ac_be, &arg->ac_be); + ath10k_wmi_set_wmm_param(&cmd->ac_bk, &arg->ac_bk); + ath10k_wmi_set_wmm_param(&cmd->ac_vi, &arg->ac_vi); + ath10k_wmi_set_wmm_param(&cmd->ac_vo, &arg->ac_vo); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n"); return skb; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 34d8c44b90e8..c0093938c6ee 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2939,7 +2939,7 @@ struct wmi_wmm_params_arg { u32 no_ack; }; -struct wmi_pdev_set_wmm_params_arg { +struct wmi_wmm_params_all_arg { struct wmi_wmm_params_arg ac_be; struct wmi_wmm_params_arg ac_bk; struct wmi_wmm_params_arg ac_vi; @@ -4869,8 +4869,8 @@ void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, struct wmi_host_mem_chunks *chunks); void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, const struct wmi_start_scan_arg *arg); -void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, - const struct wmi_wmm_params_arg *arg); +void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params, + const struct wmi_wmm_params_arg *arg); void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, const struct wmi_channel_arg *arg); int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg); -- cgit v1.2.1 From 6d492fe2d81e84ee49382879bfc13213c6e8e569 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 28 Jan 2015 09:57:22 +0200 Subject: ath10k: implement per-vdev wmm param setup command New wmi-tlv firmware for qca6174 supports this. This will be used soon. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 17 ++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 38 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 4 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 3 +++ drivers/net/wireless/ath/ath10k/wmi.h | 1 + 5 files changed, 63 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 6e9e38412b54..987414abc443 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -78,6 +78,8 @@ struct wmi_ops { const struct wmi_vdev_spectral_conf_arg *arg); struct sk_buff *(*gen_vdev_spectral_enable)(struct ath10k *ar, u32 vdev_id, u32 trigger, u32 enable); + struct sk_buff *(*gen_vdev_wmm_conf)(struct ath10k *ar, u32 vdev_id, + const struct wmi_wmm_params_all_arg *arg); struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id, const u8 peer_addr[ETH_ALEN]); struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id, @@ -600,6 +602,21 @@ ath10k_wmi_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id, return ath10k_wmi_cmd_send(ar, skb, cmd_id); } +static inline int +ath10k_wmi_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, + const struct wmi_wmm_params_all_arg *arg) +{ + struct sk_buff *skb; + u32 cmd_id; + + skb = ar->wmi.ops->gen_vdev_wmm_conf(ar, vdev_id, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->vdev_set_wmm_params_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + static inline int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, const u8 peer_addr[ETH_ALEN]) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 23a376124de3..00ca544bc94d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1599,6 +1599,42 @@ static void *ath10k_wmi_tlv_put_wmm(void *ptr, return ptr + sizeof(*tlv) + sizeof(*wmm); } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, + const struct wmi_wmm_params_all_arg *arg) +{ + struct wmi_tlv_vdev_set_wmm_cmd *cmd; + struct wmi_wmm_params *wmm; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + void *ptr; + + len = (sizeof(*tlv) + sizeof(*cmd)) + + (4 * (sizeof(*tlv) + sizeof(*wmm))); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev wmm conf\n"); + return skb; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, const u8 peer_addr[ETH_ALEN]) @@ -2426,6 +2462,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = { .gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED, + .vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID, }; static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { @@ -2569,6 +2606,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_vdev_down = ath10k_wmi_tlv_op_gen_vdev_down, .gen_vdev_set_param = ath10k_wmi_tlv_op_gen_vdev_set_param, .gen_vdev_install_key = ath10k_wmi_tlv_op_gen_vdev_install_key, + .gen_vdev_wmm_conf = ath10k_wmi_tlv_op_gen_vdev_wmm_conf, .gen_peer_create = ath10k_wmi_tlv_op_gen_peer_create, .gen_peer_delete = ath10k_wmi_tlv_op_gen_peer_delete, .gen_peer_flush = ath10k_wmi_tlv_op_gen_peer_flush, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 87db762ac1a2..3dc43b90469d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1302,6 +1302,10 @@ struct wmi_tlv_pdev_set_wmm_cmd { __le32 dg_type; /* no idea.. */ } __packed; +struct wmi_tlv_vdev_set_wmm_cmd { + __le32 vdev_id; +} __packed; + struct wmi_tlv_phyerr_ev { __le32 num_phyerrs; __le32 tsf_l32; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 050e5088acf2..81561e4ae308 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5188,6 +5188,7 @@ static const struct wmi_ops wmi_ops = { .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + /* .gen_vdev_wmm_conf not implemented */ .gen_peer_create = ath10k_wmi_op_gen_peer_create, .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, @@ -5251,6 +5252,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + /* .gen_vdev_wmm_conf not implemented */ .gen_peer_create = ath10k_wmi_op_gen_peer_create, .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, @@ -5313,6 +5315,7 @@ static const struct wmi_ops wmi_10_2_ops = { .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + /* .gen_vdev_wmm_conf not implemented */ .gen_peer_create = ath10k_wmi_op_gen_peer_create, .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index c0093938c6ee..3c48e0d21900 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -551,6 +551,7 @@ struct wmi_cmd_map { u32 gpio_config_cmdid; u32 gpio_output_cmdid; u32 pdev_get_temperature_cmdid; + u32 vdev_set_wmm_params_cmdid; }; /* -- cgit v1.2.1 From 7fc979a79d9b9af15052b4c7fd1debd44294ba4f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 28 Jan 2015 09:57:28 +0200 Subject: ath10k: use per-vif wmm param setup if possible New wmi-tlv firmware for qca6174 supports this. This should fix issues related to multi-vif WMM. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 62e8adc492cb..0c2ccc101176 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4129,11 +4129,23 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, */ p->txop = params->txop * 32; - /* FIXME: FW accepts wmm params per hw, not per vif */ - ret = ath10k_wmi_pdev_set_wmm_params(ar, &arvif->wmm_params); - if (ret) { - ath10k_warn(ar, "failed to set wmm params: %d\n", ret); - goto exit; + if (ar->wmi.ops->gen_vdev_wmm_conf) { + ret = ath10k_wmi_vdev_wmm_conf(ar, arvif->vdev_id, + &arvif->wmm_params); + if (ret) { + ath10k_warn(ar, "failed to set vdev wmm params on vdev %i: %d\n", + arvif->vdev_id, ret); + goto exit; + } + } else { + /* This won't work well with multi-interface cases but it's + * better than nothing. + */ + ret = ath10k_wmi_pdev_set_wmm_params(ar, &arvif->wmm_params); + if (ret) { + ath10k_warn(ar, "failed to set wmm params: %d\n", ret); + goto exit; + } } ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd); -- cgit v1.2.1 From 6e8b188ba782bd04f942b7d489b8b2b81606f690 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 28 Jan 2015 09:57:39 +0200 Subject: ath10k: implement sta keepalive command New wmi-tlv firmware for qca6174 has STA keepalive service available. The service can provide automatic idle connection polling via NullFunc frames to AP when acting as a client. Signed-off-by: Janusz Dziedzic Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 20 ++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 45 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 7 +++++ drivers/net/wireless/ath/ath10k/wmi.h | 10 +++++++ 4 files changed, 82 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 987414abc443..058f88b6ff53 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -143,6 +143,8 @@ struct wmi_ops { const u8 peer_addr[ETH_ALEN], const struct wmi_sta_uapsd_auto_trig_arg *args, u32 num_ac); + struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar, + const struct wmi_sta_keepalive_arg *arg); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -1034,4 +1036,22 @@ ath10k_wmi_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id, const u8 *p2p_ie) return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->p2p_go_set_beacon_ie); } +static inline int +ath10k_wmi_sta_keepalive(struct ath10k *ar, + const struct wmi_sta_keepalive_arg *arg) +{ + struct sk_buff *skb; + u32 cmd_id; + + if (!ar->wmi.ops->gen_sta_keepalive) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_sta_keepalive(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->sta_keepalive_cmd; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 00ca544bc94d..be32db96701f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1635,6 +1635,50 @@ ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, return skb; } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar, + const struct wmi_sta_keepalive_arg *arg) +{ + struct wmi_tlv_sta_keepalive_cmd *cmd; + struct wmi_sta_keepalive_arp_resp *arp; + struct sk_buff *skb; + struct wmi_tlv *tlv; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + sizeof(*arp); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + cmd->enabled = __cpu_to_le32(arg->enabled); + cmd->method = __cpu_to_le32(arg->method); + cmd->interval = __cpu_to_le32(arg->interval); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE); + tlv->len = __cpu_to_le16(sizeof(*arp)); + arp = (void *)tlv->value; + + arp->src_ip4_addr = arg->src_ip4_addr; + arp->dest_ip4_addr = arg->dest_ip4_addr; + ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv sta keepalive vdev %d enabled %d method %d inverval %d\n", + arg->vdev_id, arg->enabled, arg->method, arg->interval); + return skb; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, const u8 peer_addr[ETH_ALEN]) @@ -2634,6 +2678,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl, .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie, .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd, + .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive, }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 3dc43b90469d..de68fe76eae6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1432,6 +1432,13 @@ struct wmi_tlv_diag_data_ev { __le32 num_items; } __packed; +struct wmi_tlv_sta_keepalive_cmd { + __le32 vdev_id; + __le32 enabled; + __le32 method; /* WMI_STA_KEEPALIVE_METHOD_ */ + __le32 interval; /* in seconds */ +} __packed; + void ath10k_wmi_tlv_attach(struct ath10k *ar); #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 3c48e0d21900..1a99a7dd0e95 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4680,6 +4680,16 @@ struct wmi_sta_keepalive_cmd { struct wmi_sta_keepalive_arp_resp arp_resp; } __packed; +struct wmi_sta_keepalive_arg { + u32 vdev_id; + u32 enabled; + u32 method; + u32 interval; + __be32 src_ip4_addr; + __be32 dest_ip4_addr; + const u8 dest_mac_addr[ETH_ALEN]; +}; + enum wmi_force_fw_hang_type { WMI_FORCE_FW_HANG_ASSERT = 1, WMI_FORCE_FW_HANG_NO_DETECT, -- cgit v1.2.1 From 46725b15334ca0598f1cc7ea34d2f6963bec11cb Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 28 Jan 2015 09:57:49 +0200 Subject: ath10k: disable sta keepalive Firmware revisions providing sta keepalive service have it enabled by default. mac80211 already does idle connection polling so it makes no sense to duplicate this in ath10k. mac80211 wouldn't even know of the offloaded keepalive NullFunc frames. This prevents sending out some extraneous frames on the air. Signed-off-by: Janusz Dziedzic Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 42 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 5 +++++ 2 files changed, 47 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0c2ccc101176..4ee74f660443 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1286,6 +1286,38 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) return 0; } +static int ath10k_mac_vif_disable_keepalive(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + struct wmi_sta_keepalive_arg arg = {}; + int ret; + + lockdep_assert_held(&arvif->ar->conf_mutex); + + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + return 0; + + if (!test_bit(WMI_SERVICE_STA_KEEP_ALIVE, ar->wmi.svc_map)) + return 0; + + /* Some firmware revisions have a bug and ignore the `enabled` field. + * Instead use the interval to disable the keepalive. + */ + arg.vdev_id = arvif->vdev_id; + arg.enabled = 1; + arg.method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME; + arg.interval = WMI_STA_KEEPALIVE_INTERVAL_DISABLE; + + ret = ath10k_wmi_sta_keepalive(ar, &arg); + if (ret) { + ath10k_warn(ar, "failed to submit keepalive on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + /**********************/ /* Station management */ /**********************/ @@ -3180,6 +3212,16 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ar->free_vdev_map &= ~(1LL << arvif->vdev_id); list_add(&arvif->list, &ar->arvifs); + /* It makes no sense to have firmware do keepalives. mac80211 already + * takes care of this with idle connection polling. + */ + ret = ath10k_mac_vif_disable_keepalive(arvif); + if (ret) { + ath10k_warn(ar, "failed to disable keepalive on vdev %i: %d\n", + arvif->vdev_id, ret); + goto err_vdev_delete; + } + vdev_param = ar->wmi.vdev_param->def_keyid; ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param, arvif->def_wep_key_idx); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 1a99a7dd0e95..4b654083b857 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4665,6 +4665,11 @@ enum wmi_sta_keepalive_method { WMI_STA_KEEPALIVE_METHOD_UNSOLICITATED_ARP_RESPONSE = 2, }; +#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0 + +/* Firmware crashes if keepalive interval exceeds this limit */ +#define WMI_STA_KEEPALIVE_INTERVAL_MAX_SECONDS 0xffff + /* note: ip4 addresses are in network byte order, i.e. big endian */ struct wmi_sta_keepalive_arp_resp { __be32 src_ip4_addr; -- cgit v1.2.1 From d68bb12ab4a306ee76ab33a57b2a0067d4d5092d Mon Sep 17 00:00:00 2001 From: Yanbo Li Date: Fri, 23 Jan 2015 08:18:20 +0800 Subject: ath10k: Enable the MCS8 and MCS9 at 2.4G band Enable the MCS8 and MCS9 support for 2.4G band, it will use these data rate with other devices having the same capability. Signed-off-by: Yanbo Li Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 14 ++++++++++++-- drivers/net/wireless/ath/ath10k/wmi.h | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4ee74f660443..f9440deffa26 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1586,6 +1586,10 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, return; arg->peer_flags |= WMI_PEER_VHT; + + if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) + arg->peer_flags |= WMI_PEER_VHT_2G; + arg->peer_vht_caps = vht_cap->cap; ampdu_factor = (vht_cap->cap & @@ -1664,7 +1668,12 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, switch (ar->hw->conf.chandef.chan->band) { case IEEE80211_BAND_2GHZ: - if (sta->ht_cap.ht_supported) { + if (sta->vht_cap.vht_supported) { + if (sta->bandwidth == IEEE80211_STA_RX_BW_40) + phymode = MODE_11AC_VHT40; + else + phymode = MODE_11AC_VHT20; + } else if (sta->ht_cap.ht_supported) { if (sta->bandwidth == IEEE80211_STA_RX_BW_40) phymode = MODE_11NG_HT40; else @@ -5301,7 +5310,8 @@ int ath10k_mac_register(struct ath10k *ar) band->bitrates = ath10k_g_rates; band->ht_cap = ht_cap; - /* vht is not supported in 2.4 GHz */ + /* Enable the VHT support at 2.4 GHz */ + band->vht_cap = vht_cap; ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4b654083b857..20ce3603e64b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4514,7 +4514,7 @@ struct wmi_peer_set_q_empty_callback_cmd { #define WMI_PEER_SPATIAL_MUX 0x00200000 #define WMI_PEER_VHT 0x02000000 #define WMI_PEER_80MHZ 0x04000000 -#define WMI_PEER_PMF 0x08000000 +#define WMI_PEER_VHT_2G 0x08000000 /* * Peer rate capabilities. -- cgit v1.2.1 From 6c3d7d785966f89bda1be17aef59ad14ce321f38 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 26 Jan 2015 22:13:06 +0530 Subject: ath10k: fix target wakeup timeout During drv_start/drv_stop stress testing in ARM platform, sometimes target is taking more that 5ms to wake up. Similar behaviour also noted during driver load and unload iterations. On such cases, the wakup duration lies between 5-6ms. Hence increasing pci wakup timeout 10ms to be more safer. With this changes, able to complete power down/up >100 iterations without any issues. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index ce4a1ef89961..bddf54320160 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -194,7 +194,7 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) #define ATH10K_PCI_RX_POST_RETRY_MS 50 #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */ -#define PCIE_WAKE_TIMEOUT 5000 /* 5ms */ +#define PCIE_WAKE_TIMEOUT 10000 /* 10ms */ #define BAR_NUM 0 -- cgit v1.2.1 From 4b222ca68a7a24501c1a7b7505512e845799dd65 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Wed, 28 Jan 2015 20:06:48 +0800 Subject: net: gianfar: remove the unneeded check of disabled device Since commit cd1e65044d44 ("of/device: Don't register disabled devices"), the disabled device will not be registered at all. So we don't need to do the check again in the platform device driver. Signed-off-by: Kevin Hao Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 93ff846e96f1..43df78882e48 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -764,7 +764,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) u32 *tx_queues, *rx_queues; unsigned short mode, poll_mode; - if (!np || !of_device_is_available(np)) + if (!np) return -ENODEV; if (of_device_is_compatible(np, "fsl,etsec2")) { -- cgit v1.2.1 From e5a49c1e3b189c744770e04d2b46ec7ca37d604c Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 28 Jan 2015 11:33:04 -0800 Subject: net: cpsw: Add a minimal cpsw-common module for shared code Looks like davinci_emac and cpsw can share some code although the device registers have a different layout. At least the code for getting the MAC address using syscon can be shared by passing the register offset. Let's start with that and set up a minimal shared cpsw-shared.c. Cc: Brian Hutchinson Cc: Felipe Balbi Signed-off-by: Tony Lindgren Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/Makefile | 3 ++ drivers/net/ethernet/ti/cpsw-common.c | 53 +++++++++++++++++++++++++++++++++++ drivers/net/ethernet/ti/cpsw.c | 35 ++--------------------- drivers/net/ethernet/ti/cpsw.h | 2 ++ 4 files changed, 60 insertions(+), 33 deletions(-) create mode 100644 drivers/net/ethernet/ti/cpsw-common.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 0a9813bc0451..5475cf60fa2d 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -2,6 +2,9 @@ # Makefile for the TI network device drivers. # +obj-$(CONFIG_TI_CPSW) += cpsw-common.o +obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o + obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_CPMAC) += cpmac.o obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o diff --git a/drivers/net/ethernet/ti/cpsw-common.c b/drivers/net/ethernet/ti/cpsw-common.c new file mode 100644 index 000000000000..763ada18ad3d --- /dev/null +++ b/drivers/net/ethernet/ti/cpsw-common.c @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#define AM33XX_CTRL_MAC_LO_REG(offset, id) ((offset) + 0x8 * (id)) +#define AM33XX_CTRL_MAC_HI_REG(offset, id) ((offset) + 0x8 * (id) + 0x4) + +int cpsw_am33xx_cm_get_macid(struct device *dev, u16 offset, int slave, + u8 *mac_addr) +{ + u32 macid_lo; + u32 macid_hi; + struct regmap *syscon; + + syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); + if (IS_ERR(syscon)) { + if (PTR_ERR(syscon) == -ENODEV) + return 0; + return PTR_ERR(syscon); + } + + regmap_read(syscon, AM33XX_CTRL_MAC_LO_REG(offset, slave), + &macid_lo); + regmap_read(syscon, AM33XX_CTRL_MAC_HI_REG(offset, slave), + &macid_hi); + + mac_addr[5] = (macid_lo >> 8) & 0xff; + mac_addr[4] = macid_lo & 0xff; + mac_addr[3] = (macid_hi >> 24) & 0xff; + mac_addr[2] = (macid_hi >> 16) & 0xff; + mac_addr[1] = (macid_hi >> 8) & 0xff; + mac_addr[0] = macid_hi & 0xff; + + return 0; +} +EXPORT_SYMBOL_GPL(cpsw_am33xx_cm_get_macid); + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 2b9d404f8586..7d8dd0d2182e 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include @@ -1936,36 +1934,6 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, slave->port_vlan = data->dual_emac_res_vlan; } -#define AM33XX_CTRL_MAC_LO_REG(id) (0x630 + 0x8 * id) -#define AM33XX_CTRL_MAC_HI_REG(id) (0x630 + 0x8 * id + 0x4) - -static int cpsw_am33xx_cm_get_macid(struct device *dev, int slave, - u8 *mac_addr) -{ - u32 macid_lo; - u32 macid_hi; - struct regmap *syscon; - - syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); - if (IS_ERR(syscon)) { - if (PTR_ERR(syscon) == -ENODEV) - return 0; - return PTR_ERR(syscon); - } - - regmap_read(syscon, AM33XX_CTRL_MAC_LO_REG(slave), &macid_lo); - regmap_read(syscon, AM33XX_CTRL_MAC_HI_REG(slave), &macid_hi); - - mac_addr[5] = (macid_lo >> 8) & 0xff; - mac_addr[4] = macid_lo & 0xff; - mac_addr[3] = (macid_hi >> 24) & 0xff; - mac_addr[2] = (macid_hi >> 16) & 0xff; - mac_addr[1] = (macid_hi >> 8) & 0xff; - mac_addr[0] = macid_hi & 0xff; - - return 0; -} - static int cpsw_probe_dt(struct cpsw_platform_data *data, struct platform_device *pdev) { @@ -2090,7 +2058,8 @@ no_phy_slave: memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN); } else { if (of_machine_is_compatible("ti,am33xx")) { - ret = cpsw_am33xx_cm_get_macid(&pdev->dev, i, + ret = cpsw_am33xx_cm_get_macid(&pdev->dev, + 0x630, i, slave_data->mac_addr); if (ret) return ret; diff --git a/drivers/net/ethernet/ti/cpsw.h b/drivers/net/ethernet/ti/cpsw.h index 1b710674630c..ca90efafd156 100644 --- a/drivers/net/ethernet/ti/cpsw.h +++ b/drivers/net/ethernet/ti/cpsw.h @@ -41,5 +41,7 @@ struct cpsw_platform_data { }; void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave); +int cpsw_am33xx_cm_get_macid(struct device *dev, u16 offset, int slave, + u8 *mac_addr); #endif /* __CPSW_H__ */ -- cgit v1.2.1 From 9120bd6e9f779d921450ec53cea02eff07003eae Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 28 Jan 2015 11:33:05 -0800 Subject: net: davinci_emac: Get device dm816x MAC address using the cpsw code At least on dm81xx, we can get the davinci_emac MAC address the same way as on am33xx cpsw. Let's also use ether_addr_copy() for davinci_emac while at it. Cc: Brian Hutchinson Cc: Felipe Balbi Signed-off-by: Tony Lindgren Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_emac.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 5fae4354722c..a7169384ff6e 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -69,6 +69,7 @@ #include #include +#include "cpsw.h" #include "davinci_cpdma.h" static int debug_level; @@ -1838,7 +1839,7 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv) if (!is_valid_ether_addr(pdata->mac_addr)) { mac_addr = of_get_mac_address(np); if (mac_addr) - memcpy(pdata->mac_addr, mac_addr, ETH_ALEN); + ether_addr_copy(pdata->mac_addr, mac_addr); } of_property_read_u32(np, "ti,davinci-ctrl-reg-offset", @@ -1879,6 +1880,22 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv) return pdata; } +static int davinci_emac_try_get_mac(struct platform_device *pdev, + int instance, u8 *mac_addr) +{ + int error = -EINVAL; + + if (!pdev->dev.of_node) + return error; + + if (of_device_is_compatible(pdev->dev.of_node, "ti,dm816-emac")) + error = cpsw_am33xx_cm_get_macid(&pdev->dev, 0x30, + instance, + mac_addr); + + return error; +} + /** * davinci_emac_probe - EMAC device probe * @pdev: The DaVinci EMAC device that we are removing @@ -2009,6 +2026,10 @@ static int davinci_emac_probe(struct platform_device *pdev) } ndev->irq = res->start; + rc = davinci_emac_try_get_mac(pdev, res_ctrl ? 0 : 1, priv->mac_addr); + if (!rc) + ether_addr_copy(ndev->dev_addr, priv->mac_addr); + if (!is_valid_ether_addr(priv->mac_addr)) { /* Use random MAC if none passed */ eth_hw_addr_random(ndev); -- cgit v1.2.1 From f276c0ce5d9256bb87e65f88ddea28a6a5eafdb2 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 28 Jan 2015 11:33:06 -0800 Subject: net: davinci_emac: Get device MAC on 3517 Looks like on 3517 davinci_emac MAC address registers have a different layout compared to dm816x and am33xx. Let's add a function to get the 3517 MAC address. Signed-off-by: Tony Lindgren Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_emac.c | 35 +++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index a7169384ff6e..aeebc0a7bf47 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,7 @@ #include #include #include +#include #include #include @@ -1880,6 +1882,33 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv) return pdata; } +static int davinci_emac_3517_get_macid(struct device *dev, u16 offset, + int slave, u8 *mac_addr) +{ + u32 macid_lsb; + u32 macid_msb; + struct regmap *syscon; + + syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); + if (IS_ERR(syscon)) { + if (PTR_ERR(syscon) == -ENODEV) + return 0; + return PTR_ERR(syscon); + } + + regmap_read(syscon, offset, &macid_lsb); + regmap_read(syscon, offset + 4, &macid_msb); + + mac_addr[0] = (macid_msb >> 16) & 0xff; + mac_addr[1] = (macid_msb >> 8) & 0xff; + mac_addr[2] = macid_msb & 0xff; + mac_addr[3] = (macid_lsb >> 16) & 0xff; + mac_addr[4] = (macid_lsb >> 8) & 0xff; + mac_addr[5] = macid_lsb & 0xff; + + return 0; +} + static int davinci_emac_try_get_mac(struct platform_device *pdev, int instance, u8 *mac_addr) { @@ -1888,7 +1917,11 @@ static int davinci_emac_try_get_mac(struct platform_device *pdev, if (!pdev->dev.of_node) return error; - if (of_device_is_compatible(pdev->dev.of_node, "ti,dm816-emac")) + if (of_device_is_compatible(pdev->dev.of_node, "ti,am3517-emac")) + error = davinci_emac_3517_get_macid(&pdev->dev, 0x110, + 0, mac_addr); + else if (of_device_is_compatible(pdev->dev.of_node, + "ti,dm816-emac")) error = cpsw_am33xx_cm_get_macid(&pdev->dev, 0x30, instance, mac_addr); -- cgit v1.2.1 From 207895fd388c7c4c48bc33055cd726d9e750298c Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 29 Jan 2015 12:15:03 +0100 Subject: net: mark some potential candidates __read_mostly They are all either written once or extremly rarely (e.g. from init code), so we can move them to the .data..read_mostly section. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 2e195289ddf4..2a175006028b 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -9,7 +9,7 @@ #include "ipvlan.h" -static u32 ipvlan_jhash_secret; +static u32 ipvlan_jhash_secret __read_mostly; void ipvlan_init_secret(void) { -- cgit v1.2.1 From 58c11b5faed6913f73f2763d3a85e4a668e8ba2b Mon Sep 17 00:00:00 2001 From: "Karicheri, Muralidharan" Date: Thu, 29 Jan 2015 18:15:51 -0500 Subject: drivers: net: cpsw: make cpsw_ale.c a module to allow re-use on Keystone NetCP on Keystone has cpsw ale function similar to other TI SoCs and this driver is re-used. To allow both ti cpsw and keystone netcp to re-use the driver, convert the cpsw ale to a module and configure it through Kconfig option CONFIG_TI_CPSW_ALE. Currently it is statically linked to both TI CPSW and NetCP and this causes issues when the above drivers are built as dynamic modules. This patch addresses this issue While at it, fix the Makefile and code to build both netcp_core and netcp_ethss as dynamic modules. This is needed to support arm allmodconfig. This also requires exporting of API calls provided by netcp_core so that both the above can be dynamic modules. Signed-off-by: Murali Karicheri Acked-by: Arnd Bergmann Acked-by: Lad, Prabhakar Acked-by: Mugunthan V N Tested-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/Kconfig | 19 +++++++++++++++++-- drivers/net/ethernet/ti/Makefile | 8 +++++--- drivers/net/ethernet/ti/cpsw_ale.c | 26 ++++++++++++++++++++++++-- drivers/net/ethernet/ti/netcp_core.c | 8 ++++++++ drivers/net/ethernet/ti/netcp_ethss.c | 5 +++++ 5 files changed, 59 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 4ea1663f3dea..3bc992cd70b7 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -56,12 +56,18 @@ config TI_CPSW_PHY_SEL This driver supports configuring of the phy mode connected to the CPSW. +config TI_CPSW_ALE + tristate "TI CPSW ALE Support" + ---help--- + This driver supports TI's CPSW ALE module. + config TI_CPSW tristate "TI CPSW Switch Support" depends on ARCH_DAVINCI || ARCH_OMAP2PLUS select TI_DAVINCI_CPDMA select TI_DAVINCI_MDIO select TI_CPSW_PHY_SEL + select TI_CPSW_ALE select MFD_SYSCON select REGMAP ---help--- @@ -80,15 +86,24 @@ config TI_CPTS and Layer 2 packets, and the driver offers a PTP Hardware Clock. config TI_KEYSTONE_NETCP - tristate "TI Keystone NETCP Ethernet subsystem Support" + tristate "TI Keystone NETCP Core Support" + select TI_CPSW_ALE depends on OF depends on KEYSTONE_NAVIGATOR_DMA && KEYSTONE_NAVIGATOR_QMSS ---help--- - This driver supports TI's Keystone NETCP Ethernet subsystem. + This driver supports TI's Keystone NETCP Core. To compile this driver as a module, choose M here: the module will be called keystone_netcp. +config TI_KEYSTONE_NETCP_ETHSS + depends on TI_KEYSTONE_NETCP + tristate "TI Keystone NETCP Ethernet subsystem Support" + ---help--- + + To compile this driver as a module, choose M here: the module + will be called keystone_netcp_ethss. + config TLAN tristate "TI ThunderLAN support" depends on (PCI || EISA) diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 5475cf60fa2d..d420d9413e4a 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -11,9 +11,11 @@ obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o +obj-$(CONFIG_TI_CPSW_ALE) += cpsw_ale.o obj-$(CONFIG_TI_CPSW) += ti_cpsw.o -ti_cpsw-y := cpsw_ale.o cpsw.o cpts.o +ti_cpsw-y := cpsw.o cpts.o obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o -keystone_netcp-y := netcp_core.o netcp_ethss.o netcp_sgmii.o \ - netcp_xgbepcsr.o cpsw_ale.o +keystone_netcp-y := netcp_core.o +obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o +keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 5246b3a18ff8..6e927b4583aa 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ #include +#include #include #include #include @@ -146,7 +147,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry) return idx; } -int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) +static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS]; int type, idx; @@ -167,7 +168,7 @@ int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) return -ENOENT; } -int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid) +static int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS]; int type, idx; @@ -265,6 +266,7 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid) } return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast); static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry, int port_mask) @@ -297,6 +299,7 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask) } return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_flush); static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry, int flags, u16 vid) @@ -334,6 +337,7 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast); int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags, u16 vid) @@ -349,6 +353,7 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast); int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, int flags, u16 vid, int mcast_state) @@ -380,6 +385,7 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast); int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, int flags, u16 vid) @@ -401,6 +407,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast); int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, int reg_mcast, int unreg_mcast) @@ -430,6 +437,7 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan); int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) { @@ -450,6 +458,7 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan); void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti) { @@ -479,6 +488,7 @@ void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti) cpsw_ale_write(ale, idx, ale_entry); } } +EXPORT_SYMBOL_GPL(cpsw_ale_set_allmulti); struct ale_control_info { const char *name; @@ -704,6 +714,7 @@ int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_control_set); int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) { @@ -727,6 +738,7 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) tmp = __raw_readl(ale->params.ale_regs + offset) >> shift; return tmp & BITMASK(info->bits); } +EXPORT_SYMBOL_GPL(cpsw_ale_control_get); static void cpsw_ale_timer(unsigned long arg) { @@ -750,6 +762,7 @@ int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout) } return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_set_ageout); void cpsw_ale_start(struct cpsw_ale *ale) { @@ -769,11 +782,13 @@ void cpsw_ale_start(struct cpsw_ale *ale) add_timer(&ale->timer); } } +EXPORT_SYMBOL_GPL(cpsw_ale_start); void cpsw_ale_stop(struct cpsw_ale *ale) { del_timer_sync(&ale->timer); } +EXPORT_SYMBOL_GPL(cpsw_ale_stop); struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) { @@ -788,6 +803,7 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) return ale; } +EXPORT_SYMBOL_GPL(cpsw_ale_create); int cpsw_ale_destroy(struct cpsw_ale *ale) { @@ -797,6 +813,7 @@ int cpsw_ale_destroy(struct cpsw_ale *ale) kfree(ale); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_destroy); void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) { @@ -807,3 +824,8 @@ void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) data += ALE_ENTRY_WORDS; } } +EXPORT_SYMBOL_GPL(cpsw_ale_dump); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI CPSW ALE driver"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index ba3002ec710a..a31a8c3c8e7c 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -354,6 +354,7 @@ fail: netcp_unregister_module(module); return ret; } +EXPORT_SYMBOL_GPL(netcp_register_module); static void netcp_release_module(struct netcp_device *netcp_device, struct netcp_module *module) @@ -414,6 +415,7 @@ void netcp_unregister_module(struct netcp_module *module) mutex_unlock(&netcp_modules_lock); } +EXPORT_SYMBOL_GPL(netcp_unregister_module); void *netcp_module_get_intf_data(struct netcp_module *module, struct netcp_intf *intf) @@ -425,6 +427,7 @@ void *netcp_module_get_intf_data(struct netcp_module *module, return intf_modpriv->module_priv; return NULL; } +EXPORT_SYMBOL_GPL(netcp_module_get_intf_data); /* Module TX and RX Hook management */ struct netcp_hook_list { @@ -459,6 +462,7 @@ int netcp_register_txhook(struct netcp_intf *netcp_priv, int order, return 0; } +EXPORT_SYMBOL_GPL(netcp_register_txhook); int netcp_unregister_txhook(struct netcp_intf *netcp_priv, int order, netcp_hook_rtn *hook_rtn, void *hook_data) @@ -480,6 +484,7 @@ int netcp_unregister_txhook(struct netcp_intf *netcp_priv, int order, spin_unlock_irqrestore(&netcp_priv->lock, flags); return -ENOENT; } +EXPORT_SYMBOL_GPL(netcp_unregister_txhook); int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order, netcp_hook_rtn *hook_rtn, void *hook_data) @@ -1226,6 +1231,7 @@ int netcp_txpipe_close(struct netcp_tx_pipe *tx_pipe) } return 0; } +EXPORT_SYMBOL_GPL(netcp_txpipe_close); int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe) { @@ -1267,6 +1273,7 @@ err: tx_pipe->dma_channel = NULL; return ret; } +EXPORT_SYMBOL_GPL(netcp_txpipe_open); int netcp_txpipe_init(struct netcp_tx_pipe *tx_pipe, struct netcp_device *netcp_device, @@ -1278,6 +1285,7 @@ int netcp_txpipe_init(struct netcp_tx_pipe *tx_pipe, tx_pipe->dma_queue_id = dma_queue_id; return 0; } +EXPORT_SYMBOL_GPL(netcp_txpipe_init); static struct netcp_addr *netcp_addr_find(struct netcp_intf *netcp, const u8 *addr, diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index fa1041a78b46..345cd2563772 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -2154,3 +2155,7 @@ static void __exit keystone_gbe_exit(void) netcp_unregister_module(&xgbe_module); } module_exit(keystone_gbe_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI NETCP ETHSS driver for Keystone SOCs"); +MODULE_AUTHOR("Sandeep Nair Date: Wed, 28 Jan 2015 09:00:27 +0200 Subject: iwlwifi: mvm: don't reprobe if we fail during reconfig and fw_restart is false If we don't want to restart the firmware, don't reprobe either in case of a failure during reconfiguration. This allows us to debug failures in the reconfig flow as well. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 8bf8c2a29e5e..b1dea6800b3b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -870,7 +870,10 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) * If WoWLAN fw asserted, don't restart either, mac80211 * can't recover this since we're already half suspended. */ - if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + if (!mvm->restart_fw && fw_error) { + schedule_work(&mvm->fw_error_dump_wk); + } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, + &mvm->status)) { struct iwl_mvm_reprobe *reprobe; IWL_ERR(mvm, @@ -894,16 +897,13 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) reprobe->dev = mvm->trans->dev; INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); schedule_work(&reprobe->work); - } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && - (!fw_error || mvm->restart_fw)) { + } else if (mvm->cur_ucode == IWL_UCODE_REGULAR) { /* don't let the transport/FW power down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); if (fw_error && mvm->restart_fw > 0) mvm->restart_fw--; ieee80211_restart_hw(mvm->hw); - } else if (fw_error) { - schedule_work(&mvm->fw_error_dump_wk); } } -- cgit v1.2.1 From edbad05131a3d94f997eb6c8040aab40f4fffe48 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Jan 2015 23:43:24 +0100 Subject: iwlwifi: mvm: remove space padding after sysassert description There's really no reason to pad out the field with spaces at the end of the line - they're practically invisible there anyway. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 4eb3cad31aa9..02f434d32800 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -432,7 +432,7 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) mvm->status, table.valid); } - IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, + IWL_ERR(mvm, "0x%08X | %s\n", table.error_id, desc_lookup(table.error_id)); IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); -- cgit v1.2.1 From 5523d11cc46393a1e61b7ef4a0b2d4e7ed9521e4 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 29 Jan 2015 12:48:20 +0200 Subject: iwlwifi: mvm: always use mac color zero We don't really need to use different mac colors when adding mac contexts, because they're not used anywhere. In fact, the firmware doesn't accept 255 as a valid color, so we get into a SYSASSERT 0x3401 when we reach that. Remove the color increment to use always zero and avoid reaching 255. CC: [3.10+] Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index cef6f3373542..cfd7bfcb3fc6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -707,9 +707,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, mvmvif->uploaded = false; mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; - /* does this make sense at all? */ - mvmvif->color++; - spin_lock_bh(&mvm->time_event_lock); iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); spin_unlock_bh(&mvm->time_event_lock); -- cgit v1.2.1 From e885c58bf88248a7e033749f532c3718442de22a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 25 Jan 2015 15:54:40 +0200 Subject: iwlwifi: pcie: don't dump useless data when a TFD queue hangs Printing all the scratch data of the TFDs of that queue is useless and stuffed the kernel log with data. Remove that. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/tx.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index d40cd4a67d6e..6c7bfe8905ca 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -147,7 +147,6 @@ static void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, static void iwl_pcie_txq_stuck_timer(unsigned long data) { struct iwl_txq *txq = (void *)data; - struct iwl_queue *q = &txq->q; struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie); u32 scd_sram_addr = trans_pcie->scd_base_addr + @@ -198,11 +197,6 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) iwl_read_prph(trans, SCD_QUEUE_WRPTR(i))); } - for (i = q->read_ptr; i != q->write_ptr; - i = iwl_queue_inc_wrap(i)) - IWL_ERR(trans, "scratch %d = 0x%08x\n", i, - le32_to_cpu(txq->scratchbufs[i].scratch)); - iwl_force_nmi(trans); } -- cgit v1.2.1 From 3d44eebf773950dd2e24ad7ac786b589d6522d67 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Fri, 16 Jan 2015 22:37:04 +0200 Subject: iwlwifi: mvm: add beamformer support VHT Beamformer (BFER) will be used if the peer supports it and there's a benefit to use it vs. STBC or SISO. The driver now tells the FW whether BFER and/or STBC are allowed but the FW will make the decision to use either or stick to SISO on its own. BFER is limited to a single remote peer. The driver takes care of ensuring this to the FW and prioritizes with which peer BFER will be used. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 + drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | 35 ++++-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 7 +- drivers/net/wireless/iwlwifi/mvm/rs.c | 157 ++++++++++++++++++++++++--- drivers/net/wireless/iwlwifi/mvm/rs.h | 4 +- 5 files changed, 177 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index e4f589898eda..016d91384681 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -270,6 +270,7 @@ enum iwl_ucode_tlv_api { * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. + * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current * tx power value into TPC Report action frame and Link Measurement Report @@ -288,6 +289,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), IWL_UCODE_TLV_CAPA_LAR_SUPPORT = BIT(1), IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2), + IWL_UCODE_TLV_CAPA_BEAMFORMER = BIT(3), IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = BIT(6), IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8), IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 6a2a6b0ab91b..4c33f2775dc9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h @@ -308,16 +308,33 @@ enum { #define LQ_FLAG_DYNAMIC_BW_POS 6 #define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS) -/* Single Stream Parameters - * SS_STBC/BFER_ALLOWED - Controls whether STBC or Beamformer (BFER) is allowed - * ucode will make a smart decision between SISO/STBC/BFER - * SS_PARAMS_VALID - if not set ignore the ss_params field. +/* Single Stream Tx Parameters (lq_cmd->ss_params) + * Flags to control a smart FW decision about whether BFER/STBC/SISO will be + * used for single stream Tx. */ -enum { - RS_SS_STBC_ALLOWED = BIT(0), - RS_SS_BFER_ALLOWED = BIT(1), - RS_SS_PARAMS_VALID = BIT(31), -}; + +/* Bit 0-1: Max STBC streams allowed. Can be 0-3. + * (0) - No STBC allowed + * (1) - 2x1 STBC allowed (HT/VHT) + * (2) - 4x2 STBC allowed (HT/VHT) + * (3) - 3x2 STBC allowed (HT only) + * All our chips are at most 2 antennas so only (1) is valid for now. + */ +#define LQ_SS_STBC_ALLOWED_POS 0 +#define LQ_SS_STBC_ALLOWED_MSK (3 << LQ_SS_STBC_ALLOWED_MSK) + +/* 2x1 STBC is allowed */ +#define LQ_SS_STBC_1SS_ALLOWED (1 << LQ_SS_STBC_ALLOWED_POS) + +/* Bit 2: Beamformer (VHT only) is allowed */ +#define LQ_SS_BFER_ALLOWED_POS 2 +#define LQ_SS_BFER_ALLOWED (1 << LQ_SS_BFER_ALLOWED_POS) + +/* Bit 31: ss_params field is valid. Used for FW backward compatibility + * with other drivers which don't support the ss_params API yet + */ +#define LQ_SS_PARAMS_VALID_POS 31 +#define LQ_SS_PARAMS_VALID (1 << LQ_SS_PARAMS_VALID_POS) /** * struct iwl_lq_cmd - link quality command diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index cfd7bfcb3fc6..51e02e6ba0ac 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -401,10 +401,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; - if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) + if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) { hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; + if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) + hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |= + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + } + hw->wiphy->hw_version = mvm->trans->hw_id; if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 9f32f2db95bd..95b718b4f8ab 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1805,7 +1805,7 @@ static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, /* Our chip supports Tx STBC and the peer is an HT/VHT STA which * supports STBC of at least 1*SS */ - if (!lq_sta->stbc) + if (!lq_sta->stbc_capable) return false; if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) @@ -2626,7 +2626,7 @@ static void rs_ht_init(struct iwl_mvm *mvm, if (mvm->cfg->ht_params->stbc && (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) - lq_sta->stbc = true; + lq_sta->stbc_capable = true; lq_sta->is_vht = false; } @@ -2645,7 +2645,12 @@ static void rs_vht_init(struct iwl_mvm *mvm, if (mvm->cfg->ht_params->stbc && (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) - lq_sta->stbc = true; + lq_sta->stbc_capable = true; + + if ((mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) && + (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && + (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) + lq_sta->bfer_capable = true; lq_sta->is_vht = true; } @@ -2778,11 +2783,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate); IWL_DEBUG_RATE(mvm, - "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d\n", + "LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d BFER=%d\n", lq_sta->active_legacy_rate, lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, - lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc); + lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc_capable, + lq_sta->bfer_capable); IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", lq_sta->max_legacy_rate_idx, lq_sta->max_siso_rate_idx, @@ -2916,23 +2922,15 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, u8 valid_tx_ant = 0; struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; bool toggle_ant = false; - bool stbc_allowed = false; memcpy(&rate, initial_rate, sizeof(rate)); valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); - stbc_allowed = rs_stbc_allow(mvm, sta, lq_sta); - if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) { - u32 ss_params = RS_SS_PARAMS_VALID; - - if (stbc_allowed) - ss_params |= RS_SS_STBC_ALLOWED; - lq_cmd->ss_params = cpu_to_le32(ss_params); - } else { - /* TODO: remove old API when min FW API hits 14 */ - rate.stbc = stbc_allowed; - } + /* TODO: remove old API when min FW API hits 14 */ + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) && + rs_stbc_allow(mvm, sta, lq_sta)) + rate.stbc = true; if (is_siso(&rate)) { num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES; @@ -2980,6 +2978,128 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, } +struct rs_bfer_active_iter_data { + struct ieee80211_sta *exclude_sta; + struct iwl_mvm_sta *bfer_mvmsta; +}; + +static void rs_bfer_active_iter(void *_data, + struct ieee80211_sta *sta) +{ + struct rs_bfer_active_iter_data *data = _data; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_lq_cmd *lq_cmd = &mvmsta->lq_sta.lq; + u32 ss_params = le32_to_cpu(lq_cmd->ss_params); + + if (sta == data->exclude_sta) + return; + + /* The current sta has BFER allowed */ + if (ss_params & LQ_SS_BFER_ALLOWED) { + WARN_ON_ONCE(data->bfer_mvmsta != NULL); + + data->bfer_mvmsta = mvmsta; + } +} + +static int rs_bfer_priority(struct iwl_mvm_sta *sta) +{ + int prio = -1; + enum nl80211_iftype viftype = ieee80211_vif_type_p2p(sta->vif); + + switch (viftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + prio = 3; + break; + case NL80211_IFTYPE_P2P_CLIENT: + prio = 2; + break; + case NL80211_IFTYPE_STATION: + prio = 1; + break; + default: + WARN_ONCE(true, "viftype %d sta_id %d", viftype, sta->sta_id); + prio = -1; + } + + return prio; +} + +/* Returns >0 if sta1 has a higher BFER priority compared to sta2 */ +static int rs_bfer_priority_cmp(struct iwl_mvm_sta *sta1, + struct iwl_mvm_sta *sta2) +{ + int prio1 = rs_bfer_priority(sta1); + int prio2 = rs_bfer_priority(sta2); + + if (prio1 > prio2) + return 1; + if (prio1 < prio2) + return -1; + return 0; +} + +static void rs_set_lq_ss_params(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta, + const struct rs_rate *initial_rate) +{ + struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct rs_bfer_active_iter_data data = { + .exclude_sta = sta, + .bfer_mvmsta = NULL, + }; + struct iwl_mvm_sta *bfer_mvmsta = NULL; + u32 ss_params = LQ_SS_PARAMS_VALID; + + if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) + goto out; + + if (lq_sta->stbc_capable) + ss_params |= LQ_SS_STBC_1SS_ALLOWED; + + if (!lq_sta->bfer_capable) + goto out; + + ieee80211_iterate_stations_atomic(mvm->hw, + rs_bfer_active_iter, + &data); + bfer_mvmsta = data.bfer_mvmsta; + + /* This code is safe as it doesn't run concurrently for different + * stations. This is guaranteed by the fact that calls to + * ieee80211_tx_status wouldn't run concurrently for a single HW. + */ + if (!bfer_mvmsta) { + IWL_DEBUG_RATE(mvm, "No sta with BFER allowed found. Allow\n"); + + ss_params |= LQ_SS_BFER_ALLOWED; + goto out; + } + + IWL_DEBUG_RATE(mvm, "Found existing sta %d with BFER activated\n", + bfer_mvmsta->sta_id); + + /* Disallow BFER on another STA if active and we're a higher priority */ + if (rs_bfer_priority_cmp(mvmsta, bfer_mvmsta) > 0) { + struct iwl_lq_cmd *bfersta_lq_cmd = &bfer_mvmsta->lq_sta.lq; + u32 bfersta_ss_params = le32_to_cpu(bfersta_lq_cmd->ss_params); + + bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED; + bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params); + iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd, false); + + ss_params |= LQ_SS_BFER_ALLOWED; + IWL_DEBUG_RATE(mvm, + "Lower priority BFER sta found (%d). Switch BFER\n", + bfer_mvmsta->sta_id); + } +out: + lq_cmd->ss_params = cpu_to_le32(ss_params); +} + static void rs_fill_lq_cmd(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, @@ -3006,6 +3126,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, rs_build_rates_table(mvm, sta, lq_sta, initial_rate); + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) + rs_set_lq_ss_params(mvm, sta, lq_sta, initial_rate); + if (num_of_ant(initial_rate->ant) == 1) lq_cmd->single_stream_ant_msk = initial_rate->ant; diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index f8f5bf21cc38..ba57f5ae2375 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -293,7 +293,9 @@ struct iwl_lq_sta { u64 last_tx; bool is_vht; bool ldpc; /* LDPC Rx is supported by the STA */ - bool stbc; /* Tx STBC is supported by chip and Rx by STA */ + bool stbc_capable; /* Tx STBC is supported by chip and Rx by STA */ + bool bfer_capable; /* Remote supports beamformee and we BFer */ + enum ieee80211_band band; /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ -- cgit v1.2.1 From 1e9c62fa9158f35dfd73ef6231154710154e6e09 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 28 Jan 2015 14:44:06 +0200 Subject: iwlwifi: mvm: rs: enable forcing single stream Tx decision In certain testing scenarios we'd like to force a decision between STBC/BFER/SISO. In the normal scenario this decision is done by the FW. Enable this option vis debugfs. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | 8 +++ drivers/net/wireless/iwlwifi/mvm/rs.c | 84 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/rs.h | 10 ++++ 3 files changed, 102 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 4c33f2775dc9..0f1ea80a55ef 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h @@ -330,6 +330,14 @@ enum { #define LQ_SS_BFER_ALLOWED_POS 2 #define LQ_SS_BFER_ALLOWED (1 << LQ_SS_BFER_ALLOWED_POS) +/* Bit 3: Force BFER or STBC for testing + * If this is set: + * If BFER is allowed then force the ucode to choose BFER else + * If STBC is allowed then force the ucode to choose STBC over SISO + */ +#define LQ_SS_FORCE_POS 3 +#define LQ_SS_FORCE (1 << LQ_SS_FORCE_POS) + /* Bit 31: ss_params field is valid. Used for FW backward compatibility * with other drivers which don't support the ss_params API yet */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 95b718b4f8ab..194bd1f939ca 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -39,6 +39,7 @@ #include "sta.h" #include "iwl-op-mode.h" #include "mvm.h" +#include "debugfs.h" #define RS_NAME "iwl-mvm-rs" @@ -3057,6 +3058,20 @@ static void rs_set_lq_ss_params(struct iwl_mvm *mvm, if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) goto out; + /* Check if forcing the decision is configured. + * Note that SISO is forced by not allowing STBC or BFER + */ + if (lq_sta->ss_force == RS_SS_FORCE_STBC) + ss_params |= (LQ_SS_STBC_1SS_ALLOWED | LQ_SS_FORCE); + else if (lq_sta->ss_force == RS_SS_FORCE_BFER) + ss_params |= (LQ_SS_BFER_ALLOWED | LQ_SS_FORCE); + + if (lq_sta->ss_force != RS_SS_FORCE_NONE) { + IWL_DEBUG_RATE(mvm, "Forcing single stream Tx decision %d\n", + lq_sta->ss_force); + goto out; + } + if (lq_sta->stbc_capable) ss_params |= LQ_SS_STBC_1SS_ALLOWED; @@ -3502,9 +3517,73 @@ static const struct file_operations rs_sta_dbgfs_drv_tx_stats_ops = { .llseek = default_llseek, }; +static ssize_t iwl_dbgfs_ss_force_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_lq_sta *lq_sta = file->private_data; + char buf[12]; + int bufsz = sizeof(buf); + int pos = 0; + static const char * const ss_force_name[] = { + [RS_SS_FORCE_NONE] = "none", + [RS_SS_FORCE_STBC] = "stbc", + [RS_SS_FORCE_BFER] = "bfer", + [RS_SS_FORCE_SISO] = "siso", + }; + + pos += scnprintf(buf+pos, bufsz-pos, "%s\n", + ss_force_name[lq_sta->ss_force]); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = lq_sta->pers.drv; + int ret = 0; + + if (!strncmp("none", buf, 4)) { + lq_sta->ss_force = RS_SS_FORCE_NONE; + } else if (!strncmp("siso", buf, 4)) { + lq_sta->ss_force = RS_SS_FORCE_SISO; + } else if (!strncmp("stbc", buf, 4)) { + if (lq_sta->stbc_capable) { + lq_sta->ss_force = RS_SS_FORCE_STBC; + } else { + IWL_ERR(mvm, + "can't force STBC. peer doesn't support\n"); + ret = -EINVAL; + } + } else if (!strncmp("bfer", buf, 4)) { + if (lq_sta->bfer_capable) { + lq_sta->ss_force = RS_SS_FORCE_BFER; + } else { + IWL_ERR(mvm, + "can't force BFER. peer doesn't support\n"); + ret = -EINVAL; + } + } else { + IWL_ERR(mvm, "valid values none|siso|stbc|bfer\n"); + ret = -EINVAL; + } + return ret ?: count; +} + +#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ + _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_lq_sta) +#define MVM_DEBUGFS_ADD_FILE_RS(name, parent, mode) do { \ + if (!debugfs_create_file(#name, mode, parent, lq_sta, \ + &iwl_dbgfs_##name##_ops)) \ + goto err; \ + } while (0) + +MVM_DEBUGFS_READ_WRITE_FILE_OPS(ss_force, 32); + static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) { struct iwl_lq_sta *lq_sta = mvm_sta; + debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, lq_sta, &rs_sta_dbgfs_scale_table_ops); debugfs_create_file("rate_stats_table", S_IRUSR, dir, @@ -3515,6 +3594,11 @@ static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) &lq_sta->tx_agg_tid_en); debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir, &lq_sta->pers.dbg_fixed_txp_reduction); + + MVM_DEBUGFS_ADD_FILE_RS(ss_force, dir, S_IRUSR | S_IWUSR); + return; +err: + IWL_ERR((struct iwl_mvm *)mvm, "Can't create debugfs entity\n"); } static void rs_remove_debugfs(void *mvm, void *mvm_sta) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index ba57f5ae2375..dc4ef3dfafe1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -240,6 +240,13 @@ enum rs_column { RS_COLUMN_INVALID, }; +enum rs_ss_force_opt { + RS_SS_FORCE_NONE = 0, + RS_SS_FORCE_STBC, + RS_SS_FORCE_BFER, + RS_SS_FORCE_SISO, +}; + /* Packet stats per rate */ struct rs_rate_stats { u64 success; @@ -324,6 +331,9 @@ struct iwl_lq_sta { /* tx power reduce for this sta */ int tpc_reduce; + /* force STBC/BFER/SISO for testing */ + enum rs_ss_force_opt ss_force; + /* persistent fields - initialized only once - keep last! */ struct lq_sta_pers { #ifdef CONFIG_MAC80211_DEBUGFS -- cgit v1.2.1 From cb6bb128b73ae898d6ee0281c2b2644f70633d58 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 25 Jan 2015 10:36:31 +0200 Subject: iwlwifi: pcie: prepare the enablement of 31 TFD queues Some devices have 31 TFD queues. Don't enable it yet since there are still issues with it, but at least prepare the code for it. There was a bug in the read pointer assignment, fix that. Also, move the inline functions to iwl-scd.h which is the right place. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 26 ++------------------ drivers/net/wireless/iwlwifi/iwl-scd.h | 41 +++++++++++++++++++++++++------ drivers/net/wireless/iwlwifi/pcie/trans.c | 1 + drivers/net/wireless/iwlwifi/pcie/tx.c | 4 +++ 4 files changed, 40 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index b21fcf042b77..6221e4dfc64f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -252,6 +252,7 @@ #define SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) +#define SCD_GP_CTRL_ENABLE_31_QUEUES BIT(0) /* Context Data */ #define SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600) @@ -285,32 +286,9 @@ #define SCD_CHAINEXT_EN (SCD_BASE + 0x244) #define SCD_AGGR_SEL (SCD_BASE + 0x248) #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) +#define SCD_GP_CTRL (SCD_BASE + 0x1a8) #define SCD_EN_CTRL (SCD_BASE + 0x254) -static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl) -{ - if (chnl < 20) - return SCD_BASE + 0x18 + chnl * 4; - WARN_ON_ONCE(chnl >= 32); - return SCD_BASE + 0x284 + (chnl - 20) * 4; -} - -static inline unsigned int SCD_QUEUE_RDPTR(unsigned int chnl) -{ - if (chnl < 20) - return SCD_BASE + 0x68 + chnl * 4; - WARN_ON_ONCE(chnl >= 32); - return SCD_BASE + 0x2B4 + (chnl - 20) * 4; -} - -static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl) -{ - if (chnl < 20) - return SCD_BASE + 0x10c + chnl * 4; - WARN_ON_ONCE(chnl >= 32); - return SCD_BASE + 0x384 + (chnl - 20) * 4; -} - /*********************** END TX SCHEDULER *************************************/ /* Oscillator clock */ diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h index 6c622b21bba7..f2353ebf2666 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scd.h +++ b/drivers/net/wireless/iwlwifi/iwl-scd.h @@ -69,14 +69,6 @@ #include "iwl-prph.h" -static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans, - u16 txq_id) -{ - iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), - (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| - (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); -} - static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans, u16 txq_id) { @@ -115,4 +107,37 @@ static inline void iwl_scd_enable_set_active(struct iwl_trans *trans, { iwl_write_prph(trans, SCD_EN_CTRL, value); } + +static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl) +{ + if (chnl < 20) + return SCD_BASE + 0x18 + chnl * 4; + WARN_ON_ONCE(chnl >= 32); + return SCD_BASE + 0x284 + (chnl - 20) * 4; +} + +static inline unsigned int SCD_QUEUE_RDPTR(unsigned int chnl) +{ + if (chnl < 20) + return SCD_BASE + 0x68 + chnl * 4; + WARN_ON_ONCE(chnl >= 32); + return SCD_BASE + 0x2B4 + chnl * 4; +} + +static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl) +{ + if (chnl < 20) + return SCD_BASE + 0x10c + chnl * 4; + WARN_ON_ONCE(chnl >= 32); + return SCD_BASE + 0x334 + chnl * 4; +} + +static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans, + u16 txq_id) +{ + iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), + (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| + (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); +} + #endif diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 1ff87677c3d3..eb0ffc158b30 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -75,6 +75,7 @@ #include "iwl-trans.h" #include "iwl-csr.h" #include "iwl-prph.h" +#include "iwl-scd.h" #include "iwl-agn-hw.h" #include "iwl-fw-error-dump.h" #include "internal.h" diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 6c7bfe8905ca..0a9408378707 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -892,6 +892,10 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) } } + if (trans->cfg->base_params->num_of_queues > 20) + iwl_set_bits_prph(trans, SCD_GP_CTRL, + SCD_GP_CTRL_ENABLE_31_QUEUES); + return 0; error: /*Upon error, free only if we allocated something */ -- cgit v1.2.1 From cd8f438405032ac8ff88bd8f2eca5e0c0063b14b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 29 Jan 2015 21:34:00 +0200 Subject: iwlwifi: pcie: disable the SCD_BASE_ADDR when we resume from WoWLAN The base address of the scheduler in the device's memory (SRAM) comes from two different sources. The periphery register and the alive notification from the firmware. We have a check in iwl_pcie_tx_start that ensures that they are the same. When we resume from WoWLAN, the firmware may have crashed for whatever reason. In that case, the whole device may be reset which means that the periphery register will hold a meaningless value. When we come to compare trans_pcie->scd_base_addr (which really holds the value we had when we loaded the WoWLAN firmware upon suspend) and the current value of the register, we don't see a match unsurprisingly. Trick the check to avoid a loud yet harmless WARN. Note that when the WoWLAN has crashed, we will see that in iwl_trans_pcie_d3_resume which will let the op_mode know. Once the op_mode is informed that the WowLAN firmware has crashed, it can't do much besides resetting the whole device. CC: Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/tx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 0a9408378707..59aefa43ea85 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -716,7 +716,12 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, trans_pcie->kw.dma >> 4); - iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr); + /* + * Send 0 as the scd_base_addr since the device may have be reset + * while we were in WoWLAN in which case SCD_SRAM_BASE_ADDR will + * contain garbage. + */ + iwl_pcie_tx_start(trans, 0); } /* -- cgit v1.2.1 From 5cb1270143668fa72007b52a8be6b4aa2c182809 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 22 Jan 2015 12:19:26 +0200 Subject: iwlwifi: mvm: improve TDLS ch-sw state machine Add a response-received state and add more limits on allowed requests in each state of the connection. Previously ch-switch requests from other peers could interrupt an outgoing active ch-switch. Also stale packets from the current peer could disrupt the channel switch state. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/tdls.c | 48 +++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 7773ffc4ca62..fc80b7b43b21 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -532,6 +532,7 @@ enum { enum iwl_mvm_tdls_cs_state { IWL_MVM_TDLS_SW_IDLE = 0, IWL_MVM_TDLS_SW_REQ_SENT, + IWL_MVM_TDLS_SW_RESP_RCVD, IWL_MVM_TDLS_SW_REQ_RCVD, IWL_MVM_TDLS_SW_ACTIVE, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index c0e00bae5bd0..ea1831ccc8f3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -228,6 +228,8 @@ iwl_mvm_tdls_cs_state_str(enum iwl_mvm_tdls_cs_state state) return "IDLE"; case IWL_MVM_TDLS_SW_REQ_SENT: return "REQ SENT"; + case IWL_MVM_TDLS_SW_RESP_RCVD: + return "RESP RECEIVED"; case IWL_MVM_TDLS_SW_REQ_RCVD: return "REQ RECEIVED"; case IWL_MVM_TDLS_SW_ACTIVE: @@ -325,17 +327,27 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, ret = -EINVAL; break; case IWL_MVM_TDLS_SW_REQ_SENT: + /* only allow requests from the same peer */ + if (!same_peer) + ret = -EBUSY; + else if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH && + !peer_initiator) + /* + * We received a ch-switch request while an outgoing + * one is pending. Allow it if the peer is the link + * initiator. + */ + ret = -EBUSY; + else if (type == TDLS_SEND_CHAN_SW_REQ) + /* wait for idle before sending another request */ + ret = -EBUSY; + break; + case IWL_MVM_TDLS_SW_RESP_RCVD: /* - * We received a ch-switch request while an outgoing one is - * pending. Allow it to proceed if the other peer is the same - * one we sent to, and we are not the link initiator. + * we are waiting for the FW to give an "active" notification, + * so ignore requests in the meantime */ - if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH) { - if (!same_peer) - ret = -EBUSY; - else if (!peer_initiator) /* we are the initiator */ - ret = -EBUSY; - } + ret = -EBUSY; break; case IWL_MVM_TDLS_SW_REQ_RCVD: /* as above, allow the link initiator to proceed */ @@ -349,9 +361,12 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, } break; case IWL_MVM_TDLS_SW_ACTIVE: - /* we don't allow initiations during active channel switch */ - if (type == TDLS_SEND_CHAN_SW_REQ) - ret = -EINVAL; + /* + * the only valid request when active is a request to return + * to the base channel by the current off-channel peer + */ + if (type != TDLS_MOVE_CH || !same_peer) + ret = -EBUSY; break; } @@ -473,6 +488,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, type == TDLS_SEND_CHAN_SW_REQ ? IWL_MVM_TDLS_SW_REQ_SENT : IWL_MVM_TDLS_SW_REQ_RCVD); + } else { + iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_RESP_RCVD); } out: @@ -657,12 +674,15 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); enum iwl_tdls_channel_switch_type type; unsigned int delay; + const char *action_str = + params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ? + "REQ" : "RESP"; mutex_lock(&mvm->mutex); IWL_DEBUG_TDLS(mvm, - "Received TDLS ch switch action %d from %pM status %d\n", - params->action_code, params->sta->addr, params->status); + "Received TDLS ch switch action %s from %pM status %d\n", + action_str, params->sta->addr, params->status); /* * we got a non-zero status from a peer we were switching to - move to -- cgit v1.2.1 From b9dccdb33c4dc86922d025d02e91715ad9510732 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 22 Jan 2015 14:24:44 +0200 Subject: iwlwifi: mvm: ignore stale TDLS ch-switch responses During out-of-channel activities (e.g. scan) TDLS ch-switch responses from a peer are kept in FW. These packets arrive only after the out-of-channel activity is complete, which can be in the order of several seconds. Since TDLS ch-sw has no dialog-token-like mechanism for distinguishing sessions, use the GP2 time of the incoming ch-switch response to discern validity. For this purpose record the GP2 time of an outgoing TDLS ch-sw request and compare to the Rx time of the ch-sw response. The methods works in practice since the GP2 time of FW-deferred Rx is accurate and contains the real Rx timestamp. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/tdls.c | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fc80b7b43b21..ed097268a1bc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -798,6 +798,9 @@ struct iwl_mvm { struct cfg80211_chan_def chandef; struct sk_buff *skb; /* ch sw template */ u32 ch_sw_tm_ie; + + /* timestamp of last ch-sw request sent (GP2 time) */ + u32 sent_timestamp; } peer; } tdls_cs; diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index ea1831ccc8f3..a87b506c8c72 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -64,6 +64,8 @@ #include #include "mvm.h" #include "time-event.h" +#include "iwl-io.h" +#include "iwl-prph.h" #define TU_TO_US(x) (x * 1024) #define TU_TO_MS(x) (TU_TO_US(x) / 1000) @@ -250,6 +252,11 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, iwl_mvm_tdls_cs_state_str(state)); mvm->tdls_cs.state = state; + /* we only send requests to our switching peer - update sent time */ + if (state == IWL_MVM_TDLS_SW_REQ_SENT) + mvm->tdls_cs.peer.sent_timestamp = + iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG); + if (state == IWL_MVM_TDLS_SW_IDLE) mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT; } @@ -302,7 +309,7 @@ out: static int iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, enum iwl_tdls_channel_switch_type type, - const u8 *peer, bool peer_initiator) + const u8 *peer, bool peer_initiator, u32 timestamp) { bool same_peer = false; int ret = 0; @@ -341,6 +348,9 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, else if (type == TDLS_SEND_CHAN_SW_REQ) /* wait for idle before sending another request */ ret = -EBUSY; + else if (timestamp <= mvm->tdls_cs.peer.sent_timestamp) + /* we got a stale response - ignore it */ + ret = -EINVAL; break; case IWL_MVM_TDLS_SW_RESP_RCVD: /* @@ -399,7 +409,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator); + ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator, + timestamp); if (ret) return ret; -- cgit v1.2.1 From ce71c2f7976881f39fcf14f28bd7633612acd0ef Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 11 Jan 2015 17:19:39 +0200 Subject: iwlwifi: mvm: enable watchdog on Tx queues for mvm This watchdog allows to monitor the transmit queues. When a queue doesn't progress for a too long time, a timer fires and then, debug data can be collected. This watchdog has never been enabled on dvm controlled devices, so don't enable it there. In order to have it running on mvm controlled devices, we need to fix a small issue in the transport layer: mvm controlled devices use the shadow registers optimization. In this case, the watchdog wasn't running at all, even if enabled by the module parameter. Fix that on the way. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/main.c | 6 +----- drivers/net/wireless/iwlwifi/iwl-drv.c | 5 ----- drivers/net/wireless/iwlwifi/iwl-modparams.h | 2 -- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/ops.c | 9 ++++++--- drivers/net/wireless/iwlwifi/pcie/tx.c | 2 +- 6 files changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index de43dd7e170a..a21400cd84ac 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -1228,11 +1228,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; - if (!iwlwifi_mod_params.wd_disable) - trans_cfg.queue_watchdog_timeout = - priv->cfg->base_params->wd_timeout; - else - trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; + trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; trans_cfg.command_names = iwl_dvm_cmd_strings; trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM; diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index e7c0df6db6ee..996e7f16adf9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1367,7 +1367,6 @@ struct iwl_mod_params iwlwifi_mod_params = { .restart_fw = true, .bt_coex_active = true, .power_level = IWL_POWER_INDEX_1, - .wd_disable = true, .d0i3_disable = true, #ifndef CONFIG_IWLWIFI_UAPSD .uapsd_disable = true, @@ -1478,10 +1477,6 @@ module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, MODULE_PARM_DESC(antenna_coupling, "specify antenna coupling in dB (default: 0 dB)"); -module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); -MODULE_PARM_DESC(wd_disable, - "Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)"); - module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); MODULE_PARM_DESC(nvm_file, "NVM file name"); diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index 2a8cf4b2445c..e8eabd21ccfe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -96,7 +96,6 @@ enum iwl_disable_11n { * use IWL_[DIS,EN]ABLE_HT_* constants * @amsdu_size_8K: enable 8K amsdu size, default = 0 * @restart_fw: restart firmware, default = 1 - * @wd_disable: disable stuck queue check, default = 1 * @bt_coex_active: enable bt coex, default = true * @led_mode: system default, default = 0 * @power_save: enable power save, default = false @@ -111,7 +110,6 @@ struct iwl_mod_params { unsigned int disable_11n; int amsdu_size_8K; bool restart_fw; - int wd_disable; bool bt_coex_active; int led_mode; bool power_save; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index ed097268a1bc..4a7620cb5775 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -119,11 +119,13 @@ extern const struct ieee80211_ops iwl_mvm_hw_ops; * We will register to mac80211 to have testmode working. The NIC must not * be up'ed after the INIT fw asserted. This is useful to be able to use * proprietary tools over testmode to debug the INIT fw. + * @tfd_q_hang_detect: enabled the detection of hung transmit queues * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power * Save)-2(default), LP(Low Power)-3 */ struct iwl_mvm_mod_params { bool init_dbg; + bool tfd_q_hang_detect; int power_scheme; }; extern struct iwl_mvm_mod_params iwlmvm_mod_params; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index b1dea6800b3b..f801824197e1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -93,6 +93,7 @@ static const struct iwl_op_mode_ops iwl_mvm_ops; struct iwl_mvm_mod_params iwlmvm_mod_params = { .power_scheme = IWL_POWER_SCHEME_BPS, + .tfd_q_hang_detect = true /* rest of fields are 0 by default */ }; @@ -102,6 +103,10 @@ MODULE_PARM_DESC(init_dbg, module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO); MODULE_PARM_DESC(power_scheme, "power management scheme: 1-active, 2-balanced, 3-low power, default: 2"); +module_param_named(tfd_q_hang_detect, iwlmvm_mod_params.tfd_q_hang_detect, + bool, S_IRUGO); +MODULE_PARM_DESC(tfd_q_hang_detect, + "TFD queues hang detection (default: true"); /* * module init and exit functions @@ -473,10 +478,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) trans_cfg.bc_table_dword = true; - if (!iwlwifi_mod_params.wd_disable) + if (iwlmvm_mod_params.tfd_q_hang_detect) trans_cfg.queue_watchdog_timeout = cfg->base_params->wd_timeout; - else - trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; trans_cfg.command_names = iwl_mvm_cmd_strings; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 59aefa43ea85..bb9dd3ecbcf5 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1849,7 +1849,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* start timer if queue currently empty */ if (q->read_ptr == q->write_ptr) { - if (txq->need_update && trans_pcie->wd_timeout) + if (trans_pcie->wd_timeout) mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id); -- cgit v1.2.1 From 4cf677fd547d7671835d799e4d377b949510c642 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 12 Jan 2015 14:38:29 +0200 Subject: iwlwifi: allow to define the stuck queue timer per queue Different queue can have different behavior. While it can be unacceptable for a certain queue to be stuck for 2 seconds (e.g. the command queue), it can happen that another queue will stay stuck for even longer (a queue servicing a power saving client in GO). The op_mode can even make the timeout be a function of the listen interval. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/main.c | 3 +- drivers/net/wireless/iwlwifi/dvm/tx.c | 2 +- drivers/net/wireless/iwlwifi/dvm/ucode.c | 2 +- drivers/net/wireless/iwlwifi/iwl-config.h | 2 +- drivers/net/wireless/iwlwifi/iwl-trans.h | 29 +++++++++++--------- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 10 +++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 15 ++++++---- drivers/net/wireless/iwlwifi/mvm/ops.c | 8 ++++-- drivers/net/wireless/iwlwifi/mvm/sta.c | 15 ++++++++-- drivers/net/wireless/iwlwifi/mvm/utils.c | 8 ++++-- drivers/net/wireless/iwlwifi/pcie/internal.h | 10 +++---- drivers/net/wireless/iwlwifi/pcie/trans.c | 4 +-- drivers/net/wireless/iwlwifi/pcie/tx.c | 41 +++++++++++++++------------- 13 files changed, 87 insertions(+), 62 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index a21400cd84ac..c4d6dd7402d9 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -1228,7 +1228,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; - trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; + trans_cfg.cmd_q_wdg_timeout = IWL_WATCHDOG_DISABLED; + trans_cfg.command_names = iwl_dvm_cmd_strings; trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM; diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index d1ce3ce13591..1e40a12de077 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -715,7 +715,7 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, fifo = ctx->ac_to_fifo[tid_to_ac[tid]]; iwl_trans_txq_enable(priv->trans, q, fifo, sta_priv->sta_id, tid, - buf_size, ssn); + buf_size, ssn, 0); /* * If the limit is 0, then it wasn't initialised yet, diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index d5cee1530597..4dbef7e58c2e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -267,7 +267,7 @@ static int iwl_alive_notify(struct iwl_priv *priv) for (i = 0; i < n_queues; i++) if (queue_to_txf[i] != IWL_TX_FIFO_UNUSED) iwl_trans_ac_txq_enable(priv->trans, i, - queue_to_txf[i]); + queue_to_txf[i], 0); priv->passive_no_rx = false; priv->transport_queue_stop = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 445bff690a63..4b190d98a1ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -126,7 +126,7 @@ enum iwl_led_mode { /* TX queue watchdog timeouts in mSecs */ #define IWL_WATCHDOG_DISABLED 0 -#define IWL_DEF_WD_TIMEOUT 2000 +#define IWL_DEF_WD_TIMEOUT 2500 #define IWL_LONG_WD_TIMEOUT 10000 #define IWL_MAX_WD_TIMEOUT 120000 diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 84d8477432a2..a96bd8db6ceb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -368,6 +368,7 @@ enum iwl_trans_status { * @cmd_queue: the index of the command queue. * Must be set before start_fw. * @cmd_fifo: the fifo for host commands + * @cmd_q_wdg_timeout: the timeout of the watchdog timer for the command queue. * @no_reclaim_cmds: Some devices erroneously don't set the * SEQ_RX_FRAME bit on some notifications, this is the * list of such notifications to filter. Max length is @@ -378,8 +379,6 @@ enum iwl_trans_status { * @bc_table_dword: set to true if the BC table expects the byte count to be * in DWORD (as opposed to bytes) * @scd_set_active: should the transport configure the SCD for HCMD queue - * @queue_watchdog_timeout: time (in ms) after which queues - * are considered stuck and will trigger device restart * @command_names: array of command names, must be 256 entries * (one for each command); for debugging only * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until @@ -390,13 +389,13 @@ struct iwl_trans_config { u8 cmd_queue; u8 cmd_fifo; + unsigned int cmd_q_wdg_timeout; const u8 *no_reclaim_cmds; unsigned int n_no_reclaim_cmds; bool rx_buf_size_8k; bool bc_table_dword; bool scd_set_active; - unsigned int queue_watchdog_timeout; const char *const *command_names; u32 sdio_adma_addr; @@ -511,7 +510,8 @@ struct iwl_trans_ops { struct sk_buff_head *skbs); void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg); + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int queue_wdg_timeout); void (*txq_disable)(struct iwl_trans *trans, int queue, bool configure_scd); @@ -829,19 +829,21 @@ static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, static inline void iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg) + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int queue_wdg_timeout) { might_sleep(); if (unlikely((trans->state != IWL_TRANS_FW_ALIVE))) IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - trans->ops->txq_enable(trans, queue, ssn, cfg); + trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout); } static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, int fifo, int sta_id, int tid, - int frame_limit, u16 ssn) + int frame_limit, u16 ssn, + unsigned int queue_wdg_timeout) { struct iwl_trans_txq_scd_cfg cfg = { .fifo = fifo, @@ -851,11 +853,12 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, .aggregate = sta_id >= 0, }; - iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg); + iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg, queue_wdg_timeout); } -static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, - int fifo) +static inline +void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo, + unsigned int queue_wdg_timeout) { struct iwl_trans_txq_scd_cfg cfg = { .fifo = fifo, @@ -865,16 +868,16 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, .aggregate = false, }; - iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg); + iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout); } static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, - u32 txq_bm) + u32 txqs) { if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return trans->ops->wait_tx_queue_empty(trans, txq_bm); + return trans->ops->wait_tx_queue_empty(trans, txqs); } static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 8bf78fa8ace0..7bdc6220743f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -462,6 +462,9 @@ exit_fail: int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { + unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? + mvm->cfg->base_params->wd_timeout : + IWL_WATCHDOG_DISABLED; u32 ac; int ret; @@ -474,16 +477,17 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) switch (vif->type) { case NL80211_IFTYPE_P2P_DEVICE: iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, - IWL_MVM_TX_FIFO_VO); + IWL_MVM_TX_FIFO_VO, wdg_timeout); break; case NL80211_IFTYPE_AP: iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, - IWL_MVM_TX_FIFO_MCAST); + IWL_MVM_TX_FIFO_MCAST, wdg_timeout); /* fall through */ default: for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac], - iwl_mvm_ac_to_tx_fifo[ac]); + iwl_mvm_ac_to_tx_fifo[ac], + wdg_timeout); break; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4a7620cb5775..6c69d0584f6c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1318,11 +1318,13 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) /* hw scheduler queue config */ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg); + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int wdg_timeout); void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags); -static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, - u8 fifo) +static inline +void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, + u8 fifo, unsigned int wdg_timeout) { struct iwl_trans_txq_scd_cfg cfg = { .fifo = fifo, @@ -1331,12 +1333,13 @@ static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, .frame_limit = IWL_FRAME_LIMIT, }; - iwl_mvm_enable_txq(mvm, queue, 0, &cfg); + iwl_mvm_enable_txq(mvm, queue, 0, &cfg, wdg_timeout); } static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, int tid, - int frame_limit, u16 ssn) + int frame_limit, u16 ssn, + unsigned int wdg_timeout) { struct iwl_trans_txq_scd_cfg cfg = { .fifo = fifo, @@ -1346,7 +1349,7 @@ static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, .aggregate = true, }; - iwl_mvm_enable_txq(mvm, queue, ssn, &cfg); + iwl_mvm_enable_txq(mvm, queue, ssn, &cfg, wdg_timeout); } /* Assoc status */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index f801824197e1..b6181efa9921 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -478,9 +478,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) trans_cfg.bc_table_dword = true; - if (iwlmvm_mod_params.tfd_q_hang_detect) - trans_cfg.queue_watchdog_timeout = cfg->base_params->wd_timeout; - trans_cfg.command_names = iwl_mvm_cmd_strings; trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; @@ -489,6 +486,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.sdio_adma_addr = fw->sdio_adma_addr; + /* Set a short watchdog for the command queue */ + trans_cfg.cmd_q_wdg_timeout = + iwlmvm_mod_params.tfd_q_hang_detect ? IWL_DEF_WD_TIMEOUT : + IWL_WATCHDOG_DISABLED; + snprintf(mvm->hw->wiphy->fw_version, sizeof(mvm->hw->wiphy->fw_version), "%s", fw->fw_version); diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 14a848480d04..5c23cddaaae3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -209,6 +209,9 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm, { unsigned long used_hw_queues; struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? + mvm->cfg->base_params->wd_timeout : + IWL_WATCHDOG_DISABLED; u32 ac; lockdep_assert_held(&mvm->mutex); @@ -232,7 +235,7 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm, /* Found a place for all queues - enable them */ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac], - iwl_mvm_ac_to_tx_fifo[ac]); + iwl_mvm_ac_to_tx_fifo[ac], wdg_timeout); mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]); } @@ -626,13 +629,16 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) { + unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? + mvm->cfg->base_params->wd_timeout : + IWL_WATCHDOG_DISABLED; int ret; lockdep_assert_held(&mvm->mutex); /* Map Aux queue to fifo - needs to happen before adding Aux station */ iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, - IWL_MVM_TX_FIFO_MCAST); + IWL_MVM_TX_FIFO_MCAST, wdg_timeout); /* Allocate aux station and assign to it the aux queue */ ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), @@ -965,6 +971,9 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; + unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? + mvm->cfg->base_params->wd_timeout : + IWL_WATCHDOG_DISABLED; int queue, fifo, ret; u16 ssn; @@ -988,7 +997,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EIO; iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid, - buf_size, ssn); + buf_size, ssn, wdg_timeout); /* * Even though in theory the peer could have different diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 02f434d32800..8decf9953229 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -531,7 +531,8 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) } void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg) + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int wdg_timeout) { struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, @@ -545,11 +546,12 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, }; if (!iwl_mvm_is_scd_cfg_supported(mvm)) { - iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, cfg); + iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, cfg, + wdg_timeout); return; } - iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL); + iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout); WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd), "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); } diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index e5652d82d79e..cae0eb8835ce 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -216,6 +216,7 @@ struct iwl_pcie_txq_scratch_buf { * @need_update: indicates need to update read/write index * @active: stores if queue is active * @ampdu: true if this queue is an ampdu queue for an specific RA/TID + * @wd_timeout: queue watchdog timeout (jiffies) - per queue * * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame * descriptors) and required locking structures. @@ -232,6 +233,7 @@ struct iwl_txq { bool need_update; u8 active; bool ampdu; + unsigned long wd_timeout; }; static inline dma_addr_t @@ -259,7 +261,6 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @scd_set_active: should the transport configure the SCD for HCMD queue * @rx_page_order: page order for receive buffer size - * @wd_timeout: queue watchdog timeout (jiffies) * @reg_lock: protect hw register access * @cmd_in_flight: true when we have a host command in flight * @fw_mon_phys: physical address of the buffer for the firmware monitor @@ -302,6 +303,7 @@ struct iwl_trans_pcie { u8 cmd_queue; u8 cmd_fifo; + unsigned int cmd_q_wdg_timeout; u8 n_no_reclaim_cmds; u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; @@ -312,9 +314,6 @@ struct iwl_trans_pcie { const char *const *command_names; - /* queue watchdog */ - unsigned long wd_timeout; - /*protect hw register */ spinlock_t reg_lock; bool cmd_in_flight; @@ -373,7 +372,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); int iwl_pcie_tx_stop(struct iwl_trans *trans); void iwl_pcie_tx_free(struct iwl_trans *trans); void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg); + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int wdg_timeout); void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, bool configure_scd); int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index eb0ffc158b30..69935aa5a1b3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1269,6 +1269,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans_pcie->cmd_queue = trans_cfg->cmd_queue; trans_pcie->cmd_fifo = trans_cfg->cmd_fifo; + trans_pcie->cmd_q_wdg_timeout = trans_cfg->cmd_q_wdg_timeout; if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS)) trans_pcie->n_no_reclaim_cmds = 0; else @@ -1283,9 +1284,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, else trans_pcie->rx_page_order = get_order(4 * 1024); - trans_pcie->wd_timeout = - msecs_to_jiffies(trans_cfg->queue_watchdog_timeout); - trans_pcie->command_names = trans_cfg->command_names; trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; trans_pcie->scd_set_active = trans_cfg->scd_set_active; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index bb9dd3ecbcf5..af0bce736358 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -163,7 +163,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) spin_unlock(&txq->lock); IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id, - jiffies_to_msecs(trans_pcie->wd_timeout)); + jiffies_to_msecs(txq->wd_timeout)); IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", txq->q.read_ptr, txq->q.write_ptr); @@ -674,7 +674,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue, - trans_pcie->cmd_fifo); + trans_pcie->cmd_fifo, + trans_pcie->cmd_q_wdg_timeout); /* Activate all Tx DMA/FIFO channels */ iwl_scd_activate_fifos(trans); @@ -909,10 +910,9 @@ error: return ret; } -static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie, - struct iwl_txq *txq) +static inline void iwl_pcie_txq_progress(struct iwl_txq *txq) { - if (!trans_pcie->wd_timeout) + if (!txq->wd_timeout) return; /* @@ -922,7 +922,7 @@ static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie, if (txq->q.read_ptr == txq->q.write_ptr) del_timer(&txq->stuck_timer); else - mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); + mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); } /* Frees buffers until index _not_ inclusive */ @@ -984,7 +984,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, iwl_pcie_txq_free_tfd(trans, txq); } - iwl_pcie_txq_progress(trans_pcie, txq); + iwl_pcie_txq_progress(txq); if (iwl_queue_space(&txq->q) > txq->q.low_mark) iwl_wake_queue(trans, txq); @@ -1112,7 +1112,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); } - iwl_pcie_txq_progress(trans_pcie, txq); + iwl_pcie_txq_progress(txq); } static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, @@ -1145,14 +1145,18 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg) + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int wdg_timeout) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; int fifo = -1; if (test_and_set_bit(txq_id, trans_pcie->queue_used)) WARN_ONCE(1, "queue %d already used - expect issues", txq_id); + txq->wd_timeout = msecs_to_jiffies(wdg_timeout); + if (cfg) { fifo = cfg->fifo; @@ -1176,7 +1180,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, /* enable aggregations for the queue */ iwl_scd_txq_enable_agg(trans, txq_id); - trans_pcie->txq[txq_id].ampdu = true; + txq->ampdu = true; } else { /* * disable aggregations for the queue, this will also @@ -1185,14 +1189,14 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, */ iwl_scd_txq_disable_agg(trans, txq_id); - ssn = trans_pcie->txq[txq_id].q.read_ptr; + ssn = txq->q.read_ptr; } } /* Place first TFD at index corresponding to start sequence number. * Assumes that ssn_idx is valid (!= 0xFFF) */ - trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff); - trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff); + txq->q.read_ptr = (ssn & 0xff); + txq->q.write_ptr = (ssn & 0xff); iwl_write_direct32(trans, HBUS_TARG_WRPTR, (ssn & 0xff) | (txq_id << 8)); @@ -1233,7 +1237,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, txq_id, ssn & 0xff); } - trans_pcie->txq[txq_id].active = true; + txq->active = true; } void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, @@ -1498,8 +1502,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); /* start timer if queue currently empty */ - if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) - mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); + if (q->read_ptr == q->write_ptr && txq->wd_timeout) + mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); spin_lock_irqsave(&trans_pcie->reg_lock, flags); ret = iwl_pcie_set_cmd_in_flight(trans, cmd); @@ -1849,9 +1853,8 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* start timer if queue currently empty */ if (q->read_ptr == q->write_ptr) { - if (trans_pcie->wd_timeout) - mod_timer(&txq->stuck_timer, - jiffies + trans_pcie->wd_timeout); + if (txq->wd_timeout) + mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id); iwl_trans_pcie_ref(trans); } -- cgit v1.2.1 From 5a4b2afa77dea0e0ce6aa1c3f0dbf90dd9a681eb Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Tue, 13 Jan 2015 11:54:51 +0200 Subject: iwlwifi: mvm: Fix a few EBS error handling bugs Last EBS status wasn't set to success in the initialization, which caused the first scan to be without EBS. Fix that. When EBS is not enabled by the driver, the FW still sends ebs_status success, which can override EBS failure state. Consider only EBS failures, to avoid such override. Last_ebs_success is set back to true upon disconnection. Last_ebs_success wasn't set in umac scan abort flow, fix that too. Signed-off-by: Haim Dreyfuss Signed-off-by: David Spinadel Reviewed-by: Alexander Bondar Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 3 +++ drivers/net/wireless/iwlwifi/mvm/scan.c | 13 ++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index b6181efa9921..2dffc3600ed3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -568,6 +568,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (!mvm->scan_cmd) goto out_free; + /* Set EBS as successful as long as not stated otherwise by the FW. */ + mvm->last_ebs_successful = true; + err = iwl_mvm_mac_setup_register(mvm); if (err) goto out_free; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 3bd5f34d3285..4169e3d7c109 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -704,7 +704,8 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); } - mvm->last_ebs_successful = !ebs_status; + if (ebs_status) + mvm->last_ebs_successful = false; return 0; } @@ -2025,7 +2026,9 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, notif->ebs_status == IWL_SCAN_EBS_SUCCESS ? "success" : "failed"); - mvm->last_ebs_successful = !notif->ebs_status; + if (notif->ebs_status) + mvm->last_ebs_successful = false; + mvm->scan_uid[uid_idx] = 0; if (!sched) { @@ -2058,10 +2061,14 @@ static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait, /* * Clear scan uid of scans that was aborted from above and completed - * in FW so the RX handler does nothing. + * in FW so the RX handler does nothing. Set last_ebs_successful here if + * needed. */ scan_done->mvm->scan_uid[uid_idx] = 0; + if (notif->ebs_status) + scan_done->mvm->last_ebs_successful = false; + return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type); } -- cgit v1.2.1 From fd66fc1cafd72ddf27dbec3a5e29e99839d1bc84 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 27 Jan 2015 15:06:57 +0200 Subject: iwlwifi: mvm: fix failure path when power_update fails in add_interface When iwl_mvm_power_update_mac() is called, we have already added the mac context, so if this call fails we should remove the mac. CC: [3.15+] Fixes: commit e5e7aa8e2561 ('iwlwifi: mvm: refactor power code') Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 51e02e6ba0ac..1ff7ec08532d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1355,7 +1355,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, ret = iwl_mvm_power_update_mac(mvm); if (ret) - goto out_release; + goto out_remove_mac; /* beacon filtering */ ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); -- cgit v1.2.1 From 4db6558ccc4124d725d4c96eb55720bbbb597112 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Mon, 5 Jan 2015 15:00:35 +0200 Subject: iwlwifi: mvm: Enable EBS also in single scan on umac interface Enable EBS on one shot scans if supported by FW. Signed-off-by: Haim Dreyfuss Reviewed-by: Alexander Bondar Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 4169e3d7c109..8b74ce7b0e64 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -1863,6 +1863,13 @@ int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; cmd->general_flags = cpu_to_le32(flags); + + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS && + mvm->last_ebs_successful) + cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS | + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; + cmd->n_channels = req->req.n_channels; for (i = 0; i < req->req.n_ssids; i++) -- cgit v1.2.1 From a25d40e27e542b8cd936ef1803e18304a6b2afb8 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Fri, 23 Jan 2015 21:13:01 +0200 Subject: iwlwifi: mvm: Fix building channels in scan_config_cmd Use the chanel hw_value and not the center frequency when building channel array for scan_config_cmd. Signed-off-by: Ilan Peer Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 8b74ce7b0e64..7e9aa3cb3254 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -1683,10 +1683,10 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; for (i = 0; i < band->n_channels; i++, j++) - scan_config->channel_array[j] = band->channels[i].center_freq; + scan_config->channel_array[j] = band->channels[i].hw_value; band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; for (i = 0; i < band->n_channels; i++, j++) - scan_config->channel_array[j] = band->channels[i].center_freq; + scan_config->channel_array[j] = band->channels[i].hw_value; cmd.data[0] = scan_config; cmd.len[0] = cmd_size; -- cgit v1.2.1 From 3ac856c100f4eccdd8e4f56704f32ebdd5f4dd80 Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:21:53 +0100 Subject: hso: remove useless header file timer.h No timer related function is used in this driver. Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 9c5aa922a9f4..73549bb65a48 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.1 From 29bd3bc1194c624ce863cab2a7da9bc1f0c3b47b Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:21:54 +0100 Subject: hso: fix crash when device disappears while serial port is open When the device disappear, the function hso_disconnect() is called to perform cleanup. In the cleanup function, hso_free_interface() calls tty_port_tty_hangup() in view of scheduling a work to hang up the tty if needed. If the port was not open then hso_serial_ref_free() is called directly to cleanup everything. Otherwise, hso_serial_ref_free() is called when the last fd associated to the port is closed. For each open port, tty_release() will call the close method, hso_serial_close(), which drops the last kref and call hso_serial_ref_free() which unregisters, destroys the tty port and finally frees the structure in which the tty_port structure is included. Later, in tty_release(), more precisely when release_tty() is called, the tty_port previously freed is accessed to cancel the tty buf workqueue and it leads to a crash. In view of avoiding this crash, we add a cleanup method that is called at the end of the hangup process and we drop the last kref in this function when all the ports have been closed, when tty_port is no more needed and when it is safe to free the structure containing the tty_port structure. Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 73549bb65a48..191c1fac08b6 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1270,7 +1270,6 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) goto err_out; D1("Opening %d", serial->minor); - kref_get(&serial->parent->ref); /* setup */ tty->driver_data = serial; @@ -1289,7 +1288,8 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) if (result) { hso_stop_serial_device(serial->parent); serial->port.count--; - kref_put(&serial->parent->ref, hso_serial_ref_free); + } else { + kref_get(&serial->parent->ref); } } else { D1("Port was already open"); @@ -1339,8 +1339,6 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) usb_autopm_put_interface(serial->parent->interface); mutex_unlock(&serial->parent->mutex); - - kref_put(&serial->parent->ref, hso_serial_ref_free); } /* close the requested serial port */ @@ -1391,6 +1389,16 @@ static int hso_serial_write_room(struct tty_struct *tty) return room; } +static void hso_serial_cleanup(struct tty_struct *tty) +{ + struct hso_serial *serial = tty->driver_data; + + if (!serial) + return; + + kref_put(&serial->parent->ref, hso_serial_ref_free); +} + /* setup the term */ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) { @@ -3214,6 +3222,7 @@ static const struct tty_operations hso_serial_ops = { .close = hso_serial_close, .write = hso_serial_write, .write_room = hso_serial_write_room, + .cleanup = hso_serial_cleanup, .ioctl = hso_serial_ioctl, .set_termios = hso_serial_set_termios, .chars_in_buffer = hso_serial_chars_in_buffer, -- cgit v1.2.1 From 295fc56f465ee8e013b2889e42094da9b2bd7125 Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:21:55 +0100 Subject: hso: fix memory leak when device disconnects In the disconnect path, tx_buffer should freed like tx_data to avoid a memory leak when the device disconnects. Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 191c1fac08b6..d855cead3978 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2253,6 +2253,7 @@ static void hso_serial_common_free(struct hso_serial *serial) /* unlink and free TX URB */ usb_free_urb(serial->tx_urb); + kfree(serial->tx_buffer); kfree(serial->tx_data); tty_port_destroy(&serial->port); } -- cgit v1.2.1 From 2e6d01ff759c5f0fc831694c01c477a6c0ebf7b1 Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:21:56 +0100 Subject: hso: fix memory leak in hso_create_rfkill() When the rfkill interface was created, a buffer containing the name of the rfkill node was allocated. This buffer was never freed when the device disappears. To fix the problem, we put the name given to rfkill_alloc() in the hso_net structure. Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index d855cead3978..e1cfe19c72d5 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -153,6 +153,7 @@ struct hso_net { struct hso_device *parent; struct net_device *net; struct rfkill *rfkill; + char name[8]; struct usb_endpoint_descriptor *in_endp; struct usb_endpoint_descriptor *out_endp; @@ -2467,27 +2468,20 @@ static void hso_create_rfkill(struct hso_device *hso_dev, { struct hso_net *hso_net = dev2net(hso_dev); struct device *dev = &hso_net->net->dev; - char *rfkn; - rfkn = kzalloc(20, GFP_KERNEL); - if (!rfkn) - dev_err(dev, "%s - Out of memory\n", __func__); - - snprintf(rfkn, 20, "hso-%d", + snprintf(hso_net->name, sizeof(hso_net->name), "hso-%d", interface->altsetting->desc.bInterfaceNumber); - hso_net->rfkill = rfkill_alloc(rfkn, + hso_net->rfkill = rfkill_alloc(hso_net->name, &interface_to_usbdev(interface)->dev, RFKILL_TYPE_WWAN, &hso_rfkill_ops, hso_dev); if (!hso_net->rfkill) { dev_err(dev, "%s - Out of memory\n", __func__); - kfree(rfkn); return; } if (rfkill_register(hso_net->rfkill) < 0) { rfkill_destroy(hso_net->rfkill); - kfree(rfkn); hso_net->rfkill = NULL; dev_err(dev, "%s - Failed to register rfkill\n", __func__); return; -- cgit v1.2.1 From 799276791f5e7d9174143823e2fefce649ce8429 Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:21:57 +0100 Subject: hso: fix small indentation error Simply remove the useless extra tab. Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index e1cfe19c72d5..0c115f81db86 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2206,8 +2206,8 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) for (i = 0; i < serial->num_rx_urbs; i++) { if (serial->rx_urb[i]) { - usb_kill_urb(serial->rx_urb[i]); - serial->rx_urb_filled[i] = 0; + usb_kill_urb(serial->rx_urb[i]); + serial->rx_urb_filled[i] = 0; } } serial->curr_rx_urb_idx = 0; -- cgit v1.2.1 From f6516b697c8a1772c1b4ca0be30764e70c3143dd Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:21:58 +0100 Subject: hso: rename hso_dev into serial in hso_free_interface() In other functions of the driver, variables of type "struct hso_serial" are denoted by "serial" and variables of type "struct hso_device" are denoted by "hso_dev". This patch makes the hso_free_interface() consistent with these notations. Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 0c115f81db86..fc310303bed8 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -3114,17 +3114,17 @@ static void hso_serial_ref_free(struct kref *ref) static void hso_free_interface(struct usb_interface *interface) { - struct hso_serial *hso_dev; + struct hso_serial *serial; int i; for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { if (serial_table[i] && (serial_table[i]->interface == interface)) { - hso_dev = dev2ser(serial_table[i]); - tty_port_tty_hangup(&hso_dev->port, false); - mutex_lock(&hso_dev->parent->mutex); - hso_dev->parent->usb_gone = 1; - mutex_unlock(&hso_dev->parent->mutex); + serial = dev2ser(serial_table[i]); + tty_port_tty_hangup(&serial->port, false); + mutex_lock(&serial->parent->mutex); + serial->parent->usb_gone = 1; + mutex_unlock(&serial->parent->mutex); kref_put(&serial_table[i]->ref, hso_serial_ref_free); } } -- cgit v1.2.1 From 26c1f1f544450d850971173725fe2f256ea2508b Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:21:59 +0100 Subject: hso: replace reset_device work by usb_queue_reset_device() There is no need for a dedicated reset work in the hso driver since there is already a reset work foreseen in usb_interface that does the same. Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index fc310303bed8..1e85ae76539e 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -274,7 +274,6 @@ struct hso_device { u8 usb_gone; struct work_struct async_get_intf; struct work_struct async_put_intf; - struct work_struct reset_device; struct usb_device *usb; struct usb_interface *interface; @@ -340,7 +339,6 @@ static void async_put_intf(struct work_struct *data); static int hso_put_activity(struct hso_device *hso_dev); static int hso_get_activity(struct hso_device *hso_dev); static void tiocmget_intr_callback(struct urb *urb); -static void reset_device(struct work_struct *data); /*****************************************************************************/ /* Helping functions */ /*****************************************************************************/ @@ -696,7 +694,7 @@ static void handle_usb_error(int status, const char *function, case -ETIMEDOUT: explanation = "protocol error"; if (hso_dev) - schedule_work(&hso_dev->reset_device); + usb_queue_reset_device(hso_dev->interface); break; default: explanation = "unknown status"; @@ -2347,7 +2345,6 @@ static struct hso_device *hso_create_device(struct usb_interface *intf, INIT_WORK(&hso_dev->async_get_intf, async_get_intf); INIT_WORK(&hso_dev->async_put_intf, async_put_intf); - INIT_WORK(&hso_dev->reset_device, reset_device); return hso_dev; } @@ -3085,26 +3082,6 @@ out: return result; } -static void reset_device(struct work_struct *data) -{ - struct hso_device *hso_dev = - container_of(data, struct hso_device, reset_device); - struct usb_device *usb = hso_dev->usb; - int result; - - if (hso_dev->usb_gone) { - D1("No reset during disconnect\n"); - } else { - result = usb_lock_device_for_reset(usb, hso_dev->interface); - if (result < 0) - D1("unable to lock device for reset: %d\n", result); - else { - usb_reset_device(usb); - usb_unlock_device(usb); - } - } -} - static void hso_serial_ref_free(struct kref *ref) { struct hso_device *hso_dev = container_of(ref, struct hso_device, ref); -- cgit v1.2.1 From 69b377b31be622762ebde5e5e63e8bed2e22bcea Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:22:00 +0100 Subject: hso: move tty_unregister outside hso_serial_common_free() The function hso_serial_common_free() is called either by the cleanup method of the tty or by the usb disconnect method. In the former case, the usb_disconnect() has been already called and the sysfs group associated to the device has been removed. By calling tty_unregister directly from the usb_disconnect() method, we avoid a warning due to the removal of the sysfs group of the usb device. Example of warning: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 778 at fs/sysfs/group.c:225 sysfs_remove_group+0x50/0x94() sysfs group c0645a88 not found for kobject 'ttyHS5' Modules linked in: CPU: 0 PID: 778 Comm: kworker/0:3 Tainted: G W 3.18.0+ #105 Workqueue: events release_one_tty [] (unwind_backtrace) from [] (show_stack+0x14/0x1c) [] (show_stack) from [] (warn_slowpath_common+0x5c/0x7c) [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x30/0x40) [] (warn_slowpath_fmt) from [] (sysfs_remove_group+0x50/0x94) [] (sysfs_remove_group) from [] (device_del+0x30/0x190) [] (device_del) from [] (device_unregister+0xc/0x18) [] (device_unregister) from [] (device_destroy+0x30/0x3c) [] (device_destroy) from [] (tty_unregister_device+0x2c/0x5c) [] (tty_unregister_device) from [] (hso_serial_common_free+0x2c/0x88) [] (hso_serial_common_free) from [] (hso_serial_ref_free+0x3c/0xb8) [] (hso_serial_ref_free) from [] (release_one_tty+0x30/0x84) [] (release_one_tty) from [] (process_one_work+0x21c/0x3c8) [] (process_one_work) from [] (worker_thread+0x3d8/0x560) [] (worker_thread) from [] (kthread+0xc0/0xcc) [] (kthread) from [] (ret_from_fork+0x14/0x24) ---[ end trace cb88537fdc8fa208 ]--- Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 1e85ae76539e..5d885888658e 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2234,14 +2234,17 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) return 0; } -static void hso_serial_common_free(struct hso_serial *serial) +static void hso_serial_tty_unregister(struct hso_serial *serial) { - int i; - if (serial->parent->dev) device_remove_file(serial->parent->dev, &dev_attr_hsotype); tty_unregister_device(tty_drv, serial->minor); +} + +static void hso_serial_common_free(struct hso_serial *serial) +{ + int i; for (i = 0; i < serial->num_rx_urbs; i++) { /* unlink and free RX URB */ @@ -2323,6 +2326,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, return 0; exit: + hso_serial_tty_unregister(serial); hso_serial_common_free(serial); return -1; } @@ -2683,6 +2687,7 @@ static struct hso_device *hso_create_bulk_serial_device( return hso_dev; exit2: + hso_serial_tty_unregister(serial); hso_serial_common_free(serial); exit: hso_free_tiomget(serial); @@ -3102,6 +3107,7 @@ static void hso_free_interface(struct usb_interface *interface) mutex_lock(&serial->parent->mutex); serial->parent->usb_gone = 1; mutex_unlock(&serial->parent->mutex); + hso_serial_tty_unregister(serial); kref_put(&serial_table[i]->ref, hso_serial_ref_free); } } -- cgit v1.2.1 From 301d3b7e109e28171d99948467448fd12ebfba06 Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:22:01 +0100 Subject: hso: update serial_table in usb disconnect method The serial_table is used to map the minor number of the usb serial device to its associated context. The table is updated in the probe method and in hso_serial_ref_free() which is called either from the tty cleanup method or from the usb disconnect method. This patch ensures that the serial_table is updated in the disconnect method and no more from the cleanup method to avoid the following potential race condition. - hso_disconnect() is called for usb interface "x". Because the serial port was open and because the cleanup method of the tty_port hasn't been called yet, hso_serial_ref_free() is not run. - hso_probe() is called and fails for a new hso serial usb interface "y". The function hso_free_interface() is called and iterates over the element of serial_table to find the device associated to the usb interface context. If the usb interface context of usb interface "y" has been created at the same place as for usb interface "x", then the cleanup functions are called for usb interfaces "x" and "y" and hso_serial_ref_free() is called for both interfaces. - release_tty() is called for serial port linked to usb interface "x" and possibly crash because the tty_port structure contained in the hso_device structure has been freed. Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 5d885888658e..cb33fb4e9a80 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2597,7 +2597,6 @@ static void hso_free_serial_device(struct hso_device *hso_dev) if (!serial) return; - set_serial_by_index(serial->minor, NULL); hso_serial_common_free(serial); @@ -3109,6 +3108,7 @@ static void hso_free_interface(struct usb_interface *interface) mutex_unlock(&serial->parent->mutex); hso_serial_tty_unregister(serial); kref_put(&serial_table[i]->ref, hso_serial_ref_free); + set_serial_by_index(i, NULL); } } -- cgit v1.2.1 From cc491970f5cef560b9e5bf037f0c9dd1e4d6a4bd Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:22:02 +0100 Subject: hso: add missing cancel_work_sync in disconnect() For hso serial devices, two cancel_work_sync were missing in the disconnect method. Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index cb33fb4e9a80..e94a02395357 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -3106,6 +3106,8 @@ static void hso_free_interface(struct usb_interface *interface) mutex_lock(&serial->parent->mutex); serial->parent->usb_gone = 1; mutex_unlock(&serial->parent->mutex); + cancel_work_sync(&serial_table[i]->async_put_intf); + cancel_work_sync(&serial_table[i]->async_get_intf); hso_serial_tty_unregister(serial); kref_put(&serial_table[i]->ref, hso_serial_ref_free); set_serial_by_index(i, NULL); -- cgit v1.2.1 From 38121067b10268385ca00978d1c1a241cd5eadfb Mon Sep 17 00:00:00 2001 From: Olivier Sobrie Date: Fri, 30 Jan 2015 13:22:03 +0100 Subject: hso: fix rfkill name conflicts By using only the usb interface number for the rfkill name, we might have a name conflicts in case two similar hso devices are connected. In this patch, the name of the hso rfkill interface embed the value of a counter that is incremented each time a new rfkill interface is added. Suggested-by: Dan Williams Signed-off-by: Olivier Sobrie Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index e94a02395357..7833bd1d9791 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -153,7 +153,7 @@ struct hso_net { struct hso_device *parent; struct net_device *net; struct rfkill *rfkill; - char name[8]; + char name[24]; struct usb_endpoint_descriptor *in_endp; struct usb_endpoint_descriptor *out_endp; @@ -2469,9 +2469,10 @@ static void hso_create_rfkill(struct hso_device *hso_dev, { struct hso_net *hso_net = dev2net(hso_dev); struct device *dev = &hso_net->net->dev; + static u32 rfkill_counter; snprintf(hso_net->name, sizeof(hso_net->name), "hso-%d", - interface->altsetting->desc.bInterfaceNumber); + rfkill_counter++); hso_net->rfkill = rfkill_alloc(hso_net->name, &interface_to_usbdev(interface)->dev, -- cgit v1.2.1 From 908edc5461565597bfc083c68088b780888e55b0 Mon Sep 17 00:00:00 2001 From: Mohammad Jamal Date: Fri, 23 Jan 2015 19:28:29 +0530 Subject: ieee802154: cc2520: Replace shift operations by BIT macro This patch replaces the shifting operations by BIT macro Signed-off-by: Mohammad Jamal Acked-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index a43c8acb7268..b38656732ff7 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -44,9 +44,9 @@ #define CC2520_FREG_MASK 0x3F /* status byte values */ -#define CC2520_STATUS_XOSC32M_STABLE (1 << 7) -#define CC2520_STATUS_RSSI_VALID (1 << 6) -#define CC2520_STATUS_TX_UNDERFLOW (1 << 3) +#define CC2520_STATUS_XOSC32M_STABLE BIT(7) +#define CC2520_STATUS_RSSI_VALID BIT(6) +#define CC2520_STATUS_TX_UNDERFLOW BIT(3) /* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */ #define CC2520_MINCHANNEL 11 -- cgit v1.2.1 From 3251ca334bcc379b4685bf6850bf38db365cbe6f Mon Sep 17 00:00:00 2001 From: Mohammad Jamal Date: Fri, 23 Jan 2015 19:25:27 +0530 Subject: ieee802154: cc2520: Fix space before , coding style issue This patch removes the warnings (space before , ) shown by checkpatch.pl Signed-off-by: Mohammad Jamal Acked-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index b38656732ff7..181b349b060e 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -549,14 +549,14 @@ cc2520_ed(struct ieee802154_hw *hw, u8 *level) u8 rssi; int ret; - ret = cc2520_read_register(priv , CC2520_RSSISTAT, &status); + ret = cc2520_read_register(priv, CC2520_RSSISTAT, &status); if (ret) return ret; if (status != RSSI_VALID) return -EINVAL; - ret = cc2520_read_register(priv , CC2520_RSSI, &rssi); + ret = cc2520_read_register(priv, CC2520_RSSI, &rssi); if (ret) return ret; -- cgit v1.2.1 From 3051fa617a3bb753185341a2040eaa454a54669e Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 30 Jan 2015 08:49:27 +0530 Subject: cxgb4: Remove preprocessor check for CONFIG_CXGB4_DCB In commit dc9daab226aa ("cxgb4: Added support in debugfs to dump sge_qinfo") a preprocessor check for CONFIG_CXGB4_DCB got added, which should have been CONFIG_CHELSIO_T4_DCB. After adding the right preprocessor, build fails due to missing function ethqset2pinfo. Fixing that as well. V2: Updated description since the patch also fixes build failure Reported-by: Paul Bolle Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 47c0869f34ca..61c000a08ebb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -1229,6 +1229,28 @@ static const struct file_operations rss_vf_config_debugfs_fops = { .release = seq_release_private }; +/** + * ethqset2pinfo - return port_info of an Ethernet Queue Set + * @adap: the adapter + * @qset: Ethernet Queue Set + */ +static inline struct port_info *ethqset2pinfo(struct adapter *adap, int qset) +{ + int pidx; + + for_each_port(adap, pidx) { + struct port_info *pi = adap2pinfo(adap, pidx); + + if (qset >= pi->first_qset && + qset < pi->first_qset + pi->nqsets) + return pi; + } + + /* should never happen! */ + BUG_ON(1); + return NULL; +} + static int sge_qinfo_show(struct seq_file *seq, void *v) { struct adapter *adap = seq->private; @@ -1272,7 +1294,7 @@ do { \ T("TxQ inuse:", q.in_use); T("TxQ CIDX:", q.cidx); T("TxQ PIDX:", q.pidx); -#ifdef CONFIG_CXGB4_DCB +#ifdef CONFIG_CHELSIO_T4_DCB T("DCB Prio:", dcb_prio); S3("u", "DCB PGID:", (ethqset2pinfo(adap, base_qset + i)->dcb.pgid >> -- cgit v1.2.1 From b2dec116fb9f3d8c7dd2e878fa1b9b88262985f7 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Fri, 30 Jan 2015 13:49:32 +0800 Subject: stmmac: DMA threshold mode or SF mode can be different among multiple device instance - In tx_hard_error_bump_tc interrupt, tc should be bumped only when current device instance is in DMA threshold mode. Check per device xstats.threshold other than global tc. - Set per device xstats.threshold to SF_DMA_MODE when current device instance is set to SF mode. v2-changes: - fix ident style Signed-off-by: Sonic Zhang Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9c11c4d0f3fd..55e89b3838f1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1288,7 +1288,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) * that needs to not insert csum in the TDES. */ priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE); - tc = SF_DMA_MODE; + priv->xstats.threshold = SF_DMA_MODE; } else priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); } @@ -1452,7 +1452,8 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv) } if (unlikely(status & tx_hard_error_bump_tc)) { /* Try to bump up the dma threshold on this failure */ - if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { + if (unlikely(priv->xstats.threshold != SF_DMA_MODE) && + (tc <= 256)) { tc += 64; if (priv->plat->force_thresh_dma_mode) priv->hw->dma->dma_mode(priv->ioaddr, tc, tc); -- cgit v1.2.1 From add511b38266aa10c1079f9248854e6a415c4dc2 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Thu, 29 Jan 2015 22:40:12 -0800 Subject: bridge: add flags argument to ndo_bridge_setlink and ndo_bridge_dellink bridge flags are needed inside ndo_bridge_setlink/dellink handlers to avoid another call to parse IFLA_AF_SPEC inside these handlers This is used later in this series Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 3 ++- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- drivers/net/ethernet/rocker/rocker.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 598c5070c629..efed92c7b731 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4327,7 +4327,8 @@ fw_exit: return status; } -static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh) +static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, + u16 flags) { struct be_adapter *adapter = netdev_priv(dev); struct nlattr *attr, *br_spec; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 7bb421bfd84e..e4086fea4be2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7786,7 +7786,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], } static int ixgbe_ndo_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh) + struct nlmsghdr *nlh, u16 flags) { struct ixgbe_adapter *adapter = netdev_priv(dev); struct nlattr *attr, *br_spec; diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 11f4ffcc113d..f0d607ca5e73 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -3722,7 +3722,7 @@ skip: } static int rocker_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh) + struct nlmsghdr *nlh, u16 flags) { struct rocker_port *rocker_port = netdev_priv(dev); struct nlattr *protinfo; -- cgit v1.2.1 From eb0ac4207f2db7245f07606a2b7929e604b875bd Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Thu, 29 Jan 2015 22:40:15 -0800 Subject: rocker: set feature NETIF_F_HW_SWITCH_OFFLOAD This patch sets the NETIF_F_HW_SWITCH_OFFLOAD feature flag on rocker ports Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index f0d607ca5e73..3c17ef2e3ff3 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4030,7 +4030,8 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) NAPI_POLL_WEIGHT); rocker_carrier_init(rocker_port); - dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | + NETIF_F_HW_SWITCH_OFFLOAD; err = register_netdev(dev); if (err) { -- cgit v1.2.1 From c158cba38ccd6e7c7787a6ec904d97b9d22537f5 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Thu, 29 Jan 2015 22:40:16 -0800 Subject: bonding: handle NETIF_F_HW_SWITCH_OFFLOAD flag and add ndo_bridge_setlink/dellink handlers We want bond to pick up the offload flag if any of its slaves have it. NETIF_F_HW_SWITCH_OFFLOAD flag is added to the mask, so that netdev_increment_features does not ignore it. This also adds ndo_bridge_setlink and ndo_bridge_dellink handlers. These currently point to the default handlers provided by the switchdev api. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e229a8657de8..c9e519cb9214 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -979,7 +980,11 @@ static netdev_features_t bond_fix_features(struct net_device *dev, netdev_features_t mask; struct slave *slave; - mask = features; + /* If any slave has the offload feature flag set, + * set the offload flag on the bond. + */ + mask = features | NETIF_F_HW_SWITCH_OFFLOAD; + features &= ~NETIF_F_ONE_FOR_ALL; features |= NETIF_F_ALL_FOR_ALL; @@ -3952,6 +3957,8 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_add_slave = bond_enslave, .ndo_del_slave = bond_release, .ndo_fix_features = bond_fix_features, + .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink, + .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink, }; static const struct device_type bond_type = { -- cgit v1.2.1 From a16a8ee7f60327086a35b688c78b555a8b4ac363 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Thu, 29 Jan 2015 22:40:17 -0800 Subject: team: handle NETIF_F_HW_SWITCH_OFFLOAD flag and add ndo_bridge_setlink/dellink handlers Currently ndo_bridge_setlink and ndo_bridge_dellink handlers point to the default switchdev handlers This follows my bonding driver changes. I have only compile tested this patch. However similar bonding code has been tested. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- drivers/net/team/team.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 4b2bfc52c52f..0e62274e884a 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -1925,7 +1926,7 @@ static netdev_features_t team_fix_features(struct net_device *dev, struct team *team = netdev_priv(dev); netdev_features_t mask; - mask = features; + mask = features | NETIF_F_HW_SWITCH_OFFLOAD; features &= ~NETIF_F_ONE_FOR_ALL; features |= NETIF_F_ALL_FOR_ALL; @@ -1975,6 +1976,8 @@ static const struct net_device_ops team_netdev_ops = { .ndo_del_slave = team_del_slave, .ndo_fix_features = team_fix_features, .ndo_change_carrier = team_change_carrier, + .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink, + .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink, }; /*********************** -- cgit v1.2.1 From 9766e97af1b901ffbb36fcc648e50626d926bb24 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 29 Jan 2015 20:59:33 -0700 Subject: net: rocker: Add support for retrieving port level statistics Add support for retrieving port level statistics from device. Hook is added for ethtool's stats functionality. For example, $ ethtool -S eth3 NIC statistics: rx_packets: 12 rx_bytes: 2790 rx_dropped: 0 rx_errors: 0 tx_packets: 8 tx_bytes: 728 tx_dropped: 0 tx_errors: 0 Signed-off-by: David Ahern Acked-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 134 +++++++++++++++++++++++++++++++++++ drivers/net/ethernet/rocker/rocker.h | 21 ++++++ 2 files changed, 155 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 3c17ef2e3ff3..34389b6aa67c 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -3833,11 +3833,145 @@ static void rocker_port_get_drvinfo(struct net_device *dev, strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version)); } +static struct rocker_port_stats { + char str[ETH_GSTRING_LEN]; + int type; +} rocker_port_stats[] = { + { "rx_packets", ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, }, + { "rx_bytes", ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, }, + { "rx_dropped", ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, }, + { "rx_errors", ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, }, + + { "tx_packets", ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, }, + { "tx_bytes", ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, }, + { "tx_dropped", ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, }, + { "tx_errors", ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, }, +}; + +#define ROCKER_PORT_STATS_LEN ARRAY_SIZE(rocker_port_stats) + +static void rocker_port_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) { + memcpy(p, rocker_port_stats[i].str, ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int +rocker_cmd_get_port_stats_prep(struct rocker *rocker, + struct rocker_port *rocker_port, + struct rocker_desc_info *desc_info, + void *priv) +{ + struct rocker_tlv *cmd_stats; + + if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, + ROCKER_TLV_CMD_TYPE_GET_PORT_STATS)) + return -EMSGSIZE; + + cmd_stats = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO); + if (!cmd_stats) + return -EMSGSIZE; + + if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_STATS_LPORT, + rocker_port->lport)) + return -EMSGSIZE; + + rocker_tlv_nest_end(desc_info, cmd_stats); + + return 0; +} + +static int +rocker_cmd_get_port_stats_ethtool_proc(struct rocker *rocker, + struct rocker_port *rocker_port, + struct rocker_desc_info *desc_info, + void *priv) +{ + struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1]; + struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1]; + struct rocker_tlv *pattr; + u32 lport; + u64 *data = priv; + int i; + + rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info); + + if (!attrs[ROCKER_TLV_CMD_INFO]) + return -EIO; + + rocker_tlv_parse_nested(stats_attrs, ROCKER_TLV_CMD_PORT_STATS_MAX, + attrs[ROCKER_TLV_CMD_INFO]); + + if (!stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT]) + return -EIO; + + lport = rocker_tlv_get_u32(stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT]); + if (lport != rocker_port->lport) + return -EIO; + + for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) { + pattr = stats_attrs[rocker_port_stats[i].type]; + if (!pattr) + continue; + + data[i] = rocker_tlv_get_u64(pattr); + } + + return 0; +} + +static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port, + void *priv) +{ + return rocker_cmd_exec(rocker_port->rocker, rocker_port, + rocker_cmd_get_port_stats_prep, NULL, + rocker_cmd_get_port_stats_ethtool_proc, + priv, false); +} + +static void rocker_port_get_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct rocker_port *rocker_port = netdev_priv(dev); + + if (rocker_cmd_get_port_stats_ethtool(rocker_port, data) != 0) { + int i; + + for (i = 0; i < ARRAY_SIZE(rocker_port_stats); ++i) + data[i] = 0; + } + + return; +} + +static int rocker_port_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ROCKER_PORT_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + static const struct ethtool_ops rocker_port_ethtool_ops = { .get_settings = rocker_port_get_settings, .set_settings = rocker_port_set_settings, .get_drvinfo = rocker_port_get_drvinfo, .get_link = ethtool_op_get_link, + .get_strings = rocker_port_get_strings, + .get_ethtool_stats = rocker_port_get_stats, + .get_sset_count = rocker_port_get_sset_count, }; /***************** diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index 8d2865ba634c..a5bc432feada 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -127,6 +127,9 @@ enum { ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL, ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS, + ROCKER_TLV_CMD_TYPE_CLEAR_PORT_STATS, + ROCKER_TLV_CMD_TYPE_GET_PORT_STATS, + __ROCKER_TLV_CMD_TYPE_MAX, ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1, }; @@ -146,6 +149,24 @@ enum { __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1, }; +enum { + ROCKER_TLV_CMD_PORT_STATS_UNSPEC, + ROCKER_TLV_CMD_PORT_STATS_LPORT, /* u32 */ + + ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, /* u64 */ + + ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, /* u64 */ + + __ROCKER_TLV_CMD_PORT_STATS_MAX, + ROCKER_TLV_CMD_PORT_STATS_MAX = __ROCKER_TLV_CMD_PORT_STATS_MAX - 1, +}; + enum rocker_port_mode { ROCKER_PORT_MODE_OF_DPA, }; -- cgit v1.2.1 From c38740d015577dc0c28b03210050af338d35e1b7 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 2 Feb 2015 19:49:43 +0200 Subject: iwlwifi: mvm: don't send a command the firmware doesn't know -9.ucode doesn't know the command SHARED_MEM_CFG yet. Fixes: 04fd2c28226f ("iwlwifi: mvm: add rxf and txf to dump data") Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index a322a5e3d31b..ca38e9817374 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -575,7 +575,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } - iwl_mvm_get_shared_mem_conf(mvm); + if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) + iwl_mvm_get_shared_mem_conf(mvm); ret = iwl_mvm_sf_update(mvm, NULL, false); if (ret) -- cgit v1.2.1 From 4c0c46be90b0316a75a6d0c44bf3f62152c6963f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Jan 2015 22:57:01 +0100 Subject: net: hip04: add missing MODULE_LICENSE The hip04 ethernet driver causes a new compile-time warning when built as a loadable module: WARNING: modpost: missing MODULE_LICENSE() in drivers/net/ethernet/hisilicon/hip04_eth.o see include/linux/module.h for more information This adds the license as "GPL", which matches the header of the file. Signed-off-by: Arnd Bergmann Acked-by: Ding Tianhong Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hip04_eth.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index c02b81bcfffb..b72d238695d7 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -968,3 +968,4 @@ static struct platform_driver hip04_mac_driver = { module_platform_driver(hip04_mac_driver); MODULE_DESCRIPTION("HISILICON P04 Ethernet driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.1 From 98830dd0fed031264b9d6ccb85b582506da95886 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Jan 2015 22:58:19 +0100 Subject: net/tulip: don't warn about unknown ARM architecture ARM has 32-byte cache lines, which according to the comment in the init registers function seems to work best with the default value of 0x4800 that is also used on sparc and parisc. This adds ARM to the same list, to use that default but no longer warn about it. Signed-off-by: Arnd Bergmann Acked-by: Grant Grundler Signed-off-by: David S. Miller --- drivers/net/ethernet/dec/tulip/winbond-840.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c index 6aa887e0e1cb..9beb3d34d4ba 100644 --- a/drivers/net/ethernet/dec/tulip/winbond-840.c +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c @@ -904,7 +904,7 @@ static void init_registers(struct net_device *dev) } #elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__) i |= 0xE000; -#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) +#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) || defined(CONFIG_ARM) i |= 0x4800; #else #warning Processor architecture undefined -- cgit v1.2.1 From ba0c39cb98a1eec3635ae5f959fef963738d12a5 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Fri, 30 Jan 2015 17:20:17 -0800 Subject: cxgb4 : Improve IEEE DCBx support, other minor open-lldp fixes * Add support for IEEE ets & pfc api. * Fix bug that resulted in incorrect bandwidth percentage being returned for CEE peers * Convert pfc enabled info from firmware format to what dcbnl expects before returning Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 98 +++++++++++++++++++++++++- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h | 11 +++ 2 files changed, 107 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index a35d1ec6950e..b65a5bda3195 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -428,7 +428,10 @@ static void cxgb4_getpgtccfg(struct net_device *dev, int tc, } *pgid = (be32_to_cpu(pcmd.u.dcb.pgid.pgid) >> (tc * 4)) & 0xf; - INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + if (local) + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + else + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE; err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); if (err != FW_PORT_DCB_CFG_SUCCESS) { @@ -900,6 +903,88 @@ cxgb4_ieee_negotiation_complete(struct net_device *dev, (dcb->supported & DCB_CAP_DCBX_VER_IEEE)); } +static int cxgb4_ieee_read_ets(struct net_device *dev, struct ieee_ets *ets, + int local) +{ + struct port_info *pi = netdev2pinfo(dev); + struct port_dcb_info *dcb = &pi->dcb; + struct adapter *adap = pi->adapter; + uint32_t tc_info; + struct fw_port_cmd pcmd; + int i, bwg, err; + + if (!(dcb->msgs & (CXGB4_DCB_FW_PGID | CXGB4_DCB_FW_PGRATE))) + return 0; + + ets->ets_cap = dcb->pg_num_tcs_supported; + + if (local) { + ets->willing = 1; + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + } else { + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + } + + pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err); + return err; + } + + tc_info = be32_to_cpu(pcmd.u.dcb.pgid.pgid); + + if (local) + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + else + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + + pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n", + -err); + return err; + } + + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { + bwg = (tc_info >> ((7 - i) * 4)) & 0xF; + ets->prio_tc[i] = bwg; + ets->tc_tx_bw[i] = pcmd.u.dcb.pgrate.pgrate[i]; + ets->tc_rx_bw[i] = ets->tc_tx_bw[i]; + ets->tc_tsa[i] = pcmd.u.dcb.pgrate.tsa[i]; + } + + return 0; +} + +static int cxgb4_ieee_get_ets(struct net_device *dev, struct ieee_ets *ets) +{ + return cxgb4_ieee_read_ets(dev, ets, 1); +} + +/* We reuse this for peer PFC as well, as we can't have it enabled one way */ +static int cxgb4_ieee_get_pfc(struct net_device *dev, struct ieee_pfc *pfc) +{ + struct port_info *pi = netdev2pinfo(dev); + struct port_dcb_info *dcb = &pi->dcb; + + memset(pfc, 0, sizeof(struct ieee_pfc)); + + if (!(dcb->msgs & CXGB4_DCB_FW_PFC)) + return 0; + + pfc->pfc_cap = dcb->pfc_num_tcs_supported; + pfc->pfc_en = bitswap_1(dcb->pfcen); + + return 0; +} + +static int cxgb4_ieee_peer_ets(struct net_device *dev, struct ieee_ets *ets) +{ + return cxgb4_ieee_read_ets(dev, ets, 0); +} + /* Fill in the Application User Priority Map associated with the * specified Application. * Priority for IEEE dcb_app is an integer, with 0 being a valid value @@ -1106,14 +1191,23 @@ static int cxgb4_cee_peer_getpfc(struct net_device *dev, struct cee_pfc *pfc) struct port_info *pi = netdev2pinfo(dev); cxgb4_getnumtcs(dev, DCB_NUMTCS_ATTR_PFC, &(pfc->tcs_supported)); - pfc->pfc_en = pi->dcb.pfcen; + + /* Firmware sends this to us in a formwat that is a bit flipped version + * of spec, correct it before we send it to host. This is taken care of + * by bit shifting in other uses of pfcen + */ + pfc->pfc_en = bitswap_1(pi->dcb.pfcen); return 0; } const struct dcbnl_rtnl_ops cxgb4_dcb_ops = { + .ieee_getets = cxgb4_ieee_get_ets, + .ieee_getpfc = cxgb4_ieee_get_pfc, .ieee_getapp = cxgb4_ieee_getapp, .ieee_setapp = cxgb4_ieee_setapp, + .ieee_peer_getets = cxgb4_ieee_peer_ets, + .ieee_peer_getpfc = cxgb4_ieee_get_pfc, /* CEE std */ .getstate = cxgb4_getstate, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h index 31ce425616c9..ccf24d3dc982 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h @@ -136,6 +136,17 @@ void cxgb4_dcb_handle_fw_update(struct adapter *, const struct fw_port_cmd *); void cxgb4_dcb_set_caps(struct adapter *, const struct fw_port_cmd *); extern const struct dcbnl_rtnl_ops cxgb4_dcb_ops; +static inline __u8 bitswap_1(unsigned char val) +{ + return ((val & 0x80) >> 7) | + ((val & 0x40) >> 5) | + ((val & 0x20) >> 3) | + ((val & 0x10) >> 1) | + ((val & 0x08) << 1) | + ((val & 0x04) << 3) | + ((val & 0x02) << 5) | + ((val & 0x01) << 7); +} #define CXGB4_DCB_ENABLED true #else /* !CONFIG_CHELSIO_T4_DCB */ -- cgit v1.2.1 From b9a641d9cb768177a7c867e382a2fdb6023b06ad Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Feb 2015 13:22:27 +0100 Subject: iwlwifi: mvm: reduce quota threshold The quota threshold should be reduced to 4 to update the firmware more frequently. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/constants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index d91c46b0f888..beba375489f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -99,7 +99,7 @@ #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 #define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 -#define IWL_MVM_QUOTA_THRESHOLD 8 +#define IWL_MVM_QUOTA_THRESHOLD 4 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_DISABLE_P2P_MIMO 0 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 -- cgit v1.2.1 From b661a5da57766f4f565d64238b753d6efc0f5499 Mon Sep 17 00:00:00 2001 From: Troy Tan Date: Tue, 20 Jan 2015 11:01:22 -0600 Subject: rtlwifi: rtl8192ee: Fix adhoc fail When the buffer descriptor index exceeds 2, then a TX HANG condition will result. Signed-off-by: Troy Tan Signed-off-by: Larry Finger Cc: Stable [V3.18] Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ee/fw.c | 6 +----- drivers/net/wireless/rtlwifi/rtl8192ee/hw.c | 26 -------------------------- 2 files changed, 1 insertion(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c index 45c128b91f7f..c5d4b8013cde 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c @@ -666,7 +666,6 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) struct sk_buff *skb = NULL; u32 totalpacketlen; - bool rtstatus; u8 u1rsvdpageloc[5] = { 0 }; bool b_dlok = false; @@ -728,10 +727,7 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) memcpy((u8 *)skb_put(skb, totalpacketlen), &reserved_page_packet, totalpacketlen); - rtstatus = rtl_cmd_send_packet(hw, skb); - - if (rtstatus) - b_dlok = true; + b_dlok = true; if (b_dlok) { RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c index 1a87edca2c3f..3c27ec2c7b5a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c @@ -85,29 +85,6 @@ static void _rtl92ee_enable_bcn_sub_func(struct ieee80211_hw *hw) _rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(1)); } -static void _rtl92ee_return_beacon_queue_skb(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; - unsigned long flags; - - spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); - while (skb_queue_len(&ring->queue)) { - struct rtl_tx_buffer_desc *entry = - &ring->buffer_desc[ring->idx]; - struct sk_buff *skb = __skb_dequeue(&ring->queue); - - pci_unmap_single(rtlpci->pdev, - rtlpriv->cfg->ops->get_desc( - (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), - skb->len, PCI_DMA_TODEVICE); - kfree_skb(skb); - ring->idx = (ring->idx + 1) % ring->entries; - } - spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); -} - static void _rtl92ee_disable_bcn_sub_func(struct ieee80211_hw *hw) { _rtl92ee_set_bcn_ctrl_reg(hw, BIT(1), 0); @@ -403,9 +380,6 @@ static void _rtl92ee_download_rsvd_page(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_DWBCN0_CTRL + 2, bcnvalid_reg | BIT(0)); - /* Return Beacon TCB */ - _rtl92ee_return_beacon_queue_skb(hw); - /* download rsvd page */ rtl92ee_set_fw_rsvdpagepkt(hw, false); -- cgit v1.2.1 From 6e5f4436162848289f071be38ee6b87dc8ea653d Mon Sep 17 00:00:00 2001 From: Troy Tan Date: Tue, 20 Jan 2015 11:01:23 -0600 Subject: rtlwifi: rtl8192ee: Fix TX hang due to failure to update TX write point Initially, the routine to update the write point in the FIFO buffer was coded to save CPU time by not doing the calculation every interrupt. This was an error and results in TX hangs. Signed-off-by: Troy Tan Signed-off-by: Larry Finger Cc: Stable [V3.18] Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ee/trx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c index 55d1da5e162b..04b91aade21d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c @@ -1027,8 +1027,7 @@ bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index) static u8 stop_report_cnt; struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; - /*checking Read/Write Point each interrupt wastes CPU */ - if (stop_report_cnt > 15 || !rtlpriv->link_info.busytraffic) { + { u16 point_diff = 0; u16 cur_tx_rp, cur_tx_wp; u32 tmpu32 = 0; -- cgit v1.2.1 From 92ff754240b892cbc16dee5aa080322f3db88b68 Mon Sep 17 00:00:00 2001 From: Troy Tan Date: Tue, 20 Jan 2015 11:01:24 -0600 Subject: rtlwifi: rtl8192ee: Fix parsing of received packet The firmware supplies two kinds of packets via the RX mechanism. Besides the normal data received over the air, these packets may contain bluetooth status and other information. The present code fails to detect which kind of information was received. Signed-off-by: Troy Tan Signed-off-by: Larry Finger Cc: Stable [V3.18] Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ee/trx.c | 4 ++++ drivers/net/wireless/rtlwifi/rtl8192ee/trx.h | 2 ++ 2 files changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c index 04b91aade21d..2b60bdc7452f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c @@ -354,6 +354,10 @@ bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr; u32 phystatus = GET_RX_DESC_PHYST(pdesc); + if (GET_RX_STATUS_DESC_RPT_SEL(pdesc) == 0) + status->packet_report_type = NORMAL_RX; + else + status->packet_report_type = C2H_PACKET; status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc); status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) * RX_DRV_INFO_SIZE_UNIT; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h index 48504c25fffb..5abb749b33e9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h @@ -542,6 +542,8 @@ LE_BITS_TO_4BYTE(__pdesc+8, 12, 4) #define GET_RX_DESC_RX_IS_QOS(__pdesc) \ LE_BITS_TO_4BYTE(__pdesc+8, 16, 1) +#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 28, 1) #define GET_RX_DESC_RXMCS(__pdesc) \ LE_BITS_TO_4BYTE(__pdesc+12, 0, 7) -- cgit v1.2.1 From 21b39ddb5bb2294fe64fbd29045591fe0707825f Mon Sep 17 00:00:00 2001 From: Troy Tan Date: Tue, 20 Jan 2015 11:01:26 -0600 Subject: rtlwifi: rtl8192ee: Fix DMA stalls There are instances where the DMA engine stalls. The new code detects such stalls and restarts DMA without needing a power reset. Signed-off-by: Troy Tan Signed-off-by: Larry Finger Cc: Stable [3.18] Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ee/hw.c | 140 +++++++++++++++++++++++++++ drivers/net/wireless/rtlwifi/rtl8192ee/reg.h | 2 + 2 files changed, 142 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c index 3c27ec2c7b5a..b461b3128da5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c @@ -1137,6 +1137,139 @@ void rtl92ee_enable_hw_security_config(struct ieee80211_hw *hw) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); } +static bool _rtl8192ee_check_pcie_dma_hang(struct rtl_priv *rtlpriv) +{ + u8 tmp; + + /* write reg 0x350 Bit[26]=1. Enable debug port. */ + tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3); + if (!(tmp & BIT(2))) { + rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3, + tmp | BIT(2)); + mdelay(100); /* Suggested by DD Justin_tsai. */ + } + + /* read reg 0x350 Bit[25] if 1 : RX hang + * read reg 0x350 Bit[24] if 1 : TX hang + */ + tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3); + if ((tmp & BIT(0)) || (tmp & BIT(1))) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "CheckPcieDMAHang8192EE(): true!!\n"); + return true; + } + return false; +} + +static void _rtl8192ee_reset_pcie_interface_dma(struct rtl_priv *rtlpriv, + bool mac_power_on) +{ + u8 tmp; + bool release_mac_rx_pause; + u8 backup_pcie_dma_pause; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "ResetPcieInterfaceDMA8192EE()\n"); + + /* Revise Note: Follow the document "PCIe RX DMA Hang Reset Flow_v03" + * released by SD1 Alan. + */ + + /* 1. disable register write lock + * write 0x1C bit[1:0] = 2'h0 + * write 0xCC bit[2] = 1'b1 + */ + tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL); + tmp &= ~(BIT(1) | BIT(0)); + rtl_write_byte(rtlpriv, REG_RSV_CTRL, tmp); + tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2); + tmp |= BIT(2); + rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp); + + /* 2. Check and pause TRX DMA + * write 0x284 bit[18] = 1'b1 + * write 0x301 = 0xFF + */ + tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL); + if (tmp & BIT(2)) { + /* Already pause before the function for another reason. */ + release_mac_rx_pause = false; + } else { + rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, (tmp | BIT(2))); + release_mac_rx_pause = true; + } + + backup_pcie_dma_pause = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 1); + if (backup_pcie_dma_pause != 0xFF) + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFF); + + if (mac_power_on) { + /* 3. reset TRX function + * write 0x100 = 0x00 + */ + rtl_write_byte(rtlpriv, REG_CR, 0); + } + + /* 4. Reset PCIe DMA + * write 0x003 bit[0] = 0 + */ + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + tmp &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp); + + /* 5. Enable PCIe DMA + * write 0x003 bit[0] = 1 + */ + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + tmp |= BIT(0); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp); + + if (mac_power_on) { + /* 6. enable TRX function + * write 0x100 = 0xFF + */ + rtl_write_byte(rtlpriv, REG_CR, 0xFF); + + /* We should init LLT & RQPN and + * prepare Tx/Rx descrptor address later + * because MAC function is reset. + */ + } + + /* 7. Restore PCIe autoload down bit + * write 0xF8 bit[17] = 1'b1 + */ + tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2); + tmp |= BIT(1); + rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2, tmp); + + /* In MAC power on state, BB and RF maybe in ON state, + * if we release TRx DMA here + * it will cause packets to be started to Tx/Rx, + * so we release Tx/Rx DMA later. + */ + if (!mac_power_on) { + /* 8. release TRX DMA + * write 0x284 bit[18] = 1'b0 + * write 0x301 = 0x00 + */ + if (release_mac_rx_pause) { + tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL); + rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, + (tmp & (~BIT(2)))); + } + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, + backup_pcie_dma_pause); + } + + /* 9. lock system register + * write 0xCC bit[2] = 1'b0 + */ + tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2); + tmp &= ~(BIT(2)); + rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp); +} + int rtl92ee_hw_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1162,6 +1295,13 @@ int rtl92ee_hw_init(struct ieee80211_hw *hw) rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E; } + if (_rtl8192ee_check_pcie_dma_hang(rtlpriv)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "92ee dma hang!\n"); + _rtl8192ee_reset_pcie_interface_dma(rtlpriv, + rtlhal->mac_func_enable); + rtlhal->mac_func_enable = false; + } + rtstatus = _rtl92ee_init_mac(hw); rtl_write_byte(rtlpriv, 0x577, 0x03); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h index 3f2a9596e7cd..1eaa1fab550d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h @@ -77,9 +77,11 @@ #define REG_HIMRE 0x00B8 #define REG_HISRE 0x00BC +#define REG_PMC_DBG_CTRL2 0x00CC #define REG_EFUSE_ACCESS 0x00CF #define REG_HPON_FSM 0x00EC #define REG_SYS_CFG1 0x00F0 +#define REG_MAC_PHY_CTRL_NORMAL 0x00F8 #define REG_SYS_CFG2 0x00FC #define REG_CR 0x0100 -- cgit v1.2.1 From ee6f0dd8a836311883fedfe060f23e0da2176950 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 30 Jan 2015 00:40:04 -0800 Subject: mwifiex: correction in wakeup timer handling Wakeup timer is in sync with 'pm_wakeup_fw_try' flag. It has been started instead of cancelling at one place. This patch corrects it. Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sta_event.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index c03b82c2fe1c..80ffe7412496 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -312,8 +312,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; - mod_timer(&adapter->wakeup_timer, - jiffies + (HZ*3)); + del_timer_sync(&adapter->wakeup_timer); break; } if (!mwifiex_send_null_packet -- cgit v1.2.1 From 7a1f4e61eb6417aecd20822a5f15e72d21c7f3f9 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 30 Jan 2015 00:40:05 -0800 Subject: mwifiex: fix memory leak in mwifiex_send_processed_packet() Memory is leaked after downloading already processed packet. This patch fixes the problem by freeing returned skb. Other transmit paths don't have this problem. Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/wmm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index ffffd2c5a76e..ef717acec8b7 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1228,6 +1228,9 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, case -EINPROGRESS: if (adapter->iface_type != MWIFIEX_PCIE) adapter->data_sent = false; + break; + case 0: + mwifiex_write_data_complete(adapter, skb, 0, ret); default: break; } -- cgit v1.2.1 From 0ea3186ce03cfa9b1c5cb8677ac3ffcd19695cd7 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 30 Jan 2015 00:40:06 -0800 Subject: mwifiex: fix NULL packet downloading issues This patch makes sure that skb is freed after downloading NULL packet in error cases. Also, USB chipsets return -EINPROGRESS after downloading packets, they are freed in USB completion handler later. We will add missing change to set tx_lock_flag for USB which blocks further packets. Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sta_tx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index 1debe76017b1..5ce2d9a4f919 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -183,9 +183,13 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) } switch (ret) { case -EBUSY: - adapter->data_sent = true; - /* Fall through FAILURE handling */ + dev_kfree_skb_any(skb); + dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n", + __func__, ret); + adapter->dbg.num_tx_host_to_card_failure++; + break; case -1: + adapter->data_sent = false; dev_kfree_skb_any(skb); dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n", __func__, ret); @@ -198,6 +202,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) adapter->tx_lock_flag = true; break; case -EINPROGRESS: + adapter->tx_lock_flag = true; break; default: break; -- cgit v1.2.1 From fc8f0456dcce1701291928febf8410994749d4af Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 30 Jan 2015 00:40:07 -0800 Subject: mwifiex: disable UAPSD mode when AP starts When AP is started, firmware exits power save mode. This means power save manager of AP takes priority over station. Firmware stop sending periodic AWAKE events to host. We may have UAPSD enabled on station which buffers data packets until AWAKE event from firmware. Data path is unnecessarily blocked in this case. This patch disables UAPSD mode to reenable transmit data path. Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sta_cmdresp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 39f31766812f..5f8da5924666 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -1105,6 +1105,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_UAP_SYS_CONFIG: break; case HostCmd_CMD_UAP_BSS_START: + adapter->tx_lock_flag = false; + adapter->pps_uapsd_mode = false; + adapter->delay_null_pkt = false; priv->bss_started = 1; break; case HostCmd_CMD_UAP_BSS_STOP: -- cgit v1.2.1 From 4895efc9a11ba6a3089b42c5dd4aabf68e467d64 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:21 +0530 Subject: ath9k: Remove ATH9K_HW_WOW_DEVICE_CAPABLE Enabling WOW based on the chip is incorrect since it needs to be done for specific sub-devices which have proper platform support. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.c | 3 --- drivers/net/wireless/ath/ath9k/hw.h | 2 -- drivers/net/wireless/ath/ath9k/wow.c | 4 +--- 3 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 82d8f32a3461..8c2f9e290b35 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2544,9 +2544,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_RTT; } - if (AR_SREV_9462(ah)) - pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE; - if (AR_SREV_9300_20_OR_LATER(ah) && ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 450704e49f03..dabc94e11805 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -248,12 +248,10 @@ enum ath9k_hw_caps { #ifdef CONFIG_ATH9K_PCOEM ATH9K_HW_CAP_RTT = BIT(14), ATH9K_HW_CAP_MCI = BIT(15), - ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(16), ATH9K_HW_CAP_BT_ANT_DIV = BIT(17), #else ATH9K_HW_CAP_RTT = 0, ATH9K_HW_CAP_MCI = 0, - ATH9K_HW_WOW_DEVICE_CAPABLE = 0, ATH9K_HW_CAP_BT_ANT_DIV = 0, #endif ATH9K_HW_CAP_DFS = BIT(18), diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 5f30e580d942..4ffaadd167a8 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -352,9 +352,7 @@ void ath9k_init_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && - (sc->driver_data & ATH9K_PCI_WOW) && - device_can_wakeup(sc->dev)) + if ((sc->driver_data & ATH9K_PCI_WOW) && device_can_wakeup(sc->dev)) hw->wiphy->wowlan = &ath9k_wowlan_support; atomic_set(&sc->wow_sleep_proc_intr, -1); -- cgit v1.2.1 From 13084c2d18bfee72594ba3a969dfdd972544e644 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:22 +0530 Subject: ath9k: Return early for error conditions Do not try to cancel work instances and ANI when the device is not present or WOW triggers are not configured. Bail out early and use ath_err() for such error conditions. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 4ffaadd167a8..1d5cd88783bd 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -197,21 +197,21 @@ int ath9k_suspend(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); - ath_cancel_work(sc); - ath_stop_ani(sc); - if (test_bit(ATH_OP_INVALID, &common->op_flags)) { - ath_dbg(common, ANY, "Device not present\n"); - ret = -EINVAL; + ath_err(common, "Device not present\n"); + ret = -ENODEV; goto fail_wow; } if (WARN_ON(!wowlan)) { - ath_dbg(common, WOW, "None of the WoW triggers enabled\n"); + ath_err(common, "None of the WoW triggers enabled\n"); ret = -EINVAL; goto fail_wow; } + ath_cancel_work(sc); + ath_stop_ani(sc); + if (!device_can_wakeup(sc->dev)) { ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); ret = 1; -- cgit v1.2.1 From 410b4e27992b7bc3ed8064dc9383eb66c1fee04d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:23 +0530 Subject: ath9k: Remove redundant device_can_wakeup() check WOW capability is registered with mac80211 only when the device has the ability to wakeup, so there is no need to check in the suspend() routine. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 1d5cd88783bd..272c05c5c24e 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -212,12 +212,6 @@ int ath9k_suspend(struct ieee80211_hw *hw, ath_cancel_work(sc); ath_stop_ani(sc); - if (!device_can_wakeup(sc->dev)) { - ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); - ret = 1; - goto fail_wow; - } - /* * none of the sta vifs are associated * and we are not currently handling multivif -- cgit v1.2.1 From dc4b277d51599453f9ebf8e117957c26187d5fce Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:24 +0530 Subject: ath9k: Check early for multi-vif/STA conditions If multiple interfaces are active or there is no associated station interface, bail out early and return 1 so that mac80211 can proceed with the normal suspend routine. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 272c05c5c24e..1799a1d69ebd 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -209,29 +209,21 @@ int ath9k_suspend(struct ieee80211_hw *hw, goto fail_wow; } - ath_cancel_work(sc); - ath_stop_ani(sc); - - /* - * none of the sta vifs are associated - * and we are not currently handling multivif - * cases, for instance we have to seperately - * configure 'keep alive frame' for each - * STA. - */ - - if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { - ath_dbg(common, WOW, "None of the STA vifs are associated\n"); + if (sc->cur_chan->nvifs > 1) { + ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); ret = 1; goto fail_wow; } - if (sc->cur_chan->nvifs > 1) { - ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { + ath_dbg(common, WOW, "None of the STA vifs are associated\n"); ret = 1; goto fail_wow; } + ath_cancel_work(sc); + ath_stop_ani(sc); + ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", -- cgit v1.2.1 From 1331f5a751eb143bc7732c880bbdde4431e90a77 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:25 +0530 Subject: ath9k: Check multi-channel context for WOW If CONFIG_ATH9K_CHANNEL_CONTEXT is enabled, check whether multiple contexts are active and if so, return 1 without enabling WOW since we don't support it in this case. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 1799a1d69ebd..1b005c697c03 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -215,6 +215,15 @@ int ath9k_suspend(struct ieee80211_hw *hw, goto fail_wow; } + if (ath9k_is_chanctx_enabled()) { + if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) { + ath_dbg(common, WOW, + "Multi-channel WOW is not supported\n"); + ret = 1; + goto fail_wow; + } + } + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { ath_dbg(common, WOW, "None of the STA vifs are associated\n"); ret = 1; -- cgit v1.2.1 From 661d25815ea533d06c7535ddd1c4810fa7ab9e22 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:26 +0530 Subject: ath9k: Fix wow init/deinit Registering the card as a wakeup source needs to be done once, during initialization. When the WOW configuration changes, the card's status as wakeup source needs to be changed too and this is done via the set_wakeup() callback. Also, make sure the device is removed properly using ath9k_deinit_wow(). Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++++ drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/wow.c | 22 ++++++++++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e84b5769deb0..4209d7baf1d4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -838,6 +838,7 @@ struct ath9k_wow_pattern { #ifdef CONFIG_ATH9K_WOW void ath9k_init_wow(struct ieee80211_hw *hw); +void ath9k_deinit_wow(struct ieee80211_hw *hw); int ath9k_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); int ath9k_resume(struct ieee80211_hw *hw); @@ -846,6 +847,9 @@ void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled); static inline void ath9k_init_wow(struct ieee80211_hw *hw) { } +static inline void ath9k_deinit_wow(struct ieee80211_hw *hw) +{ +} static inline int ath9k_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 2aef14e47c39..6c6e88495394 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -996,6 +996,7 @@ void ath9k_deinit_device(struct ath_softc *sc) ath9k_ps_restore(sc); ath9k_deinit_debug(sc); + ath9k_deinit_wow(hw); ieee80211_unregister_hw(hw); ath_rx_cleanup(sc); ath9k_deinit_softc(sc); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 1b005c697c03..8bcbaa91529e 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -336,20 +336,34 @@ int ath9k_resume(struct ieee80211_hw *hw) void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); mutex_lock(&sc->mutex); - device_init_wakeup(sc->dev, 1); device_set_wakeup_enable(sc->dev, enabled); mutex_unlock(&sc->mutex); + + ath_dbg(common, WOW, "WoW wakeup source is %s\n", + (enabled) ? "enabled" : "disabled"); } void ath9k_init_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - if ((sc->driver_data & ATH9K_PCI_WOW) && device_can_wakeup(sc->dev)) + if (sc->driver_data & ATH9K_PCI_WOW) { hw->wiphy->wowlan = &ath9k_wowlan_support; - atomic_set(&sc->wow_sleep_proc_intr, -1); - atomic_set(&sc->wow_got_bmiss_intr, -1); + atomic_set(&sc->wow_sleep_proc_intr, -1); + atomic_set(&sc->wow_got_bmiss_intr, -1); + + device_init_wakeup(sc->dev, 1); + } +} + +void ath9k_deinit_wow(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + + if (sc->driver_data & ATH9K_PCI_WOW) + device_init_wakeup(sc->dev, 0); } -- cgit v1.2.1 From 249943a2215c4d03c5dacf549b4ef9bf8439f17b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:27 +0530 Subject: ath9k: Check WOW triggers properly This patch makes sure that valid WOW triggers are present before trying to suspend the device. Also, introduce and use ATH_OP_WOW_ENABLED to bypass PCI suspend and clear it in resume(). Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath9k/pci.c | 5 +++- drivers/net/wireless/ath/ath9k/wow.c | 53 ++++++++++++++++-------------------- 3 files changed, 29 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index ccba4fea7269..1eebe2ea3dfb 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -64,6 +64,7 @@ enum ath_op_flags { ATH_OP_HW_RESET, ATH_OP_SCANNING, ATH_OP_MULTI_CHANNEL, + ATH_OP_WOW_ENABLED, }; enum ath_bus_type { diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index cc5c6810f32e..e6fef1be9977 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -998,9 +998,12 @@ static int ath_pci_suspend(struct device *device) struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - if (sc->wow_enabled) + if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) { + dev_info(&pdev->dev, "WOW is enabled, bypassing PCI suspend\n"); return 0; + } /* The device has to be moved to FULLSLEEP forcibly. * Otherwise the chip never moved to full sleep, diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 8bcbaa91529e..c0c564de982e 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -23,21 +23,21 @@ static const struct wiphy_wowlan_support ath9k_wowlan_support = { .pattern_max_len = MAX_PATTERN_SIZE, }; -static void ath9k_wow_map_triggers(struct ath_softc *sc, - struct cfg80211_wowlan *wowlan, - u32 *wow_triggers) +static u8 ath9k_wow_map_triggers(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan) { + u8 wow_triggers = 0; + if (wowlan->disconnect) - *wow_triggers |= AH_WOW_LINK_CHANGE | - AH_WOW_BEACON_MISS; + wow_triggers |= AH_WOW_LINK_CHANGE | + AH_WOW_BEACON_MISS; if (wowlan->magic_pkt) - *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; + wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; if (wowlan->n_patterns) - *wow_triggers |= AH_WOW_USER_PATTERN_EN; - - sc->wow_enabled = *wow_triggers; + wow_triggers |= AH_WOW_USER_PATTERN_EN; + return wow_triggers; } static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) @@ -45,7 +45,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); int pattern_count = 0; - int i, byte_cnt; + int i, byte_cnt = 0; u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; u8 dis_deauth_mask[MAX_PATTERN_SIZE]; @@ -80,12 +80,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) * | x:x:x:x:x:x -- 22 bytes */ - /* Create Disassociate Pattern first */ - - byte_cnt = 0; - /* Fill out the mask with all FF's */ - for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) dis_deauth_mask[i] = 0xff; @@ -108,17 +103,13 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) byte_cnt += 6; /* copy the bssid, its same as the source mac address */ - memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); /* Create Disassociate pattern mask */ - dis_deauth_mask[0] = 0xfe; dis_deauth_mask[1] = 0x03; dis_deauth_mask[2] = 0xc0; - ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, pattern_count, byte_cnt); @@ -131,7 +122,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, pattern_count, byte_cnt); - } static void ath9k_wow_add_pattern(struct ath_softc *sc, @@ -190,7 +180,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u32 wow_triggers_enabled = 0; + u8 triggers; int ret = 0; ath9k_deinit_channel_context(sc); @@ -230,14 +220,16 @@ int ath9k_suspend(struct ieee80211_hw *hw, goto fail_wow; } + triggers = ath9k_wow_map_triggers(sc, wowlan); + if (!triggers) { + ath_dbg(common, WOW, "No valid WoW triggers\n"); + ret = 1; + goto fail_wow; + } + ath_cancel_work(sc); ath_stop_ani(sc); - ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); - - ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", - wow_triggers_enabled); - ath9k_ps_wakeup(sc); ath9k_stop_btcoex(sc); @@ -248,7 +240,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, */ ath9k_wow_add_disassoc_deauth_pattern(sc); - if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) + if (triggers & AH_WOW_USER_PATTERN_EN) ath9k_wow_add_pattern(sc, wowlan); spin_lock_bh(&sc->sc_pcu_lock); @@ -273,12 +265,13 @@ int ath9k_suspend(struct ieee80211_hw *hw, synchronize_irq(sc->irq); tasklet_kill(&sc->intr_tq); - ath9k_hw_wow_enable(ah, wow_triggers_enabled); + ath9k_hw_wow_enable(ah, triggers); ath9k_ps_restore(sc); - ath_dbg(common, ANY, "WoW enabled in ath9k\n"); + ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers); atomic_inc(&sc->wow_sleep_proc_intr); + set_bit(ATH_OP_WOW_ENABLED, &common->op_flags); fail_wow: mutex_unlock(&sc->mutex); return ret; @@ -327,6 +320,8 @@ int ath9k_resume(struct ieee80211_hw *hw) ath_restart_work(sc); ath9k_start_btcoex(sc); + clear_bit(ATH_OP_WOW_ENABLED, &common->op_flags); + ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); -- cgit v1.2.1 From c4d0975bba51ac339727703123cfca8034c1aeb3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:28 +0530 Subject: ath9k: Remove unused BMISS processing The various variables tracking bmiss interrupts are not really used anywhere except in a debug message. Remove them since they have no functional purpose. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 -- drivers/net/wireless/ath/ath9k/main.c | 9 --------- drivers/net/wireless/ath/ath9k/wow.c | 18 ------------------ 3 files changed, 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 4209d7baf1d4..803a7d4ff1b2 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -1043,8 +1043,6 @@ struct ath_softc { s16 tx99_power; #ifdef CONFIG_ATH9K_WOW - atomic_t wow_got_bmiss_intr; - atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */ u32 wow_intr_before_sleep; #endif }; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9a72640237cb..98b1e4aa1506 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -556,15 +556,6 @@ irqreturn_t ath_isr(int irq, void *dev) (status & ATH9K_INT_BB_WATCHDOG)) goto chip_reset; -#ifdef CONFIG_ATH9K_WOW - if (status & ATH9K_INT_BMISS) { - if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { - atomic_inc(&sc->wow_got_bmiss_intr); - atomic_dec(&sc->wow_sleep_proc_intr); - } - } -#endif - if (status & ATH9K_INT_SWBA) tasklet_schedule(&sc->bcon_tasklet); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index c0c564de982e..fa60dbb0bf14 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -269,7 +269,6 @@ int ath9k_suspend(struct ieee80211_hw *hw, ath9k_ps_restore(sc); ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers); - atomic_inc(&sc->wow_sleep_proc_intr); set_bit(ATH_OP_WOW_ENABLED, &common->op_flags); fail_wow: @@ -299,19 +298,6 @@ int ath9k_resume(struct ieee80211_hw *hw) wow_status = ath9k_hw_wow_wakeup(ah); - if (atomic_read(&sc->wow_got_bmiss_intr) == 0) { - /* - * some devices may not pick beacon miss - * as the reason they woke up so we add - * that here for that shortcoming. - */ - wow_status |= AH_WOW_BEACON_MISS; - atomic_dec(&sc->wow_got_bmiss_intr); - ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n"); - } - - atomic_dec(&sc->wow_sleep_proc_intr); - if (wow_status) { ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", ath9k_hw_wow_event_to_string(wow_status), wow_status); @@ -347,10 +333,6 @@ void ath9k_init_wow(struct ieee80211_hw *hw) if (sc->driver_data & ATH9K_PCI_WOW) { hw->wiphy->wowlan = &ath9k_wowlan_support; - - atomic_set(&sc->wow_sleep_proc_intr, -1); - atomic_set(&sc->wow_got_bmiss_intr, -1); - device_init_wakeup(sc->dev, 1); } } -- cgit v1.2.1 From e094c3375c5179ea30505676fd35e08568a77ee2 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:29 +0530 Subject: ath9k: Remove ath9k_hw_wow_event_to_string Printing the value of the wakeup status is sufficient. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 15 --------------- drivers/net/wireless/ath/ath9k/hw.h | 5 ----- drivers/net/wireless/ath/ath9k/wow.c | 10 +++------- 3 files changed, 3 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index 81c88dd606dc..3abc9073f4ac 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -19,21 +19,6 @@ #include "reg.h" #include "hw-ops.h" -const char *ath9k_hw_wow_event_to_string(u32 wow_event) -{ - if (wow_event & AH_WOW_MAGIC_PATTERN_EN) - return "Magic pattern"; - if (wow_event & AH_WOW_USER_PATTERN_EN) - return "User pattern"; - if (wow_event & AH_WOW_LINK_CHANGE) - return "Link change"; - if (wow_event & AH_WOW_BEACON_MISS) - return "Beacon miss"; - - return "unknown reason"; -} -EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); - static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index dabc94e11805..22b04222a1bd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1146,17 +1146,12 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) #ifdef CONFIG_ATH9K_WOW -const char *ath9k_hw_wow_event_to_string(u32 wow_event); void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, u8 *user_mask, int pattern_count, int pattern_len); u32 ath9k_hw_wow_wakeup(struct ath_hw *ah); void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable); #else -static inline const char *ath9k_hw_wow_event_to_string(u32 wow_event) -{ - return NULL; -} static inline void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, u8 *user_mask, diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index fa60dbb0bf14..d4cfbc363eb5 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -281,7 +281,7 @@ int ath9k_resume(struct ieee80211_hw *hw) struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u32 wow_status; + u8 status; mutex_lock(&sc->mutex); @@ -296,12 +296,8 @@ int ath9k_resume(struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_pcu_lock); - wow_status = ath9k_hw_wow_wakeup(ah); - - if (wow_status) { - ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", - ath9k_hw_wow_event_to_string(wow_status), wow_status); - } + status = ath9k_hw_wow_wakeup(ah); + ath_dbg(common, WOW, "Resume with WoW status: 0x%x\n", status); ath_restart_work(sc); ath9k_start_btcoex(sc); -- cgit v1.2.1 From 8b861715087fe17796fe411eff1c7f7e493d0d10 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:30 +0530 Subject: ath9k: Add a debugfs file for WOW This can be used to force WOW for cards that are not present in the supported PCI ID list. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/debug.c | 68 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/wow.c | 4 +- 3 files changed, 71 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 803a7d4ff1b2..20216c56e158 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -1044,6 +1044,7 @@ struct ath_softc { #ifdef CONFIG_ATH9K_WOW u32 wow_intr_before_sleep; + bool force_wow; #endif }; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index dd5d3914799b..50a2e0ac3b8b 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1043,6 +1043,69 @@ static const struct file_operations fops_ackto = { }; #endif +#ifdef CONFIG_ATH9K_WOW + +static ssize_t read_file_wow(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned int len = 0, size = 32; + ssize_t retval; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += scnprintf(buf + len, size - len, "WOW: %s\n", + sc->force_wow ? "ENABLED" : "DISABLED"); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static ssize_t write_file_wow(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val != 1) + return -EINVAL; + + if (!sc->force_wow) { + sc->force_wow = true; + ath9k_init_wow(sc->hw); + } + + return count; +} + +static const struct file_operations fops_wow = { + .read = read_file_wow, + .write = write_file_wow, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +#endif + static ssize_t read_file_tpc(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1313,6 +1376,11 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_btcoex); #endif +#ifdef CONFIG_ATH9K_WOW + debugfs_create_file("wow", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_wow); +#endif + #ifdef CONFIG_ATH9K_DYNACK debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_ackto); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index d4cfbc363eb5..4b3b56563714 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -327,7 +327,7 @@ void ath9k_init_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - if (sc->driver_data & ATH9K_PCI_WOW) { + if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) { hw->wiphy->wowlan = &ath9k_wowlan_support; device_init_wakeup(sc->dev, 1); } @@ -337,6 +337,6 @@ void ath9k_deinit_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - if (sc->driver_data & ATH9K_PCI_WOW) + if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) device_init_wakeup(sc->dev, 0); } -- cgit v1.2.1 From 34d102c921100a70d8262adc1afc09f492782778 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:31 +0530 Subject: ath9k: Simplify user pattern configuration There is no need to allocate a new structure and free it for every user pattern, instead use local variables. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 6 ----- drivers/net/wireless/ath/ath9k/wow.c | 49 +++++++++------------------------- 2 files changed, 12 insertions(+), 43 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 20216c56e158..0f8e9464e4ab 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -830,12 +830,6 @@ static inline void ath_fill_led_pin(struct ath_softc *sc) /* Wake on Wireless LAN */ /************************/ -struct ath9k_wow_pattern { - u8 pattern_bytes[MAX_PATTERN_SIZE]; - u8 mask_bytes[MAX_PATTERN_SIZE]; - u32 pattern_len; -}; - #ifdef CONFIG_ATH9K_WOW void ath9k_init_wow(struct ieee80211_hw *hw); void ath9k_deinit_wow(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 4b3b56563714..da52b1ffff24 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -128,50 +128,25 @@ static void ath9k_wow_add_pattern(struct ath_softc *sc, struct cfg80211_wowlan *wowlan) { struct ath_hw *ah = sc->sc_ah; - struct ath9k_wow_pattern *wow_pattern = NULL; struct cfg80211_pkt_pattern *patterns = wowlan->patterns; + u8 wow_pattern[MAX_PATTERN_SIZE]; + u8 wow_mask[MAX_PATTERN_SIZE]; int mask_len; s8 i = 0; - if (!wowlan->n_patterns) - return; - - /* - * Add the new user configured patterns - */ for (i = 0; i < wowlan->n_patterns; i++) { - - wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL); - - if (!wow_pattern) - return; - - /* - * TODO: convert the generic user space pattern to - * appropriate chip specific/802.11 pattern. - */ - - mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); - memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE); - memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE); - memcpy(wow_pattern->pattern_bytes, patterns[i].pattern, - patterns[i].pattern_len); - memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len); - wow_pattern->pattern_len = patterns[i].pattern_len; - - /* - * just need to take care of deauth and disssoc pattern, - * make sure we don't overwrite them. - */ - - ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes, - wow_pattern->mask_bytes, + mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8); + memset(wow_pattern, 0, MAX_PATTERN_SIZE); + memset(wow_mask, 0, MAX_PATTERN_SIZE); + memcpy(wow_pattern, patterns[i].pattern, patterns[i].pattern_len); + memcpy(wow_mask, patterns[i].mask, mask_len); + + ath9k_hw_wow_apply_pattern(ah, + wow_pattern, + wow_mask, i + 2, - wow_pattern->pattern_len); - kfree(wow_pattern); - + patterns[i].pattern_len); } - } int ath9k_suspend(struct ieee80211_hw *hw, -- cgit v1.2.1 From 41fe8837215a82ea3469267d6fac57e830f9e59a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:32 +0530 Subject: ath9k: Add a HW structure for WOW This can be used to hold the WOW state in ath9k_hw. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 10 +++++----- drivers/net/wireless/ath/ath9k/hw.h | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index 3abc9073f4ac..bb6141765020 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -137,7 +137,7 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, * other fields */ - ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); + ah->wow.wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); if (pattern_count < 4) { /* Pattern 0-3 uses AR_WOW_LENGTH1 register */ @@ -174,7 +174,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) * register. This mask will clean it up. */ - val &= ah->wow_event_mask; + val &= ah->wow.wow_event_mask; if (val) { if (val & AR_WOW_MAGIC_PAT_FOUND) @@ -218,7 +218,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) if (ah->is_pciexpress) ath9k_hw_configpcipowersave(ah, false); - ah->wow_event_mask = 0; + ah->wow.wow_event_mask = 0; return wow_status; } @@ -235,7 +235,7 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) * are from the 'pattern_enable' in this function and * 'pattern_count' of ath9k_hw_wow_apply_pattern() */ - wow_event_mask = ah->wow_event_mask; + wow_event_mask = ah->wow.wow_event_mask; /* * Untie Power-on-Reset from the PCI-E-Reset. When we are in @@ -402,6 +402,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); ath9k_hw_set_powermode_wow_sleep(ah); - ah->wow_event_mask = wow_event_mask; + ah->wow.wow_event_mask = wow_event_mask; } EXPORT_SYMBOL(ath9k_hw_wow_enable); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 22b04222a1bd..d36210ae880e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -270,6 +270,10 @@ enum ath9k_hw_caps { * of those types. */ +struct ath9k_hw_wow { + u32 wow_event_mask; +}; + struct ath9k_hw_capabilities { u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ u16 rts_aggr_limit; @@ -928,7 +932,7 @@ struct ath_hw { u32 ent_mode; #ifdef CONFIG_ATH9K_WOW - u32 wow_event_mask; + struct ath9k_hw_wow wow; #endif bool is_clk_25mhz; int (*get_mac_revision)(void); -- cgit v1.2.1 From 12a444224479597cf49d49aed109389f6da4f2d8 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:33 +0530 Subject: ath9k: Register max WOW patterns Since the number of patterns that can be configured in the HW is higher for newer chips, store the chip-specific value in ath9k_hw_wow. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.c | 7 +++++++ drivers/net/wireless/ath/ath9k/hw.h | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8c2f9e290b35..60aa8d71e753 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2548,6 +2548,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; +#ifdef CONFIG_ATH9K_WOW + if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah)) + ah->wow.max_patterns = MAX_NUM_PATTERN; + else + ah->wow.max_patterns = MAX_NUM_PATTERN_LEGACY; +#endif + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index d36210ae880e..e1801c91d538 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -204,7 +204,8 @@ #define MAX_PATTERN_SIZE 256 #define MAX_PATTERN_MASK_SIZE 32 -#define MAX_NUM_PATTERN 8 +#define MAX_NUM_PATTERN 16 +#define MAX_NUM_PATTERN_LEGACY 8 #define MAX_NUM_USER_PATTERN 6 /* deducting the disassociate and deauthenticate packets */ @@ -272,6 +273,7 @@ enum ath9k_hw_caps { struct ath9k_hw_wow { u32 wow_event_mask; + u8 max_patterns; }; struct ath9k_hw_capabilities { -- cgit v1.2.1 From ce6e982bbc1e30ee21fd60c8d7ff238dad7be785 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:34 +0530 Subject: ath9k: Move WOW registers to reg_wow.h Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 1 + drivers/net/wireless/ath/ath9k/reg.h | 120 ------------------------ drivers/net/wireless/ath/ath9k/reg_wow.h | 136 ++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 120 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/reg_wow.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index bb6141765020..6681a7b03cd0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -17,6 +17,7 @@ #include #include "ath9k.h" #include "reg.h" +#include "reg_wow.h" #include "hw-ops.h" static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 3c0b1807bb2b..b1b803d05926 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -2010,126 +2010,6 @@ enum { #define AR_WOW_BEACON_TIMO_MAX 0xffffffff -/* - * MAC WoW Registers - */ - -#define AR_WOW_PATTERN 0x825C -#define AR_WOW_COUNT 0x8260 -#define AR_WOW_BCN_EN 0x8270 -#define AR_WOW_BCN_TIMO 0x8274 -#define AR_WOW_KEEP_ALIVE_TIMO 0x8278 -#define AR_WOW_KEEP_ALIVE 0x827c -#define AR_WOW_US_SCALAR 0x8284 -#define AR_WOW_KEEP_ALIVE_DELAY 0x8288 -#define AR_WOW_PATTERN_MATCH 0x828c -#define AR_WOW_PATTERN_OFF1 0x8290 /* pattern bytes 0 -> 3 */ -#define AR_WOW_PATTERN_OFF2 0x8294 /* pattern bytes 4 -> 7 */ - -/* for AR9285 or later version of chips */ -#define AR_WOW_EXACT 0x829c -#define AR_WOW_LENGTH1 0x8360 -#define AR_WOW_LENGTH2 0X8364 -/* register to enable match for less than 256 bytes packets */ -#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368 - -#define AR_SW_WOW_CONTROL 0x20018 -#define AR_SW_WOW_ENABLE 0x1 -#define AR_SWITCH_TO_REFCLK 0x2 -#define AR_RESET_CONTROL 0x4 -#define AR_RESET_VALUE_MASK 0x8 -#define AR_HW_WOW_DISABLE 0x10 -#define AR_CLR_MAC_INTERRUPT 0x20 -#define AR_CLR_KA_INTERRUPT 0x40 - -/* AR_WOW_PATTERN register values */ -#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 28) /* in usecs */ -#define AR_WOW_MAC_INTR_EN 0x00040000 -#define AR_WOW_MAGIC_EN 0x00010000 -#define AR_WOW_PATTERN_EN(x) (x & 0xff) -#define AR_WOW_PAT_FOUND_SHIFT 8 -#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT)) -#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT) -#define AR_WOW_MAGIC_PAT_FOUND 0x00020000 -#define AR_WOW_MAC_INTR 0x00080000 -#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000 -#define AR_WOW_BEACON_FAIL 0x00200000 - -#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \ - AR_WOW_MAGIC_PAT_FOUND | \ - AR_WOW_KEEP_ALIVE_FAIL | \ - AR_WOW_BEACON_FAIL)) -#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \ - AR_WOW_MAGIC_EN | \ - AR_WOW_MAC_INTR_EN | \ - AR_WOW_BEACON_FAIL | \ - AR_WOW_KEEP_ALIVE_FAIL)) - -/* AR_WOW_COUNT register values */ -#define AR_WOW_AIFS_CNT(x) (x & 0xff) -#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8) -#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16) - -/* AR_WOW_BCN_EN register */ -#define AR_WOW_BEACON_FAIL_EN 0x00000001 - -/* AR_WOW_BCN_TIMO rgister */ -#define AR_WOW_BEACON_TIMO 0x40000000 /* valid if BCN_EN is set */ - -/* AR_WOW_KEEP_ALIVE_TIMO register */ -#define AR_WOW_KEEP_ALIVE_TIMO_VALUE -#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff - -/* AR_WOW_KEEP_ALIVE register */ -#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001 -#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002 - -/* AR_WOW_KEEP_ALIVE_DELAY register */ -#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */ - - -/* - * keep it long for beacon workaround - ensure no false alarm - */ -#define AR_WOW_BMISSTHRESHOLD 0x20 - -/* AR_WOW_PATTERN_MATCH register */ -#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf) -#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8) - -/* - * default values for Wow Configuration for backoff, aifs, slot, keep-alive - * to be programmed into various registers. - */ -#define AR_WOW_PAT_BACKOFF 0x00000004 /* AR_WOW_PATTERN_REG */ -#define AR_WOW_CNT_AIFS_CNT 0x00000022 /* AR_WOW_COUNT_REG */ -#define AR_WOW_CNT_SLOT_CNT 0x00000009 /* AR_WOW_COUNT_REG */ -/* - * Keepalive count applicable for AR9280 2.0 and above. - */ -#define AR_WOW_CNT_KA_CNT 0x00000008 /* AR_WOW_COUNT register */ - -/* WoW - Transmit buffer for keep alive frames */ -#define AR_WOW_TRANSMIT_BUFFER 0xe000 /* E000 - EFFC */ - -#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2)) - -#define AR_WOW_KA_DESC_WORD2 0xe000 - -#define AR_WOW_KA_DATA_WORD0 0xe030 - -/* WoW Transmit Buffer for patterns */ -#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8)) -#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5)) - -/* Currently Pattern 0-7 are supported - so bit 0-7 are set */ -#define AR_WOW_PATTERN_SUPPORTED 0xff -#define AR_WOW_LENGTH_MAX 0xff -#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3) -#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) -#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3) -#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i)) - #define AR9271_CORE_CLOCK 117 /* clock to 117Mhz */ #define AR9271_TARGET_BAUD_RATE 19200 /* 115200 */ diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h new file mode 100644 index 000000000000..3dbe5db4dd31 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/reg_wow.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef REG_WOW_H +#define REG_WOW_H + +#define AR_WOW_PATTERN 0x825C +#define AR_WOW_COUNT 0x8260 +#define AR_WOW_BCN_EN 0x8270 +#define AR_WOW_BCN_TIMO 0x8274 +#define AR_WOW_KEEP_ALIVE_TIMO 0x8278 +#define AR_WOW_KEEP_ALIVE 0x827c +#define AR_WOW_US_SCALAR 0x8284 +#define AR_WOW_KEEP_ALIVE_DELAY 0x8288 +#define AR_WOW_PATTERN_MATCH 0x828c +#define AR_WOW_PATTERN_OFF1 0x8290 /* pattern bytes 0 -> 3 */ +#define AR_WOW_PATTERN_OFF2 0x8294 /* pattern bytes 4 -> 7 */ + +/* for AR9285 or later version of chips */ +#define AR_WOW_EXACT 0x829c +#define AR_WOW_LENGTH1 0x8360 +#define AR_WOW_LENGTH2 0X8364 +/* register to enable match for less than 256 bytes packets */ +#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368 + +#define AR_SW_WOW_CONTROL 0x20018 +#define AR_SW_WOW_ENABLE 0x1 +#define AR_SWITCH_TO_REFCLK 0x2 +#define AR_RESET_CONTROL 0x4 +#define AR_RESET_VALUE_MASK 0x8 +#define AR_HW_WOW_DISABLE 0x10 +#define AR_CLR_MAC_INTERRUPT 0x20 +#define AR_CLR_KA_INTERRUPT 0x40 + +/* AR_WOW_PATTERN register values */ +#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 28) /* in usecs */ +#define AR_WOW_MAC_INTR_EN 0x00040000 +#define AR_WOW_MAGIC_EN 0x00010000 +#define AR_WOW_PATTERN_EN(x) (x & 0xff) +#define AR_WOW_PAT_FOUND_SHIFT 8 +#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT)) +#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT) +#define AR_WOW_MAGIC_PAT_FOUND 0x00020000 +#define AR_WOW_MAC_INTR 0x00080000 +#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000 +#define AR_WOW_BEACON_FAIL 0x00200000 + +#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \ + AR_WOW_MAGIC_PAT_FOUND | \ + AR_WOW_KEEP_ALIVE_FAIL | \ + AR_WOW_BEACON_FAIL)) +#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \ + AR_WOW_MAGIC_EN | \ + AR_WOW_MAC_INTR_EN | \ + AR_WOW_BEACON_FAIL | \ + AR_WOW_KEEP_ALIVE_FAIL)) + +/* AR_WOW_COUNT register values */ +#define AR_WOW_AIFS_CNT(x) (x & 0xff) +#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8) +#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16) + +/* AR_WOW_BCN_EN register */ +#define AR_WOW_BEACON_FAIL_EN 0x00000001 + +/* AR_WOW_BCN_TIMO rgister */ +#define AR_WOW_BEACON_TIMO 0x40000000 /* valid if BCN_EN is set */ + +/* AR_WOW_KEEP_ALIVE_TIMO register */ +#define AR_WOW_KEEP_ALIVE_TIMO_VALUE +#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff + +/* AR_WOW_KEEP_ALIVE register */ +#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001 +#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002 + +/* AR_WOW_KEEP_ALIVE_DELAY register */ +#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */ + + +/* + * keep it long for beacon workaround - ensure no false alarm + */ +#define AR_WOW_BMISSTHRESHOLD 0x20 + +/* AR_WOW_PATTERN_MATCH register */ +#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf) +#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8) + +/* + * default values for Wow Configuration for backoff, aifs, slot, keep-alive + * to be programmed into various registers. + */ +#define AR_WOW_PAT_BACKOFF 0x00000004 /* AR_WOW_PATTERN_REG */ +#define AR_WOW_CNT_AIFS_CNT 0x00000022 /* AR_WOW_COUNT_REG */ +#define AR_WOW_CNT_SLOT_CNT 0x00000009 /* AR_WOW_COUNT_REG */ +/* + * Keepalive count applicable for AR9280 2.0 and above. + */ +#define AR_WOW_CNT_KA_CNT 0x00000008 /* AR_WOW_COUNT register */ + +/* WoW - Transmit buffer for keep alive frames */ +#define AR_WOW_TRANSMIT_BUFFER 0xe000 /* E000 - EFFC */ + +#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2)) + +#define AR_WOW_KA_DESC_WORD2 0xe000 + +#define AR_WOW_KA_DATA_WORD0 0xe030 + +/* WoW Transmit Buffer for patterns */ +#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8)) +#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5)) + +/* Currently Pattern 0-7 are supported - so bit 0-7 are set */ +#define AR_WOW_PATTERN_SUPPORTED 0xff +#define AR_WOW_LENGTH_MAX 0xff +#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3) +#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) +#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3) +#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i)) + +#endif /* REG_WOW_H */ -- cgit v1.2.1 From c65fb2637a5c772faaea50e19813bb52e66b0006 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:35 +0530 Subject: ath9k: Remove incorrect register macros These macros are applicable to pre-AR9003 chips and the addresses are different for the AR9003 family. Since they are unused anyway, remove them. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/reg_wow.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h index 3dbe5db4dd31..780553a7e3fd 100644 --- a/drivers/net/wireless/ath/ath9k/reg_wow.h +++ b/drivers/net/wireless/ath/ath9k/reg_wow.h @@ -23,14 +23,9 @@ #define AR_WOW_BCN_TIMO 0x8274 #define AR_WOW_KEEP_ALIVE_TIMO 0x8278 #define AR_WOW_KEEP_ALIVE 0x827c -#define AR_WOW_US_SCALAR 0x8284 #define AR_WOW_KEEP_ALIVE_DELAY 0x8288 #define AR_WOW_PATTERN_MATCH 0x828c -#define AR_WOW_PATTERN_OFF1 0x8290 /* pattern bytes 0 -> 3 */ -#define AR_WOW_PATTERN_OFF2 0x8294 /* pattern bytes 4 -> 7 */ -/* for AR9285 or later version of chips */ -#define AR_WOW_EXACT 0x829c #define AR_WOW_LENGTH1 0x8360 #define AR_WOW_LENGTH2 0X8364 /* register to enable match for less than 256 bytes packets */ -- cgit v1.2.1 From 404033c16c0a739fba8a5f00a306e33e3a367d19 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:36 +0530 Subject: ath9k: Cleanup reg_wow.h * Remove unnecessary comments. * Remove unused macros. * Indent the macros. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/reg_wow.h | 68 +++++++------------------------- 1 file changed, 15 insertions(+), 53 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h index 780553a7e3fd..e6de4a375182 100644 --- a/drivers/net/wireless/ath/ath9k/reg_wow.h +++ b/drivers/net/wireless/ath/ath9k/reg_wow.h @@ -25,10 +25,8 @@ #define AR_WOW_KEEP_ALIVE 0x827c #define AR_WOW_KEEP_ALIVE_DELAY 0x8288 #define AR_WOW_PATTERN_MATCH 0x828c - #define AR_WOW_LENGTH1 0x8360 #define AR_WOW_LENGTH2 0X8364 -/* register to enable match for less than 256 bytes packets */ #define AR_WOW_PATTERN_MATCH_LT_256B 0x8368 #define AR_SW_WOW_CONTROL 0x20018 @@ -40,7 +38,6 @@ #define AR_CLR_MAC_INTERRUPT 0x20 #define AR_CLR_KA_INTERRUPT 0x40 -/* AR_WOW_PATTERN register values */ #define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 28) /* in usecs */ #define AR_WOW_MAC_INTR_EN 0x00040000 #define AR_WOW_MAGIC_EN 0x00010000 @@ -63,69 +60,34 @@ AR_WOW_BEACON_FAIL | \ AR_WOW_KEEP_ALIVE_FAIL)) -/* AR_WOW_COUNT register values */ #define AR_WOW_AIFS_CNT(x) (x & 0xff) #define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8) #define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16) -/* AR_WOW_BCN_EN register */ #define AR_WOW_BEACON_FAIL_EN 0x00000001 - -/* AR_WOW_BCN_TIMO rgister */ -#define AR_WOW_BEACON_TIMO 0x40000000 /* valid if BCN_EN is set */ - -/* AR_WOW_KEEP_ALIVE_TIMO register */ -#define AR_WOW_KEEP_ALIVE_TIMO_VALUE +#define AR_WOW_BEACON_TIMO 0x40000000 #define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff - -/* AR_WOW_KEEP_ALIVE register */ #define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001 #define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002 - -/* AR_WOW_KEEP_ALIVE_DELAY register */ #define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */ - - -/* - * keep it long for beacon workaround - ensure no false alarm - */ #define AR_WOW_BMISSTHRESHOLD 0x20 - -/* AR_WOW_PATTERN_MATCH register */ #define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf) #define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8) - -/* - * default values for Wow Configuration for backoff, aifs, slot, keep-alive - * to be programmed into various registers. - */ -#define AR_WOW_PAT_BACKOFF 0x00000004 /* AR_WOW_PATTERN_REG */ -#define AR_WOW_CNT_AIFS_CNT 0x00000022 /* AR_WOW_COUNT_REG */ -#define AR_WOW_CNT_SLOT_CNT 0x00000009 /* AR_WOW_COUNT_REG */ -/* - * Keepalive count applicable for AR9280 2.0 and above. - */ -#define AR_WOW_CNT_KA_CNT 0x00000008 /* AR_WOW_COUNT register */ - -/* WoW - Transmit buffer for keep alive frames */ -#define AR_WOW_TRANSMIT_BUFFER 0xe000 /* E000 - EFFC */ - -#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2)) - -#define AR_WOW_KA_DESC_WORD2 0xe000 - -#define AR_WOW_KA_DATA_WORD0 0xe030 - -/* WoW Transmit Buffer for patterns */ -#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8)) -#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5)) - -/* Currently Pattern 0-7 are supported - so bit 0-7 are set */ +#define AR_WOW_PAT_BACKOFF 0x00000004 +#define AR_WOW_CNT_AIFS_CNT 0x00000022 +#define AR_WOW_CNT_SLOT_CNT 0x00000009 +#define AR_WOW_CNT_KA_CNT 0x00000008 + +#define AR_WOW_TRANSMIT_BUFFER 0xe000 +#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2)) +#define AR_WOW_KA_DESC_WORD2 0xe000 +#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8)) +#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5)) #define AR_WOW_PATTERN_SUPPORTED 0xff #define AR_WOW_LENGTH_MAX 0xff -#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3) -#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) -#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3) -#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i)) +#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3) +#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) +#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3) +#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i)) #endif /* REG_WOW_H */ -- cgit v1.2.1 From 6af75e4da330bf7ead84566275a9b49fe471bb4d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:37 +0530 Subject: ath9k: Fix max pattern check Since the maximum number of configurable patterns is chip-specific, use the HW capability instead of a fixed value for checking if a free pattern slot is available. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 12 +++---- drivers/net/wireless/ath/ath9k/hw.h | 17 ++++----- drivers/net/wireless/ath/ath9k/wow.c | 53 ++++++++++++++++++++--------- 3 files changed, 51 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index 6681a7b03cd0..d2a4f6f49045 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -89,17 +89,16 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) } -void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, - u8 *user_mask, int pattern_count, - int pattern_len) +int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len) { int i; u32 pattern_val, mask_val; u32 set, clr; - /* FIXME: should check count by querying the hardware capability */ - if (pattern_count >= MAX_NUM_PATTERN) - return; + if (pattern_count >= ah->wow.max_patterns) + return -ENOSPC; REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); @@ -154,6 +153,7 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, REG_RMW(ah, AR_WOW_LENGTH2, set, clr); } + return 0; } EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e1801c91d538..f51a28f0740e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1152,18 +1152,19 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) #ifdef CONFIG_ATH9K_WOW -void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, - u8 *user_mask, int pattern_count, - int pattern_len); +int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len); u32 ath9k_hw_wow_wakeup(struct ath_hw *ah); void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable); #else -static inline void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, - u8 *user_pattern, - u8 *user_mask, - int pattern_count, - int pattern_len) +static inline int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, + u8 *user_pattern, + u8 *user_mask, + int pattern_count, + int pattern_len) { + return 0; } static inline u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) { diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index da52b1ffff24..5092939876f6 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -40,12 +40,12 @@ static u8 ath9k_wow_map_triggers(struct ath_softc *sc, return wow_triggers; } -static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) +static int ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); int pattern_count = 0; - int i, byte_cnt = 0; + int ret, i, byte_cnt = 0; u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; u8 dis_deauth_mask[MAX_PATTERN_SIZE]; @@ -110,8 +110,10 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) dis_deauth_mask[1] = 0x03; dis_deauth_mask[2] = 0xc0; - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, - pattern_count, byte_cnt); + ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); + if (ret) + goto exit; pattern_count++; /* @@ -120,18 +122,20 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) */ dis_deauth_pattern[0] = 0xC0; - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, - pattern_count, byte_cnt); + ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); +exit: + return ret; } -static void ath9k_wow_add_pattern(struct ath_softc *sc, - struct cfg80211_wowlan *wowlan) +static int ath9k_wow_add_pattern(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan) { struct ath_hw *ah = sc->sc_ah; struct cfg80211_pkt_pattern *patterns = wowlan->patterns; u8 wow_pattern[MAX_PATTERN_SIZE]; u8 wow_mask[MAX_PATTERN_SIZE]; - int mask_len; + int mask_len, ret = 0; s8 i = 0; for (i = 0; i < wowlan->n_patterns; i++) { @@ -141,12 +145,16 @@ static void ath9k_wow_add_pattern(struct ath_softc *sc, memcpy(wow_pattern, patterns[i].pattern, patterns[i].pattern_len); memcpy(wow_mask, patterns[i].mask, mask_len); - ath9k_hw_wow_apply_pattern(ah, - wow_pattern, - wow_mask, - i + 2, - patterns[i].pattern_len); + ret = ath9k_hw_wow_apply_pattern(ah, + wow_pattern, + wow_mask, + i + 2, + patterns[i].pattern_len); + if (ret) + break; } + + return ret; } int ath9k_suspend(struct ieee80211_hw *hw, @@ -213,10 +221,21 @@ int ath9k_suspend(struct ieee80211_hw *hw, * Enable wake up on recieving disassoc/deauth * frame by default. */ - ath9k_wow_add_disassoc_deauth_pattern(sc); + ret = ath9k_wow_add_disassoc_deauth_pattern(sc); + if (ret) { + ath_err(common, + "Unable to add disassoc/deauth pattern: %d\n", ret); + goto fail_wow; + } - if (triggers & AH_WOW_USER_PATTERN_EN) - ath9k_wow_add_pattern(sc, wowlan); + if (triggers & AH_WOW_USER_PATTERN_EN) { + ret = ath9k_wow_add_pattern(sc, wowlan); + if (ret) { + ath_err(common, + "Unable to add user pattern: %d\n", ret); + goto fail_wow; + } + } spin_lock_bh(&sc->sc_pcu_lock); /* -- cgit v1.2.1 From a3c74902082c0e77aaf1065b5489867508db44ca Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 1 Feb 2015 10:55:11 +0200 Subject: wil6210: remove old Tx work-around In the Tx, work around used to force destination index 0 to be used. This is no more necessary, as firmware supports multiple destinations Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 0499ebcdeff5..24c4b9a6a004 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -873,9 +873,6 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, d->mac.d[1] = 0; d->mac.d[2] = 0; d->mac.ucode_cmd = 0; - /* use dst index 0 */ - d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) | - (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS); /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); -- cgit v1.2.1 From e59d16c08b3aa147f5c3c664d5dfda77fa93a827 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 1 Feb 2015 10:55:12 +0200 Subject: wil6210: avoid Tx descriptor double write Non-cacheable Tx descriptor for the last fragment of multi-fragment frame used to be written back twice. Refactor code to always write non-cacheable descriptor only once Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 24c4b9a6a004..e37cab1c5a53 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -981,8 +981,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, vring->ctx[i].nr_frags = nr_frags; wil_tx_desc_set_nr_frags(d, nr_frags); - if (nr_frags) - *_d = *d; /* middle segments */ for (; f < nr_frags; f++) { @@ -990,6 +988,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, &skb_shinfo(skb)->frags[f]; int len = skb_frag_size(frag); + *_d = *d; i = (swhead + f + 1) % vring->size; _d = &vring->va[i].tx; pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), @@ -1003,7 +1002,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, * it will succeed here too */ wil_tx_desc_offload_cksum_set(wil, d, skb); - *_d = *d; } /* for the last seg only */ d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); -- cgit v1.2.1 From 5933a06dc96cad21b7c125995791c93a86be7915 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 1 Feb 2015 10:55:13 +0200 Subject: wil6210: fix race between xmit and Tx vring de-allocation Use spinlock, this should not impact Tx as lock is always free except for de-allocation. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 25 ++++++++++++++++++++++--- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index e37cab1c5a53..85ecea2e6a67 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -671,6 +671,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, } memset(txdata, 0, sizeof(*txdata)); + spin_lock_init(&txdata->lock); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -718,8 +719,10 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) wil_dbg_misc(wil, "%s() id=%d\n", __func__, id); + spin_lock_bh(&txdata->lock); + txdata->enabled = 0; /* no Tx can be in progress or start anew */ + spin_unlock_bh(&txdata->lock); /* make sure NAPI won't touch this vring */ - wil->vring_tx_data[id].enabled = 0; if (test_bit(wil_status_napi_en, wil->status)) napi_synchronize(&wil->napi_tx); @@ -935,8 +938,8 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, return 0; } -static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, - struct sk_buff *skb) +static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb) { struct device *dev = wil_to_dev(wil); struct vring_tx_desc dd, *d = ⅆ @@ -952,6 +955,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_dbg_txrx(wil, "%s()\n", __func__); + if (unlikely(!txdata->enabled)) + return -EINVAL; + if (avail < 1 + nr_frags) { wil_err_ratelimited(wil, "Tx ring full. No space for %d fragments\n", @@ -1050,6 +1056,19 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, return -EINVAL; } +static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb) +{ + int vring_index = vring - wil->vring_tx; + struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; + int rc; + + spin_lock(&txdata->lock); + rc = __wil_tx_vring(wil, vring, skb); + spin_unlock(&txdata->lock); + return rc; +} + netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 90dc24fb60f8..94611568fc9a 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -385,6 +385,7 @@ struct vring_tx_data { u16 agg_timeout; u8 agg_amsdu; bool addba_in_progress; /* if set, agg_xxx is for request in progress */ + spinlock_t lock; }; enum { /* for wil6210_priv.status */ -- cgit v1.2.1 From 5b29c573f3dcb22534489194ba97aeb495cc65ca Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 1 Feb 2015 10:55:14 +0200 Subject: wil6210: more Tx debug Print Tx descriptors Print ring index for all Tx related messages Sort prefixes: Tx for transmit, TxC for completion, added "D" for descriptor related prints Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 85ecea2e6a67..8439f65db259 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -960,16 +960,16 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, if (avail < 1 + nr_frags) { wil_err_ratelimited(wil, - "Tx ring full. No space for %d fragments\n", - 1 + nr_frags); + "Tx ring[%2d] full. No space for %d fragments\n", + vring_index, 1 + nr_frags); return -ENOMEM; } _d = &vring->va[i].tx; pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb), - skb->data, &pa); + wil_dbg_txrx(wil, "Tx[%2d] skb %d bytes 0x%p -> %pad\n", vring_index, + skb_headlen(skb), skb->data, &pa); wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); @@ -980,7 +980,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); /* Process TCP/UDP checksum offloading */ if (wil_tx_desc_offload_cksum_set(wil, d, skb)) { - wil_err(wil, "VRING #%d Failed to set cksum, drop packet\n", + wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", vring_index); goto dma_error; } @@ -995,6 +995,9 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, int len = skb_frag_size(frag); *_d = *d; + wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); + wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); i = (swhead + f + 1) % vring->size; _d = &vring->va[i].tx; pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), @@ -1014,6 +1017,9 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS); d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); *_d = *d; + wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); + wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); /* hold reference to skb * to prevent skb release before accounting @@ -1021,15 +1027,13 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, */ vring->ctx[i].skb = skb_get(skb); - wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, - (const void *)d, sizeof(*d), false); - if (wil_vring_is_empty(vring)) /* performance monitoring */ txdata->idle += get_cycles() - txdata->last_idle; /* advance swhead */ wil_vring_advance_head(vring, nr_frags + 1); - wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); + wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead, + vring->swhead); trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); @@ -1211,10 +1215,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) trace_wil6210_tx_done(ringid, vring->swtail, dmalen, d->dma.error); wil_dbg_txrx(wil, - "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", - vring->swtail, dmalen, d->dma.status, - d->dma.error); - wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, + "TxC[%2d][%3d] : %d bytes, status 0x%02x err 0x%02x\n", + ringid, vring->swtail, dmalen, + d->dma.status, d->dma.error); + wil_hex_dump_txrx("TxCD ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); wil_txdesc_unmap(dev, d, ctx); -- cgit v1.2.1 From feeac225bed91c8da221e32a433780a5edcb14e8 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 1 Feb 2015 10:55:15 +0200 Subject: wil6210: print ciphers in debug info Print (at debug level) all cipher and AKM suites Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 37 +++++++++++++++++++---------- 1 file changed, 25 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index e758f430ed82..2d5ea21be47e 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -334,6 +334,30 @@ out: return rc; } +static void wil_print_crypto(struct wil6210_priv *wil, + struct cfg80211_crypto_settings *c) +{ + int i, n; + + wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n", + c->wpa_versions, c->cipher_group); + wil_dbg_misc(wil, "Pairwise ciphers [%d] {\n", c->n_ciphers_pairwise); + n = min_t(int, c->n_ciphers_pairwise, ARRAY_SIZE(c->ciphers_pairwise)); + for (i = 0; i < n; i++) + wil_dbg_misc(wil, " [%d] = 0x%08x\n", i, + c->ciphers_pairwise[i]); + wil_dbg_misc(wil, "}\n"); + wil_dbg_misc(wil, "AKM suites [%d] {\n", c->n_akm_suites); + n = min_t(int, c->n_akm_suites, ARRAY_SIZE(c->akm_suites)); + for (i = 0; i < n; i++) + wil_dbg_misc(wil, " [%d] = 0x%08x\n", i, + c->akm_suites[i]); + wil_dbg_misc(wil, "}\n"); + wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n", + c->control_port, be16_to_cpu(c->control_port_ethertype), + c->control_port_no_encrypt); +} + static void wil_print_connect_params(struct wil6210_priv *wil, struct cfg80211_connect_params *sme) { @@ -348,6 +372,7 @@ static void wil_print_connect_params(struct wil6210_priv *wil, print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET, 16, 1, sme->ssid, sme->ssid_len, true); wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open"); + wil_print_crypto(wil, &sme->crypto); } static int wil_cfg80211_connect(struct wiphy *wiphy, @@ -619,18 +644,6 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b) b->assocresp_ies, b->assocresp_ies_len); } -static void wil_print_crypto(struct wil6210_priv *wil, - struct cfg80211_crypto_settings *c) -{ - wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n", - c->wpa_versions, c->cipher_group); - wil_dbg_misc(wil, "Pairwise ciphers [%d]\n", c->n_ciphers_pairwise); - wil_dbg_misc(wil, "AKM suites [%d]\n", c->n_akm_suites); - wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n", - c->control_port, be16_to_cpu(c->control_port_ethertype), - c->control_port_no_encrypt); -} - static int wil_fix_bcon(struct wil6210_priv *wil, struct cfg80211_beacon_data *bcon) { -- cgit v1.2.1 From 7201472ed376882927ecc0d917acec6cc1610c80 Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Sun, 1 Feb 2015 10:55:16 +0200 Subject: wil6210: Remove msm platform related code Current implementation depends on msm-bus driver which is not merged into mainline kernel therefore this code is removed Signed-off-by: Hamad Kadmany Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/Kconfig | 9 - drivers/net/wireless/ath/wil6210/Makefile | 1 - drivers/net/wireless/ath/wil6210/wil_platform.c | 12 +- .../net/wireless/ath/wil6210/wil_platform_msm.c | 257 --------------------- .../net/wireless/ath/wil6210/wil_platform_msm.h | 24 -- 5 files changed, 1 insertion(+), 302 deletions(-) delete mode 100644 drivers/net/wireless/ath/wil6210/wil_platform_msm.c delete mode 100644 drivers/net/wireless/ath/wil6210/wil_platform_msm.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index 481680a3aa55..ce8c0381825e 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig @@ -39,12 +39,3 @@ config WIL6210_TRACING option if you are interested in debugging the driver. If unsure, say Y to make it easier to debug problems. - -config WIL6210_PLATFORM_MSM - bool "wil6210 MSM platform specific support" - depends on WIL6210 - depends on ARCH_MSM - default y - ---help--- - Say Y here to enable wil6210 driver support for MSM - platform specific features diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 8ad4b5f97e04..caa717bf52f3 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -14,7 +14,6 @@ wil6210-y += ioctl.o wil6210-y += fw.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o wil6210-y += wil_platform.o -wil6210-$(CONFIG_WIL6210_PLATFORM_MSM) += wil_platform_msm.o wil6210-y += ethtool.o # for tracing framework to find trace.h diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c index 8f1d78f8a74d..976a071ba74e 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.c +++ b/drivers/net/wireless/ath/wil6210/wil_platform.c @@ -17,10 +17,6 @@ #include "linux/device.h" #include "wil_platform.h" -#ifdef CONFIG_WIL6210_PLATFORM_MSM -#include "wil_platform_msm.h" -#endif - /** * wil_platform_init() - wil6210 platform module init * @@ -37,13 +33,7 @@ void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops) return NULL; } -#ifdef CONFIG_WIL6210_PLATFORM_MSM - handle = wil_platform_msm_init(dev, ops); - if (handle) - return handle; -#endif - - /* other platform specific init functions should be called here */ + /* platform specific init functions should be called here */ return handle; } diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c deleted file mode 100644 index b354a743240d..000000000000 --- a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2014 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include "wil_platform.h" -#include "wil_platform_msm.h" - -/** - * struct wil_platform_msm - wil6210 msm platform module info - * - * @dev: device object - * @msm_bus_handle: handle for using msm_bus API - * @pdata: bus scale info retrieved from DT - */ -struct wil_platform_msm { - struct device *dev; - uint32_t msm_bus_handle; - struct msm_bus_scale_pdata *pdata; -}; - -#define KBTOB(a) (a * 1000ULL) - -/** - * wil_platform_get_pdata() - Generate bus client data from device tree - * provided by clients. - * - * dev: device object - * of_node: Device tree node to extract information from - * - * The function returns a valid pointer to the allocated bus-scale-pdata - * if the vectors were correctly read from the client's device node. - * Any error in reading or parsing the device node will return NULL - * to the caller. - */ -static struct msm_bus_scale_pdata *wil_platform_get_pdata( - struct device *dev, - struct device_node *of_node) -{ - struct msm_bus_scale_pdata *pdata; - struct msm_bus_paths *usecase; - int i, j, ret, len; - unsigned int num_usecases, num_paths, mem_size; - const uint32_t *vec_arr; - struct msm_bus_vectors *vectors; - - /* first read num_usecases and num_paths so we can calculate - * amount of memory to allocate - */ - ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases", - &num_usecases); - if (ret) { - dev_err(dev, "Error: num-usecases not found\n"); - return NULL; - } - - ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths", - &num_paths); - if (ret) { - dev_err(dev, "Error: num_paths not found\n"); - return NULL; - } - - /* pdata memory layout: - * msm_bus_scale_pdata - * msm_bus_paths[num_usecases] - * msm_bus_vectors[num_usecases][num_paths] - */ - mem_size = sizeof(struct msm_bus_scale_pdata) + - sizeof(struct msm_bus_paths) * num_usecases + - sizeof(struct msm_bus_vectors) * num_usecases * num_paths; - - pdata = kzalloc(mem_size, GFP_KERNEL); - if (!pdata) - return NULL; - - ret = of_property_read_string(of_node, "qcom,msm-bus,name", - &pdata->name); - if (ret) { - dev_err(dev, "Error: Client name not found\n"); - goto err; - } - - if (of_property_read_bool(of_node, "qcom,msm-bus,active-only")) { - pdata->active_only = 1; - } else { - dev_info(dev, "active_only flag absent.\n"); - dev_info(dev, "Using dual context by default\n"); - } - - pdata->num_usecases = num_usecases; - pdata->usecase = (struct msm_bus_paths *)(pdata + 1); - - vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len); - if (vec_arr == NULL) { - dev_err(dev, "Error: Vector array not found\n"); - goto err; - } - - if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) { - dev_err(dev, "Error: Length-error on getting vectors\n"); - goto err; - } - - vectors = (struct msm_bus_vectors *)(pdata->usecase + num_usecases); - for (i = 0; i < num_usecases; i++) { - usecase = &pdata->usecase[i]; - usecase->num_paths = num_paths; - usecase->vectors = &vectors[i]; - - for (j = 0; j < num_paths; j++) { - int index = ((i * num_paths) + j) * 4; - - usecase->vectors[j].src = be32_to_cpu(vec_arr[index]); - usecase->vectors[j].dst = - be32_to_cpu(vec_arr[index + 1]); - usecase->vectors[j].ab = (uint64_t) - KBTOB(be32_to_cpu(vec_arr[index + 2])); - usecase->vectors[j].ib = (uint64_t) - KBTOB(be32_to_cpu(vec_arr[index + 3])); - } - } - - return pdata; - -err: - kfree(pdata); - - return NULL; -} - -/* wil_platform API (callbacks) */ - -static int wil_platform_bus_request(void *handle, - uint32_t kbps /* KBytes/Sec */) -{ - int rc, i; - struct wil_platform_msm *msm = (struct wil_platform_msm *)handle; - int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */ - struct msm_bus_paths *usecase; - uint32_t usecase_kbps; - uint32_t min_kbps = ~0; - - /* find the lowest usecase that is bigger than requested kbps */ - for (i = 0; i < msm->pdata->num_usecases; i++) { - usecase = &msm->pdata->usecase[i]; - /* assume we have single path (vectors[0]). If we ever - * have multiple paths, need to define the behavior */ - usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000); - if (usecase_kbps >= kbps && usecase_kbps < min_kbps) { - min_kbps = usecase_kbps; - vote = i; - } - } - - rc = msm_bus_scale_client_update_request(msm->msm_bus_handle, vote); - if (rc) - dev_err(msm->dev, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n", - kbps, vote, rc); - else - /* TOOD: remove */ - dev_info(msm->dev, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n", - kbps, vote); - - return rc; -} - -static void wil_platform_uninit(void *handle) -{ - struct wil_platform_msm *msm = (struct wil_platform_msm *)handle; - - dev_info(msm->dev, "wil_platform_uninit\n"); - - if (msm->msm_bus_handle) - msm_bus_scale_unregister_client(msm->msm_bus_handle); - - kfree(msm->pdata); - kfree(msm); -} - -static int wil_platform_msm_bus_register(struct wil_platform_msm *msm, - struct device_node *node) -{ - msm->pdata = wil_platform_get_pdata(msm->dev, node); - if (!msm->pdata) { - dev_err(msm->dev, "Failed getting DT info\n"); - return -EINVAL; - } - - msm->msm_bus_handle = msm_bus_scale_register_client(msm->pdata); - if (!msm->msm_bus_handle) { - dev_err(msm->dev, "Failed msm_bus registration\n"); - return -EINVAL; - } - - dev_info(msm->dev, "msm_bus registration succeeded! handle 0x%x\n", - msm->msm_bus_handle); - - return 0; -} - -/** - * wil_platform_msm_init() - wil6210 msm platform module init - * - * The function must be called before all other functions in this module. - * It returns a handle which is used with the rest of the API - * - */ -void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops) -{ - struct device_node *of_node; - struct wil_platform_msm *msm; - int rc; - - of_node = of_find_compatible_node(NULL, NULL, "qcom,wil6210"); - if (!of_node) { - /* this could mean non-msm platform */ - dev_err(dev, "DT node not found\n"); - return NULL; - } - - msm = kzalloc(sizeof(*msm), GFP_KERNEL); - if (!msm) - return NULL; - - msm->dev = dev; - - /* register with msm_bus module for scaling requests */ - rc = wil_platform_msm_bus_register(msm, of_node); - if (rc) - goto cleanup; - - memset(ops, 0, sizeof(*ops)); - ops->bus_request = wil_platform_bus_request; - ops->uninit = wil_platform_uninit; - - return (void *)msm; - -cleanup: - kfree(msm); - return NULL; -} diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h deleted file mode 100644 index 2f2229edb498..000000000000 --- a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2014 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef __WIL_PLATFORM__MSM_H__ -#define __WIL_PLATFORM_MSM_H__ - -#include "wil_platform.h" - -void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops); - -#endif /* __WIL_PLATFORM__MSM_H__ */ -- cgit v1.2.1 From 627613f8f081928efe2e82100f54c67e17bea72c Mon Sep 17 00:00:00 2001 From: SenthilKumar Jegadeesan Date: Thu, 29 Jan 2015 13:50:38 +0200 Subject: ath10k: prevent setting wrong key idx for station Ath10k driver sets wrong default key idx that results in sending unicast frames with multicast key. The reason for this behavior is that cached broadcast key is installed for station MAC address on association. After dot1x completes, unicast key is installed for station MAC address. Default key idx is set to broadcast key id when driver tries to send broadcast frame. This causes firmware to use broadcast key id to transmit unicast frames to stations. Used TX_USAGE flag to set default key for stations. Added callback for setting unicast default idx which will be invoked on every default key idx configuration. Signed-off-by: SenthilKumar Jegadeesan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 4 +- drivers/net/wireless/ath/ath10k/mac.c | 161 +++++++++++++++------------------ 2 files changed, 72 insertions(+), 93 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index abb32037c3f7..a47b41dd966f 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -285,10 +285,8 @@ struct ath10k_vif { u32 aid; u8 bssid[ETH_ALEN]; - struct work_struct wep_key_work; struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; - u8 def_wep_key_idx; - u8 def_wep_key_newidx; + s8 def_wep_key_idx; u16 tx_seq_no; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index f9440deffa26..d3fe1a378e8b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -37,7 +37,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif, struct ieee80211_key_conf *key, enum set_key_cmd cmd, - const u8 *macaddr) + const u8 *macaddr, bool def_idx) { struct ath10k *ar = arvif->ar; struct wmi_vdev_install_key_arg arg = { @@ -72,6 +72,9 @@ static int ath10k_send_key(struct ath10k_vif *arvif, * Otherwise pairwise key must be set */ if (memcmp(macaddr, arvif->vif->addr, ETH_ALEN)) arg.key_flags = WMI_KEY_PAIRWISE; + + if (def_idx) + arg.key_flags |= WMI_KEY_TX_USAGE; break; default: ath10k_warn(ar, "cipher %d is not supported\n", key->cipher); @@ -89,7 +92,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif, static int ath10k_install_key(struct ath10k_vif *arvif, struct ieee80211_key_conf *key, enum set_key_cmd cmd, - const u8 *macaddr) + const u8 *macaddr, bool def_idx) { struct ath10k *ar = arvif->ar; int ret; @@ -98,7 +101,7 @@ static int ath10k_install_key(struct ath10k_vif *arvif, reinit_completion(&ar->install_key_done); - ret = ath10k_send_key(arvif, key, cmd, macaddr); + ret = ath10k_send_key(arvif, key, cmd, macaddr, def_idx); if (ret) return ret; @@ -116,6 +119,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, struct ath10k_peer *peer; int ret; int i; + bool def_idx; lockdep_assert_held(&ar->conf_mutex); @@ -129,9 +133,14 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) { if (arvif->wep_keys[i] == NULL) continue; + /* set TX_USAGE flag for default key id */ + if (arvif->def_wep_key_idx == i) + def_idx = true; + else + def_idx = false; ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, - addr); + addr, def_idx); if (ret) return ret; @@ -165,8 +174,9 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, if (peer->keys[i] == NULL) continue; + /* key flags are not required to delete the key */ ret = ath10k_install_key(arvif, peer->keys[i], - DISABLE_KEY, addr); + DISABLE_KEY, addr, false); if (ret && first_errno == 0) first_errno = ret; @@ -240,8 +250,8 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, if (i == ARRAY_SIZE(peer->keys)) break; - - ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr); + /* key flags are not required to delete the key */ + ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, false); if (ret && first_errno == 0) first_errno = ret; @@ -1855,7 +1865,8 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, ath10k_warn(ar, "faield to down vdev %i: %d\n", arvif->vdev_id, ret); - arvif->def_wep_key_idx = 0; + arvif->def_wep_key_idx = -1; + arvif->is_up = false; } @@ -1914,11 +1925,14 @@ static int ath10k_station_assoc(struct ath10k *ar, } } - ret = ath10k_install_peer_wep_keys(arvif, sta->addr); - if (ret) { - ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", - arvif->vdev_id, ret); - return ret; + /* Plumb cached keys only for static WEP */ + if (arvif->def_wep_key_idx != -1) { + ret = ath10k_install_peer_wep_keys(arvif, sta->addr); + if (ret) { + ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } } } @@ -2190,69 +2204,6 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb) } } -static void ath10k_tx_wep_key_work(struct work_struct *work) -{ - struct ath10k_vif *arvif = container_of(work, struct ath10k_vif, - wep_key_work); - struct ath10k *ar = arvif->ar; - int ret, keyidx = arvif->def_wep_key_newidx; - - mutex_lock(&arvif->ar->conf_mutex); - - if (arvif->ar->state != ATH10K_STATE_ON) - goto unlock; - - if (arvif->def_wep_key_idx == keyidx) - goto unlock; - - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", - arvif->vdev_id, keyidx); - - ret = ath10k_wmi_vdev_set_param(arvif->ar, - arvif->vdev_id, - arvif->ar->wmi.vdev_param->def_keyid, - keyidx); - if (ret) { - ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n", - arvif->vdev_id, - ret); - goto unlock; - } - - arvif->def_wep_key_idx = keyidx; - -unlock: - mutex_unlock(&arvif->ar->conf_mutex); -} - -static void ath10k_tx_h_update_wep_key(struct ieee80211_vif *vif, - struct ieee80211_key_conf *key, - struct sk_buff *skb) -{ - struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); - struct ath10k *ar = arvif->ar; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - - if (!ieee80211_has_protected(hdr->frame_control)) - return; - - if (!key) - return; - - if (key->cipher != WLAN_CIPHER_SUITE_WEP40 && - key->cipher != WLAN_CIPHER_SUITE_WEP104) - return; - - if (key->keyidx == arvif->def_wep_key_idx) - return; - - /* FIXME: Most likely a few frames will be TXed with an old key. Simply - * queueing frames until key index is updated is not an option because - * sk_buff may need more processing to be done, e.g. offchannel */ - arvif->def_wep_key_newidx = key->keyidx; - ieee80211_queue_work(ar->hw, &arvif->wep_key_work); -} - static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct ieee80211_vif *vif, struct sk_buff *skb) @@ -2613,7 +2564,6 @@ static void ath10k_tx(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; - struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; /* We should disable CCK RATE due to P2P */ @@ -2627,7 +2577,6 @@ static void ath10k_tx(struct ieee80211_hw *hw, /* it makes no sense to process injected frames like that */ if (vif && vif->type != NL80211_IFTYPE_MONITOR) { ath10k_tx_h_nwifi(hw, skb); - ath10k_tx_h_update_wep_key(vif, key, skb); ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb); ath10k_tx_h_seq_no(vif, skb); } @@ -3132,7 +3081,6 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, arvif->ar = ar; arvif->vif = vif; - INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work); INIT_LIST_HEAD(&arvif->list); if (ar->free_vdev_map == 0) { @@ -3231,14 +3179,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err_vdev_delete; } - vdev_param = ar->wmi.vdev_param->def_keyid; - ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param, - arvif->def_wep_key_idx); - if (ret) { - ath10k_warn(ar, "failed to set vdev %i default key id: %d\n", - arvif->vdev_id, ret); - goto err_vdev_delete; - } + arvif->def_wep_key_idx = -1; vdev_param = ar->wmi.vdev_param->tx_encap_type; ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, @@ -3358,8 +3299,6 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); int ret; - cancel_work_sync(&arvif->wep_key_work); - mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); @@ -3731,6 +3670,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *peer_addr; bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 || key->cipher == WLAN_CIPHER_SUITE_WEP104; + bool def_idx = false; int ret = 0; if (key->keyidx > WMI_MAX_KEY_INDEX) @@ -3776,7 +3716,14 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ath10k_clear_vdev_key(arvif, key); } - ret = ath10k_install_key(arvif, key, cmd, peer_addr); + /* set TX_USAGE flag for all the keys incase of dot1x-WEP. For + * static WEP, do not set this flag for the keys whose key id + * is greater than default key id. + */ + if (arvif->def_wep_key_idx == -1) + def_idx = true; + + ret = ath10k_install_key(arvif, key, cmd, peer_addr, def_idx); if (ret) { ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret); @@ -3801,6 +3748,39 @@ exit: return ret; } +static void ath10k_set_default_unicast_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + int keyidx) +{ + struct ath10k *ar = hw->priv; + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + int ret; + + mutex_lock(&arvif->ar->conf_mutex); + + if (arvif->ar->state != ATH10K_STATE_ON) + goto unlock; + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", + arvif->vdev_id, keyidx); + + ret = ath10k_wmi_vdev_set_param(arvif->ar, + arvif->vdev_id, + arvif->ar->wmi.vdev_param->def_keyid, + keyidx); + + if (ret) { + ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n", + arvif->vdev_id, + ret); + goto unlock; + } + + arvif->def_wep_key_idx = keyidx; +unlock: + mutex_unlock(&arvif->ar->conf_mutex); +} + static void ath10k_sta_rc_update_wk(struct work_struct *wk) { struct ath10k *ar; @@ -4966,6 +4946,7 @@ static const struct ieee80211_ops ath10k_ops = { .hw_scan = ath10k_hw_scan, .cancel_hw_scan = ath10k_cancel_hw_scan, .set_key = ath10k_set_key, + .set_default_unicast_key = ath10k_set_default_unicast_key, .sta_state = ath10k_sta_state, .conf_tx = ath10k_conf_tx, .remain_on_channel = ath10k_remain_on_channel, -- cgit v1.2.1 From 9ad501827bd153dc2865dd60a456e3e43283b507 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 29 Jan 2015 14:29:47 +0200 Subject: ath10k: change dma beacon cmd prototype The command logic shouldn't really care about arvif structure. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 14 ++++++++++---- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 20 +++++++++++--------- drivers/net/wireless/ath/ath10k/wmi.c | 27 +++++++++++++++++---------- 3 files changed, 38 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 058f88b6ff53..de436162a805 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -104,7 +104,10 @@ struct wmi_ops { u32 value); struct sk_buff *(*gen_scan_chan_list)(struct ath10k *ar, const struct wmi_scan_chan_list_arg *arg); - struct sk_buff *(*gen_beacon_dma)(struct ath10k_vif *arvif); + struct sk_buff *(*gen_beacon_dma)(struct ath10k *ar, u32 vdev_id, + const void *bcn, size_t bcn_len, + u32 bcn_paddr, bool dtim_zero, + bool deliver_cab); struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar, const struct wmi_wmm_params_all_arg *arg); struct sk_buff *(*gen_request_stats)(struct ath10k *ar, @@ -768,16 +771,19 @@ ath10k_wmi_peer_assoc(struct ath10k *ar, } static inline int -ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) +ath10k_wmi_beacon_send_ref_nowait(struct ath10k *ar, u32 vdev_id, + const void *bcn, size_t bcn_len, + u32 bcn_paddr, bool dtim_zero, + bool deliver_cab) { - struct ath10k *ar = arvif->ar; struct sk_buff *skb; int ret; if (!ar->wmi.ops->gen_beacon_dma) return -EOPNOTSUPP; - skb = ar->wmi.ops->gen_beacon_dma(arvif); + skb = ar->wmi.ops->gen_beacon_dma(ar, vdev_id, bcn, bcn_len, bcn_paddr, + dtim_zero, deliver_cab); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index be32db96701f..ba78c187976c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2001,13 +2001,15 @@ ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar, } static struct sk_buff * -ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k_vif *arvif) +ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, + const void *bcn, size_t bcn_len, + u32 bcn_paddr, bool dtim_zero, + bool deliver_cab) + { - struct ath10k *ar = arvif->ar; struct wmi_bcn_tx_ref_cmd *cmd; struct wmi_tlv *tlv; struct sk_buff *skb; - struct sk_buff *beacon = arvif->beacon; struct ieee80211_hdr *hdr; u16 fc; @@ -2015,24 +2017,24 @@ ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k_vif *arvif) if (!skb) return ERR_PTR(-ENOMEM); - hdr = (struct ieee80211_hdr *)beacon->data; + hdr = (struct ieee80211_hdr *)bcn; fc = le16_to_cpu(hdr->frame_control); tlv = (void *)skb->data; tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD); tlv->len = __cpu_to_le16(sizeof(*cmd)); cmd = (void *)tlv->value; - cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); - cmd->data_len = __cpu_to_le32(beacon->len); - cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr); + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->data_len = __cpu_to_le32(bcn_len); + cmd->data_ptr = __cpu_to_le32(bcn_paddr); cmd->msdu_id = 0; cmd->frame_control = __cpu_to_le32(fc); cmd->flags = 0; - if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero) + if (dtim_zero) cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); - if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab) + if (deliver_cab) cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv beacon dma\n"); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 81561e4ae308..01c0230cbf9b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -956,6 +956,8 @@ err_pull: static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) { + struct sk_buff *bcn; + struct ath10k_skb_cb *cb; int ret; lockdep_assert_held(&arvif->ar->data_lock); @@ -966,7 +968,12 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) if (arvif->beacon_sent) return; - ret = ath10k_wmi_beacon_send_ref_nowait(arvif); + bcn = arvif->beacon; + cb = ATH10K_SKB_CB(bcn); + ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar, arvif->vdev_id, + bcn->data, bcn->len, cb->paddr, + cb->bcn.dtim_zero, + cb->bcn.deliver_cab); if (ret) return; @@ -4856,12 +4863,12 @@ ath10k_wmi_10_2_op_gen_pdev_get_temperature(struct ath10k *ar) /* This function assumes the beacon is already DMA mapped */ static struct sk_buff * -ath10k_wmi_op_gen_beacon_dma(struct ath10k_vif *arvif) +ath10k_wmi_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, const void *bcn, + size_t bcn_len, u32 bcn_paddr, bool dtim_zero, + bool deliver_cab) { - struct ath10k *ar = arvif->ar; struct wmi_bcn_tx_ref_cmd *cmd; struct sk_buff *skb; - struct sk_buff *beacon = arvif->beacon; struct ieee80211_hdr *hdr; u16 fc; @@ -4869,22 +4876,22 @@ ath10k_wmi_op_gen_beacon_dma(struct ath10k_vif *arvif) if (!skb) return ERR_PTR(-ENOMEM); - hdr = (struct ieee80211_hdr *)beacon->data; + hdr = (struct ieee80211_hdr *)bcn; fc = le16_to_cpu(hdr->frame_control); cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data; - cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); - cmd->data_len = __cpu_to_le32(beacon->len); - cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr); + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->data_len = __cpu_to_le32(bcn_len); + cmd->data_ptr = __cpu_to_le32(bcn_paddr); cmd->msdu_id = 0; cmd->frame_control = __cpu_to_le32(fc); cmd->flags = 0; cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA); - if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero) + if (dtim_zero) cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); - if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab) + if (deliver_cab) cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); return skb; -- cgit v1.2.1 From af21319fcda4c43aa89186e0d6001432c5d6000e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 29 Jan 2015 14:29:52 +0200 Subject: ath10k: fix beacon deadlock This should fix a very rare occurrence of the following deadlock: [] ath10k_wmi_tx_beacons_nowait+0x1e/0x50 [ath10k_core] [] ath10k_wmi_op_ep_tx_credits+0x16/0x40 [ath10k_core] [] ath10k_htc_send+0x285/0x3d0 [ath10k_core] [] ath10k_wmi_cmd_send_nowait+0x81/0x110 [ath10k_core] [] ath10k_wmi_tx_beacon_nowait.part.33+0x51/0x90 [ath10k_core] [] ath10k_wmi_tx_beacons_iter+0x30/0x40 [ath10k_core] [] __iterate_active_interfaces+0xa6/0x100 [] ? ath10k_wmi_tx_beacon_nowait.part.33+0x90/0x90 [ath10k_core] [] ieee80211_iterate_active_interfaces_atomic+0xe/0x10 [] ath10k_wmi_tx_beacons_nowait+0x36/0x50 [ath10k_core] [] ath10k_wmi_op_ep_tx_credits+0x16/0x40 [ath10k_core] [] ath10k_htc_rx+0x280/0x410 [ath10k_core] [] ? ath10k_ce_completed_recv_next+0x60/0x80 [ath10k_pci] [] ath10k_pci_ce_recv_data+0x11b/0x1d0 [ath10k_pci] [] ath10k_ce_per_engine_service+0x64/0xc0 [ath10k_pci] [] ath10k_ce_per_engine_service_any+0x22/0x50 [ath10k_pci] [] ath10k_pci_tasklet+0x30/0x90 [ath10k_pci] [] tasklet_action+0xc5/0x100 To prevent this make sure to release ar->data_lock while calling to ath10k_wmi_beacon_send_ref_nowait(). Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 8 +++- drivers/net/wireless/ath/ath10k/mac.c | 6 ++- drivers/net/wireless/ath/ath10k/wmi.c | 68 +++++++++++++++++++++++----------- 3 files changed, 58 insertions(+), 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index a47b41dd966f..c8ba6bd4b968 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -262,6 +262,12 @@ struct ath10k_sta { #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) +enum ath10k_beacon_state { + ATH10K_BEACON_SCHEDULED = 0, + ATH10K_BEACON_SENDING, + ATH10K_BEACON_SENT, +}; + struct ath10k_vif { struct list_head list; @@ -272,7 +278,7 @@ struct ath10k_vif { u32 dtim_period; struct sk_buff *beacon; /* protected by data_lock */ - bool beacon_sent; + enum ath10k_beacon_state beacon_state; void *beacon_buf; dma_addr_t beacon_paddr; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index d3fe1a378e8b..d0d882d632d1 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -531,10 +531,14 @@ void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif) dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr, arvif->beacon->len, DMA_TO_DEVICE); + if (WARN_ON(arvif->beacon_state != ATH10K_BEACON_SCHEDULED && + arvif->beacon_state != ATH10K_BEACON_SENT)) + return; + dev_kfree_skb_any(arvif->beacon); arvif->beacon = NULL; - arvif->beacon_sent = false; + arvif->beacon_state = ATH10K_BEACON_SCHEDULED; } static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 01c0230cbf9b..d6c5b423b836 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -956,30 +956,45 @@ err_pull: static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) { - struct sk_buff *bcn; + struct ath10k *ar = arvif->ar; struct ath10k_skb_cb *cb; + struct sk_buff *bcn; int ret; - lockdep_assert_held(&arvif->ar->data_lock); + spin_lock_bh(&ar->data_lock); - if (arvif->beacon == NULL) - return; + bcn = arvif->beacon; - if (arvif->beacon_sent) - return; + if (!bcn) + goto unlock; - bcn = arvif->beacon; cb = ATH10K_SKB_CB(bcn); - ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar, arvif->vdev_id, - bcn->data, bcn->len, cb->paddr, - cb->bcn.dtim_zero, - cb->bcn.deliver_cab); - if (ret) - return; - /* We need to retain the arvif->beacon reference for DMA unmapping and - * freeing the skbuff later. */ - arvif->beacon_sent = true; + switch (arvif->beacon_state) { + case ATH10K_BEACON_SENDING: + case ATH10K_BEACON_SENT: + break; + case ATH10K_BEACON_SCHEDULED: + arvif->beacon_state = ATH10K_BEACON_SENDING; + spin_unlock_bh(&ar->data_lock); + + ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar, + arvif->vdev_id, + bcn->data, bcn->len, + cb->paddr, + cb->bcn.dtim_zero, + cb->bcn.deliver_cab); + + spin_lock_bh(&ar->data_lock); + + if (ret == 0) + arvif->beacon_state = ATH10K_BEACON_SENT; + else + arvif->beacon_state = ATH10K_BEACON_SCHEDULED; + } + +unlock: + spin_unlock_bh(&ar->data_lock); } static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, @@ -992,12 +1007,10 @@ static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar) { - spin_lock_bh(&ar->data_lock); ieee80211_iterate_active_interfaces_atomic(ar->hw, IEEE80211_IFACE_ITER_NORMAL, ath10k_wmi_tx_beacons_iter, NULL); - spin_unlock_bh(&ar->data_lock); } static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar) @@ -2459,9 +2472,19 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) spin_lock_bh(&ar->data_lock); if (arvif->beacon) { - if (!arvif->beacon_sent) - ath10k_warn(ar, "SWBA overrun on vdev %d\n", + switch (arvif->beacon_state) { + case ATH10K_BEACON_SENT: + break; + case ATH10K_BEACON_SCHEDULED: + ath10k_warn(ar, "SWBA overrun on vdev %d, skipped old beacon\n", + arvif->vdev_id); + break; + case ATH10K_BEACON_SENDING: + ath10k_warn(ar, "SWBA overrun on vdev %d, skipped new beacon\n", arvif->vdev_id); + dev_kfree_skb(bcn); + goto skip; + } ath10k_mac_vif_beacon_free(arvif); } @@ -2489,15 +2512,16 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) } arvif->beacon = bcn; - arvif->beacon_sent = false; + arvif->beacon_state = ATH10K_BEACON_SCHEDULED; trace_ath10k_tx_hdr(ar, bcn->data, bcn->len); trace_ath10k_tx_payload(ar, bcn->data, bcn->len); - ath10k_wmi_tx_beacon_nowait(arvif); skip: spin_unlock_bh(&ar->data_lock); } + + ath10k_wmi_tx_beacons_nowait(ar); } void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb) -- cgit v1.2.1 From 75930d1a80e81052376ffc5298aadfe8a075d9d2 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 28 Jan 2015 11:31:32 +0100 Subject: ath10k: Use TX cksum offload only for CHECKSUM_PARTIAL Otherwise ath10k will just checksum everything even if it did not go through the TCP/IP stack (for example bridged frames). In the worst case this could mean recreating the checksum for incorrect data. Signed-off-by: Helmut Schaa Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_tx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index c1961e77d58d..cbd2bc9e6202 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -515,8 +515,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); - flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; - flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; + if (msdu->ip_summed == CHECKSUM_PARTIAL) { + flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; + flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; + } /* Prevent firmware from sending up tx inspection requests. There's * nothing ath10k can do with frames requested for inspection so force -- cgit v1.2.1 From 467210a67b8e4e63dc7fb0bc9aca21e412f32da5 Mon Sep 17 00:00:00 2001 From: SenthilKumar Jegadeesan Date: Thu, 29 Jan 2015 14:36:52 +0530 Subject: ath10k: add log level configuration for fw_dbglog Introduce an optional log level configuration for the existing debugfs fw_dbglog file. It allows users to configure the desired log level for firmware dbglog messages. To configure log level as WARN: echo 0xffffffff 2 > /sys/kernel/debug/ieee80211/phy0/ath10k/fw_dbglog The values are: VERBOSE 0 INFO 1 WARN 2 ERR 3 Signed-off-by: SenthilKumar Jegadeesan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/debug.c | 32 ++++++++++++++++++++++--------- drivers/net/wireless/ath/ath10k/wmi-ops.h | 7 ++++--- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 4 ++-- drivers/net/wireless/ath/ath10k/wmi.c | 5 +++-- 5 files changed, 33 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index c8ba6bd4b968..d60e46fe6d19 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -350,6 +350,7 @@ struct ath10k_debug { /* protected by conf_mutex */ u32 fw_dbglog_mask; + u32 fw_dbglog_level; u32 pktlog_filter; u32 reg_addr; u32 nf_cal_period; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 42b2e49b2836..d2281e5c2ffe 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1318,10 +1318,10 @@ static ssize_t ath10k_read_fw_dbglog(struct file *file, { struct ath10k *ar = file->private_data; unsigned int len; - char buf[32]; + char buf[64]; - len = scnprintf(buf, sizeof(buf), "0x%08x\n", - ar->debug.fw_dbglog_mask); + len = scnprintf(buf, sizeof(buf), "0x%08x %u\n", + ar->debug.fw_dbglog_mask, ar->debug.fw_dbglog_level); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -1331,19 +1331,32 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; - unsigned long mask; int ret; + char buf[64]; + unsigned int log_level, mask; - ret = kstrtoul_from_user(user_buf, count, 0, &mask); - if (ret) - return ret; + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = 0; + + ret = sscanf(buf, "%x %u", &mask, &log_level); + + if (!ret) + return -EINVAL; + + if (ret == 1) + /* default if user did not specify */ + log_level = ATH10K_DBGLOG_LEVEL_WARN; mutex_lock(&ar->conf_mutex); ar->debug.fw_dbglog_mask = mask; + ar->debug.fw_dbglog_level = log_level; if (ar->state == ATH10K_STATE_ON) { - ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); + ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask, + ar->debug.fw_dbglog_level); if (ret) { ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n", ret); @@ -1685,7 +1698,8 @@ int ath10k_debug_start(struct ath10k *ar) ret); if (ar->debug.fw_dbglog_mask) { - ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); + ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask, + ATH10K_DBGLOG_LEVEL_WARN); if (ret) /* not serious */ ath10k_warn(ar, "failed to enable dbglog during start: %d", diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index de436162a805..04dc4b9db04e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -116,7 +116,8 @@ struct wmi_ops { enum wmi_force_fw_hang_type type, u32 delay_ms); struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb); - struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u32 module_enable); + struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u32 module_enable, + u32 log_level); struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter); struct sk_buff *(*gen_pktlog_disable)(struct ath10k *ar); struct sk_buff *(*gen_pdev_set_quiet_mode)(struct ath10k *ar, @@ -846,14 +847,14 @@ ath10k_wmi_force_fw_hang(struct ath10k *ar, } static inline int -ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) +ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable, u32 log_level) { struct sk_buff *skb; if (!ar->wmi.ops->gen_dbglog_cfg) return -EOPNOTSUPP; - skb = ar->wmi.ops->gen_dbglog_cfg(ar, module_enable); + skb = ar->wmi.ops->gen_dbglog_cfg(ar, module_enable, log_level); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index ba78c187976c..71614ba1b145 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2126,8 +2126,8 @@ ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar, } static struct sk_buff * -ath10k_wmi_tlv_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable) -{ +ath10k_wmi_tlv_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable, + u32 log_level) { struct wmi_tlv_dbglog_cmd *cmd; struct wmi_tlv *tlv; struct sk_buff *skb; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index d6c5b423b836..fd213d9e4214 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4991,7 +4991,8 @@ ath10k_wmi_op_gen_force_fw_hang(struct ath10k *ar, } static struct sk_buff * -ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable) +ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable, + u32 log_level) { struct wmi_dbglog_cfg_cmd *cmd; struct sk_buff *skb; @@ -5004,7 +5005,7 @@ ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable) cmd = (struct wmi_dbglog_cfg_cmd *)skb->data; if (module_enable) { - cfg = SM(ATH10K_DBGLOG_LEVEL_VERBOSE, + cfg = SM(log_level, ATH10K_DBGLOG_CFG_LOG_LVL); } else { /* set back defaults, all modules with WARN level */ -- cgit v1.2.1 From 608b8f736bf520649ced45b0fdabf847be8e5e55 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 29 Jan 2015 13:24:33 +0100 Subject: ath10k: enable qca6174 hw3.2 The 3.2 revision has a different target BMI version so it wasn't recognized by ath10k (despite the chip_id rev being on the supported list already). Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 15 +++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 1 + 2 files changed, 16 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 5e9e1a6958f4..310e12bc078a 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -85,6 +85,21 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, }, }, + { + .id = QCA6174_HW_3_2_VERSION, + .name = "qca6174 hw3.2", + .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, + .uart_pin = 6, + .fw = { + /* uses same binaries as hw3.0 */ + .dir = QCA6174_HW_3_0_FW_DIR, + .fw = QCA6174_HW_3_0_FW_FILE, + .otp = QCA6174_HW_3_0_OTP_FILE, + .board = QCA6174_HW_3_0_BOARD_DATA_FILE, + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, + }, }; static void ath10k_send_suspend_complete(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 577127844ec8..460771fcfe9e 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -40,6 +40,7 @@ #define QCA6174_HW_1_3_VERSION 0x05000003 #define QCA6174_HW_2_1_VERSION 0x05010000 #define QCA6174_HW_3_0_VERSION 0x05020000 +#define QCA6174_HW_3_2_VERSION 0x05030000 enum qca6174_pci_rev { QCA6174_PCI_REV_1_1 = 0x11, -- cgit v1.2.1 From 8a00785edd166361e08c6cf710bf3acdd6038005 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 1 Feb 2015 03:34:34 -0500 Subject: can: janz-ican3: fix type mismatch in assignment return type of wait_for_completion_timeout is unsigned long not int, this patch removes the type mismatch by moving the call into the condition. Signed-off-by: Nicholas Mc Guire Signed-off-by: Marc Kleine-Budde --- drivers/net/can/janz-ican3.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 0eb4d181ae4d..4dd183a3643a 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -1679,8 +1679,7 @@ static int ican3_get_berr_counter(const struct net_device *ndev, if (ret) return ret; - ret = wait_for_completion_timeout(&mod->buserror_comp, HZ); - if (ret == 0) { + if (!wait_for_completion_timeout(&mod->buserror_comp, HZ)) { netdev_info(mod->ndev, "%s timed out\n", __func__); return -ETIMEDOUT; } @@ -1705,8 +1704,7 @@ static ssize_t ican3_sysfs_show_term(struct device *dev, if (ret) return ret; - ret = wait_for_completion_timeout(&mod->termination_comp, HZ); - if (ret == 0) { + if (!wait_for_completion_timeout(&mod->termination_comp, HZ)) { netdev_info(mod->ndev, "%s timed out\n", __func__); return -ETIMEDOUT; } -- cgit v1.2.1 From a9ca6e13d66042b3ac18d1352b88b7cd0da8fc21 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Mon, 2 Feb 2015 15:15:55 -0500 Subject: can: kvaser_usb: Ignore spurious error events after a busoff Sending data in high speed then introducing a busoff results in spurious BUS_ERROR events from the USBCan-II firmware directly _after_ the triggered BUS_OFF event. In the current CAN state handling code, this will lead to an invalid can state of ACTIVE, ERROR, or PASSIVE even though the CAN controller has been already shut down due to the busoff. Guard the state handling code from such invalid events. Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/kvaser_usb.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 17d28d7dd412..2928f7003041 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -11,7 +11,7 @@ * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs , esd gmbh * Copyright (C) 2012 Olivier Sobrie - * Copyright (C) 2015 Valeo A.S. + * Copyright (C) 2015 Valeo S.A. */ #include @@ -824,14 +824,15 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri else if (es->status & M16C_STATE_BUS_PASSIVE) new_state = CAN_STATE_ERROR_PASSIVE; else if (es->status & M16C_STATE_BUS_ERROR) { - if ((es->txerr >= 256) || (es->rxerr >= 256)) - new_state = CAN_STATE_BUS_OFF; - else if ((es->txerr >= 128) || (es->rxerr >= 128)) - new_state = CAN_STATE_ERROR_PASSIVE; - else if ((es->txerr >= 96) || (es->rxerr >= 96)) - new_state = CAN_STATE_ERROR_WARNING; - else if (cur_state > CAN_STATE_ERROR_ACTIVE) - new_state = CAN_STATE_ERROR_ACTIVE; + /* Guard against spurious error events after a busoff */ + if (cur_state < CAN_STATE_BUS_OFF) { + if ((es->txerr >= 128) || (es->rxerr >= 128)) + new_state = CAN_STATE_ERROR_PASSIVE; + else if ((es->txerr >= 96) || (es->rxerr >= 96)) + new_state = CAN_STATE_ERROR_WARNING; + else if (cur_state > CAN_STATE_ERROR_ACTIVE) + new_state = CAN_STATE_ERROR_ACTIVE; + } } if (!es->status) -- cgit v1.2.1 From 4fc9b87bae25e843989d022bed66dd009bdc5a71 Mon Sep 17 00:00:00 2001 From: LEROY Christophe Date: Mon, 2 Feb 2015 18:06:54 +0100 Subject: net: fs_enet: Implement NETIF_F_SG feature Freescale ethernet controllers have the capability to re-assemble fragmented data into a single ethernet frame. This patch uses this capability and implements NETIP_F_SG feature into the fs_enet ethernet driver. On a MPC885, I get 53% performance improvement on a ftp transfer of a 15Mb file: * Without the patch : 2,8 Mbps * With the patch : 4,3 Mbps Signed-off-by: Christophe Leroy Signed-off-by: David S. Miller --- .../net/ethernet/freescale/fs_enet/fs_enet-main.c | 95 +++++++++++++++------- drivers/net/ethernet/freescale/fs_enet/fs_enet.h | 1 + 2 files changed, 66 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c index 9e2bcb807923..a17628769a1f 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c @@ -278,14 +278,20 @@ static int fs_enet_tx_napi(struct napi_struct *napi, int budget) fep->stats.collisions++; /* unmap */ - dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), - skb->len, DMA_TO_DEVICE); + if (fep->mapped_as_page[dirtyidx]) + dma_unmap_page(fep->dev, CBDR_BUFADDR(bdp), + CBDR_DATLEN(bdp), DMA_TO_DEVICE); + else + dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), + CBDR_DATLEN(bdp), DMA_TO_DEVICE); /* * Free the sk buffer associated with this last transmit. */ - dev_kfree_skb(skb); - fep->tx_skbuff[dirtyidx] = NULL; + if (skb) { + dev_kfree_skb(skb); + fep->tx_skbuff[dirtyidx] = NULL; + } /* * Update pointer to next buffer descriptor to be transmitted. @@ -299,7 +305,7 @@ static int fs_enet_tx_napi(struct napi_struct *napi, int budget) * Since we have freed up a buffer, the ring is no longer * full. */ - if (!fep->tx_free++) + if (++fep->tx_free >= MAX_SKB_FRAGS) do_wake = 1; has_tx_work = 1; } @@ -509,6 +515,9 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) cbd_t __iomem *bdp; int curidx; u16 sc; + int nr_frags = skb_shinfo(skb)->nr_frags; + skb_frag_t *frag; + int len; #ifdef CONFIG_FS_ENET_MPC5121_FEC if (((unsigned long)skb->data) & 0x3) { @@ -530,7 +539,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) */ bdp = fep->cur_tx; - if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { + if (fep->tx_free <= nr_frags || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { netif_stop_queue(dev); spin_unlock(&fep->tx_lock); @@ -543,35 +552,42 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) } curidx = bdp - fep->tx_bd_base; - /* - * Clear all of the status flags. - */ - CBDC_SC(bdp, BD_ENET_TX_STATS); - - /* - * Save skb pointer. - */ - fep->tx_skbuff[curidx] = skb; - - fep->stats.tx_bytes += skb->len; + len = skb->len; + fep->stats.tx_bytes += len; + if (nr_frags) + len -= skb->data_len; + fep->tx_free -= nr_frags + 1; /* * Push the data cache so the CPM does not get stale memory data. */ CBDW_BUFADDR(bdp, dma_map_single(fep->dev, - skb->data, skb->len, DMA_TO_DEVICE)); - CBDW_DATLEN(bdp, skb->len); + skb->data, len, DMA_TO_DEVICE)); + CBDW_DATLEN(bdp, len); + + fep->mapped_as_page[curidx] = 0; + frag = skb_shinfo(skb)->frags; + while (nr_frags) { + CBDC_SC(bdp, + BD_ENET_TX_STATS | BD_ENET_TX_LAST | BD_ENET_TX_TC); + CBDS_SC(bdp, BD_ENET_TX_READY); + + if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) + bdp++, curidx++; + else + bdp = fep->tx_bd_base, curidx = 0; - /* - * If this was the last BD in the ring, start at the beginning again. - */ - if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) - fep->cur_tx++; - else - fep->cur_tx = fep->tx_bd_base; + len = skb_frag_size(frag); + CBDW_BUFADDR(bdp, skb_frag_dma_map(fep->dev, frag, 0, len, + DMA_TO_DEVICE)); + CBDW_DATLEN(bdp, len); - if (!--fep->tx_free) - netif_stop_queue(dev); + fep->tx_skbuff[curidx] = NULL; + fep->mapped_as_page[curidx] = 1; + + frag++; + nr_frags--; + } /* Trigger transmission start */ sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | @@ -582,8 +598,22 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) * yay for hw reuse :) */ if (skb->len <= 60) sc |= BD_ENET_TX_PAD; + CBDC_SC(bdp, BD_ENET_TX_STATS); CBDS_SC(bdp, sc); + /* Save skb pointer. */ + fep->tx_skbuff[curidx] = skb; + + /* If this was the last BD in the ring, start at the beginning again. */ + if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) + bdp++; + else + bdp = fep->tx_bd_base; + fep->cur_tx = bdp; + + if (fep->tx_free < MAX_SKB_FRAGS) + netif_stop_queue(dev); + skb_tx_timestamp(skb); (*fep->ops->tx_kickstart)(dev); @@ -917,7 +947,7 @@ static int fs_enet_probe(struct platform_device *ofdev) } fpi->rx_ring = 32; - fpi->tx_ring = 32; + fpi->tx_ring = 64; fpi->rx_copybreak = 240; fpi->napi_weight = 17; fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0); @@ -955,7 +985,8 @@ static int fs_enet_probe(struct platform_device *ofdev) privsize = sizeof(*fep) + sizeof(struct sk_buff **) * - (fpi->rx_ring + fpi->tx_ring); + (fpi->rx_ring + fpi->tx_ring) + + sizeof(char) * fpi->tx_ring; ndev = alloc_etherdev(privsize); if (!ndev) { @@ -978,6 +1009,8 @@ static int fs_enet_probe(struct platform_device *ofdev) fep->rx_skbuff = (struct sk_buff **)&fep[1]; fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; + fep->mapped_as_page = (char *)(fep->rx_skbuff + fpi->rx_ring + + fpi->tx_ring); spin_lock_init(&fep->lock); spin_lock_init(&fep->tx_lock); @@ -1007,6 +1040,8 @@ static int fs_enet_probe(struct platform_device *ofdev) netif_carrier_off(ndev); + ndev->features |= NETIF_F_SG; + ret = register_netdev(ndev); if (ret) goto out_free_bd; diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet.h b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h index 3a4b49e0e717..f184d8f952e2 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet.h +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h @@ -134,6 +134,7 @@ struct fs_enet_private { void __iomem *ring_base; struct sk_buff **rx_skbuff; struct sk_buff **tx_skbuff; + char *mapped_as_page; cbd_t __iomem *rx_bd_base; /* Address of Rx and Tx buffers. */ cbd_t __iomem *tx_bd_base; cbd_t __iomem *dirty_tx; /* ring entries to be free()ed. */ -- cgit v1.2.1 From dcdc8994697faa789669c3fdaca1a8bc27a8f356 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Mon, 2 Feb 2015 16:07:34 -0800 Subject: net: add skb functions to process remote checksum offload This patch adds skb_remcsum_process and skb_gro_remcsum_process to perform the appropriate adjustments to the skb when receiving remote checksum offload. Updated vxlan and gue to use these functions. Tested: Ran TCP_RR and TCP_STREAM netperf for VXLAN and GUE, did not see any change in performance. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 31bac2a21ce3..c184717e8b28 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -558,7 +558,6 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, u32 data) { size_t start, offset, plen; - __wsum delta; if (skb->remcsum_offload) return vh; @@ -580,12 +579,7 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, return NULL; } - delta = remcsum_adjust((void *)vh + hdrlen, - NAPI_GRO_CB(skb)->csum, start, offset); - - /* Adjust skb->csum since we changed the packet */ - skb->csum = csum_add(skb->csum, delta); - NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta); + skb_gro_remcsum_process(skb, (void *)vh + hdrlen, start, offset); skb->remcsum_offload = 1; @@ -1159,7 +1153,6 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, size_t hdrlen, u32 data) { size_t start, offset, plen; - __wsum delta; if (skb->remcsum_offload) { /* Already processed in GRO path */ @@ -1179,14 +1172,7 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, vh = (struct vxlanhdr *)(udp_hdr(skb) + 1); - if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE)) - __skb_checksum_complete(skb); - - delta = remcsum_adjust((void *)vh + hdrlen, - skb->csum, start, offset); - - /* Adjust skb->csum since we changed the packet */ - skb->csum = csum_add(skb->csum, delta); + skb_remcsum_process(skb, (void *)vh + hdrlen, start, offset); return vh; } -- cgit v1.2.1 From 51fd9471492adecaebae199a6b18ff929062620a Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Tue, 3 Feb 2015 03:44:45 -0500 Subject: tlan: use msecs_to_jiffies for conversion This is only an API consolidation and should make things more readable it replaces var * HZ / 1000 by msecs_to_jiffies(var). Signed-off-by: Nicholas Mc Guire Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index f2ff0074aac9..1f722c99afb9 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -2540,7 +2540,7 @@ static void tlan_phy_power_down(struct net_device *dev) * This is abitrary. It is intended to make sure the * transceiver settles. */ - tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_PUP); + tlan_set_timer(dev, msecs_to_jiffies(50), TLAN_TIMER_PHY_PUP); } @@ -2593,7 +2593,7 @@ static void tlan_phy_reset(struct net_device *dev) * I don't remember why I wait this long. * I've changed this to 50ms, as it seems long enough. */ - tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_START_LINK); + tlan_set_timer(dev, msecs_to_jiffies(50), TLAN_TIMER_PHY_START_LINK); } @@ -2658,7 +2658,7 @@ static void tlan_phy_start_link(struct net_device *dev) data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, data); - tlan_set_timer(dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN); + tlan_set_timer(dev, msecs_to_jiffies(40), TLAN_TIMER_PHY_PDOWN); return; } else if (priv->phy_num == 0) { control = 0; @@ -2725,7 +2725,7 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) && (priv->phy_num != 0)) { priv->phy_num = 0; - tlan_set_timer(dev, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN); + tlan_set_timer(dev, msecs_to_jiffies(400), TLAN_TIMER_PHY_PDOWN); return; } @@ -2744,7 +2744,7 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) /* Wait for 100 ms. No reason in partiticular. */ - tlan_set_timer(dev, (HZ/10), TLAN_TIMER_FINISH_RESET); + tlan_set_timer(dev, msecs_to_jiffies(100), TLAN_TIMER_FINISH_RESET); } @@ -2796,7 +2796,7 @@ static void tlan_phy_monitor(unsigned long data) /* set to external PHY */ priv->phy_num = 1; /* restart autonegotiation */ - tlan_set_timer(dev, 4 * HZ / 10, + tlan_set_timer(dev, msecs_to_jiffies(400), TLAN_TIMER_PHY_PDOWN); return; } -- cgit v1.2.1 From b5057dd79c2db9a2be5306fdcdb2eae5c9c0e109 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Tue, 3 Feb 2015 03:45:11 -0500 Subject: tlan: msecs_to_jiffies convrsion This is only an API consolidation and should make things more readable it replaces var * HZ / 1000 by msecs_to_jiffies(var). As there is a discrepancy between the code and the comments this is in a separate patch. Signed-off-by: Nicholas Mc Guire Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 1f722c99afb9..691ec936e88d 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -2561,7 +2561,7 @@ static void tlan_phy_power_up(struct net_device *dev) * transceiver. The TLAN docs say both 50 ms and * 500 ms, so do the longer, just in case. */ - tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_RESET); + tlan_set_timer(dev, msecs_to_jiffies(500), TLAN_TIMER_PHY_RESET); } -- cgit v1.2.1 From 69a2338e05995b10225b2a131f7540d1305980e4 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Tue, 3 Feb 2015 16:48:30 +0200 Subject: net/bonding: Move slave state changes to a helper function Move slave state changes to a helper function, this is a pre-step for adding functionality of dispatching an event when this helper is called. This commit doesn't add new functionality. Signed-off-by: Moni Shoua Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 64 ++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index c9e519cb9214..92fe3a1bf52b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -790,7 +790,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) } new_active->delay = 0; - new_active->link = BOND_LINK_UP; + bond_set_slave_link_state(new_active, BOND_LINK_UP); if (BOND_MODE(bond) == BOND_MODE_8023AD) bond_3ad_handle_link_change(new_active, BOND_LINK_UP); @@ -1181,6 +1181,21 @@ static void bond_free_slave(struct slave *slave) kfree(slave); } +static void bond_fill_ifbond(struct bonding *bond, struct ifbond *info) +{ + info->bond_mode = BOND_MODE(bond); + info->miimon = bond->params.miimon; + info->num_slaves = bond->slave_cnt; +} + +static void bond_fill_ifslave(struct slave *slave, struct ifslave *info) +{ + strcpy(info->slave_name, slave->dev->name); + info->link = slave->link; + info->state = bond_slave_state(slave); + info->link_failure_count = slave->link_failure_count; +} + /* enslave device to bond device */ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { @@ -1444,19 +1459,22 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (bond->params.miimon) { if (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS) { if (bond->params.updelay) { - new_slave->link = BOND_LINK_BACK; + bond_set_slave_link_state(new_slave, + BOND_LINK_BACK); new_slave->delay = bond->params.updelay; } else { - new_slave->link = BOND_LINK_UP; + bond_set_slave_link_state(new_slave, + BOND_LINK_UP); } } else { - new_slave->link = BOND_LINK_DOWN; + bond_set_slave_link_state(new_slave, BOND_LINK_DOWN); } } else if (bond->params.arp_interval) { - new_slave->link = (netif_carrier_ok(slave_dev) ? - BOND_LINK_UP : BOND_LINK_DOWN); + bond_set_slave_link_state(new_slave, + (netif_carrier_ok(slave_dev) ? + BOND_LINK_UP : BOND_LINK_DOWN)); } else { - new_slave->link = BOND_LINK_UP; + bond_set_slave_link_state(new_slave, BOND_LINK_UP); } if (new_slave->link != BOND_LINK_DOWN) @@ -1821,11 +1839,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev, static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) { struct bonding *bond = netdev_priv(bond_dev); - - info->bond_mode = BOND_MODE(bond); - info->miimon = bond->params.miimon; - info->num_slaves = bond->slave_cnt; - + bond_fill_ifbond(bond, info); return 0; } @@ -1839,10 +1853,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in bond_for_each_slave(bond, slave, iter) { if (i++ == (int)info->slave_id) { res = 0; - strcpy(info->slave_name, slave->dev->name); - info->link = slave->link; - info->state = bond_slave_state(slave); - info->link_failure_count = slave->link_failure_count; + bond_fill_ifslave(slave, info); break; } } @@ -1872,7 +1883,7 @@ static int bond_miimon_inspect(struct bonding *bond) if (link_state) continue; - slave->link = BOND_LINK_FAIL; + bond_set_slave_link_state(slave, BOND_LINK_FAIL); slave->delay = bond->params.downdelay; if (slave->delay) { netdev_info(bond->dev, "link status down for %sinterface %s, disabling it in %d ms\n", @@ -1887,7 +1898,7 @@ static int bond_miimon_inspect(struct bonding *bond) case BOND_LINK_FAIL: if (link_state) { /* recovered before downdelay expired */ - slave->link = BOND_LINK_UP; + bond_set_slave_link_state(slave, BOND_LINK_UP); slave->last_link_up = jiffies; netdev_info(bond->dev, "link status up again after %d ms for interface %s\n", (bond->params.downdelay - slave->delay) * @@ -1909,7 +1920,7 @@ static int bond_miimon_inspect(struct bonding *bond) if (!link_state) continue; - slave->link = BOND_LINK_BACK; + bond_set_slave_link_state(slave, BOND_LINK_BACK); slave->delay = bond->params.updelay; if (slave->delay) { @@ -1922,7 +1933,8 @@ static int bond_miimon_inspect(struct bonding *bond) /*FALLTHRU*/ case BOND_LINK_BACK: if (!link_state) { - slave->link = BOND_LINK_DOWN; + bond_set_slave_link_state(slave, + BOND_LINK_DOWN); netdev_info(bond->dev, "link status down again after %d ms for interface %s\n", (bond->params.updelay - slave->delay) * bond->params.miimon, @@ -1960,7 +1972,7 @@ static void bond_miimon_commit(struct bonding *bond) continue; case BOND_LINK_UP: - slave->link = BOND_LINK_UP; + bond_set_slave_link_state(slave, BOND_LINK_UP); slave->last_link_up = jiffies; primary = rtnl_dereference(bond->primary_slave); @@ -2000,7 +2012,7 @@ static void bond_miimon_commit(struct bonding *bond) if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; - slave->link = BOND_LINK_DOWN; + bond_set_slave_link_state(slave, BOND_LINK_DOWN); if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP || BOND_MODE(bond) == BOND_MODE_8023AD) @@ -2583,7 +2595,7 @@ static void bond_ab_arp_commit(struct bonding *bond) struct slave *current_arp_slave; current_arp_slave = rtnl_dereference(bond->current_arp_slave); - slave->link = BOND_LINK_UP; + bond_set_slave_link_state(slave, BOND_LINK_UP); if (current_arp_slave) { bond_set_slave_inactive_flags( current_arp_slave, @@ -2606,7 +2618,7 @@ static void bond_ab_arp_commit(struct bonding *bond) if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; - slave->link = BOND_LINK_DOWN; + bond_set_slave_link_state(slave, BOND_LINK_DOWN); bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); @@ -2685,7 +2697,7 @@ static bool bond_ab_arp_probe(struct bonding *bond) * up when it is actually down */ if (!bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) { - slave->link = BOND_LINK_DOWN; + bond_set_slave_link_state(slave, BOND_LINK_DOWN); if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; @@ -2705,7 +2717,7 @@ static bool bond_ab_arp_probe(struct bonding *bond) if (!new_slave) goto check_state; - new_slave->link = BOND_LINK_BACK; + bond_set_slave_link_state(new_slave, BOND_LINK_BACK); bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER); bond_arp_send_all(bond, new_slave); new_slave->last_link_up = jiffies; -- cgit v1.2.1 From 69e6113343cfe983511904ffca0d7a1466460b67 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Tue, 3 Feb 2015 16:48:31 +0200 Subject: net/bonding: Notify state change on slaves Use notifier chain to dispatch an event upon a change in slave state. Event is dispatched with slave specific info. Signed-off-by: Moni Shoua Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 92fe3a1bf52b..679ef00d6b16 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1196,6 +1196,47 @@ static void bond_fill_ifslave(struct slave *slave, struct ifslave *info) info->link_failure_count = slave->link_failure_count; } +static void bond_netdev_notify(struct slave *slave, struct net_device *dev) +{ + struct bonding *bond = slave->bond; + struct netdev_bonding_info bonding_info; + + rtnl_lock(); + /* make sure that slave is still valid */ + if (dev->priv_flags & IFF_BONDING) { + bond_fill_ifslave(slave, &bonding_info.slave); + bond_fill_ifbond(bond, &bonding_info.master); + netdev_bonding_info_change(slave->dev, &bonding_info); + } + rtnl_unlock(); +} + +static void bond_netdev_notify_work(struct work_struct *_work) +{ + struct netdev_notify_work *w = + container_of(_work, struct netdev_notify_work, work.work); + + bond_netdev_notify(w->slave, w->dev); + dev_put(w->dev); +} + +void bond_queue_slave_event(struct slave *slave) +{ + struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC); + + if (!nnw) + return; + + INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work); + nnw->slave = slave; + nnw->dev = slave->dev; + + if (queue_delayed_work(slave->bond->wq, &nnw->work, 0)) + dev_hold(slave->dev); + else + kfree(nnw); +} + /* enslave device to bond device */ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { @@ -1590,6 +1631,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) new_slave->link != BOND_LINK_DOWN ? "an up" : "a down"); /* enslave is successful */ + bond_queue_slave_event(new_slave); return 0; /* Undo stages on error */ -- cgit v1.2.1 From 59e14e325066be49b49b6c2503337c69a9ee29fc Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Tue, 3 Feb 2015 16:48:32 +0200 Subject: net/mlx4_core: Port aggregation low level interface Implement the hardware interface required for port aggregation. 1. Disable RX port check on receive - don't perform a validity check that matches to QP's port and the port where the packet is received. 2. Virtual to physical port remap - configure virtual to physical port mapping. Port remap capability for virtual functions. Signed-off-by: Moni Shoua Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 9 +++++ drivers/net/ethernet/mellanox/mlx4/fw.c | 56 +++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 154effbfd8be..a681d7c0bb9f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1583,6 +1583,15 @@ static struct mlx4_cmd_info cmd_info[] = { .verify = NULL, .wrapper = mlx4_CMD_EPERM_wrapper }, + { + .opcode = MLX4_CMD_VIRT_PORT_MAP, + .has_inbox = false, + .has_outbox = false, + .out_is_imm = false, + .encode_slave_id = false, + .verify = NULL, + .wrapper = mlx4_CMD_EPERM_wrapper + }, }; static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index dbabfae3a3de..4b08a393ebcb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -142,7 +142,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) [17] = "Asymmetric EQs support", [18] = "More than 80 VFs support", [19] = "Performance optimized for limited rule configuration flow steering support", - [20] = "Recoverable error events support" + [20] = "Recoverable error events support", + [21] = "Port Remap support" }; int i; @@ -863,6 +864,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_EQE_STRIDE; MLX4_GET(dev_cap->bmme_flags, outbox, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); + if (dev_cap->bmme_flags & MLX4_FLAG_PORT_REMAP) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PORT_REMAP; MLX4_GET(field, outbox, QUERY_DEV_CAP_CONFIG_DEV_OFFSET); if (field & 0x20) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CONFIG_DEV; @@ -1120,9 +1123,10 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, field &= 0x7f; MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET); - /* For guests, disable mw type 2 */ + /* For guests, disable mw type 2 and port remap*/ MLX4_GET(bmme_flags, outbox->buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN; + bmme_flags &= ~MLX4_FLAG_PORT_REMAP; MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); /* turn off device-managed steering capability if not enabled */ @@ -2100,13 +2104,16 @@ struct mlx4_config_dev { __be32 rsvd1[3]; __be16 vxlan_udp_dport; __be16 rsvd2; - __be32 rsvd3[27]; - __be16 rsvd4; - u8 rsvd5; + __be32 rsvd3; + __be32 roce_flags; + __be32 rsvd4[25]; + __be16 rsvd5; + u8 rsvd6; u8 rx_checksum_val; }; #define MLX4_VXLAN_UDP_DPORT (1 << 0) +#define MLX4_DISABLE_RX_PORT BIT(18) static int mlx4_CONFIG_DEV_set(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev) { @@ -2209,6 +2216,45 @@ int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port) } EXPORT_SYMBOL_GPL(mlx4_config_vxlan_port); +#define CONFIG_DISABLE_RX_PORT BIT(15) +int mlx4_disable_rx_port_check(struct mlx4_dev *dev, bool dis) +{ + struct mlx4_config_dev config_dev; + + memset(&config_dev, 0, sizeof(config_dev)); + config_dev.update_flags = cpu_to_be32(MLX4_DISABLE_RX_PORT); + if (dis) + config_dev.roce_flags = + cpu_to_be32(CONFIG_DISABLE_RX_PORT); + + return mlx4_CONFIG_DEV_set(dev, &config_dev); +} + +int mlx4_virt2phy_port_map(struct mlx4_dev *dev, u32 port1, u32 port2) +{ + struct mlx4_cmd_mailbox *mailbox; + struct { + __be32 v_port1; + __be32 v_port2; + } *v2p; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return -ENOMEM; + + v2p = mailbox->buf; + v2p->v_port1 = cpu_to_be32(port1); + v2p->v_port2 = cpu_to_be32(port2); + + err = mlx4_cmd(dev, mailbox->dma, 0, + MLX4_SET_PORT_VIRT2PHY, MLX4_CMD_VIRT_PORT_MAP, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages) { -- cgit v1.2.1 From 53f33ae295a5098f12218da1400f55ad7df7447c Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Tue, 3 Feb 2015 16:48:33 +0200 Subject: net/mlx4_core: Port aggregation upper layer interface Supply interface functions to bond and unbond ports of a mlx4 internal interfaces. Example for such an interface is the one registered by the mlx4 IB driver under RoCE. There are 1. Functions to go in/out to/from bonded mode 2. Function to remap virtual ports to physical ports The bond_mutex prevents simultaneous access to data that keep status of the device in bonded mode. The upper mlx4 interface marks to the mlx4 core module that they want to be subject for such bonding by setting the MLX4_INTFF_BONDING flag. Interface which goes to/from bonded mode is re-created. The mlx4 Ethernet driver does not set this flag when registering the interface, the IB driver does. Signed-off-by: Moni Shoua Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_resources.c | 8 +- drivers/net/ethernet/mellanox/mlx4/intf.c | 54 +++++++++++++ drivers/net/ethernet/mellanox/mlx4/main.c | 89 ++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/mlx4.h | 3 + drivers/net/ethernet/mellanox/mlx4/qp.c | 2 + .../net/ethernet/mellanox/mlx4/resource_tracker.c | 3 + 6 files changed, 157 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c index f1a5500ff72d..34f2fdf4fe5d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c @@ -50,10 +50,14 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, context->mtu_msgmax = 0xff; if (!is_tx && !rss) context->rq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); - if (is_tx) + if (is_tx) { context->sq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); - else + if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP) + context->params2 |= MLX4_QP_BIT_FPP; + + } else { context->sq_size_stride = ilog2(TXBB_SIZE) - 4; + } context->usr_page = cpu_to_be32(mdev->priv_uar.index); context->local_qpn = cpu_to_be32(qpn); context->pri_path.ackto = 1 & 0x07; diff --git a/drivers/net/ethernet/mellanox/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c index 68d2bad325d5..6fce58718837 100644 --- a/drivers/net/ethernet/mellanox/mlx4/intf.c +++ b/drivers/net/ethernet/mellanox/mlx4/intf.c @@ -33,11 +33,13 @@ #include #include +#include #include "mlx4.h" struct mlx4_device_context { struct list_head list; + struct list_head bond_list; struct mlx4_interface *intf; void *context; }; @@ -115,6 +117,58 @@ void mlx4_unregister_interface(struct mlx4_interface *intf) } EXPORT_SYMBOL_GPL(mlx4_unregister_interface); +int mlx4_do_bond(struct mlx4_dev *dev, bool enable) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_device_context *dev_ctx = NULL, *temp_dev_ctx; + unsigned long flags; + int ret; + LIST_HEAD(bond_list); + + if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP)) + return -ENOTSUPP; + + ret = mlx4_disable_rx_port_check(dev, enable); + if (ret) { + mlx4_err(dev, "Fail to %s rx port check\n", + enable ? "enable" : "disable"); + return ret; + } + if (enable) { + dev->flags |= MLX4_FLAG_BONDED; + } else { + ret = mlx4_virt2phy_port_map(dev, 1, 2); + if (ret) { + mlx4_err(dev, "Fail to reset port map\n"); + return ret; + } + dev->flags &= ~MLX4_FLAG_BONDED; + } + + spin_lock_irqsave(&priv->ctx_lock, flags); + list_for_each_entry_safe(dev_ctx, temp_dev_ctx, &priv->ctx_list, list) { + if (dev_ctx->intf->flags & MLX4_INTFF_BONDING) { + list_add_tail(&dev_ctx->bond_list, &bond_list); + list_del(&dev_ctx->list); + } + } + spin_unlock_irqrestore(&priv->ctx_lock, flags); + + list_for_each_entry(dev_ctx, &bond_list, bond_list) { + dev_ctx->intf->remove(dev, dev_ctx->context); + dev_ctx->context = dev_ctx->intf->add(dev); + + spin_lock_irqsave(&priv->ctx_lock, flags); + list_add_tail(&dev_ctx->list, &priv->ctx_list); + spin_unlock_irqrestore(&priv->ctx_lock, flags); + + mlx4_dbg(dev, "Inrerface for protocol %d restarted with when bonded mode is %s\n", + dev_ctx->intf->protocol, enable ? + "enabled" : "disabled"); + } + return 0; +} + void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, unsigned long param) { diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index cc9f48439244..f3245fe0f442 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -1160,6 +1160,91 @@ err_set_port: return err ? err : count; } +int mlx4_bond(struct mlx4_dev *dev) +{ + int ret = 0; + struct mlx4_priv *priv = mlx4_priv(dev); + + mutex_lock(&priv->bond_mutex); + + if (!mlx4_is_bonded(dev)) + ret = mlx4_do_bond(dev, true); + else + ret = 0; + + mutex_unlock(&priv->bond_mutex); + if (ret) + mlx4_err(dev, "Failed to bond device: %d\n", ret); + else + mlx4_dbg(dev, "Device is bonded\n"); + return ret; +} +EXPORT_SYMBOL_GPL(mlx4_bond); + +int mlx4_unbond(struct mlx4_dev *dev) +{ + int ret = 0; + struct mlx4_priv *priv = mlx4_priv(dev); + + mutex_lock(&priv->bond_mutex); + + if (mlx4_is_bonded(dev)) + ret = mlx4_do_bond(dev, false); + + mutex_unlock(&priv->bond_mutex); + if (ret) + mlx4_err(dev, "Failed to unbond device: %d\n", ret); + else + mlx4_dbg(dev, "Device is unbonded\n"); + return ret; +} +EXPORT_SYMBOL_GPL(mlx4_unbond); + + +int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p) +{ + u8 port1 = v2p->port1; + u8 port2 = v2p->port2; + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP)) + return -ENOTSUPP; + + mutex_lock(&priv->bond_mutex); + + /* zero means keep current mapping for this port */ + if (port1 == 0) + port1 = priv->v2p.port1; + if (port2 == 0) + port2 = priv->v2p.port2; + + if ((port1 < 1) || (port1 > MLX4_MAX_PORTS) || + (port2 < 1) || (port2 > MLX4_MAX_PORTS) || + (port1 == 2 && port2 == 1)) { + /* besides boundary checks cross mapping makes + * no sense and therefore not allowed */ + err = -EINVAL; + } else if ((port1 == priv->v2p.port1) && + (port2 == priv->v2p.port2)) { + err = 0; + } else { + err = mlx4_virt2phy_port_map(dev, port1, port2); + if (!err) { + mlx4_dbg(dev, "port map changed: [%d][%d]\n", + port1, port2); + priv->v2p.port1 = port1; + priv->v2p.port2 = port2; + } else { + mlx4_err(dev, "Failed to change port mape: %d\n", err); + } + } + + mutex_unlock(&priv->bond_mutex); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_port_map_set); + static int mlx4_load_fw(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -2638,6 +2723,7 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data, spin_lock_init(&priv->ctx_lock); mutex_init(&priv->port_mutex); + mutex_init(&priv->bond_mutex); INIT_LIST_HEAD(&priv->pgdir_list); mutex_init(&priv->pgdir_mutex); @@ -2934,6 +3020,9 @@ slave_start: goto err_port; } + priv->v2p.port1 = 1; + priv->v2p.port2 = 2; + err = mlx4_register_device(dev); if (err) goto err_port; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 148dc0945aab..803f17653da7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -885,6 +885,8 @@ struct mlx4_priv { int reserved_mtts; int fs_hash_mode; u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS]; + struct mlx4_port_map v2p; /* cached port mapping configuration */ + struct mutex bond_mutex; /* for bond mode */ __be64 slave_node_guids[MLX4_MFUNC_MAX]; atomic_t opreq_count; @@ -1364,6 +1366,7 @@ int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port); /* Returns the VF index of slave */ int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave); int mlx4_config_mad_demux(struct mlx4_dev *dev); +int mlx4_do_bond(struct mlx4_dev *dev, bool enable); enum mlx4_zone_flags { MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO = 1UL << 0, diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 1586ecce13c7..2bb8553bd905 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -882,6 +882,8 @@ int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt, for (i = 0; i < ARRAY_SIZE(states) - 1; i++) { context->flags &= cpu_to_be32(~(0xf << 28)); context->flags |= cpu_to_be32(states[i + 1] << 28); + if (states[i + 1] != MLX4_QP_STATE_RTR) + context->params2 &= ~MLX4_QP_BIT_FPP; err = mlx4_qp_modify(dev, mtt, states[i], states[i + 1], context, 0, 0, qp); if (err) { diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 79feeb6b0d87..c5f3dfca226b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -2944,6 +2944,9 @@ static int verify_qp_parameters(struct mlx4_dev *dev, qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; optpar = be32_to_cpu(*(__be32 *) inbox->buf); + if (slave != mlx4_master_func_num(dev)) + qp_ctx->params2 &= ~MLX4_QP_BIT_FPP; + switch (qp_type) { case MLX4_QP_ST_RC: case MLX4_QP_ST_XRC: -- cgit v1.2.1 From 5da0354726e4a6ae2e25c1fa2feb77585d997b05 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Tue, 3 Feb 2015 16:48:34 +0200 Subject: net/mlx4_en: Port aggregation configuration Capture NETDEV events generated by the bonding driver and based on that make decisions of how to configure port aggregation in the mlx4 core driver. This includes setting the V2P port table and re-creating the interested interfaces in bonded/non-bonded mode. Signed-off-by: Moni Shoua Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_main.c | 8 ++ drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 176 +++++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 5 + 3 files changed, 189 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index c643d2bbb7b9..58d5a07d0ff4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -214,6 +214,8 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr) iounmap(mdev->uar_map); mlx4_uar_free(dev, &mdev->priv_uar); mlx4_pd_free(dev, mdev->priv_pdn); + if (mdev->nb.notifier_call) + unregister_netdevice_notifier(&mdev->nb); kfree(mdev); } @@ -298,6 +300,12 @@ static void *mlx4_en_add(struct mlx4_dev *dev) if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) mdev->pndev[i] = NULL; } + /* register notifier */ + mdev->nb.notifier_call = mlx4_en_netdev_event; + if (register_netdevice_notifier(&mdev->nb)) { + mdev->nb.notifier_call = NULL; + mlx4_err(mdev, "Failed to create notifier\n"); + } return mdev; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index e075ff1f4e80..028937b2a199 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2062,6 +2062,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) /* Detach the netdev so tasks would not attempt to access it */ mutex_lock(&mdev->state_lock); mdev->pndev[priv->port] = NULL; + mdev->upper[priv->port] = NULL; mutex_unlock(&mdev->state_lock); mlx4_en_free_resources(priv); @@ -2441,6 +2442,180 @@ static const struct net_device_ops mlx4_netdev_ops_master = { #endif }; +struct mlx4_en_bond { + struct work_struct work; + struct mlx4_en_priv *priv; + int is_bonded; + struct mlx4_port_map port_map; +}; + +static void mlx4_en_bond_work(struct work_struct *work) +{ + struct mlx4_en_bond *bond = container_of(work, + struct mlx4_en_bond, + work); + int err = 0; + struct mlx4_dev *dev = bond->priv->mdev->dev; + + if (bond->is_bonded) { + if (!mlx4_is_bonded(dev)) { + err = mlx4_bond(dev); + if (err) + en_err(bond->priv, "Fail to bond device\n"); + } + if (!err) { + err = mlx4_port_map_set(dev, &bond->port_map); + if (err) + en_err(bond->priv, "Fail to set port map [%d][%d]: %d\n", + bond->port_map.port1, + bond->port_map.port2, + err); + } + } else if (mlx4_is_bonded(dev)) { + err = mlx4_unbond(dev); + if (err) + en_err(bond->priv, "Fail to unbond device\n"); + } + dev_put(bond->priv->dev); + kfree(bond); +} + +static int mlx4_en_queue_bond_work(struct mlx4_en_priv *priv, int is_bonded, + u8 v2p_p1, u8 v2p_p2) +{ + struct mlx4_en_bond *bond = NULL; + + bond = kzalloc(sizeof(*bond), GFP_ATOMIC); + if (!bond) + return -ENOMEM; + + INIT_WORK(&bond->work, mlx4_en_bond_work); + bond->priv = priv; + bond->is_bonded = is_bonded; + bond->port_map.port1 = v2p_p1; + bond->port_map.port2 = v2p_p2; + dev_hold(priv->dev); + queue_work(priv->mdev->workqueue, &bond->work); + return 0; +} + +int mlx4_en_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + u8 port = 0; + struct mlx4_en_dev *mdev; + struct mlx4_dev *dev; + int i, num_eth_ports = 0; + bool do_bond = true; + struct mlx4_en_priv *priv; + u8 v2p_port1 = 0; + u8 v2p_port2 = 0; + + if (!net_eq(dev_net(ndev), &init_net)) + return NOTIFY_DONE; + + mdev = container_of(this, struct mlx4_en_dev, nb); + dev = mdev->dev; + + /* Go into this mode only when two network devices set on two ports + * of the same mlx4 device are slaves of the same bonding master + */ + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { + ++num_eth_ports; + if (!port && (mdev->pndev[i] == ndev)) + port = i; + mdev->upper[i] = mdev->pndev[i] ? + netdev_master_upper_dev_get(mdev->pndev[i]) : NULL; + /* condition not met: network device is a slave */ + if (!mdev->upper[i]) + do_bond = false; + if (num_eth_ports < 2) + continue; + /* condition not met: same master */ + if (mdev->upper[i] != mdev->upper[i-1]) + do_bond = false; + } + /* condition not met: 2 salves */ + do_bond = (num_eth_ports == 2) ? do_bond : false; + + /* handle only events that come with enough info */ + if ((do_bond && (event != NETDEV_BONDING_INFO)) || !port) + return NOTIFY_DONE; + + priv = netdev_priv(ndev); + if (do_bond) { + struct netdev_notifier_bonding_info *notifier_info = ptr; + struct netdev_bonding_info *bonding_info = + ¬ifier_info->bonding_info; + + /* required mode 1, 2 or 4 */ + if ((bonding_info->master.bond_mode != BOND_MODE_ACTIVEBACKUP) && + (bonding_info->master.bond_mode != BOND_MODE_XOR) && + (bonding_info->master.bond_mode != BOND_MODE_8023AD)) + do_bond = false; + + /* require exactly 2 slaves */ + if (bonding_info->master.num_slaves != 2) + do_bond = false; + + /* calc v2p */ + if (do_bond) { + if (bonding_info->master.bond_mode == + BOND_MODE_ACTIVEBACKUP) { + /* in active-backup mode virtual ports are + * mapped to the physical port of the active + * slave */ + if (bonding_info->slave.state == + BOND_STATE_BACKUP) { + if (port == 1) { + v2p_port1 = 2; + v2p_port2 = 2; + } else { + v2p_port1 = 1; + v2p_port2 = 1; + } + } else { /* BOND_STATE_ACTIVE */ + if (port == 1) { + v2p_port1 = 1; + v2p_port2 = 1; + } else { + v2p_port1 = 2; + v2p_port2 = 2; + } + } + } else { /* Active-Active */ + /* in active-active mode a virtual port is + * mapped to the native physical port if and only + * if the physical port is up */ + __s8 link = bonding_info->slave.link; + + if (port == 1) + v2p_port2 = 2; + else + v2p_port1 = 1; + if ((link == BOND_LINK_UP) || + (link == BOND_LINK_FAIL)) { + if (port == 1) + v2p_port1 = 1; + else + v2p_port2 = 2; + } else { /* BOND_LINK_DOWN || BOND_LINK_BACK */ + if (port == 1) + v2p_port1 = 2; + else + v2p_port2 = 1; + } + } + } + } + + mlx4_en_queue_bond_work(priv, do_bond, + v2p_port1, v2p_port2); + + return NOTIFY_DONE; +} + int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, struct mlx4_en_port_profile *prof) { @@ -2623,6 +2798,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, } mdev->pndev[port] = dev; + mdev->upper[port] = NULL; netif_carrier_off(dev); mlx4_en_set_default_moderation(priv); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 944a112dff37..2a8268e6be15 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -390,6 +390,7 @@ struct mlx4_en_dev { struct pci_dev *pdev; struct mutex state_lock; struct net_device *pndev[MLX4_MAX_PORTS + 1]; + struct net_device *upper[MLX4_MAX_PORTS + 1]; u32 port_cnt; bool device_up; struct mlx4_en_profile profile; @@ -410,6 +411,7 @@ struct mlx4_en_dev { unsigned long overflow_period; struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_clock_info; + struct notifier_block nb; }; @@ -845,6 +847,9 @@ int mlx4_en_reset_config(struct net_device *dev, struct hwtstamp_config ts_config, netdev_features_t new_features); +int mlx4_en_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr); + /* * Functions for time stamping */ -- cgit v1.2.1 From b332068ce4261b37d05f438fbc487e357fffa108 Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Tue, 3 Feb 2015 17:57:15 +0200 Subject: net/mlx4_core: Fix mpt_entry initialization in mlx4_mr_rereg_mem_write() a) Previously, mlx4_mr_rereg_write filled the MPT's start and length with the old MPT's values. Fixing the initialization to take the new start and length. b) In addition access flags in mpt_status were initialized instead of status due to bad boolean operation. Fixing the operation. c) Initialization of pd_slave caused a protection error. Fix - removing this initialization. d) In resource_tracker.c: Fixing vf encoding to be one-based. Fixes: e630664c ('mlx4_core: Add helper functions to support MR re-registration') Signed-off-by: Maor Gottlieb Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mr.c | 13 +++++-------- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index d21e884a0838..78f51e103880 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -598,14 +598,11 @@ int mlx4_mr_rereg_mem_write(struct mlx4_dev *dev, struct mlx4_mr *mr, if (err) return err; - mpt_entry->start = cpu_to_be64(mr->iova); - mpt_entry->length = cpu_to_be64(mr->size); - mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift); - - mpt_entry->pd_flags &= cpu_to_be32(MLX4_MPT_PD_MASK | - MLX4_MPT_PD_FLAG_EN_INV); - mpt_entry->flags &= cpu_to_be32(MLX4_MPT_FLAG_FREE | - MLX4_MPT_FLAG_SW_OWNS); + mpt_entry->start = cpu_to_be64(iova); + mpt_entry->length = cpu_to_be64(size); + mpt_entry->entity_size = cpu_to_be32(page_shift); + mpt_entry->flags &= ~(cpu_to_be32(MLX4_MPT_FLAG_FREE | + MLX4_MPT_FLAG_SW_OWNS)); if (mr->mtt.order < 0) { mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_PHYSICAL); mpt_entry->mtt_addr = 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index c5f3dfca226b..486e3d26cd4a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -2541,7 +2541,7 @@ int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, /* Make sure that the PD bits related to the slave id are zeros. */ pd = mr_get_pd(inbox->buf); pd_slave = (pd >> 17) & 0x7f; - if (pd_slave != 0 && pd_slave != slave) { + if (pd_slave != 0 && --pd_slave != slave) { err = -EPERM; goto ex_abort; } -- cgit v1.2.1 From 6af0a52f65840bdfae5e24df51cbe9965a4146f6 Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Tue, 3 Feb 2015 17:57:16 +0200 Subject: net/mlx4: mlx4_config_dev_retrieval() - Initialize struct config_dev before using Add Initialization to struct config_dev before filling and using it. Fix to warning: warning: config_dev.rx_checksum_val may be used uninitialized in this function Signed-off-by: Maor Gottlieb Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 4b08a393ebcb..5a21e5dc94cb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -2169,7 +2169,7 @@ static const u8 config_dev_csum_flags[] = { int mlx4_config_dev_retrieval(struct mlx4_dev *dev, struct mlx4_config_dev_params *params) { - struct mlx4_config_dev config_dev; + struct mlx4_config_dev config_dev = {0}; int err; u8 csum_mask; -- cgit v1.2.1 From 0fab541ac2ca9bc69522e488a9dda825e2d4a243 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 3 Feb 2015 17:57:17 +0200 Subject: net/mlx4_core: Fix misleading debug print on CQE stride support We do support cache line sizes of 32 and 64 bytes without activating the CQE stride feature. Fix a misleading print saying that these cache line sizes aren't supported. Signed-off-by: Or Gerlitz Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index f3245fe0f442..7e487223489a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -251,7 +251,8 @@ static void mlx4_enable_cqe_eqe_stride(struct mlx4_dev *dev) if (mlx4_is_master(dev)) dev_cap->function_caps |= MLX4_FUNC_CAP_EQE_CQE_STRIDE; } else { - mlx4_dbg(dev, "Disabling CQE stride cacheLine unsupported\n"); + if (cache_line_size() != 32 && cache_line_size() != 64) + mlx4_dbg(dev, "Disabling CQE stride, cacheLine size unsupported\n"); dev_cap->flags2 &= ~MLX4_DEV_CAP_FLAG2_CQE_STRIDE; dev_cap->flags2 &= ~MLX4_DEV_CAP_FLAG2_EQE_STRIDE; } -- cgit v1.2.1 From 1c755cc5be5023c9523d558de0c507316efa6c62 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 3 Feb 2015 17:57:18 +0200 Subject: net/mlx5_core: Move to use hex PCI device IDs Align the IDs in the code with the modinfo, lspci -n, etc tools outputs. Signed-off-by: Or Gerlitz Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 3f4525619a07..d6651937d899 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -903,12 +903,12 @@ static void remove_one(struct pci_dev *pdev) } static const struct pci_device_id mlx5_core_pci_table[] = { - { PCI_VDEVICE(MELLANOX, 4113) }, /* Connect-IB */ - { PCI_VDEVICE(MELLANOX, 4114) }, /* Connect-IB VF */ - { PCI_VDEVICE(MELLANOX, 4115) }, /* ConnectX-4 */ - { PCI_VDEVICE(MELLANOX, 4116) }, /* ConnectX-4 VF */ - { PCI_VDEVICE(MELLANOX, 4117) }, /* ConnectX-4LX */ - { PCI_VDEVICE(MELLANOX, 4118) }, /* ConnectX-4LX VF */ + { PCI_VDEVICE(MELLANOX, 0x1011) }, /* Connect-IB */ + { PCI_VDEVICE(MELLANOX, 0x1012) }, /* Connect-IB VF */ + { PCI_VDEVICE(MELLANOX, 0x1013) }, /* ConnectX-4 */ + { PCI_VDEVICE(MELLANOX, 0x1014) }, /* ConnectX-4 VF */ + { PCI_VDEVICE(MELLANOX, 0x1015) }, /* ConnectX-4LX */ + { PCI_VDEVICE(MELLANOX, 0x1016) }, /* ConnectX-4LX VF */ { 0, } }; -- cgit v1.2.1 From b110d2ce490f990af6985fbae619fde5ae4cc46f Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Tue, 3 Feb 2015 17:57:19 +0200 Subject: net/mlx4_en: Print page allocator information After Initialization of page_alloc, print actual allocated page size and number of frags it contains. prints is done only when drv message level is set on the interface. Signed-off-by: Ido Shamay Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 2ba5d368edce..30a2203a7cd1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -162,6 +162,10 @@ static int mlx4_en_init_allocator(struct mlx4_en_priv *priv, if (mlx4_alloc_pages(priv, &ring->page_alloc[i], frag_info, GFP_KERNEL | __GFP_COLD)) goto out; + + en_dbg(DRV, priv, " frag %d allocator: - size:%d frags:%d\n", + i, ring->page_alloc[i].page_size, + atomic_read(&ring->page_alloc[i].page->_count)); } return 0; -- cgit v1.2.1 From e8e7f018f1951b0359647ca0c1ff1be4f896b99f Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Tue, 3 Feb 2015 17:57:20 +0200 Subject: net/mlx4_en: Adjust RX frag strides to frag sizes This patch improves memory utilization and therefore the packets rate for special MTU's. Instead of setting the frag_stride to the maximal hard coded frag_size, use the actual frag_size that is set according to the MTU, when setting the stride of the last frag. So, for example, for MTU 1600, where the frag_size of the 2nd frag is 86, the frag_size is set to 128 instead of 4096. See below: Before: frag:0 - size:1536 prefix:0 stride:1536 frag:1 - size:86 prefix:1536 stride:4096 frag 0 allocator: - size:32768 frags:21 frag 1 allocator: - size:32768 frags:8 After: frag:0 - size:1536 prefix:0 stride:1536 frag:1 - size:86 prefix:1536 stride:128 frag 0 allocator: - size:32768 frags:21 frag 1 allocator: - size:32768 frags:256 Signed-off-by: Ido Shamay Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 30a2203a7cd1..698d60de1255 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -1063,8 +1063,9 @@ void mlx4_en_calc_rx_buf(struct net_device *dev) (eff_mtu > buf_size + frag_sizes[i]) ? frag_sizes[i] : eff_mtu - buf_size; priv->frag_info[i].frag_prefix_size = buf_size; - priv->frag_info[i].frag_stride = ALIGN(frag_sizes[i], - SMP_CACHE_BYTES); + priv->frag_info[i].frag_stride = + ALIGN(priv->frag_info[i].frag_size, + SMP_CACHE_BYTES); buf_size += priv->frag_info[i].frag_size; i++; } -- cgit v1.2.1 From cfb53f36a5b5eb60213fdb6ba191eb9d8b5e1163 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Tue, 3 Feb 2015 17:57:21 +0200 Subject: net/mlx4_en: Notify TX Vlan offload change Notify users when TX vlan offload feature changed with ethtool. Relevant command - ethtool -K txvlan on/off. Signed-off-by: Ido Shamay Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 028937b2a199..2a210c4efb89 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2202,6 +2202,10 @@ static int mlx4_en_set_features(struct net_device *netdev, return ret; } + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_TX)) + en_info(priv, "Turn %s TX vlan strip offload\n", + (features & NETIF_F_HW_VLAN_CTAG_TX) ? "ON" : "OFF"); + if (features & NETIF_F_LOOPBACK) priv->ctrl_flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK); else -- cgit v1.2.1 From f339664c0be145b381c788bc0d5c07fbe1dd9d85 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 3 Feb 2015 19:47:33 +0100 Subject: IBM-EMAC: Delete an unnecessary check before the function call "of_dev_put" The of_dev_put() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/emac/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 9388a83818f2..162762d1a12c 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -2367,7 +2367,7 @@ static int emac_wait_deps(struct emac_instance *dev) err = emac_check_deps(dev, deps) ? 0 : -ENODEV; for (i = 0; i < EMAC_DEP_COUNT; i++) { of_node_put(deps[i].node); - if (err && deps[i].ofdev) + if (err) of_dev_put(deps[i].ofdev); } if (err == 0) { -- cgit v1.2.1 From 9b55669c14212f89dba39a2d8e00c1ec1d44c1ec Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 3 Feb 2015 20:12:25 +0100 Subject: NetCP: Deletion of unnecessary checks before two function calls The functions cpsw_ale_destroy() and of_dev_put() test whether their argument is NULL and then return immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 345cd2563772..84f5ce525750 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -2011,12 +2011,10 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, quit: if (gbe_dev->hw_stats) devm_kfree(dev, gbe_dev->hw_stats); - if (gbe_dev->ale) - cpsw_ale_destroy(gbe_dev->ale); + cpsw_ale_destroy(gbe_dev->ale); if (gbe_dev->ss_regs) devm_iounmap(dev, gbe_dev->ss_regs); - if (interfaces) - of_node_put(interfaces); + of_node_put(interfaces); devm_kfree(dev, gbe_dev); return ret; } -- cgit v1.2.1 From 3a336cb17183b29827fdffaffb5e62f8912f5ca1 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 4 Feb 2015 15:32:52 +0530 Subject: cxgb4: Add low latency socket busy_poll support cxgb_busy_poll, corresponding to ndo_busy_poll, gets called by the socket waiting for data. With busy_poll enabled, improvement is seen in latency numbers as observed by collecting netperf TCP_RR numbers. Below are latency number, with and without busy-poll, in a switched environment for a particular msg size: netperf command: netperf -4 -H -l 30 -t TCP_RR -- -r1,1 Latency without busy-poll: ~16.25 us Latency with busy-poll : ~08.79 us Based on original work by Kumar Sanghvi Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 113 ++++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 16 +++- drivers/net/ethernet/chelsio/cxgb4/sge.c | 47 +++++++++- drivers/net/ethernet/chelsio/cxgb4/t4_values.h | 1 + 4 files changed, 174 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index fb6980a09981..55019c93387d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -476,6 +476,22 @@ struct sge_rspq { /* state for an SGE response queue */ struct adapter *adap; struct net_device *netdev; /* associated net device */ rspq_handler_t handler; +#ifdef CONFIG_NET_RX_BUSY_POLL +#define CXGB_POLL_STATE_IDLE 0 +#define CXGB_POLL_STATE_NAPI BIT(0) /* NAPI owns this poll */ +#define CXGB_POLL_STATE_POLL BIT(1) /* poll owns this poll */ +#define CXGB_POLL_STATE_NAPI_YIELD BIT(2) /* NAPI yielded this poll */ +#define CXGB_POLL_STATE_POLL_YIELD BIT(3) /* poll yielded this poll */ +#define CXGB_POLL_YIELD (CXGB_POLL_STATE_NAPI_YIELD | \ + CXGB_POLL_STATE_POLL_YIELD) +#define CXGB_POLL_LOCKED (CXGB_POLL_STATE_NAPI | \ + CXGB_POLL_STATE_POLL) +#define CXGB_POLL_USER_PEND (CXGB_POLL_STATE_POLL | \ + CXGB_POLL_STATE_POLL_YIELD) + unsigned int bpoll_state; + spinlock_t bpoll_lock; /* lock for busy poll */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ + }; struct sge_eth_stats { /* Ethernet queue statistics */ @@ -880,6 +896,102 @@ static inline struct adapter *netdev2adap(const struct net_device *dev) return netdev2pinfo(dev)->adapter; } +#ifdef CONFIG_NET_RX_BUSY_POLL +static inline void cxgb_busy_poll_init_lock(struct sge_rspq *q) +{ + spin_lock_init(&q->bpoll_lock); + q->bpoll_state = CXGB_POLL_STATE_IDLE; +} + +static inline bool cxgb_poll_lock_napi(struct sge_rspq *q) +{ + bool rc = true; + + spin_lock(&q->bpoll_lock); + if (q->bpoll_state & CXGB_POLL_LOCKED) { + q->bpoll_state |= CXGB_POLL_STATE_NAPI_YIELD; + rc = false; + } else { + q->bpoll_state = CXGB_POLL_STATE_NAPI; + } + spin_unlock(&q->bpoll_lock); + return rc; +} + +static inline bool cxgb_poll_unlock_napi(struct sge_rspq *q) +{ + bool rc = false; + + spin_lock(&q->bpoll_lock); + if (q->bpoll_state & CXGB_POLL_STATE_POLL_YIELD) + rc = true; + q->bpoll_state = CXGB_POLL_STATE_IDLE; + spin_unlock(&q->bpoll_lock); + return rc; +} + +static inline bool cxgb_poll_lock_poll(struct sge_rspq *q) +{ + bool rc = true; + + spin_lock_bh(&q->bpoll_lock); + if (q->bpoll_state & CXGB_POLL_LOCKED) { + q->bpoll_state |= CXGB_POLL_STATE_POLL_YIELD; + rc = false; + } else { + q->bpoll_state |= CXGB_POLL_STATE_POLL; + } + spin_unlock_bh(&q->bpoll_lock); + return rc; +} + +static inline bool cxgb_poll_unlock_poll(struct sge_rspq *q) +{ + bool rc = false; + + spin_lock_bh(&q->bpoll_lock); + if (q->bpoll_state & CXGB_POLL_STATE_POLL_YIELD) + rc = true; + q->bpoll_state = CXGB_POLL_STATE_IDLE; + spin_unlock_bh(&q->bpoll_lock); + return rc; +} + +static inline bool cxgb_poll_busy_polling(struct sge_rspq *q) +{ + return q->bpoll_state & CXGB_POLL_USER_PEND; +} +#else +static inline void cxgb_busy_poll_init_lock(struct sge_rspq *q) +{ +} + +static inline bool cxgb_poll_lock_napi(struct sge_rspq *q) +{ + return true; +} + +static inline bool cxgb_poll_unlock_napi(struct sge_rspq *q) +{ + return false; +} + +static inline bool cxgb_poll_lock_poll(struct sge_rspq *q) +{ + return false; +} + +static inline bool cxgb_poll_unlock_poll(struct sge_rspq *q) +{ + return false; +} + +static inline bool cxgb_poll_busy_polling(struct sge_rspq *q) +{ + return false; +} +#endif /* CONFIG_NET_RX_BUSY_POLL */ + void t4_os_portmod_changed(const struct adapter *adap, int port_id); void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat); @@ -908,6 +1020,7 @@ irqreturn_t t4_sge_intr_msix(int irq, void *cookie); int t4_sge_init(struct adapter *adap); void t4_sge_start(struct adapter *adap); void t4_sge_stop(struct adapter *adap); +int cxgb_busy_poll(struct napi_struct *napi); extern int dbfifo_int_thresh; #define for_each_port(adapter, iter) \ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 5bf490a781aa..041742b5e0e8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -923,8 +923,14 @@ static void quiesce_rx(struct adapter *adap) for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { struct sge_rspq *q = adap->sge.ingr_map[i]; - if (q && q->handler) + if (q && q->handler) { napi_disable(&q->napi); + local_bh_disable(); + while (!cxgb_poll_lock_napi(q)) + mdelay(1); + local_bh_enable(); + } + } } @@ -940,8 +946,10 @@ static void enable_rx(struct adapter *adap) if (!q) continue; - if (q->handler) + if (q->handler) { + cxgb_busy_poll_init_lock(q); napi_enable(&q->napi); + } /* 0-increment GTS to start the timer and enable interrupts */ t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), SEINTARM_V(q->intr_params) | @@ -4563,6 +4571,10 @@ static const struct net_device_ops cxgb4_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = cxgb_netpoll, #endif +#ifdef CONFIG_NET_RX_BUSY_POLL + .ndo_busy_poll = cxgb_busy_poll, +#endif + }; void t4_fatal_err(struct adapter *adap) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 619156112b21..b4b9f6048fe7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -43,6 +43,9 @@ #include #include #include +#ifdef CONFIG_NET_RX_BUSY_POLL +#include +#endif /* CONFIG_NET_RX_BUSY_POLL */ #include "cxgb4.h" #include "t4_regs.h" #include "t4_values.h" @@ -1720,6 +1723,7 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl, skb->truesize += skb->data_len; skb->ip_summed = CHECKSUM_UNNECESSARY; skb_record_rx_queue(skb, rxq->rspq.idx); + skb_mark_napi_id(skb, &rxq->rspq.napi); if (rxq->rspq.netdev->features & NETIF_F_RXHASH) skb_set_hash(skb, (__force u32)pkt->rsshdr.hash_val, PKT_HASH_TYPE_L3); @@ -1763,6 +1767,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, csum_ok = pkt->csum_calc && !pkt->err_vec && (q->netdev->features & NETIF_F_RXCSUM); if ((pkt->l2info & htonl(RXF_TCP_F)) && + !(cxgb_poll_busy_polling(q)) && (q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) { do_gro(rxq, si, pkt); return 0; @@ -1801,6 +1806,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(pkt->vlan)); rxq->stats.vlan_ex++; } + skb_mark_napi_id(skb, &q->napi); netif_receive_skb(skb); return 0; } @@ -1963,6 +1969,38 @@ static int process_responses(struct sge_rspq *q, int budget) return budget - budget_left; } +#ifdef CONFIG_NET_RX_BUSY_POLL +int cxgb_busy_poll(struct napi_struct *napi) +{ + struct sge_rspq *q = container_of(napi, struct sge_rspq, napi); + unsigned int params, work_done; + u32 val; + + if (!cxgb_poll_lock_poll(q)) + return LL_FLUSH_BUSY; + + work_done = process_responses(q, 4); + params = QINTR_TIMER_IDX(TIMERREG_COUNTER0_X) | QINTR_CNT_EN; + q->next_intr_params = params; + val = CIDXINC_V(work_done) | SEINTARM_V(params); + + /* If we don't have access to the new User GTS (T5+), use the old + * doorbell mechanism; otherwise use the new BAR2 mechanism. + */ + if (unlikely(!q->bar2_addr)) + t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS_A), + val | INGRESSQID_V((u32)q->cntxt_id)); + else { + writel(val | INGRESSQID_V(q->bar2_qid), + q->bar2_addr + SGE_UDB_GTS); + wmb(); + } + + cxgb_poll_unlock_poll(q); + return work_done; +} +#endif /* CONFIG_NET_RX_BUSY_POLL */ + /** * napi_rx_handler - the NAPI handler for Rx processing * @napi: the napi instance @@ -1978,9 +2016,13 @@ static int napi_rx_handler(struct napi_struct *napi, int budget) { unsigned int params; struct sge_rspq *q = container_of(napi, struct sge_rspq, napi); - int work_done = process_responses(q, budget); + int work_done; u32 val; + if (!cxgb_poll_lock_napi(q)) + return budget; + + work_done = process_responses(q, budget); if (likely(work_done < budget)) { int timer_index; @@ -2018,6 +2060,7 @@ static int napi_rx_handler(struct napi_struct *napi, int budget) q->bar2_addr + SGE_UDB_GTS); wmb(); } + cxgb_poll_unlock_napi(q); return work_done; } @@ -2341,6 +2384,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq, goto err; netif_napi_add(dev, &iq->napi, napi_rx_handler, 64); + napi_hash_add(&iq->napi); iq->cur_desc = iq->desc; iq->cidx = 0; iq->gen = 1; @@ -2598,6 +2642,7 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, rq->cntxt_id, fl_id, 0xffff); dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len, rq->desc, rq->phys_addr); + napi_hash_del(&rq->napi); netif_napi_del(&rq->napi); rq->netdev = NULL; rq->cntxt_id = rq->abs_id = 0; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h index a40484432ebf..997ec87470c7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h @@ -59,6 +59,7 @@ /* GTS register */ #define SGE_TIMERREGS 6 +#define TIMERREG_COUNTER0_X 0 /* T5 and later support a new BAR2-based doorbell mechanism for Egress Queues. * The User Doorbells are each 128 bytes in length with a Simple Doorbell at -- cgit v1.2.1 From 0b5b6beea1a3f2b75e5b5baf9df073bf709f9297 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 11:28:43 +0100 Subject: cxgb4: Delete an unnecessary check before the function call "release_firmware" The release_firmware() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 041742b5e0e8..5db5b4f7b94d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -5142,8 +5142,7 @@ static int adap_init0(struct adapter *adap) state, &reset); /* Cleaning up */ - if (fw != NULL) - release_firmware(fw); + release_firmware(fw); t4_free_mem(card_fw); if (ret < 0) -- cgit v1.2.1 From 2d4ad4f6903f3a7b4eccb6e7eeb82f22edd648ea Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 12:32:14 +0100 Subject: myri10ge: Delete an unnecessary check before the function call "kfree" The kfree() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: David S. Miller --- drivers/net/ethernet/myricom/myri10ge/myri10ge.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 71af98bb72cb..1412f5af05ec 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -4226,8 +4226,7 @@ static void myri10ge_remove(struct pci_dev *pdev) mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span); #endif myri10ge_free_slices(mgp); - if (mgp->msix_vectors != NULL) - kfree(mgp->msix_vectors); + kfree(mgp->msix_vectors); dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus); -- cgit v1.2.1 From 1b4b32c6b88b3a0985b9448f52b3a58021de5653 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 12:56:42 +0100 Subject: net: fec: Delete unnecessary checks before the function call "kfree" The kfree() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 58cabee00abf..9bb6220663b2 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2596,12 +2596,9 @@ static void fec_enet_free_queue(struct net_device *ndev) } for (i = 0; i < fep->num_rx_queues; i++) - if (fep->rx_queue[i]) - kfree(fep->rx_queue[i]); - + kfree(fep->rx_queue[i]); for (i = 0; i < fep->num_tx_queues; i++) - if (fep->tx_queue[i]) - kfree(fep->tx_queue[i]); + kfree(fep->tx_queue[i]); } static int fec_enet_alloc_queue(struct net_device *ndev) -- cgit v1.2.1 From de7017625e8b642506b7e56574353cc9695ca357 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 13:17:48 +0100 Subject: netxen: Delete an unnecessary check before the function call "kfree" The kfree() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index afb8efb25781..e0c31e3947d1 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -176,9 +176,7 @@ netxen_alloc_sds_rings(struct netxen_recv_context *recv_ctx, int count) static void netxen_free_sds_rings(struct netxen_recv_context *recv_ctx) { - if (recv_ctx->sds_rings != NULL) - kfree(recv_ctx->sds_rings); - + kfree(recv_ctx->sds_rings); recv_ctx->sds_rings = NULL; } -- cgit v1.2.1 From f86b4ae6ac772f8177bfdd460ea43c319ca3f92d Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Wed, 4 Feb 2015 12:31:28 +0000 Subject: net: ethernet: ti/cpsw-common.c: fix sparse warning this patch fixes following sparse warning: cpsw-common.c:23:5: warning: symbol 'cpsw_am33xx_cm_get_macid' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw-common.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpsw-common.c b/drivers/net/ethernet/ti/cpsw-common.c index 763ada18ad3d..f59509486113 100644 --- a/drivers/net/ethernet/ti/cpsw-common.c +++ b/drivers/net/ethernet/ti/cpsw-common.c @@ -17,6 +17,8 @@ #include #include +#include "cpsw.h" + #define AM33XX_CTRL_MAC_LO_REG(offset, id) ((offset) + 0x8 * (id)) #define AM33XX_CTRL_MAC_HI_REG(offset, id) ((offset) + 0x8 * (id) + 0x4) -- cgit v1.2.1 From 7061b2bdd620e4dda449d4d4db69de57751ab289 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 14:07:56 +0100 Subject: qlogic: Deletion of unnecessary checks before two function calls The functions kfree() and vfree() perform also input parameter validation. Thus the test around their calls is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 24 ++++++++-------------- .../net/ethernet/qlogic/qlcnic/qlcnic_minidump.c | 3 +-- 2 files changed, 9 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 2528c3fb6b90..a430a34a4434 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -294,9 +294,7 @@ int qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count) void qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx) { - if (recv_ctx->sds_rings != NULL) - kfree(recv_ctx->sds_rings); - + kfree(recv_ctx->sds_rings); recv_ctx->sds_rings = NULL; } @@ -1257,8 +1255,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC) { if (fw_dump->tmpl_hdr == NULL || adapter->fw_version > prev_fw_version) { - if (fw_dump->tmpl_hdr) - vfree(fw_dump->tmpl_hdr); + vfree(fw_dump->tmpl_hdr); if (!qlcnic_fw_cmd_get_minidump_temp(adapter)) dev_info(&pdev->dev, "Supports FW dump capability\n"); @@ -2374,13 +2371,12 @@ void qlcnic_free_tx_rings(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; - if (tx_ring && tx_ring->cmd_buf_arr != NULL) { + if (tx_ring) { vfree(tx_ring->cmd_buf_arr); tx_ring->cmd_buf_arr = NULL; } } - if (adapter->tx_ring != NULL) - kfree(adapter->tx_ring); + kfree(adapter->tx_ring); } int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter, @@ -2758,13 +2754,9 @@ static void qlcnic_remove(struct pci_dev *pdev) } qlcnic_dcb_free(adapter->dcb); - qlcnic_detach(adapter); - - if (adapter->npars != NULL) - kfree(adapter->npars); - if (adapter->eswitch != NULL) - kfree(adapter->eswitch); + kfree(adapter->npars); + kfree(adapter->eswitch); if (qlcnic_82xx_check(adapter)) qlcnic_clr_all_drv_state(adapter, 0); @@ -2932,13 +2924,13 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter) static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter) { - if (adapter->fhash.fmax && adapter->fhash.fhead) + if (adapter->fhash.fmax) kfree(adapter->fhash.fhead); adapter->fhash.fhead = NULL; adapter->fhash.fmax = 0; - if (adapter->rx_fhash.fmax && adapter->rx_fhash.fhead) + if (adapter->rx_fhash.fmax) kfree(adapter->rx_fhash.fhead); adapter->rx_fhash.fmax = 0; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index c9f57fb84b9e..332bb8a3f430 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -1407,8 +1407,7 @@ void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter) current_version = qlcnic_83xx_get_fw_version(adapter); if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) { - if (fw_dump->tmpl_hdr) - vfree(fw_dump->tmpl_hdr); + vfree(fw_dump->tmpl_hdr); if (!qlcnic_fw_cmd_get_minidump_temp(adapter)) dev_info(&pdev->dev, "Supports FW dump capability\n"); } -- cgit v1.2.1 From c4d33e24b650e3fc3659b8fafe3e88ead731b658 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 4 Feb 2015 14:37:34 +0100 Subject: tun: Use static attribute groups for sysfs entries Instead of manual calls of device_create_file() and device_remove_files(), assign the static attribute groups to netdev groups array. This simplifies the code and avoids the possible races. Signed-off-by: Takashi Iwai Signed-off-by: David S. Miller --- drivers/net/tun.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index be196e89ab6c..3ff8cd7bf74d 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1565,6 +1565,17 @@ static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL); static DEVICE_ATTR(owner, 0444, tun_show_owner, NULL); static DEVICE_ATTR(group, 0444, tun_show_group, NULL); +static struct attribute *tun_dev_attrs[] = { + &dev_attr_tun_flags.attr, + &dev_attr_owner.attr, + &dev_attr_group.attr, + NULL +}; + +static const struct attribute_group tun_attr_group = { + .attrs = tun_dev_attrs +}; + static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) { struct tun_struct *tun; @@ -1645,6 +1656,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) dev_net_set(dev, net); dev->rtnl_link_ops = &tun_link_ops; dev->ifindex = tfile->ifindex; + dev->sysfs_groups[0] = &tun_attr_group; tun = netdev_priv(dev); tun->dev = dev; @@ -1680,11 +1692,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) err = register_netdevice(tun->dev); if (err < 0) goto err_detach; - - if (device_create_file(&tun->dev->dev, &dev_attr_tun_flags) || - device_create_file(&tun->dev->dev, &dev_attr_owner) || - device_create_file(&tun->dev->dev, &dev_attr_group)) - pr_err("Failed to create tun sysfs files\n"); } netif_carrier_on(tun->dev); -- cgit v1.2.1 From 27b917e54bed7156c2b0249969ace34a5f585626 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 4 Feb 2015 14:38:55 +0100 Subject: xen-netfront: Use static attribute groups for sysfs entries Instead of manual calls of device_create_file() and device_remove_files(), assign the static attribute groups to netdev groups array. This simplifies the code and avoids the possible races. Signed-off-by: Takashi Iwai Acked-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 62 ++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 46 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 7cfa6c027c0c..e9b960f0ff32 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -219,11 +219,7 @@ static grant_ref_t xennet_get_rx_ref(struct netfront_queue *queue, } #ifdef CONFIG_SYSFS -static int xennet_sysfs_addif(struct net_device *netdev); -static void xennet_sysfs_delif(struct net_device *netdev); -#else /* !CONFIG_SYSFS */ -#define xennet_sysfs_addif(dev) (0) -#define xennet_sysfs_delif(dev) do { } while (0) +static const struct attribute_group xennet_dev_group; #endif static bool xennet_can_sg(struct net_device *dev) @@ -1317,20 +1313,15 @@ static int netfront_probe(struct xenbus_device *dev, info = netdev_priv(netdev); dev_set_drvdata(&dev->dev, info); - +#ifdef CONFIG_SYSFS + info->netdev->sysfs_groups[0] = &xennet_dev_group; +#endif err = register_netdev(info->netdev); if (err) { pr_warn("%s: register_netdev err=%d\n", __func__, err); goto fail; } - err = xennet_sysfs_addif(info->netdev); - if (err) { - unregister_netdev(info->netdev); - pr_warn("%s: add sysfs failed err=%d\n", __func__, err); - goto fail; - } - return 0; fail: @@ -2094,39 +2085,20 @@ static ssize_t store_rxbuf(struct device *dev, return len; } -static struct device_attribute xennet_attrs[] = { - __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf), - __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf), - __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf, NULL), -}; +static DEVICE_ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf); +static DEVICE_ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf); +static DEVICE_ATTR(rxbuf_cur, S_IRUGO, show_rxbuf, NULL); -static int xennet_sysfs_addif(struct net_device *netdev) -{ - int i; - int err; - - for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) { - err = device_create_file(&netdev->dev, - &xennet_attrs[i]); - if (err) - goto fail; - } - return 0; - - fail: - while (--i >= 0) - device_remove_file(&netdev->dev, &xennet_attrs[i]); - return err; -} - -static void xennet_sysfs_delif(struct net_device *netdev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) - device_remove_file(&netdev->dev, &xennet_attrs[i]); -} +static struct attribute *xennet_dev_attrs[] = { + &dev_attr_rxbuf_min.attr, + &dev_attr_rxbuf_max.attr, + &dev_attr_rxbuf_cur.attr, + NULL +}; +static const struct attribute_group xennet_dev_group = { + .attrs = xennet_dev_attrs +}; #endif /* CONFIG_SYSFS */ static int xennet_remove(struct xenbus_device *dev) @@ -2140,8 +2112,6 @@ static int xennet_remove(struct xenbus_device *dev) xennet_disconnect_backend(info); - xennet_sysfs_delif(info->netdev); - unregister_netdev(info->netdev); for (i = 0; i < num_queues; ++i) { -- cgit v1.2.1 From 7af348be47fd2df5d276add2167b5838d48ba044 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 15:56:58 +0100 Subject: net: ep93xx_eth: Delete unnecessary checks before the function call "kfree" The kfree() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/ethernet/cirrus/ep93xx_eth.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c index 3a12c096ea1c..de9f7c97d916 100644 --- a/drivers/net/ethernet/cirrus/ep93xx_eth.c +++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c @@ -475,8 +475,7 @@ static void ep93xx_free_buffers(struct ep93xx_priv *ep) if (d) dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_FROM_DEVICE); - if (ep->rx_buf[i] != NULL) - kfree(ep->rx_buf[i]); + kfree(ep->rx_buf[i]); } for (i = 0; i < TX_QUEUE_ENTRIES; i++) { @@ -486,8 +485,7 @@ static void ep93xx_free_buffers(struct ep93xx_priv *ep) if (d) dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_TO_DEVICE); - if (ep->tx_buf[i] != NULL) - kfree(ep->tx_buf[i]); + kfree(ep->tx_buf[i]); } dma_free_coherent(dev, sizeof(struct ep93xx_descs), ep->descs, -- cgit v1.2.1 From db79a621835ee91d3e10177abd97f48e0a4dcf9b Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 4 Feb 2015 17:00:04 +0100 Subject: vxlan: Only set has-GBP bit in header if any other bits would be set This allows for a VXLAN-GBP socket to talk to a Linux VXLAN socket by not setting any of the bits. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index c184717e8b28..d08072c10aa9 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1667,6 +1667,9 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags, { struct vxlanhdr_gbp *gbp; + if (!md->gbp) + return; + gbp = (struct vxlanhdr_gbp *)vxh; vxh->vx_flags |= htonl(VXLAN_HF_GBP); -- cgit v1.2.1 From 4134069f3ea6cd96903e426bd3dfb9bb44165357 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Feb 2015 11:15:24 +0100 Subject: hso: Use static attribute groups for sysfs entry Pass the static attribute groups and the driver data via tty_port_register_device_attr() instead of manual device_create_file() and device_remove_file() calls. Signed-off-by: Takashi Iwai Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 7833bd1d9791..6b8efcabb816 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -531,6 +531,13 @@ static ssize_t hso_sysfs_show_porttype(struct device *dev, } static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); +static struct attribute *hso_serial_dev_attrs[] = { + &dev_attr_hsotype.attr, + NULL +}; + +ATTRIBUTE_GROUPS(hso_serial_dev); + static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb) { int idx; @@ -2236,9 +2243,6 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) static void hso_serial_tty_unregister(struct hso_serial *serial) { - if (serial->parent->dev) - device_remove_file(serial->parent->dev, &dev_attr_hsotype); - tty_unregister_device(tty_drv, serial->minor); } @@ -2274,11 +2278,10 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, goto exit; /* register our minor number */ - serial->parent->dev = tty_port_register_device(&serial->port, tty_drv, - minor, &serial->parent->interface->dev); + serial->parent->dev = tty_port_register_device_attr(&serial->port, + tty_drv, minor, &serial->parent->interface->dev, + serial->parent, hso_serial_dev_groups); dev = serial->parent->dev; - dev_set_drvdata(dev, serial->parent); - i = device_create_file(dev, &dev_attr_hsotype); /* fill in specific data for later use */ serial->minor = minor; -- cgit v1.2.1 From e8a308affcd79d95dad111f7872e43e9f73abb3b Mon Sep 17 00:00:00 2001 From: Kiran Padwal Date: Thu, 5 Feb 2015 17:01:37 +0530 Subject: ARCNET: Add missing error check for devm_kzalloc This patch add a missing check on the return value of devm_kzalloc, which would cause a NULL pointer dereference in a OOM situation. Signed-off-by: Kiran Padwal Signed-off-by: David S. Miller --- drivers/net/arcnet/com20020-pci.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 6c99ff0b0bdd..945f532078e9 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -78,6 +78,9 @@ static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *i priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + ci = (struct com20020_pci_card_info *)id->driver_data; priv->ci = ci; -- cgit v1.2.1 From da19fcd0d85f36420f578fe6dfe7a2a581b4fa6e Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 15:06:33 +0000 Subject: hyperv: fix sparse warnings this patch fixes following sparse warnings: netvsc.c:688:5: warning: symbol 'netvsc_copy_to_send_buf' was not declared. Should it be static? rndis_filter.c:627:5: warning: symbol 'rndis_filter_set_offload_params' was not declared. Should it be static? rndis_filter.c:702:5: warning: symbol 'rndis_filter_set_rss_param' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 6 +++--- drivers/net/hyperv/rndis_filter.c | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 58bb4102afac..208eb05446ba 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -685,9 +685,9 @@ static u32 netvsc_get_next_send_section(struct netvsc_device *net_device) return ret_val; } -u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device, - unsigned int section_index, - struct hv_netvsc_packet *packet) +static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device, + unsigned int section_index, + struct hv_netvsc_packet *packet) { char *start = net_device->send_buf; char *dest = (start + (section_index * net_device->send_section_size)); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 7bd83870b2a7..7816d98bdddc 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -624,7 +624,8 @@ cleanup: return ret; } -int rndis_filter_set_offload_params(struct hv_device *hdev, +static int +rndis_filter_set_offload_params(struct hv_device *hdev, struct ndis_offload_params *req_offloads) { struct netvsc_device *nvdev = hv_get_drvdata(hdev); @@ -699,7 +700,7 @@ u8 netvsc_hash_key[HASH_KEYLEN] = { 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa }; -int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue) +static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue) { struct net_device *ndev = rdev->net_dev->ndev; struct rndis_request *request; -- cgit v1.2.1 From 4a95b6d0a73e6ca38211e751b982a9665e108ff5 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 15:20:09 +0000 Subject: chelsio: cxgb4: fix sparse warning this patch fixes following sparse warning: cxgb4_dcb.c:25:6: warning: symbol 'dcb_ver_array' was not declared. Should it be static? Alongside making it const. Signed-off-by: Lad, Prabhakar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index b65a5bda3195..6074680bc985 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -22,7 +22,7 @@ /* DCBx version control */ -char *dcb_ver_array[] = { +static const char * const dcb_ver_array[] = { "Unknown", "DCBx-CIN", "DCBx-CEE 1.01", -- cgit v1.2.1 From bc0ee163732bbb3e1b72a629726713e3ddfd4e61 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 15:24:43 +0000 Subject: be2net: fix sparse warning this patch fixes following sparse warning: be_cmds.c:2750:5: warning: symbol 'be_cmd_set_qos' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 4bd425ea3421..b5aa77284508 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2747,7 +2747,7 @@ err: return status; } -int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain) +static int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain) { struct be_mcc_wrb *wrb; struct be_cmd_req_set_qos *req; -- cgit v1.2.1 From a20667bf7d1f76e20c42812e69b6eb1d471a3d49 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 15:29:55 +0000 Subject: enic: enic_ethtool: fix sparse warning this patch fixes following sparse warning: enic_ethtool.c:95:6: warning: symbol 'enic_intr_coal_set_rx' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index 0c396c1f55dc..28d9ca675a27 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -92,7 +92,7 @@ static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats); static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats); static const unsigned int enic_n_gen_stats = ARRAY_SIZE(enic_gen_stats); -void enic_intr_coal_set_rx(struct enic *enic, u32 timer) +static void enic_intr_coal_set_rx(struct enic *enic, u32 timer) { int i; int intr; -- cgit v1.2.1 From 57ae84a0099a767c2cc5947d642b3eeabc6f9d68 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 15:34:13 +0000 Subject: enic: enic_main: fix sparse warnings this patch fixes following sparse warnings: enic_main.c:92:28: warning: symbol 'mod_table' was not declared. Should it be static? enic_main.c:109:28: warning: symbol 'mod_range' was not declared. Should it be static? enic_main.c:1306:5: warning: symbol 'enic_busy_poll' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index ee44c827164d..9cbe038a388e 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -89,7 +89,7 @@ MODULE_DEVICE_TABLE(pci, enic_id_table); * coalescing timer values * {rx_rate in Mbps, mapping percentage of the range} */ -struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = { +static struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = { {4000, 0}, {4400, 10}, {5060, 20}, @@ -106,7 +106,7 @@ struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = { /* This table helps the driver to pick different ranges for rx coalescing * timer depending on the link speed. */ -struct enic_intr_mod_range mod_range[ENIC_MAX_LINK_SPEEDS] = { +static struct enic_intr_mod_range mod_range[ENIC_MAX_LINK_SPEEDS] = { {0, 0}, /* 0 - 4 Gbps */ {0, 3}, /* 4 - 10 Gbps */ {3, 6}, /* 10 - 40 Gbps */ @@ -1303,7 +1303,7 @@ static void enic_set_rx_cpu_rmap(struct enic *enic) #endif /* CONFIG_RFS_ACCEL */ #ifdef CONFIG_NET_RX_BUSY_POLL -int enic_busy_poll(struct napi_struct *napi) +static int enic_busy_poll(struct napi_struct *napi) { struct net_device *netdev = napi->dev; struct enic *enic = netdev_priv(netdev); -- cgit v1.2.1 From 1444c301a42217335d21fd3704baa34e72a1e6bf Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 15:47:17 +0000 Subject: net: bnx2x: fix sparse warnings this patch fixes following sparse warnings: bnx2x_main.c:9172:6: warning: symbol 'bnx2x_stop_ptp' was not declared. Should it be static? bnx2x_main.c:13321:6: warning: symbol 'bnx2x_register_phc' was not declared. Should it be static? bnx2x_main.c:14638:5: warning: symbol 'bnx2x_enable_ptp_packets' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 0758c8bef4ba..7155e1d2c208 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9169,7 +9169,7 @@ static void bnx2x_disable_ptp(struct bnx2x *bp) } /* Called during unload, to stop PTP-related stuff */ -void bnx2x_stop_ptp(struct bnx2x *bp) +static void bnx2x_stop_ptp(struct bnx2x *bp) { /* Cancel PTP work queue. Should be done after the Tx queues are * drained to prevent additional scheduling. @@ -13318,7 +13318,7 @@ static int bnx2x_ptp_enable(struct ptp_clock_info *ptp, return -ENOTSUPP; } -void bnx2x_register_phc(struct bnx2x *bp) +static void bnx2x_register_phc(struct bnx2x *bp) { /* Fill the ptp_clock_info struct and register PTP clock*/ bp->ptp_clock_info.owner = THIS_MODULE; @@ -14635,7 +14635,7 @@ static int bnx2x_send_reset_timesync_ramrod(struct bnx2x *bp) return bnx2x_func_state_change(bp, &func_params); } -int bnx2x_enable_ptp_packets(struct bnx2x *bp) +static int bnx2x_enable_ptp_packets(struct bnx2x *bp) { struct bnx2x_queue_state_params q_params; int rc, i; -- cgit v1.2.1 From 8093b1c313a3328f8cef497aef863f8fd9c1bfdf Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 16:21:07 +0000 Subject: net/macb: fix sparse warning this patch fixes following sparse warning: macb.c:2038:26: warning: symbol 'gem_ethtool_ops' was not declared. Should it be static? Alongside drops exporting of gem_ethtool_ops as there is no need. Signed-off-by: Lad, Prabhakar Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 4f7bd13796b8..ad76b8e35a00 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2035,7 +2035,7 @@ const struct ethtool_ops macb_ethtool_ops = { }; EXPORT_SYMBOL_GPL(macb_ethtool_ops); -const struct ethtool_ops gem_ethtool_ops = { +static const struct ethtool_ops gem_ethtool_ops = { .get_settings = macb_get_settings, .set_settings = macb_set_settings, .get_regs_len = macb_get_regs_len, @@ -2046,7 +2046,6 @@ const struct ethtool_ops gem_ethtool_ops = { .get_strings = gem_get_ethtool_strings, .get_sset_count = gem_get_sset_count, }; -EXPORT_SYMBOL_GPL(gem_ethtool_ops); int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { -- cgit v1.2.1 From 38741d50eb45554897e288f4b5ff2815e202c8aa Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 13:38:07 +0000 Subject: xen-netback: fix sparse warning this patch fixes following sparse warning: interface.c:83:5: warning: symbol 'xenvif_poll' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Acked-by: Wei Liu Signed-off-by: David S. Miller --- drivers/net/xen-netback/interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 037f74f0fcf6..2b2484b4cc29 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -80,7 +80,7 @@ static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -int xenvif_poll(struct napi_struct *napi, int budget) +static int xenvif_poll(struct napi_struct *napi, int budget) { struct xenvif_queue *queue = container_of(napi, struct xenvif_queue, napi); -- cgit v1.2.1 From 2ca292d968ef20cb04f31192d1f626bd8d782960 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 13:56:09 +0000 Subject: vxge: fix sparse warning this patch fixes following sparse warning: vxge-config.c:4640:30: warning: Using plain integer as NULL pointer Signed-off-by: Lad, Prabhakar Signed-off-by: David S. Miller --- drivers/net/ethernet/neterion/vxge/vxge-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c index 2bbd01fcb9b0..6223930a8155 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-config.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c @@ -4637,7 +4637,7 @@ static void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id) vpath->ringh = NULL; vpath->fifoh = NULL; memset(&vpath->vpath_handles, 0, sizeof(struct list_head)); - vpath->stats_block = 0; + vpath->stats_block = NULL; vpath->hw_stats = NULL; vpath->hw_stats_sav = NULL; vpath->sw_stats = NULL; -- cgit v1.2.1 From 33a44c2873ba64c54d11a9364b6b43271761d245 Mon Sep 17 00:00:00 2001 From: Matthew Vick Date: Tue, 27 Jan 2015 02:33:26 +0000 Subject: fm10k: Validate VLAN ID in fm10k_update_xc_addr_pf Currently, fm10k_update_xc_addr_pf has an issue where it does not properly drop the upper-most four bits of the VLAN ID due to type promotion. Resolve the issue not by masking off the bits, but by throwing an error if the VLAN ID is out-of-bounds. Reported-by: Rasmus Villemoes Signed-off-by: Matthew Vick Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_pf.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c index 275423d4f777..7e4711958e46 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c @@ -330,13 +330,10 @@ static s32 fm10k_update_xc_addr_pf(struct fm10k_hw *hw, u16 glort, struct fm10k_mac_update mac_update; u32 msg[5]; - /* if glort is not valid return error */ - if (!fm10k_glort_valid_pf(hw, glort)) + /* if glort or vlan are not valid return error */ + if (!fm10k_glort_valid_pf(hw, glort) || vid >= FM10K_VLAN_TABLE_VID_MAX) return FM10K_ERR_PARAM; - /* drop upper 4 bits of VLAN ID */ - vid = (vid << 4) >> 4; - /* record fields */ mac_update.mac_lower = cpu_to_le32(((u32)mac[2] << 24) | ((u32)mac[3] << 16) | -- cgit v1.2.1 From f4a80f1ef7ba70f24d28f78706965f9871ac1d9f Mon Sep 17 00:00:00 2001 From: Matthew Vick Date: Tue, 27 Jan 2015 03:39:25 +0000 Subject: fm10k: Resolve compile warnings with W=1 Fix two cases where variables are being set but not used. Signed-off-by: Matthew Vick Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_mbx.c | 5 ++--- drivers/net/ethernet/intel/fm10k/fm10k_ptp.c | 3 --- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c index 14a4ea795c01..9f5457c9e627 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c @@ -1194,12 +1194,11 @@ static s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw, { const enum fm10k_mbx_state state = mbx->state; const u32 *hdr = &mbx->mbx_hdr; - u16 head, tail; + u16 head; s32 err; - /* we will need to pull all of the fields for verification */ + /* we will need to pull the header field for verification */ head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); - tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL); /* We should not be receiving disconnect if Rx is incomplete */ if (mbx->pushed) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c b/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c index 7822809436a3..d966044e017a 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c @@ -57,7 +57,6 @@ void fm10k_ts_tx_enqueue(struct fm10k_intfc *interface, struct sk_buff *skb) struct sk_buff_head *list = &interface->ts_tx_skb_queue; struct sk_buff *clone; unsigned long flags; - __le16 dglort; /* create clone for us to return on the Tx path */ clone = skb_clone_sk(skb); @@ -65,8 +64,6 @@ void fm10k_ts_tx_enqueue(struct fm10k_intfc *interface, struct sk_buff *skb) return; FM10K_CB(clone)->ts_tx_timeout = jiffies + FM10K_TS_TX_TIMEOUT; - dglort = FM10K_CB(clone)->fi.w.dglort; - spin_lock_irqsave(&list->lock, flags); /* attempt to locate any buffers with the same dglort, -- cgit v1.2.1 From 7ddbde3f74c08fadb729513cf305f5f201aa1feb Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Sat, 6 Dec 2014 05:59:21 +0000 Subject: ixgbe: cleanup sparse errors in new ixgbe_x550.c file This patch cleans up prototypes that should have been defined as static. Signed-off-by: Don Skidmore Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 65 ++++++++++++++------------- 1 file changed, 35 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index ffdd1231f419..fcba952af6e2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -80,7 +80,7 @@ static s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, * Initializes the EEPROM parameters ixgbe_eeprom_info within the * ixgbe_hw struct in order to set up EEPROM access. **/ -s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw) +static s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw) { struct ixgbe_eeprom_info *eeprom = &hw->eeprom; u32 eec; @@ -110,8 +110,8 @@ s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw) * @device_type: 3 bit device type * @phy_data: Pointer to read data from the register **/ -s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, - u32 device_type, u32 *data) +static s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u32 *data) { u32 i, command, error; @@ -158,7 +158,8 @@ s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, * * Reads a 16 bit word from the EEPROM using the hostif. **/ -s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) +static s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, + u16 *data) { s32 status; struct ixgbe_hic_read_shadow_ram buffer; @@ -193,8 +194,8 @@ s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) * * Reads a 16 bit word(s) from the EEPROM using the hostif. **/ -s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw, - u16 offset, u16 words, u16 *data) +static s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw, + u16 offset, u16 words, u16 *data) { struct ixgbe_hic_read_shadow_ram buffer; u32 current_word = 0; @@ -331,7 +332,8 @@ static s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr, * * Returns a negative error code on error, or the 16-bit checksum **/ -s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size) +static s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, + u32 buffer_size) { u16 eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1]; u16 *local_buffer; @@ -407,7 +409,7 @@ s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size) * * Returns a negative error code on error, or the 16-bit checksum **/ -s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw) +static s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw) { return ixgbe_calc_checksum_X550(hw, NULL, 0); } @@ -419,7 +421,7 @@ s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw) * * Reads a 16 bit word from the EEPROM using the hostif. **/ -s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) +static s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) { s32 status = 0; @@ -440,7 +442,8 @@ s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) * Performs checksum calculation and validates the EEPROM checksum. If the * caller does not need checksum_val, the value can be NULL. **/ -s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val) +static s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, + u16 *checksum_val) { s32 status; u16 checksum; @@ -489,7 +492,8 @@ s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val) * * Write a 16 bit word to the EEPROM using the hostif. **/ -s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 data) +static s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, + u16 data) { s32 status; struct ixgbe_hic_write_shadow_ram buffer; @@ -517,7 +521,7 @@ s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 data) * * Write a 16 bit word to the EEPROM using the hostif. **/ -s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data) +static s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data) { s32 status = 0; @@ -537,7 +541,7 @@ s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data) * * Issue a shadow RAM dump to FW to copy EEPROM from shadow RAM to the flash. **/ -s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) +static s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) { s32 status = 0; union ixgbe_hic_hdr2 buffer; @@ -560,7 +564,7 @@ s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) * checksum and updates the EEPROM and instructs the hardware to update * the flash. **/ -s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) +static s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) { s32 status; u16 checksum = 0; @@ -600,8 +604,9 @@ s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) * * Write a 16 bit word(s) to the EEPROM using the hostif. **/ -s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw, - u16 offset, u16 words, u16 *data) +static s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw, + u16 offset, u16 words, + u16 *data) { s32 status = 0; u32 i = 0; @@ -630,7 +635,7 @@ s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw, /** ixgbe_init_mac_link_ops_X550em - init mac link function pointers * @hw: pointer to hardware structure **/ -void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw) +static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; @@ -647,7 +652,7 @@ void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw) /** ixgbe_setup_sfp_modules_X550em - Setup SFP module * @hw: pointer to hardware structure */ -s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) +static s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) { bool setup_linear; u16 reg_slice, edc_mode; @@ -703,9 +708,9 @@ s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) * @speed: pointer to link speed * @autoneg: true when autoneg or autotry is enabled **/ -s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *autoneg) +static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg) { /* SFP */ if (hw->phy.media_type == ixgbe_media_type_fiber) { @@ -740,8 +745,8 @@ s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, * @device_type: 3 bit device type * @data: Data to write to the register **/ -s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, - u32 device_type, u32 data) +static s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u32 data) { u32 i, command, error; @@ -904,7 +909,7 @@ static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) * * Configures the integrated KX4 PHY. **/ -s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw) +static s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw) { s32 status; u32 reg_val; @@ -942,7 +947,7 @@ s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw) * * Configures the integrated KR PHY. **/ -s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) +static s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) { s32 status; u32 reg_val; @@ -987,7 +992,7 @@ s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) * A return of a non-zero value indicates an error, and the base driver should * not report link up. **/ -s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw) +static s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw) { u32 status; u16 lasi, autoneg_status, speed; @@ -1049,7 +1054,7 @@ s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw) * set during init_shared_code because the PHY/SFP type was * not known. Perform the SFP init if necessary. **/ -s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) +static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) { struct ixgbe_phy_info *phy = &hw->phy; s32 ret_val; @@ -1102,7 +1107,7 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) * Returns the media type (fiber, copper, backplane) * */ -enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw) +static enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw) { enum ixgbe_media_type media_type; @@ -1129,7 +1134,7 @@ enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw) /** ixgbe_init_ext_t_x550em - Start (unstall) the external Base T PHY. ** @hw: pointer to hardware structure **/ -s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw) +static s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw) { u32 status; u16 reg; @@ -1202,7 +1207,7 @@ s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw) ** and clears all interrupts, perform a PHY reset, and perform a link (MAC) ** reset. **/ -s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) +static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) { ixgbe_link_speed link_speed; s32 status; -- cgit v1.2.1 From dec2e395fd35ebbd642c71b1c871298cba68cded Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Sat, 6 Dec 2014 09:18:57 +0000 Subject: ixgbe: allow multiple queues in SRIOV mode ixgbe_set_sriov_queues() has the logic to allow multiple queues, this patch just removes the limitation. Signed-off-by: Emil Tantilov Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index c76ba90ecc6e..a82a36bc789e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -101,9 +101,6 @@ static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter) adapter->dcb_cfg.num_tcs.pfc_tcs = 1; } - /* We do not support RSS w/ SR-IOV */ - adapter->ring_feature[RING_F_RSS].limit = 1; - /* Disable RSC when in SR-IOV mode */ adapter->flags2 &= ~(IXGBE_FLAG2_RSC_CAPABLE | IXGBE_FLAG2_RSC_ENABLED); -- cgit v1.2.1 From 2dc571aa61d3fe5b20167f16e0390e749cd4bb97 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Sat, 6 Dec 2014 09:19:02 +0000 Subject: ixgbevf: enable multiple queue support This patch enables multiple queues and RSS support for the VF. Maximum of 2 queues are supported due to available vectors. Signed-off-by: Emil Tantilov Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf.h | 1 + drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 8c44ab25f3fa..65cda344eec9 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -124,6 +124,7 @@ struct ixgbevf_ring { #define MAX_RX_QUEUES IXGBE_VF_MAX_RX_QUEUES #define MAX_TX_QUEUES IXGBE_VF_MAX_TX_QUEUES +#define IXGBEVF_MAX_RSS_QUEUES 2 #define IXGBEVF_DEFAULT_TXD 1024 #define IXGBEVF_DEFAULT_RXD 512 diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index fe2e10f40df8..92154ee87b42 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -1794,7 +1794,8 @@ static int ixgbevf_configure_dcb(struct ixgbevf_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; unsigned int def_q = 0; unsigned int num_tcs = 0; - unsigned int num_rx_queues = 1; + unsigned int num_rx_queues = adapter->num_rx_queues; + unsigned int num_tx_queues = adapter->num_tx_queues; int err; spin_lock_bh(&adapter->mbx_lock); @@ -1808,6 +1809,9 @@ static int ixgbevf_configure_dcb(struct ixgbevf_adapter *adapter) return err; if (num_tcs > 1) { + /* we need only one Tx queue */ + num_tx_queues = 1; + /* update default Tx ring register index */ adapter->tx_ring[0]->reg_idx = def_q; @@ -1816,7 +1820,8 @@ static int ixgbevf_configure_dcb(struct ixgbevf_adapter *adapter) } /* if we have a bad config abort request queue reset */ - if (adapter->num_rx_queues != num_rx_queues) { + if ((adapter->num_rx_queues != num_rx_queues) || + (adapter->num_tx_queues != num_tx_queues)) { /* force mailbox timeout to prevent further messages */ hw->mbx.timeout = 0; @@ -2181,8 +2186,19 @@ static void ixgbevf_set_num_queues(struct ixgbevf_adapter *adapter) return; /* we need as many queues as traffic classes */ - if (num_tcs > 1) + if (num_tcs > 1) { adapter->num_rx_queues = num_tcs; + } else { + u16 rss = min_t(u16, num_online_cpus(), IXGBEVF_MAX_RSS_QUEUES); + + switch (hw->api_version) { + case ixgbe_mbox_api_11: + adapter->num_rx_queues = rss; + adapter->num_tx_queues = rss; + default: + break; + } + } } /** -- cgit v1.2.1 From 9295edb472dcd85cb27d2f23dc2e6bae054a0228 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Sat, 6 Dec 2014 09:19:09 +0000 Subject: ixgbevf: add RSS support for X550 X550 provides RSS registers for configuring RSS per VF. This patch introduces ixgbevf_setup_vfmrqc() which uses the VFRETA, VFRSSRK and VFMRQC registers to configure RSS on X550. Signed-off-by: Emil Tantilov Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 35 +++++++++++++++++++++++ drivers/net/ethernet/intel/ixgbevf/regs.h | 10 +++++++ 2 files changed, 45 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 92154ee87b42..a5735263b1de 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -1584,6 +1584,39 @@ static void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter, reg_idx); } +static void ixgbevf_setup_vfmrqc(struct ixgbevf_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 vfmrqc = 0, vfreta = 0; + u32 rss_key[10]; + u16 rss_i = adapter->num_rx_queues; + int i, j; + + /* Fill out hash function seeds */ + netdev_rss_key_fill(rss_key, sizeof(rss_key)); + for (i = 0; i < 10; i++) + IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), rss_key[i]); + + /* Fill out redirection table */ + for (i = 0, j = 0; i < 64; i++, j++) { + if (j == rss_i) + j = 0; + vfreta = (vfreta << 8) | (j * 0x1); + if ((i & 3) == 3) + IXGBE_WRITE_REG(hw, IXGBE_VFRETA(i >> 2), vfreta); + } + + /* Perform hash on these packet types */ + vfmrqc |= IXGBE_VFMRQC_RSS_FIELD_IPV4 | + IXGBE_VFMRQC_RSS_FIELD_IPV4_TCP | + IXGBE_VFMRQC_RSS_FIELD_IPV6 | + IXGBE_VFMRQC_RSS_FIELD_IPV6_TCP; + + vfmrqc |= IXGBE_VFMRQC_RSSEN; + + IXGBE_WRITE_REG(hw, IXGBE_VFMRQC, vfmrqc); +} + static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, struct ixgbevf_ring *ring) { @@ -1640,6 +1673,8 @@ static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter) struct net_device *netdev = adapter->netdev; ixgbevf_setup_psrtype(adapter); + if (hw->mac.type >= ixgbe_mac_X550_vf) + ixgbevf_setup_vfmrqc(adapter); /* notify the PF of our intent to use this size of frame */ ixgbevf_rlpml_set_vf(hw, netdev->mtu + ETH_HLEN + ETH_FCS_LEN); diff --git a/drivers/net/ethernet/intel/ixgbevf/regs.h b/drivers/net/ethernet/intel/ixgbevf/regs.h index 09dd8f698bea..3e712fd6e695 100644 --- a/drivers/net/ethernet/intel/ixgbevf/regs.h +++ b/drivers/net/ethernet/intel/ixgbevf/regs.h @@ -69,6 +69,16 @@ #define IXGBE_VFGOTC_LSB 0x02020 #define IXGBE_VFGOTC_MSB 0x02024 #define IXGBE_VFMPRC 0x01034 +#define IXGBE_VFMRQC 0x3000 +#define IXGBE_VFRSSRK(x) (0x3100 + ((x) * 4)) +#define IXGBE_VFRETA(x) (0x3200 + ((x) * 4)) + +/* VFMRQC bits */ +#define IXGBE_VFMRQC_RSSEN 0x00000001 /* RSS Enable */ +#define IXGBE_VFMRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define IXGBE_VFMRQC_RSS_FIELD_IPV4 0x00020000 +#define IXGBE_VFMRQC_RSS_FIELD_IPV6 0x00100000 +#define IXGBE_VFMRQC_RSS_FIELD_IPV6_TCP 0x00200000 #define IXGBE_WRITE_FLUSH(a) (IXGBE_READ_REG(a, IXGBE_VFSTATUS)) -- cgit v1.2.1 From 42ce2c8ef6a9bc1459965f8a5a1e7a87049ef1af Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 10 Dec 2014 05:28:51 +0000 Subject: ixgbe: fix setting port VLAN This patch fixes couple of issues introduced by commit 2b509c0cd292 ("ixgbe: cleanup ixgbe_ndo_set_vf_vlan") - fix setting of the VLAN inside ixgbe_enable_port_vlan() - disable the "hide VLAN" bit in PFQDE when port VLAN is disabled Signed-off-by: Emil Tantilov Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index a82a36bc789e..7f37fe7269a7 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -1094,14 +1094,12 @@ static int ixgbe_enable_port_vlan(struct ixgbe_adapter *adapter, int vf, u16 vlan, u8 qos) { struct ixgbe_hw *hw = &adapter->hw; - int err = 0; + int err; - if (adapter->vfinfo[vf].pf_vlan) - err = ixgbe_set_vf_vlan(adapter, false, - adapter->vfinfo[vf].pf_vlan, - vf); + err = ixgbe_set_vf_vlan(adapter, true, vlan, vf); if (err) goto out; + ixgbe_set_vmvir(adapter, vlan, qos, vf); ixgbe_set_vmolr(hw, vf, false); if (adapter->vfinfo[vf].spoofchk_enabled) @@ -1140,6 +1138,11 @@ static int ixgbe_disable_port_vlan(struct ixgbe_adapter *adapter, int vf) hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf); if (adapter->vfinfo[vf].vlan_count) adapter->vfinfo[vf].vlan_count--; + + /* disable hide VLAN on X550 */ + if (hw->mac.type >= ixgbe_mac_X550) + ixgbe_write_qde(adapter, vf, IXGBE_QDE_ENABLE); + adapter->vfinfo[vf].pf_vlan = 0; adapter->vfinfo[vf].pf_qos = 0; -- cgit v1.2.1 From f9c9e488ce1e521ef1bf9f7b72a01c861475fcd3 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 10 Dec 2014 07:26:14 +0000 Subject: ixgbe: cleanup redundant default method set_rxpba My original patch 6a14ee0cfb19 "ixgbe: Add X550 support function pointers" accidental set a default value for this structure member twice. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index fcba952af6e2..84affca432b2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -1350,7 +1350,6 @@ static struct ixgbe_mac_operations mac_ops_X550 = { .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic, .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic, .setup_link = &ixgbe_setup_mac_link_X540, - .set_rxpba = &ixgbe_set_rxpba_generic, .get_link_capabilities = &ixgbe_get_copper_link_capabilities_generic, .setup_sfp = NULL, }; -- cgit v1.2.1 From 4dedadcbae35c84366c2543bce37e045b1665196 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Fri, 12 Dec 2014 05:37:30 +0000 Subject: ixgbe: Cleanup probe to remove redundant attempt to ID PHY We always identify the PHY in our reset_hw path anyway so there is no need to do it in get_invariants(). The reason I even noticed this is that for new hardware (X550em) we don't assign some methods until later in probe and calling phy.ops.read_reg could lead to a panic. Signed-off-by: Don Skidmore Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index ba54ff07b438..49395420c9b3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -55,9 +55,6 @@ s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; - /* Call PHY identify routine to get the phy type */ - ixgbe_identify_phy_generic(hw); - mac->mcft_size = IXGBE_X540_MC_TBL_SIZE; mac->vft_size = IXGBE_X540_VFT_TBL_SIZE; mac->num_rar_entries = IXGBE_X540_RAR_ENTRIES; -- cgit v1.2.1 From 3f207800a998fb1b0b36df251e826ee7682294f7 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Tue, 23 Dec 2014 07:40:34 +0000 Subject: ixgbe: add VXLAN offload support for X550 devices Add support VXLAN receive checksum offload in X550 hardware. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/Kconfig | 11 +++ drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 98 ++++++++++++++++++++++++++- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 5 ++ 4 files changed, 113 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 4d61ef50b465..f4ff465584a0 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -192,6 +192,17 @@ config IXGBE To compile this driver as a module, choose M here. The module will be called ixgbe. +config IXGBE_VXLAN + bool "Virtual eXtensible Local Area Network Support" + default n + depends on IXGBE && VXLAN && !(IXGBE=y && VXLAN=m) + ---help--- + This allows one to create VXLAN virtual interfaces that provide + Layer 2 Networks over Layer 3 Networks. VXLAN is often used + to tunnel virtual network infrastructure in virtualized environments. + Say Y here if you want to use Virtual eXtensible Local Area Network + (VXLAN) in the driver. + config IXGBE_HWMON bool "Intel(R) 10GbE PCI Express adapters HWMON support" default y diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 38fc64cf5dca..699117aff5fe 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -753,6 +753,7 @@ struct ixgbe_adapter { u32 timer_event_accumulator; u32 vferr_refcount; struct ixgbe_mac_addr *mac_table; + u16 vxlan_port; struct kobject *info_kobj; #ifdef CONFIG_IXGBE_HWMON struct hwmon_buff *ixgbe_hwmon_buff; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index e9e3a1eb9a97..6aa9b96b2e10 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -50,6 +50,7 @@ #include #include #include +#include #ifdef CONFIG_OF #include @@ -1396,12 +1397,23 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring, union ixgbe_adv_rx_desc *rx_desc, struct sk_buff *skb) { + __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; + __le16 hdr_info = rx_desc->wb.lower.lo_dword.hs_rss.hdr_info; + bool encap_pkt = false; + skb_checksum_none_assert(skb); /* Rx csum disabled */ if (!(ring->netdev->features & NETIF_F_RXCSUM)) return; + if ((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_VXLAN)) && + (hdr_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_TUNNEL >> 16))) { + encap_pkt = true; + skb->encapsulation = 1; + skb->ip_summed = CHECKSUM_NONE; + } + /* if IP and error */ if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_IPCS) && ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_IPE)) { @@ -1413,8 +1425,6 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring, return; if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_TCPE)) { - __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; - /* * 82599 errata, UDP frames with a 0 checksum can be marked as * checksum errors. @@ -1429,6 +1439,17 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring, /* It must be a TCP or UDP packet with a valid checksum */ skb->ip_summed = CHECKSUM_UNNECESSARY; + if (encap_pkt) { + if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_OUTERIPCS)) + return; + + if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_OUTERIPER)) { + ring->rx_stats.csum_err++; + return; + } + /* If we checked the outer header let the stack know */ + skb->csum_level = 1; + } } static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring, @@ -5627,6 +5648,10 @@ static int ixgbe_open(struct net_device *netdev) ixgbe_up_complete(adapter); +#if IS_ENABLED(CONFIG_IXGBE_VXLAN) + vxlan_get_rx_port(netdev); + +#endif return 0; err_set_queues: @@ -7771,6 +7796,64 @@ static int ixgbe_set_features(struct net_device *netdev, return 0; } +/** + * ixgbe_add_vxlan_port - Get notifications about VXLAN ports that come up + * @dev: The port's netdev + * @sa_family: Socket Family that VXLAN is notifiying us about + * @port: New UDP port number that VXLAN started listening to + **/ +static void ixgbe_add_vxlan_port(struct net_device *dev, sa_family_t sa_family, + __be16 port) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ixgbe_hw *hw = &adapter->hw; + u16 new_port = ntohs(port); + + if (sa_family == AF_INET6) + return; + + if (adapter->vxlan_port == new_port) { + netdev_info(dev, "Port %d already offloaded\n", new_port); + return; + } + + if (adapter->vxlan_port) { + netdev_info(dev, + "Hit Max num of UDP ports, not adding port %d\n", + new_port); + return; + } + + adapter->vxlan_port = new_port; + IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, new_port); +} + +/** + * ixgbe_del_vxlan_port - Get notifications about VXLAN ports that go away + * @dev: The port's netdev + * @sa_family: Socket Family that VXLAN is notifying us about + * @port: UDP port number that VXLAN stopped listening to + **/ +static void ixgbe_del_vxlan_port(struct net_device *dev, sa_family_t sa_family, + __be16 port) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ixgbe_hw *hw = &adapter->hw; + u16 new_port = ntohs(port); + + if (sa_family == AF_INET6) + return; + + if (adapter->vxlan_port != new_port) { + netdev_info(dev, "Port %d was not found, not deleting\n", + new_port); + return; + } + + adapter->vxlan_port = 0; + IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, 0); +} + static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, @@ -7982,6 +8065,8 @@ static const struct net_device_ops ixgbe_netdev_ops = { .ndo_bridge_getlink = ixgbe_ndo_bridge_getlink, .ndo_dfwd_add_station = ixgbe_fwd_add, .ndo_dfwd_del_station = ixgbe_fwd_del, + .ndo_add_vxlan_port = ixgbe_add_vxlan_port, + .ndo_del_vxlan_port = ixgbe_del_vxlan_port, }; /** @@ -8339,6 +8424,15 @@ skip_sriov: netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_SUPP_NOFCS; + switch (adapter->hw.mac.type) { + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + netdev->hw_enc_features |= NETIF_F_RXCSUM; + break; + default: + break; + } + #ifdef CONFIG_IXGBE_DCB netdev->dcbnl_ops = &dcbnl_ops; #endif diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index d101b25dc4b6..02b57bfe72b0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -399,6 +399,7 @@ struct ixgbe_thermal_sensor_data { #define IXGBE_WUPL 0x05900 #define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */ +#define IXGBE_VXLANCTRL 0x0000507C /* Rx filter VXLAN UDPPORT Register */ #define IXGBE_FHFT(_n) (0x09000 + ((_n) * 0x100)) /* Flex host filter table */ #define IXGBE_FHFT_EXT(_n) (0x09800 + ((_n) * 0x100)) /* Ext Flexible Host * Filter Table */ @@ -2122,6 +2123,7 @@ enum { #define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ #define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */ #define IXGBE_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ +#define IXGBE_RXD_STAT_OUTERIPCS 0x100 /* Cloud IP xsum calculated */ #define IXGBE_RXD_STAT_VEXT 0x200 /* 1st VLAN found */ #define IXGBE_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ #define IXGBE_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ @@ -2139,6 +2141,7 @@ enum { #define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */ #define IXGBE_RXDADV_ERR_MASK 0xfff00000 /* RDESC.ERRORS mask */ #define IXGBE_RXDADV_ERR_SHIFT 20 /* RDESC.ERRORS shift */ +#define IXGBE_RXDADV_ERR_OUTERIPER 0x04000000 /* CRC IP Header error */ #define IXGBE_RXDADV_ERR_FCEOFE 0x80000000 /* FCoEFe/IPE */ #define IXGBE_RXDADV_ERR_FCERR 0x00700000 /* FCERR/FDIRERR */ #define IXGBE_RXDADV_ERR_FDIR_LEN 0x00100000 /* FDIR Length error */ @@ -2227,6 +2230,8 @@ enum { #define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */ #define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */ #define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */ +#define IXGBE_RXDADV_PKTTYPE_VXLAN 0x00000800 /* VXLAN hdr present */ +#define IXGBE_RXDADV_PKTTYPE_TUNNEL 0x00010000 /* Tunnel type */ #define IXGBE_RXDADV_PKTTYPE_IPSEC_ESP 0x00001000 /* IPSec ESP */ #define IXGBE_RXDADV_PKTTYPE_IPSEC_AH 0x00002000 /* IPSec AH */ #define IXGBE_RXDADV_PKTTYPE_LINKSEC 0x00004000 /* LinkSec Encap */ -- cgit v1.2.1 From 39f35a370b59d65506bbfb8f9c1b9362d58b44fe Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 28 Jan 2015 03:21:13 +0000 Subject: ixgbevf: set vlan_features in a single write instead of several ORs Clean up the setting of vlan_features by enabling all features at once. Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index a5735263b1de..6d24aa57ce3c 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3873,11 +3873,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; - netdev->vlan_features |= NETIF_F_TSO; - netdev->vlan_features |= NETIF_F_TSO6; - netdev->vlan_features |= NETIF_F_IP_CSUM; - netdev->vlan_features |= NETIF_F_IPV6_CSUM; - netdev->vlan_features |= NETIF_F_SG; + netdev->vlan_features |= NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | + NETIF_F_SG; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; -- cgit v1.2.1 From d9bdb57f9c9eee20835a947f2b9ece1ed2ef8485 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 28 Jan 2015 03:21:18 +0000 Subject: ixgbevf: Fix ordering of shutdown to correctly disable Rx and Tx This patch updates the ordering of the shutdown path so that we attempt to shutdown the rings more gracefully. Basically the big changes are that we shutdown the main Rx filter in the case of Rx and we set the carrier_off state in the case of Tx so that packets stop being delivered from outside the driver. Then we shut down interrupts and NAPI. Finally we stop the rings from performing DMA and clean them. This is a bit more graceful than the previous path. CC: Alexander Duyck Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 38 ++++++++++------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 6d24aa57ce3c..a4b3d66b39a0 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -1957,6 +1957,10 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter) clear_bit(__IXGBEVF_DOWN, &adapter->state); ixgbevf_napi_enable_all(adapter); + /* clear any pending interrupts, may auto mask */ + IXGBE_READ_REG(hw, IXGBE_VTEICR); + ixgbevf_irq_enable(adapter); + /* enable transmits */ netif_tx_start_all_queues(netdev); @@ -1969,16 +1973,9 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter) void ixgbevf_up(struct ixgbevf_adapter *adapter) { - struct ixgbe_hw *hw = &adapter->hw; - ixgbevf_configure(adapter); ixgbevf_up_complete(adapter); - - /* clear any pending interrupts, may auto mask */ - IXGBE_READ_REG(hw, IXGBE_VTEICR); - - ixgbevf_irq_enable(adapter); } /** @@ -2085,17 +2082,20 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) ixgbevf_disable_rx_queue(adapter, adapter->rx_ring[i]); - netif_tx_disable(netdev); - - msleep(10); + usleep_range(10000, 20000); netif_tx_stop_all_queues(netdev); + /* call carrier off first to avoid false dev_watchdog timeouts */ + netif_carrier_off(netdev); + netif_tx_disable(netdev); + ixgbevf_irq_disable(adapter); ixgbevf_napi_disable_all(adapter); del_timer_sync(&adapter->watchdog_timer); + /* can't call flush scheduled work here because it can deadlock * if linkwatch_event tries to acquire the rtnl_lock which we are * holding */ @@ -2110,8 +2110,6 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter) IXGBE_TXDCTL_SWFLSH); } - netif_carrier_off(netdev); - if (!pci_channel_offline(adapter->pdev)) ixgbevf_reset(adapter); @@ -2995,10 +2993,6 @@ static int ixgbevf_open(struct net_device *netdev) if (!adapter->num_msix_vectors) return -ENOMEM; - /* disallow open during test */ - if (test_bit(__IXGBEVF_TESTING, &adapter->state)) - return -EBUSY; - if (hw->adapter_stopped) { ixgbevf_reset(adapter); /* if adapter is still stopped then PF isn't up and @@ -3011,6 +3005,12 @@ static int ixgbevf_open(struct net_device *netdev) } } + /* disallow open during test */ + if (test_bit(__IXGBEVF_TESTING, &adapter->state)) + return -EBUSY; + + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = ixgbevf_setup_all_tx_resources(adapter); if (err) @@ -3030,15 +3030,11 @@ static int ixgbevf_open(struct net_device *netdev) */ ixgbevf_map_rings_to_vectors(adapter); - ixgbevf_up_complete(adapter); - - /* clear any pending interrupts, may auto mask */ - IXGBE_READ_REG(hw, IXGBE_VTEICR); err = ixgbevf_request_irq(adapter); if (err) goto err_req_irq; - ixgbevf_irq_enable(adapter); + ixgbevf_up_complete(adapter); return 0; -- cgit v1.2.1 From e08400b707739f0eca1645413924743466ea70b8 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 28 Jan 2015 03:21:24 +0000 Subject: ixgbevf: Add code to check for Tx hang This patch adds code to allow for Tx hang checking. The idea is to provide more robust debug info in the event of a transmit unit hang. Similar to the logic in ixgbe. CC: Alexander Duyck Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf.h | 21 +++- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 113 ++++++++++++++++++---- 2 files changed, 115 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 65cda344eec9..65c2aee2a083 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -43,6 +43,13 @@ #define BP_EXTENDED_STATS #endif +#define IXGBE_MAX_TXD_PWR 14 +#define IXGBE_MAX_DATA_PER_TXD BIT(IXGBE_MAX_TXD_PWR) + +/* Tx Descriptors needed, worst case */ +#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IXGBE_MAX_DATA_PER_TXD) +#define DESC_NEEDED (MAX_SKB_FRAGS + 4) + /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ struct ixgbevf_tx_buffer { @@ -85,6 +92,18 @@ struct ixgbevf_rx_queue_stats { u64 csum_err; }; +enum ixgbevf_ring_state_t { + __IXGBEVF_TX_DETECT_HANG, + __IXGBEVF_HANG_CHECK_ARMED, +}; + +#define check_for_tx_hang(ring) \ + test_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) +#define set_check_for_tx_hang(ring) \ + set_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) +#define clear_check_for_tx_hang(ring) \ + clear_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) + struct ixgbevf_ring { struct ixgbevf_ring *next; struct net_device *netdev; @@ -101,7 +120,7 @@ struct ixgbevf_ring { struct ixgbevf_tx_buffer *tx_buffer_info; struct ixgbevf_rx_buffer *rx_buffer_info; }; - + unsigned long state; struct ixgbevf_stats stats; struct u64_stats_sync syncp; union { diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index a4b3d66b39a0..87f9f8686b6f 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -199,14 +199,64 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, /* tx_buffer must be completely set up in the transmit path */ } -#define IXGBE_MAX_TXD_PWR 14 -#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) +static u64 ixgbevf_get_tx_completed(struct ixgbevf_ring *ring) +{ + return ring->stats.packets; +} + +static u32 ixgbevf_get_tx_pending(struct ixgbevf_ring *ring) +{ + struct ixgbevf_adapter *adapter = netdev_priv(ring->netdev); + struct ixgbe_hw *hw = &adapter->hw; + + u32 head = IXGBE_READ_REG(hw, IXGBE_VFTDH(ring->reg_idx)); + u32 tail = IXGBE_READ_REG(hw, IXGBE_VFTDT(ring->reg_idx)); + + if (head != tail) + return (head < tail) ? + tail - head : (tail + ring->count - head); + + return 0; +} + +static inline bool ixgbevf_check_tx_hang(struct ixgbevf_ring *tx_ring) +{ + u32 tx_done = ixgbevf_get_tx_completed(tx_ring); + u32 tx_done_old = tx_ring->tx_stats.tx_done_old; + u32 tx_pending = ixgbevf_get_tx_pending(tx_ring); + + clear_check_for_tx_hang(tx_ring); -/* Tx Descriptors needed, worst case */ -#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IXGBE_MAX_DATA_PER_TXD) -#define DESC_NEEDED (MAX_SKB_FRAGS + 4) + /* Check for a hung queue, but be thorough. This verifies + * that a transmit has been completed since the previous + * check AND there is at least one packet pending. The + * ARMED bit is set to indicate a potential hang. + */ + if ((tx_done_old == tx_done) && tx_pending) { + /* make sure it is true for two checks in a row */ + return test_and_set_bit(__IXGBEVF_HANG_CHECK_ARMED, + &tx_ring->state); + } + /* reset the countdown */ + clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &tx_ring->state); + + /* update completed stats and continue */ + tx_ring->tx_stats.tx_done_old = tx_done; + + return false; +} + +/** + * ixgbevf_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ +static void ixgbevf_tx_timeout(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); -static void ixgbevf_tx_timeout(struct net_device *netdev); + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->reset_task); +} /** * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes @@ -311,6 +361,37 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, q_vector->tx.total_bytes += total_bytes; q_vector->tx.total_packets += total_packets; + if (check_for_tx_hang(tx_ring) && ixgbevf_check_tx_hang(tx_ring)) { + struct ixgbe_hw *hw = &adapter->hw; + union ixgbe_adv_tx_desc *eop_desc; + + eop_desc = tx_ring->tx_buffer_info[i].next_to_watch; + + pr_err("Detected Tx Unit Hang\n" + " Tx Queue <%d>\n" + " TDH, TDT <%x>, <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "tx_buffer_info[next_to_clean]\n" + " next_to_watch <%p>\n" + " eop_desc->wb.status <%x>\n" + " time_stamp <%lx>\n" + " jiffies <%lx>\n", + tx_ring->queue_index, + IXGBE_READ_REG(hw, IXGBE_VFTDH(tx_ring->reg_idx)), + IXGBE_READ_REG(hw, IXGBE_VFTDT(tx_ring->reg_idx)), + tx_ring->next_to_use, i, + eop_desc, (eop_desc ? eop_desc->wb.status : 0), + tx_ring->tx_buffer_info[i].time_stamp, jiffies); + + netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index); + + /* schedule immediate reset if we believe we hung */ + schedule_work(&adapter->reset_task); + + return true; + } + #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) && (ixgbevf_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD))) { @@ -1479,6 +1560,8 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, txdctl |= (1 << 8) | /* HTHRESH = 1 */ 32; /* PTHRESH = 32 */ + clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state); + IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl); /* poll to verify queue is enabled */ @@ -2643,6 +2726,12 @@ static void ixgbevf_watchdog(unsigned long data) if (test_bit(__IXGBEVF_DOWN, &adapter->state)) goto watchdog_short_circuit; + /* Force detection of hung controller */ + if (netif_carrier_ok(adapter->netdev)) { + for (i = 0; i < adapter->num_tx_queues; i++) + set_check_for_tx_hang(adapter->tx_ring[i]); + } + /* get one bit for every active tx/rx interrupt vector */ for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { struct ixgbevf_q_vector *qv = adapter->q_vector[i]; @@ -2656,18 +2745,6 @@ watchdog_short_circuit: schedule_work(&adapter->watchdog_task); } -/** - * ixgbevf_tx_timeout - Respond to a Tx Hang - * @netdev: network interface device structure - **/ -static void ixgbevf_tx_timeout(struct net_device *netdev) -{ - struct ixgbevf_adapter *adapter = netdev_priv(netdev); - - /* Do the reset outside of interrupt context */ - schedule_work(&adapter->reset_task); -} - static void ixgbevf_reset_task(struct work_struct *work) { struct ixgbevf_adapter *adapter; -- cgit v1.2.1 From e66c92ad5839ffd0ffd0ac7f7afd622151ef6272 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 28 Jan 2015 03:21:29 +0000 Subject: ixgbevf: rewrite watchdog task to function similar to igbvf This patch cleans up the logic dealing with link down/up by breaking down the link detection and up/down events into separate functions - similar to how these events are handled in other drivers. CC: Alexander Duyck Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf.h | 1 + drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 187 +++++++++++++--------- 2 files changed, 113 insertions(+), 75 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 65c2aee2a083..a41ab370278f 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -436,6 +436,7 @@ struct ixgbevf_adapter { bool link_up; spinlock_t mbx_lock; + unsigned long last_reset; struct work_struct watchdog_task; }; diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 87f9f8686b6f..c1100654a4be 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -2231,6 +2231,8 @@ void ixgbevf_reset(struct ixgbevf_adapter *adapter) memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); } + + adapter->last_reset = jiffies; } static int ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter, @@ -2684,7 +2686,8 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; int i; - if (!adapter->link_up) + if (test_bit(__IXGBEVF_DOWN, &adapter->state) || + test_bit(__IXGBEVF_RESETTING, &adapter->state)) return; UPDATE_VF_COUNTER_32bit(IXGBE_VFGPRC, adapter->stats.last_vfgprc, @@ -2714,17 +2717,45 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter) static void ixgbevf_watchdog(unsigned long data) { struct ixgbevf_adapter *adapter = (struct ixgbevf_adapter *)data; + + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->watchdog_task); +} + +static void ixgbevf_reset_task(struct work_struct *work) +{ + struct ixgbevf_adapter *adapter; + + adapter = container_of(work, struct ixgbevf_adapter, reset_task); + + /* If we're already down or resetting, just bail */ + if (test_bit(__IXGBEVF_DOWN, &adapter->state) || + test_bit(__IXGBEVF_RESETTING, &adapter->state)) + return; + + adapter->tx_timeout_count++; + + ixgbevf_reinit_locked(adapter); +} + +/* ixgbevf_check_hang_subtask - check for hung queues and dropped interrupts + * @adapter - pointer to the device adapter structure + * + * This function serves two purposes. First it strobes the interrupt lines + * in order to make certain interrupts are occurring. Secondly it sets the + * bits needed to check for TX hangs. As a result we should immediately + * determine if a hang has occurred. + */ +static void ixgbevf_check_hang_subtask(struct ixgbevf_adapter *adapter) +{ struct ixgbe_hw *hw = &adapter->hw; u32 eics = 0; int i; - /* - * Do the watchdog outside of interrupt context due to the lovely - * delays that some of the newer hardware requires - */ - - if (test_bit(__IXGBEVF_DOWN, &adapter->state)) - goto watchdog_short_circuit; + /* If we're down or resetting, just bail */ + if (test_bit(__IXGBEVF_DOWN, &adapter->state) || + test_bit(__IXGBEVF_RESETTING, &adapter->state)) + return; /* Force detection of hung controller */ if (netif_carrier_ok(adapter->netdev)) { @@ -2739,26 +2770,80 @@ static void ixgbevf_watchdog(unsigned long data) eics |= 1 << i; } + /* Cause software interrupt to ensure rings are cleaned */ IXGBE_WRITE_REG(hw, IXGBE_VTEICS, eics); +} -watchdog_short_circuit: - schedule_work(&adapter->watchdog_task); +/** + * ixgbevf_watchdog_update_link - update the link status + * @adapter - pointer to the device adapter structure + **/ +static void ixgbevf_watchdog_update_link(struct ixgbevf_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 link_speed = adapter->link_speed; + bool link_up = adapter->link_up; + s32 err; + + spin_lock_bh(&adapter->mbx_lock); + + err = hw->mac.ops.check_link(hw, &link_speed, &link_up, false); + + spin_unlock_bh(&adapter->mbx_lock); + + /* if check for link returns error we will need to reset */ + if (err && time_after(jiffies, adapter->last_reset + (10 * HZ))) { + schedule_work(&adapter->reset_task); + link_up = false; + } + + adapter->link_up = link_up; + adapter->link_speed = link_speed; } -static void ixgbevf_reset_task(struct work_struct *work) +/** + * ixgbevf_watchdog_link_is_up - update netif_carrier status and + * print link up message + * @adapter - pointer to the device adapter structure + **/ +static void ixgbevf_watchdog_link_is_up(struct ixgbevf_adapter *adapter) { - struct ixgbevf_adapter *adapter; - adapter = container_of(work, struct ixgbevf_adapter, reset_task); + struct net_device *netdev = adapter->netdev; - /* If we're already down or resetting, just bail */ - if (test_bit(__IXGBEVF_DOWN, &adapter->state) || - test_bit(__IXGBEVF_REMOVING, &adapter->state) || - test_bit(__IXGBEVF_RESETTING, &adapter->state)) + /* only continue if link was previously down */ + if (netif_carrier_ok(netdev)) return; - adapter->tx_timeout_count++; + dev_info(&adapter->pdev->dev, "NIC Link is Up %s\n", + (adapter->link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? + "10 Gbps" : + (adapter->link_speed == IXGBE_LINK_SPEED_1GB_FULL) ? + "1 Gbps" : + (adapter->link_speed == IXGBE_LINK_SPEED_100_FULL) ? + "100 Mbps" : + "unknown speed"); - ixgbevf_reinit_locked(adapter); + netif_carrier_on(netdev); +} + +/** + * ixgbevf_watchdog_link_is_down - update netif_carrier status and + * print link down message + * @adapter - pointer to the adapter structure + **/ +static void ixgbevf_watchdog_link_is_down(struct ixgbevf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + adapter->link_speed = 0; + + /* only continue if link was up previously */ + if (!netif_carrier_ok(netdev)) + return; + + dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); + + netif_carrier_off(netdev); } /** @@ -2770,11 +2855,7 @@ static void ixgbevf_watchdog_task(struct work_struct *work) struct ixgbevf_adapter *adapter = container_of(work, struct ixgbevf_adapter, watchdog_task); - struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; - u32 link_speed = adapter->link_speed; - bool link_up = adapter->link_up; - s32 need_reset; if (IXGBE_REMOVED(hw->hw_addr)) { if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) { @@ -2784,66 +2865,22 @@ static void ixgbevf_watchdog_task(struct work_struct *work) } return; } + ixgbevf_queue_reset_subtask(adapter); adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; - /* - * Always check the link on the watchdog because we have - * no LSC interrupt - */ - spin_lock_bh(&adapter->mbx_lock); - - need_reset = hw->mac.ops.check_link(hw, &link_speed, &link_up, false); - - spin_unlock_bh(&adapter->mbx_lock); - - if (need_reset) { - adapter->link_up = link_up; - adapter->link_speed = link_speed; - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - schedule_work(&adapter->reset_task); - goto pf_has_reset; - } - adapter->link_up = link_up; - adapter->link_speed = link_speed; + ixgbevf_watchdog_update_link(adapter); - if (link_up) { - if (!netif_carrier_ok(netdev)) { - char *link_speed_string; - switch (link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - link_speed_string = "10 Gbps"; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - link_speed_string = "1 Gbps"; - break; - case IXGBE_LINK_SPEED_100_FULL: - link_speed_string = "100 Mbps"; - break; - default: - link_speed_string = "unknown speed"; - break; - } - dev_info(&adapter->pdev->dev, - "NIC Link is Up, %s\n", link_speed_string); - netif_carrier_on(netdev); - netif_tx_wake_all_queues(netdev); - } - } else { - adapter->link_up = false; - adapter->link_speed = 0; - if (netif_carrier_ok(netdev)) { - dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - } - } + if (adapter->link_up) + ixgbevf_watchdog_link_is_up(adapter); + else + ixgbevf_watchdog_link_is_down(adapter); ixgbevf_update_stats(adapter); -pf_has_reset: + ixgbevf_check_hang_subtask(adapter); + /* Reset the timer */ if (!test_bit(__IXGBEVF_DOWN, &adapter->state) && !test_bit(__IXGBEVF_REMOVING, &adapter->state)) -- cgit v1.2.1 From 9ac5c5ccdbfd41c1dea802462a9b0abcfc106abc Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 28 Jan 2015 03:21:34 +0000 Subject: ixgbevf: combine all of the tasks into a single service task This change combines the reset and watchdog tasklets into a single task. The advantage of this is that we can avoid multiple schedules of the reset task when we have a reset event needed due to either the mailbox going down or transmit packets being present on a link down. CC: Alexander Duyck Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf.h | 13 +- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 140 +++++++++++++--------- 2 files changed, 87 insertions(+), 66 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index a41ab370278f..3a9b356dff01 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -367,8 +367,6 @@ struct ixgbevf_adapter { /* this field must be first, see ixgbevf_process_skb_fields */ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; - struct timer_list watchdog_timer; - struct work_struct reset_task; struct ixgbevf_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; /* Interrupt Throttle Rate */ @@ -398,8 +396,7 @@ struct ixgbevf_adapter { * thus the additional *_CAPABLE flags. */ u32 flags; -#define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1) - +#define IXGBEVF_FLAG_RESET_REQUESTED (u32)(1) #define IXGBEVF_FLAG_QUEUE_RESET_REQUESTED (u32)(1 << 2) struct msix_entry *msix_entries; @@ -435,10 +432,11 @@ struct ixgbevf_adapter { u32 link_speed; bool link_up; + struct timer_list service_timer; + struct work_struct service_task; + spinlock_t mbx_lock; unsigned long last_reset; - - struct work_struct watchdog_task; }; enum ixbgevf_state_t { @@ -447,7 +445,8 @@ enum ixbgevf_state_t { __IXGBEVF_DOWN, __IXGBEVF_DISABLED, __IXGBEVF_REMOVING, - __IXGBEVF_WORK_INIT, + __IXGBEVF_SERVICE_SCHED, + __IXGBEVF_SERVICE_INITED, }; enum ixgbevf_boards { diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index c1100654a4be..4186981e562d 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -98,6 +98,23 @@ static int debug = -1; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +static void ixgbevf_service_event_schedule(struct ixgbevf_adapter *adapter) +{ + if (!test_bit(__IXGBEVF_DOWN, &adapter->state) && + !test_bit(__IXGBEVF_REMOVING, &adapter->state) && + !test_and_set_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state)) + schedule_work(&adapter->service_task); +} + +static void ixgbevf_service_event_complete(struct ixgbevf_adapter *adapter) +{ + BUG_ON(!test_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state)); + + /* flush memory to make sure state is correct before next watchdog */ + smp_mb__before_atomic(); + clear_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state); +} + /* forward decls */ static void ixgbevf_queue_reset_subtask(struct ixgbevf_adapter *adapter); static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector); @@ -111,8 +128,8 @@ static void ixgbevf_remove_adapter(struct ixgbe_hw *hw) return; hw->hw_addr = NULL; dev_err(&adapter->pdev->dev, "Adapter removed\n"); - if (test_bit(__IXGBEVF_WORK_INIT, &adapter->state)) - schedule_work(&adapter->watchdog_task); + if (test_bit(__IXGBEVF_SERVICE_INITED, &adapter->state)) + ixgbevf_service_event_schedule(adapter); } static void ixgbevf_check_remove(struct ixgbe_hw *hw, u32 reg) @@ -246,6 +263,15 @@ static inline bool ixgbevf_check_tx_hang(struct ixgbevf_ring *tx_ring) return false; } +static void ixgbevf_tx_timeout_reset(struct ixgbevf_adapter *adapter) +{ + /* Do the reset outside of interrupt context */ + if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) { + adapter->flags |= IXGBEVF_FLAG_RESET_REQUESTED; + ixgbevf_service_event_schedule(adapter); + } +} + /** * ixgbevf_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure @@ -254,8 +280,7 @@ static void ixgbevf_tx_timeout(struct net_device *netdev) { struct ixgbevf_adapter *adapter = netdev_priv(netdev); - /* Do the reset outside of interrupt context */ - schedule_work(&adapter->reset_task); + ixgbevf_tx_timeout_reset(adapter); } /** @@ -387,7 +412,7 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index); /* schedule immediate reset if we believe we hung */ - schedule_work(&adapter->reset_task); + ixgbevf_tx_timeout_reset(adapter); return true; } @@ -1239,9 +1264,7 @@ static irqreturn_t ixgbevf_msix_other(int irq, void *data) hw->mac.get_link_status = 1; - if (!test_bit(__IXGBEVF_DOWN, &adapter->state) && - !test_bit(__IXGBEVF_REMOVING, &adapter->state)) - mod_timer(&adapter->watchdog_timer, jiffies); + ixgbevf_service_event_schedule(adapter); IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, adapter->eims_other); @@ -2051,7 +2074,7 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter) ixgbevf_init_last_counter_stats(adapter); hw->mac.get_link_status = 1; - mod_timer(&adapter->watchdog_timer, jiffies); + mod_timer(&adapter->service_timer, jiffies); } void ixgbevf_up(struct ixgbevf_adapter *adapter) @@ -2177,13 +2200,7 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter) ixgbevf_napi_disable_all(adapter); - del_timer_sync(&adapter->watchdog_timer); - - /* can't call flush scheduled work here because it can deadlock - * if linkwatch_event tries to acquire the rtnl_lock which we are - * holding */ - while (adapter->flags & IXGBE_FLAG_IN_WATCHDOG_TASK) - msleep(1); + del_timer_sync(&adapter->service_timer); /* disable transmits in the hardware now that interrupts are off */ for (i = 0; i < adapter->num_tx_queues; i++) { @@ -2711,22 +2728,25 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter) } /** - * ixgbevf_watchdog - Timer Call-back + * ixgbevf_service_timer - Timer Call-back * @data: pointer to adapter cast into an unsigned long **/ -static void ixgbevf_watchdog(unsigned long data) +static void ixgbevf_service_timer(unsigned long data) { struct ixgbevf_adapter *adapter = (struct ixgbevf_adapter *)data; - /* Do the reset outside of interrupt context */ - schedule_work(&adapter->watchdog_task); + /* Reset the timer */ + mod_timer(&adapter->service_timer, (HZ * 2) + jiffies); + + ixgbevf_service_event_schedule(adapter); } -static void ixgbevf_reset_task(struct work_struct *work) +static void ixgbevf_reset_subtask(struct ixgbevf_adapter *adapter) { - struct ixgbevf_adapter *adapter; + if (!(adapter->flags & IXGBEVF_FLAG_RESET_REQUESTED)) + return; - adapter = container_of(work, struct ixgbevf_adapter, reset_task); + adapter->flags &= ~IXGBEVF_FLAG_RESET_REQUESTED; /* If we're already down or resetting, just bail */ if (test_bit(__IXGBEVF_DOWN, &adapter->state) || @@ -2766,6 +2786,7 @@ static void ixgbevf_check_hang_subtask(struct ixgbevf_adapter *adapter) /* get one bit for every active tx/rx interrupt vector */ for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { struct ixgbevf_q_vector *qv = adapter->q_vector[i]; + if (qv->rx.ring || qv->tx.ring) eics |= 1 << i; } @@ -2793,7 +2814,7 @@ static void ixgbevf_watchdog_update_link(struct ixgbevf_adapter *adapter) /* if check for link returns error we will need to reset */ if (err && time_after(jiffies, adapter->last_reset + (10 * HZ))) { - schedule_work(&adapter->reset_task); + adapter->flags |= IXGBEVF_FLAG_RESET_REQUESTED; link_up = false; } @@ -2847,14 +2868,35 @@ static void ixgbevf_watchdog_link_is_down(struct ixgbevf_adapter *adapter) } /** - * ixgbevf_watchdog_task - worker thread to bring link up + * ixgbevf_watchdog_subtask - worker thread to bring link up + * @work: pointer to work_struct containing our data + **/ +static void ixgbevf_watchdog_subtask(struct ixgbevf_adapter *adapter) +{ + /* if interface is down do nothing */ + if (test_bit(__IXGBEVF_DOWN, &adapter->state) || + test_bit(__IXGBEVF_RESETTING, &adapter->state)) + return; + + ixgbevf_watchdog_update_link(adapter); + + if (adapter->link_up) + ixgbevf_watchdog_link_is_up(adapter); + else + ixgbevf_watchdog_link_is_down(adapter); + + ixgbevf_update_stats(adapter); +} + +/** + * ixgbevf_service_task - manages and runs subtasks * @work: pointer to work_struct containing our data **/ -static void ixgbevf_watchdog_task(struct work_struct *work) +static void ixgbevf_service_task(struct work_struct *work) { struct ixgbevf_adapter *adapter = container_of(work, struct ixgbevf_adapter, - watchdog_task); + service_task); struct ixgbe_hw *hw = &adapter->hw; if (IXGBE_REMOVED(hw->hw_addr)) { @@ -2867,27 +2909,11 @@ static void ixgbevf_watchdog_task(struct work_struct *work) } ixgbevf_queue_reset_subtask(adapter); - - adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; - - ixgbevf_watchdog_update_link(adapter); - - if (adapter->link_up) - ixgbevf_watchdog_link_is_up(adapter); - else - ixgbevf_watchdog_link_is_down(adapter); - - ixgbevf_update_stats(adapter); - + ixgbevf_reset_subtask(adapter); + ixgbevf_watchdog_subtask(adapter); ixgbevf_check_hang_subtask(adapter); - /* Reset the timer */ - if (!test_bit(__IXGBEVF_DOWN, &adapter->state) && - !test_bit(__IXGBEVF_REMOVING, &adapter->state)) - mod_timer(&adapter->watchdog_timer, - round_jiffies(jiffies + (2 * HZ))); - - adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; + ixgbevf_service_event_complete(adapter); } /** @@ -3994,17 +4020,17 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->priv_flags |= IFF_UNICAST_FLT; - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = ixgbevf_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; - if (IXGBE_REMOVED(hw->hw_addr)) { err = -EIO; goto err_sw_init; } - INIT_WORK(&adapter->reset_task, ixgbevf_reset_task); - INIT_WORK(&adapter->watchdog_task, ixgbevf_watchdog_task); - set_bit(__IXGBEVF_WORK_INIT, &adapter->state); + + setup_timer(&adapter->service_timer, &ixgbevf_service_timer, + (unsigned long)adapter); + + INIT_WORK(&adapter->service_task, ixgbevf_service_task); + set_bit(__IXGBEVF_SERVICE_INITED, &adapter->state); + clear_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state); err = ixgbevf_init_interrupt_scheme(adapter); if (err) @@ -4078,11 +4104,7 @@ static void ixgbevf_remove(struct pci_dev *pdev) adapter = netdev_priv(netdev); set_bit(__IXGBEVF_REMOVING, &adapter->state); - - del_timer_sync(&adapter->watchdog_timer); - - cancel_work_sync(&adapter->reset_task); - cancel_work_sync(&adapter->watchdog_task); + cancel_work_sync(&adapter->service_task); if (netdev->reg_state == NETREG_REGISTERED) unregister_netdev(netdev); @@ -4116,7 +4138,7 @@ static pci_ers_result_t ixgbevf_io_error_detected(struct pci_dev *pdev, struct net_device *netdev = pci_get_drvdata(pdev); struct ixgbevf_adapter *adapter = netdev_priv(netdev); - if (!test_bit(__IXGBEVF_WORK_INIT, &adapter->state)) + if (!test_bit(__IXGBEVF_SERVICE_INITED, &adapter->state)) return PCI_ERS_RESULT_DISCONNECT; rtnl_lock(); -- cgit v1.2.1 From 5b7f000ff94c77031a628f87b788b1a032f2d4d9 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 28 Jan 2015 07:03:38 +0000 Subject: ixgbe: add Tx anti spoofing support This patch enables the ethertype Anti-Spoofing feature for affected devices. It is configured such that LLDP packets sent by a VF will be dropped. Signed-off-by: Don Skidmore Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 2 ++ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 14 ++++++++++++++ drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 7 +++++++ drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 24 ++++++++++++++++++++++++ 4 files changed, 47 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 699117aff5fe..7dcbbec09a70 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -76,6 +76,8 @@ #define IXGBE_MAX_RXD 4096 #define IXGBE_MIN_RXD 64 +#define IXGBE_ETH_P_LLDP 0x88CC + /* flow control */ #define IXGBE_MIN_FCRTL 0x40 #define IXGBE_MAX_FCRTL 0x7FF80 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 6aa9b96b2e10..70cc4c5c0a01 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -3585,10 +3585,24 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter) /* Enable MAC Anti-Spoofing */ hw->mac.ops.set_mac_anti_spoofing(hw, (adapter->num_vfs != 0), adapter->num_vfs); + + /* Ensure LLDP is set for Ethertype Antispoofing if we will be + * calling set_ethertype_anti_spoofing for each VF in loop below + */ + if (hw->mac.ops.set_ethertype_anti_spoofing) + IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_LLDP), + (IXGBE_ETQF_FILTER_EN | /* enable filter */ + IXGBE_ETQF_TX_ANTISPOOF | /* tx antispoof */ + IXGBE_ETH_P_LLDP)); /* LLDP eth type */ + /* For VFs that have spoof checking turned off */ for (i = 0; i < adapter->num_vfs; i++) { if (!adapter->vfinfo[i].spoofchk_enabled) ixgbe_ndo_set_vf_spoofchk(adapter->netdev, i, false); + + /* enable ethertype anti spoofing if hw supports it */ + if (hw->mac.ops.set_ethertype_anti_spoofing) + hw->mac.ops.set_ethertype_anti_spoofing(hw, true, i); } } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 02b57bfe72b0..fc5ecee56ca8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -378,6 +378,8 @@ struct ixgbe_thermal_sensor_data { #define IXGBE_SPOOF_MACAS_MASK 0xFF #define IXGBE_SPOOF_VLANAS_MASK 0xFF00 #define IXGBE_SPOOF_VLANAS_SHIFT 8 +#define IXGBE_SPOOF_ETHERTYPEAS 0xFF000000 +#define IXGBE_SPOOF_ETHERTYPEAS_SHIFT 16 #define IXGBE_PFVFSPOOF_REG_COUNT 8 #define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */ @@ -1541,6 +1543,7 @@ enum { #define IXGBE_MAX_ETQF_FILTERS 8 #define IXGBE_ETQF_FCOE 0x08000000 /* bit 27 */ #define IXGBE_ETQF_BCN 0x10000000 /* bit 28 */ +#define IXGBE_ETQF_TX_ANTISPOOF 0x20000000 /* bit 29 */ #define IXGBE_ETQF_1588 0x40000000 /* bit 30 */ #define IXGBE_ETQF_FILTER_EN 0x80000000 /* bit 31 */ #define IXGBE_ETQF_POOL_ENABLE (1 << 26) /* bit 26 */ @@ -1566,6 +1569,9 @@ enum { #define IXGBE_ETQF_FILTER_FCOE 2 #define IXGBE_ETQF_FILTER_1588 3 #define IXGBE_ETQF_FILTER_FIP 4 +#define IXGBE_ETQF_FILTER_LLDP 5 +#define IXGBE_ETQF_FILTER_LACP 6 + /* VLAN Control Bit Masks */ #define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */ #define IXGBE_VLNCTRL_CFI 0x10000000 /* bit 28 */ @@ -3061,6 +3067,7 @@ struct ixgbe_mac_operations { s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8); s32 (*get_thermal_sensor_data)(struct ixgbe_hw *); s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw); + void (*set_ethertype_anti_spoofing)(struct ixgbe_hw *, bool, int); /* DMA Coalescing */ s32 (*dmac_config)(struct ixgbe_hw *hw); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 84affca432b2..50bf81908dd6 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -1300,6 +1300,28 @@ mac_reset_top: return status; } +/** ixgbe_set_ethertype_anti_spoofing_X550 - Enable/Disable Ethertype + * anti-spoofing + * @hw: pointer to hardware structure + * @enable: enable or disable switch for Ethertype anti-spoofing + * @vf: Virtual Function pool - VF Pool to set for Ethertype anti-spoofing + **/ +void ixgbe_set_ethertype_anti_spoofing_X550(struct ixgbe_hw *hw, bool enable, + int vf) +{ + int vf_target_reg = vf >> 3; + int vf_target_shift = vf % 8 + IXGBE_SPOOF_ETHERTYPEAS_SHIFT; + u32 pfvfspoof; + + pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg)); + if (enable) + pfvfspoof |= (1 << vf_target_shift); + else + pfvfspoof &= ~(1 << vf_target_shift); + + IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); +} + #define X550_COMMON_MAC \ .init_hw = &ixgbe_init_hw_generic, \ .start_hw = &ixgbe_start_hw_X540, \ @@ -1334,6 +1356,8 @@ mac_reset_top: .init_uta_tables = &ixgbe_init_uta_tables_generic, \ .set_mac_anti_spoofing = &ixgbe_set_mac_anti_spoofing, \ .set_vlan_anti_spoofing = &ixgbe_set_vlan_anti_spoofing, \ + .set_ethertype_anti_spoofing = \ + &ixgbe_set_ethertype_anti_spoofing_X550, \ .acquire_swfw_sync = &ixgbe_acquire_swfw_sync_X540, \ .release_swfw_sync = &ixgbe_release_swfw_sync_X540, \ .disable_rx_buff = &ixgbe_disable_rx_buff_generic, \ -- cgit v1.2.1 From d0311314d00298f83aa5450a1d4a92889e7cc2ea Mon Sep 17 00:00:00 2001 From: Troy Tan Date: Tue, 3 Feb 2015 11:15:17 -0600 Subject: rtlwifi: rtl8192ee: Fix handling of new style descriptors The hardware and firmware for the RTL8192EE utilize a FIFO list of descriptors. There were some problems with the initial implementation. The worst of these failed to detect that the FIFO was becoming full, which led to the device needing to be power cycled. As this condition is not relevant to most of the devices supported by rtlwifi, a callback routine was added to detect this situation. This patch implements the necessary changes in the pci handler, and the linkage into the appropriate rtl8192ee routine. Signed-off-by: Troy Tan Signed-off-by: Larry Finger Cc: Stable [V3.18] Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/pci.c | 31 +++++++++++++++++++++------- drivers/net/wireless/rtlwifi/rtl8192ee/sw.c | 3 +-- drivers/net/wireless/rtlwifi/rtl8192ee/trx.c | 20 ++++++++++++++++++ drivers/net/wireless/rtlwifi/rtl8192ee/trx.h | 1 + drivers/net/wireless/rtlwifi/wifi.h | 1 + 5 files changed, 46 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 846a2e6e34d8..88331d729b0e 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -578,6 +578,13 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) else entry = (u8 *)(&ring->desc[ring->idx]); + if (rtlpriv->cfg->ops->get_available_desc && + rtlpriv->cfg->ops->get_available_desc(hw, prio) <= 1) { + RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_DMESG, + "no available desc!\n"); + return; + } + if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx)) return; ring->idx = (ring->idx + 1) % ring->entries; @@ -641,10 +648,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) ieee80211_tx_status_irqsafe(hw, skb); - if ((ring->entries - skb_queue_len(&ring->queue)) - == 2) { + if ((ring->entries - skb_queue_len(&ring->queue)) <= 4) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n", prio, ring->idx, skb_queue_len(&ring->queue)); @@ -786,7 +792,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) rx_remained_cnt = rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw, hw_queue); - if (rx_remained_cnt < 1) + if (rx_remained_cnt == 0) return; } else { /* rx descriptor */ @@ -834,18 +840,18 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) else skb_reserve(skb, stats.rx_drvinfo_size + stats.rx_bufshift); - } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "skb->end - skb->tail = %d, len is %d\n", skb->end - skb->tail, len); - break; + dev_kfree_skb_any(skb); + goto new_trx_end; } /* handle command packet here */ if (rtlpriv->cfg->ops->rx_command_packet && rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) { dev_kfree_skb_any(skb); - goto end; + goto new_trx_end; } /* @@ -895,6 +901,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) } else { dev_kfree_skb_any(skb); } +new_trx_end: if (rtlpriv->use_new_trx_flow) { rtlpci->rx_ring[hw_queue].next_rx_rp += 1; rtlpci->rx_ring[hw_queue].next_rx_rp %= @@ -910,7 +917,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) rtlpriv->enter_ps = false; schedule_work(&rtlpriv->works.lps_change_work); } -end: if (rtlpriv->use_new_trx_flow) { _rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc, rxring_idx, @@ -1672,6 +1678,15 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, } } + if (rtlpriv->cfg->ops->get_available_desc && + rtlpriv->cfg->ops->get_available_desc(hw, hw_queue) == 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "get_available_desc fail\n"); + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, + flags); + return skb->len; + } + if (ieee80211_is_data_qos(fc)) { tid = rtl_get_tid(skb); if (sta) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c index 9b5a7d5be121..c31c6bfb536d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c @@ -113,8 +113,6 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw) RCR_HTC_LOC_CTRL | RCR_AMF | RCR_ACF | - RCR_ADF | - RCR_AICV | RCR_ACRC32 | RCR_AB | RCR_AM | @@ -241,6 +239,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = { .set_desc = rtl92ee_set_desc, .get_desc = rtl92ee_get_desc, .is_tx_desc_closed = rtl92ee_is_tx_desc_closed, + .get_available_desc = rtl92ee_get_available_desc, .tx_polling = rtl92ee_tx_polling, .enable_hw_sec = rtl92ee_enable_hw_security_config, .set_key = rtl92ee_set_key, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c index 2b60bdc7452f..1245e2f53c8d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c @@ -555,6 +555,26 @@ static u16 get_desc_addr_fr_q_idx(u16 queue_index) return desc_address; } +u16 rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 point_diff = 0; + u16 current_tx_read_point = 0, current_tx_write_point = 0; + u32 tmp_4byte; + + tmp_4byte = rtl_read_dword(rtlpriv, + get_desc_addr_fr_q_idx(q_idx)); + current_tx_read_point = (u16)((tmp_4byte >> 16) & 0x0fff); + current_tx_write_point = (u16)((tmp_4byte) & 0x0fff); + + point_diff = calc_fifo_space(current_tx_read_point, + current_tx_write_point); + + rtlpci->tx_ring[q_idx].avl_desc = point_diff; + return point_diff; +} + void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, u8 *tx_bd_desc, u8 *desc, u8 queue_index, struct sk_buff *skb, dma_addr_t addr) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h index 5abb749b33e9..8f78ac9e6040 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h @@ -831,6 +831,7 @@ void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc, u8 queue_index); u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index); +u16 rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 queue_index); void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, u8 *tx_bd_desc, u8 *desc, u8 queue_index, struct sk_buff *skb, dma_addr_t addr); diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index b53d9dd7a595..51572912c53d 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -2182,6 +2182,7 @@ struct rtl_hal_ops { void (*add_wowlan_pattern)(struct ieee80211_hw *hw, struct rtl_wow_pattern *rtl_pattern, u8 index); + u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx); }; struct rtl_intf_ops { -- cgit v1.2.1 From 6d4beca3775222884e1ee9d48ef586c438c3dfa1 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 3 Feb 2015 11:15:18 -0600 Subject: rtlwifi: rtl8192ee: Fix problems with calculating free space in FIFO This driver utilizes a FIFO buffer for RX descriptors. There are four places in the code where it calculates the number of free slots. Several of those locations do the calculation incorrectly. To fix these and to prevent future mistakes, a common inline routine is created. Signed-off-by: Larry Finger Cc: Stable [V3.18] Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/pci.h | 7 +++++++ drivers/net/wireless/rtlwifi/rtl8192ee/trx.c | 9 +-------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 5e832306dba9..d4567d12e07e 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -325,4 +325,11 @@ static inline void pci_write32_async(struct rtl_priv *rtlpriv, writel(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr); } +static inline u16 calc_fifo_space(u16 rp, u16 wp) +{ + if (rp <= wp) + return RTL_PCI_MAX_RX_COUNT - 1 + rp - wp; + return rp - wp - 1; +} + #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c index 1245e2f53c8d..d39ee67f6113 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c @@ -499,14 +499,7 @@ u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index) if (!start_rx) return 0; - if ((last_read_point > (RX_DESC_NUM_92E / 2)) && - (read_point <= (RX_DESC_NUM_92E / 2))) { - remind_cnt = RX_DESC_NUM_92E - write_point; - } else { - remind_cnt = (read_point >= write_point) ? - (read_point - write_point) : - (RX_DESC_NUM_92E - write_point + read_point); - } + remind_cnt = calc_fifo_space(read_point, write_point); if (remind_cnt == 0) return 0; -- cgit v1.2.1 From a28815db67a8a27afb4a17d30103e47c6e9e036f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 2 Feb 2015 18:21:08 +0530 Subject: ath9k: Add support for more WOW patterns Newer chips like WB222, WB335 support more than 8 user-configurable patterns. This patch adds support for it by setting up the correct HW registers. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 48 +++++++++++++---------------- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/reg_wow.h | 34 ++++++++++++++++++++ 3 files changed, 56 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index d2a4f6f49045..4b53d0b4d113 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -100,9 +100,11 @@ int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, if (pattern_count >= ah->wow.max_patterns) return -ENOSPC; - REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); + if (pattern_count < MAX_NUM_PATTERN_LEGACY) + REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); + else + REG_SET_BIT(ah, AR_MAC_PCU_WOW4, BIT(pattern_count - 8)); - /* set the registers for pattern */ for (i = 0; i < MAX_PATTERN_SIZE; i += 4) { memcpy(&pattern_val, user_pattern, 4); REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i), @@ -110,47 +112,39 @@ int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, user_pattern += 4; } - /* set the registers for mask */ for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) { memcpy(&mask_val, user_mask, 4); REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val); user_mask += 4; } - /* set the pattern length to be matched - * - * AR_WOW_LENGTH1_REG1 - * bit 31:24 pattern 0 length - * bit 23:16 pattern 1 length - * bit 15:8 pattern 2 length - * bit 7:0 pattern 3 length - * - * AR_WOW_LENGTH1_REG2 - * bit 31:24 pattern 4 length - * bit 23:16 pattern 5 length - * bit 15:8 pattern 6 length - * bit 7:0 pattern 7 length - * - * the below logic writes out the new - * pattern length for the corresponding - * pattern_count, while masking out the - * other fields - */ - - ah->wow.wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); + if (pattern_count < MAX_NUM_PATTERN_LEGACY) + ah->wow.wow_event_mask |= + BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); + else + ah->wow.wow_event_mask2 |= + BIT((pattern_count - 8) + AR_WOW_PAT_FOUND_SHIFT); if (pattern_count < 4) { - /* Pattern 0-3 uses AR_WOW_LENGTH1 register */ set = (pattern_len & AR_WOW_LENGTH_MAX) << AR_WOW_LEN1_SHIFT(pattern_count); clr = AR_WOW_LENGTH1_MASK(pattern_count); REG_RMW(ah, AR_WOW_LENGTH1, set, clr); - } else { - /* Pattern 4-7 uses AR_WOW_LENGTH2 register */ + } else if (pattern_count < 8) { set = (pattern_len & AR_WOW_LENGTH_MAX) << AR_WOW_LEN2_SHIFT(pattern_count); clr = AR_WOW_LENGTH2_MASK(pattern_count); REG_RMW(ah, AR_WOW_LENGTH2, set, clr); + } else if (pattern_count < 12) { + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN3_SHIFT(pattern_count); + clr = AR_WOW_LENGTH3_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH3, set, clr); + } else if (pattern_count < MAX_NUM_PATTERN) { + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN4_SHIFT(pattern_count); + clr = AR_WOW_LENGTH4_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH4, set, clr); } return 0; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f51a28f0740e..c8b3d8f608a2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -273,6 +273,7 @@ enum ath9k_hw_caps { struct ath9k_hw_wow { u32 wow_event_mask; + u32 wow_event_mask2; u8 max_patterns; }; diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h index e6de4a375182..83f27f9be7aa 100644 --- a/drivers/net/wireless/ath/ath9k/reg_wow.h +++ b/drivers/net/wireless/ath/ath9k/reg_wow.h @@ -25,9 +25,39 @@ #define AR_WOW_KEEP_ALIVE 0x827c #define AR_WOW_KEEP_ALIVE_DELAY 0x8288 #define AR_WOW_PATTERN_MATCH 0x828c + +/* + * AR_WOW_LENGTH1 + * bit 31:24 pattern 0 length + * bit 23:16 pattern 1 length + * bit 15:8 pattern 2 length + * bit 7:0 pattern 3 length + * + * AR_WOW_LENGTH2 + * bit 31:24 pattern 4 length + * bit 23:16 pattern 5 length + * bit 15:8 pattern 6 length + * bit 7:0 pattern 7 length + * + * AR_WOW_LENGTH3 + * bit 31:24 pattern 8 length + * bit 23:16 pattern 9 length + * bit 15:8 pattern 10 length + * bit 7:0 pattern 11 length + * + * AR_WOW_LENGTH4 + * bit 31:24 pattern 12 length + * bit 23:16 pattern 13 length + * bit 15:8 pattern 14 length + * bit 7:0 pattern 15 length + */ #define AR_WOW_LENGTH1 0x8360 #define AR_WOW_LENGTH2 0X8364 +#define AR_WOW_LENGTH3 0X8380 +#define AR_WOW_LENGTH4 0X8384 + #define AR_WOW_PATTERN_MATCH_LT_256B 0x8368 +#define AR_MAC_PCU_WOW4 0x8370 #define AR_SW_WOW_CONTROL 0x20018 #define AR_SW_WOW_ENABLE 0x1 @@ -89,5 +119,9 @@ #define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) #define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3) #define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i)) +#define AR_WOW_LEN3_SHIFT(_i) ((0xb - ((_i) & 0xb)) << 0x3) +#define AR_WOW_LENGTH3_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN3_SHIFT(_i)) +#define AR_WOW_LEN4_SHIFT(_i) ((0xf - ((_i) & 0xf)) << 0x3) +#define AR_WOW_LENGTH4_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN4_SHIFT(_i)) #endif /* REG_WOW_H */ -- cgit v1.2.1 From e68e9c10fbe0d4e49732783aae534ba0a328887f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 2 Feb 2015 18:21:09 +0530 Subject: ath9k: Register correct WOW details with mac80211 Since the number of user patterns is higher for newer chips, make sure that this is registered during initialization. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 5092939876f6..8d0b1730a9d5 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -16,13 +16,20 @@ #include "ath9k.h" -static const struct wiphy_wowlan_support ath9k_wowlan_support = { +static const struct wiphy_wowlan_support ath9k_wowlan_support_legacy = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, .n_patterns = MAX_NUM_USER_PATTERN, .pattern_min_len = 1, .pattern_max_len = MAX_PATTERN_SIZE, }; +static const struct wiphy_wowlan_support ath9k_wowlan_support = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = MAX_NUM_PATTERN - 2, + .pattern_min_len = 1, + .pattern_max_len = MAX_PATTERN_SIZE, +}; + static u8 ath9k_wow_map_triggers(struct ath_softc *sc, struct cfg80211_wowlan *wowlan) { @@ -320,9 +327,14 @@ void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) void ath9k_init_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) { - hw->wiphy->wowlan = &ath9k_wowlan_support; + if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah)) + hw->wiphy->wowlan = &ath9k_wowlan_support; + else + hw->wiphy->wowlan = &ath9k_wowlan_support_legacy; + device_init_wakeup(sc->dev, 1); } } -- cgit v1.2.1 From bb6313140b3c8356cf36675a8edbf6782dc6c3d0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 2 Feb 2015 18:21:10 +0530 Subject: ath9k: Fix issues with WoW enable This patch addresses several issues with the ath9k_hw_wow_enable() routine: * The usage of set/clr variables is removed. Writing the required values to registers is cleaner. * The shift value of 28 for the contention window field in AR_WOW_PATTERN is incorrect, change it to 27. * Disabling Keep Alive needs to be done based on the LINK_CHANGE option. This is done unconditionally now, fix this. * The workaround for the D1/D3 issue is required only for AR9462. * The bitfield for enabling pattern matching for packets less than 256 bytes has expanded for new chips, handle this accordingly. * General cleanup. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 181 ++++++++++++++-------------- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/reg_wow.h | 5 +- 3 files changed, 93 insertions(+), 95 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index 4b53d0b4d113..6ffa0e0d028c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -222,14 +222,9 @@ EXPORT_SYMBOL(ath9k_hw_wow_wakeup); void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) { u32 wow_event_mask; + u32 keep_alive, magic_pattern, host_pm_ctrl; u32 set, clr; - /* - * wow_event_mask is a mask to the AR_WOW_PATTERN register to - * indicate which WoW events we have enabled. The WoW events - * are from the 'pattern_enable' in this function and - * 'pattern_count' of ath9k_hw_wow_apply_pattern() - */ wow_event_mask = ah->wow.wow_event_mask; /* @@ -249,152 +244,154 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) } /* - * set the power states appropriately and enable PME + * AR_PMCTRL_HOST_PME_EN - Override PME enable in configuration + * space and allow MAC to generate WoW anyway. + * + * AR_PMCTRL_PWR_PM_CTRL_ENA - ??? + * + * AR_PMCTRL_AUX_PWR_DET - PCI core SYS_AUX_PWR_DET signal, + * needs to be set for WoW in PCI mode. + * + * AR_PMCTRL_WOW_PME_CLR - WoW Clear Signal going to the MAC. + * + * Set the power states appropriately and enable PME. + * + * Set and clear WOW_PME_CLEAR for the chip + * to generate next wow signal. */ - set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA | - AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR; + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_HOST_PME_EN | + AR_PMCTRL_PWR_PM_CTRL_ENA | + AR_PMCTRL_AUX_PWR_DET | + AR_PMCTRL_WOW_PME_CLR); + REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR); /* - * set and clear WOW_PME_CLEAR registers for the chip - * to generate next wow signal. + * Random Backoff. + * + * 31:28 in AR_WOW_PATTERN : Indicates the number of bits used in the + * contention window. For value N, + * the random backoff will be selected between + * 0 and (2 ^ N) - 1. */ - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); - clr = AR_PMCTRL_WOW_PME_CLR; - REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); + REG_SET_BIT(ah, AR_WOW_PATTERN, + AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF)); /* - * Setup for: - * - beacon misses - * - magic pattern - * - keep alive timeout - * - pattern matching + * AIFS time, Slot time, Keep Alive count. */ - + REG_SET_BIT(ah, AR_WOW_COUNT, AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | + AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | + AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT)); /* - * Program default values for pattern backoff, aifs/slot/KAL count, - * beacon miss timeout, KAL timeout, etc. + * Beacon timeout. */ - set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); - REG_SET_BIT(ah, AR_WOW_PATTERN, set); - - set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | - AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | - AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); - REG_SET_BIT(ah, AR_WOW_COUNT, set); - if (pattern_enable & AH_WOW_BEACON_MISS) - set = AR_WOW_BEACON_TIMO; - /* We are not using beacon miss, program a large value */ + REG_WRITE(ah, AR_WOW_BCN_TIMO, AR_WOW_BEACON_TIMO); else - set = AR_WOW_BEACON_TIMO_MAX; - - REG_WRITE(ah, AR_WOW_BCN_TIMO, set); + REG_WRITE(ah, AR_WOW_BCN_TIMO, AR_WOW_BEACON_TIMO_MAX); /* - * Keep alive timo in ms except AR9280 + * Keep alive timeout in ms. */ if (!pattern_enable) - set = AR_WOW_KEEP_ALIVE_NEVER; + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, AR_WOW_KEEP_ALIVE_NEVER); else - set = KAL_TIMEOUT * 32; - - REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set); + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, KAL_TIMEOUT * 32); /* - * Keep alive delay in us. based on 'power on clock', - * therefore in usec + * Keep alive delay in us. */ - set = KAL_DELAY * 1000; - REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set); + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, KAL_DELAY * 1000); /* - * Create keep alive pattern to respond to beacons + * Create keep alive pattern to respond to beacons. */ ath9k_wow_create_keep_alive_pattern(ah); /* - * Configure MAC WoW Registers + * Configure keep alive register. */ - set = 0; + keep_alive = REG_READ(ah, AR_WOW_KEEP_ALIVE); + /* Send keep alive timeouts anyway */ - clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; + keep_alive &= ~AR_WOW_KEEP_ALIVE_AUTO_DIS; - if (pattern_enable & AH_WOW_LINK_CHANGE) + if (pattern_enable & AH_WOW_LINK_CHANGE) { + keep_alive &= ~AR_WOW_KEEP_ALIVE_FAIL_DIS; wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; - else - set = AR_WOW_KEEP_ALIVE_FAIL_DIS; + } else { + keep_alive |= AR_WOW_KEEP_ALIVE_FAIL_DIS; + } - set = AR_WOW_KEEP_ALIVE_FAIL_DIS; - REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); + REG_WRITE(ah, AR_WOW_KEEP_ALIVE, keep_alive); /* - * we are relying on a bmiss failure. ensure we have - * enough threshold to prevent false positives + * We are relying on a bmiss failure, ensure we have + * enough threshold to prevent false positives. */ REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, AR_WOW_BMISSTHRESHOLD); - set = 0; - clr = 0; - if (pattern_enable & AH_WOW_BEACON_MISS) { - set = AR_WOW_BEACON_FAIL_EN; wow_event_mask |= AR_WOW_BEACON_FAIL; + REG_SET_BIT(ah, AR_WOW_BCN_EN, AR_WOW_BEACON_FAIL_EN); } else { - clr = AR_WOW_BEACON_FAIL_EN; + REG_CLR_BIT(ah, AR_WOW_BCN_EN, AR_WOW_BEACON_FAIL_EN); } - REG_RMW(ah, AR_WOW_BCN_EN, set, clr); - - set = 0; - clr = 0; /* - * Enable the magic packet registers + * Enable the magic packet registers. */ + magic_pattern = REG_READ(ah, AR_WOW_PATTERN); + magic_pattern |= AR_WOW_MAC_INTR_EN; + if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { - set = AR_WOW_MAGIC_EN; + magic_pattern |= AR_WOW_MAGIC_EN; wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; } else { - clr = AR_WOW_MAGIC_EN; + magic_pattern &= ~AR_WOW_MAGIC_EN; } - set |= AR_WOW_MAC_INTR_EN; - REG_RMW(ah, AR_WOW_PATTERN, set, clr); + REG_WRITE(ah, AR_WOW_PATTERN, magic_pattern); + + /* + * Enable pattern matching for packets which are less + * than 256 bytes. + */ REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, AR_WOW_PATTERN_SUPPORTED); /* - * Set the power states appropriately and enable PME + * Set the power states appropriately and enable PME. */ - clr = 0; - set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | - AR_PMCTRL_PWR_PM_CTRL_ENA; + host_pm_ctrl = REG_READ(ah, AR_PCIE_PM_CTRL); + host_pm_ctrl |= AR_PMCTRL_PWR_STATE_D1D3 | + AR_PMCTRL_HOST_PME_EN | + AR_PMCTRL_PWR_PM_CTRL_ENA; + host_pm_ctrl &= ~AR_PCIE_PM_CTRL_ENA; - clr = AR_PCIE_PM_CTRL_ENA; - REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); + if (AR_SREV_9462(ah)) { + /* + * This is needed to prevent the chip waking up + * the host within 3-4 seconds with certain + * platform/BIOS. + */ + host_pm_ctrl &= ~AR_PMCTRL_PWR_STATE_D1D3; + host_pm_ctrl |= AR_PMCTRL_PWR_STATE_D1D3_REAL; + } + + REG_WRITE(ah, AR_PCIE_PM_CTRL, host_pm_ctrl); /* - * this is needed to prevent the chip waking up - * the host within 3-4 seconds with certain - * platform/BIOS. The fix is to enable - * D1 & D3 to match original definition and - * also match the OTP value. Anyway this - * is more related to SW WOW. + * Enable sequence number generation when asleep. */ - clr = AR_PMCTRL_PWR_STATE_D1D3; - REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); - - set = AR_PMCTRL_PWR_STATE_D1D3_REAL; - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); - REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); - /* to bring down WOW power low margin */ - set = BIT(13); - REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); + /* To bring down WOW power low margin */ + REG_SET_BIT(ah, AR_PCIE_PHY_REG3, BIT(13)); + /* HW WoW */ - clr = BIT(5); - REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); + REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, BIT(5)); ath9k_hw_set_powermode_wow_sleep(ah); ah->wow.wow_event_mask = wow_event_mask; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c8b3d8f608a2..e82e570de330 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -199,7 +199,7 @@ #define KAL_NUM_DESC_WORDS 12 #define KAL_ANTENNA_MODE 1 #define KAL_TO_DS 1 -#define KAL_DELAY 4 /*delay of 4ms between 2 KAL frames */ +#define KAL_DELAY 4 /* delay of 4ms between 2 KAL frames */ #define KAL_TIMEOUT 900 #define MAX_PATTERN_SIZE 256 diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h index 83f27f9be7aa..3abfca56ca58 100644 --- a/drivers/net/wireless/ath/ath9k/reg_wow.h +++ b/drivers/net/wireless/ath/ath9k/reg_wow.h @@ -68,7 +68,7 @@ #define AR_CLR_MAC_INTERRUPT 0x20 #define AR_CLR_KA_INTERRUPT 0x40 -#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 28) /* in usecs */ +#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 27) /* in usecs */ #define AR_WOW_MAC_INTR_EN 0x00040000 #define AR_WOW_MAGIC_EN 0x00010000 #define AR_WOW_PATTERN_EN(x) (x & 0xff) @@ -113,7 +113,8 @@ #define AR_WOW_KA_DESC_WORD2 0xe000 #define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8)) #define AR_WOW_TB_MASK(i) (0xec00 + (i << 5)) -#define AR_WOW_PATTERN_SUPPORTED 0xff +#define AR_WOW_PATTERN_SUPPORTED_LEGACY 0xff +#define AR_WOW_PATTERN_SUPPORTED 0xffff #define AR_WOW_LENGTH_MAX 0xff #define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3) #define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) -- cgit v1.2.1 From b6f68b1ecbffc0aec1704c731c3b99acbe3becfd Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 2 Feb 2015 18:21:11 +0530 Subject: ath9k: Program AR_WA correctly Setting the required configuration in the PCIE WorkAround register needs to be done after all the WoW parameters have been set. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 39 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index 6ffa0e0d028c..cf45b91f0a60 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -219,30 +219,33 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_wow_wakeup); +static void ath9k_hw_wow_set_arwr_reg(struct ath_hw *ah) +{ + u32 wa_reg; + + if (!ah->is_pciexpress) + return; + + /* + * We need to untie the internal POR (power-on-reset) + * to the external PCI-E reset. We also need to tie + * the PCI-E Phy reset to the PCI-E reset. + */ + wa_reg = REG_READ(ah, AR_WA); + wa_reg &= ~AR_WA_UNTIE_RESET_EN; + wa_reg |= AR_WA_RESET_EN; + wa_reg |= AR_WA_POR_SHORT; + + REG_WRITE(ah, AR_WA, wa_reg); +} + void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) { u32 wow_event_mask; u32 keep_alive, magic_pattern, host_pm_ctrl; - u32 set, clr; wow_event_mask = ah->wow.wow_event_mask; - /* - * Untie Power-on-Reset from the PCI-E-Reset. When we are in - * WOW sleep, we do want the Reset from the PCI-E to disturb - * our hw state - */ - if (ah->is_pciexpress) { - /* - * we need to untie the internal POR (power-on-reset) - * to the external PCI-E reset. We also need to tie - * the PCI-E Phy reset to the PCI-E reset. - */ - set = AR_WA_RESET_EN | AR_WA_POR_SHORT; - clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE; - REG_RMW(ah, AR_WA, set, clr); - } - /* * AR_PMCTRL_HOST_PME_EN - Override PME enable in configuration * space and allow MAC to generate WoW anyway. @@ -390,6 +393,8 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) /* To bring down WOW power low margin */ REG_SET_BIT(ah, AR_PCIE_PHY_REG3, BIT(13)); + ath9k_hw_wow_set_arwr_reg(ah); + /* HW WoW */ REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, BIT(5)); -- cgit v1.2.1 From 23ee7c33aa7caae5985a919e597ba2e355d540ea Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 2 Feb 2015 18:21:12 +0530 Subject: ath9k: Clear TSF2 properly Chips in the AR9003 family have a second TSF, which needs to be cleared when putting the card to sleep. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 9 +++++++++ drivers/net/wireless/ath/ath9k/reg.h | 2 ++ 2 files changed, 11 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index cf45b91f0a60..2dc50a0eedc4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -35,6 +35,15 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) return; } + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + if (!REG_READ(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL)) + REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE); + } else if (AR_SREV_9485(ah)){ + if (!(REG_READ(ah, AR_NDP2_TIMER_MODE) & + AR_GEN_TIMERS2_MODE_ENABLE_MASK)) + REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE); + } + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); } diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index b1b803d05926..9587ec655680 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1883,6 +1883,7 @@ enum { #define AR_FIRST_NDP_TIMER 7 #define AR_NDP2_PERIOD 0x81a0 #define AR_NDP2_TIMER_MODE 0x81c0 +#define AR_GEN_TIMERS2_MODE_ENABLE_MASK 0x000000FF #define AR_GEN_TIMERS(_i) (0x8200 + ((_i) << 2)) #define AR_NEXT_TBTT_TIMER AR_GEN_TIMERS(0) @@ -1978,6 +1979,7 @@ enum { #define AR_DIRECT_CONNECT 0x83a0 #define AR_DC_AP_STA_EN 0x00000001 +#define AR_DC_TSF2_ENABLE 0x00000001 #define AR_AES_MUTE_MASK0 0x805c #define AR_AES_MUTE_MASK0_FC 0x0000FFFF -- cgit v1.2.1 From c20bbda32a1f5b8293abae9bc39ad964d017afea Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 2 Feb 2015 18:21:13 +0530 Subject: ath9k: Choose correct rate for 2GHz channel Set the transmit rate for the keep-alive frames as 1M/CCK when the current channel is in the 2GHz band. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index 2dc50a0eedc4..86bfc9604dca 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -62,11 +62,15 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) /* set the transmit buffer */ ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); ctl[1] = 0; - ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */ ctl[4] = 0; ctl[7] = (ah->txchainmask) << 2; ctl[2] = 0xf << 16; /* tx_tries 0 */ + if (IS_CHAN_2GHZ(ah->curchan)) + ctl[3] = 0x1b; /* CCK_1M */ + else + ctl[3] = 0xb; /* OFDM_6M */ + for (i = 0; i < KAL_NUM_DESC_WORDS; i++) REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); -- cgit v1.2.1 From 8bfae4f9938b6c1f033a5159febe97e441d6d526 Mon Sep 17 00:00:00 2001 From: Sergey Ryazanov Date: Wed, 4 Feb 2015 00:21:13 +0300 Subject: ath5k: fix spontaneus AR5312 freezes Sometimes while CPU have some load and ath5k doing the wireless interface reset the whole WiSoC completely freezes. Set of tests shows that using atomic delay function while we wait interface reset helps to avoid such freezes. The easiest way to reproduce this issue: create a station interface, start continous scan with wpa_supplicant and load CPU by something. Or just create multiple station interfaces and put them all in continous scan. This patch partially reverts the commit 1846ac3dbec0 ("ath5k: Use usleep_range where possible"), which replaces initial udelay() by usleep_range(). I do not know actual source of this issue, but all looks like that HW freeze is caused by transaction on internal SoC bus, while wireless block is in reset state. Also I should note that I do not know how many chips are affected, but I did not see this issue with chips, other than AR5312. CC: Jiri Slaby CC: Nick Kossifidis CC: Luis R. Rodriguez Fixes: 1846ac3dbec0 ("ath5k: Use usleep_range where possible") Reported-by: Christophe Prevotaux Tested-by: Christophe Prevotaux Tested-by: Eric Bree Signed-off-by: Sergey Ryazanov Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath5k/reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index a3399c4f13a9..b9b651ea9851 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -478,7 +478,7 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) regval = ioread32(reg); iowrite32(regval | val, reg); regval = ioread32(reg); - usleep_range(100, 150); + udelay(100); /* NB: should be atomic */ /* Bring BB/MAC out of reset */ iowrite32(regval & ~val, reg); -- cgit v1.2.1 From 4d24550112311a2c053c539b0ea0521c42fc9305 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Wed, 4 Feb 2015 02:39:49 -0500 Subject: cw1200: use msecs_to_jiffies for conversion This is only an API consolidation to make things more readable. Instances of HZ / CONST are replaced by appropriate msecs_to_jiffies(). Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/cw1200/scan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c index f2e276faca70..bff81b8d4164 100644 --- a/drivers/net/wireless/cw1200/scan.c +++ b/drivers/net/wireless/cw1200/scan.c @@ -39,9 +39,9 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan) cancel_delayed_work_sync(&priv->clear_recent_scan_work); atomic_set(&priv->scan.in_progress, 1); atomic_set(&priv->recent_scan, 1); - cw1200_pm_stay_awake(&priv->pm_state, tmo * HZ / 1000); + cw1200_pm_stay_awake(&priv->pm_state, msecs_to_jiffies(tmo)); queue_delayed_work(priv->workqueue, &priv->scan.timeout, - tmo * HZ / 1000); + msecs_to_jiffies(tmo)); ret = wsm_scan(priv, scan); if (ret) { atomic_set(&priv->scan.in_progress, 0); @@ -386,8 +386,8 @@ void cw1200_probe_work(struct work_struct *work) if (down_trylock(&priv->scan.lock)) { /* Scan is already in progress. Requeue self. */ schedule(); - queue_delayed_work(priv->workqueue, - &priv->scan.probe_work, HZ / 10); + queue_delayed_work(priv->workqueue, &priv->scan.probe_work, + msecs_to_jiffies(100)); mutex_unlock(&priv->conf_mutex); return; } -- cgit v1.2.1 From ab458cc85fa23fd6367493b0668e126a6a552f32 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Wed, 4 Feb 2015 03:07:39 -0500 Subject: orinoco: orinoco_plx use msecs_to_jiffies for conversion This is only an API consolidation and should make things more readable it replaces var * HZ / 1000 by msecs_to_jiffies(var). Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/orinoco/orinoco_plx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index b8f6e5c431ae..8b045236b6e0 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -121,7 +121,7 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv) mdelay(1); /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + (PLX_RESET_TIME * HZ / 1000); + 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); -- cgit v1.2.1 From 3427da4597ae2bf909a7f6f0c7bc48b07215c009 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Wed, 4 Feb 2015 03:07:40 -0500 Subject: orinoco: orinoco_pci use msecs_to_jiffies for conversion This is only an API consolidation and should make things more readable it replaces var * HZ / 1000 by msecs_to_jiffies(var). Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/orinoco/orinoco_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index b6bdad632842..74219d59d7e1 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -94,7 +94,7 @@ static int orinoco_pci_cor_reset(struct orinoco_private *priv) mdelay(HERMES_PCI_COR_OFFT); /* The card is ready when it's no longer busy */ - timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000); + 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); -- cgit v1.2.1 From c1f1f6663b3c749dd9eba9eaeb178859080104e2 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Wed, 4 Feb 2015 03:07:41 -0500 Subject: orinoco: orinoco_tmd use msecs_to_jiffies for conversion This is only an API consolidation and should make things more readable it replaces var * HZ / 1000 by msecs_to_jiffies(var). Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/orinoco/orinoco_tmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index 79d0e33b625e..20ce569b8a43 100644 --- a/drivers/net/wireless/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -71,7 +71,7 @@ static int orinoco_tmd_cor_reset(struct orinoco_private *priv) mdelay(1); /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + (TMD_RESET_TIME * HZ / 1000); + 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); -- cgit v1.2.1 From df970d39b90e0c316c62a9db6d796edef2a31526 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 16:32:15 +0100 Subject: cw1200: Delete an unnecessary check before the function call "release_firmware" The release_firmware() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Kalle Valo --- drivers/net/wireless/cw1200/fwio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c index 6f1b9aace8b3..581dfdedd436 100644 --- a/drivers/net/wireless/cw1200/fwio.c +++ b/drivers/net/wireless/cw1200/fwio.c @@ -246,8 +246,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) error: kfree(buf); - if (firmware) - release_firmware(firmware); + release_firmware(firmware); return ret; #undef APB_WRITE -- cgit v1.2.1 From ee4ddad82356116351660b0adfcb8e837eda371f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 17:28:41 +0100 Subject: cw1200: Less function calls in cw1200_load_firmware_cw1200() after error detection The functions kfree() and release_firmware() were called in a few cases by the cw1200_load_firmware_cw1200() function during error handling even if the passed variables contained still a null pointer. Corresponding implementation details could be improved by adjustments for jump targets. Signed-off-by: Markus Elfring Signed-off-by: Kalle Valo --- drivers/net/wireless/cw1200/fwio.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c index 581dfdedd436..30e7646d04af 100644 --- a/drivers/net/wireless/cw1200/fwio.c +++ b/drivers/net/wireless/cw1200/fwio.c @@ -66,25 +66,31 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) do { \ ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \ if (ret < 0) \ - goto error; \ + goto exit; \ + } while (0) +#define APB_WRITE2(reg, val) \ + do { \ + ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \ + if (ret < 0) \ + goto free_buffer; \ } while (0) #define APB_READ(reg, val) \ do { \ ret = cw1200_apb_read_32(priv, CW1200_APB(reg), &(val)); \ if (ret < 0) \ - goto error; \ + goto free_buffer; \ } while (0) #define REG_WRITE(reg, val) \ do { \ ret = cw1200_reg_write_32(priv, (reg), (val)); \ if (ret < 0) \ - goto error; \ + goto exit; \ } while (0) #define REG_READ(reg, val) \ do { \ ret = cw1200_reg_read_32(priv, (reg), &(val)); \ if (ret < 0) \ - goto error; \ + goto exit; \ } while (0) switch (priv->hw_revision) { @@ -142,14 +148,14 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) ret = request_firmware(&firmware, fw_path, priv->pdev); if (ret) { pr_err("Can't load firmware file %s.\n", fw_path); - goto error; + goto exit; } buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA); if (!buf) { pr_err("Can't allocate firmware load buffer.\n"); ret = -ENOMEM; - goto error; + goto firmware_release; } /* Check if the bootloader is ready */ @@ -163,7 +169,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) if (val32 != DOWNLOAD_I_AM_HERE) { pr_err("Bootloader is not ready.\n"); ret = -ETIMEDOUT; - goto error; + goto free_buffer; } /* Calculcate number of download blocks */ @@ -171,7 +177,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) /* Updating the length in Download Ctrl Area */ val32 = firmware->size; /* Explicit cast from size_t to u32 */ - APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, val32); + APB_WRITE2(DOWNLOAD_IMAGE_SIZE_REG, val32); /* Firmware downloading loop */ for (block = 0; block < num_blocks; block++) { @@ -183,7 +189,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) if (val32 != DOWNLOAD_PENDING) { pr_err("Bootloader reported error %d.\n", val32); ret = -EIO; - goto error; + goto free_buffer; } /* loop until put - get <= 24K */ @@ -198,7 +204,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) { pr_err("Timeout waiting for FIFO.\n"); ret = -ETIMEDOUT; - goto error; + goto free_buffer; } /* calculate the block size */ @@ -220,12 +226,12 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) if (ret < 0) { pr_err("Can't write firmware block @ %d!\n", put & (DOWNLOAD_FIFO_SIZE - 1)); - goto error; + goto free_buffer; } /* update the put register */ put += block_size; - APB_WRITE(DOWNLOAD_PUT_REG, put); + APB_WRITE2(DOWNLOAD_PUT_REG, put); } /* End of firmware download loop */ /* Wait for the download completion */ @@ -238,18 +244,21 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) if (val32 != DOWNLOAD_SUCCESS) { pr_err("Wait for download completion failed: 0x%.8X\n", val32); ret = -ETIMEDOUT; - goto error; + goto free_buffer; } else { pr_info("Firmware download completed.\n"); ret = 0; } -error: +free_buffer: kfree(buf); +firmware_release: release_firmware(firmware); +exit: return ret; #undef APB_WRITE +#undef APB_WRITE2 #undef APB_READ #undef REG_WRITE #undef REG_READ -- cgit v1.2.1 From c0420ea0b598021302b1e1f0f28d621f93968e5d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 18:48:28 +0100 Subject: ath9k: Delete an unnecessary check before the function call "relay_close" The relay_close() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/common-spectral.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index ec93ddf0863a..5cee231cca1f 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -582,7 +582,7 @@ static struct rchan_callbacks rfs_spec_scan_cb = { void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv) { - if (config_enabled(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) { + if (config_enabled(CONFIG_ATH9K_DEBUGFS)) { relay_close(spec_priv->rfs_chan_spec_scan); spec_priv->rfs_chan_spec_scan = NULL; } -- cgit v1.2.1 From 71b9d0aeac4c7070229f309bc901382422ab5708 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 19:53:11 +0100 Subject: orinoco: Delete an unnecessary check before the function call "kfree" The kfree() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Kalle Valo --- drivers/net/wireless/orinoco/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 38ec8d19ac29..c410180479e6 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -2342,7 +2342,7 @@ void free_orinocodev(struct orinoco_private *priv) list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) { list_del(&sd->list); - if ((sd->len > 0) && sd->buf) + if (sd->len > 0) kfree(sd->buf); kfree(sd); } -- cgit v1.2.1 From 6f24fe305986afcb9eb2bde1031798b3b2ebf649 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 20:06:39 +0100 Subject: hostap: Delete an unnecessary check before the function call "kfree" The kfree() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Kalle Valo --- drivers/net/wireless/hostap/hostap_ap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 596525528f50..fd8d83dd4f62 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -145,7 +145,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) if (sta->aid > 0) ap->sta_aid[sta->aid - 1] = NULL; - if (!sta->ap && sta->u.sta.challenge) + if (!sta->ap) kfree(sta->u.sta.challenge); del_timer_sync(&sta->timer); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ -- cgit v1.2.1 From 297540f69fa9c7292c9866e71cb22a7bc4c5003b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 4 Feb 2015 20:28:49 +0100 Subject: brcm80211: Delete unnecessary checks before two function calls The functions brcmu_pkt_buf_free_skb() and usb_free_urb() test whether their argument is NULL and then return immediately. Thus the test around the call is not needed. Signed-off-by: Markus Elfring Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 3 +-- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 5e9d20853bbb..faec35c899ec 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -2538,8 +2538,7 @@ static void brcmf_sdio_bus_stop(struct device *dev) brcmu_pktq_flush(&bus->txq, true, NULL, NULL); /* Clear any held glomming stuff */ - if (bus->glomd) - brcmu_pkt_buf_free_skb(bus->glomd); + brcmu_pkt_buf_free_skb(bus->glomd); brcmf_sdio_free_glom(bus); /* Clear rx control and wake any waiters */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 1b9572988c77..5df6aa72cc2d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -421,7 +421,7 @@ fail: brcmf_err("fail!\n"); while (!list_empty(q)) { req = list_entry(q->next, struct brcmf_usbreq, list); - if (req && req->urb) + if (req) usb_free_urb(req->urb); list_del(q->next); } -- cgit v1.2.1 From 37c85c3498c5538db050ff287e346127dbc16f7c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 5 Feb 2015 11:00:42 +0300 Subject: net: sxgbe: fix error handling in init_rx_ring() There are a couple bugs with the error handling in this function. 1) If we can't allocate "rx_ring->rx_skbuff" then we should call dma_free_coherent() but we don't. 2) free_rx_ring() frees "rx_ring->rx_skbuff_dma" and "rx_ring->rx_skbuff" so calling it in a loop causes a double free. Also it was a bit confusing how we sometimes freed things before doing the goto. I've cleaned it up so it does error handling in normal kernel style. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 57 +++++++++++++++++++------ 1 file changed, 43 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index b1a271853d85..d860dca01475 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -365,6 +365,26 @@ static int sxgbe_init_rx_buffers(struct net_device *dev, return 0; } + +/** + * sxgbe_free_rx_buffers - free what sxgbe_init_rx_buffers() allocated + * @dev: net device structure + * @rx_ring: ring to be freed + * @rx_rsize: ring size + * Description: this function initializes the DMA RX descriptor + */ +static void sxgbe_free_rx_buffers(struct net_device *dev, + struct sxgbe_rx_norm_desc *p, int i, + unsigned int dma_buf_sz, + struct sxgbe_rx_queue *rx_ring) +{ + struct sxgbe_priv_data *priv = netdev_priv(dev); + + kfree_skb(rx_ring->rx_skbuff[i]); + dma_unmap_single(priv->device, rx_ring->rx_skbuff_dma[i], + dma_buf_sz, DMA_FROM_DEVICE); +} + /** * init_tx_ring - init the TX descriptor ring * @dev: net device structure @@ -457,7 +477,7 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, /* RX ring is not allcoated */ if (rx_ring == NULL) { netdev_err(dev, "No memory for RX queue\n"); - goto error; + return -ENOMEM; } /* assign queue number */ @@ -469,23 +489,21 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, &rx_ring->dma_rx_phy, GFP_KERNEL); if (rx_ring->dma_rx == NULL) - goto error; + return -ENOMEM; /* allocate memory for RX skbuff array */ rx_ring->rx_skbuff_dma = kmalloc_array(rx_rsize, sizeof(dma_addr_t), GFP_KERNEL); if (!rx_ring->rx_skbuff_dma) { - dma_free_coherent(priv->device, - rx_rsize * sizeof(struct sxgbe_rx_norm_desc), - rx_ring->dma_rx, rx_ring->dma_rx_phy); - goto error; + ret = -ENOMEM; + goto err_free_dma_rx; } rx_ring->rx_skbuff = kmalloc_array(rx_rsize, sizeof(struct sk_buff *), GFP_KERNEL); if (!rx_ring->rx_skbuff) { - kfree(rx_ring->rx_skbuff_dma); - goto error; + ret = -ENOMEM; + goto err_free_skbuff_dma; } /* initialise the buffers */ @@ -495,7 +513,7 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, ret = sxgbe_init_rx_buffers(dev, p, desc_index, bfsize, rx_ring); if (ret) - goto err_init_rx_buffers; + goto err_free_rx_buffers; } /* initalise counters */ @@ -505,11 +523,22 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, return 0; -err_init_rx_buffers: - while (--desc_index >= 0) - free_rx_ring(priv->device, rx_ring, desc_index); -error: - return -ENOMEM; +err_free_rx_buffers: + while (--desc_index >= 0) { + struct sxgbe_rx_norm_desc *p; + + p = rx_ring->dma_rx + desc_index; + sxgbe_free_rx_buffers(dev, p, desc_index, bfsize, rx_ring); + } + kfree(rx_ring->rx_skbuff); +err_free_skbuff_dma: + kfree(rx_ring->rx_skbuff_dma); +err_free_dma_rx: + dma_free_coherent(priv->device, + rx_rsize * sizeof(struct sxgbe_rx_norm_desc), + rx_ring->dma_rx, rx_ring->dma_rx_phy); + + return ret; } /** * free_tx_ring - free the TX descriptor ring -- cgit v1.2.1 From 6e0ba47f9191511a91556b7ca2c491362680a0f3 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Thu, 5 Feb 2015 14:52:06 +0100 Subject: dsa: do not dereference non-existing routing table In the case where there is only one switch, no routing table will have been allocated, so do not dereference it in this case. Signed-off-by: Tobias Waldekranz Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6131.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index 1230f52aa70e..2540ef0142af 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -139,7 +139,8 @@ static int mv88e6131_setup_global(struct dsa_switch *ds) int nexthop; nexthop = 0x1f; - if (i != ds->index && i < ds->dst->pd->nr_chips) + if (ds->pd->rtable && + i != ds->index && i < ds->dst->pd->nr_chips) nexthop = ds->pd->rtable[i] & 0x1f; REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop); -- cgit v1.2.1 From b083668c93e5bf889e6ec4761540be1accc3f1b1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Feb 2015 11:40:41 -0800 Subject: net: dsa: bcm_sf2: move GPHY enabling to its own function Move the code that touches the single GPHY register from bcm_sf2_sw_resume() to a separate function since we will have to enable/disable the GPHY from different locations, and we want the code to be self-contained. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 09f6b3cc1f66..45c0e2b97f5f 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -233,6 +233,24 @@ static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable) core_writel(priv, reg, CORE_EEE_EN_CTRL); } +static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable) +{ + struct bcm_sf2_priv *priv = ds_to_priv(ds); + u32 reg; + + if (!enable) + return; + + reg = reg_readl(priv, REG_SPHY_CNTRL); + reg |= PHY_RESET; + reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS); + reg_writel(priv, reg, REG_SPHY_CNTRL); + udelay(21); + reg = reg_readl(priv, REG_SPHY_CNTRL); + reg &= ~PHY_RESET; + reg_writel(priv, reg, REG_SPHY_CNTRL); +} + static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, struct phy_device *phy) { @@ -771,7 +789,6 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) { struct bcm_sf2_priv *priv = ds_to_priv(ds); unsigned int port; - u32 reg; int ret; ret = bcm_sf2_sw_rst(priv); @@ -780,17 +797,8 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) return ret; } - /* Reinitialize the single GPHY */ - if (priv->hw_params.num_gphy == 1) { - reg = reg_readl(priv, REG_SPHY_CNTRL); - reg |= PHY_RESET; - reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS); - reg_writel(priv, reg, REG_SPHY_CNTRL); - udelay(21); - reg = reg_readl(priv, REG_SPHY_CNTRL); - reg &= ~PHY_RESET; - reg_writel(priv, reg, REG_SPHY_CNTRL); - } + if (priv->hw_params.num_gphy == 1) + bcm_sf2_gphy_enable_set(ds, true); for (port = 0; port < DSA_MAX_PORTS; port++) { if ((1 << port) & ds->phys_port_mask) -- cgit v1.2.1 From 9af197a8f6ecab8c22e4ad0167616151fce5a4cb Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Feb 2015 11:40:42 -0800 Subject: net: dsa: bcm_sf2: implement GPHY power down Implement the power on/off recommended procedure for the Single GPHY we have on our Starfighter 2 switch. In order to make sure we get proper LED link/activity signaling during suspend, switch the link indication from the Switch/MAC to the PHY. Finally, since the GPHY needs to be reset to be put in low power mode, we will loose any context applied to it: workarounds, EEE etc.. so we need to call phy_init_hw() to get our fixups re-applied successfully. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 50 ++++++++++++++++++++++++++++++++++-------- drivers/net/dsa/bcm_sf2_regs.h | 4 ++++ 2 files changed, 45 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 45c0e2b97f5f..4daffb284931 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -238,17 +238,28 @@ static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable) struct bcm_sf2_priv *priv = ds_to_priv(ds); u32 reg; - if (!enable) - return; - - reg = reg_readl(priv, REG_SPHY_CNTRL); - reg |= PHY_RESET; - reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS); - reg_writel(priv, reg, REG_SPHY_CNTRL); - udelay(21); reg = reg_readl(priv, REG_SPHY_CNTRL); - reg &= ~PHY_RESET; + if (enable) { + reg |= PHY_RESET; + reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | CK25_DIS); + reg_writel(priv, reg, REG_SPHY_CNTRL); + udelay(21); + reg = reg_readl(priv, REG_SPHY_CNTRL); + reg &= ~PHY_RESET; + } else { + reg |= EXT_PWR_DOWN | IDDQ_BIAS | PHY_RESET; + reg_writel(priv, reg, REG_SPHY_CNTRL); + mdelay(1); + reg |= CK25_DIS; + } reg_writel(priv, reg, REG_SPHY_CNTRL); + + /* Use PHY-driven LED signaling */ + if (!enable) { + reg = reg_readl(priv, REG_LED_CNTRL(0)); + reg |= SPDLNK_SRC_SEL; + reg_writel(priv, reg, REG_LED_CNTRL(0)); + } } static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, @@ -266,6 +277,24 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, /* Clear the Rx and Tx disable bits and set to no spanning tree */ core_writel(priv, 0, CORE_G_PCTL_PORT(port)); + /* Re-enable the GPHY and re-apply workarounds */ + if (port == 0 && priv->hw_params.num_gphy == 1) { + bcm_sf2_gphy_enable_set(ds, true); + if (phy) { + /* if phy_stop() has been called before, phy + * will be in halted state, and phy_start() + * will call resume. + * + * the resume path does not configure back + * autoneg settings, and since we hard reset + * the phy manually here, we need to reset the + * state machine also. + */ + phy->state = PHY_READY; + phy_init_hw(phy); + } + } + /* Enable port 7 interrupts to get notified */ if (port == 7) intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF)); @@ -299,6 +328,9 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port, intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR); } + if (port == 0 && priv->hw_params.num_gphy == 1) + bcm_sf2_gphy_enable_set(ds, false); + if (dsa_is_cpu_port(ds, port)) off = CORE_IMP_CTL; else diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h index 1bb49cb699ab..cabdfa5e217a 100644 --- a/drivers/net/dsa/bcm_sf2_regs.h +++ b/drivers/net/dsa/bcm_sf2_regs.h @@ -61,6 +61,10 @@ #define LPI_COUNT_SHIFT 9 #define LPI_COUNT_MASK 0x3F +#define REG_LED_CNTRL_BASE 0x90 +#define REG_LED_CNTRL(x) (REG_LED_CNTRL_BASE + (x) * 4) +#define SPDLNK_SRC_SEL (1 << 24) + /* Register set relative to 'INTRL2_0' and 'INTRL2_1' */ #define INTRL2_CPU_STATUS 0x00 #define INTRL2_CPU_SET 0x04 -- cgit v1.2.1 From fd972b736bfec7e0297dac9501211abb91b436fd Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Thu, 5 Feb 2015 19:17:14 -0600 Subject: amd-xgbe: Check per channel DMA interrupt use in main ISR When using per channel DMA interrupts the transmit interrupt (TI) and the receive interrupt (RI) are masked off so as to not generate an interrupt to the main ISR. However, should another interrupt fire for the DMA channel that is handled by the main ISR the TI/RI bits can still be set. This will cause the wrong and uninitialized napi structure to be used causing a panic. Add a check to be sure per channel DMA interrupts are not enabled before acting on those bit flags. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index e5ffb2ccb67d..477a7e35d21a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -337,12 +337,13 @@ static irqreturn_t xgbe_isr(int irq, void *data) dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); DBGPR(" DMA_CH%u_ISR = %08x\n", i, dma_ch_isr); - /* If we get a TI or RI interrupt that means per channel DMA - * interrupts are not enabled, so we use the private data napi - * structure, not the per channel napi structure + /* The TI or RI interrupt bits may still be set even if using + * per channel DMA interrupts. Check to be sure those are not + * enabled before using the private data napi structure. */ - if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) || - XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI)) { + if (!pdata->per_channel_irq && + (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) || + XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI))) { if (napi_schedule_prep(&pdata->napi)) { /* Disable Tx and Rx interrupts */ xgbe_disable_rx_tx_ints(pdata); -- cgit v1.2.1 From e1a2ca92727500ea8d25326216d700bed6176117 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 6 Feb 2015 11:30:45 +0800 Subject: r8152: adjust rx_bottom If a error occurs when submitting rx, skip the remaining submissions and try to submit them again next time. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index b74a272243ae..41a1cbc6cc7f 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1643,7 +1643,7 @@ static int rx_bottom(struct r8152 *tp, int budget) { unsigned long flags; struct list_head *cursor, *next, rx_queue; - int work_done = 0; + int ret = 0, work_done = 0; if (!skb_queue_empty(&tp->rx_queue)) { while (work_done < budget) { @@ -1734,7 +1734,18 @@ find_next_rx: } submit: - r8152_submit_rx(tp, agg, GFP_ATOMIC); + if (!ret) { + ret = r8152_submit_rx(tp, agg, GFP_ATOMIC); + } else { + urb->actual_length = 0; + list_add_tail(&agg->list, next); + } + } + + if (!list_empty(&rx_queue)) { + spin_lock_irqsave(&tp->rx_lock, flags); + list_splice_tail(&rx_queue, &tp->rx_done); + spin_unlock_irqrestore(&tp->rx_lock, flags); } out1: -- cgit v1.2.1 From 34203e25cb04ca942e29907b602c4f3d40e3c8ec Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 6 Feb 2015 11:30:46 +0800 Subject: r8152: adjust lpm timer Set LPM timer to 500us, except for RTL_VER_04 which doesn't link at USB 3.0. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 41a1cbc6cc7f..ff122fae6586 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3256,10 +3256,10 @@ static void r8153_init(struct r8152 *tp) ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL); ocp_data &= ~LPM_TIMER_MASK; - if (tp->udev->speed == USB_SPEED_SUPER) - ocp_data |= LPM_TIMER_500US; - else + if (tp->version == RTL_VER_04 && tp->udev->speed != USB_SPEED_SUPER) ocp_data |= LPM_TIMER_500MS; + else + ocp_data |= LPM_TIMER_500US; ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data); ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2); -- cgit v1.2.1 From 51d979faa274d2a924907bdf59f88a216dcc19a9 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 6 Feb 2015 11:30:47 +0800 Subject: r8152: check linking status with netif_carrier_ok Replace (tp->speed & LINK_STATUS) with netif_carrier_ok(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ff122fae6586..66678093db10 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -581,7 +581,6 @@ struct r8152 { u16 ocp_base; u8 *intr_buff; u8 version; - u8 speed; }; enum rtl_version { @@ -1157,12 +1156,12 @@ static void intr_callback(struct urb *urb) d = urb->transfer_buffer; if (INTR_LINK & __le16_to_cpu(d[0])) { - if (!(tp->speed & LINK_STATUS)) { + if (!netif_carrier_ok(tp->netdev)) { set_bit(RTL8152_LINK_CHG, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } } else { - if (tp->speed & LINK_STATUS) { + if (netif_carrier_ok(tp->netdev)) { set_bit(RTL8152_LINK_CHG, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } @@ -1894,7 +1893,7 @@ static void rtl8152_set_rx_mode(struct net_device *netdev) { struct r8152 *tp = netdev_priv(netdev); - if (tp->speed & LINK_STATUS) { + if (netif_carrier_ok(netdev)) { set_bit(RTL8152_SET_RX_MODE, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } @@ -2918,21 +2917,20 @@ static void set_carrier(struct r8152 *tp) speed = rtl8152_get_speed(tp); if (speed & LINK_STATUS) { - if (!(tp->speed & LINK_STATUS)) { + if (!netif_carrier_ok(netdev)) { tp->rtl_ops.enable(tp); set_bit(RTL8152_SET_RX_MODE, &tp->flags); netif_carrier_on(netdev); rtl_start_rx(tp); } } else { - if (tp->speed & LINK_STATUS) { + if (netif_carrier_ok(netdev)) { netif_carrier_off(netdev); napi_disable(&tp->napi); tp->rtl_ops.disable(tp); napi_enable(&tp->napi); } } - tp->speed = speed; } static void rtl_work_func_t(struct work_struct *work) @@ -2964,7 +2962,7 @@ static void rtl_work_func_t(struct work_struct *work) /* don't schedule napi before linking */ if (test_bit(SCHEDULE_NAPI, &tp->flags) && - (tp->speed & LINK_STATUS)) { + netif_carrier_ok(tp->netdev)) { clear_bit(SCHEDULE_NAPI, &tp->flags); napi_schedule(&tp->napi); } @@ -2987,8 +2985,7 @@ static int rtl8152_open(struct net_device *netdev) if (res) goto out; - /* set speed to 0 to avoid autoresume try to submit rx */ - tp->speed = 0; + netif_carrier_off(netdev); res = usb_autopm_get_interface(tp->intf); if (res < 0) { @@ -3005,7 +3002,7 @@ static int rtl8152_open(struct net_device *netdev) cancel_delayed_work_sync(&tp->schedule); /* disable the tx/rx, if the workqueue has enabled them. */ - if (tp->speed & LINK_STATUS) + if (netif_carrier_ok(netdev)) tp->rtl_ops.disable(tp); } @@ -3014,7 +3011,6 @@ static int rtl8152_open(struct net_device *netdev) rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); - tp->speed = 0; netif_carrier_off(netdev); netif_start_queue(netdev); set_bit(WORK_ENABLE, &tp->flags); @@ -3340,7 +3336,7 @@ static int rtl8152_resume(struct usb_interface *intf) rtl_runtime_suspend_enable(tp, false); clear_bit(SELECTIVE_SUSPEND, &tp->flags); set_bit(WORK_ENABLE, &tp->flags); - if (tp->speed & LINK_STATUS) + if (netif_carrier_ok(tp->netdev)) rtl_start_rx(tp); } else { tp->rtl_ops.up(tp); @@ -3348,7 +3344,6 @@ static int rtl8152_resume(struct usb_interface *intf) tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); - tp->speed = 0; netif_carrier_off(tp->netdev); set_bit(WORK_ENABLE, &tp->flags); } -- cgit v1.2.1 From 53543db5d5e3e147c5e03cecb1495d7d50ca43e2 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 6 Feb 2015 11:30:48 +0800 Subject: r8152: check RTL8152_UNPLUG for rtl8152_close It is unnecessary to accress the hw register if the device is unplugged. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 66678093db10..aade7b545f02 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3046,7 +3046,7 @@ static int rtl8152_close(struct net_device *netdev) netif_stop_queue(netdev); res = usb_autopm_get_interface(tp->intf); - if (res < 0) { + if (res < 0 || test_bit(RTL8152_UNPLUG, &tp->flags)) { rtl_drop_queued_tx(tp); rtl_stop_rx(tp); } else { -- cgit v1.2.1 From ccc39faf58113b33ed100b7c24d806538ac75df7 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 6 Feb 2015 11:30:49 +0800 Subject: r8152: adjust the line feed for hw_features Keep NETIF_F_HW_VLAN_CTAG_RX and NETIF_F_HW_VLAN_CTAG_TX at the same line. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index aade7b545f02..8bdd4773233e 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3908,8 +3908,7 @@ static int rtl8152_probe(struct usb_interface *intf, netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | NETIF_F_TSO6 | - NETIF_F_HW_VLAN_CTAG_RX | - NETIF_F_HW_VLAN_CTAG_TX; + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | NETIF_F_TSO6; -- cgit v1.2.1 From 6e74d1749a338d1435b413a92968f7e3de7c0278 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 6 Feb 2015 11:30:50 +0800 Subject: r8152: replace get_protocol with vlan_get_protocol vlan_get_protocol() has been defined and use it to replace get_protocol(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 8bdd4773233e..24e6aef907eb 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1330,18 +1330,6 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) return agg; } -static inline __be16 get_protocol(struct sk_buff *skb) -{ - __be16 protocol; - - if (skb->protocol == htons(ETH_P_8021Q)) - protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; - else - protocol = skb->protocol; - - return protocol; -} - /* r8152_csum_workaround() * The hw limites the value the transport offset. When the offset is out of the * range, calculate the checksum by sw. @@ -1447,7 +1435,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, goto unavailable; } - switch (get_protocol(skb)) { + switch (vlan_get_protocol(skb)) { case htons(ETH_P_IP): opts1 |= GTSENDV4; break; @@ -1478,7 +1466,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, goto unavailable; } - switch (get_protocol(skb)) { + switch (vlan_get_protocol(skb)) { case htons(ETH_P_IP): opts2 |= IPV4_CS; ip_protocol = ip_hdr(skb)->protocol; -- cgit v1.2.1 From f5aaaa6db62ac679ca42884cb8e22db7330cfca9 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 6 Feb 2015 11:30:51 +0800 Subject: r8152: use BIT macro Use BIT macro to replace (1 << bits). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 24e6aef907eb..5980ac6c48dd 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -489,16 +489,16 @@ struct rx_desc { #define RX_LEN_MASK 0x7fff __le32 opts2; -#define RD_UDP_CS (1 << 23) -#define RD_TCP_CS (1 << 22) -#define RD_IPV6_CS (1 << 20) -#define RD_IPV4_CS (1 << 19) +#define RD_UDP_CS BIT(23) +#define RD_TCP_CS BIT(22) +#define RD_IPV6_CS BIT(20) +#define RD_IPV4_CS BIT(19) __le32 opts3; -#define IPF (1 << 23) /* IP checksum fail */ -#define UDPF (1 << 22) /* UDP checksum fail */ -#define TCPF (1 << 21) /* TCP checksum fail */ -#define RX_VLAN_TAG (1 << 16) +#define IPF BIT(23) /* IP checksum fail */ +#define UDPF BIT(22) /* UDP checksum fail */ +#define TCPF BIT(21) /* TCP checksum fail */ +#define RX_VLAN_TAG BIT(16) __le32 opts4; __le32 opts5; @@ -507,24 +507,24 @@ struct rx_desc { struct tx_desc { __le32 opts1; -#define TX_FS (1 << 31) /* First segment of a packet */ -#define TX_LS (1 << 30) /* Final segment of a packet */ -#define GTSENDV4 (1 << 28) -#define GTSENDV6 (1 << 27) +#define TX_FS BIT(31) /* First segment of a packet */ +#define TX_LS BIT(30) /* Final segment of a packet */ +#define GTSENDV4 BIT(28) +#define GTSENDV6 BIT(27) #define GTTCPHO_SHIFT 18 #define GTTCPHO_MAX 0x7fU #define TX_LEN_MAX 0x3ffffU __le32 opts2; -#define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */ -#define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */ -#define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */ -#define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */ +#define UDP_CS BIT(31) /* Calculate UDP/IP checksum */ +#define TCP_CS BIT(30) /* Calculate TCP/IP checksum */ +#define IPV4_CS BIT(29) /* Calculate IPv4 checksum */ +#define IPV6_CS BIT(28) /* Calculate IPv6 checksum */ #define MSS_SHIFT 17 #define MSS_MAX 0x7ffU #define TCPHO_SHIFT 17 #define TCPHO_MAX 0x7ffU -#define TX_VLAN_TAG (1 << 16) +#define TX_VLAN_TAG BIT(16) }; struct r8152; -- cgit v1.2.1 From f7062ee5e44a044da41cdae8370368314103a930 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Fri, 6 Feb 2015 08:18:35 -0500 Subject: be2net: move un-exported routines from be.h to respective src files Routines that are called only inside one src file must remain in that file itself. Including them in a header file that is used for exporting routine/struct definitions, causes unnecessary compilation of other src files, when such a routine is modified. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 166 ---------------------------- drivers/net/ethernet/emulex/benet/be_cmds.c | 18 +++ drivers/net/ethernet/emulex/benet/be_main.c | 149 +++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 166 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 9fa2569f56cb..3b1d59d1bd1c 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -59,26 +59,6 @@ #define OC_SUBSYS_DEVICE_ID3 0xE612 #define OC_SUBSYS_DEVICE_ID4 0xE652 -static inline char *nic_name(struct pci_dev *pdev) -{ - switch (pdev->device) { - case OC_DEVICE_ID1: - return OC_NAME; - case OC_DEVICE_ID2: - return OC_NAME_BE; - case OC_DEVICE_ID3: - case OC_DEVICE_ID4: - return OC_NAME_LANCER; - case BE_DEVICE_ID2: - return BE3_NAME; - case OC_DEVICE_ID5: - case OC_DEVICE_ID6: - return OC_NAME_SH; - default: - return BE_NAME; - } -} - /* Number of bytes of an RX frame that are copied to skb->data */ #define BE_HDR_LEN ((u16) 64) /* allocate extra space to allow tunneling decapsulation without head reallocation */ @@ -734,19 +714,6 @@ static inline bool is_ipv4_pkt(struct sk_buff *skb) return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4; } -static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) -{ - u32 addr; - - addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0); - - mac[5] = (u8)(addr & 0xFF); - mac[4] = (u8)((addr >> 8) & 0xFF); - mac[3] = (u8)((addr >> 16) & 0xFF); - /* Use the OUI from the current MAC address */ - memcpy(mac, adapter->netdev->dev_addr, 3); -} - static inline bool be_multi_rxq(const struct be_adapter *adapter) { return adapter->num_rx_qs > 1; @@ -769,129 +736,6 @@ static inline void be_clear_all_error(struct be_adapter *adapter) adapter->fw_timeout = false; } -static inline bool be_is_wol_excluded(struct be_adapter *adapter) -{ - struct pci_dev *pdev = adapter->pdev; - - if (!be_physfn(adapter)) - return true; - - switch (pdev->subsystem_device) { - case OC_SUBSYS_DEVICE_ID1: - case OC_SUBSYS_DEVICE_ID2: - case OC_SUBSYS_DEVICE_ID3: - case OC_SUBSYS_DEVICE_ID4: - return true; - default: - return false; - } -} - -static inline int qnq_async_evt_rcvd(struct be_adapter *adapter) -{ - return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD; -} - -#ifdef CONFIG_NET_RX_BUSY_POLL -static inline bool be_lock_napi(struct be_eq_obj *eqo) -{ - bool status = true; - - spin_lock(&eqo->lock); /* BH is already disabled */ - if (eqo->state & BE_EQ_LOCKED) { - WARN_ON(eqo->state & BE_EQ_NAPI); - eqo->state |= BE_EQ_NAPI_YIELD; - status = false; - } else { - eqo->state = BE_EQ_NAPI; - } - spin_unlock(&eqo->lock); - return status; -} - -static inline void be_unlock_napi(struct be_eq_obj *eqo) -{ - spin_lock(&eqo->lock); /* BH is already disabled */ - - WARN_ON(eqo->state & (BE_EQ_POLL | BE_EQ_NAPI_YIELD)); - eqo->state = BE_EQ_IDLE; - - spin_unlock(&eqo->lock); -} - -static inline bool be_lock_busy_poll(struct be_eq_obj *eqo) -{ - bool status = true; - - spin_lock_bh(&eqo->lock); - if (eqo->state & BE_EQ_LOCKED) { - eqo->state |= BE_EQ_POLL_YIELD; - status = false; - } else { - eqo->state |= BE_EQ_POLL; - } - spin_unlock_bh(&eqo->lock); - return status; -} - -static inline void be_unlock_busy_poll(struct be_eq_obj *eqo) -{ - spin_lock_bh(&eqo->lock); - - WARN_ON(eqo->state & (BE_EQ_NAPI)); - eqo->state = BE_EQ_IDLE; - - spin_unlock_bh(&eqo->lock); -} - -static inline void be_enable_busy_poll(struct be_eq_obj *eqo) -{ - spin_lock_init(&eqo->lock); - eqo->state = BE_EQ_IDLE; -} - -static inline void be_disable_busy_poll(struct be_eq_obj *eqo) -{ - local_bh_disable(); - - /* It's enough to just acquire napi lock on the eqo to stop - * be_busy_poll() from processing any queueus. - */ - while (!be_lock_napi(eqo)) - mdelay(1); - - local_bh_enable(); -} - -#else /* CONFIG_NET_RX_BUSY_POLL */ - -static inline bool be_lock_napi(struct be_eq_obj *eqo) -{ - return true; -} - -static inline void be_unlock_napi(struct be_eq_obj *eqo) -{ -} - -static inline bool be_lock_busy_poll(struct be_eq_obj *eqo) -{ - return false; -} - -static inline void be_unlock_busy_poll(struct be_eq_obj *eqo) -{ -} - -static inline void be_enable_busy_poll(struct be_eq_obj *eqo) -{ -} - -static inline void be_disable_busy_poll(struct be_eq_obj *eqo) -{ -} -#endif /* CONFIG_NET_RX_BUSY_POLL */ - void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); void be_link_status_update(struct be_adapter *adapter, u8 link_status); @@ -900,16 +744,6 @@ int be_load_fw(struct be_adapter *adapter, u8 *func); bool be_is_wol_supported(struct be_adapter *adapter); bool be_pause_supported(struct be_adapter *adapter); u32 be_get_fw_log_level(struct be_adapter *adapter); - -static inline int fw_major_num(const char *fw_ver) -{ - int fw_major = 0; - - sscanf(fw_ver, "%d.", &fw_major); - - return fw_major; -} - int be_update_queues(struct be_adapter *adapter); int be_poll(struct napi_struct *napi, int budget); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index b5aa77284508..6830bffa4eee 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -3241,6 +3241,24 @@ err: return status; } +static bool be_is_wol_excluded(struct be_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + if (!be_physfn(adapter)) + return true; + + switch (pdev->subsystem_device) { + case OC_SUBSYS_DEVICE_ID1: + case OC_SUBSYS_DEVICE_ID2: + case OC_SUBSYS_DEVICE_ID3: + case OC_SUBSYS_DEVICE_ID4: + return true; + default: + return false; + } +} + int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) { struct be_mcc_wrb *wrb; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index efed92c7b731..1605bd7a0749 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -854,6 +854,11 @@ dma_err: return 0; } +static inline int qnq_async_evt_rcvd(struct be_adapter *adapter) +{ + return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD; +} + static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, struct sk_buff *skb, bool *skip_hw_vlan) @@ -2526,6 +2531,106 @@ static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo, } } +#ifdef CONFIG_NET_RX_BUSY_POLL +static inline bool be_lock_napi(struct be_eq_obj *eqo) +{ + bool status = true; + + spin_lock(&eqo->lock); /* BH is already disabled */ + if (eqo->state & BE_EQ_LOCKED) { + WARN_ON(eqo->state & BE_EQ_NAPI); + eqo->state |= BE_EQ_NAPI_YIELD; + status = false; + } else { + eqo->state = BE_EQ_NAPI; + } + spin_unlock(&eqo->lock); + return status; +} + +static inline void be_unlock_napi(struct be_eq_obj *eqo) +{ + spin_lock(&eqo->lock); /* BH is already disabled */ + + WARN_ON(eqo->state & (BE_EQ_POLL | BE_EQ_NAPI_YIELD)); + eqo->state = BE_EQ_IDLE; + + spin_unlock(&eqo->lock); +} + +static inline bool be_lock_busy_poll(struct be_eq_obj *eqo) +{ + bool status = true; + + spin_lock_bh(&eqo->lock); + if (eqo->state & BE_EQ_LOCKED) { + eqo->state |= BE_EQ_POLL_YIELD; + status = false; + } else { + eqo->state |= BE_EQ_POLL; + } + spin_unlock_bh(&eqo->lock); + return status; +} + +static inline void be_unlock_busy_poll(struct be_eq_obj *eqo) +{ + spin_lock_bh(&eqo->lock); + + WARN_ON(eqo->state & (BE_EQ_NAPI)); + eqo->state = BE_EQ_IDLE; + + spin_unlock_bh(&eqo->lock); +} + +static inline void be_enable_busy_poll(struct be_eq_obj *eqo) +{ + spin_lock_init(&eqo->lock); + eqo->state = BE_EQ_IDLE; +} + +static inline void be_disable_busy_poll(struct be_eq_obj *eqo) +{ + local_bh_disable(); + + /* It's enough to just acquire napi lock on the eqo to stop + * be_busy_poll() from processing any queueus. + */ + while (!be_lock_napi(eqo)) + mdelay(1); + + local_bh_enable(); +} + +#else /* CONFIG_NET_RX_BUSY_POLL */ + +static inline bool be_lock_napi(struct be_eq_obj *eqo) +{ + return true; +} + +static inline void be_unlock_napi(struct be_eq_obj *eqo) +{ +} + +static inline bool be_lock_busy_poll(struct be_eq_obj *eqo) +{ + return false; +} + +static inline void be_unlock_busy_poll(struct be_eq_obj *eqo) +{ +} + +static inline void be_enable_busy_poll(struct be_eq_obj *eqo) +{ +} + +static inline void be_disable_busy_poll(struct be_eq_obj *eqo) +{ +} +#endif /* CONFIG_NET_RX_BUSY_POLL */ + int be_poll(struct napi_struct *napi, int budget) { struct be_eq_obj *eqo = container_of(napi, struct be_eq_obj, napi); @@ -3020,6 +3125,19 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) return status; } +static void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) +{ + u32 addr; + + addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0); + + mac[5] = (u8)(addr & 0xFF); + mac[4] = (u8)((addr >> 8) & 0xFF); + mac[3] = (u8)((addr >> 16) & 0xFF); + /* Use the OUI from the current MAC address */ + memcpy(mac, adapter->netdev->dev_addr, 3); +} + /* * Generate a seed MAC address from the PF MAC Address using jhash. * MAC Address for VFs are assigned incrementally starting from the seed. @@ -3664,6 +3782,17 @@ int be_update_queues(struct be_adapter *adapter) return status; } +static inline int fw_major_num(const char *fw_ver) +{ + int fw_major = 0, i; + + i = sscanf(fw_ver, "%d.", &fw_major); + if (i != 1) + return 0; + + return fw_major; +} + static int be_setup(struct be_adapter *adapter) { struct device *dev = &adapter->pdev->dev; @@ -4940,6 +5069,26 @@ static inline char *func_name(struct be_adapter *adapter) return be_physfn(adapter) ? "PF" : "VF"; } +static inline char *nic_name(struct pci_dev *pdev) +{ + switch (pdev->device) { + case OC_DEVICE_ID1: + return OC_NAME; + case OC_DEVICE_ID2: + return OC_NAME_BE; + case OC_DEVICE_ID3: + case OC_DEVICE_ID4: + return OC_NAME_LANCER; + case BE_DEVICE_ID2: + return BE3_NAME; + case OC_DEVICE_ID5: + case OC_DEVICE_ID6: + return OC_NAME_SH; + default: + return BE_NAME; + } +} + static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) { int status = 0; -- cgit v1.2.1 From 83b06116994a8c3648b03da92d7fc0ac839c8ced Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Fri, 6 Feb 2015 08:18:36 -0500 Subject: be2net: replace (1 << x) with BIT(x) BIT(x) is the preffered usage. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 18 +++++++++--------- drivers/net/ethernet/emulex/benet/be_cmds.h | 8 ++++---- drivers/net/ethernet/emulex/benet/be_hw.h | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 3b1d59d1bd1c..9869556f367d 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -361,15 +361,15 @@ enum vf_state { ASSIGNED = 1 }; -#define BE_FLAGS_LINK_STATUS_INIT 1 -#define BE_FLAGS_SRIOV_ENABLED (1 << 2) -#define BE_FLAGS_WORKER_SCHEDULED (1 << 3) -#define BE_FLAGS_VLAN_PROMISC (1 << 4) -#define BE_FLAGS_MCAST_PROMISC (1 << 5) -#define BE_FLAGS_NAPI_ENABLED (1 << 9) -#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11) -#define BE_FLAGS_VXLAN_OFFLOADS (1 << 12) -#define BE_FLAGS_SETUP_DONE (1 << 13) +#define BE_FLAGS_LINK_STATUS_INIT BIT(1) +#define BE_FLAGS_SRIOV_ENABLED BIT(2) +#define BE_FLAGS_WORKER_SCHEDULED BIT(3) +#define BE_FLAGS_VLAN_PROMISC BIT(4) +#define BE_FLAGS_MCAST_PROMISC BIT(5) +#define BE_FLAGS_NAPI_ENABLED BIT(6) +#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD BIT(7) +#define BE_FLAGS_VXLAN_OFFLOADS BIT(8) +#define BE_FLAGS_SETUP_DONE BIT(9) #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index c2701ccd0a1d..c231e45e7070 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -44,10 +44,10 @@ struct be_mcc_wrb { } payload; }; -#define CQE_FLAGS_VALID_MASK (1 << 31) -#define CQE_FLAGS_ASYNC_MASK (1 << 30) -#define CQE_FLAGS_COMPLETED_MASK (1 << 28) -#define CQE_FLAGS_CONSUMED_MASK (1 << 27) +#define CQE_FLAGS_VALID_MASK BIT(31) +#define CQE_FLAGS_ASYNC_MASK BIT(30) +#define CQE_FLAGS_COMPLETED_MASK BIT(28) +#define CQE_FLAGS_CONSUMED_MASK BIT(27) /* Completion Status */ enum mcc_base_status { diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index 8e91ae851a7c..a8593aa46359 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -75,7 +75,7 @@ * atomically without having to arbitrate for the PCI Interrupt Disable bit * with the OS. */ -#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */ +#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK BIT(29) /* bit 29 */ /********* PCI Function Capability *********/ #define BE_FUNCTION_CAPS_RSS 0x2 @@ -224,7 +224,7 @@ struct amap_eth_hdr_wrb { } __packed; #define TX_HDR_WRB_COMPL 1 /* word 2 */ -#define TX_HDR_WRB_EVT (1 << 1) /* word 2 */ +#define TX_HDR_WRB_EVT BIT(1) /* word 2 */ #define TX_HDR_WRB_NUM_SHIFT 13 /* word 2: bits 13:17 */ #define TX_HDR_WRB_NUM_MASK 0x1F /* word 2: bits 13:17 */ -- cgit v1.2.1 From 5d3acd0d161012caee0a8be2d03ac04ba901df09 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Fri, 6 Feb 2015 08:18:37 -0500 Subject: be2net: refactor code that checks flash file compatibility This patch re-factors the code that checks for flash file compatibility with the chip type, for better readability, as follows: - be_get_ufi_type() returns the UFI type from the flash file - be_check_ufi_compatibility() checks if the UFI type is compatible with the adapter/chip that is being flashed Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.h | 8 ++ drivers/net/ethernet/emulex/benet/be_main.c | 138 ++++++++++++++-------------- 2 files changed, 78 insertions(+), 68 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index c231e45e7070..bed4a32c41f3 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1091,6 +1091,9 @@ struct be_cmd_req_query_fw_cfg { u32 rsvd[31]; }; +/* ASIC revisions */ +#define ASIC_REV_B0 0x10 + struct be_cmd_resp_query_fw_cfg { struct be_cmd_resp_hdr hdr; u32 be_config_number; @@ -1260,6 +1263,11 @@ struct flash_file_hdr_g2 { u8 build[24]; }; +/* First letter of the build version of the image */ +#define BLD_STR_UFI_TYPE_BE2 '2' +#define BLD_STR_UFI_TYPE_BE3 '3' +#define BLD_STR_UFI_TYPE_SH '4' + struct flash_file_hdr_g3 { u8 sign[52]; u8 ufi_version[4]; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 1605bd7a0749..2b9e1be1568d 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4058,6 +4058,7 @@ static int be_flash_BEx(struct be_adapter *adapter, pflashcomp = gen2_flash_types; filehdr_size = sizeof(struct flash_file_hdr_g2); num_comp = ARRAY_SIZE(gen2_flash_types); + img_hdrs_size = 0; } /* Get flash section info*/ @@ -4331,98 +4332,99 @@ static int lancer_fw_download(struct be_adapter *adapter, return 0; } -#define UFI_TYPE2 2 -#define UFI_TYPE3 3 -#define UFI_TYPE3R 10 -#define UFI_TYPE4 4 +#define BE2_UFI 2 +#define BE3_UFI 3 +#define BE3R_UFI 10 +#define SH_UFI 4 + static int be_get_ufi_type(struct be_adapter *adapter, struct flash_file_hdr_g3 *fhdr) { - if (!fhdr) - goto be_get_ufi_exit; + if (!fhdr) { + dev_err(&adapter->pdev->dev, "Invalid FW UFI file"); + return -1; + } - if (skyhawk_chip(adapter) && fhdr->build[0] == '4') - return UFI_TYPE4; - else if (BE3_chip(adapter) && fhdr->build[0] == '3') { - if (fhdr->asic_type_rev == 0x10) - return UFI_TYPE3R; - else - return UFI_TYPE3; - } else if (BE2_chip(adapter) && fhdr->build[0] == '2') - return UFI_TYPE2; + /* First letter of the build version is used to identify + * which chip this image file is meant for. + */ + switch (fhdr->build[0]) { + case BLD_STR_UFI_TYPE_SH: + return SH_UFI; + case BLD_STR_UFI_TYPE_BE3: + return (fhdr->asic_type_rev == ASIC_REV_B0) ? BE3R_UFI : + BE3_UFI; + case BLD_STR_UFI_TYPE_BE2: + return BE2_UFI; + default: + return -1; + } +} -be_get_ufi_exit: - dev_err(&adapter->pdev->dev, - "UFI and Interface are not compatible for flashing\n"); - return -1; +/* Check if the flash image file is compatible with the adapter that + * is being flashed. + * BE3 chips with asic-rev B0 must be flashed only with BE3R_UFI type. + */ +static bool be_check_ufi_compatibility(struct be_adapter *adapter, + struct flash_file_hdr_g3 *fhdr) +{ + int ufi_type = be_get_ufi_type(adapter, fhdr); + + switch (ufi_type) { + case SH_UFI: + return skyhawk_chip(adapter); + case BE3R_UFI: + return BE3_chip(adapter); + case BE3_UFI: + return (BE3_chip(adapter) && adapter->asic_rev < ASIC_REV_B0); + case BE2_UFI: + return BE2_chip(adapter); + default: + return false; + } } static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw) { + struct device *dev = &adapter->pdev->dev; struct flash_file_hdr_g3 *fhdr3; - struct image_hdr *img_hdr_ptr = NULL; + struct image_hdr *img_hdr_ptr; + int status = 0, i, num_imgs; struct be_dma_mem flash_cmd; - const u8 *p; - int status = 0, i = 0, num_imgs = 0, ufi_type = 0; - flash_cmd.size = sizeof(struct be_cmd_write_flashrom); - flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size, - &flash_cmd.dma, GFP_KERNEL); - if (!flash_cmd.va) { - status = -ENOMEM; - goto be_fw_exit; + fhdr3 = (struct flash_file_hdr_g3 *)fw->data; + if (!be_check_ufi_compatibility(adapter, fhdr3)) { + dev_err(dev, "Flash image is not compatible with adapter\n"); + return -EINVAL; } - p = fw->data; - fhdr3 = (struct flash_file_hdr_g3 *)p; - - ufi_type = be_get_ufi_type(adapter, fhdr3); + flash_cmd.size = sizeof(struct be_cmd_write_flashrom); + flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size, &flash_cmd.dma, + GFP_KERNEL); + if (!flash_cmd.va) + return -ENOMEM; num_imgs = le32_to_cpu(fhdr3->num_imgs); for (i = 0; i < num_imgs; i++) { img_hdr_ptr = (struct image_hdr *)(fw->data + (sizeof(struct flash_file_hdr_g3) + i * sizeof(struct image_hdr))); - if (le32_to_cpu(img_hdr_ptr->imageid) == 1) { - switch (ufi_type) { - case UFI_TYPE4: - status = be_flash_skyhawk(adapter, fw, - &flash_cmd, num_imgs); - break; - case UFI_TYPE3R: - status = be_flash_BEx(adapter, fw, &flash_cmd, - num_imgs); - break; - case UFI_TYPE3: - /* Do not flash this ufi on BE3-R cards */ - if (adapter->asic_rev < 0x10) - status = be_flash_BEx(adapter, fw, - &flash_cmd, - num_imgs); - else { - status = -EINVAL; - dev_err(&adapter->pdev->dev, - "Can't load BE3 UFI on BE3R\n"); - } - } - } - } - - if (ufi_type == UFI_TYPE2) - status = be_flash_BEx(adapter, fw, &flash_cmd, 0); - else if (ufi_type == -1) - status = -EINVAL; + if (!BE2_chip(adapter) && + le32_to_cpu(img_hdr_ptr->imageid) != 1) + continue; - dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va, - flash_cmd.dma); - if (status) { - dev_err(&adapter->pdev->dev, "Firmware load error\n"); - goto be_fw_exit; + if (skyhawk_chip(adapter)) + status = be_flash_skyhawk(adapter, fw, &flash_cmd, + num_imgs); + else + status = be_flash_BEx(adapter, fw, &flash_cmd, + num_imgs); } - dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); + dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); + if (!status) + dev_info(dev, "Firmware flashed successfully\n"); -be_fw_exit: return status; } -- cgit v1.2.1 From 81a9e226ff2c5cf963a79c1cbecd6e68c0e35a21 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Fri, 6 Feb 2015 08:18:38 -0500 Subject: be2net: avoid flashing SH-B0 UFI image on SH-P2 chip Skyhawk-B0 FW UFI is not compatible to flash on Skyhawk-P2 ASIC. But, Skyhawk-P2 FW UFI is compatible with both B0 and P2 chips. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.h | 1 + drivers/net/ethernet/emulex/benet/be_main.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index bed4a32c41f3..774c5d1719e1 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1093,6 +1093,7 @@ struct be_cmd_req_query_fw_cfg { /* ASIC revisions */ #define ASIC_REV_B0 0x10 +#define ASIC_REV_P2 0x11 struct be_cmd_resp_query_fw_cfg { struct be_cmd_resp_hdr hdr; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 2b9e1be1568d..36f140a9c31e 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4336,6 +4336,7 @@ static int lancer_fw_download(struct be_adapter *adapter, #define BE3_UFI 3 #define BE3R_UFI 10 #define SH_UFI 4 +#define SH_P2_UFI 11 static int be_get_ufi_type(struct be_adapter *adapter, struct flash_file_hdr_g3 *fhdr) @@ -4350,7 +4351,8 @@ static int be_get_ufi_type(struct be_adapter *adapter, */ switch (fhdr->build[0]) { case BLD_STR_UFI_TYPE_SH: - return SH_UFI; + return (fhdr->asic_type_rev == ASIC_REV_P2) ? SH_P2_UFI : + SH_UFI; case BLD_STR_UFI_TYPE_BE3: return (fhdr->asic_type_rev == ASIC_REV_B0) ? BE3R_UFI : BE3_UFI; @@ -4364,6 +4366,7 @@ static int be_get_ufi_type(struct be_adapter *adapter, /* Check if the flash image file is compatible with the adapter that * is being flashed. * BE3 chips with asic-rev B0 must be flashed only with BE3R_UFI type. + * Skyhawk chips with asic-rev P2 must be flashed only with SH_P2_UFI type. */ static bool be_check_ufi_compatibility(struct be_adapter *adapter, struct flash_file_hdr_g3 *fhdr) @@ -4371,8 +4374,11 @@ static bool be_check_ufi_compatibility(struct be_adapter *adapter, int ufi_type = be_get_ufi_type(adapter, fhdr); switch (ufi_type) { - case SH_UFI: + case SH_P2_UFI: return skyhawk_chip(adapter); + case SH_UFI: + return (skyhawk_chip(adapter) && + adapter->asic_rev < ASIC_REV_P2); case BE3R_UFI: return BE3_chip(adapter); case BE3_UFI: -- cgit v1.2.1 From 70a7b5257018c518007c7212977bab6ccacd9468 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Fri, 6 Feb 2015 08:18:39 -0500 Subject: be2net: use offset based FW flashing for Skyhawk chip While sending FW update cmds to the FW, the driver specifies the "type" of each component that needs to be flashed. The FW then picks the offset in the flash area at which the componnet is to be flashed. This doesn't work when new components that the current FW doesn't recognize, need to be flashed. Recent FWs (10.2 and above) support a scheme of FW-update wherein the "offset" of the component in the flash area can be specified instead of the "type". This patch uses the "offset" based FW-update mechanism and only when it fails, it fallsback to the old "type" based update. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 18 +++++--- drivers/net/ethernet/emulex/benet/be_cmds.h | 6 ++- drivers/net/ethernet/emulex/benet/be_main.c | 65 ++++++++++++++++++++++------- 3 files changed, 66 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 6830bffa4eee..03119ac548f6 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2436,7 +2436,8 @@ err_unlock: } int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, - u32 flash_type, u32 flash_opcode, u32 buf_size) + u32 flash_type, u32 flash_opcode, u32 img_offset, + u32 buf_size) { struct be_mcc_wrb *wrb; struct be_cmd_write_flashrom *req; @@ -2457,6 +2458,9 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, cmd); req->params.op_type = cpu_to_le32(flash_type); + if (flash_type == OPTYPE_OFFSET_SPECIFIED) + req->params.offset = cpu_to_le32(img_offset); + req->params.op_code = cpu_to_le32(flash_opcode); req->params.data_buf_size = cpu_to_le32(buf_size); @@ -2477,10 +2481,10 @@ err_unlock: } int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, - u16 optype, int offset) + u16 img_optype, u32 img_offset, u32 crc_offset) { - struct be_mcc_wrb *wrb; struct be_cmd_read_flash_crc *req; + struct be_mcc_wrb *wrb; int status; spin_lock_bh(&adapter->mcc_lock); @@ -2496,9 +2500,13 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, OPCODE_COMMON_READ_FLASHROM, sizeof(*req), wrb, NULL); - req->params.op_type = cpu_to_le32(optype); + req->params.op_type = cpu_to_le32(img_optype); + if (img_optype == OPTYPE_OFFSET_SPECIFIED) + req->params.offset = cpu_to_le32(img_offset + crc_offset); + else + req->params.offset = cpu_to_le32(crc_offset); + req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT); - req->params.offset = cpu_to_le32(offset); req->params.data_buf_size = cpu_to_le32(0x4); status = be_mcc_notify_wait(adapter); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 774c5d1719e1..402d64f5bb7c 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1172,6 +1172,7 @@ struct be_cmd_resp_get_beacon_state { #define OPTYPE_REDBOOT 1 #define OPTYPE_BIOS 2 #define OPTYPE_PXE_BIOS 3 +#define OPTYPE_OFFSET_SPECIFIED 7 #define OPTYPE_FCOE_BIOS 8 #define OPTYPE_ISCSI_BACKUP 9 #define OPTYPE_FCOE_FW_ACTIVE 10 @@ -2255,7 +2256,8 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, u8 page_num, u8 *data); int be_cmd_query_cable_type(struct be_adapter *adapter); int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, - u32 flash_oper, u32 flash_opcode, u32 buf_size); + u32 flash_oper, u32 flash_opcode, u32 img_offset, + u32 buf_size); int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 data_size, u32 data_offset, const char *obj_name, u32 *data_written, @@ -2265,7 +2267,7 @@ int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 *data_read, u32 *eof, u8 *addn_status); int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name); int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, - u16 optype, int offset); + u16 img_optype, u32 img_offset, u32 crc_offset); int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, struct be_dma_mem *nonemb_cmd); int be_cmd_fw_init(struct be_adapter *adapter); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 36f140a9c31e..01571da9cd12 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3942,7 +3942,8 @@ static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p, int status; u8 crc[4]; - status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_size - 4); + status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_offset, + img_size - 4); if (status) return status; @@ -3958,13 +3959,13 @@ static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p, } static int be_flash(struct be_adapter *adapter, const u8 *img, - struct be_dma_mem *flash_cmd, int optype, int img_size) + struct be_dma_mem *flash_cmd, int optype, int img_size, + u32 img_offset) { + u32 flash_op, num_bytes, total_bytes = img_size, bytes_sent = 0; struct be_cmd_write_flashrom *req = flash_cmd->va; - u32 total_bytes, flash_op, num_bytes; int status; - total_bytes = img_size; while (total_bytes) { num_bytes = min_t(u32, 32*1024, total_bytes); @@ -3985,12 +3986,15 @@ static int be_flash(struct be_adapter *adapter, const u8 *img, memcpy(req->data_buf, img, num_bytes); img += num_bytes; status = be_cmd_write_flashrom(adapter, flash_cmd, optype, - flash_op, num_bytes); + flash_op, img_offset + + bytes_sent, num_bytes); if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST && optype == OPTYPE_PHY_FW) break; else if (status) return status; + + bytes_sent += num_bytes; } return 0; } @@ -4103,7 +4107,7 @@ static int be_flash_BEx(struct be_adapter *adapter, return -1; status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype, - pflashcomp[i].size); + pflashcomp[i].size, 0); if (status) { dev_err(dev, "Flashing section type 0x%x failed\n", pflashcomp[i].img_type); @@ -4170,12 +4174,12 @@ static int be_flash_skyhawk(struct be_adapter *adapter, struct be_dma_mem *flash_cmd, int num_of_images) { int img_hdrs_size = num_of_images * sizeof(struct image_hdr); + bool crc_match, old_fw_img, flash_offset_support = true; struct device *dev = &adapter->pdev->dev; struct flash_section_info *fsec = NULL; u32 img_offset, img_size, img_type; + u16 img_optype, flash_optype; int status, i, filehdr_size; - bool crc_match, old_fw_img; - u16 img_optype; const u8 *p; filehdr_size = sizeof(struct flash_file_hdr_g3); @@ -4185,6 +4189,7 @@ static int be_flash_skyhawk(struct be_adapter *adapter, return -EINVAL; } +retry_flash: for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) { img_offset = le32_to_cpu(fsec->fsec_entry[i].offset); img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size); @@ -4194,6 +4199,12 @@ static int be_flash_skyhawk(struct be_adapter *adapter, if (img_optype == 0xFFFF) continue; + + if (flash_offset_support) + flash_optype = OPTYPE_OFFSET_SPECIFIED; + else + flash_optype = img_optype; + /* Don't bother verifying CRC if an old FW image is being * flashed */ @@ -4202,16 +4213,26 @@ static int be_flash_skyhawk(struct be_adapter *adapter, status = be_check_flash_crc(adapter, fw->data, img_offset, img_size, filehdr_size + - img_hdrs_size, img_optype, + img_hdrs_size, flash_optype, &crc_match); - /* The current FW image on the card does not recognize the new - * FLASH op_type. The FW download is partially complete. - * Reboot the server now to enable FW image to recognize the - * new FLASH op_type. To complete the remaining process, - * download the same FW again after the reboot. - */ if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST || base_status(status) == MCC_STATUS_ILLEGAL_FIELD) { + /* The current FW image on the card does not support + * OFFSET based flashing. Retry using older mechanism + * of OPTYPE based flashing + */ + if (flash_optype == OPTYPE_OFFSET_SPECIFIED) { + flash_offset_support = false; + goto retry_flash; + } + + /* The current FW image on the card does not recognize + * the new FLASH op_type. The FW download is partially + * complete. Reboot the server now to enable FW image + * to recognize the new FLASH op_type. To complete the + * remaining process, download the same FW again after + * the reboot. + */ dev_err(dev, "Flash incomplete. Reset the server\n"); dev_err(dev, "Download FW image again after reset\n"); return -EAGAIN; @@ -4229,7 +4250,19 @@ flash: if (p + img_size > fw->data + fw->size) return -1; - status = be_flash(adapter, p, flash_cmd, img_optype, img_size); + status = be_flash(adapter, p, flash_cmd, flash_optype, img_size, + img_offset); + + /* The current FW image on the card does not support OFFSET + * based flashing. Retry using older mechanism of OPTYPE based + * flashing + */ + if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD && + flash_optype == OPTYPE_OFFSET_SPECIFIED) { + flash_offset_support = false; + goto retry_flash; + } + /* For old FW images ignore ILLEGAL_FIELD error or errors on * UFI_DIR region */ -- cgit v1.2.1 From ac34b74378a15b01d16ae84d616b405dd0948ecb Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Fri, 6 Feb 2015 08:18:40 -0500 Subject: be2net: remove duplicate code in be_cmd_rx_filter() This patch passes BE_IF_FLAGS_XXX flags to be_cmd_rx_filter() routine instead of the IFF_XXX flags. Doing this gets rid of the code to convert the IFF_XXX flags to the BE_IF_FLAGS_XXX used by the FW cmd. The patch also removes code for setting if_flags_mask that was duplicated for each filter mode. Signed-off-by: Sathya Perla Signed-off-by: Kalesh AP Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 54 ++++++++++------------------- drivers/net/ethernet/emulex/benet/be_cmds.h | 4 +++ drivers/net/ethernet/emulex/benet/be_main.c | 29 +++++++--------- 3 files changed, 36 insertions(+), 51 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 03119ac548f6..ceae6235e707 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1886,7 +1886,7 @@ err: return status; } -int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) +static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) { struct be_mcc_wrb *wrb; struct be_dma_mem *mem = &adapter->rx_filter; @@ -1906,31 +1906,13 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) wrb, mem); req->if_id = cpu_to_le32(adapter->if_handle); - if (flags & IFF_PROMISC) { - req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | - BE_IF_FLAGS_VLAN_PROMISCUOUS | - BE_IF_FLAGS_MCAST_PROMISCUOUS); - if (value == ON) - req->if_flags = - cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | - BE_IF_FLAGS_VLAN_PROMISCUOUS | - BE_IF_FLAGS_MCAST_PROMISCUOUS); - } else if (flags & IFF_ALLMULTI) { - req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); - req->if_flags = cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); - } else if (flags & BE_FLAGS_VLAN_PROMISC) { - req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS); - - if (value == ON) - req->if_flags = - cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS); - } else { + req->if_flags_mask = cpu_to_le32(flags); + req->if_flags = (value == ON) ? req->if_flags_mask : 0; + + if (flags & BE_IF_FLAGS_MULTICAST) { struct netdev_hw_addr *ha; int i = 0; - req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_MULTICAST); - req->if_flags = cpu_to_le32(BE_IF_FLAGS_MULTICAST); - /* Reset mcast promisc mode if already set by setting mask * and not setting flags field */ @@ -1942,24 +1924,26 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN); } - if ((req->if_flags_mask & cpu_to_le32(be_if_cap_flags(adapter))) != - req->if_flags_mask) { - dev_warn(&adapter->pdev->dev, - "Cannot set rx filter flags 0x%x\n", - req->if_flags_mask); - dev_warn(&adapter->pdev->dev, - "Interface is capable of 0x%x flags only\n", - be_if_cap_flags(adapter)); - } - req->if_flags_mask &= cpu_to_le32(be_if_cap_flags(adapter)); - status = be_mcc_notify_wait(adapter); - err: spin_unlock_bh(&adapter->mcc_lock); return status; } +int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) +{ + struct device *dev = &adapter->pdev->dev; + + if ((flags & be_if_cap_flags(adapter)) != flags) { + dev_warn(dev, "Cannot set rx filter flags 0x%x\n", flags); + dev_warn(dev, "Interface is capable of 0x%x flags only\n", + be_if_cap_flags(adapter)); + } + flags &= be_if_cap_flags(adapter); + + return __be_cmd_rx_filter(adapter, flags, value); +} + /* Uses synchrounous mcc */ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) { diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 402d64f5bb7c..cf9d87086546 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -586,6 +586,10 @@ enum be_if_flags { BE_IF_FLAGS_PASS_L3L4_ERRORS | BE_IF_FLAGS_MULTICAST |\ BE_IF_FLAGS_UNTAGGED) +#define BE_IF_FLAGS_ALL_PROMISCUOUS (BE_IF_FLAGS_PROMISCUOUS | \ + BE_IF_FLAGS_VLAN_PROMISCUOUS |\ + BE_IF_FLAGS_MCAST_PROMISCUOUS) + /* An RX interface is an object with one or more MAC addresses and * filtering capabilities. */ struct be_cmd_req_if_create { diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 01571da9cd12..a75eb7487240 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1133,16 +1133,12 @@ static int be_vid_config(struct be_adapter *adapter) MCC_ADDL_STATUS_INSUFFICIENT_RESOURCES) goto set_vlan_promisc; dev_err(dev, "Setting HW VLAN filtering failed\n"); - } else { - if (adapter->flags & BE_FLAGS_VLAN_PROMISC) { - /* hw VLAN filtering re-enabled. */ - status = be_cmd_rx_filter(adapter, - BE_FLAGS_VLAN_PROMISC, OFF); - if (!status) { - dev_info(dev, - "Disabling VLAN Promiscuous mode\n"); - adapter->flags &= ~BE_FLAGS_VLAN_PROMISC; - } + } else if (adapter->flags & BE_FLAGS_VLAN_PROMISC) { + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, + OFF); + if (!status) { + dev_info(dev, "Disabling VLAN Promiscuous mode\n"); + adapter->flags &= ~BE_FLAGS_VLAN_PROMISC; } } @@ -1152,7 +1148,7 @@ set_vlan_promisc: if (adapter->flags & BE_FLAGS_VLAN_PROMISC) return 0; - status = be_cmd_rx_filter(adapter, BE_FLAGS_VLAN_PROMISC, ON); + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, ON); if (!status) { dev_info(dev, "Enable VLAN Promiscuous mode\n"); adapter->flags |= BE_FLAGS_VLAN_PROMISC; @@ -1204,7 +1200,7 @@ static void be_clear_promisc(struct be_adapter *adapter) adapter->promiscuous = false; adapter->flags &= ~(BE_FLAGS_VLAN_PROMISC | BE_FLAGS_MCAST_PROMISC); - be_cmd_rx_filter(adapter, IFF_PROMISC, OFF); + be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, OFF); } static void be_set_rx_mode(struct net_device *netdev) @@ -1213,7 +1209,7 @@ static void be_set_rx_mode(struct net_device *netdev) int status; if (netdev->flags & IFF_PROMISC) { - be_cmd_rx_filter(adapter, IFF_PROMISC, ON); + be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, ON); adapter->promiscuous = true; goto done; } @@ -1240,7 +1236,8 @@ static void be_set_rx_mode(struct net_device *netdev) } if (netdev_uc_count(netdev) > be_max_uc(adapter)) { - be_cmd_rx_filter(adapter, IFF_PROMISC, ON); + be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, + ON); adapter->promiscuous = true; goto done; } @@ -1253,7 +1250,7 @@ static void be_set_rx_mode(struct net_device *netdev) } } - status = be_cmd_rx_filter(adapter, IFF_MULTICAST, ON); + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MULTICAST, ON); if (!status) { if (adapter->flags & BE_FLAGS_MCAST_PROMISC) adapter->flags &= ~BE_FLAGS_MCAST_PROMISC; @@ -1267,7 +1264,7 @@ set_mcast_promisc: /* Set to MCAST promisc mode if setting MULTICAST address fails * or if num configured exceeds what we support */ - status = be_cmd_rx_filter(adapter, IFF_ALLMULTI, ON); + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MCAST_PROMISCUOUS, ON); if (!status) adapter->flags |= BE_FLAGS_MCAST_PROMISC; done: -- cgit v1.2.1 From f66b7cfd95a5e13ca8bc4854252cd027f3d7fe86 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Fri, 6 Feb 2015 08:18:41 -0500 Subject: be2net: refactor be_set_rx_mode() and be_vid_config() for readability This patch re-factors the filter setting (uc-list, mc-list, promisc, vlan) code in be_set_rx_mode() and be_vid_config() to make it more readable and reduce code duplication. This patch adds a separate field to track the state/mode of filtering, along with moving all the filtering related fields to one place in be be_adapter structure. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 13 +- drivers/net/ethernet/emulex/benet/be_main.c | 211 ++++++++++++++++------------ 2 files changed, 127 insertions(+), 97 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 9869556f367d..98716e1c7615 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -364,8 +364,6 @@ enum vf_state { #define BE_FLAGS_LINK_STATUS_INIT BIT(1) #define BE_FLAGS_SRIOV_ENABLED BIT(2) #define BE_FLAGS_WORKER_SCHEDULED BIT(3) -#define BE_FLAGS_VLAN_PROMISC BIT(4) -#define BE_FLAGS_MCAST_PROMISC BIT(5) #define BE_FLAGS_NAPI_ENABLED BIT(6) #define BE_FLAGS_QNQ_ASYNC_EVT_RCVD BIT(7) #define BE_FLAGS_VXLAN_OFFLOADS BIT(8) @@ -449,8 +447,6 @@ struct be_adapter { struct be_drv_stats drv_stats; struct be_aic_obj aic_obj[MAX_EVT_QS]; - u16 vlans_added; - unsigned long vids[BITS_TO_LONGS(VLAN_N_VID)]; u8 vlan_prio_bmap; /* Available Priority BitMap */ u16 recommended_prio; /* Recommended Priority */ struct be_dma_mem rx_filter; /* Cmd DMA mem for rx-filter */ @@ -466,8 +462,15 @@ struct be_adapter { /* Ethtool knobs and info */ char fw_ver[FW_VER_LEN]; char fw_on_flash[FW_VER_LEN]; + + /* IFACE filtering fields */ int if_handle; /* Used to configure filtering */ + u32 if_flags; /* Interface filtering flags */ u32 *pmac_id; /* MAC addr handle used by BE card */ + u32 uc_macs; /* Count of secondary UC MAC programmed */ + unsigned long vids[BITS_TO_LONGS(VLAN_N_VID)]; + u16 vlans_added; + u32 beacon_state; /* for set_phys_id */ bool eeh_error; @@ -475,7 +478,6 @@ struct be_adapter { bool hw_error; u32 port_num; - bool promiscuous; u8 mc_type; u32 function_mode; u32 function_caps; @@ -508,7 +510,6 @@ struct be_adapter { struct phy_info phy; u8 wol_cap; bool wol_en; - u32 uc_macs; /* Count of secondary UC MAC programmed */ u16 asic_rev; u16 qnq_vid; u32 msg_enable; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index a75eb7487240..617038fa92f0 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1104,6 +1104,43 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu) return 0; } +static inline bool be_in_all_promisc(struct be_adapter *adapter) +{ + return (adapter->if_flags & BE_IF_FLAGS_ALL_PROMISCUOUS) == + BE_IF_FLAGS_ALL_PROMISCUOUS; +} + +static int be_set_vlan_promisc(struct be_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + int status; + + if (adapter->if_flags & BE_IF_FLAGS_VLAN_PROMISCUOUS) + return 0; + + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, ON); + if (!status) { + dev_info(dev, "Enabled VLAN promiscuous mode\n"); + adapter->if_flags |= BE_IF_FLAGS_VLAN_PROMISCUOUS; + } else { + dev_err(dev, "Failed to enable VLAN promiscuous mode\n"); + } + return status; +} + +static int be_clear_vlan_promisc(struct be_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + int status; + + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, OFF); + if (!status) { + dev_info(dev, "Disabling VLAN promiscuous mode\n"); + adapter->if_flags &= ~BE_IF_FLAGS_VLAN_PROMISCUOUS; + } + return status; +} + /* * A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE. * If the user configures more, place BE in vlan promiscuous mode. @@ -1116,11 +1153,11 @@ static int be_vid_config(struct be_adapter *adapter) int status = 0; /* No need to further configure vids if in promiscuous mode */ - if (adapter->promiscuous) + if (be_in_all_promisc(adapter)) return 0; if (adapter->vlans_added > be_max_vlans(adapter)) - goto set_vlan_promisc; + return be_set_vlan_promisc(adapter); /* Construct VLAN Table to give to HW */ for_each_set_bit(i, adapter->vids, VLAN_N_VID) @@ -1128,32 +1165,14 @@ static int be_vid_config(struct be_adapter *adapter) status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num); if (status) { + dev_err(dev, "Setting HW VLAN filtering failed\n"); /* Set to VLAN promisc mode as setting VLAN filter failed */ if (addl_status(status) == MCC_ADDL_STATUS_INSUFFICIENT_RESOURCES) - goto set_vlan_promisc; - dev_err(dev, "Setting HW VLAN filtering failed\n"); - } else if (adapter->flags & BE_FLAGS_VLAN_PROMISC) { - status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, - OFF); - if (!status) { - dev_info(dev, "Disabling VLAN Promiscuous mode\n"); - adapter->flags &= ~BE_FLAGS_VLAN_PROMISC; - } + return be_set_vlan_promisc(adapter); + } else if (adapter->if_flags & BE_IF_FLAGS_VLAN_PROMISCUOUS) { + status = be_clear_vlan_promisc(adapter); } - - return status; - -set_vlan_promisc: - if (adapter->flags & BE_FLAGS_VLAN_PROMISC) - return 0; - - status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, ON); - if (!status) { - dev_info(dev, "Enable VLAN Promiscuous mode\n"); - adapter->flags |= BE_FLAGS_VLAN_PROMISC; - } else - dev_err(dev, "Failed to enable VLAN Promiscuous mode\n"); return status; } @@ -1195,80 +1214,99 @@ static int be_vlan_rem_vid(struct net_device *netdev, __be16 proto, u16 vid) return be_vid_config(adapter); } -static void be_clear_promisc(struct be_adapter *adapter) +static void be_clear_all_promisc(struct be_adapter *adapter) { - adapter->promiscuous = false; - adapter->flags &= ~(BE_FLAGS_VLAN_PROMISC | BE_FLAGS_MCAST_PROMISC); - be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, OFF); + adapter->if_flags &= ~BE_IF_FLAGS_ALL_PROMISCUOUS; } -static void be_set_rx_mode(struct net_device *netdev) +static void be_set_all_promisc(struct be_adapter *adapter) +{ + be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, ON); + adapter->if_flags |= BE_IF_FLAGS_ALL_PROMISCUOUS; +} + +static void be_set_mc_promisc(struct be_adapter *adapter) { - struct be_adapter *adapter = netdev_priv(netdev); int status; - if (netdev->flags & IFF_PROMISC) { - be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, ON); - adapter->promiscuous = true; - goto done; - } + if (adapter->if_flags & BE_IF_FLAGS_MCAST_PROMISCUOUS) + return; - /* BE was previously in promiscuous mode; disable it */ - if (adapter->promiscuous) { - be_clear_promisc(adapter); - if (adapter->vlans_added) - be_vid_config(adapter); + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MCAST_PROMISCUOUS, ON); + if (!status) + adapter->if_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS; +} + +static void be_set_mc_list(struct be_adapter *adapter) +{ + int status; + + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MULTICAST, ON); + if (!status) + adapter->if_flags &= ~BE_IF_FLAGS_MCAST_PROMISCUOUS; + else + be_set_mc_promisc(adapter); +} + +static void be_set_uc_list(struct be_adapter *adapter) +{ + struct netdev_hw_addr *ha; + int i = 1; /* First slot is claimed by the Primary MAC */ + + for (; adapter->uc_macs > 0; adapter->uc_macs--, i++) + be_cmd_pmac_del(adapter, adapter->if_handle, + adapter->pmac_id[i], 0); + + if (netdev_uc_count(adapter->netdev) > be_max_uc(adapter)) { + be_set_all_promisc(adapter); + return; } - /* Enable multicast promisc if num configured exceeds what we support */ - if (netdev->flags & IFF_ALLMULTI || - netdev_mc_count(netdev) > be_max_mc(adapter)) - goto set_mcast_promisc; + netdev_for_each_uc_addr(ha, adapter->netdev) { + adapter->uc_macs++; /* First slot is for Primary MAC */ + be_cmd_pmac_add(adapter, (u8 *)ha->addr, adapter->if_handle, + &adapter->pmac_id[adapter->uc_macs], 0); + } +} - if (netdev_uc_count(netdev) != adapter->uc_macs) { - struct netdev_hw_addr *ha; - int i = 1; /* First slot is claimed by the Primary MAC */ +static void be_clear_uc_list(struct be_adapter *adapter) +{ + int i; - for (; adapter->uc_macs > 0; adapter->uc_macs--, i++) { - be_cmd_pmac_del(adapter, adapter->if_handle, - adapter->pmac_id[i], 0); - } + for (i = 1; i < (adapter->uc_macs + 1); i++) + be_cmd_pmac_del(adapter, adapter->if_handle, + adapter->pmac_id[i], 0); + adapter->uc_macs = 0; +} - if (netdev_uc_count(netdev) > be_max_uc(adapter)) { - be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, - ON); - adapter->promiscuous = true; - goto done; - } +static void be_set_rx_mode(struct net_device *netdev) +{ + struct be_adapter *adapter = netdev_priv(netdev); - netdev_for_each_uc_addr(ha, adapter->netdev) { - adapter->uc_macs++; /* First slot is for Primary MAC */ - be_cmd_pmac_add(adapter, (u8 *)ha->addr, - adapter->if_handle, - &adapter->pmac_id[adapter->uc_macs], 0); - } + if (netdev->flags & IFF_PROMISC) { + be_set_all_promisc(adapter); + return; } - status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MULTICAST, ON); - if (!status) { - if (adapter->flags & BE_FLAGS_MCAST_PROMISC) - adapter->flags &= ~BE_FLAGS_MCAST_PROMISC; - goto done; + /* Interface was previously in promiscuous mode; disable it */ + if (be_in_all_promisc(adapter)) { + be_clear_all_promisc(adapter); + if (adapter->vlans_added) + be_vid_config(adapter); } -set_mcast_promisc: - if (adapter->flags & BE_FLAGS_MCAST_PROMISC) + /* Enable multicast promisc if num configured exceeds what we support */ + if (netdev->flags & IFF_ALLMULTI || + netdev_mc_count(netdev) > be_max_mc(adapter)) { + be_set_mc_promisc(adapter); return; + } - /* Set to MCAST promisc mode if setting MULTICAST address fails - * or if num configured exceeds what we support - */ - status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MCAST_PROMISCUOUS, ON); - if (!status) - adapter->flags |= BE_FLAGS_MCAST_PROMISC; -done: - return; + if (netdev_uc_count(netdev) != adapter->uc_macs) + be_set_uc_list(adapter); + + be_set_mc_list(adapter); } static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) @@ -2947,11 +2985,7 @@ static int be_close(struct net_device *netdev) be_tx_compl_clean(adapter); be_rx_qs_destroy(adapter); - - for (i = 1; i < (adapter->uc_macs + 1); i++) - be_cmd_pmac_del(adapter, adapter->if_handle, - adapter->pmac_id[i], 0); - adapter->uc_macs = 0; + be_clear_uc_list(adapter); for_all_evt_queues(adapter, eqo, i) { if (msix_enabled(adapter)) @@ -3235,14 +3269,9 @@ static void be_cancel_worker(struct be_adapter *adapter) static void be_mac_clear(struct be_adapter *adapter) { - int i; - if (adapter->pmac_id) { - for (i = 0; i < (adapter->uc_macs + 1); i++) - be_cmd_pmac_del(adapter, adapter->if_handle, - adapter->pmac_id[i], 0); - adapter->uc_macs = 0; - + be_cmd_pmac_del(adapter, adapter->if_handle, + adapter->pmac_id[0], 0); kfree(adapter->pmac_id); adapter->pmac_id = NULL; } @@ -3526,7 +3555,7 @@ static void be_setup_init(struct be_adapter *adapter) adapter->phy.link_speed = -1; adapter->if_handle = -1; adapter->be3_native = false; - adapter->promiscuous = false; + adapter->if_flags = 0; if (be_physfn(adapter)) adapter->cmd_privileges = MAX_PRIVILEGES; else -- cgit v1.2.1 From 21252377bb2b9f038b4c9d829f69cafca4a4c1c7 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Fri, 6 Feb 2015 08:18:42 -0500 Subject: be2net: process port misconfig async event This patch adds support for processing the port misconfigure async event generated by the FW. This event is generated typically when an optical module is incorrectly installed or is faulty. This patch also moves the port_name field to the adapter struct for logging the event. As the be_cmd_query_port_name() call is now moved to be_get_config(), it is modified to use the mailbox instead of MCCQ Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 6 ++ drivers/net/ethernet/emulex/benet/be_cmds.c | 119 ++++++++++++++++++++++------ drivers/net/ethernet/emulex/benet/be_cmds.h | 16 +++- drivers/net/ethernet/emulex/benet/be_main.c | 28 +++++-- 4 files changed, 139 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 98716e1c7615..27de37aa90af 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -368,6 +368,7 @@ enum vf_state { #define BE_FLAGS_QNQ_ASYNC_EVT_RCVD BIT(7) #define BE_FLAGS_VXLAN_OFFLOADS BIT(8) #define BE_FLAGS_SETUP_DONE BIT(9) +#define BE_FLAGS_EVT_INCOMPATIBLE_SFP BIT(10) #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 @@ -377,6 +378,8 @@ enum vf_state { #define LANCER_DELETE_FW_DUMP 0x2 struct phy_info { +/* From SFF-8472 spec */ +#define SFP_VENDOR_NAME_LEN 17 u8 transceiver; u8 autoneg; u8 fc_autoneg; @@ -390,6 +393,8 @@ struct phy_info { u32 advertising; u32 supported; u8 cable_type; + u8 vendor_name[SFP_VENDOR_NAME_LEN]; + u8 vendor_pn[SFP_VENDOR_NAME_LEN]; }; struct be_resources { @@ -478,6 +483,7 @@ struct be_adapter { bool hw_error; u32 port_num; + char port_name; u8 mc_type; u32 function_mode; u32 function_caps; diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index ceae6235e707..36916cfa70f9 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -19,6 +19,22 @@ #include "be.h" #include "be_cmds.h" +static char *be_port_misconfig_evt_desc[] = { + "A valid SFP module detected", + "Optics faulted/ incorrectly installed/ not installed.", + "Optics of two types installed.", + "Incompatible optics.", + "Unknown port SFP status" +}; + +static char *be_port_misconfig_remedy_desc[] = { + "", + "Reseat optics. If issue not resolved, replace", + "Remove one optic or install matching pair of optics", + "Replace with compatible optics for card to function", + "" +}; + static struct be_cmd_priv_map cmd_priv_map[] = { { OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, @@ -249,6 +265,29 @@ static void be_async_link_state_process(struct be_adapter *adapter, evt->port_link_status & LINK_STATUS_MASK); } +static void be_async_port_misconfig_event_process(struct be_adapter *adapter, + struct be_mcc_compl *compl) +{ + struct be_async_event_misconfig_port *evt = + (struct be_async_event_misconfig_port *)compl; + u32 sfp_mismatch_evt = le32_to_cpu(evt->event_data_word1); + struct device *dev = &adapter->pdev->dev; + u8 port_misconfig_evt; + + port_misconfig_evt = + ((sfp_mismatch_evt >> (adapter->hba_port_num * 8)) & 0xff); + + /* Log an error message that would allow a user to determine + * whether the SFPs have an issue + */ + dev_info(dev, "Port %c: %s %s", adapter->port_name, + be_port_misconfig_evt_desc[port_misconfig_evt], + be_port_misconfig_remedy_desc[port_misconfig_evt]); + + if (port_misconfig_evt == INCOMPATIBLE_SFP) + adapter->flags |= BE_FLAGS_EVT_INCOMPATIBLE_SFP; +} + /* Grp5 CoS Priority evt */ static void be_async_grp5_cos_priority_process(struct be_adapter *adapter, struct be_mcc_compl *compl) @@ -334,6 +373,16 @@ static void be_async_dbg_evt_process(struct be_adapter *adapter, } } +static void be_async_sliport_evt_process(struct be_adapter *adapter, + struct be_mcc_compl *cmp) +{ + u8 event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) & + ASYNC_EVENT_TYPE_MASK; + + if (event_type == ASYNC_EVENT_PORT_MISCONFIG) + be_async_port_misconfig_event_process(adapter, cmp); +} + static inline bool is_link_state_evt(u32 flags) { return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == @@ -352,6 +401,12 @@ static inline bool is_dbg_evt(u32 flags) ASYNC_EVENT_CODE_QNQ; } +static inline bool is_sliport_evt(u32 flags) +{ + return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_SLIPORT; +} + static void be_mcc_event_process(struct be_adapter *adapter, struct be_mcc_compl *compl) { @@ -361,6 +416,8 @@ static void be_mcc_event_process(struct be_adapter *adapter, be_async_grp5_evt_process(adapter, compl); else if (is_dbg_evt(compl->flags)) be_async_dbg_evt_process(adapter, compl); + else if (is_sliport_evt(compl->flags)) + be_async_sliport_evt_process(adapter, compl); } static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) @@ -1171,9 +1228,15 @@ static int be_cmd_mccq_ext_create(struct be_adapter *adapter, ctxt, 1); } - /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */ - req->async_event_bitmap[0] = cpu_to_le32(0x00000022); - req->async_event_bitmap[0] |= cpu_to_le32(1 << ASYNC_EVENT_CODE_QNQ); + /* Subscribe to Link State, Sliport Event and Group 5 Events + * (bits 1, 5 and 17 set) + */ + req->async_event_bitmap[0] = + cpu_to_le32(BIT(ASYNC_EVENT_CODE_LINK_STATE) | + BIT(ASYNC_EVENT_CODE_GRP_5) | + BIT(ASYNC_EVENT_CODE_QNQ) | + BIT(ASYNC_EVENT_CODE_SLIPORT)); + be_dws_cpu_to_le(ctxt, sizeof(req->context)); be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); @@ -2344,6 +2407,24 @@ int be_cmd_query_cable_type(struct be_adapter *adapter) return status; } +int be_cmd_query_sfp_info(struct be_adapter *adapter) +{ + u8 page_data[PAGE_DATA_LEN]; + int status; + + status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, + page_data); + if (!status) { + strlcpy(adapter->phy.vendor_name, page_data + + SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1); + strlcpy(adapter->phy.vendor_pn, + page_data + SFP_VENDOR_PN_OFFSET, + SFP_VENDOR_NAME_LEN - 1); + } + + return status; +} + int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name) { struct lancer_cmd_req_delete_object *req; @@ -3437,42 +3518,34 @@ err: return status; } -int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name) +int be_cmd_query_port_name(struct be_adapter *adapter) { - struct be_mcc_wrb *wrb; struct be_cmd_req_get_port_name *req; + struct be_mcc_wrb *wrb; int status; - if (!lancer_chip(adapter)) { - *port_name = adapter->hba_port_num + '0'; - return 0; - } - - spin_lock_bh(&adapter->mcc_lock); - - wrb = wrb_from_mccq(adapter); - if (!wrb) { - status = -EBUSY; - goto err; - } + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_PORT_NAME, sizeof(*req), wrb, NULL); - req->hdr.version = 1; + if (!BEx_chip(adapter)) + req->hdr.version = 1; - status = be_mcc_notify_wait(adapter); + status = be_mbox_notify_wait(adapter); if (!status) { struct be_cmd_resp_get_port_name *resp = embedded_payload(wrb); - *port_name = resp->port_name[adapter->hba_port_num]; + adapter->port_name = resp->port_name[adapter->hba_port_num]; } else { - *port_name = adapter->hba_port_num + '0'; + adapter->port_name = adapter->hba_port_num + '0'; } -err: - spin_unlock_bh(&adapter->mcc_lock); + + mutex_unlock(&adapter->mbox_lock); return status; } diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index cf9d87086546..db761e8e42a3 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -102,6 +102,8 @@ struct be_mcc_compl { #define ASYNC_EVENT_PVID_STATE 0x3 #define ASYNC_EVENT_CODE_QNQ 0x6 #define ASYNC_DEBUG_EVENT_TYPE_QNQ 1 +#define ASYNC_EVENT_CODE_SLIPORT 0x11 +#define ASYNC_EVENT_PORT_MISCONFIG 0x9 enum { LINK_DOWN = 0x0, @@ -169,6 +171,15 @@ struct be_async_event_qnq { u32 flags; } __packed; +#define INCOMPATIBLE_SFP 0x3 +/* async event indicating misconfigured port */ +struct be_async_event_misconfig_port { + u32 event_data_word1; + u32 event_data_word2; + u32 rsvd0; + u32 flags; +} __packed; + struct be_mcc_mailbox { struct be_mcc_wrb wrb; struct be_mcc_compl compl; @@ -1028,6 +1039,8 @@ enum { #define SFP_PLUS_SFF_8472_COMP 0x5E #define SFP_PLUS_CABLE_TYPE_OFFSET 0x8 #define SFP_PLUS_COPPER_CABLE 0x4 +#define SFP_VENDOR_NAME_OFFSET 0x14 +#define SFP_VENDOR_PN_OFFSET 0x28 #define PAGE_DATA_LEN 256 struct be_cmd_resp_port_type { @@ -2259,6 +2272,7 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, u8 page_num, u8 *data); int be_cmd_query_cable_type(struct be_adapter *adapter); +int be_cmd_query_sfp_info(struct be_adapter *adapter); int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 flash_oper, u32 flash_opcode, u32 img_offset, u32 buf_size); @@ -2326,7 +2340,7 @@ int lancer_initiate_dump(struct be_adapter *adapter); int lancer_delete_dump(struct be_adapter *adapter); bool dump_present(struct be_adapter *adapter); int lancer_test_and_set_rdy_state(struct be_adapter *adapter); -int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name); +int be_cmd_query_port_name(struct be_adapter *adapter); int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res); int be_cmd_get_profile_config(struct be_adapter *adapter, diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 617038fa92f0..195d357e2f3f 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3682,7 +3682,9 @@ static int be_get_config(struct be_adapter *adapter) if (status) return status; - if (be_physfn(adapter)) { + be_cmd_query_port_name(adapter); + + if (be_physfn(adapter)) { status = be_cmd_get_active_profile(adapter, &profile_id); if (!status) dev_info(&adapter->pdev->dev, @@ -5052,6 +5054,20 @@ static void be_func_recovery_task(struct work_struct *work) msecs_to_jiffies(1000)); } +static void be_log_sfp_info(struct be_adapter *adapter) +{ + int status; + + status = be_cmd_query_sfp_info(adapter); + if (!status) { + dev_err(&adapter->pdev->dev, + "Unqualified SFP+ detected on %c from %s part no: %s", + adapter->port_name, adapter->phy.vendor_name, + adapter->phy.vendor_pn); + } + adapter->flags &= ~BE_FLAGS_EVT_INCOMPATIBLE_SFP; +} + static void be_worker(struct work_struct *work) { struct be_adapter *adapter = @@ -5090,6 +5106,9 @@ static void be_worker(struct work_struct *work) be_eqd_update(adapter); + if (adapter->flags & BE_FLAGS_EVT_INCOMPATIBLE_SFP) + be_log_sfp_info(adapter); + reschedule: adapter->work_counter++; schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); @@ -5158,10 +5177,9 @@ static inline char *nic_name(struct pci_dev *pdev) static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) { - int status = 0; struct be_adapter *adapter; struct net_device *netdev; - char port_name; + int status = 0; dev_info(&pdev->dev, "%s version is %s\n", DRV_NAME, DRV_VER); @@ -5255,10 +5273,8 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) schedule_delayed_work(&adapter->func_recovery_work, msecs_to_jiffies(1000)); - be_cmd_query_port_name(adapter, &port_name); - dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev), - func_name(adapter), mc_name(adapter), port_name); + func_name(adapter), mc_name(adapter), adapter->port_name); return 0; -- cgit v1.2.1 From f986afcbe05f507e4520cf0e92bdb56637a3e6c1 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Fri, 6 Feb 2015 08:18:43 -0500 Subject: be2net: avoid unncessary swapping of fields in eth_tx_wrb The 32-bit fields of a tx-wrb are little endian. The driver is currently using be_dws_le_to_cpu() routine to swap (cpu to le) all the fields of a tx-wrb. So, the rsvd field is also unnecessarily swapped. This patch fixes this by individually swapping the required fields. Also, the type of the fields in eth_tx_wrb{} is now changed to __le32 from u32 to avoid sparse warnings. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_hw.h | 10 ++++----- drivers/net/ethernet/emulex/benet/be_main.c | 35 ++++++++++++++++++----------- 2 files changed, 27 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index a8593aa46359..48840889db62 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -193,10 +193,10 @@ struct be_eq_entry { /* TX Queue Descriptor */ #define ETH_WRB_FRAG_LEN_MASK 0xFFFF struct be_eth_wrb { - u32 frag_pa_hi; /* dword 0 */ - u32 frag_pa_lo; /* dword 1 */ - u32 rsvd0; /* dword 2 */ - u32 frag_len; /* dword 3: bits 0 - 15 */ + __le32 frag_pa_hi; /* dword 0 */ + __le32 frag_pa_lo; /* dword 1 */ + u32 rsvd0; /* dword 2 */ + __le32 frag_len; /* dword 3: bits 0 - 15 */ } __packed; /* Pseudo amap definition for eth_hdr_wrb in which each bit of the @@ -229,7 +229,7 @@ struct amap_eth_hdr_wrb { #define TX_HDR_WRB_NUM_MASK 0x1F /* word 2: bits 13:17 */ struct be_eth_hdr_wrb { - u32 dw[4]; + __le32 dw[4]; }; /********* Tx Compl Status Encoding *********/ diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 195d357e2f3f..932b93a14965 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -682,9 +682,20 @@ static u32 skb_wrb_cnt(struct sk_buff *skb) static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len) { - wrb->frag_pa_hi = upper_32_bits(addr); - wrb->frag_pa_lo = addr & 0xFFFFFFFF; - wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK; + wrb->frag_pa_hi = cpu_to_le32(upper_32_bits(addr)); + wrb->frag_pa_lo = cpu_to_le32(lower_32_bits(addr)); + wrb->frag_len = cpu_to_le32(len & ETH_WRB_FRAG_LEN_MASK); + wrb->rsvd0 = 0; +} + +/* A dummy wrb is just all zeros. Using a separate routine for dummy-wrb + * to avoid the swap and shift/mask operations in wrb_fill(). + */ +static inline void wrb_fill_dummy(struct be_eth_wrb *wrb) +{ + wrb->frag_pa_hi = 0; + wrb->frag_pa_lo = 0; + wrb->frag_len = 0; wrb->rsvd0 = 0; } @@ -765,16 +776,16 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, bool unmap_single) { dma_addr_t dma; + u32 frag_len = le32_to_cpu(wrb->frag_len); - be_dws_le_to_cpu(wrb, sizeof(*wrb)); - dma = (u64)wrb->frag_pa_hi << 32 | (u64)wrb->frag_pa_lo; - if (wrb->frag_len) { + dma = (u64)le32_to_cpu(wrb->frag_pa_hi) << 32 | + (u64)le32_to_cpu(wrb->frag_pa_lo); + if (frag_len) { if (unmap_single) - dma_unmap_single(dev, dma, wrb->frag_len, - DMA_TO_DEVICE); + dma_unmap_single(dev, dma, frag_len, DMA_TO_DEVICE); else - dma_unmap_page(dev, dma, wrb->frag_len, DMA_TO_DEVICE); + dma_unmap_page(dev, dma, frag_len, DMA_TO_DEVICE); } } @@ -806,7 +817,6 @@ static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, map_single = true; wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, len); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); queue_head_inc(txq); copied += len; } @@ -820,7 +830,6 @@ static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, goto dma_err; wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, skb_frag_size(frag)); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); queue_head_inc(txq); copied += skb_frag_size(frag); } @@ -846,7 +855,7 @@ dma_err: wrb = queue_head_node(txq); unmap_tx_frag(dev, wrb, map_single); map_single = false; - copied -= wrb->frag_len; + copied -= le32_to_cpu(wrb->frag_len); adapter->drv_stats.dma_map_errors++; queue_head_inc(txq); } @@ -1037,7 +1046,7 @@ static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo) /* compose a dummy wrb if there are odd set of wrbs to notify */ if (!lancer_chip(adapter) && (txo->pend_wrb_cnt & 1)) { - wrb_fill(queue_head_node(txq), 0, 0); + wrb_fill_dummy(queue_head_node(txq)); queue_head_inc(txq); atomic_inc(&txq->used); txo->pend_wrb_cnt++; -- cgit v1.2.1 From 70a5f3bb5f80d9bc7aa746816b32ab17e3c56029 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 6 Feb 2015 19:32:51 +0530 Subject: cxgb4: Add support in debugfs to display sensor information Dump out various chip sensor information. Currently Chip Temperature and Core Voltage. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 36 ++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 6 ++++ 2 files changed, 42 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 61c000a08ebb..35ec23073c7f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -813,6 +813,41 @@ static const struct file_operations mps_tcam_debugfs_fops = { .release = seq_release, }; +/* Display various sensor information. + */ +static int sensors_show(struct seq_file *seq, void *v) +{ + struct adapter *adap = seq->private; + u32 param[7], val[7]; + int ret; + + /* Note that if the sensors haven't been initialized and turned on + * we'll get values of 0, so treat those as "" ... + */ + param[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) | + FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_TMP)); + param[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) | + FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_VDD)); + ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, + param, val); + + if (ret < 0 || val[0] == 0) + seq_puts(seq, "Temperature: \n"); + else + seq_printf(seq, "Temperature: %dC\n", val[0]); + + if (ret < 0 || val[1] == 0) + seq_puts(seq, "Core VDD: \n"); + else + seq_printf(seq, "Core VDD: %dmV\n", val[1]); + + return 0; +} + +DEFINE_SIMPLE_DEBUGFS_FILE(sensors); + #if IS_ENABLED(CONFIG_IPV6) static int clip_tbl_open(struct inode *inode, struct file *file) { @@ -1584,6 +1619,7 @@ int t4_setup_debugfs(struct adapter *adap) { "obq_ulp3", &cim_obq_fops, S_IRUSR, 3 }, { "obq_sge", &cim_obq_fops, S_IRUSR, 4 }, { "obq_ncsi", &cim_obq_fops, S_IRUSR, 5 }, + { "sensors", &sensors_debugfs_fops, S_IRUSR, 0 }, { "pm_stats", &pm_stats_debugfs_fops, S_IRUSR, 0 }, #if IS_ENABLED(CONFIG_IPV6) { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 }, diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 1e72cda5eb1a..95fc425375c4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -1059,6 +1059,7 @@ enum fw_params_param_dev { FW_PARAMS_PARAM_DEV_FWREV = 0x0B, FW_PARAMS_PARAM_DEV_TPREV = 0x0C, FW_PARAMS_PARAM_DEV_CF = 0x0D, + FW_PARAMS_PARAM_DEV_DIAG = 0x11, FW_PARAMS_PARAM_DEV_MAXORDIRD_QP = 0x13, /* max supported QP IRD/ORD */ FW_PARAMS_PARAM_DEV_MAXIRD_ADAPTER = 0x14, /* max supported adap IRD */ FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17, @@ -1122,6 +1123,11 @@ enum fw_params_param_dmaq { FW_PARAMS_PARAM_DMAQ_EQ_DCBPRIO_ETH = 0x13, }; +enum fw_params_param_dev_diag { + FW_PARAM_DEV_DIAG_TMP = 0x00, + FW_PARAM_DEV_DIAG_VDD = 0x01, +}; + enum fw_params_param_dev_fwcache { FW_PARAM_DEV_FWCACHE_FLUSH = 0x00, FW_PARAM_DEV_FWCACHE_FLUSHINV = 0x01, -- cgit v1.2.1 From 2d277b3b44ede5c1812f5e49d2c8bdb7869f1661 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 6 Feb 2015 19:32:52 +0530 Subject: cxgb4: Added support in debugfs to display TP logic analyzer output Dump Transport Processor event trace. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 248 +++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 47 ++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 1 + drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 22 ++ 5 files changed, 320 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 55019c93387d..d827bb65103e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -221,6 +221,7 @@ struct sge_params { struct tp_params { unsigned int ntxchan; /* # of Tx channels */ unsigned int tre; /* log2 of core clocks per TP tick */ + unsigned int la_mask; /* what events are recorded by TP LA */ unsigned short tx_modq_map; /* TX modulation scheduler queue to */ /* channel map */ @@ -1174,6 +1175,7 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p); void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log); void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr, unsigned int mask, unsigned int val); +void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr); void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, struct tp_tcp_stats *v6); void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 35ec23073c7f..1304fe045e7c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -315,6 +315,253 @@ static const struct file_operations cim_obq_fops = { .release = seq_release_private }; +struct field_desc { + const char *name; + unsigned int start; + unsigned int width; +}; + +static void field_desc_show(struct seq_file *seq, u64 v, + const struct field_desc *p) +{ + char buf[32]; + int line_size = 0; + + while (p->name) { + u64 mask = (1ULL << p->width) - 1; + int len = scnprintf(buf, sizeof(buf), "%s: %llu", p->name, + ((unsigned long long)v >> p->start) & mask); + + if (line_size + len >= 79) { + line_size = 8; + seq_puts(seq, "\n "); + } + seq_printf(seq, "%s ", buf); + line_size += len + 1; + p++; + } + seq_putc(seq, '\n'); +} + +static struct field_desc tp_la0[] = { + { "RcfOpCodeOut", 60, 4 }, + { "State", 56, 4 }, + { "WcfState", 52, 4 }, + { "RcfOpcSrcOut", 50, 2 }, + { "CRxError", 49, 1 }, + { "ERxError", 48, 1 }, + { "SanityFailed", 47, 1 }, + { "SpuriousMsg", 46, 1 }, + { "FlushInputMsg", 45, 1 }, + { "FlushInputCpl", 44, 1 }, + { "RssUpBit", 43, 1 }, + { "RssFilterHit", 42, 1 }, + { "Tid", 32, 10 }, + { "InitTcb", 31, 1 }, + { "LineNumber", 24, 7 }, + { "Emsg", 23, 1 }, + { "EdataOut", 22, 1 }, + { "Cmsg", 21, 1 }, + { "CdataOut", 20, 1 }, + { "EreadPdu", 19, 1 }, + { "CreadPdu", 18, 1 }, + { "TunnelPkt", 17, 1 }, + { "RcfPeerFin", 16, 1 }, + { "RcfReasonOut", 12, 4 }, + { "TxCchannel", 10, 2 }, + { "RcfTxChannel", 8, 2 }, + { "RxEchannel", 6, 2 }, + { "RcfRxChannel", 5, 1 }, + { "RcfDataOutSrdy", 4, 1 }, + { "RxDvld", 3, 1 }, + { "RxOoDvld", 2, 1 }, + { "RxCongestion", 1, 1 }, + { "TxCongestion", 0, 1 }, + { NULL } +}; + +static int tp_la_show(struct seq_file *seq, void *v, int idx) +{ + const u64 *p = v; + + field_desc_show(seq, *p, tp_la0); + return 0; +} + +static int tp_la_show2(struct seq_file *seq, void *v, int idx) +{ + const u64 *p = v; + + if (idx) + seq_putc(seq, '\n'); + field_desc_show(seq, p[0], tp_la0); + if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) + field_desc_show(seq, p[1], tp_la0); + return 0; +} + +static int tp_la_show3(struct seq_file *seq, void *v, int idx) +{ + static struct field_desc tp_la1[] = { + { "CplCmdIn", 56, 8 }, + { "CplCmdOut", 48, 8 }, + { "ESynOut", 47, 1 }, + { "EAckOut", 46, 1 }, + { "EFinOut", 45, 1 }, + { "ERstOut", 44, 1 }, + { "SynIn", 43, 1 }, + { "AckIn", 42, 1 }, + { "FinIn", 41, 1 }, + { "RstIn", 40, 1 }, + { "DataIn", 39, 1 }, + { "DataInVld", 38, 1 }, + { "PadIn", 37, 1 }, + { "RxBufEmpty", 36, 1 }, + { "RxDdp", 35, 1 }, + { "RxFbCongestion", 34, 1 }, + { "TxFbCongestion", 33, 1 }, + { "TxPktSumSrdy", 32, 1 }, + { "RcfUlpType", 28, 4 }, + { "Eread", 27, 1 }, + { "Ebypass", 26, 1 }, + { "Esave", 25, 1 }, + { "Static0", 24, 1 }, + { "Cread", 23, 1 }, + { "Cbypass", 22, 1 }, + { "Csave", 21, 1 }, + { "CPktOut", 20, 1 }, + { "RxPagePoolFull", 18, 2 }, + { "RxLpbkPkt", 17, 1 }, + { "TxLpbkPkt", 16, 1 }, + { "RxVfValid", 15, 1 }, + { "SynLearned", 14, 1 }, + { "SetDelEntry", 13, 1 }, + { "SetInvEntry", 12, 1 }, + { "CpcmdDvld", 11, 1 }, + { "CpcmdSave", 10, 1 }, + { "RxPstructsFull", 8, 2 }, + { "EpcmdDvld", 7, 1 }, + { "EpcmdFlush", 6, 1 }, + { "EpcmdTrimPrefix", 5, 1 }, + { "EpcmdTrimPostfix", 4, 1 }, + { "ERssIp4Pkt", 3, 1 }, + { "ERssIp6Pkt", 2, 1 }, + { "ERssTcpUdpPkt", 1, 1 }, + { "ERssFceFipPkt", 0, 1 }, + { NULL } + }; + static struct field_desc tp_la2[] = { + { "CplCmdIn", 56, 8 }, + { "MpsVfVld", 55, 1 }, + { "MpsPf", 52, 3 }, + { "MpsVf", 44, 8 }, + { "SynIn", 43, 1 }, + { "AckIn", 42, 1 }, + { "FinIn", 41, 1 }, + { "RstIn", 40, 1 }, + { "DataIn", 39, 1 }, + { "DataInVld", 38, 1 }, + { "PadIn", 37, 1 }, + { "RxBufEmpty", 36, 1 }, + { "RxDdp", 35, 1 }, + { "RxFbCongestion", 34, 1 }, + { "TxFbCongestion", 33, 1 }, + { "TxPktSumSrdy", 32, 1 }, + { "RcfUlpType", 28, 4 }, + { "Eread", 27, 1 }, + { "Ebypass", 26, 1 }, + { "Esave", 25, 1 }, + { "Static0", 24, 1 }, + { "Cread", 23, 1 }, + { "Cbypass", 22, 1 }, + { "Csave", 21, 1 }, + { "CPktOut", 20, 1 }, + { "RxPagePoolFull", 18, 2 }, + { "RxLpbkPkt", 17, 1 }, + { "TxLpbkPkt", 16, 1 }, + { "RxVfValid", 15, 1 }, + { "SynLearned", 14, 1 }, + { "SetDelEntry", 13, 1 }, + { "SetInvEntry", 12, 1 }, + { "CpcmdDvld", 11, 1 }, + { "CpcmdSave", 10, 1 }, + { "RxPstructsFull", 8, 2 }, + { "EpcmdDvld", 7, 1 }, + { "EpcmdFlush", 6, 1 }, + { "EpcmdTrimPrefix", 5, 1 }, + { "EpcmdTrimPostfix", 4, 1 }, + { "ERssIp4Pkt", 3, 1 }, + { "ERssIp6Pkt", 2, 1 }, + { "ERssTcpUdpPkt", 1, 1 }, + { "ERssFceFipPkt", 0, 1 }, + { NULL } + }; + const u64 *p = v; + + if (idx) + seq_putc(seq, '\n'); + field_desc_show(seq, p[0], tp_la0); + if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) + field_desc_show(seq, p[1], (p[0] & BIT(17)) ? tp_la2 : tp_la1); + return 0; +} + +static int tp_la_open(struct inode *inode, struct file *file) +{ + struct seq_tab *p; + struct adapter *adap = inode->i_private; + + switch (DBGLAMODE_G(t4_read_reg(adap, TP_DBG_LA_CONFIG_A))) { + case 2: + p = seq_open_tab(file, TPLA_SIZE / 2, 2 * sizeof(u64), 0, + tp_la_show2); + break; + case 3: + p = seq_open_tab(file, TPLA_SIZE / 2, 2 * sizeof(u64), 0, + tp_la_show3); + break; + default: + p = seq_open_tab(file, TPLA_SIZE, sizeof(u64), 0, tp_la_show); + } + if (!p) + return -ENOMEM; + + t4_tp_read_la(adap, (u64 *)p->data, NULL); + return 0; +} + +static ssize_t tp_la_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + int err; + char s[32]; + unsigned long val; + size_t size = min(sizeof(s) - 1, count); + struct adapter *adap = FILE_DATA(file)->i_private; + + if (copy_from_user(s, buf, size)) + return -EFAULT; + s[size] = '\0'; + err = kstrtoul(s, 0, &val); + if (err) + return err; + if (val > 0xffff) + return -EINVAL; + adap->params.tp.la_mask = val << 16; + t4_set_reg_field(adap, TP_DBG_LA_CONFIG_A, 0xffff0000U, + adap->params.tp.la_mask); + return count; +} + +static const struct file_operations tp_la_fops = { + .owner = THIS_MODULE, + .open = tp_la_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, + .write = tp_la_write +}; + /* Show the PM memory stats. These stats include: * * TX: @@ -1619,6 +1866,7 @@ int t4_setup_debugfs(struct adapter *adap) { "obq_ulp3", &cim_obq_fops, S_IRUSR, 3 }, { "obq_sge", &cim_obq_fops, S_IRUSR, 4 }, { "obq_ncsi", &cim_obq_fops, S_IRUSR, 5 }, + { "tp_la", &tp_la_fops, S_IRUSR, 0 }, { "sensors", &sensors_debugfs_fops, S_IRUSR, 0 }, { "pm_stats", &pm_stats_debugfs_fops, S_IRUSR, 0 }, #if IS_ENABLED(CONFIG_IPV6) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index ea16c623e8b2..e82c0ba66d55 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -4782,3 +4782,50 @@ restart: } return ret; } + +/** + * t4_tp_read_la - read TP LA capture buffer + * @adap: the adapter + * @la_buf: where to store the LA data + * @wrptr: the HW write pointer within the capture buffer + * + * Reads the contents of the TP LA buffer with the most recent entry at + * the end of the returned data and with the entry at @wrptr first. + * We leave the LA in the running state we find it in. + */ +void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr) +{ + bool last_incomplete; + unsigned int i, cfg, val, idx; + + cfg = t4_read_reg(adap, TP_DBG_LA_CONFIG_A) & 0xffff; + if (cfg & DBGLAENABLE_F) /* freeze LA */ + t4_write_reg(adap, TP_DBG_LA_CONFIG_A, + adap->params.tp.la_mask | (cfg ^ DBGLAENABLE_F)); + + val = t4_read_reg(adap, TP_DBG_LA_CONFIG_A); + idx = DBGLAWPTR_G(val); + last_incomplete = DBGLAMODE_G(val) >= 2 && (val & DBGLAWHLF_F) == 0; + if (last_incomplete) + idx = (idx + 1) & DBGLARPTR_M; + if (wrptr) + *wrptr = idx; + + val &= 0xffff; + val &= ~DBGLARPTR_V(DBGLARPTR_M); + val |= adap->params.tp.la_mask; + + for (i = 0; i < TPLA_SIZE; i++) { + t4_write_reg(adap, TP_DBG_LA_CONFIG_A, DBGLARPTR_V(idx) | val); + la_buf[i] = t4_read_reg64(adap, TP_DBG_LA_DATAL_A); + idx = (idx + 1) & DBGLARPTR_M; + } + + /* Wipe out last entry if it isn't valid */ + if (last_incomplete) + la_buf[TPLA_SIZE - 1] = ~0ULL; + + if (cfg & DBGLAENABLE_F) /* restore running state */ + t4_write_reg(adap, TP_DBG_LA_CONFIG_A, + cfg | adap->params.tp.la_mask); +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index 664375f290ee..f0b98d7d74da 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -63,6 +63,7 @@ enum { CIMLA_SIZE = 2048, /* # of 32-bit words in CIM LA */ CIM_IBQ_SIZE = 128, /* # of 128-bit words in a CIM IBQ */ CIM_OBQ_SIZE = 128, /* # of 128-bit words in a CIM OBQ */ + TPLA_SIZE = 128, /* # of 64-bit words in TP LA */ }; enum { diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 940b56cd5caa..15d0eccfa6ec 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1183,9 +1183,31 @@ #define RSVDSPACEINT_F RSVDSPACEINT_V(1U) /* registers for module TP */ +#define DBGLAWHLF_S 23 +#define DBGLAWHLF_V(x) ((x) << DBGLAWHLF_S) +#define DBGLAWHLF_F DBGLAWHLF_V(1U) + +#define DBGLAWPTR_S 16 +#define DBGLAWPTR_M 0x7fU +#define DBGLAWPTR_G(x) (((x) >> DBGLAWPTR_S) & DBGLAWPTR_M) + +#define DBGLAENABLE_S 12 +#define DBGLAENABLE_V(x) ((x) << DBGLAENABLE_S) +#define DBGLAENABLE_F DBGLAENABLE_V(1U) + +#define DBGLARPTR_S 0 +#define DBGLARPTR_M 0x7fU +#define DBGLARPTR_V(x) ((x) << DBGLARPTR_S) + +#define TP_DBG_LA_DATAL_A 0x7ed8 +#define TP_DBG_LA_CONFIG_A 0x7ed4 #define TP_OUT_CONFIG_A 0x7d04 #define TP_GLOBAL_CONFIG_A 0x7d08 +#define DBGLAMODE_S 14 +#define DBGLAMODE_M 0x3U +#define DBGLAMODE_G(x) (((x) >> DBGLAMODE_S) & DBGLAMODE_M) + #define FIVETUPLELOOKUP_S 17 #define FIVETUPLELOOKUP_M 0x3U #define FIVETUPLELOOKUP_V(x) ((x) << FIVETUPLELOOKUP_S) -- cgit v1.2.1 From 797ff0f573184778771b6d1186eca72f7e3adb4d Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 6 Feb 2015 19:32:53 +0530 Subject: cxgb4: Add support for ULP RX logic analyzer output in debugfs Dump Upper Layer Protocol RX module command trace Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 ++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 36 ++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 15 +++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 1 + drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 4 +++ 5 files changed, 58 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index d827bb65103e..6e18b42cafb3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1181,6 +1181,8 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, const unsigned short *alpha, const unsigned short *beta); +void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf); + void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid); void t4_wol_magic_enable(struct adapter *adap, unsigned int port, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 1304fe045e7c..5a462730bdbe 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -562,6 +562,41 @@ static const struct file_operations tp_la_fops = { .write = tp_la_write }; +static int ulprx_la_show(struct seq_file *seq, void *v, int idx) +{ + const u32 *p = v; + + if (v == SEQ_START_TOKEN) + seq_puts(seq, " Pcmd Type Message" + " Data\n"); + else + seq_printf(seq, "%08x%08x %4x %08x %08x%08x%08x%08x\n", + p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]); + return 0; +} + +static int ulprx_la_open(struct inode *inode, struct file *file) +{ + struct seq_tab *p; + struct adapter *adap = inode->i_private; + + p = seq_open_tab(file, ULPRX_LA_SIZE, 8 * sizeof(u32), 1, + ulprx_la_show); + if (!p) + return -ENOMEM; + + t4_ulprx_read_la(adap, (u32 *)p->data); + return 0; +} + +static const struct file_operations ulprx_la_fops = { + .owner = THIS_MODULE, + .open = ulprx_la_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + /* Show the PM memory stats. These stats include: * * TX: @@ -1867,6 +1902,7 @@ int t4_setup_debugfs(struct adapter *adap) { "obq_sge", &cim_obq_fops, S_IRUSR, 4 }, { "obq_ncsi", &cim_obq_fops, S_IRUSR, 5 }, { "tp_la", &tp_la_fops, S_IRUSR, 0 }, + { "ulprx_la", &ulprx_la_fops, S_IRUSR, 0 }, { "sensors", &sensors_debugfs_fops, S_IRUSR, 0 }, { "pm_stats", &pm_stats_debugfs_fops, S_IRUSR, 0 }, #if IS_ENABLED(CONFIG_IPV6) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index e82c0ba66d55..9938f2aa5ef7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -1263,6 +1263,21 @@ int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op) return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL); } +void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf) +{ + unsigned int i, j; + + for (i = 0; i < 8; i++) { + u32 *p = la_buf + i; + + t4_write_reg(adap, ULP_RX_LA_CTL_A, i); + j = t4_read_reg(adap, ULP_RX_LA_WRPTR_A); + t4_write_reg(adap, ULP_RX_LA_RDPTR_A, j); + for (j = 0; j < ULPRX_LA_SIZE; j++, p += 8) + *p = t4_read_reg(adap, ULP_RX_LA_RDDATA_A); + } +} + #define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \ FW_PORT_CAP_ANEG) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index f0b98d7d74da..380b15c0417a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -64,6 +64,7 @@ enum { CIM_IBQ_SIZE = 128, /* # of 128-bit words in a CIM IBQ */ CIM_OBQ_SIZE = 128, /* # of 128-bit words in a CIM OBQ */ TPLA_SIZE = 128, /* # of 64-bit words in TP LA */ + ULPRX_LA_SIZE = 512, /* # of 256-bit words in ULP_RX LA */ }; enum { diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 15d0eccfa6ec..91e0ea1954f0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -2270,6 +2270,10 @@ #define ULP_RX_INT_CAUSE_A 0x19158 #define ULP_RX_ISCSI_TAGMASK_A 0x19164 #define ULP_RX_ISCSI_PSZ_A 0x19168 +#define ULP_RX_LA_CTL_A 0x1923c +#define ULP_RX_LA_RDPTR_A 0x19240 +#define ULP_RX_LA_RDDATA_A 0x19244 +#define ULP_RX_LA_WRPTR_A 0x19248 #define HPZ3_S 24 #define HPZ3_V(x) ((x) << HPZ3_S) -- cgit v1.2.1 From bf7c781d576823e5d71f40585aeeac430a1845c8 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 6 Feb 2015 19:32:54 +0530 Subject: cxgb4: Add support to dump mailbox content in debugfs Adds support to dump the current contents of mailbox and the driver which owns it. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 85 ++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 1 + drivers/net/ethernet/chelsio/cxgb4/t4_values.h | 5 ++ 3 files changed, 91 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 5a462730bdbe..83e29320a945 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -40,6 +40,7 @@ #include "cxgb4.h" #include "t4_regs.h" +#include "t4_values.h" #include "t4fw_api.h" #include "cxgb4_debugfs.h" #include "clip_tbl.h" @@ -920,6 +921,82 @@ static const struct file_operations devlog_fops = { .release = seq_release_private }; +static int mbox_show(struct seq_file *seq, void *v) +{ + static const char * const owner[] = { "none", "FW", "driver", + "unknown" }; + + int i; + unsigned int mbox = (uintptr_t)seq->private & 7; + struct adapter *adap = seq->private - mbox; + void __iomem *addr = adap->regs + PF_REG(mbox, CIM_PF_MAILBOX_DATA_A); + unsigned int ctrl_reg = (is_t4(adap->params.chip) + ? CIM_PF_MAILBOX_CTRL_A + : CIM_PF_MAILBOX_CTRL_SHADOW_COPY_A); + void __iomem *ctrl = adap->regs + PF_REG(mbox, ctrl_reg); + + i = MBOWNER_G(readl(ctrl)); + seq_printf(seq, "mailbox owned by %s\n\n", owner[i]); + + for (i = 0; i < MBOX_LEN; i += 8) + seq_printf(seq, "%016llx\n", + (unsigned long long)readq(addr + i)); + return 0; +} + +static int mbox_open(struct inode *inode, struct file *file) +{ + return single_open(file, mbox_show, inode->i_private); +} + +static ssize_t mbox_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + int i; + char c = '\n', s[256]; + unsigned long long data[8]; + const struct inode *ino; + unsigned int mbox; + struct adapter *adap; + void __iomem *addr; + void __iomem *ctrl; + + if (count > sizeof(s) - 1 || !count) + return -EINVAL; + if (copy_from_user(s, buf, count)) + return -EFAULT; + s[count] = '\0'; + + if (sscanf(s, "%llx %llx %llx %llx %llx %llx %llx %llx%c", &data[0], + &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], + &data[7], &c) < 8 || c != '\n') + return -EINVAL; + + ino = FILE_DATA(file); + mbox = (uintptr_t)ino->i_private & 7; + adap = ino->i_private - mbox; + addr = adap->regs + PF_REG(mbox, CIM_PF_MAILBOX_DATA_A); + ctrl = addr + MBOX_LEN; + + if (MBOWNER_G(readl(ctrl)) != X_MBOWNER_PL) + return -EBUSY; + + for (i = 0; i < 8; i++) + writeq(data[i], addr + 8 * i); + + writel(MBMSGVALID_F | MBOWNER_V(X_MBOWNER_FW), ctrl); + return count; +} + +static const struct file_operations mbox_debugfs_fops = { + .owner = THIS_MODULE, + .open = mbox_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = mbox_write +}; + static ssize_t flash_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -1881,6 +1958,14 @@ int t4_setup_debugfs(struct adapter *adap) { "cim_qcfg", &cim_qcfg_fops, S_IRUSR, 0 }, { "clk", &clk_debugfs_fops, S_IRUSR, 0 }, { "devlog", &devlog_fops, S_IRUSR, 0 }, + { "mbox0", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 0 }, + { "mbox1", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 1 }, + { "mbox2", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 2 }, + { "mbox3", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 3 }, + { "mbox4", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 4 }, + { "mbox5", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 5 }, + { "mbox6", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 6 }, + { "mbox7", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 7 }, { "l2t", &t4_l2t_fops, S_IRUSR, 0}, { "mps_tcam", &mps_tcam_debugfs_fops, S_IRUSR, 0 }, { "rss", &rss_debugfs_fops, S_IRUSR, 0 }, diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 91e0ea1954f0..3f18d5c5e7f0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -947,6 +947,7 @@ /* registers for module CIM */ #define CIM_BOOT_CFG_A 0x7b00 +#define CIM_PF_MAILBOX_CTRL_SHADOW_COPY_A 0x290 #define BOOTADDR_M 0xffffff00U diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h index 997ec87470c7..19b2dcf6acde 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h @@ -79,6 +79,11 @@ #define SGE_UDB_GTS 20 #define SGE_UDB_WCDOORBELL 64 +/* CIM register field values. + */ +#define X_MBOWNER_FW 1 +#define X_MBOWNER_PL 2 + /* PCI-E definitions */ #define WINDOW_SHIFT_X 10 #define PCIEOFST_SHIFT_X 10 -- cgit v1.2.1 From bad4379263d2c2442f5273adc856dd67e4274f3f Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 6 Feb 2015 19:32:55 +0530 Subject: cxgb4: Add support in debugfs to dump the congestion control table Dump Transport Processor modules congestion control configuration Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 28 ++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 21 ++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 3 +++ 4 files changed, 53 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 6e18b42cafb3..0fe3a52fb0b8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1173,6 +1173,7 @@ void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres); const char *t4_get_port_type_description(enum fw_port_type port_type); void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p); void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log); +void t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN]); void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr, unsigned int mask, unsigned int val); void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 83e29320a945..a1029eecef02 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -663,6 +663,33 @@ static const struct file_operations pm_stats_debugfs_fops = { .write = pm_stats_clear }; +static int cctrl_tbl_show(struct seq_file *seq, void *v) +{ + static const char * const dec_fac[] = { + "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", + "0.9375" }; + + int i; + u16 incr[NMTUS][NCCTRL_WIN]; + struct adapter *adap = seq->private; + + t4_read_cong_tbl(adap, incr); + + for (i = 0; i < NCCTRL_WIN; ++i) { + seq_printf(seq, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, + incr[0][i], incr[1][i], incr[2][i], incr[3][i], + incr[4][i], incr[5][i], incr[6][i], incr[7][i]); + seq_printf(seq, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", + incr[8][i], incr[9][i], incr[10][i], incr[11][i], + incr[12][i], incr[13][i], incr[14][i], incr[15][i], + adap->params.a_wnd[i], + dec_fac[adap->params.b_wnd[i]]); + } + return 0; +} + +DEFINE_SIMPLE_DEBUGFS_FILE(cctrl_tbl); + /* Format a value in a unit that differs from the value's native unit by the * given factor. */ @@ -1990,6 +2017,7 @@ int t4_setup_debugfs(struct adapter *adap) { "ulprx_la", &ulprx_la_fops, S_IRUSR, 0 }, { "sensors", &sensors_debugfs_fops, S_IRUSR, 0 }, { "pm_stats", &pm_stats_debugfs_fops, S_IRUSR, 0 }, + { "cctrl", &cctrl_tbl_debugfs_fops, S_IRUSR, 0 }, #if IS_ENABLED(CONFIG_IPV6) { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 }, #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 9938f2aa5ef7..2c13e8005319 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -2418,6 +2418,27 @@ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) } } +/** + * t4_read_cong_tbl - reads the congestion control table + * @adap: the adapter + * @incr: where to store the alpha values + * + * Reads the additive increments programmed into the HW congestion + * control table. + */ +void t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN]) +{ + unsigned int mtu, w; + + for (mtu = 0; mtu < NMTUS; ++mtu) + for (w = 0; w < NCCTRL_WIN; ++w) { + t4_write_reg(adap, TP_CCTRL_TABLE_A, + ROWINDEX_V(0xffff) | (mtu << 5) | w); + incr[mtu][w] = (u16)t4_read_reg(adap, + TP_CCTRL_TABLE_A) & 0x1fff; + } +} + /** * t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register * @adap: the adapter diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 3f18d5c5e7f0..231a725f6d5d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1292,6 +1292,9 @@ #define KEEPALIVEMAXR2_V(x) ((x) << KEEPALIVEMAXR2_S) #define KEEPALIVEMAXR2_G(x) (((x) >> KEEPALIVEMAXR2_S) & KEEPALIVEMAXR2_M) +#define ROWINDEX_S 16 +#define ROWINDEX_V(x) ((x) << ROWINDEX_S) + #define TP_CCTRL_TABLE_A 0x7ddc #define TP_MTU_TABLE_A 0x7de4 -- cgit v1.2.1 From 567e4b79731c352a17d73c483959f795d3593e03 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 6 Feb 2015 12:59:01 -0800 Subject: net: rfs: add hash collision detection Receive Flow Steering is a nice solution but suffers from hash collisions when a mix of connected and unconnected traffic is received on the host, when flow hash table is populated. Also, clearing flow in inet_release() makes RFS not very good for short lived flows, as many packets can follow close(). (FIN , ACK packets, ...) This patch extends the information stored into global hash table to not only include cpu number, but upper part of the hash value. I use a 32bit value, and dynamically split it in two parts. For host with less than 64 possible cpus, this gives 6 bits for the cpu number, and 26 (32-6) bits for the upper part of the hash. Since hash bucket selection use low order bits of the hash, we have a full hash match, if /proc/sys/net/core/rps_sock_flow_entries is big enough. If the hash found in flow table does not match, we fallback to RPS (if it is enabled for the rxqueue). This means that a packet for an non connected flow can avoid the IPI through a unrelated/victim CPU. This also means we no longer have to clear the table at socket close time, and this helps short lived flows performance. Signed-off-by: Eric Dumazet Acked-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/tun.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ad7d3d5f3ee5..857dca47bf80 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -256,7 +256,6 @@ static void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e) { tun_debug(KERN_INFO, tun, "delete flow: hash %u index %u\n", e->rxhash, e->queue_index); - sock_rps_reset_flow_hash(e->rps_rxhash); hlist_del_rcu(&e->hash_link); kfree_rcu(e, rcu); --tun->flow_count; @@ -373,10 +372,8 @@ unlock: */ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash) { - if (unlikely(e->rps_rxhash != hash)) { - sock_rps_reset_flow_hash(e->rps_rxhash); + if (unlikely(e->rps_rxhash != hash)) e->rps_rxhash = hash; - } } /* We try to identify a flow through its rxhash first. The reason that -- cgit v1.2.1 From dd83829ed9da6262487252851ca0aa67600d7d56 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Fri, 6 Feb 2015 13:48:28 -0800 Subject: Driver: Vmxnet3: Change the hex constant to its decimal equivalent The hex constant chosen for VMXNET3_REV1_MAGIC is offensive, replace it with its decimal equivalent. Signed-off-by: Shrikrishna Khare Reviewed-by: Shreyas Bhatewara Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_defs.h | 2 +- drivers/net/vmxnet3/vmxnet3_int.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h index 25b6fa4810b5..3718d024f638 100644 --- a/drivers/net/vmxnet3/vmxnet3_defs.h +++ b/drivers/net/vmxnet3/vmxnet3_defs.h @@ -393,7 +393,7 @@ struct Vmxnet3_DriverInfo { }; -#define VMXNET3_REV1_MAGIC 0xbabefee1 +#define VMXNET3_REV1_MAGIC 3133079265u /* * QueueDescPA must be 128 bytes aligned. It points to an array of diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 406144b436bf..cd71c77f78f2 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -69,10 +69,10 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.3.3.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.3.4.0-k" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01030300 +#define VMXNET3_DRIVER_VERSION_NUM 0x01030400 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */ -- cgit v1.2.1 From a4870f79c228d109c1e51df4a899394515271604 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Sat, 7 Feb 2015 03:17:31 +0100 Subject: vxlan: Wrong type passed to %pIS src_ip is a pointer to a union vxlan_addr, one member of which is a struct sockaddr. Passing a pointer to src_ip is wrong; one should pass the value of src_ip itself. Since %pIS formally expects something of type struct sockaddr*, let's pass a pointer to the appropriate union member, though this of course doesn't change the generated code. Fixes: e4c7ed415387 ("vxlan: add ipv6 support") Signed-off-by: Rasmus Villemoes Acked-by: Cong Wang Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index a8c755dcab14..11defbb24183 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -991,7 +991,7 @@ static bool vxlan_snoop(struct net_device *dev, if (net_ratelimit()) netdev_info(dev, "%pM migrated from %pIS to %pIS\n", - src_mac, &rdst->remote_ip, &src_ip); + src_mac, &rdst->remote_ip.sa, &src_ip->sa); rdst->remote_ip = *src_ip; f->updated = jiffies; -- cgit v1.2.1 From cf86da489d9bf7abed2e7034d94e75fb17b7b1b2 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Wed, 7 Jan 2015 11:40:17 +0000 Subject: i40e: i40e_fcoe.c: Remove unused function Remove the function i40e_rx_is_fip() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c index 2cd841b29059..dc8cbdde9e23 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -38,15 +38,6 @@ #include "i40e.h" #include "i40e_fcoe.h" -/** - * i40e_rx_is_fip - returns true if the rx packet type is FIP - * @ptype: the packet type field from rx descriptor write-back - **/ -static inline bool i40e_rx_is_fip(u16 ptype) -{ - return ptype == I40E_RX_PTYPE_L2_FIP_PAY2; -} - /** * i40e_rx_is_fcoe - returns true if the rx packet type is FCoE * @ptype: the packet type field from rx descriptor write-back -- cgit v1.2.1 From 83840e4bd5a3ae0022e5cdd02bde149338b6b499 Mon Sep 17 00:00:00 2001 From: John W Linville Date: Wed, 14 Jan 2015 03:06:28 +0000 Subject: i40e: avoid use of uninitialized v_budget in i40e_init_msix This I40E_FCOE block increments v_budget before it has been initialized, then v_budget gets overwritten a few lines later. This patch just reorders the code hunks in what I believe was the intended sequence. Coverity: CID 1260099 Signed-off-by: John W Linville Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index e774a23901f9..9efb69ab2ab0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6933,17 +6933,17 @@ static int i40e_init_msix(struct i40e_pf *pf) if (pf->flags & I40E_FLAG_FD_SB_ENABLED) other_vecs++; + /* Scale down if necessary, and the rings will share vectors */ + pf->num_lan_msix = min_t(int, pf->num_lan_msix, + (hw->func_caps.num_msix_vectors - other_vecs)); + v_budget = pf->num_lan_msix + other_vecs; + #ifdef I40E_FCOE if (pf->flags & I40E_FLAG_FCOE_ENABLED) { pf->num_fcoe_msix = pf->num_fcoe_qps; v_budget += pf->num_fcoe_msix; } - #endif - /* Scale down if necessary, and the rings will share vectors */ - pf->num_lan_msix = min_t(int, pf->num_lan_msix, - (hw->func_caps.num_msix_vectors - other_vecs)); - v_budget = pf->num_lan_msix + other_vecs; pf->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry), GFP_KERNEL); -- cgit v1.2.1 From 1750a22fa9ec34d3842a78780c838d6bf88fc6b5 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 9 Jan 2015 11:18:13 +0000 Subject: i40e: delay after VF reset Delay a minimum of 10ms after VF reset, to allow the hardware's internal FIFOs to flush. Change-ID: I8a02ddb28c9f0d7303a1eb21d0b2443e5b4c1cda Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 044019b9d406..4e4232a58843 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -668,13 +668,13 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr) /* poll VPGEN_VFRSTAT reg to make sure * that reset is complete */ - for (i = 0; i < 100; i++) { - /* vf reset requires driver to first reset the - * vf and then poll the status register to make sure - * that the requested op was completed - * successfully + for (i = 0; i < 10; i++) { + /* VF reset requires driver to first reset the VF and then + * poll the status register to make sure that the reset + * completed successfully. Due to internal HW FIFO flushes, + * we must wait 10ms before the register will be valid. */ - usleep_range(10, 20); + usleep_range(10000, 20000); reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id)); if (reg & I40E_VPGEN_VFRSTAT_VFRD_MASK) { rsd = true; -- cgit v1.2.1 From 07574897d3fefb7f6af5c4128c322a5a05491e62 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 9 Jan 2015 11:18:14 +0000 Subject: i40e: Use even more ARQ descriptors When enabling 64 VFs and loading the VF driver in the host kernel, we can easily overrun the PF's admin receive queue. Double the size of this queue, and increase the work limit to allow the PF to handle more requests in a single pass through the service task. Change-ID: I0efbbdc61954bffad422a2f33c4b948a59370bf5 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index fadf8fa3cb75..b35413d25860 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -87,8 +87,8 @@ #define I40E_MINIMUM_FCOE 1 /* minimum number of QPs for FCoE */ #endif /* I40E_FCOE */ #define I40E_MAX_AQ_BUF_SIZE 4096 -#define I40E_AQ_LEN 128 -#define I40E_AQ_WORK_LIMIT 16 +#define I40E_AQ_LEN 256 +#define I40E_AQ_WORK_LIMIT 32 #define I40E_MAX_USER_PRIORITY 8 #define I40E_DEFAULT_MSG_ENABLE 4 #define I40E_QUEUE_WAIT_RETRY_LIMIT 10 -- cgit v1.2.1 From 3ba9bcb4b68fa63f38bca910ccd4a1bf3cb4195f Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 9 Jan 2015 11:18:15 +0000 Subject: i40e: add locking around VF reset During VF deallocation, we need to lock out the VF reset code. However, we cannot depend on simply masking the interrupt, as this does not lock out the service task, which can still call the reset routine. Instead, leave the interrupt enabled, but add locking around the VF disable and reset routines. For the disable code, we wait to get the lock, as the reset code will take a finite amount of time to run. For the reset code, we just return if we fail to get the lock. Since we know that the VFs are being disabled, we don't need to handle the reset. This fixes a panic when disabling SR-IOV. Change-ID: Iea0a6cdef35c331f48c6d5b2f8e6f0e86322e7d8 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index b35413d25860..2b65cdcad6ba 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -148,6 +148,7 @@ enum i40e_state_t { __I40E_FD_FLUSH_REQUESTED, __I40E_RESET_FAILED, __I40E_PORT_TX_SUSPENDED, + __I40E_VF_DISABLE, }; enum i40e_interrupt_policy { diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 4e4232a58843..40f042af4131 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -647,6 +647,9 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr) int i; u32 reg; + if (test_and_set_bit(__I40E_VF_DISABLE, &pf->state)) + return; + /* warn the VF */ clear_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states); @@ -706,6 +709,7 @@ complete_reset: /* tell the VF the reset is done */ wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE); i40e_flush(hw); + clear_bit(__I40E_VF_DISABLE, &pf->state); } /** @@ -790,6 +794,8 @@ void i40e_free_vfs(struct i40e_pf *pf) if (!pf->vf) return; + while (test_and_set_bit(__I40E_VF_DISABLE, &pf->state)) + usleep_range(1000, 2000); /* Disable IOV before freeing resources. This lets any VF drivers * running in the host get themselves cleaned up before we yank @@ -800,9 +806,6 @@ void i40e_free_vfs(struct i40e_pf *pf) msleep(20); /* let any messages in transit get finished up */ - /* Disable interrupt 0 so we don't try to handle the VFLR. */ - i40e_irq_dynamic_disable_icr0(pf); - /* free up vf resources */ tmp = pf->num_alloc_vfs; pf->num_alloc_vfs = 0; @@ -834,9 +837,7 @@ void i40e_free_vfs(struct i40e_pf *pf) dev_warn(&pf->pdev->dev, "unable to disable SR-IOV because VFs are assigned.\n"); } - - /* Re-enable interrupt 0. */ - i40e_irq_dynamic_enable_icr0(pf); + clear_bit(__I40E_VF_DISABLE, &pf->state); } #ifdef CONFIG_PCI_IOV -- cgit v1.2.1 From f4a718810cf73fa55c85d253634d4a1f9464f6e7 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 9 Jan 2015 11:18:16 +0000 Subject: i40evf: reset on module unload When the module is being unloaded, don't wait for the PF to politely handle all of our admin queue requests, as that might take forever with a lot of VFs enabled. Instead, just stop everything and request a VF reset. When the original shutdown code was written, VF resets were unreliable, so we avoided them. But with production hardware and firmware, and the 1.x PF driver, this is no longer the case. This fixes a potential multi-minute delay on driver unload, VF disable, or system shutdown. Change-ID: Ib43d6d860ef6b9b8f26e8dce0615a0302608c7d9 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index f946aac1df71..cd71c47732b2 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2423,7 +2423,6 @@ static void i40evf_remove(struct pci_dev *pdev) struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40evf_mac_filter *f, *ftmp; struct i40e_hw *hw = &adapter->hw; - int count = 50; cancel_delayed_work_sync(&adapter->init_task); cancel_work_sync(&adapter->reset_task); @@ -2432,12 +2431,18 @@ static void i40evf_remove(struct pci_dev *pdev) unregister_netdev(netdev); adapter->netdev_registered = false; } - while (count-- && adapter->aq_required) - msleep(50); - if (count < 0) - dev_err(&pdev->dev, "Timed out waiting for PF driver.\n"); + /* Shut down all the garbage mashers on the detention level */ adapter->state = __I40EVF_REMOVE; + adapter->aq_required = 0; + adapter->aq_pending = 0; + i40evf_request_reset(adapter); + msleep(20); + /* If the FW isn't responding, kick it once, but only once. */ + if (!i40evf_asq_done(hw)) { + i40evf_request_reset(adapter); + msleep(20); + } if (adapter->msix_entries) { i40evf_misc_irq_disable(adapter); -- cgit v1.2.1 From 8b011ebb5c371f8767e6e813a1aca3b7fc795f94 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 9 Jan 2015 11:18:17 +0000 Subject: i40evf: ignore bogus messages from FW Occasionally on shutdown, the FW will hand us a bunch of messages filled with zeros, which can cause us to spin trying to handle them. Just ignore these and get on with shutting down. Change-ID: I347e9648f7153ad5a7b7e0847b87f7aad5f3e0da Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index cd71c47732b2..38126f5d6fd9 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1631,7 +1631,7 @@ static void i40evf_adminq_task(struct work_struct *work) v_msg = (struct i40e_virtchnl_msg *)&event.desc; do { ret = i40evf_clean_arq_element(hw, &event, &pending); - if (ret) + if (ret || !v_msg->v_opcode) break; /* No event to process or error cleaning ARQ */ i40evf_virtchnl_completion(adapter, v_msg->v_opcode, -- cgit v1.2.1 From 00293fdc4229e493556f8cca403305f3c2124743 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 9 Jan 2015 11:18:18 +0000 Subject: i40evf: stop the watchdog for shutdown Stop the watchdog during shutdown. Failing to do this causes a log full of admin queue errors and the occasional hang when the system is shut down. Change-ID: Ib2fd11213cca2fa589eb68577e86b1000c23c250 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 38126f5d6fd9..8d8c201c63c1 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2213,12 +2213,18 @@ err: static void i40evf_shutdown(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); + struct i40evf_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); if (netif_running(netdev)) i40evf_close(netdev); + /* Prevent the watchdog from running. */ + adapter->state = __I40EVF_REMOVE; + adapter->aq_required = 0; + adapter->aq_pending = 0; + #ifdef CONFIG_PM pci_save_state(pdev); -- cgit v1.2.1 From acde2c2d28c8afee41eb67ee1cbf9e47a3f3e475 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 9 Feb 2015 09:47:10 +0530 Subject: cxgb4: Fix trace observed while dumping clip_tbl Handle clip_tbl debugfs entry, when clip_tbl isn't allocated. In commit b5a02f503caa0837 ("cxgb4: Update ipv6 address handling api") wrong argument was passed for single_open for clip_tbl debugfs entry, which led to below trace. Fixing it. ====== call Trace: [] clip_tbl_open+0x16/0x30 [cxgb4] [] do_dentry_open+0x21a/0x370 [] vfs_open+0x49/0x50 [] do_last+0x21e/0x800 [] path_openat+0x92/0x470 [] ? rb_reserve_next_event+0xaf/0x380 [] ? rb_reserve_next_event+0xaf/0x380 [] do_filp_open+0x4a/0xa0 [] ? __alloc_fd+0xcd/0x140 [] do_sys_open+0x11a/0x230 [] ? syscall_trace_enter_phase2+0xaf/0x1b0 [] SyS_open+0x1e/0x20 [] tracesys_phase2+0xd4/0xd9 Code: 89 e5 66 66 66 66 90 48 8b 47 e0 48 8b 40 30 48 8b 40 58 c9 c3 66 0f 1f 84 00 00 00 00 00 55 48 89 e5 66 66 66 66 90 48 8b 47 e0 <48> 8b 40 58 c9 c3 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 RIP [] PDE_DATA+0xd/0x20 RSP CR2: 0000000000000058 ===== Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c | 3 +++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c index 2b407b6a35a8..9062a8434246 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c @@ -81,6 +81,9 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) int addr_len; int ret = 0; + if (!ctbl) + return 0; + if (v6) addr_len = 16; else diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index a1029eecef02..d221f6b28fcd 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -1237,7 +1237,7 @@ DEFINE_SIMPLE_DEBUGFS_FILE(sensors); #if IS_ENABLED(CONFIG_IPV6) static int clip_tbl_open(struct inode *inode, struct file *file) { - return single_open(file, clip_tbl_show, PDE_DATA(inode)); + return single_open(file, clip_tbl_show, inode->i_private); } static const struct file_operations clip_tbl_debugfs_fops = { -- cgit v1.2.1 From 88086e5d0adf27cf819e11a0a3159d8ef09773a6 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 9 Jan 2015 11:18:19 +0000 Subject: i40e: stop the service task at shutdown Stop the service task in the shutdown handler, preventing it from accessing the admin queue after it had been closed. This fixes a panic that could occur when the system was shut down with a lot of VFs enabled. Change-ID: I286735e3842de472385bbf7ad68d30331e508add Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 9efb69ab2ab0..1923a0bcd6e6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -9736,6 +9736,8 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state) set_bit(__I40E_SUSPENDED, &pf->state); set_bit(__I40E_DOWN, &pf->state); + del_timer_sync(&pf->service_timer); + cancel_work_sync(&pf->service_task); rtnl_lock(); i40e_prep_for_reset(pf); rtnl_unlock(); -- cgit v1.2.1 From c29af37fd5b7b649b57139cee6bf730c996fe756 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Sat, 10 Jan 2015 01:07:19 +0000 Subject: i40evf: Force Tx writeback on ITR This patch forces Tx descriptor writebacks on ITR by kicking off the SWINT interrupt when we notice that there are non-cache-aligned Tx descriptors waiting in the ring while interrupts are disabled under NAPI. Change-ID: dd6d9675629bf266c7515ad7a201394618c35444 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 4 +-- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 38 +++++++++++++++++++++++++-- drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 1 + 3 files changed, 39 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 420d66274d69..5aa6ef15f241 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -836,8 +836,8 @@ static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) { u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK | I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK | - I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK - /* allow 00 to be written to the index */; + I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK; + /* allow 00 to be written to the index */ wr32(&vsi->back->hw, I40E_PFINT_DYN_CTLN(q_vector->v_idx + vsi->base_vector - 1), diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 82c3798fdd36..4bf15da509e3 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -192,6 +192,8 @@ static inline u32 i40e_get_head(struct i40e_ring *tx_ring) return le32_to_cpu(*(volatile __le32 *)head); } +#define WB_STRIDE 0x3 + /** * i40e_clean_tx_irq - Reclaim resources after transmit completes * @tx_ring: tx ring to clean @@ -293,6 +295,14 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) tx_ring->q_vector->tx.total_bytes += total_bytes; tx_ring->q_vector->tx.total_packets += total_packets; + if (budget && + !((i & WB_STRIDE) == WB_STRIDE) && + !test_bit(__I40E_DOWN, &tx_ring->vsi->state) && + (I40E_DESC_UNUSED(tx_ring) != tx_ring->count)) + tx_ring->arm_wb = true; + else + tx_ring->arm_wb = false; + if (check_for_tx_hang(tx_ring) && i40e_check_tx_hang(tx_ring)) { /* schedule immediate reset if we believe we hung */ dev_info(tx_ring->dev, "Detected Tx Unit Hang\n" @@ -343,6 +353,24 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) return budget > 0; } +/** + * i40e_force_wb -Arm hardware to do a wb on noncache aligned descriptors + * @vsi: the VSI we care about + * @q_vector: the vector on which to force writeback + * + **/ +static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) +{ + u32 val = I40E_VFINT_DYN_CTLN_INTENA_MASK | + I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK | + I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK; + /* allow 00 to be written to the index */ + + wr32(&vsi->back->hw, + I40E_VFINT_DYN_CTLN1(q_vector->v_idx + vsi->base_vector - 1), + val); +} + /** * i40e_set_new_dynamic_itr - Find new ITR level * @rc: structure containing ring performance data @@ -1065,6 +1093,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) struct i40e_vsi *vsi = q_vector->vsi; struct i40e_ring *ring; bool clean_complete = true; + bool arm_wb = false; int budget_per_ring; if (test_bit(__I40E_DOWN, &vsi->state)) { @@ -1075,8 +1104,10 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) /* Since the actual Tx work is minimal, we can give the Tx a larger * budget and be more aggressive about cleaning up the Tx descriptors. */ - i40e_for_each_ring(ring, q_vector->tx) + i40e_for_each_ring(ring, q_vector->tx) { clean_complete &= i40e_clean_tx_irq(ring, vsi->work_limit); + arm_wb |= ring->arm_wb; + } /* We attempt to distribute budget to each Rx queue fairly, but don't * allow the budget to go below 1 because that would exit polling early. @@ -1087,8 +1118,11 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) clean_complete &= i40e_clean_rx_irq(ring, budget_per_ring); /* If work not completed, return budget and polling will return */ - if (!clean_complete) + if (!clean_complete) { + if (arm_wb) + i40e_force_wb(vsi, q_vector); return budget; + } /* Work is done so exit the polling mode and re-enable the interrupt */ napi_complete(napi); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index c7f29626eada..4e15903b2b6d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -238,6 +238,7 @@ struct i40e_ring { u8 atr_count; bool ring_active; /* is ring online or not */ + bool arm_wb; /* do something to arm write back */ /* stats structs */ struct i40e_queue_stats stats; -- cgit v1.2.1 From 9be00d67579710d8383f2bf030a649f9c76289e7 Mon Sep 17 00:00:00 2001 From: Matt Jared Date: Sat, 24 Jan 2015 09:58:28 +0000 Subject: i40e: fix led blink toggle to enable steady state Make sure to clear the GPIO blink field, instead of OR'ing against zero if the field is already '1'. Change-ID: Ie52a52abd48f6f52b20778a6b8b0c542dfc9245c Signed-off-by: Matt Jared Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 5669bfa39f14..11a9ffebf8d8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1142,8 +1142,10 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink) if (mode == I40E_LINK_ACTIVITY) blink = false; - gpio_val |= (blink ? 1 : 0) << - I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT; + if (blink) + gpio_val |= (1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); + else + gpio_val &= ~(1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); wr32(hw, I40E_GLGEN_GPIO_CTL(i), gpio_val); break; -- cgit v1.2.1 From 031477736becaa063aa3f3d06934a14ff100820b Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 24 Jan 2015 09:58:29 +0000 Subject: i40e: Fix function header s/enable/disable Change-ID: Ic0572a6c59d03e05a0a35d2e2e9d532e0512638d Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 1923a0bcd6e6..cbe281be1c9f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2940,7 +2940,7 @@ void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector) /** * i40e_irq_dynamic_disable - Disable default interrupt generation settings * @vsi: pointer to a vsi - * @vector: enable a particular Hw Interrupt vector + * @vector: disable a particular Hw Interrupt vector **/ void i40e_irq_dynamic_disable(struct i40e_vsi *vsi, int vector) { -- cgit v1.2.1 From 4d48b56659b4bc16f9b0ff344112ff3922ab4b66 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Sat, 24 Jan 2015 09:58:30 +0000 Subject: i40e: use dev_port for fcoe netdev Set different dev_port value 1 for FCoE netdev than the default zero dev_port value for PF netdev, this helps biosdevname user tool to differentiate them correctly while both attached to the same PCI function. Change-ID: I8fb90e4ef52a1242f7580e49a3f0918735aee8ef Signed-off-by: Vasu Dev Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c index dc8cbdde9e23..401f7ed76c1f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -1502,6 +1502,12 @@ void i40e_fcoe_config_netdev(struct net_device *netdev, struct i40e_vsi *vsi) strlcpy(netdev->name, "fcoe%d", IFNAMSIZ-1); netdev->mtu = FCOE_MTU; SET_NETDEV_DEV(netdev, &pf->pdev->dev); + /* set different dev_port value 1 for FCoE netdev than the default + * zero dev_port value for PF netdev, this helps biosdevname user + * tool to differentiate them correctly while both attached to the + * same PCI function. + */ + netdev->dev_port = 1; i40e_add_filter(vsi, hw->mac.san_addr, 0, false, false); i40e_add_filter(vsi, (u8[6]) FC_FCOE_FLOGI_MAC, 0, false, false); i40e_add_filter(vsi, FIP_ALL_FCOE_MACS, 0, false, false); -- cgit v1.2.1 From 9230165f00ddfeb17094bbfe1b0665521c1856d2 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Sat, 24 Jan 2015 09:58:31 +0000 Subject: i40e: Enable Loopback for the FCOE vsi as well For all VSIs on a VEB, Loopback mode should be either on or off. Our configuration requires them to be ON so that VSIs can directly talk to each other without going out on the wire. Change-ID: I77b8310bc846329972b13b185949ab1431a46c30 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c index 401f7ed76c1f..27c206e62da7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -395,6 +395,7 @@ int i40e_fcoe_vsi_init(struct i40e_vsi *vsi, struct i40e_vsi_context *ctxt) I40E_AQ_VSI_PROP_INGRESS_UP_VALID | I40E_AQ_VSI_PROP_EGRESS_UP_VALID)); + info->switch_id = cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB); enabled_tc = i40e_get_fcoe_tc_map(pf); i40e_vsi_setup_queue_map(vsi, ctxt, enabled_tc, true); -- cgit v1.2.1 From 638702bd59a336f48f39a58ed8bdf199c08afeda Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Sat, 24 Jan 2015 09:58:32 +0000 Subject: i40e/i40evf: Add call to u64_stats_init to init This patch adds a call to u64_stats_init to Rx setup. This done in order to avoid lockdep errors with seqcount on newer kernels. Change-ID: Ia8ba8f0bcbd1c0e926f97d70aeee4ce4fd055e93 Signed-off-by: Carolyn Wyborny Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 ++ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 5aa6ef15f241..f4d6d90572d1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1098,6 +1098,8 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring) if (!rx_ring->rx_bi) goto err; + u64_stats_init(rx_ring->syncp); + /* Round up to nearest 4K */ rx_ring->size = ring_is_16byte_desc_enabled(rx_ring) ? rx_ring->count * sizeof(union i40e_16byte_rx_desc) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 4bf15da509e3..459499a47ca3 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -596,6 +596,8 @@ int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring) if (!rx_ring->rx_bi) goto err; + u64_stats_init(rx_ring->syncp); + /* Round up to nearest 4K */ rx_ring->size = ring_is_16byte_desc_enabled(rx_ring) ? rx_ring->count * sizeof(union i40e_16byte_rx_desc) -- cgit v1.2.1 From 92e584fe443995bbb84069a4d13ea8ebedb5c5c8 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Sun, 8 Feb 2015 11:49:32 +0200 Subject: net/bonding: Fix potential bad memory access during bonding events When queuing work to send the NETDEV_BONDING_INFO netdev event, it's possible that when the work is executed, the pointer to the slave becomes invalid. This can happen if between queuing the event and the execution of the work, the net-device was un-ensvaled and re-enslaved. Fix that by queuing a work with the data of the slave instead of the slave structure. Fixes: 69e6113343cf ('net/bonding: Notify state change on slaves') Reported-by: Nikolay Aleksandrov Signed-off-by: Moni Shoua Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 679ef00d6b16..b979c265fc51 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1196,18 +1196,11 @@ static void bond_fill_ifslave(struct slave *slave, struct ifslave *info) info->link_failure_count = slave->link_failure_count; } -static void bond_netdev_notify(struct slave *slave, struct net_device *dev) +static void bond_netdev_notify(struct net_device *dev, + struct netdev_bonding_info *info) { - struct bonding *bond = slave->bond; - struct netdev_bonding_info bonding_info; - rtnl_lock(); - /* make sure that slave is still valid */ - if (dev->priv_flags & IFF_BONDING) { - bond_fill_ifslave(slave, &bonding_info.slave); - bond_fill_ifbond(bond, &bonding_info.master); - netdev_bonding_info_change(slave->dev, &bonding_info); - } + netdev_bonding_info_change(dev, info); rtnl_unlock(); } @@ -1216,25 +1209,26 @@ static void bond_netdev_notify_work(struct work_struct *_work) struct netdev_notify_work *w = container_of(_work, struct netdev_notify_work, work.work); - bond_netdev_notify(w->slave, w->dev); + bond_netdev_notify(w->dev, &w->bonding_info); dev_put(w->dev); + kfree(w); } void bond_queue_slave_event(struct slave *slave) { + struct bonding *bond = slave->bond; struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC); if (!nnw) return; - INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work); - nnw->slave = slave; + dev_hold(slave->dev); nnw->dev = slave->dev; + bond_fill_ifslave(slave, &nnw->bonding_info.slave); + bond_fill_ifbond(bond, &nnw->bonding_info.master); + INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work); - if (queue_delayed_work(slave->bond->wq, &nnw->work, 0)) - dev_hold(slave->dev); - else - kfree(nnw); + queue_delayed_work(slave->bond->wq, &nnw->work, 0); } /* enslave device to bond device */ -- cgit v1.2.1 From ba3f8cd55f2aaa734ba44d8dd8cfaa6503c83d63 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 9 Feb 2015 12:07:30 +0530 Subject: cxgb4: Add support in cxgb4 to get expansion rom version via ethtool Add support to get option/expansion rom version flashed in the adapter via ethtool getdrvinfo function. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 9 ++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 37 +++++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 8 ++++++ 4 files changed, 55 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 0fe3a52fb0b8..d6cda17efe6e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1121,6 +1121,7 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, unsigned int t4_flash_cfg_addr(struct adapter *adapter); int t4_get_fw_version(struct adapter *adapter, u32 *vers); int t4_get_tp_version(struct adapter *adapter, u32 *vers); +int t4_get_exprom_version(struct adapter *adapter, u32 *vers); int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info, const u8 *fw_data, unsigned int fw_size, struct fw_hdr *card_fw, enum dev_state state, int *reset); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 5db5b4f7b94d..a22cf932ca35 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1419,6 +1419,7 @@ static int get_eeprom_len(struct net_device *dev) static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct adapter *adapter = netdev2adap(dev); + u32 exprom_vers; strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); @@ -1436,6 +1437,14 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers), FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers), FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers)); + + if (!t4_get_exprom_version(adapter, &exprom_vers)) + snprintf(info->erom_version, sizeof(info->erom_version), + "%u.%u.%u.%u", + FW_HDR_FW_VER_MAJOR_G(exprom_vers), + FW_HDR_FW_VER_MINOR_G(exprom_vers), + FW_HDR_FW_VER_MICRO_G(exprom_vers), + FW_HDR_FW_VER_BUILD_G(exprom_vers)); } static void get_strings(struct net_device *dev, u32 stringset, u8 *data) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 2c13e8005319..4d643b65265e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -948,6 +948,43 @@ int t4_get_tp_version(struct adapter *adapter, u32 *vers) 1, vers, 0); } +/** + * t4_get_exprom_version - return the Expansion ROM version (if any) + * @adapter: the adapter + * @vers: where to place the version + * + * Reads the Expansion ROM header from FLASH and returns the version + * number (if present) through the @vers return value pointer. We return + * this in the Firmware Version Format since it's convenient. Return + * 0 on success, -ENOENT if no Expansion ROM is present. + */ +int t4_get_exprom_version(struct adapter *adap, u32 *vers) +{ + struct exprom_header { + unsigned char hdr_arr[16]; /* must start with 0x55aa */ + unsigned char hdr_ver[4]; /* Expansion ROM version */ + } *hdr; + u32 exprom_header_buf[DIV_ROUND_UP(sizeof(struct exprom_header), + sizeof(u32))]; + int ret; + + ret = t4_read_flash(adap, FLASH_EXP_ROM_START, + ARRAY_SIZE(exprom_header_buf), exprom_header_buf, + 0); + if (ret) + return ret; + + hdr = (struct exprom_header *)exprom_header_buf; + if (hdr->hdr_arr[0] != 0x55 || hdr->hdr_arr[1] != 0xaa) + return -ENOENT; + + *vers = (FW_HDR_FW_VER_MAJOR_V(hdr->hdr_ver[0]) | + FW_HDR_FW_VER_MINOR_V(hdr->hdr_ver[1]) | + FW_HDR_FW_VER_MICRO_V(hdr->hdr_ver[2]) | + FW_HDR_FW_VER_BUILD_V(hdr->hdr_ver[3])); + return 0; +} + /* Is the given firmware API compatible with the one the driver was compiled * with? */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 95fc425375c4..9b353a88cbda 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -3018,21 +3018,29 @@ enum fw_hdr_chip { #define FW_HDR_FW_VER_MAJOR_S 24 #define FW_HDR_FW_VER_MAJOR_M 0xff +#define FW_HDR_FW_VER_MAJOR_V(x) \ + ((x) << FW_HDR_FW_VER_MAJOR_S) #define FW_HDR_FW_VER_MAJOR_G(x) \ (((x) >> FW_HDR_FW_VER_MAJOR_S) & FW_HDR_FW_VER_MAJOR_M) #define FW_HDR_FW_VER_MINOR_S 16 #define FW_HDR_FW_VER_MINOR_M 0xff +#define FW_HDR_FW_VER_MINOR_V(x) \ + ((x) << FW_HDR_FW_VER_MINOR_S) #define FW_HDR_FW_VER_MINOR_G(x) \ (((x) >> FW_HDR_FW_VER_MINOR_S) & FW_HDR_FW_VER_MINOR_M) #define FW_HDR_FW_VER_MICRO_S 8 #define FW_HDR_FW_VER_MICRO_M 0xff +#define FW_HDR_FW_VER_MICRO_V(x) \ + ((x) << FW_HDR_FW_VER_MICRO_S) #define FW_HDR_FW_VER_MICRO_G(x) \ (((x) >> FW_HDR_FW_VER_MICRO_S) & FW_HDR_FW_VER_MICRO_M) #define FW_HDR_FW_VER_BUILD_S 0 #define FW_HDR_FW_VER_BUILD_M 0xff +#define FW_HDR_FW_VER_BUILD_V(x) \ + ((x) << FW_HDR_FW_VER_BUILD_S) #define FW_HDR_FW_VER_BUILD_G(x) \ (((x) >> FW_HDR_FW_VER_BUILD_S) & FW_HDR_FW_VER_BUILD_M) -- cgit v1.2.1 From 1d966d03a37f7f58abf12e87203d03f96950cfd0 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 9 Feb 2015 11:10:41 +0100 Subject: net: Mellanox: Delete unnecessary checks before the function call "vunmap" The vunmap() function performs also input parameter validation. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/alloc.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/alloc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c index a716c26e0d99..0c51c69f802f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c @@ -662,7 +662,7 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf) buf->direct.buf, buf->direct.map); else { - if (BITS_PER_LONG == 64 && buf->direct.buf) + if (BITS_PER_LONG == 64) vunmap(buf->direct.buf); for (i = 0; i < buf->nbufs; ++i) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index 56779c1c7811..201ca6d76ce5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -121,7 +121,7 @@ void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf) dma_free_coherent(&dev->pdev->dev, buf->size, buf->direct.buf, buf->direct.map); else { - if (BITS_PER_LONG == 64 && buf->direct.buf) + if (BITS_PER_LONG == 64) vunmap(buf->direct.buf); for (i = 0; i < buf->nbufs; i++) -- cgit v1.2.1 From f217d6ca4a8cde473358637aa29daaaa3d0b57a9 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Mon, 9 Feb 2015 17:42:31 -0800 Subject: i40e: Fix for stats init function call in Rx setup This patch fixes indentation issue and error found in argument reported by static analysis. Without this patch, sparse and other static analysis errors will be found. Reported-by: Fengguang Wu Reported-by: Julia Lawall Signed-off-by: Carolyn Wyborny Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 +- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index f4d6d90572d1..2206d2d36f0f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1098,7 +1098,7 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring) if (!rx_ring->rx_bi) goto err; - u64_stats_init(rx_ring->syncp); + u64_stats_init(&rx_ring->syncp); /* Round up to nearest 4K */ rx_ring->size = ring_is_16byte_desc_enabled(rx_ring) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 459499a47ca3..29004382f462 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -596,7 +596,7 @@ int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring) if (!rx_ring->rx_bi) goto err; - u64_stats_init(rx_ring->syncp); + u64_stats_init(&rx_ring->syncp); /* Round up to nearest 4K */ rx_ring->size = ring_is_16byte_desc_enabled(rx_ring) -- cgit v1.2.1