ath11k: use cache line aligned buffers for dbring
authorRameshkumar Sundaram <quic_ramess@quicinc.com>
Tue, 2 Nov 2021 05:41:33 +0000 (11:11 +0530)
committerKalle Valo <kvalo@codeaurora.org>
Wed, 17 Nov 2021 07:28:29 +0000 (09:28 +0200)
The DMA buffers of dbring which is used for spectral/cfr
starts at certain offset from original kmalloc() returned buffer.
This is not cache line aligned.
And also driver tries to access the data that is immediately before
this offset address (i.e. buff->paddr) after doing dma map.
This will cause cache line sharing issues and data corruption,
if CPU happen to write back cache after HW has dma'ed the data.

Fix this by mapping a cache line aligned buffer to dma.

Tested on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1

Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1635831693-15962-1-git-send-email-quic_ramess@quicinc.com
drivers/net/wireless/ath/ath11k/dbring.c
drivers/net/wireless/ath/ath11k/dbring.h

index fd98ba5b1130b47231ca65abae015dce21536b56..de220a10bce30eb98adde58de55b21aed1d0bf3f 100644 (file)
@@ -87,17 +87,23 @@ static int ath11k_dbring_fill_bufs(struct ath11k *ar,
        req_entries = min(num_free, ring->bufs_max);
        num_remain = req_entries;
        align = ring->buf_align;
-       size = sizeof(*buff) + ring->buf_sz + align - 1;
+       size = ring->buf_sz + align - 1;
 
        while (num_remain > 0) {
-               buff = kzalloc(size, GFP_ATOMIC);
+               buff = kzalloc(sizeof(*buff), GFP_ATOMIC);
                if (!buff)
                        break;
 
+               buff->payload = kzalloc(size, GFP_ATOMIC);
+               if (!buff->payload) {
+                       kfree(buff);
+                       break;
+               }
                ret = ath11k_dbring_bufs_replenish(ar, ring, buff);
                if (ret) {
                        ath11k_warn(ar->ab, "failed to replenish db ring num_remain %d req_ent %d\n",
                                    num_remain, req_entries);
+                       kfree(buff->payload);
                        kfree(buff);
                        break;
                }
@@ -282,7 +288,7 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab,
 
        srng = &ab->hal.srng_list[ring->refill_srng.ring_id];
        num_entry = ev->fixed.num_buf_release_entry;
-       size = sizeof(*buff) + ring->buf_sz + ring->buf_align - 1;
+       size = ring->buf_sz + ring->buf_align - 1;
        num_buff_reaped = 0;
 
        spin_lock_bh(&srng->lock);
@@ -319,7 +325,8 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab,
                        ring->handler(ar, &handler_data);
                }
 
-               memset(buff, 0, size);
+               buff->paddr = 0;
+               memset(buff->payload, 0, size);
                ath11k_dbring_bufs_replenish(ar, ring, buff);
        }
 
@@ -346,6 +353,7 @@ void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring)
                idr_remove(&ring->bufs_idr, buf_id);
                dma_unmap_single(ar->ab->dev, buff->paddr,
                                 ring->buf_sz, DMA_FROM_DEVICE);
+               kfree(buff->payload);
                kfree(buff);
        }
 
index f7fce9ef9c36c47387b29d606babf7cb393112a3..78a985faa0a1542fb104739726d51e189da2b22e 100644 (file)
@@ -13,7 +13,7 @@
 
 struct ath11k_dbring_element {
        dma_addr_t paddr;
-       u8 payload[0];
+       u8 *payload;
 };
 
 struct ath11k_dbring_data {