1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) Nelson Integration, LLC 2016
12 #include <linux/ctype.h>
13 #include <linux/list.h>
15 #ifdef CONFIG_NEEDS_MANUAL_RELOC
16 DECLARE_GLOBAL_DATA_PTR;
19 struct block_cache_node {
29 static LIST_HEAD(block_cache);
31 static struct block_cache_stats _stats = {
32 .max_blocks_per_entry = 8,
36 #ifdef CONFIG_NEEDS_MANUAL_RELOC
37 int blkcache_init(void)
39 struct list_head *head = &block_cache;
41 head->next = (uintptr_t)head->next + gd->reloc_off;
42 head->prev = (uintptr_t)head->prev + gd->reloc_off;
48 static struct block_cache_node *cache_find(int iftype, int devnum,
49 lbaint_t start, lbaint_t blkcnt,
52 struct block_cache_node *node;
54 list_for_each_entry(node, &block_cache, lh)
55 if ((node->iftype == iftype) &&
56 (node->devnum == devnum) &&
57 (node->blksz == blksz) &&
58 (node->start <= start) &&
59 (node->start + node->blkcnt >= start + blkcnt)) {
60 if (block_cache.next != &node->lh) {
61 /* maintain MRU ordering */
63 list_add(&node->lh, &block_cache);
70 int blkcache_read(int iftype, int devnum,
71 lbaint_t start, lbaint_t blkcnt,
72 unsigned long blksz, void *buffer)
74 struct block_cache_node *node = cache_find(iftype, devnum, start,
77 const char *src = node->cache + (start - node->start) * blksz;
78 memcpy(buffer, src, blksz * blkcnt);
79 debug("hit: start " LBAF ", count " LBAFU "\n",
85 debug("miss: start " LBAF ", count " LBAFU "\n",
91 void blkcache_fill(int iftype, int devnum,
92 lbaint_t start, lbaint_t blkcnt,
93 unsigned long blksz, void const *buffer)
96 struct block_cache_node *node;
98 /* don't cache big stuff */
99 if (blkcnt > _stats.max_blocks_per_entry)
102 if (_stats.max_entries == 0)
105 bytes = blksz * blkcnt;
106 if (_stats.max_entries <= _stats.entries) {
108 node = (struct block_cache_node *)block_cache.prev;
111 debug("drop: start " LBAF ", count " LBAFU "\n",
112 node->start, node->blkcnt);
113 if (node->blkcnt * node->blksz < bytes) {
118 node = malloc(sizeof(*node));
125 node->cache = malloc(bytes);
132 debug("fill: start " LBAF ", count " LBAFU "\n",
135 node->iftype = iftype;
136 node->devnum = devnum;
138 node->blkcnt = blkcnt;
140 memcpy(node->cache, buffer, bytes);
141 list_add(&node->lh, &block_cache);
145 void blkcache_invalidate(int iftype, int devnum)
147 struct list_head *entry, *n;
148 struct block_cache_node *node;
150 list_for_each_safe(entry, n, &block_cache) {
151 node = (struct block_cache_node *)entry;
152 if ((node->iftype == iftype) &&
153 (node->devnum == devnum)) {
162 void blkcache_configure(unsigned blocks, unsigned entries)
164 struct block_cache_node *node;
165 if ((blocks != _stats.max_blocks_per_entry) ||
166 (entries != _stats.max_entries)) {
167 /* invalidate cache */
168 while (!list_empty(&block_cache)) {
169 node = (struct block_cache_node *)block_cache.next;
177 _stats.max_blocks_per_entry = blocks;
178 _stats.max_entries = entries;
184 void blkcache_stats(struct block_cache_stats *stats)
186 memcpy(stats, &_stats, sizeof(*stats));