Merge "qcacmn: Avoid using small buffer address"

Bu işleme şunda yer alıyor:
Linux Build Service Account
2023-04-21 03:18:18 -07:00
işlemeyi yapan: Gerrit - the friendly Code Review server
işleme 752d15e049
2 değiştirilmiş dosya ile 202 ekleme ve 0 silme

Dosyayı Görüntüle

@@ -1487,4 +1487,45 @@ int
qdf_iommu_domain_get_attr(qdf_iommu_domain_t *domain,
enum qdf_iommu_attr attr, void *data);
#endif
#define DEFAULT_DEBUG_DOMAIN_INIT 0
#ifdef QCA_DMA_PADDR_CHECK
/**
* qdf_dma_invalid_buf_list_init() - Initialize dma invalid buffer list
*
* Return: none
*/
void qdf_dma_invalid_buf_list_init(void);
/**
* qdf_dma_invalid_buf_list_deinit() - Deinitialize dma invalid buffer list
*
* Return: none
*/
void qdf_dma_invalid_buf_list_deinit(void);
/**
* qdf_dma_invalid_buf_free() - Free dma invalid buffer
* @dev: Pointer to device handle
* @domain: Debug domain
*
* Return: none
*/
void qdf_dma_invalid_buf_free(void *dev, uint8_t domain);
#else
static inline void
qdf_dma_invalid_buf_list_init(void)
{
}
static inline void
qdf_dma_invalid_buf_list_deinit(void)
{
}
static inline void
qdf_dma_invalid_buf_free(void *dev, uint8_t domain)
{
}
#endif /* QCA_DMA_PADDR_CHECK */
#endif /* __QDF_MEMORY_H */

Dosyayı Görüntüle

@@ -2410,7 +2410,106 @@ void *qdf_mem_dma_alloc(qdf_device_t osdev, void *dev, qdf_size_t size,
return NULL;
}
#elif defined(QCA_DMA_PADDR_CHECK)
#ifdef CONFIG_LEAK_DETECTION
#define MAX_DEBUG_DOMAIN_COUNT QDF_DEBUG_DOMAIN_COUNT
#define debug_domain_get() qdf_debug_domain_get()
#else
#define MAX_DEBUG_DOMAIN_COUNT 1
#define debug_domain_get() DEFAULT_DEBUG_DOMAIN_INIT
#endif
/**
* struct qdf_dma_buf_entry - DMA invalid buffer list entry
* @node: QDF list node member
* @size: DMA buffer size
* @phy_addr: DMA buffer physical address
* @vaddr: DMA buffer virtual address. if DMA buffer size is larger than entry
* size, we use the DMA buffer to save entry info and the starting
* address of the entry is the DMA buffer vaddr, in this way, we can
* reduce unnecessary memory consumption. if DMA buffer size is smaller
* than entry size, we need alloc another buffer, and vaddr will be set
* to the invalid dma buffer virtual address.
*/
struct qdf_dma_buf_entry {
qdf_list_node_t node;
qdf_size_t size;
qdf_dma_addr_t phy_addr;
void *vaddr;
};
#define DMA_PHY_ADDR_RESERVED 0x2000
#define QDF_DMA_MEM_ALLOC_MAX_RETRIES 10
#define QDF_DMA_INVALID_BUF_LIST_SIZE 128
static qdf_list_t qdf_invalid_buf_list[MAX_DEBUG_DOMAIN_COUNT];
static bool qdf_invalid_buf_list_init[MAX_DEBUG_DOMAIN_COUNT];
static qdf_spinlock_t qdf_invalid_buf_list_lock;
static inline void *qdf_mem_dma_alloc(qdf_device_t osdev, void *dev,
qdf_size_t size, qdf_dma_addr_t *paddr)
{
void *vaddr;
uint32_t retry;
QDF_STATUS status;
bool is_separate;
qdf_list_t *cur_buf_list;
struct qdf_dma_buf_entry *entry;
uint8_t current_domain;
for (retry = 0; retry < QDF_DMA_MEM_ALLOC_MAX_RETRIES; retry++) {
vaddr = dma_alloc_coherent(dev, size, paddr,
qdf_mem_malloc_flags());
if (!vaddr)
return NULL;
if (qdf_likely(*paddr > DMA_PHY_ADDR_RESERVED))
return vaddr;
current_domain = debug_domain_get();
/* if qdf_invalid_buf_list not init, so we can't store memory
* info and can't hold it. let's free the invalid memory and
* try to get memory with phy address greater than
* DMA_PHY_ADDR_RESERVED
*/
if (current_domain >= MAX_DEBUG_DOMAIN_COUNT ||
!qdf_invalid_buf_list_init[current_domain]) {
qdf_debug("physical address below 0x%x, re-alloc",
DMA_PHY_ADDR_RESERVED);
dma_free_coherent(dev, size, vaddr, *paddr);
continue;
}
cur_buf_list = &qdf_invalid_buf_list[current_domain];
if (size >= sizeof(*entry)) {
entry = vaddr;
entry->vaddr = NULL;
} else {
entry = qdf_mem_malloc(sizeof(*entry));
if (!entry) {
dma_free_coherent(dev, size, vaddr, *paddr);
qdf_err("qdf_mem_malloc entry failed!");
continue;
}
entry->vaddr = vaddr;
}
entry->phy_addr = *paddr;
entry->size = size;
qdf_spin_lock_irqsave(&qdf_invalid_buf_list_lock);
status = qdf_list_insert_back(cur_buf_list,
&entry->node);
qdf_spin_unlock_irqrestore(&qdf_invalid_buf_list_lock);
if (QDF_IS_STATUS_ERROR(status)) {
qdf_err("insert buf entry fail, status %d", status);
is_separate = !entry->vaddr ? false : true;
dma_free_coherent(dev, size, vaddr, *paddr);
if (is_separate)
qdf_mem_free(entry);
}
}
return NULL;
}
#else
static inline void *qdf_mem_dma_alloc(qdf_device_t osdev, void *dev,
qdf_size_t size, qdf_dma_addr_t *paddr)
@@ -2928,3 +3027,65 @@ __qdf_kmem_cache_free(qdf_kmem_cache_t cache, void *node)
{
}
#endif
#ifdef QCA_DMA_PADDR_CHECK
void qdf_dma_invalid_buf_list_init(void)
{
int i;
for (i = 0; i < MAX_DEBUG_DOMAIN_COUNT; i++) {
qdf_list_create(&qdf_invalid_buf_list[i],
QDF_DMA_INVALID_BUF_LIST_SIZE);
qdf_invalid_buf_list_init[i] = true;
}
qdf_spinlock_create(&qdf_invalid_buf_list_lock);
}
void qdf_dma_invalid_buf_free(void *dev, uint8_t domain)
{
bool is_separate;
qdf_list_t *cur_buf_list;
struct qdf_dma_buf_entry *entry;
QDF_STATUS status = QDF_STATUS_E_EMPTY;
if (!dev)
return;
if (domain >= MAX_DEBUG_DOMAIN_COUNT)
return;
if (!qdf_invalid_buf_list_init[domain])
return;
cur_buf_list = &qdf_invalid_buf_list[domain];
do {
qdf_spin_lock_irqsave(&qdf_invalid_buf_list_lock);
status = qdf_list_remove_front(cur_buf_list,
(qdf_list_node_t **)&entry);
qdf_spin_unlock_irqrestore(&qdf_invalid_buf_list_lock);
if (status != QDF_STATUS_SUCCESS)
break;
is_separate = !entry->vaddr ? false : true;
if (is_separate) {
dma_free_coherent(dev, entry->size, entry->vaddr,
entry->phy_addr);
qdf_mem_free(entry);
} else
dma_free_coherent(dev, entry->size, entry,
entry->phy_addr);
} while (!qdf_list_empty(cur_buf_list));
qdf_invalid_buf_list_init[domain] = false;
}
void qdf_dma_invalid_buf_list_deinit(void)
{
int i;
for (i = 0; i < MAX_DEBUG_DOMAIN_COUNT; i++)
qdf_list_destroy(&qdf_invalid_buf_list[i]);
qdf_spinlock_destroy(&qdf_invalid_buf_list_lock);
}
#endif /* QCA_DMA_PADDR_CHECK */