From nobody Mon Aug 21 01:36:48 2023 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4RTZp856Q8z4r1MN; Mon, 21 Aug 2023 01:36:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4RTZp84vt2z4kxd; Mon, 21 Aug 2023 01:36:48 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1692581808; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=eJMRN704dqun758SCxB4GuAQkHV+Gjgzig0RWMiQE/8=; b=RyJNMhvcsQ6ROD05SyXUMsvnYu5kT0DKTexOTR8+6Y9Br3yNo9BVfvWZk6EI1bQgl9RSOQ 71DcR+x96qt8MgtaOcxKya3PjSxdF3bTVz6AqS8BcAA6nl1JK086KdSYbnMhIWYx2eiUoW 2UV4z06zk9no4iGbh/y4vElY6LK+s+D4Xwf53Y71O3nzcUjcVqie0InvArmdxmWc5XffdB vfmVfarDbCz7BYjwH7ex5AbsyLyCocJXUcdTDhBoZUVoSJj8Pjai6zxxH+IbCb547U/7vU QIu5s2LwN2mH3LYpc/IC8ikCrsTrTLDTDMQhOnHDzMWuDxKnM2QbtKsEuOgCZg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1692581808; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=eJMRN704dqun758SCxB4GuAQkHV+Gjgzig0RWMiQE/8=; b=LOOX429IFvJSUWHA9TTsZTGvokgbHvVXdEdtNgNGQUPWOVGe+9ks6z6KTG3RQ7tR1okylC 8XQAMDptjr9hX7lpPfGWsDDIZoJzFelnVYAUmJsva7O/2zMompd8h+jzRr7aLbIvAVZZGw 6tuwzqqQUqjgpPZko+EdqbbYh641VFDaR7U6xiBHasKyoC7JwsA4BKfQOoKgy6jEX+0Mwp yjpzk/Lt2Cy95Q4dgCXafOAiK7wWvzwDtA/fy8lWY5rCU2mlrAs7FZiXwHgqIt1X2TfUp8 Lhc7MaIRhR/xBS2GXgWQe7C/Io0qjx/ZgbykyMo00h5v4r8c0Ei7Yvd5aEdmRQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1692581808; a=rsa-sha256; cv=none; b=bn9ex/8x1m1G5DpbY3zprT5ko540wmPd/ZXVW+hXFpdO8ZJV6pWhQuy3avcabGOwa0I3mI k2gs16uTzK4H7iqY+lFjq/NX6DjJf2rIw7ZoHmOSw6RzQWkbnebwga5t8V+4hl6XKqfTdj LJ/2MumaN/z/rzjsevOwCuC4Cpr2hIsO0BRTwmdfT8NPOM0r4l623Z11WAXxhlDzSKIKoG A9+ow+bwb+oDiKjL/DtUxBA+4q9ZY+SPIMvyMwZzuAA5sg5GW8bdtOGLfHyt3iMGPwiTUp KqmJ7lTQJI5N5ysizn/shJ4Rhyq1A9C331H8Ork9dwm5y8WrVbTWg5LZrgFN/g== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4RTZp840f0z11xn; Mon, 21 Aug 2023 01:36:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 37L1amw9038275; Mon, 21 Aug 2023 01:36:48 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 37L1amUR038272; Mon, 21 Aug 2023 01:36:48 GMT (envelope-from git) Date: Mon, 21 Aug 2023 01:36:48 GMT Message-Id: <202308210136.37L1amUR038272@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Bjoern A. Zeeb" Subject: git: 07724ba62b4c - main - ath10k: update driver from upstream List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: bz X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 07724ba62b4c432ea04dce9465a5ab6e2c3f5a0d Auto-Submitted: auto-generated The branch main has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=07724ba62b4c432ea04dce9465a5ab6e2c3f5a0d commit 07724ba62b4c432ea04dce9465a5ab6e2c3f5a0d Author: Bjoern A. Zeeb AuthorDate: 2023-05-20 00:37:02 +0000 Commit: Bjoern A. Zeeb CommitDate: 2023-08-21 01:32:10 +0000 ath10k: update driver from upstream This is a set of updates of the ath10k driver based on wireless-testing (wt-2023-05-11) 711dca0ca3d77414f8f346e564e9c8640147f40d (after v6.4-rc1), (wt-2023-06-09) 7bd20e011626ccc3ad53e57873452b1716fcfaaa (after v6.4-rc5), (wt-2023-07-24) 62e409149b62a285e89018e49b2e115757fb9022 (after v6.5-rc3), (wt-2023-08-06) 2a220a15be657a24868368892e3e2caba2115283 (after v6.5-rc4). MFC after: 20 days --- sys/contrib/dev/athk/ath10k/Kconfig | 1 + sys/contrib/dev/athk/ath10k/ahb.c | 31 +--- sys/contrib/dev/athk/ath10k/bmi.c | 4 +- sys/contrib/dev/athk/ath10k/ce.c | 77 +--------- sys/contrib/dev/athk/ath10k/core.c | 77 +++++++++- sys/contrib/dev/athk/ath10k/core.h | 11 +- sys/contrib/dev/athk/ath10k/coredump.c | 2 +- sys/contrib/dev/athk/ath10k/coredump.h | 2 +- sys/contrib/dev/athk/ath10k/debug.c | 11 +- sys/contrib/dev/athk/ath10k/debugfs_sta.c | 2 +- sys/contrib/dev/athk/ath10k/htc.c | 23 ++- sys/contrib/dev/athk/ath10k/htt.h | 12 +- sys/contrib/dev/athk/ath10k/htt_rx.c | 47 +++--- sys/contrib/dev/athk/ath10k/htt_tx.c | 63 ++++---- sys/contrib/dev/athk/ath10k/hw.c | 6 +- sys/contrib/dev/athk/ath10k/hw.h | 6 + sys/contrib/dev/athk/ath10k/mac.c | 227 +++++++++++++++++++---------- sys/contrib/dev/athk/ath10k/pci.c | 32 ++-- sys/contrib/dev/athk/ath10k/pci.h | 2 +- sys/contrib/dev/athk/ath10k/qmi.c | 52 +++++-- sys/contrib/dev/athk/ath10k/qmi_wlfw_v01.c | 126 ++++++++-------- sys/contrib/dev/athk/ath10k/qmi_wlfw_v01.h | 102 ++++++------- sys/contrib/dev/athk/ath10k/rx_desc.h | 2 +- sys/contrib/dev/athk/ath10k/sdio.c | 4 +- sys/contrib/dev/athk/ath10k/snoc.c | 18 +-- sys/contrib/dev/athk/ath10k/swap.h | 2 +- sys/contrib/dev/athk/ath10k/thermal.c | 2 +- sys/contrib/dev/athk/ath10k/thermal.h | 2 +- sys/contrib/dev/athk/ath10k/trace.h | 14 +- sys/contrib/dev/athk/ath10k/txrx.c | 17 ++- sys/contrib/dev/athk/ath10k/usb.c | 26 ++++ sys/contrib/dev/athk/ath10k/usb.h | 2 +- sys/contrib/dev/athk/ath10k/wmi-tlv.c | 9 +- sys/contrib/dev/athk/ath10k/wmi-tlv.h | 4 +- sys/contrib/dev/athk/ath10k/wmi.c | 73 ++-------- sys/contrib/dev/athk/ath10k/wmi.h | 16 +- 36 files changed, 609 insertions(+), 498 deletions(-) diff --git a/sys/contrib/dev/athk/ath10k/Kconfig b/sys/contrib/dev/athk/ath10k/Kconfig index ca007b800f75..e6ea884cafc1 100644 --- a/sys/contrib/dev/athk/ath10k/Kconfig +++ b/sys/contrib/dev/athk/ath10k/Kconfig @@ -44,6 +44,7 @@ config ATH10K_SNOC tristate "Qualcomm ath10k SNOC support" depends on ATH10K depends on ARCH_QCOM || COMPILE_TEST + depends on QCOM_SMEM select QCOM_SCM select QCOM_QMI_HELPERS help diff --git a/sys/contrib/dev/athk/ath10k/ahb.c b/sys/contrib/dev/athk/ath10k/ahb.c index ab8f77ae5e66..76efea2f1138 100644 --- a/sys/contrib/dev/athk/ath10k/ahb.c +++ b/sys/contrib/dev/athk/ath10k/ahb.c @@ -5,7 +5,7 @@ */ #include #include -#include +#include #include #include #include "core.h" @@ -27,7 +27,7 @@ MODULE_DEVICE_TABLE(of, ath10k_ahb_of_match); static inline struct ath10k_ahb *ath10k_ahb_priv(struct ath10k *ar) { - return &((struct ath10k_pci *)ar->drv_priv)->ahb[0]; + return &ath10k_pci_priv(ar)->ahb[0]; } static void ath10k_ahb_write32(struct ath10k *ar, u32 offset, u32 value) @@ -728,20 +728,17 @@ static int ath10k_ahb_probe(struct platform_device *pdev) struct ath10k *ar; struct ath10k_ahb *ar_ahb; struct ath10k_pci *ar_pci; - const struct of_device_id *of_id; enum ath10k_hw_rev hw_rev; size_t size; int ret; struct ath10k_bus_params bus_params = {}; - of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev); - if (!of_id) { - dev_err(&pdev->dev, "failed to find matching device tree id\n"); + hw_rev = (enum ath10k_hw_rev)of_device_get_match_data(&pdev->dev); + if (!hw_rev) { + dev_err(&pdev->dev, "OF data missing\n"); return -EINVAL; } - hw_rev = (enum ath10k_hw_rev)of_id->data; - size = sizeof(*ar_pci) + sizeof(*ar_ahb); ar = ath10k_core_create(size, &pdev->dev, ATH10K_BUS_AHB, hw_rev, &ath10k_ahb_hif_ops); @@ -819,23 +816,13 @@ err_resource_deinit: err_core_destroy: ath10k_core_destroy(ar); - platform_set_drvdata(pdev, NULL); return ret; } -static int ath10k_ahb_remove(struct platform_device *pdev) +static void ath10k_ahb_remove(struct platform_device *pdev) { struct ath10k *ar = platform_get_drvdata(pdev); - struct ath10k_ahb *ar_ahb; - - if (!ar) - return -EINVAL; - - ar_ahb = ath10k_ahb_priv(ar); - - if (!ar_ahb) - return -EINVAL; ath10k_dbg(ar, ATH10K_DBG_AHB, "ahb remove\n"); @@ -847,10 +834,6 @@ static int ath10k_ahb_remove(struct platform_device *pdev) ath10k_ahb_clock_disable(ar); ath10k_ahb_resource_deinit(ar); ath10k_core_destroy(ar); - - platform_set_drvdata(pdev, NULL); - - return 0; } static struct platform_driver ath10k_ahb_driver = { @@ -859,7 +842,7 @@ static struct platform_driver ath10k_ahb_driver = { .of_match_table = ath10k_ahb_of_match, }, .probe = ath10k_ahb_probe, - .remove = ath10k_ahb_remove, + .remove_new = ath10k_ahb_remove, }; int ath10k_ahb_init(void) diff --git a/sys/contrib/dev/athk/ath10k/bmi.c b/sys/contrib/dev/athk/ath10k/bmi.c index 2ac2bbe8c663..12c1983b4dd6 100644 --- a/sys/contrib/dev/athk/ath10k/bmi.c +++ b/sys/contrib/dev/athk/ath10k/bmi.c @@ -101,7 +101,7 @@ int ath10k_bmi_get_target_info_sdio(struct ath10k *ar, cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO); /* Step 1: Read 4 bytes of the target info and check if it is - * the special sentinal version word or the first word in the + * the special sentinel version word or the first word in the * version response. */ resplen = sizeof(u32); @@ -111,7 +111,7 @@ int ath10k_bmi_get_target_info_sdio(struct ath10k *ar, return ret; } - /* Some SDIO boards have a special sentinal byte before the real + /* Some SDIO boards have a special sentinel byte before the real * version response. */ if (__le32_to_cpu(tmp) == TARGET_VERSION_SENTINAL) { diff --git a/sys/contrib/dev/athk/ath10k/ce.c b/sys/contrib/dev/athk/ath10k/ce.c index 720d1c48111f..8168e20bb09a 100644 --- a/sys/contrib/dev/athk/ath10k/ce.c +++ b/sys/contrib/dev/athk/ath10k/ce.c @@ -77,47 +77,6 @@ static inline u32 shadow_sr_wr_ind_addr(struct ath10k *ar, return addr; } -#if defined(__linux__) -static inline u32 shadow_dst_wr_ind_addr(struct ath10k *ar, - struct ath10k_ce_pipe *ce_state) -{ - u32 ce_id = ce_state->id; - u32 addr = 0; - - switch (ce_id) { - case 1: - addr = 0x00032034; - break; - case 2: - addr = 0x00032038; - break; - case 5: - addr = 0x00032044; - break; - case 7: - addr = 0x0003204C; - break; - case 8: - addr = 0x00032050; - break; - case 9: - addr = 0x00032054; - break; - case 10: - addr = 0x00032058; - break; - case 11: - addr = 0x0003205C; - break; - default: - ath10k_warn(ar, "invalid CE id: %d", ce_id); - break; - } - - return addr; -} -#endif - static inline unsigned int ath10k_set_ring_byte(unsigned int offset, struct ath10k_hw_ce_regs_addr_map *addr_map) @@ -125,15 +84,6 @@ ath10k_set_ring_byte(unsigned int offset, return ((offset << addr_map->lsb) & addr_map->mask); } -#if defined(__linux__) -static inline unsigned int -ath10k_get_ring_byte(unsigned int offset, - struct ath10k_hw_ce_regs_addr_map *addr_map) -{ - return ((offset & addr_map->mask) >> (addr_map->lsb)); -} -#endif - static inline u32 ath10k_ce_read32(struct ath10k *ar, u32 offset) { struct ath10k_ce *ce = ath10k_ce_priv(ar); @@ -212,16 +162,6 @@ ath10k_ce_shadow_src_ring_write_index_set(struct ath10k *ar, ath10k_ce_write32(ar, shadow_sr_wr_ind_addr(ar, ce_state), value); } -#if defined(__linux__) -static inline void -ath10k_ce_shadow_dest_ring_write_index_set(struct ath10k *ar, - struct ath10k_ce_pipe *ce_state, - unsigned int value) -{ - ath10k_ce_write32(ar, shadow_dst_wr_ind_addr(ar, ce_state), value); -} -#endif - static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar, u32 ce_id, u64 addr) @@ -452,21 +392,6 @@ static inline void ath10k_ce_watermark_intr_disable(struct ath10k *ar, host_ie_addr & ~(wm_regs->wm_mask)); } -#if defined(__linux__) -static inline void ath10k_ce_error_intr_enable(struct ath10k *ar, - u32 ce_ctrl_addr) -{ - struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs; - - u32 misc_ie_addr = ath10k_ce_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->misc_ie_addr); - - ath10k_ce_write32(ar, - ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, - misc_ie_addr | misc_regs->err_mask); -} -#endif - static inline void ath10k_ce_error_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { @@ -1331,7 +1256,7 @@ EXPORT_SYMBOL(ath10k_ce_per_engine_service); /* * Handler for per-engine interrupts on ALL active CEs. * This is used in cases where the system is sharing a - * single interrput for all CEs + * single interrupt for all CEs */ void ath10k_ce_per_engine_service_any(struct ath10k *ar) diff --git a/sys/contrib/dev/athk/ath10k/core.c b/sys/contrib/dev/athk/ath10k/core.c index 8784344badf5..0a65d12d202c 100644 --- a/sys/contrib/dev/athk/ath10k/core.c +++ b/sys/contrib/dev/athk/ath10k/core.c @@ -42,9 +42,11 @@ EXPORT_SYMBOL(ath10k_debug_mask); static unsigned int ath10k_cryptmode_param; static bool uart_print; static bool skip_otp; -static bool rawmode; static bool fw_diag_log; +/* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ +unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); @@ -53,15 +55,16 @@ module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644); module_param(uart_print, bool, 0644); module_param(skip_otp, bool, 0644); -module_param(rawmode, bool, 0644); module_param(fw_diag_log, bool, 0644); +module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); MODULE_PARM_DESC(debug_mask, "Debugging mask"); MODULE_PARM_DESC(uart_print, "Uart target debugging"); MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software"); -MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath"); +MODULE_PARM_DESC(frame_mode, + "Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)"); MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); @@ -103,6 +106,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = true, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA988X_HW_2_0_VERSION, @@ -140,6 +146,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = true, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA9887_HW_1_0_VERSION, @@ -178,6 +187,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -211,6 +223,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .bmi_large_size_download = true, .supports_peer_stats_info = true, .dynamic_sar_support = true, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -248,6 +263,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -285,6 +303,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA6174_HW_3_0_VERSION, @@ -322,6 +343,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -363,6 +387,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .tx_stats_over_pktlog = false, .supports_peer_stats_info = true, .dynamic_sar_support = true, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -406,6 +433,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -456,6 +486,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -503,6 +536,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -540,6 +576,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -579,6 +618,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -609,6 +651,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .uart_pin_workaround = true, .credit_size_workaround = true, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -653,6 +698,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, + .hw_restart_disconnect = false, + .use_fw_tx_credits = true, + .delay_unmap_buffer = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -683,6 +731,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = true, + .hw_restart_disconnect = true, + .use_fw_tx_credits = false, + .delay_unmap_buffer = true, }, }; @@ -1242,6 +1293,7 @@ success: static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type) { const struct firmware *fw; + char boardname[100]; if (bd_ie_type == ATH10K_BD_IE_BOARD) { if (!ar->hw_params.fw.board) { @@ -1249,9 +1301,19 @@ static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type) return -EINVAL; } + scnprintf(boardname, sizeof(boardname), "board-%s-%s.bin", + ath10k_bus_str(ar->hif.bus), dev_name(ar->dev)); + ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, - ar->hw_params.fw.board); + boardname); + if (IS_ERR(ar->normal_mode_fw.board)) { + fw = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + ar->hw_params.fw.board); + ar->normal_mode_fw.board = fw; + } + if (IS_ERR(ar->normal_mode_fw.board)) return PTR_ERR(ar->normal_mode_fw.board); @@ -2640,7 +2702,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT; ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT; - if (rawmode) { + if (ath10k_frame_mode == ATH10K_HW_TXRX_RAW) { if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT, fw_file->fw_features)) { ath10k_err(ar, "rawmode = 1 requires support from firmware"); @@ -3125,7 +3187,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, * enabled always. * * We can still enable BTCOEX if firmware has the support - * eventhough btceox_support value is + * even though btceox_support value is * ATH10K_DT_BTCOEX_NOT_FOUND */ @@ -3662,6 +3724,9 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, mutex_init(&ar->dump_mutex); spin_lock_init(&ar->data_lock); + for (int ac = 0; ac < IEEE80211_NUM_ACS; ac++) + spin_lock_init(&ar->queue_lock[ac]); + INIT_LIST_HEAD(&ar->peers); init_waitqueue_head(&ar->peer_mapping_wq); init_waitqueue_head(&ar->htt.empty_tx_wq); diff --git a/sys/contrib/dev/athk/ath10k/core.h b/sys/contrib/dev/athk/ath10k/core.h index 1e4ea8f2dfc2..5cecb305a62c 100644 --- a/sys/contrib/dev/athk/ath10k/core.h +++ b/sys/contrib/dev/athk/ath10k/core.h @@ -64,9 +64,6 @@ #define ATH10K_KEEPALIVE_MAX_IDLE 3895 #define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900 -/* NAPI poll budget */ -#define ATH10K_NAPI_BUDGET 64 - /* SMBIOS type containing Board Data File Name Extension */ #define ATH10K_SMBIOS_BDF_EXT_TYPE 0xF8 @@ -84,7 +81,7 @@ /* The magic used by QCA spec */ #define ATH10K_SMBIOS_BDF_EXT_MAGIC "BDF_" -/* Default Airtime weight multipler (Tuned for multiclient performance) */ +/* Default Airtime weight multiplier (Tuned for multiclient performance) */ #define ATH10K_AIRTIME_WEIGHT_MULTIPLIER 4 #define ATH10K_MAX_RETRY_COUNT 30 @@ -865,7 +862,7 @@ enum ath10k_dev_flags { /* Disable HW crypto engine */ ATH10K_FLAG_HW_CRYPTO_DISABLED, - /* Bluetooth coexistance enabled */ + /* Bluetooth coexistence enabled */ ATH10K_FLAG_BTCOEX, /* Per Station statistics service */ @@ -1181,6 +1178,9 @@ struct ath10k { /* protects shared structure data */ spinlock_t data_lock; + /* serialize wake_tx_queue calls per ac */ + spinlock_t queue_lock[IEEE80211_NUM_ACS]; + struct list_head arvifs; struct list_head peers; struct ath10k_peer *peer_map[ATH10K_MAX_NUM_PEER_IDS]; @@ -1330,6 +1330,7 @@ static inline bool ath10k_peer_stats_enabled(struct ath10k *ar) return false; } +extern unsigned int ath10k_frame_mode; extern unsigned long ath10k_coredump_mask; void ath10k_core_napi_sync_disable(struct ath10k *ar); diff --git a/sys/contrib/dev/athk/ath10k/coredump.c b/sys/contrib/dev/athk/ath10k/coredump.c index fe6b6f97a916..2d1634a890dd 100644 --- a/sys/contrib/dev/athk/ath10k/coredump.c +++ b/sys/contrib/dev/athk/ath10k/coredump.c @@ -531,7 +531,7 @@ static const struct ath10k_mem_section qca6174_hw30_sdio_register_sections[] = { {0x40000, 0x400A4}, - /* SI register is skiped here. + /* SI register is skipped here. * Because it will cause bus hang * * {0x50000, 0x50018}, diff --git a/sys/contrib/dev/athk/ath10k/coredump.h b/sys/contrib/dev/athk/ath10k/coredump.h index 240d70515088..437b9759f05d 100644 --- a/sys/contrib/dev/athk/ath10k/coredump.h +++ b/sys/contrib/dev/athk/ath10k/coredump.h @@ -125,7 +125,7 @@ enum ath10k_mem_region_type { * To minimize the size of the array, the list must obey the format: * '{start0,stop0},{start1,stop1},{start2,stop2}....' The values below must * also obey to 'start0 < stop0 < start1 < stop1 < start2 < ...', otherwise - * we may encouter error in the dump processing. + * we may encounter error in the dump processing. */ struct ath10k_mem_section { u32 start; diff --git a/sys/contrib/dev/athk/ath10k/debug.c b/sys/contrib/dev/athk/ath10k/debug.c index a35a6a4839c2..d0ad271088c8 100644 --- a/sys/contrib/dev/athk/ath10k/debug.c +++ b/sys/contrib/dev/athk/ath10k/debug.c @@ -10,6 +10,7 @@ #include #include #include +#include #if defined(__FreeBSD__) #ifdef CONFIG_ATH10K_DEBUG @@ -333,8 +334,8 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) goto free; } - num_peers = ath10k_wmi_fw_stats_num_peers(&ar->debug.fw_stats.peers); - num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs); + num_peers = list_count_nodes(&ar->debug.fw_stats.peers); + num_vdevs = list_count_nodes(&ar->debug.fw_stats.vdevs); is_start = (list_empty(&ar->debug.fw_stats.pdevs) && !list_empty(&stats.pdevs)); is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && @@ -1122,7 +1123,7 @@ exit: * struct available.. */ -/* This generally cooresponds to the debugfs fw_stats file */ +/* This generally corresponds to the debugfs fw_stats file */ static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = { "tx_pkts_nic", "tx_bytes_nic", @@ -2016,7 +2017,7 @@ static ssize_t ath10k_write_btcoex(struct file *file, buf[buf_size] = '\0'; - if (strtobool(buf, &val) != 0) + if (kstrtobool(buf, &val) != 0) return -EINVAL; if (!ar->coex_support) @@ -2154,7 +2155,7 @@ static ssize_t ath10k_write_peer_stats(struct file *file, buf[buf_size] = '\0'; - if (strtobool(buf, &val) != 0) + if (kstrtobool(buf, &val) != 0) return -EINVAL; mutex_lock(&ar->conf_mutex); diff --git a/sys/contrib/dev/athk/ath10k/debugfs_sta.c b/sys/contrib/dev/athk/ath10k/debugfs_sta.c index 367539f2c370..87a3365330ff 100644 --- a/sys/contrib/dev/athk/ath10k/debugfs_sta.c +++ b/sys/contrib/dev/athk/ath10k/debugfs_sta.c @@ -498,7 +498,7 @@ static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i) { switch (i) { case ATH10K_AMPDU_SUBFRM_NUM_10: - return "upto 10"; + return "up to 10"; case ATH10K_AMPDU_SUBFRM_NUM_20: return "11-20"; case ATH10K_AMPDU_SUBFRM_NUM_30: diff --git a/sys/contrib/dev/athk/ath10k/htc.c b/sys/contrib/dev/athk/ath10k/htc.c index fab398046a3f..ea8d3296c499 100644 --- a/sys/contrib/dev/athk/ath10k/htc.c +++ b/sys/contrib/dev/athk/ath10k/htc.c @@ -7,6 +7,9 @@ #include "core.h" #include "hif.h" #include "debug.h" +#if defined(__FreeBSD__) +#include +#endif /********/ /* Send */ @@ -56,6 +59,15 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %pK\n", __func__, ep->eid, skb); + /* A corner case where the copy completion is reaching to host but still + * copy engine is processing it due to which host unmaps corresponding + * memory and causes SMMU fault, hence as workaround adding delay + * the unmapping memory to avoid SMMU faults. + */ + if (ar->hw_params.delay_unmap_buffer && + ep->ul_pipe_id == 3) + mdelay(2); + hdr = (struct ath10k_htc_hdr *)skb->data; ath10k_htc_restore_tx_skb(ep->htc, skb); @@ -947,13 +959,18 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) return -ECOMM; } - htc->total_transmit_credits = __le16_to_cpu(msg->ready.credit_count); + if (ar->hw_params.use_fw_tx_credits) + htc->total_transmit_credits = __le16_to_cpu(msg->ready.credit_count); + else + htc->total_transmit_credits = 1; + htc->target_credit_size = __le16_to_cpu(msg->ready.credit_size); ath10k_dbg(ar, ATH10K_DBG_HTC, - "Target ready! transmit resources: %d size:%d\n", + "Target ready! transmit resources: %d size:%d actual credits:%d\n", htc->total_transmit_credits, - htc->target_credit_size); + htc->target_credit_size, + msg->ready.credit_count); if ((htc->total_transmit_credits == 0) || (htc->target_credit_size == 0)) { diff --git a/sys/contrib/dev/athk/ath10k/htt.h b/sys/contrib/dev/athk/ath10k/htt.h index 79d0837fc5a7..48e9b816abaf 100644 --- a/sys/contrib/dev/athk/ath10k/htt.h +++ b/sys/contrib/dev/athk/ath10k/htt.h @@ -710,7 +710,7 @@ struct htt_rx_indication_prefix { __le16 fw_rx_desc_bytes; u8 pad0; u8 pad1; -}; +} __packed; struct htt_rx_indication { struct htt_rx_indication_hdr hdr; @@ -1127,8 +1127,10 @@ struct htt_rx_in_ord_ind { u8 reserved; __le16 msdu_count; union { - struct htt_rx_in_ord_msdu_desc msdu_descs32[0]; - struct htt_rx_in_ord_msdu_desc_ext msdu_descs64[0]; + DECLARE_FLEX_ARRAY(struct htt_rx_in_ord_msdu_desc, + msdu_descs32); + DECLARE_FLEX_ARRAY(struct htt_rx_in_ord_msdu_desc_ext, + msdu_descs64); } __packed; } __packed; @@ -1582,7 +1584,7 @@ struct htt_tx_fetch_ind { /* ath10k_htt_get_tx_fetch_ind_resp_ids() */ DECLARE_FLEX_ARRAY(__le32, resp_ids); DECLARE_FLEX_ARRAY(struct htt_tx_fetch_record, records); - }; + } __packed; } __packed; static inline void * @@ -1740,7 +1742,7 @@ struct htt_resp { struct htt_tx_mode_switch_ind tx_mode_switch_ind; struct htt_channel_change chan_change; struct htt_peer_tx_stats peer_tx_stats; - }; + } __packed; } __packed; /*** host side structures follow ***/ diff --git a/sys/contrib/dev/athk/ath10k/htt_rx.c b/sys/contrib/dev/athk/ath10k/htt_rx.c index f3c5ad8fde92..e1bbbaf70e94 100644 --- a/sys/contrib/dev/athk/ath10k/htt_rx.c +++ b/sys/contrib/dev/athk/ath10k/htt_rx.c @@ -301,12 +301,16 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt) ath10k_htt_get_vaddr_ring(htt), htt->rx_ring.base_paddr); + ath10k_htt_config_paddrs_ring(htt, NULL); + 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); + htt->rx_ring.alloc_idx.vaddr = NULL; kfree(htt->rx_ring.netbufs_ring); + htt->rx_ring.netbufs_ring = NULL; } static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) @@ -429,7 +433,11 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, RX_MSDU_END_INFO0_LAST_MSDU; /* FIXME: why are we skipping the first part of the rx_desc? */ - trace_ath10k_htt_rx_desc(ar, rx_desc + sizeof(u32), +#if defined(__linux__) + trace_ath10k_htt_rx_desc(ar, (void *)rx_desc + sizeof(u32), +#elif defined(__FreeBSD__) + trace_ath10k_htt_rx_desc(ar, (u8 *)rx_desc + sizeof(u32), +#endif hw->rx_desc_ops->rx_desc_size - sizeof(u32)); if (last_msdu) @@ -858,8 +866,10 @@ err_dma_idx: ath10k_htt_get_rx_ring_size(htt), vaddr_ring, htt->rx_ring.base_paddr); + ath10k_htt_config_paddrs_ring(htt, NULL); err_dma_ring: kfree(htt->rx_ring.netbufs_ring); + htt->rx_ring.netbufs_ring = NULL; err_netbuf: return -ENOMEM; } @@ -1389,7 +1399,7 @@ static void ath10k_process_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_get_tid(hdr, tid, sizeof(tid)), is_multicast_ether_addr(ieee80211_get_DA(hdr)) ? "mcast" : "ucast", - (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4, + IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl)), (status->encoding == RX_ENC_LEGACY) ? "legacy" : "", (status->encoding == RX_ENC_HT) ? "ht" : "", (status->encoding == RX_ENC_VHT) ? "vht" : "", @@ -1960,15 +1970,14 @@ static void ath10k_htt_rx_h_csum_offload(struct ath10k_hw_params *hw, } static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb, - u16 offset, enum htt_rx_mpdu_encrypt_type enctype) { struct ieee80211_hdr *hdr; u64 pn = 0; u8 *ehdr; - hdr = (struct ieee80211_hdr *)(skb->data + offset); - ehdr = skb->data + offset + ieee80211_hdrlen(hdr->frame_control); + hdr = (struct ieee80211_hdr *)skb->data; + ehdr = skb->data + ieee80211_hdrlen(hdr->frame_control); if (enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) { pn = ehdr[0]; @@ -1982,19 +1991,17 @@ static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb, } static bool ath10k_htt_rx_h_frag_multicast_check(struct ath10k *ar, - struct sk_buff *skb, - u16 offset) + struct sk_buff *skb) { struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr *)(skb->data + offset); + hdr = (struct ieee80211_hdr *)skb->data; return !is_multicast_ether_addr(hdr->addr1); } static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar, struct sk_buff *skb, u16 peer_id, - u16 offset, enum htt_rx_mpdu_encrypt_type enctype) { struct ath10k_peer *peer; @@ -2009,16 +2016,16 @@ static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar, return false; } - hdr = (struct ieee80211_hdr *)(skb->data + offset); + hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_data_qos(hdr->frame_control)) tid = ieee80211_get_tid(hdr); else tid = ATH10K_TXRX_NON_QOS_TID; last_pn = &peer->frag_tids_last_pn[tid]; - new_pn.pn48 = ath10k_htt_rx_h_get_pn(ar, skb, offset, enctype); + new_pn.pn48 = ath10k_htt_rx_h_get_pn(ar, skb, enctype); frag_number = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; - seq = (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + seq = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl)); if (frag_number == 0) { last_pn->pn48 = new_pn.pn48; @@ -2183,13 +2190,11 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, frag_pn_check = ath10k_htt_rx_h_frag_pn_check(ar, msdu, peer_id, - 0, enctype); if (frag) multicast_check = ath10k_htt_rx_h_frag_multicast_check(ar, - msdu, - 0); + msdu); if (!frag_pn_check || !multicast_check) { /* Discard the fragment with invalid PN or multicast DA @@ -2634,7 +2639,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, /* I have not yet seen any case where num_mpdu_ranges > 1. * qcacld does not seem handle that case either, so we introduce the - * same limitiation here as well. + * same limitation here as well. */ if (num_mpdu_ranges > 1) ath10k_warn(ar, @@ -2956,7 +2961,7 @@ static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt, hdr_space = ieee80211_hdrlen(hdr->frame_control); sc = __le16_to_cpu(hdr->seq_ctrl); - seq = (sc & IEEE80211_SCTL_SEQ) >> 4; + seq = IEEE80211_SEQ_TO_SN(sc); frag = sc & IEEE80211_SCTL_FRAG; sec_index = MS(rx_desc_info, HTT_RX_DESC_HL_INFO_MCAST_BCAST) ? @@ -3709,7 +3714,7 @@ static void ath10k_htt_rx_tx_mode_switch_ind(struct ath10k *ar, threshold = MS(info1, HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD); ath10k_dbg(ar, ATH10K_DBG_HTT, - "htt rx tx mode switch ind info0 0x%04hx info1 0x%04x enable %d num records %zd mode %d threshold %u\n", + "htt rx tx mode switch ind info0 0x%04x info1 0x%04x enable %d num records %zd mode %d threshold %u\n", info0, info1, enable, num_records, mode, threshold); len += sizeof(resp->tx_mode_switch_ind.records[0]) * num_records; @@ -3986,7 +3991,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, switch (txrate.flags) { case WMI_RATE_PREAMBLE_OFDM: if (arsta->arvif && arsta->arvif->vif) - conf = rcu_dereference(arsta->arvif->vif->chanctx_conf); + conf = rcu_dereference(arsta->arvif->vif->bss_conf.chanctx_conf); if (conf && conf->def.chan->band == NL80211_BAND_5GHZ) arsta->tx_info.status.rates[0].idx = rate_idx - 4; break; @@ -4030,6 +4035,10 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, arsta->tx_info.status.rates[0].flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; break; + case RATE_INFO_BW_160: + arsta->tx_info.status.rates[0].flags |= + IEEE80211_TX_RC_160_MHZ_WIDTH; + break; } if (peer_stats->succ_pkts) { diff --git a/sys/contrib/dev/athk/ath10k/htt_tx.c b/sys/contrib/dev/athk/ath10k/htt_tx.c index 9842a4b2f78f..bd603feb7953 100644 --- a/sys/contrib/dev/athk/ath10k/htt_tx.c +++ b/sys/contrib/dev/athk/ath10k/htt_tx.c @@ -1112,7 +1112,7 @@ int ath10k_htt_tx_fetch_resp(struct ath10k *ar, int len = 0; int ret; - /* Response IDs are echo-ed back only for host driver convienence + /* Response IDs are echo-ed back only for host driver convenience * purposes. They aren't used for anything in the driver yet so use 0. */ @@ -1275,7 +1275,6 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm struct ath10k *ar = htt->ar; int res, data_len; struct htt_cmd_hdr *cmd_hdr; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; struct htt_data_tx_desc *tx_desc; struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); struct sk_buff *tmp_skb; @@ -1286,11 +1285,15 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm u16 flags1 = 0; *** 2501 LINES SKIPPED ***