Prechádzať zdrojové kódy

cnss_prealloc: add new functions to store cache at beginning of memory

CNSS prealloc maintains various prealloc pools of 8Kb, 16Kb, 32Kb
and so on, and allocates buffer from the pool for wlan driver. When
wlan driver requests to free the memory buffer then CNSS prealloc
derives slab_cache from virtual memory via page struct to identify
prealloc pool id to put memory buffer back into the pool.

In kernel 5.17, slab_cache is removed from the page struct. Add new
functions to store cache at the beginning of allocated buffer and
when wlan driver requests to free the memory then use that cache to
identify CNSS prealloc pool to put back memory.

Change-Id: I6b3a54d3f502d977c6a61cfa6aeae597df9c8e72
CRs-Fixed: 3309289
Rajesh Chauhan 2 rokov pred
rodič
commit
48cfe543c6
1 zmenil súbory, kde vykonal 52 pridanie a 13 odobranie
  1. 52 13
      cnss_prealloc/cnss_prealloc.c

+ 52 - 13
cnss_prealloc/cnss_prealloc.c

@@ -1,5 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2012,2014-2017,2019-2021 The Linux Foundation. All rights reserved. */
+/*
+ * Copyright (c) 2012,2014-2017,2019-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
 
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -7,6 +10,7 @@
 #include <linux/mm.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/version.h>
 #ifdef CONFIG_CNSS_OUT_OF_TREE
 #include "cnss_prealloc.h"
 #else
@@ -142,6 +146,49 @@ static void cnss_pool_deinit(void)
 	}
 }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0))
+/* In kernel 5.17, slab_cache is removed from page struct, so
+ * store cache in the beginning of memory buffer.
+ */
+static inline void cnss_pool_put_cache_in_mem(void *mem, struct kmem_cache *cache)
+{
+	/* put cache at the beginnging of mem */
+	(*(struct kmem_cache **)mem) = cache;
+}
+
+static inline struct kmem_cache *cnss_pool_get_cache_from_mem(void *mem)
+{
+	struct kmem_cache *cache;
+
+	/* read cache from the beginnging of mem */
+	cache = (struct kmem_cache *)(*(struct kmem_cache **)mem);
+
+	return cache;
+}
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) */
+/* for older kernel < 5.17, we use page->slab_cache. In such case
+ * we do not reserve headroom in memory buffer to store cache.
+ */
+static inline void cnss_pool_put_cache_in_mem(void *mem, struct kmem_cache *cache)
+{
+}
+
+static inline struct kmem_cache *cnss_pool_get_cache_from_mem(void *mem)
+{
+	struct page *page;
+
+	if (!virt_addr_valid(mem))
+		return NULL;
+
+	/* mem -> page -> cache */
+	page = virt_to_head_page(mem);
+	if (!page)
+		return NULL;
+
+	return page->slab_cache;
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) */
+
 /**
  * cnss_pool_get_index() - Get the index of memory pool
  * @mem: Allocated memory
@@ -153,23 +200,13 @@ static void cnss_pool_deinit(void)
  */
 static int cnss_pool_get_index(void *mem)
 {
-	struct page *page;
 	struct kmem_cache *cache;
 	int i;
 
-	if (!virt_addr_valid(mem))
-		return -EINVAL;
-
-	/* mem -> page -> cache */
-	page = virt_to_head_page(mem);
-	if (!page)
-		return -ENOENT;
-
-	cache = page->slab_cache;
+	cache = cnss_pool_get_cache_from_mem(mem);
 	if (!cache)
 		return -ENOENT;
 
-
 	/* Check if memory belongs to a pool */
 	for (i = 0; i < ARRAY_SIZE(cnss_pools); i++) {
 		if (cnss_pools[i].cache == cache)
@@ -205,8 +242,10 @@ void *wcnss_prealloc_get(size_t size)
 		for (i = 0; i < ARRAY_SIZE(cnss_pools); i++) {
 			if (cnss_pools[i].size >= size) {
 				mem = mempool_alloc(cnss_pools[i].mp, gfp_mask);
-				if (mem)
+				if (mem) {
+					cnss_pool_put_cache_in_mem(mem, cnss_pools[i].cache);
 					break;
+				}
 			}
 		}
 	}