Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-or-later */
2 : #ifndef _PCACHE_INTERNAL_H
3 : #define _PCACHE_INTERNAL_H
4 :
5 : #include <linux/delay.h>
6 : #include <linux/crc32c.h>
7 :
8 : #define pcache_err(fmt, ...) \
9 : pr_err("dm-pcache: %s:%u " fmt, __func__, __LINE__, ##__VA_ARGS__)
10 : #define pcache_info(fmt, ...) \
11 : pr_info("dm-pcache: %s:%u " fmt, __func__, __LINE__, ##__VA_ARGS__)
12 : #define pcache_debug(fmt, ...) \
13 : pr_debug("dm-pcache: %s:%u " fmt, __func__, __LINE__, ##__VA_ARGS__)
14 :
15 : #define PCACHE_KB (1024ULL)
16 : #define PCACHE_MB (1024 * PCACHE_KB)
17 :
18 : /* Maximum number of metadata indices */
19 : #define PCACHE_META_INDEX_MAX 2
20 :
21 : #define PCACHE_CRC_SEED 0x3B15A
22 : /*
23 : * struct pcache_meta_header - PCACHE metadata header structure
24 : * @crc: CRC checksum for validating metadata integrity.
25 : * @seq: Sequence number to track metadata updates.
26 : * @version: Metadata version.
27 : * @res: Reserved space for future use.
28 : */
29 : struct pcache_meta_header {
30 : __u32 crc;
31 : __u8 seq;
32 : __u8 version;
33 : __u16 res;
34 : };
35 :
36 : /*
37 : * pcache_meta_crc - Calculate CRC for the given metadata header.
38 : * @header: Pointer to the metadata header.
39 : * @meta_size: Size of the metadata structure.
40 : *
41 : * Returns the CRC checksum calculated by excluding the CRC field itself.
42 : */
43 10429041 : static inline u32 pcache_meta_crc(struct pcache_meta_header *header, u32 meta_size)
44 : {
45 10299721 : return crc32c(PCACHE_CRC_SEED, (void *)header + 4, meta_size - 4);
46 : }
47 :
48 : /*
49 : * pcache_meta_seq_after - Check if a sequence number is more recent, accounting for overflow.
50 : * @seq1: First sequence number.
51 : * @seq2: Second sequence number.
52 : *
53 : * Determines if @seq1 is more recent than @seq2 by calculating the signed
54 : * difference between them. This approach allows handling sequence number
55 : * overflow correctly because the difference wraps naturally, and any value
56 : * greater than zero indicates that @seq1 is "after" @seq2. This method
57 : * assumes 8-bit unsigned sequence numbers, where the difference wraps
58 : * around if seq1 overflows past seq2.
59 : *
60 : * Returns:
61 : * - true if @seq1 is more recent than @seq2, indicating it comes "after"
62 : * - false otherwise.
63 : */
64 32758 : static inline bool pcache_meta_seq_after(u8 seq1, u8 seq2)
65 : {
66 32758 : return (s8)(seq1 - seq2) > 0;
67 : }
68 :
69 : /*
70 : * pcache_meta_find_latest - Find the latest valid metadata.
71 : * @header: Pointer to the metadata header.
72 : * @meta_size: Size of each metadata block.
73 : *
74 : * Finds the latest valid metadata by checking sequence numbers. If a
75 : * valid entry with the highest sequence number is found, its pointer
76 : * is returned. Returns NULL if no valid metadata is found.
77 : */
78 64660 : static inline void __must_check *pcache_meta_find_latest(struct pcache_meta_header *header,
79 : u32 meta_size, u32 meta_max_size,
80 : void *meta_ret)
81 : {
82 64660 : struct pcache_meta_header *meta, *latest = NULL;
83 64660 : u32 i, seq_latest = 0;
84 64660 : void *meta_addr;
85 :
86 64660 : meta = meta_ret;
87 :
88 193980 : for (i = 0; i < PCACHE_META_INDEX_MAX; i++) {
89 129320 : meta_addr = (void *)header + (i * meta_max_size);
90 129320 : if (copy_mc_to_kernel(meta, meta_addr, meta_size)) {
91 0 : pcache_err("hardware memory error when copy meta");
92 0 : return ERR_PTR(-EIO);
93 : }
94 :
95 : /* Skip if CRC check fails, which means corrupted */
96 129320 : if (meta->crc != pcache_meta_crc(meta, meta_size))
97 32170 : continue;
98 :
99 : /* Update latest if a more recent sequence is found */
100 97150 : if (!latest || pcache_meta_seq_after(meta->seq, seq_latest)) {
101 96928 : seq_latest = meta->seq;
102 96928 : latest = (void *)header + (i * meta_max_size);
103 : }
104 : }
105 :
106 64660 : if (!latest)
107 : return NULL;
108 :
109 64392 : if (copy_mc_to_kernel(meta_ret, latest, meta_size)) {
110 0 : pcache_err("hardware memory error");
111 0 : return ERR_PTR(-EIO);
112 : }
113 :
114 : return latest;
115 : }
116 :
117 : #endif /* _PCACHE_INTERNAL_H */
|