From ff2dd12c3c3f5c561fedfa54537d51177ccd1158 Mon Sep 17 00:00:00 2001 From: Alexander Lunev Date: Tue, 27 Jul 2021 03:43:12 +0300 Subject: [PATCH] bcm43xxx: fixed issues with unaligned buffers for DMA transfers. This fixes the following errors: - "stm32_dmacapable: stm32_dmacapable: burst crosses 1KiB up_assert: Assertion failed at file:chip/stm32_sdio.c line: 2890 task: init" - "stm32_dmacapable: stm32_dmacapable: burst crosses 1KiB up_assert: Assertion failed at file:chip/stm32_sdio.c line: 2808 task: bcmf" bcm43xxx: replaced all occurrences of "__attribute__((packed))" by compiler independent "begin_packed_struct / end_packed_struct". --- .../arm/stm32/emw3162/configs/wlan/defconfig | 1 + boards/arm/stm32/emw3162/scripts/ld.script | 3 +- .../arm/stm32/photon/configs/wlan/defconfig | 1 + boards/arm/stm32/photon/scripts/photon_dfu.ld | 3 +- .../stm32/photon/src/stm32_wlan_firmware.c | 20 +++++++++- drivers/wireless/ieee80211/bcm43xxx/Kconfig | 8 ++++ .../wireless/ieee80211/bcm43xxx/bcmf_bdc.c | 12 +++--- .../wireless/ieee80211/bcm43xxx/bcmf_bdc.h | 4 +- .../wireless/ieee80211/bcm43xxx/bcmf_cdc.c | 4 +- .../wireless/ieee80211/bcm43xxx/bcmf_sdio.h | 16 ++++++++ .../wireless/ieee80211/bcm43xxx/bcmf_sdpcm.c | 40 ++++++++++++++----- 11 files changed, 87 insertions(+), 25 deletions(-) diff --git a/boards/arm/stm32/emw3162/configs/wlan/defconfig b/boards/arm/stm32/emw3162/configs/wlan/defconfig index fe1189ad05..16f9acfa6b 100644 --- a/boards/arm/stm32/emw3162/configs/wlan/defconfig +++ b/boards/arm/stm32/emw3162/configs/wlan/defconfig @@ -27,6 +27,7 @@ CONFIG_FS_PROCFS=y CONFIG_HAVE_CXX=y CONFIG_HAVE_CXXINITIALIZE=y CONFIG_IEEE80211_BROADCOM_BCM43362=y +CONFIG_IEEE80211_BROADCOM_DMABUF_ALIGNMENT=16 CONFIG_IEEE80211_BROADCOM_FULLMAC_SDIO=y CONFIG_INTELHEX_BINARY=y CONFIG_LIBM=y diff --git a/boards/arm/stm32/emw3162/scripts/ld.script b/boards/arm/stm32/emw3162/scripts/ld.script index eb3611a6f1..493d32fa84 100644 --- a/boards/arm/stm32/emw3162/scripts/ld.script +++ b/boards/arm/stm32/emw3162/scripts/ld.script @@ -45,11 +45,10 @@ SECTIONS *(.fixup) *(.gnu.warning) - . = ALIGN(0x4); wlan_firmware_image_location = .; *(.wlan_firmware_image .wlan_firmware_image.*) wlan_firmware_image_end = .; - . = ALIGN(0x4); + wlan_nvram_image_location = .; *(.wlan_nvram_image .wlan_nvram_image.*) wlan_nvram_image_end = .; diff --git a/boards/arm/stm32/photon/configs/wlan/defconfig b/boards/arm/stm32/photon/configs/wlan/defconfig index 3a346d4b62..e061438efb 100644 --- a/boards/arm/stm32/photon/configs/wlan/defconfig +++ b/boards/arm/stm32/photon/configs/wlan/defconfig @@ -32,6 +32,7 @@ CONFIG_FS_PROCFS=y CONFIG_HAVE_CXX=y CONFIG_HAVE_CXXINITIALIZE=y CONFIG_IEEE80211_BROADCOM_BCM43362=y +CONFIG_IEEE80211_BROADCOM_DMABUF_ALIGNMENT=16 CONFIG_IEEE80211_BROADCOM_FULLMAC_SDIO=y CONFIG_INTELHEX_BINARY=y CONFIG_LIBM=y diff --git a/boards/arm/stm32/photon/scripts/photon_dfu.ld b/boards/arm/stm32/photon/scripts/photon_dfu.ld index 3ce8a661e8..7e55c02152 100644 --- a/boards/arm/stm32/photon/scripts/photon_dfu.ld +++ b/boards/arm/stm32/photon/scripts/photon_dfu.ld @@ -48,11 +48,10 @@ SECTIONS *(.fixup) *(.gnu.warning) - . = ALIGN(0x4); wlan_firmware_image_location = .; *(.wlan_firmware_image .wlan_firmware_image.*) wlan_firmware_image_end = .; - . = ALIGN(0x4); + wlan_nvram_image_location = .; *(.wlan_nvram_image .wlan_nvram_image.*) wlan_nvram_image_end = .; diff --git a/boards/arm/stm32/photon/src/stm32_wlan_firmware.c b/boards/arm/stm32/photon/src/stm32_wlan_firmware.c index 310a99a282..7f7866aa80 100644 --- a/boards/arm/stm32/photon/src/stm32_wlan_firmware.c +++ b/boards/arm/stm32/photon/src/stm32_wlan_firmware.c @@ -51,8 +51,16 @@ /* Character array of NVRAM image */ +/* SDIO_RXDMA32_CONFIG and SDIO_TXDMA32_CONFIG values in stm32_sdio.c + * give the DMA burst length of 16 bytes + * (DMA_SCR_MSIZE_32BITS x DMA_SCR_MBURST_INCR4). + * Thus the following alignment should be 0x10. + */ + const char -__attribute__((section(".wlan_nvram_image"))) bcm43362_nvram_image[] = +locate_data(".wlan_nvram_image") +aligned_data(CONFIG_IEEE80211_BROADCOM_DMABUF_ALIGNMENT) +bcm43362_nvram_image[] = "manfid=0x2d0" "\x00" "prodid=0x492" "\x00" "vendid=0x14e4" "\x00" @@ -115,8 +123,16 @@ __attribute__((section(".wlan_nvram_image"))) bcm43362_nvram_image[] = const unsigned int bcm43362_nvram_image_len = sizeof(bcm43362_nvram_image); +/* SDIO_RXDMA32_CONFIG and SDIO_TXDMA32_CONFIG values in stm32_sdio.c + * give the DMA burst length of 16 bytes + * (DMA_SCR_MSIZE_32BITS x DMA_SCR_MBURST_INCR4). + * Thus the following alignment should be 0x10. + */ + const uint8_t -__attribute__((section(".wlan_firmware_image"))) bcm43362_firmware_image[] = +locate_data(".wlan_firmware_image") +aligned_data(CONFIG_IEEE80211_BROADCOM_DMABUF_ALIGNMENT) +bcm43362_firmware_image[] = { 0x00, 0x00, 0x00, 0x00, 0xcd, 0xc2, 0x00, 0x00, 0x91, 0xc1, 0x00, 0x00, 0x91, 0xc1, 0x00, 0x00, 0x91, 0xc1, 0x00, 0x00, 0x91, 0xc1, 0x00, 0x00, diff --git a/drivers/wireless/ieee80211/bcm43xxx/Kconfig b/drivers/wireless/ieee80211/bcm43xxx/Kconfig index e46611693f..5361e173d1 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/Kconfig +++ b/drivers/wireless/ieee80211/bcm43xxx/Kconfig @@ -101,4 +101,12 @@ config IEEE80211_BROADCOM_NINTERFACES default 1 depends on EXPERIMENTAL +config IEEE80211_BROADCOM_DMABUF_ALIGNMENT + int "DMA buffer address alignment boundary" + default 4 + range 4 64 + ---help--- + This parameter should be set depending on + the used SOC DMA configuration. + endif # IEEE80211_BROADCOM_FULLMAC diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_bdc.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_bdc.c index c32305fd04..458d8a1e50 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_bdc.c +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_bdc.c @@ -48,30 +48,30 @@ * Private Types ****************************************************************************/ -struct __attribute__((packed)) bcmf_bdc_header +begin_packed_struct struct bcmf_bdc_header { uint8_t flags; /* bdc frame flags */ uint8_t priority; /* bdc frame priority */ uint8_t flags2; /* bdc frame additional flags */ uint8_t data_offset; /* Offset from end of header to payload data, in 4-bytes count */ -}; +} end_packed_struct; -struct __attribute__((packed)) bcmf_eth_header +begin_packed_struct struct bcmf_eth_header { uint16_t type; /* Vendor specific type */ uint16_t len; /* Event data length */ uint8_t version; /* Protocol version */ uint8_t oui[3]; /* Organizationally unique identifier */ uint16_t usr_type; /* User specific type */ -}; +} end_packed_struct; -struct __attribute__((packed)) bcmf_event_msg +begin_packed_struct struct bcmf_event_msg { struct ether_header eth; struct bcmf_eth_header bcm_eth; struct bcmf_event_s event; uint8_t data[0]; -}; +} end_packed_struct; /**************************************************************************** * Private Data diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_bdc.h b/drivers/wireless/ieee80211/bcm43xxx/bcmf_bdc.h index 52b644ce31..68ebb088ea 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_bdc.h +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_bdc.h @@ -33,7 +33,7 @@ /* Event frame content */ -struct __attribute__((packed)) bcmf_event_s +begin_packed_struct struct bcmf_event_s { uint16_t version; /* Vendor specific type */ uint16_t flags; @@ -46,7 +46,7 @@ struct __attribute__((packed)) bcmf_event_s char src_name[16]; /* Event source interface name */ uint8_t dst_id; /* Event destination interface id */ uint8_t bss_cfg_id; -}; +} end_packed_struct; /* Event callback handler */ diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_cdc.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_cdc.c index b260f4a3b9..3274883c04 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_cdc.c +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_cdc.c @@ -54,13 +54,13 @@ * Private Types ****************************************************************************/ -struct __attribute__((packed)) bcmf_cdc_header +begin_packed_struct struct bcmf_cdc_header { uint32_t cmd; /* Command to be sent */ uint32_t len; /* Size of command data */ uint32_t flags; /* cdc request flags, see above */ uint32_t status; /* Returned status code from chip */ -}; +} end_packed_struct; /**************************************************************************** * Private Function Prototypes diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.h b/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.h index 7059314ead..7852e5cfc6 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.h +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.h @@ -42,6 +42,7 @@ ****************************************************************************/ #define HEADER_SIZE 0x12 /* Default sdpcm + bdc header size */ +#define FIRST_WORD_SIZE 4 /* TODO move to Kconfig */ @@ -115,6 +116,21 @@ struct bcmf_sdio_frame struct bcmf_frame_s header; bool tx; dq_entry_t list_entry; + uint8_t pad[CONFIG_IEEE80211_BROADCOM_DMABUF_ALIGNMENT - + FIRST_WORD_SIZE] + aligned_data(CONFIG_IEEE80211_BROADCOM_DMABUF_ALIGNMENT); + + /* pad[] array is used and aligned in order to make the following data[] + * buffer aligned beginning from the offset of 4 bytes to the address + * boundary for SDIO DMA transfers. + * The first 4 bytes of data[] buffer are not directly used in DMA + * transfers. Instead, they are used as the initial phase just to get + * the length of the remaining long data to be read. Thus only + * the remaining part of data[] buffer beginning from the offset of 4 bytes + * is required to be aligned to the address boundary set by + * CONFIG_IEEE80211_BROADCOM_SDIO_DMA_BUF_ALIGNMENT parameter. + */ + uint8_t data[HEADER_SIZE + MAX_NETDEV_PKTSIZE + CONFIG_NET_GUARDSIZE]; }; diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdpcm.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdpcm.c index 01266d65b2..ce3cba319c 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdpcm.c +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdpcm.c @@ -58,7 +58,7 @@ * Private Types ****************************************************************************/ -struct __attribute__((packed)) bcmf_sdpcm_header +begin_packed_struct struct bcmf_sdpcm_header { uint16_t size; uint16_t checksum; @@ -69,7 +69,7 @@ struct __attribute__((packed)) bcmf_sdpcm_header uint8_t flow_control; uint8_t credit; uint16_t padding; -}; +} end_packed_struct; /**************************************************************************** * Private Function Prototypes @@ -153,9 +153,13 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv) header = (struct bcmf_sdpcm_header *)sframe->data; - /* Read header */ + /* Read the first 4 bytes of sdpcm header + * to get the length of the following data to be read + */ - ret = bcmf_transfer_bytes(sbus, false, 2, 0, (uint8_t *)header, 4); + ret = bcmf_transfer_bytes(sbus, false, 2, 0, + (uint8_t *)header, + FIRST_WORD_SIZE); if (ret != OK) { wlinfo("failread size\n"); @@ -188,10 +192,11 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv) goto exit_abort; } - /* Read remaining frame data */ + /* Read the remaining frame data (the buffer is DMA aligned here) */ ret = bcmf_transfer_bytes(sbus, false, 2, 0, - (uint8_t *)header + 4, len - 4); + (uint8_t *)header + FIRST_WORD_SIZE, + len - FIRST_WORD_SIZE); if (ret != OK) { ret = -EIO; @@ -319,8 +324,25 @@ int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv) (unsigned long)sframe->header.base); #endif - ret = bcmf_transfer_bytes(sbus, true, 2, 0, sframe->header.base, - sframe->header.len); + /* Write the first 4 bytes of sdpcm header */ + + ret = bcmf_transfer_bytes(sbus, true, 2, 0, + sframe->header.base, + FIRST_WORD_SIZE); + if (ret != OK) + { + /* TODO handle retry count and remove frame from queue + abort TX */ + + wlinfo("fail send frame %d\n", ret); + ret = -EIO; + goto exit_abort; + } + + /* Write the remaining frame data (the buffer is DMA aligned here) */ + + ret = bcmf_transfer_bytes(sbus, true, 2, 0, + sframe->header.base + FIRST_WORD_SIZE, + sframe->header.len - FIRST_WORD_SIZE); if (ret != OK) { /* TODO handle retry count and remove frame from queue + abort TX */ @@ -364,7 +386,7 @@ int bcmf_sdpcm_queue_frame(FAR struct bcmf_dev_s *priv, FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus; struct bcmf_sdio_frame *sframe = (struct bcmf_sdio_frame *)frame; struct bcmf_sdpcm_header *header = - (struct bcmf_sdpcm_header *)sframe->data; + (struct bcmf_sdpcm_header *)sframe->data; /* Prepare sw header */