From 9636951e4468f02c72cc75a82dc65d003077edbc Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sun, 31 Dec 2023 05:03:33 +0000 Subject: wifi: b43: Stop/wake correct queue in DMA Tx path when QoS is disabled When QoS is disabled, the queue priority value will not map to the correct ieee80211 queue since there is only one queue. Stop/wake queue 0 when QoS is disabled to prevent trying to stop/wake a non-existent queue and failing to stop/wake the actual queue instantiated. Log of issue before change (with kernel parameter qos=0): [ +5.112651] ------------[ cut here ]------------ [ +0.000005] WARNING: CPU: 7 PID: 25513 at net/mac80211/util.c:449 __ieee80211_wake_queue+0xd5/0x180 [mac80211] [ +0.000067] Modules linked in: b43(O) snd_seq_dummy snd_hrtimer snd_seq snd_seq_device nft_chain_nat xt_MASQUERADE nf_nat xfrm_user xfrm_algo xt_addrtype overlay ccm af_packet amdgpu snd_hda_codec_cirrus snd_hda_codec_generic ledtrig_audio drm_exec amdxcp gpu_sched xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip6t_rpfilter ipt_rpfilter xt_pkttype xt_LOG nf_log_syslog xt_tcpudp nft_compat nf_tables nfnetlink sch_fq_codel btusb uinput iTCO_wdt ctr btrtl intel_pmc_bxt i915 intel_rapl_msr mei_hdcp mei_pxp joydev at24 watchdog btintel atkbd libps2 serio radeon btbcm vivaldi_fmap btmtk intel_rapl_common snd_hda_codec_hdmi bluetooth uvcvideo nls_iso8859_1 applesmc nls_cp437 x86_pkg_temp_thermal snd_hda_intel intel_powerclamp vfat videobuf2_vmalloc coretemp fat snd_intel_dspcfg crc32_pclmul uvc polyval_clmulni snd_intel_sdw_acpi loop videobuf2_memops snd_hda_codec tun drm_suballoc_helper polyval_generic drm_ttm_helper drm_buddy tap ecdh_generic videobuf2_v4l2 gf128mul macvlan ttm ghash_clmulni_intel ecc tg3 [ +0.000044] videodev bridge snd_hda_core rapl crc16 drm_display_helper cec mousedev snd_hwdep evdev intel_cstate bcm5974 hid_appleir videobuf2_common stp mac_hid libphy snd_pcm drm_kms_helper acpi_als mei_me intel_uncore llc mc snd_timer intel_gtt industrialio_triggered_buffer apple_mfi_fastcharge i2c_i801 mei snd lpc_ich agpgart ptp i2c_smbus thunderbolt apple_gmux i2c_algo_bit kfifo_buf video industrialio soundcore pps_core wmi tiny_power_button sbs sbshc button ac cordic bcma mac80211 cfg80211 ssb rfkill libarc4 kvm_intel kvm drm irqbypass fuse backlight firmware_class efi_pstore configfs efivarfs dmi_sysfs ip_tables x_tables autofs4 dm_crypt cbc encrypted_keys trusted asn1_encoder tee tpm rng_core input_leds hid_apple led_class hid_generic usbhid hid sd_mod t10_pi crc64_rocksoft crc64 crc_t10dif crct10dif_generic ahci libahci libata uhci_hcd ehci_pci ehci_hcd crct10dif_pclmul crct10dif_common sha512_ssse3 sha512_generic sha256_ssse3 sha1_ssse3 aesni_intel usbcore scsi_mod libaes crypto_simd cryptd scsi_common [ +0.000055] usb_common rtc_cmos btrfs blake2b_generic libcrc32c crc32c_generic crc32c_intel xor raid6_pq dm_snapshot dm_bufio dm_mod dax [last unloaded: b43(O)] [ +0.000009] CPU: 7 PID: 25513 Comm: irq/17-b43 Tainted: G W O 6.6.7 #1-NixOS [ +0.000003] Hardware name: Apple Inc. MacBookPro8,3/Mac-942459F5819B171B, BIOS 87.0.0.0.0 06/13/2019 [ +0.000001] RIP: 0010:__ieee80211_wake_queue+0xd5/0x180 [mac80211] [ +0.000046] Code: 00 45 85 e4 0f 85 9b 00 00 00 48 8d bd 40 09 00 00 f0 48 0f ba ad 48 09 00 00 00 72 0f 5b 5d 41 5c 41 5d 41 5e e9 cb 6d 3c d0 <0f> 0b 5b 5d 41 5c 41 5d 41 5e c3 cc cc cc cc 48 8d b4 16 94 00 00 [ +0.000002] RSP: 0018:ffffc90003c77d60 EFLAGS: 00010097 [ +0.000001] RAX: 0000000000000001 RBX: 0000000000000002 RCX: 0000000000000000 [ +0.000001] RDX: 0000000000000000 RSI: 0000000000000002 RDI: ffff88820b924900 [ +0.000002] RBP: ffff88820b924900 R08: ffffc90003c77d90 R09: 000000000003bfd0 [ +0.000001] R10: ffff88820b924900 R11: ffffc90003c77c68 R12: 0000000000000000 [ +0.000001] R13: 0000000000000000 R14: ffffc90003c77d90 R15: ffffffffc0fa6f40 [ +0.000001] FS: 0000000000000000(0000) GS:ffff88846fb80000(0000) knlGS:0000000000000000 [ +0.000001] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ +0.000001] CR2: 00007fafda7ae008 CR3: 000000046d220005 CR4: 00000000000606e0 [ +0.000002] Call Trace: [ +0.000003] [ +0.000001] ? __ieee80211_wake_queue+0xd5/0x180 [mac80211] [ +0.000044] ? __warn+0x81/0x130 [ +0.000005] ? __ieee80211_wake_queue+0xd5/0x180 [mac80211] [ +0.000045] ? report_bug+0x171/0x1a0 [ +0.000004] ? handle_bug+0x41/0x70 [ +0.000004] ? exc_invalid_op+0x17/0x70 [ +0.000003] ? asm_exc_invalid_op+0x1a/0x20 [ +0.000005] ? __ieee80211_wake_queue+0xd5/0x180 [mac80211] [ +0.000043] ieee80211_wake_queue+0x4a/0x80 [mac80211] [ +0.000044] b43_dma_handle_txstatus+0x29c/0x3a0 [b43] [ +0.000016] ? __pfx_irq_thread_fn+0x10/0x10 [ +0.000002] b43_handle_txstatus+0x61/0x80 [b43] [ +0.000012] b43_interrupt_thread_handler+0x3f9/0x6b0 [b43] [ +0.000011] irq_thread_fn+0x23/0x60 [ +0.000002] irq_thread+0xfe/0x1c0 [ +0.000002] ? __pfx_irq_thread_dtor+0x10/0x10 [ +0.000001] ? __pfx_irq_thread+0x10/0x10 [ +0.000001] kthread+0xe8/0x120 [ +0.000003] ? __pfx_kthread+0x10/0x10 [ +0.000003] ret_from_fork+0x34/0x50 [ +0.000002] ? __pfx_kthread+0x10/0x10 [ +0.000002] ret_from_fork_asm+0x1b/0x30 [ +0.000004] [ +0.000001] ---[ end trace 0000000000000000 ]--- [ +0.000065] ------------[ cut here ]------------ [ +0.000001] WARNING: CPU: 0 PID: 56077 at net/mac80211/util.c:514 __ieee80211_stop_queue+0xcc/0xe0 [mac80211] [ +0.000077] Modules linked in: b43(O) snd_seq_dummy snd_hrtimer snd_seq snd_seq_device nft_chain_nat xt_MASQUERADE nf_nat xfrm_user xfrm_algo xt_addrtype overlay ccm af_packet amdgpu snd_hda_codec_cirrus snd_hda_codec_generic ledtrig_audio drm_exec amdxcp gpu_sched xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip6t_rpfilter ipt_rpfilter xt_pkttype xt_LOG nf_log_syslog xt_tcpudp nft_compat nf_tables nfnetlink sch_fq_codel btusb uinput iTCO_wdt ctr btrtl intel_pmc_bxt i915 intel_rapl_msr mei_hdcp mei_pxp joydev at24 watchdog btintel atkbd libps2 serio radeon btbcm vivaldi_fmap btmtk intel_rapl_common snd_hda_codec_hdmi bluetooth uvcvideo nls_iso8859_1 applesmc nls_cp437 x86_pkg_temp_thermal snd_hda_intel intel_powerclamp vfat videobuf2_vmalloc coretemp fat snd_intel_dspcfg crc32_pclmul uvc polyval_clmulni snd_intel_sdw_acpi loop videobuf2_memops snd_hda_codec tun drm_suballoc_helper polyval_generic drm_ttm_helper drm_buddy tap ecdh_generic videobuf2_v4l2 gf128mul macvlan ttm ghash_clmulni_intel ecc tg3 [ +0.000073] videodev bridge snd_hda_core rapl crc16 drm_display_helper cec mousedev snd_hwdep evdev intel_cstate bcm5974 hid_appleir videobuf2_common stp mac_hid libphy snd_pcm drm_kms_helper acpi_als mei_me intel_uncore llc mc snd_timer intel_gtt industrialio_triggered_buffer apple_mfi_fastcharge i2c_i801 mei snd lpc_ich agpgart ptp i2c_smbus thunderbolt apple_gmux i2c_algo_bit kfifo_buf video industrialio soundcore pps_core wmi tiny_power_button sbs sbshc button ac cordic bcma mac80211 cfg80211 ssb rfkill libarc4 kvm_intel kvm drm irqbypass fuse backlight firmware_class efi_pstore configfs efivarfs dmi_sysfs ip_tables x_tables autofs4 dm_crypt cbc encrypted_keys trusted asn1_encoder tee tpm rng_core input_leds hid_apple led_class hid_generic usbhid hid sd_mod t10_pi crc64_rocksoft crc64 crc_t10dif crct10dif_generic ahci libahci libata uhci_hcd ehci_pci ehci_hcd crct10dif_pclmul crct10dif_common sha512_ssse3 sha512_generic sha256_ssse3 sha1_ssse3 aesni_intel usbcore scsi_mod libaes crypto_simd cryptd scsi_common [ +0.000084] usb_common rtc_cmos btrfs blake2b_generic libcrc32c crc32c_generic crc32c_intel xor raid6_pq dm_snapshot dm_bufio dm_mod dax [last unloaded: b43] [ +0.000012] CPU: 0 PID: 56077 Comm: kworker/u16:17 Tainted: G W O 6.6.7 #1-NixOS [ +0.000003] Hardware name: Apple Inc. MacBookPro8,3/Mac-942459F5819B171B, BIOS 87.0.0.0.0 06/13/2019 [ +0.000001] Workqueue: phy7 b43_tx_work [b43] [ +0.000019] RIP: 0010:__ieee80211_stop_queue+0xcc/0xe0 [mac80211] [ +0.000076] Code: 74 11 48 8b 78 08 0f b7 d6 89 e9 4c 89 e6 e8 ab f4 00 00 65 ff 0d 9c b7 34 3f 0f 85 55 ff ff ff 0f 1f 44 00 00 e9 4b ff ff ff <0f> 0b 5b 5d 41 5c 41 5d c3 cc cc cc cc 0f 1f 80 00 00 00 00 90 90 [ +0.000002] RSP: 0000:ffffc90004157d50 EFLAGS: 00010097 [ +0.000002] RAX: 0000000000000001 RBX: 0000000000000002 RCX: 0000000000000000 [ +0.000002] RDX: 0000000000000000 RSI: 0000000000000002 RDI: ffff8882d65d0900 [ +0.000002] RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000001 [ +0.000001] R10: 00000000000000ff R11: ffff88814d0155a0 R12: ffff8882d65d0900 [ +0.000002] R13: 0000000000000000 R14: ffff8881002d2800 R15: 00000000000000d0 [ +0.000002] FS: 0000000000000000(0000) GS:ffff88846f800000(0000) knlGS:0000000000000000 [ +0.000003] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ +0.000002] CR2: 00007f2e8c10c880 CR3: 0000000385b66005 CR4: 00000000000606f0 [ +0.000002] Call Trace: [ +0.000001] [ +0.000001] ? __ieee80211_stop_queue+0xcc/0xe0 [mac80211] [ +0.000075] ? __warn+0x81/0x130 [ +0.000004] ? __ieee80211_stop_queue+0xcc/0xe0 [mac80211] [ +0.000075] ? report_bug+0x171/0x1a0 [ +0.000005] ? handle_bug+0x41/0x70 [ +0.000003] ? exc_invalid_op+0x17/0x70 [ +0.000004] ? asm_exc_invalid_op+0x1a/0x20 [ +0.000004] ? __ieee80211_stop_queue+0xcc/0xe0 [mac80211] [ +0.000076] ieee80211_stop_queue+0x36/0x50 [mac80211] [ +0.000077] b43_dma_tx+0x550/0x780 [b43] [ +0.000023] b43_tx_work+0x90/0x130 [b43] [ +0.000018] process_one_work+0x174/0x340 [ +0.000003] worker_thread+0x27b/0x3a0 [ +0.000004] ? __pfx_worker_thread+0x10/0x10 [ +0.000002] kthread+0xe8/0x120 [ +0.000003] ? __pfx_kthread+0x10/0x10 [ +0.000004] ret_from_fork+0x34/0x50 [ +0.000002] ? __pfx_kthread+0x10/0x10 [ +0.000003] ret_from_fork_asm+0x1b/0x30 [ +0.000006] [ +0.000001] ---[ end trace 0000000000000000 ]--- Fixes: e6f5b934fba8 ("b43: Add QOS support") Signed-off-by: Rahul Rameshbabu Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo Link: https://msgid.link/20231231050300.122806-2-sergeantsagara@protonmail.com --- drivers/net/wireless/broadcom/b43/b43.h | 16 ++++++++++++++++ drivers/net/wireless/broadcom/b43/dma.c | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/b43/b43.h b/drivers/net/wireless/broadcom/b43/b43.h index 67b4bac048e5..c0d8fc0b22fb 100644 --- a/drivers/net/wireless/broadcom/b43/b43.h +++ b/drivers/net/wireless/broadcom/b43/b43.h @@ -1082,6 +1082,22 @@ static inline bool b43_using_pio_transfers(struct b43_wldev *dev) return dev->__using_pio_transfers; } +static inline void b43_wake_queue(struct b43_wldev *dev, int queue_prio) +{ + if (dev->qos_enabled) + ieee80211_wake_queue(dev->wl->hw, queue_prio); + else + ieee80211_wake_queue(dev->wl->hw, 0); +} + +static inline void b43_stop_queue(struct b43_wldev *dev, int queue_prio) +{ + if (dev->qos_enabled) + ieee80211_stop_queue(dev->wl->hw, queue_prio); + else + ieee80211_stop_queue(dev->wl->hw, 0); +} + /* Message printing */ __printf(2, 3) void b43info(struct b43_wl *wl, const char *fmt, ...); __printf(2, 3) void b43err(struct b43_wl *wl, const char *fmt, ...); diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c index 760d1a28edc6..6ac7dcebfff9 100644 --- a/drivers/net/wireless/broadcom/b43/dma.c +++ b/drivers/net/wireless/broadcom/b43/dma.c @@ -1399,7 +1399,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) should_inject_overflow(ring)) { /* This TX ring is full. */ unsigned int skb_mapping = skb_get_queue_mapping(skb); - ieee80211_stop_queue(dev->wl->hw, skb_mapping); + b43_stop_queue(dev, skb_mapping); dev->wl->tx_queue_stopped[skb_mapping] = true; ring->stopped = true; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { @@ -1570,7 +1570,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, } else { /* If the driver queue is running wake the corresponding * mac80211 queue. */ - ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); + b43_wake_queue(dev, ring->queue_prio); if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); } -- cgit v1.2.3 From 77135a38f6c2f950d2306ac3d37cbb407e6243f2 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sun, 31 Dec 2023 05:03:45 +0000 Subject: wifi: b43: Stop/wake correct queue in PIO Tx path when QoS is disabled When QoS is disabled, the queue priority value will not map to the correct ieee80211 queue since there is only one queue. Stop/wake queue 0 when QoS is disabled to prevent trying to stop/wake a non-existent queue and failing to stop/wake the actual queue instantiated. Fixes: 5100d5ac81b9 ("b43: Add PIO support for PCMCIA devices") Signed-off-by: Rahul Rameshbabu Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo Link: https://msgid.link/20231231050300.122806-3-sergeantsagara@protonmail.com --- drivers/net/wireless/broadcom/b43/pio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/b43/pio.c b/drivers/net/wireless/broadcom/b43/pio.c index 0cf70fdb60a6..e41f2f5b4c26 100644 --- a/drivers/net/wireless/broadcom/b43/pio.c +++ b/drivers/net/wireless/broadcom/b43/pio.c @@ -525,7 +525,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); + b43_stop_queue(dev, skb_get_queue_mapping(skb)); q->stopped = true; goto out; } @@ -552,7 +552,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); + b43_stop_queue(dev, skb_get_queue_mapping(skb)); q->stopped = true; } @@ -587,7 +587,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, list_add(&pack->list, &q->packets_list); if (q->stopped) { - ieee80211_wake_queue(dev->wl->hw, q->queue_prio); + b43_wake_queue(dev, q->queue_prio); q->stopped = false; } } -- cgit v1.2.3 From 581c8967d66c4961076dbbee356834e9c6777184 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sun, 31 Dec 2023 05:03:51 +0000 Subject: wifi: b43: Stop correct queue in DMA worker when QoS is disabled When QoS is disabled, the queue priority value will not map to the correct ieee80211 queue since there is only one queue. Stop queue 0 when QoS is disabled to prevent trying to stop a non-existent queue and failing to stop the actual queue instantiated. Fixes: bad691946966 ("b43: avoid packet losses in the dma worker code.") Signed-off-by: Rahul Rameshbabu Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo Link: https://msgid.link/20231231050300.122806-4-sergeantsagara@protonmail.com --- drivers/net/wireless/broadcom/b43/main.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 92ca0b2ca286..97d8bdeaa06c 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -3603,7 +3603,7 @@ static void b43_tx_work(struct work_struct *work) err = b43_dma_tx(dev, skb); if (err == -ENOSPC) { wl->tx_queue_stopped[queue_num] = true; - ieee80211_stop_queue(wl->hw, queue_num); + b43_stop_queue(dev, queue_num); skb_queue_head(&wl->tx_queue[queue_num], skb); break; } @@ -3627,6 +3627,7 @@ static void b43_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct b43_wl *wl = hw_to_b43_wl(hw); + u16 skb_queue_mapping; if (unlikely(skb->len < 2 + 2 + 6)) { /* Too short, this can't be a valid frame. */ @@ -3635,12 +3636,12 @@ static void b43_op_tx(struct ieee80211_hw *hw, } B43_WARN_ON(skb_shinfo(skb)->nr_frags); - skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb); - if (!wl->tx_queue_stopped[skb->queue_mapping]) { + skb_queue_mapping = skb_get_queue_mapping(skb); + skb_queue_tail(&wl->tx_queue[skb_queue_mapping], skb); + if (!wl->tx_queue_stopped[skb_queue_mapping]) ieee80211_queue_work(wl->hw, &wl->tx_work); - } else { - ieee80211_stop_queue(wl->hw, skb->queue_mapping); - } + else + b43_stop_queue(wl->current_dev, skb_queue_mapping); } static void b43_qos_params_upload(struct b43_wldev *dev, -- cgit v1.2.3 From 09795bded2e725443fe4a4803cae2079cdaf7b26 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sun, 31 Dec 2023 05:03:58 +0000 Subject: wifi: b43: Disable QoS for bcm4331 bcm4331 seems to not function correctly with QoS support. This may be due to issues with currently available firmware or potentially a device specific issue. When queues that are not of the default "best effort" priority are selected, traffic appears to not transmit out of the hardware while no errors are returned. This behavior is present among all the other priority queues: video, voice, and background. While this can be worked around by setting a kernel parameter, the default behavior is problematic for most users and may be difficult to debug. This patch offers a working out-of-box experience for bcm4331 users. Log of the issue (using ssh low-priority traffic as an example): ssh -T -vvvv git@github.com OpenSSH_9.6p1, OpenSSL 3.0.12 24 Oct 2023 debug1: Reading configuration data /etc/ssh/ssh_config debug2: checking match for 'host * exec "/nix/store/q1c2flcykgr4wwg5a6h450hxbk4ch589-bash-5.2-p15/bin/bash -c '/nix/store/c015armnkhr6v18za0rypm7sh1i8js8w-gnupg-2.4.1/bin/gpg-connect-agent --quiet updatestartuptty /bye >/dev/null 2>&1'"' host github.com originally github.com debug3: /etc/ssh/ssh_config line 5: matched 'host "github.com"' debug1: Executing command: '/nix/store/q1c2flcykgr4wwg5a6h450hxbk4ch589-bash-5.2-p15/bin/bash -c '/nix/store/c015armnkhr6v18za0rypm7sh1i8js8w-gnupg-2.4.1/bin/gpg-connect-agent --quiet updatestartuptty /bye >/dev/null 2>&1'' debug3: command returned status 0 debug3: /etc/ssh/ssh_config line 5: matched 'exec "/nix/store/q1c2flcykgr4wwg5a6h450hxbk4ch589-bash-5.2-p15/bin/bash -c '/nix/store/c015armnkhr6v18za0r"' debug2: match found debug1: /etc/ssh/ssh_config line 9: Applying options for * debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts' -> '/home/binary-eater/.ssh/known_hosts' debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts2' -> '/home/binary-eater/.ssh/known_hosts2' debug2: resolving "github.com" port 22 debug3: resolve_host: lookup github.com:22 debug3: channel_clear_timeouts: clearing debug3: ssh_connect_direct: entering debug1: Connecting to github.com [192.30.255.113] port 22. debug3: set_sock_tos: set socket 3 IP_TOS 0x48 Fixes: e6f5b934fba8 ("b43: Add QOS support") Signed-off-by: Rahul Rameshbabu Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo Link: https://msgid.link/20231231050300.122806-5-sergeantsagara@protonmail.com --- drivers/net/wireless/broadcom/b43/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 97d8bdeaa06c..effb6c23f825 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -2587,7 +2587,8 @@ static void b43_request_firmware(struct work_struct *work) start_ieee80211: wl->hw->queues = B43_QOS_QUEUE_NUM; - if (!modparam_qos || dev->fw.opensource) + if (!modparam_qos || dev->fw.opensource || + dev->dev->chip_id == BCMA_CHIP_ID_BCM4331) wl->hw->queues = 1; err = ieee80211_register_hw(wl->hw); -- cgit v1.2.3 From 47f0e32ffe4ecfa038eadffad7f15831d0d843fb Mon Sep 17 00:00:00 2001 From: Artem Chernyshev Date: Mon, 14 Aug 2023 12:36:21 +0300 Subject: wifi: brcmsmac: phy: Remove unreachable code wlc_phy_txpwr_srom_read_nphy() in wlc_phy_attach_nphy() can not return false, so it's impossible to get true value in this if-statement. Also change those functions return types to void since no one using it. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Artem Chernyshev Reviewed-by: Jonas Gorski Signed-off-by: Kalle Valo Link: https://msgid.link/20230814093621.289754-1-artem.chernyshev@red-soft.ru --- .../net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c | 3 +-- .../net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h | 2 +- drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c | 11 +++-------- 3 files changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c index ccc621b8ed9f..07f83ff5a54a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c @@ -551,8 +551,7 @@ wlc_phy_attach(struct shared_phy *sh, struct bcma_device *d11core, if (!pi->phycal_timer) goto err; - if (!wlc_phy_attach_nphy(pi)) - goto err; + wlc_phy_attach_nphy(pi); } else if (ISLCNPHY(pi)) { if (!wlc_phy_attach_lcnphy(pi)) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h index 8668fa5558a2..70a9ec050717 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h @@ -941,7 +941,7 @@ void wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag); void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi); void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi); -bool wlc_phy_attach_nphy(struct brcms_phy *pi); +void wlc_phy_attach_nphy(struct brcms_phy *pi); bool wlc_phy_attach_lcnphy(struct brcms_phy *pi); void wlc_phy_detach_lcnphy(struct brcms_phy *pi); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index 8580a2754789..cd9b502a6a9f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -14546,7 +14546,7 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi) wlc_phy_txpwr_apply_nphy(pi); } -static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) +static void wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) { struct ssb_sprom *sprom = &pi->d11core->bus->sprom; @@ -14595,11 +14595,9 @@ static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) pi->phycal_tempdelta = 0; wlc_phy_txpwr_srom_read_ppr_nphy(pi); - - return true; } -bool wlc_phy_attach_nphy(struct brcms_phy *pi) +void wlc_phy_attach_nphy(struct brcms_phy *pi) { uint i; @@ -14645,10 +14643,7 @@ bool wlc_phy_attach_nphy(struct brcms_phy *pi) pi->pi_fptr.chanset = wlc_phy_chanspec_set_nphy; pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_nphy; - if (!wlc_phy_txpwr_srom_read_nphy(pi)) - return false; - - return true; + wlc_phy_txpwr_srom_read_nphy(pi); } static s32 get_rf_pwr_offset(struct brcms_phy *pi, s16 pga_gn, s16 pad_gn) -- cgit v1.2.3 From 0f7352557a35ab7888bc7831411ec8a3cbe20d78 Mon Sep 17 00:00:00 2001 From: Zheng Wang Date: Sun, 7 Jan 2024 08:25:04 +0100 Subject: wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach This is the candidate patch of CVE-2023-47233 : https://nvd.nist.gov/vuln/detail/CVE-2023-47233 In brcm80211 driver,it starts with the following invoking chain to start init a timeout worker: ->brcmf_usb_probe ->brcmf_usb_probe_cb ->brcmf_attach ->brcmf_bus_started ->brcmf_cfg80211_attach ->wl_init_priv ->brcmf_init_escan ->INIT_WORK(&cfg->escan_timeout_work, brcmf_cfg80211_escan_timeout_worker); If we disconnect the USB by hotplug, it will call brcmf_usb_disconnect to make cleanup. The invoking chain is : brcmf_usb_disconnect ->brcmf_usb_disconnect_cb ->brcmf_detach ->brcmf_cfg80211_detach ->kfree(cfg); While the timeout woker may still be running. This will cause a use-after-free bug on cfg in brcmf_cfg80211_escan_timeout_worker. Fix it by deleting the timer and canceling the worker in brcmf_cfg80211_detach. Fixes: e756af5b30b0 ("brcmfmac: add e-scan support.") Signed-off-by: Zheng Wang Cc: stable@vger.kernel.org [arend.vanspriel@broadcom.com: keep timer delete as is and cancel work just before free] Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240107072504.392713-1-arend.vanspriel@broadcom.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 133c5ea6429c..52df03243c9f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1179,8 +1179,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, scan_request = cfg->scan_request; cfg->scan_request = NULL; - if (timer_pending(&cfg->escan_timeout)) - del_timer_sync(&cfg->escan_timeout); + timer_delete_sync(&cfg->escan_timeout); if (fw_abort) { /* Do a scan abort to stop the driver's scan engine */ @@ -8435,6 +8434,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) brcmf_btcoex_detach(cfg); wiphy_unregister(cfg->wiphy); wl_deinit_priv(cfg); + cancel_work_sync(&cfg->escan_timeout_work); brcmf_free_wiphy(cfg->wiphy); kfree(cfg); } -- cgit v1.2.3 From 31343230abb1683e8afb254e6b13a7a7fd01fcac Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 3 Jan 2024 10:57:01 +0100 Subject: wifi: brcmfmac: export firmware interface functions With multi-vendor support the vendor-specific module may need to use the firmware interface functions so export them using the macro BRCMF_EXPORT_SYMBOL_GPL() which exports them to driver namespace. Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240103095704.135651-2-arend.vanspriel@broadcom.com --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 4 +- .../wireless/broadcom/brcm80211/brcmfmac/core.c | 2 +- .../wireless/broadcom/brcm80211/brcmfmac/feature.c | 2 +- .../wireless/broadcom/brcm80211/brcmfmac/fwil.c | 115 ++----------------- .../wireless/broadcom/brcm80211/brcmfmac/fwil.h | 127 ++++++++++++++++++--- 5 files changed, 121 insertions(+), 129 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 52df03243c9f..21096cff0c72 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3080,7 +3080,7 @@ brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp, struct brcmf_scb_val_le scbval; struct brcmf_pktcnt_le pktcnt; s32 err; - u32 rate; + u32 rate = 0; u32 rssi; /* Get the current tx rate */ @@ -7268,7 +7268,7 @@ static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg) u32 nmode = 0; u32 vhtmode = 0; u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT }; - u32 rxchain; + u32 rxchain = 0; u32 nchain; int err; s32 i; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index f599d5f896e8..a92f78026cfd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -691,7 +691,7 @@ static int brcmf_net_mon_open(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; - u32 monitor; + u32 monitor = 0; int err; brcmf_dbg(TRACE, "Enter\n"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 6d10c9efbe93..7348f73680d6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -183,7 +183,7 @@ static void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv) static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, enum brcmf_feat_id id, char *name) { - u32 data; + u32 data = 0; int err; /* we need to know firmware error */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c index 72fe8bce6eaf..2aec7d2abd52 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c @@ -142,6 +142,7 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_cmd_data_set); s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) @@ -160,36 +161,7 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) return err; } - - -s32 -brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) -{ - s32 err; - __le32 data_le = cpu_to_le32(data); - - mutex_lock(&ifp->drvr->proto_block); - brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data); - err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); - mutex_unlock(&ifp->drvr->proto_block); - - return err; -} - -s32 -brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) -{ - s32 err; - __le32 data_le = cpu_to_le32(*data); - - mutex_lock(&ifp->drvr->proto_block); - err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); - mutex_unlock(&ifp->drvr->proto_block); - *data = le32_to_cpu(data_le); - brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data); - - return err; -} +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_cmd_data_get); static u32 brcmf_create_iovar(const char *name, const char *data, u32 datalen, @@ -270,26 +242,7 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data, mutex_unlock(&drvr->proto_block); return err; } - -s32 -brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data) -{ - __le32 data_le = cpu_to_le32(data); - - return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le)); -} - -s32 -brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data) -{ - __le32 data_le = cpu_to_le32(*data); - s32 err; - - err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le)); - if (err == 0) - *data = le32_to_cpu(data_le); - return err; -} +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_iovar_data_get); static u32 brcmf_create_bsscfg(s32 bsscfgidx, const char *name, char *data, u32 datalen, @@ -364,6 +317,7 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name, mutex_unlock(&drvr->proto_block); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_bsscfg_data_set); s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, @@ -394,28 +348,7 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, mutex_unlock(&drvr->proto_block); return err; } - -s32 -brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data) -{ - __le32 data_le = cpu_to_le32(data); - - return brcmf_fil_bsscfg_data_set(ifp, name, &data_le, - sizeof(data_le)); -} - -s32 -brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data) -{ - __le32 data_le = cpu_to_le32(*data); - s32 err; - - err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le, - sizeof(data_le)); - if (err == 0) - *data = le32_to_cpu(data_le); - return err; -} +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_bsscfg_data_get); static u32 brcmf_create_xtlv(const char *name, u16 id, char *data, u32 len, char *buf, u32 buflen) @@ -465,6 +398,7 @@ s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id, mutex_unlock(&drvr->proto_block); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_xtlv_data_set); s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id, void *data, u32 len) @@ -494,39 +428,4 @@ s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id, mutex_unlock(&drvr->proto_block); return err; } - -s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, u32 data) -{ - __le32 data_le = cpu_to_le32(data); - - return brcmf_fil_xtlv_data_set(ifp, name, id, &data_le, - sizeof(data_le)); -} - -s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, u32 *data) -{ - __le32 data_le = cpu_to_le32(*data); - s32 err; - - err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); - if (err == 0) - *data = le32_to_cpu(data_le); - return err; -} - -s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, u8 *data) -{ - return brcmf_fil_xtlv_data_get(ifp, name, id, data, sizeof(*data)); -} - -s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, u16 *data) -{ - __le16 data_le = cpu_to_le16(*data); - s32 err; - - err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); - if (err == 0) - *data = le16_to_cpu(data_le); - return err; -} - +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_xtlv_data_get); \ No newline at end of file diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h index bc693157c4b1..a315a7fac6a0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h @@ -81,29 +81,122 @@ s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); -s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data); -s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data); +static inline +s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) +{ + s32 err; + __le32 data_le = cpu_to_le32(data); -s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *data, - u32 len); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data); + err = brcmf_fil_cmd_data_set(ifp, cmd, &data_le, sizeof(data_le)); + + return err; +} +static inline +s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) +{ + s32 err; + __le32 data_le = cpu_to_le32(*data); + + err = brcmf_fil_cmd_data_get(ifp, cmd, &data_le, sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data); + + return err; +} + +s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, + const void *data, u32 len); s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data, u32 len); -s32 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data); -s32 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data); - -s32 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name, void *data, - u32 len); -s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, void *data, - u32 len); -s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data); -s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data); +static inline +s32 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data) +{ + __le32 data_le = cpu_to_le32(data); + + return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le)); +} +static inline +s32 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data) +{ + __le32 data_le = cpu_to_le32(*data); + s32 err; + + err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + return err; +} + + +s32 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name, + void *data, u32 len); +s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, + void *data, u32 len); +static inline +s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data) +{ + __le32 data_le = cpu_to_le32(data); + + return brcmf_fil_bsscfg_data_set(ifp, name, &data_le, + sizeof(data_le)); +} +static inline +s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data) +{ + __le32 data_le = cpu_to_le32(*data); + s32 err; + + err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le, + sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + return err; +} + s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id, void *data, u32 len); s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id, void *data, u32 len); -s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, u32 data); -s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, u32 *data); -s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, u8 *data); -s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, u16 *data); +static inline +s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, + u32 data) +{ + __le32 data_le = cpu_to_le32(data); + + return brcmf_fil_xtlv_data_set(ifp, name, id, &data_le, + sizeof(data_le)); +} +static inline +s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, + u32 *data) +{ + __le32 data_le = cpu_to_le32(*data); + s32 err; + + err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + return err; +} +static inline +s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, + u8 *data) +{ + return brcmf_fil_xtlv_data_get(ifp, name, id, data, sizeof(*data)); +} +static inline +s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, + u16 *data) +{ + __le16 data_le = cpu_to_le16(*data); + s32 err; + + err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); + if (err == 0) + *data = le16_to_cpu(data_le); + return err; +} #endif /* _fwil_h_ */ -- cgit v1.2.3 From 14e1391b71027948cdbacdbea4bf8858c2068eb7 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 3 Jan 2024 10:57:02 +0100 Subject: wifi: brcmfmac: add per-vendor feature detection callback Adding a .feat_attach() callback allowing per-vendor overrides of the driver feature flags. In this patch the callback is only provided by BCA vendor to disable SAE feature as it has not been confirmed yet. BCA chips generally do not have the in-driver supplicant (idsup) feature so they rely on NL80211_CMD_EXTERNAL_AUTH to trigger user-space authentication. Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240103095704.135651-3-arend.vanspriel@broadcom.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c | 8 ++++++++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c | 3 +++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h | 12 ++++++++++++ 3 files changed, 23 insertions(+) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c index ac3a36fa3640..a5d9ac5e6763 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "vops.h" @@ -21,7 +22,14 @@ static void brcmf_bca_detach(struct brcmf_pub *drvr) pr_err("%s: executing\n", __func__); } +static void brcmf_bca_feat_attach(struct brcmf_if *ifp) +{ + /* SAE support not confirmed so disabling for now */ + ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_SAE); +} + const struct brcmf_fwvid_ops brcmf_bca_ops = { .attach = brcmf_bca_attach, .detach = brcmf_bca_detach, + .feat_attach = brcmf_bca_feat_attach, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 7348f73680d6..7fef93ede0fb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -13,6 +13,7 @@ #include "debug.h" #include "fwil.h" #include "fwil_types.h" +#include "fwvid.h" #include "feature.h" #include "common.h" @@ -339,6 +340,8 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver"); + brcmf_fwvid_feat_attach(ifp); + if (drvr->settings->feature_disable) { brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n", ifp->drvr->feat_flags, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h index 43df58bb70ad..17fbdbb76f51 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h @@ -8,10 +8,12 @@ #include "firmware.h" struct brcmf_pub; +struct brcmf_if; struct brcmf_fwvid_ops { int (*attach)(struct brcmf_pub *drvr); void (*detach)(struct brcmf_pub *drvr); + void (*feat_attach)(struct brcmf_if *ifp); }; /* exported functions */ @@ -44,4 +46,14 @@ static inline void brcmf_fwvid_detach(struct brcmf_pub *drvr) brcmf_fwvid_detach_ops(drvr); } +static inline void brcmf_fwvid_feat_attach(struct brcmf_if *ifp) +{ + const struct brcmf_fwvid_ops *vops = ifp->drvr->vops; + + if (!vops->feat_attach) + return; + + vops->feat_attach(ifp); +} + #endif /* FWVID_H_ */ -- cgit v1.2.3 From ba4d4726335c77bb0ac17840b2c5f764f3d40b99 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 3 Jan 2024 10:57:03 +0100 Subject: wifi: brcmfmac: move feature overrides before feature_disable The feature_disable option in brcmf_feat_attach() is a debugging or workaround option to disable features that cause driver issues. Hence they should be done as last step after all feature detection mechanisms have been completed. Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240103095704.135651-4-arend.vanspriel@broadcom.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 7fef93ede0fb..f23310a77a5d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -340,6 +340,9 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver"); + brcmf_feat_wlc_version_overrides(drvr); + brcmf_feat_firmware_overrides(drvr); + brcmf_fwvid_feat_attach(ifp); if (drvr->settings->feature_disable) { @@ -349,9 +352,6 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) ifp->drvr->feat_flags &= ~drvr->settings->feature_disable; } - brcmf_feat_wlc_version_overrides(drvr); - brcmf_feat_firmware_overrides(drvr); - /* set chip related quirks */ switch (drvr->bus_if->chip) { case BRCM_CC_43236_CHIP_ID: -- cgit v1.2.3 From 9f7861c56b51b84d30114e7fea9d744a9d5ba9b7 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 3 Jan 2024 10:57:04 +0100 Subject: wifi: brcmfmac: cfg80211: Use WSEC to set SAE password Using the WSEC command instead of sae_password seems to be the supported mechanism on newer firmware, and also how the brcmdhd driver does it. The existing firmware mechanism intended for (some) Cypress chips has been separated from the new firmware mechanism using the multi-vendor framework. Depending on the device it will select the appropriate firmware mechanism. This makes WPA3 work with iwd, or with wpa_supplicant pending a support patchset [2]. [1] https://rachelbythebay.com/w/2023/11/06/wpa3/ [2] http://lists.infradead.org/pipermail/hostap/2023-July/041653.html Signed-off-by: Hector Martin Reviewed-by: Neal Gompa [arend.vanspriel@broadcom.com: use multi-vendor framework] Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240103095704.135651-5-arend.vanspriel@broadcom.com --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 56 +++++++++------------- .../broadcom/brcm80211/brcmfmac/cfg80211.h | 2 + .../broadcom/brcm80211/brcmfmac/cyw/core.c | 28 +++++++++++ .../wireless/broadcom/brcm80211/brcmfmac/fwil.c | 1 + .../broadcom/brcm80211/brcmfmac/fwil_types.h | 2 +- .../wireless/broadcom/brcm80211/brcmfmac/fwvid.h | 13 +++++ .../broadcom/brcm80211/brcmfmac/wcc/core.c | 9 ++++ 7 files changed, 76 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 21096cff0c72..736b2ada6f59 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -32,6 +32,7 @@ #include "vendor.h" #include "bus.h" #include "common.h" +#include "fwvid.h" #define BRCMF_SCAN_IE_LEN_MAX 2048 @@ -1686,52 +1687,39 @@ static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e) return reason; } -static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) +int brcmf_set_wsec(struct brcmf_if *ifp, const u8 *key, u16 key_len, u16 flags) { struct brcmf_pub *drvr = ifp->drvr; struct brcmf_wsec_pmk_le pmk; int err; + if (key_len > sizeof(pmk.key)) { + bphy_err(drvr, "key must be less than %zu bytes\n", + sizeof(pmk.key)); + return -EINVAL; + } + memset(&pmk, 0, sizeof(pmk)); - /* pass pmk directly */ - pmk.key_len = cpu_to_le16(pmk_len); - pmk.flags = cpu_to_le16(0); - memcpy(pmk.key, pmk_data, pmk_len); + /* pass key material directly */ + pmk.key_len = cpu_to_le16(key_len); + pmk.flags = cpu_to_le16(flags); + memcpy(pmk.key, key, key_len); - /* store psk in firmware */ + /* store key material in firmware */ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK, &pmk, sizeof(pmk)); if (err < 0) bphy_err(drvr, "failed to change PSK in firmware (len=%u)\n", - pmk_len); + key_len); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_set_wsec); -static int brcmf_set_sae_password(struct brcmf_if *ifp, const u8 *pwd_data, - u16 pwd_len) +static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) { - struct brcmf_pub *drvr = ifp->drvr; - struct brcmf_wsec_sae_pwd_le sae_pwd; - int err; - - if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) { - bphy_err(drvr, "sae_password must be less than %d\n", - BRCMF_WSEC_MAX_SAE_PASSWORD_LEN); - return -EINVAL; - } - - sae_pwd.key_len = cpu_to_le16(pwd_len); - memcpy(sae_pwd.key, pwd_data, pwd_len); - - err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd, - sizeof(sae_pwd)); - if (err < 0) - bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n", - pwd_len); - - return err; + return brcmf_set_wsec(ifp, pmk_data, pmk_len, 0); } static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason, @@ -2502,8 +2490,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, bphy_err(drvr, "failed to clean up user-space RSNE\n"); goto done; } - err = brcmf_set_sae_password(ifp, sme->crypto.sae_pwd, - sme->crypto.sae_pwd_len); + err = brcmf_fwvid_set_sae_password(ifp, &sme->crypto); if (!err && sme->crypto.psk) err = brcmf_set_pmk(ifp, sme->crypto.psk, BRCMF_WSEC_MAX_PSK_LEN); @@ -5251,8 +5238,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, if (crypto->sae_pwd) { brcmf_dbg(INFO, "using SAE offload\n"); profile->use_fwauth |= BIT(BRCMF_PROFILE_FWAUTH_SAE); - err = brcmf_set_sae_password(ifp, crypto->sae_pwd, - crypto->sae_pwd_len); + err = brcmf_fwvid_set_sae_password(ifp, crypto); if (err < 0) goto exit; } @@ -5359,10 +5345,12 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev, msleep(400); if (profile->use_fwauth != BIT(BRCMF_PROFILE_FWAUTH_NONE)) { + struct cfg80211_crypto_settings crypto = {}; + if (profile->use_fwauth & BIT(BRCMF_PROFILE_FWAUTH_PSK)) brcmf_set_pmk(ifp, NULL, 0); if (profile->use_fwauth & BIT(BRCMF_PROFILE_FWAUTH_SAE)) - brcmf_set_sae_password(ifp, NULL, 0); + brcmf_fwvid_set_sae_password(ifp, &crypto); profile->use_fwauth = BIT(BRCMF_PROFILE_FWAUTH_NONE); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 0e1fa3f0dea2..dc3a6a537507 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -468,4 +468,6 @@ void brcmf_set_mpc(struct brcmf_if *ndev, int mpc); void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); void brcmf_cfg80211_free_netdev(struct net_device *ndev); +int brcmf_set_wsec(struct brcmf_if *ifp, const u8 *key, u16 key_len, u16 flags); + #endif /* BRCMFMAC_CFG80211_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index b75652ba9359..24670497f1a4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "vops.h" @@ -21,7 +22,34 @@ static void brcmf_cyw_detach(struct brcmf_pub *drvr) pr_err("%s: executing\n", __func__); } +static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, + struct cfg80211_crypto_settings *crypto) +{ + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_wsec_sae_pwd_le sae_pwd; + u16 pwd_len = crypto->sae_pwd_len; + int err; + + if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) { + bphy_err(drvr, "sae_password must be less than %d\n", + BRCMF_WSEC_MAX_SAE_PASSWORD_LEN); + return -EINVAL; + } + + sae_pwd.key_len = cpu_to_le16(pwd_len); + memcpy(sae_pwd.key, crypto->sae_pwd, pwd_len); + + err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd, + sizeof(sae_pwd)); + if (err < 0) + bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n", + pwd_len); + + return err; +} + const struct brcmf_fwvid_ops brcmf_cyw_ops = { .attach = brcmf_cyw_attach, .detach = brcmf_cyw_detach, + .set_sae_password = brcmf_cyw_set_sae_pwd, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c index 2aec7d2abd52..bc1c6b5a6e31 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c @@ -211,6 +211,7 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *dat mutex_unlock(&drvr->proto_block); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_iovar_data_set); s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 9d248ba1c0b2..e74a23e11830 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -584,7 +584,7 @@ struct brcmf_wsec_key_le { struct brcmf_wsec_pmk_le { __le16 key_len; __le16 flags; - u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1]; + u8 key[BRCMF_WSEC_MAX_SAE_PASSWORD_LEN]; }; /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h index 17fbdbb76f51..d9fc76b46db9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h @@ -6,6 +6,7 @@ #define FWVID_H_ #include "firmware.h" +#include "cfg80211.h" struct brcmf_pub; struct brcmf_if; @@ -14,6 +15,7 @@ struct brcmf_fwvid_ops { int (*attach)(struct brcmf_pub *drvr); void (*detach)(struct brcmf_pub *drvr); void (*feat_attach)(struct brcmf_if *ifp); + int (*set_sae_password)(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto); }; /* exported functions */ @@ -56,4 +58,15 @@ static inline void brcmf_fwvid_feat_attach(struct brcmf_if *ifp) vops->feat_attach(ifp); } +static inline int brcmf_fwvid_set_sae_password(struct brcmf_if *ifp, + struct cfg80211_crypto_settings *crypto) +{ + const struct brcmf_fwvid_ops *vops = ifp->drvr->vops; + + if (!vops || !vops->set_sae_password) + return -EOPNOTSUPP; + + return vops->set_sae_password(ifp, crypto); +} + #endif /* FWVID_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c index 5573a47766ad..2d8f80bd7382 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "vops.h" @@ -21,7 +22,15 @@ static void brcmf_wcc_detach(struct brcmf_pub *drvr) pr_debug("%s: executing\n", __func__); } +static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, + struct cfg80211_crypto_settings *crypto) +{ + return brcmf_set_wsec(ifp, crypto->sae_pwd, crypto->sae_pwd_len, + BRCMF_WSEC_PASSPHRASE); +} + const struct brcmf_fwvid_ops brcmf_wcc_ops = { .attach = brcmf_wcc_attach, .detach = brcmf_wcc_detach, + .set_sae_password = brcmf_wcc_set_sae_pwd, }; -- cgit v1.2.3 From 85da8f71aaa7b83ea7ef0e89182e0cd47e16d465 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sat, 6 Jan 2024 11:38:33 +0100 Subject: wifi: brcmfmac: Demote vendor-specific attach/detach messages to info People are getting spooked by brcmfmac errors on their boot console. There's no reason for these messages to be errors. Cc: stable@vger.kernel.org # 6.2.x Fixes: d6a5c562214f ("wifi: brcmfmac: add support for vendor-specific firmware api") Signed-off-by: Hector Martin [arend.vanspriel@broadcom.com: remove attach/detach vendor callbacks] Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240106103835.269149-2-arend.vanspriel@broadcom.com --- .../broadcom/brcm80211/brcmfmac/bca/core.c | 13 ----------- .../broadcom/brcm80211/brcmfmac/cyw/core.c | 13 ----------- .../wireless/broadcom/brcm80211/brcmfmac/fwvid.c | 7 +++--- .../wireless/broadcom/brcm80211/brcmfmac/fwvid.h | 26 ++-------------------- .../broadcom/brcm80211/brcmfmac/wcc/core.c | 15 +------------ 5 files changed, 6 insertions(+), 68 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c index a5d9ac5e6763..a963c242975a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c @@ -11,17 +11,6 @@ #include "vops.h" -static int brcmf_bca_attach(struct brcmf_pub *drvr) -{ - pr_err("%s: executing\n", __func__); - return 0; -} - -static void brcmf_bca_detach(struct brcmf_pub *drvr) -{ - pr_err("%s: executing\n", __func__); -} - static void brcmf_bca_feat_attach(struct brcmf_if *ifp) { /* SAE support not confirmed so disabling for now */ @@ -29,7 +18,5 @@ static void brcmf_bca_feat_attach(struct brcmf_if *ifp) } const struct brcmf_fwvid_ops brcmf_bca_ops = { - .attach = brcmf_bca_attach, - .detach = brcmf_bca_detach, .feat_attach = brcmf_bca_feat_attach, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index 24670497f1a4..bec5748310b9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -11,17 +11,6 @@ #include "vops.h" -static int brcmf_cyw_attach(struct brcmf_pub *drvr) -{ - pr_err("%s: executing\n", __func__); - return 0; -} - -static void brcmf_cyw_detach(struct brcmf_pub *drvr) -{ - pr_err("%s: executing\n", __func__); -} - static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto) { @@ -49,7 +38,5 @@ static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, } const struct brcmf_fwvid_ops brcmf_cyw_ops = { - .attach = brcmf_cyw_attach, - .detach = brcmf_cyw_detach, .set_sae_password = brcmf_cyw_set_sae_pwd, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c index 86eafdb40541..f633e2bbd891 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c @@ -89,8 +89,7 @@ int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *vmod, if (fwvid >= BRCMF_FWVENDOR_NUM) return -ERANGE; - if (WARN_ON(!vmod) || WARN_ON(!vops) || - WARN_ON(!vops->attach) || WARN_ON(!vops->detach)) + if (WARN_ON(!vmod) || WARN_ON(!vops)) return -EINVAL; if (WARN_ON(fwvid_list[fwvid].vmod)) @@ -150,7 +149,7 @@ static inline int brcmf_fwvid_request_module(enum brcmf_fwvendor fwvid) } #endif -int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr) +int brcmf_fwvid_attach(struct brcmf_pub *drvr) { enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid; int ret; @@ -175,7 +174,7 @@ int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr) return ret; } -void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr) +void brcmf_fwvid_detach(struct brcmf_pub *drvr) { enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h index d9fc76b46db9..dac22534d033 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h @@ -12,8 +12,6 @@ struct brcmf_pub; struct brcmf_if; struct brcmf_fwvid_ops { - int (*attach)(struct brcmf_pub *drvr); - void (*detach)(struct brcmf_pub *drvr); void (*feat_attach)(struct brcmf_if *ifp); int (*set_sae_password)(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto); }; @@ -24,30 +22,10 @@ int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *mod, int brcmf_fwvid_unregister_vendor(enum brcmf_fwvendor fwvid, struct module *mod); /* core driver functions */ -int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr); -void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr); +int brcmf_fwvid_attach(struct brcmf_pub *drvr); +void brcmf_fwvid_detach(struct brcmf_pub *drvr); const char *brcmf_fwvid_vendor_name(struct brcmf_pub *drvr); -static inline int brcmf_fwvid_attach(struct brcmf_pub *drvr) -{ - int ret; - - ret = brcmf_fwvid_attach_ops(drvr); - if (ret) - return ret; - - return drvr->vops->attach(drvr); -} - -static inline void brcmf_fwvid_detach(struct brcmf_pub *drvr) -{ - if (!drvr->vops) - return; - - drvr->vops->detach(drvr); - brcmf_fwvid_detach_ops(drvr); -} - static inline void brcmf_fwvid_feat_attach(struct brcmf_if *ifp) { const struct brcmf_fwvid_ops *vops = ifp->drvr->vops; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c index 2d8f80bd7382..fd593b93ad40 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c @@ -7,21 +7,10 @@ #include #include #include -#include +#include #include "vops.h" -static int brcmf_wcc_attach(struct brcmf_pub *drvr) -{ - pr_debug("%s: executing\n", __func__); - return 0; -} - -static void brcmf_wcc_detach(struct brcmf_pub *drvr) -{ - pr_debug("%s: executing\n", __func__); -} - static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto) { @@ -30,7 +19,5 @@ static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, } const struct brcmf_fwvid_ops brcmf_wcc_ops = { - .attach = brcmf_wcc_attach, - .detach = brcmf_wcc_detach, .set_sae_password = brcmf_wcc_set_sae_pwd, }; -- cgit v1.2.3 From b822015a1f57268f5b2ff656736dc4004e7097da Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 6 Jan 2024 11:38:34 +0100 Subject: wifi: brcmfmac: avoid invalid list operation when vendor attach fails When the brcmf_fwvid_attach() fails the driver instance is not added to the vendor list. Hence we should not try to delete it from that list when the brcmf_fwvid_detach() function is called in cleanup path. Cc: stable@vger.kernel.org # 6.2.x Fixes: d6a5c562214f ("wifi: brcmfmac: add support for vendor-specific firmware api") Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240106103835.269149-3-arend.vanspriel@broadcom.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c index f633e2bbd891..b427782554b5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c @@ -186,9 +186,10 @@ void brcmf_fwvid_detach(struct brcmf_pub *drvr) mutex_lock(&fwvid_list_lock); - drvr->vops = NULL; - list_del(&drvr->bus_if->list); - + if (drvr->vops) { + drvr->vops = NULL; + list_del(&drvr->bus_if->list); + } mutex_unlock(&fwvid_list_lock); } -- cgit v1.2.3 From edec42821911a68317a611a2c2434a80c48bd3c0 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 6 Jan 2024 11:38:35 +0100 Subject: wifi: brcmfmac: allow per-vendor event handling The firmware interface also defines events generated by firmware on the device. As the get/set primitives the events are likely to diverge between the vendors so this commit adds support for per-vendor handling. The number of events may differ so we let the vendor-specific code allocate the struct brcmf_fweh_info which contains array of event handlers. The existing event enumeration will be used by the higher layers and thus are common definitions. The vendor-specific code can provide a mapping table for converting the common definition to the vendor-specific firmware event definition and vice-versa. Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240106103835.269149-4-arend.vanspriel@broadcom.com --- .../broadcom/brcm80211/brcmfmac/bca/core.c | 17 +++ .../wireless/broadcom/brcm80211/brcmfmac/common.c | 18 ++- .../wireless/broadcom/brcm80211/brcmfmac/core.c | 10 +- .../wireless/broadcom/brcm80211/brcmfmac/core.h | 2 +- .../broadcom/brcm80211/brcmfmac/cyw/core.c | 17 +++ .../wireless/broadcom/brcm80211/brcmfmac/fweh.c | 154 +++++++++++++++------ .../wireless/broadcom/brcm80211/brcmfmac/fweh.h | 60 ++++++-- .../wireless/broadcom/brcm80211/brcmfmac/fwvid.c | 3 +- .../wireless/broadcom/brcm80211/brcmfmac/fwvid.h | 9 ++ .../broadcom/brcm80211/brcmfmac/wcc/core.c | 17 +++ 10 files changed, 244 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless/broadcom') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c index a963c242975a..f471c962104a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c @@ -11,12 +11,29 @@ #include "vops.h" +#define BRCMF_BCA_E_LAST 212 + static void brcmf_bca_feat_attach(struct brcmf_if *ifp) { /* SAE support not confirmed so disabling for now */ ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_SAE); } +static int brcmf_bca_alloc_fweh_info(struct brcmf_pub *drvr) +{ + struct brcmf_fweh_info *fweh; + + fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_BCA_E_LAST), + GFP_KERNEL); + if (!fweh) + return -ENOMEM; + + fweh->num_event_codes = BRCMF_BCA_E_LAST; + drvr->fweh = fweh; + return 0; +} + const struct brcmf_fwvid_ops brcmf_bca_ops = { .feat_attach = brcmf_bca_feat_attach, + .alloc_fweh_info = brcmf_bca_alloc_fweh_info, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index b6d458e022fa..b24faae35873 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -266,7 +266,7 @@ static int brcmf_c_process_cal_blob(struct brcmf_if *ifp) int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) { struct brcmf_pub *drvr = ifp->drvr; - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + struct brcmf_fweh_info *fweh = drvr->fweh; u8 buf[BRCMF_DCMD_SMLEN]; struct brcmf_bus *bus; struct brcmf_rev_info_le revinfo; @@ -413,15 +413,21 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) brcmf_c_set_joinpref_default(ifp); /* Setup event_msgs, enable E_IF */ - err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask, - BRCMF_EVENTING_MASK_LEN); + err = brcmf_fil_iovar_data_get(ifp, "event_msgs", fweh->event_mask, + fweh->event_mask_len); if (err) { bphy_err(drvr, "Get event_msgs error (%d)\n", err); goto done; } - setbit(eventmask, BRCMF_E_IF); - err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask, - BRCMF_EVENTING_MASK_LEN); + /* + * BRCMF_E_IF can safely be used to set the appropriate bit + * in the event_mask as the firmware event code is guaranteed + * to match the value of BRCMF_E_IF because it is old cruft + * that all vendors have. + */ + setbit(fweh->event_mask, BRCMF_E_IF); + err = brcmf_fil_iovar_data_set(ifp, "event_msgs", fweh->event_mask, + fweh->event_mask_len); if (err) { bphy_err(drvr, "Set event_msgs error (%d)\n", err); goto done; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index a92f78026cfd..bf91b1e1368f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -1348,13 +1348,17 @@ int brcmf_attach(struct device *dev) goto fail; } + /* attach firmware event handler */ + ret = brcmf_fweh_attach(drvr); + if (ret != 0) { + bphy_err(drvr, "brcmf_fweh_attach failed\n"); + goto fail; + } + /* Attach to events important for core code */ brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG, brcmf_psm_watchdog_notify); - /* attach firmware event handler */ - brcmf_fweh_attach(drvr); - ret = brcmf_bus_started(drvr, drvr->ops); if (ret != 0) { bphy_err(drvr, "dongle is not responding: err=%d\n", ret); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index e4f911dd414b..ea76b8d33401 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -122,7 +122,7 @@ struct brcmf_pub { struct mutex proto_block; unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; - struct brcmf_fweh_info fweh; + struct brcmf_fweh_info *fweh; struct brcmf_ampdu_rx_reorder *reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS]; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index bec5748310b9..9a4837881486 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -11,6 +11,8 @@ #include "vops.h" +#define BRCMF_CYW_E_LAST 197 + static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto) { @@ -37,6 +39,21 @@ static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, return err; } +static int brcmf_cyw_alloc_fweh_info(struct brcmf_pub *drvr) +{ + struct brcmf_fweh_info *fweh; + + fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_CYW_E_LAST), + GFP_KERNEL); + if (!fweh) + return -ENOMEM; + + fweh->num_event_codes = BRCMF_CYW_E_LAST; + drvr->fweh = fweh; + return 0; +} + const struct brcmf_fwvid_ops brcmf_cyw_ops = { .set_sae_password = brcmf_cyw_set_sae_pwd, + .alloc_fweh_info = brcmf_cyw_alloc_fweh_info, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index 68960ae98987..0774f6c59226 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -14,7 +14,8 @@ #include "fweh.h" #include "fwil.h" #include "proto.h" - +#include "bus.h" +#include "fwvid.h" /** * struct brcmf_fweh_queue_item - event item on event queue. * @@ -28,7 +29,7 @@ */ struct brcmf_fweh_queue_item { struct list_head q; - enum brcmf_fweh_event_code code; + u32 code; u8 ifidx; u8 ifaddr[ETH_ALEN]; struct brcmf_event_msg_be emsg; @@ -94,7 +95,7 @@ static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh, static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr, struct brcmf_if *ifp, - enum brcmf_fweh_event_code code, + u32 fwcode, struct brcmf_event_msg *emsg, void *data) { @@ -102,13 +103,13 @@ static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr, int err = -EINVAL; if (ifp) { - fweh = &ifp->drvr->fweh; + fweh = ifp->drvr->fweh; /* handle the event if valid interface and handler */ - if (fweh->evt_handler[code]) - err = fweh->evt_handler[code](ifp, emsg, data); + if (fweh->evt_handler[fwcode]) + err = fweh->evt_handler[fwcode](ifp, emsg, data); else - bphy_err(drvr, "unhandled event %d ignored\n", code); + bphy_err(drvr, "unhandled fwevt %d ignored\n", fwcode); } else { bphy_err(drvr, "no interface object\n"); } @@ -142,7 +143,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) && (ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT || ((ifevent->role == BRCMF_E_IF_ROLE_STA) && - (drvr->fweh.p2pdev_setup_ongoing)))); + (drvr->fweh->p2pdev_setup_ongoing)))); if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) { brcmf_dbg(EVENT, "event can be ignored\n"); return; @@ -163,7 +164,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, return; if (!is_p2pdev) brcmf_proto_add_if(drvr, ifp); - if (!drvr->fweh.evt_handler[BRCMF_E_IF]) + if (!drvr->fweh->evt_handler[BRCMF_E_IF]) if (brcmf_net_attach(ifp, false) < 0) return; } @@ -183,6 +184,45 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, } } +static void brcmf_fweh_map_event_code(struct brcmf_fweh_info *fweh, + enum brcmf_fweh_event_code code, + u32 *fw_code) +{ + int i; + + if (WARN_ON(!fw_code)) + return; + + *fw_code = code; + if (fweh->event_map) { + for (i = 0; i < fweh->event_map->n_items; i++) { + if (fweh->event_map->items[i].code == code) { + *fw_code = fweh->event_map->items[i].fwevt_code; + break; + } + } + } +} + +static void brcmf_fweh_map_fwevt_code(struct brcmf_fweh_info *fweh, u32 fw_code, + enum brcmf_fweh_event_code *code) +{ + int i; + + if (WARN_ON(!code)) + return; + + *code = fw_code; + if (fweh->event_map) { + for (i = 0; i < fweh->event_map->n_items; i++) { + if (fweh->event_map->items[i].fwevt_code == fw_code) { + *code = fweh->event_map->items[i].code; + break; + } + } + } +} + /** * brcmf_fweh_dequeue_event() - get event from the queue. * @@ -221,15 +261,19 @@ static void brcmf_fweh_event_worker(struct work_struct *work) struct brcmf_event_msg emsg; fweh = container_of(work, struct brcmf_fweh_info, event_work); - drvr = container_of(fweh, struct brcmf_pub, fweh); + drvr = fweh->drvr; while ((event = brcmf_fweh_dequeue_event(fweh))) { - brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", - brcmf_fweh_event_name(event->code), event->code, + enum brcmf_fweh_event_code code; + + brcmf_fweh_map_fwevt_code(fweh, event->code, &code); + brcmf_dbg(EVENT, "event %s (%u:%u) ifidx %u bsscfg %u addr %pM\n", + brcmf_fweh_event_name(code), code, event->code, event->emsg.ifidx, event->emsg.bsscfgidx, event->emsg.addr); if (event->emsg.bsscfgidx >= BRCMF_MAX_IFS) { - bphy_err(drvr, "invalid bsscfg index: %u\n", event->emsg.bsscfgidx); + bphy_err(drvr, "invalid bsscfg index: %u\n", + event->emsg.bsscfgidx); goto event_free; } @@ -237,7 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) emsg_be = &event->emsg; emsg.version = be16_to_cpu(emsg_be->version); emsg.flags = be16_to_cpu(emsg_be->flags); - emsg.event_code = event->code; + emsg.event_code = code; emsg.status = be32_to_cpu(emsg_be->status); emsg.reason = be32_to_cpu(emsg_be->reason); emsg.auth_type = be32_to_cpu(emsg_be->auth_type); @@ -283,7 +327,7 @@ event_free: */ void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing) { - ifp->drvr->fweh.p2pdev_setup_ongoing = ongoing; + ifp->drvr->fweh->p2pdev_setup_ongoing = ongoing; } /** @@ -291,12 +335,27 @@ void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing) * * @drvr: driver information object. */ -void brcmf_fweh_attach(struct brcmf_pub *drvr) +int brcmf_fweh_attach(struct brcmf_pub *drvr) { - struct brcmf_fweh_info *fweh = &drvr->fweh; + struct brcmf_fweh_info *fweh; + int err; + + err = brcmf_fwvid_alloc_fweh_info(drvr); + if (err < 0) + return err; + + fweh = drvr->fweh; + fweh->drvr = drvr; + + fweh->event_mask_len = DIV_ROUND_UP(fweh->num_event_codes, 8); + fweh->event_mask = kzalloc(fweh->event_mask_len, GFP_KERNEL); + if (!fweh->event_mask) + return -ENOMEM; + INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker); spin_lock_init(&fweh->evt_q_lock); INIT_LIST_HEAD(&fweh->event_q); + return 0; } /** @@ -306,14 +365,19 @@ void brcmf_fweh_attach(struct brcmf_pub *drvr) */ void brcmf_fweh_detach(struct brcmf_pub *drvr) { - struct brcmf_fweh_info *fweh = &drvr->fweh; + struct brcmf_fweh_info *fweh = drvr->fweh; + + if (!fweh) + return; /* cancel the worker if initialized */ if (fweh->event_work.func) { cancel_work_sync(&fweh->event_work); WARN_ON(!list_empty(&fweh->event_q)); - memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler)); } + drvr->fweh = NULL; + kfree(fweh->event_mask); + kfree(fweh); } /** @@ -326,11 +390,17 @@ void brcmf_fweh_detach(struct brcmf_pub *drvr) int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, brcmf_fweh_handler_t handler) { - if (drvr->fweh.evt_handler[code]) { + struct brcmf_fweh_info *fweh = drvr->fweh; + u32 evt_handler_idx; + + brcmf_fweh_map_event_code(fweh, code, &evt_handler_idx); + + if (fweh->evt_handler[evt_handler_idx]) { bphy_err(drvr, "event code %d already registered\n", code); return -ENOSPC; } - drvr->fweh.evt_handler[code] = handler; + + fweh->evt_handler[evt_handler_idx] = handler; brcmf_dbg(TRACE, "event handler registered for %s\n", brcmf_fweh_event_name(code)); return 0; @@ -345,9 +415,12 @@ int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, void brcmf_fweh_unregister(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code) { + u32 evt_handler_idx; + brcmf_dbg(TRACE, "event handler cleared for %s\n", brcmf_fweh_event_name(code)); - drvr->fweh.evt_handler[code] = NULL; + brcmf_fweh_map_event_code(drvr->fweh, code, &evt_handler_idx); + drvr->fweh->evt_handler[evt_handler_idx] = NULL; } /** @@ -357,27 +430,28 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr, */ int brcmf_fweh_activate_events(struct brcmf_if *ifp) { - struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_fweh_info *fweh = ifp->drvr->fweh; + enum brcmf_fweh_event_code code; int i, err; - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; - memset(eventmask, 0, sizeof(eventmask)); - for (i = 0; i < BRCMF_E_LAST; i++) { - if (ifp->drvr->fweh.evt_handler[i]) { + memset(fweh->event_mask, 0, fweh->event_mask_len); + for (i = 0; i < fweh->num_event_codes; i++) { + if (fweh->evt_handler[i]) { + brcmf_fweh_map_fwevt_code(fweh, i, &code); brcmf_dbg(EVENT, "enable event %s\n", - brcmf_fweh_event_name(i)); - setbit(eventmask, i); + brcmf_fweh_event_name(code)); + setbit(fweh->event_mask, i); } } /* want to handle IF event as well */ brcmf_dbg(EVENT, "enable event IF\n"); - setbit(eventmask, BRCMF_E_IF); + setbit(fweh->event_mask, BRCMF_E_IF); - err = brcmf_fil_iovar_data_set(ifp, "event_msgs", - eventmask, BRCMF_EVENTING_MASK_LEN); + err = brcmf_fil_iovar_data_set(ifp, "event_msgs", fweh->event_mask, + fweh->event_mask_len); if (err) - bphy_err(drvr, "Set event_msgs error (%d)\n", err); + bphy_err(fweh->drvr, "Set event_msgs error (%d)\n", err); return err; } @@ -397,21 +471,21 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, struct brcmf_event *event_packet, u32 packet_len, gfp_t gfp) { - enum brcmf_fweh_event_code code; - struct brcmf_fweh_info *fweh = &drvr->fweh; + u32 fwevt_idx; + struct brcmf_fweh_info *fweh = drvr->fweh; struct brcmf_fweh_queue_item *event; void *data; u32 datalen; /* get event info */ - code = get_unaligned_be32(&event_packet->msg.event_type); + fwevt_idx = get_unaligned_be32(&event_packet->msg.event_type); datalen = get_unaligned_be32(&event_packet->msg.datalen); data = &event_packet[1]; - if (code >= BRCMF_E_LAST) + if (fwevt_idx >= fweh->num_event_codes) return; - if (code != BRCMF_E_IF && !fweh->evt_handler[code]) + if (fwevt_idx != BRCMF_E_IF && !fweh->evt_handler[fwevt_idx]) return; if (datalen > BRCMF_DCMD_MAXLEN || @@ -422,13 +496,13 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, if (!event) return; - event->datalen = datalen; - event->code = code; + event->code = fwevt_idx; event->ifidx = event_packet->msg.ifidx; /* use memcpy to get aligned event message */ memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); memcpy(event->data, data, datalen); + event->datalen = datalen; memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); brcmf_fweh_queue_event(fweh, event); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h index 48414e8b9389..9ca1b2aadcb5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h @@ -17,6 +17,10 @@ struct brcmf_pub; struct brcmf_if; struct brcmf_cfg80211_info; +#define BRCMF_ABSTRACT_EVENT_BIT BIT(31) +#define BRCMF_ABSTRACT_ENUM_DEF(_id, _val) \ + BRCMF_ENUM_DEF(_id, (BRCMF_ABSTRACT_EVENT_BIT | (_val))) + /* list of firmware events */ #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \ BRCMF_ENUM_DEF(SET_SSID, 0) \ @@ -98,16 +102,9 @@ struct brcmf_cfg80211_info; /* firmware event codes sent by the dongle */ enum brcmf_fweh_event_code { BRCMF_FWEH_EVENT_ENUM_DEFLIST - /* this determines event mask length which must match - * minimum length check in device firmware so it is - * hard-coded here. - */ - BRCMF_E_LAST = 139 }; #undef BRCMF_ENUM_DEF -#define BRCMF_EVENTING_MASK_LEN DIV_ROUND_UP(BRCMF_E_LAST, 8) - /* flags field values in struct brcmf_event_msg */ #define BRCMF_EVENT_MSG_LINK 0x01 #define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 @@ -287,6 +284,33 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, const struct brcmf_event_msg *evtmsg, void *data); +/** + * struct brcmf_fweh_event_map_item - fweh event and firmware event pair. + * + * @code: fweh event code as used by higher layers. + * @fwevt_code: firmware event code as used by firmware. + * + * This mapping is needed when a functionally identical event has a + * different numerical definition between vendors. When such mapping + * is needed the higher layer event code should not collide with the + * firmware event. + */ +struct brcmf_fweh_event_map_item { + enum brcmf_fweh_event_code code; + u32 fwevt_code; +}; + +/** + * struct brcmf_fweh_event_map - mapping between firmware event and fweh event. + * + * @n_items: number of mapping items. + * @items: array of fweh event and firmware event pairs. + */ +struct brcmf_fweh_event_map { + u32 n_items; + const struct brcmf_fweh_event_map_item items[] __counted_by(n_items); +}; + /** * struct brcmf_fweh_info - firmware event handling information. * @@ -294,21 +318,33 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, * @event_work: event worker. * @evt_q_lock: lock for event queue protection. * @event_q: event queue. - * @evt_handler: registered event handlers. + * @event_mask_len: length of @event_mask used to enable firmware events. + * @event_mask: byte array used in 'event_msgs' iovar command. + * @event_map: mapping between fweh event and firmware event which + * may be provided by vendor-specific module for events that need + * mapping. + * @num_event_codes: number of firmware events supported by firmware which + * does a minimum length check for the @event_mask. This value is to + * be provided by vendor-specific module determining @event_mask_len + * and consequently the allocation size for @event_mask. + * @evt_handler: event handler registry indexed by firmware event code. */ struct brcmf_fweh_info { + struct brcmf_pub *drvr; bool p2pdev_setup_ongoing; struct work_struct event_work; spinlock_t evt_q_lock; struct list_head event_q; - int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp, - const struct brcmf_event_msg *evtmsg, - void *data); + uint event_mask_len; + u8 *event_mask; + struct brcmf_fweh_event_map *event_map; + uint num_event_codes; + brcmf_fweh_handler_t evt_handler[] __counted_by(num_event_codes); }; const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code); -void brcmf_fweh_attach(struct brcmf_pub *drvr); +int brcmf_fweh_attach(struct brcmf_pub *drvr); void brcmf_fweh_detach(struct brcmf_pub *drvr); int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, int (*handler)(struct brcmf_if *ifp, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c index b427782554b5..41eafcda77f7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c @@ -89,7 +89,8 @@ int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *vmod, if (fwvid >= BRCMF_FWVENDOR_NUM) return -ERANGE; - if (WARN_ON(!vmod) || WARN_ON(!vops)) + if (WARN_ON(!vmod) || WARN_ON(!vops) || + WARN_ON(!vops->alloc_fweh_info)) return -EINVAL; if (WARN_ON(fwvid_list[fwvid].vmod)) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h index dac22534d033..e6ac9fc341bc 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h @@ -14,6 +14,7 @@ struct brcmf_if; struct brcmf_fwvid_ops { void (*feat_attach)(struct brcmf_if *ifp); int (*set_sae_password)(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto); + int (*alloc_fweh_info)(struct brcmf_pub *drvr); }; /* exported functions */ @@ -47,4 +48,12 @@ static inline int brcmf_fwvid_set_sae_password(struct brcmf_if *ifp, return vops->set_sae_password(ifp, crypto); } +static inline int brcmf_fwvid_alloc_fweh_info(struct brcmf_pub *drvr) +{ + if (!drvr->vops) + return -EIO; + + return drvr->vops->alloc_fweh_info(drvr); +} + #endif /* FWVID_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c index fd593b93ad40..05d7c2a4fba5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c @@ -11,6 +11,8 @@ #include "vops.h" +#define BRCMF_WCC_E_LAST 213 + static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto) { @@ -18,6 +20,21 @@ static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, BRCMF_WSEC_PASSPHRASE); } +static int brcmf_wcc_alloc_fweh_info(struct brcmf_pub *drvr) +{ + struct brcmf_fweh_info *fweh; + + fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_WCC_E_LAST), + GFP_KERNEL); + if (!fweh) + return -ENOMEM; + + fweh->num_event_codes = BRCMF_WCC_E_LAST; + drvr->fweh = fweh; + return 0; +} + const struct brcmf_fwvid_ops brcmf_wcc_ops = { .set_sae_password = brcmf_wcc_set_sae_pwd, + .alloc_fweh_info = brcmf_wcc_alloc_fweh_info, }; -- cgit v1.2.3