iosys-map.h (14945B)
1/* SPDX-License-Identifier: GPL-2.0-only */ 2/* 3 * Pointer abstraction for IO/system memory 4 */ 5 6#ifndef __IOSYS_MAP_H__ 7#define __IOSYS_MAP_H__ 8 9#include <linux/io.h> 10#include <linux/string.h> 11 12/** 13 * DOC: overview 14 * 15 * When accessing a memory region, depending on its location, users may have to 16 * access it with I/O operations or memory load/store operations. For example, 17 * copying to system memory could be done with memcpy(), copying to I/O memory 18 * would be done with memcpy_toio(). 19 * 20 * .. code-block:: c 21 * 22 * void *vaddr = ...; // pointer to system memory 23 * memcpy(vaddr, src, len); 24 * 25 * void *vaddr_iomem = ...; // pointer to I/O memory 26 * memcpy_toio(vaddr, _iomem, src, len); 27 * 28 * The user of such pointer may not have information about the mapping of that 29 * region or may want to have a single code path to handle operations on that 30 * buffer, regardless if it's located in system or IO memory. The type 31 * :c:type:`struct iosys_map <iosys_map>` and its helpers abstract that so the 32 * buffer can be passed around to other drivers or have separate duties inside 33 * the same driver for allocation, read and write operations. 34 * 35 * Open-coding access to :c:type:`struct iosys_map <iosys_map>` is considered 36 * bad style. Rather then accessing its fields directly, use one of the provided 37 * helper functions, or implement your own. For example, instances of 38 * :c:type:`struct iosys_map <iosys_map>` can be initialized statically with 39 * IOSYS_MAP_INIT_VADDR(), or at runtime with iosys_map_set_vaddr(). These 40 * helpers will set an address in system memory. 41 * 42 * .. code-block:: c 43 * 44 * struct iosys_map map = IOSYS_MAP_INIT_VADDR(0xdeadbeaf); 45 * 46 * iosys_map_set_vaddr(&map, 0xdeadbeaf); 47 * 48 * To set an address in I/O memory, use iosys_map_set_vaddr_iomem(). 49 * 50 * .. code-block:: c 51 * 52 * iosys_map_set_vaddr_iomem(&map, 0xdeadbeaf); 53 * 54 * Instances of struct iosys_map do not have to be cleaned up, but 55 * can be cleared to NULL with iosys_map_clear(). Cleared mappings 56 * always refer to system memory. 57 * 58 * .. code-block:: c 59 * 60 * iosys_map_clear(&map); 61 * 62 * Test if a mapping is valid with either iosys_map_is_set() or 63 * iosys_map_is_null(). 64 * 65 * .. code-block:: c 66 * 67 * if (iosys_map_is_set(&map) != iosys_map_is_null(&map)) 68 * // always true 69 * 70 * Instances of :c:type:`struct iosys_map <iosys_map>` can be compared for 71 * equality with iosys_map_is_equal(). Mappings that point to different memory 72 * spaces, system or I/O, are never equal. That's even true if both spaces are 73 * located in the same address space, both mappings contain the same address 74 * value, or both mappings refer to NULL. 75 * 76 * .. code-block:: c 77 * 78 * struct iosys_map sys_map; // refers to system memory 79 * struct iosys_map io_map; // refers to I/O memory 80 * 81 * if (iosys_map_is_equal(&sys_map, &io_map)) 82 * // always false 83 * 84 * A set up instance of struct iosys_map can be used to access or manipulate the 85 * buffer memory. Depending on the location of the memory, the provided helpers 86 * will pick the correct operations. Data can be copied into the memory with 87 * iosys_map_memcpy_to(). The address can be manipulated with iosys_map_incr(). 88 * 89 * .. code-block:: c 90 * 91 * const void *src = ...; // source buffer 92 * size_t len = ...; // length of src 93 * 94 * iosys_map_memcpy_to(&map, src, len); 95 * iosys_map_incr(&map, len); // go to first byte after the memcpy 96 */ 97 98/** 99 * struct iosys_map - Pointer to IO/system memory 100 * @vaddr_iomem: The buffer's address if in I/O memory 101 * @vaddr: The buffer's address if in system memory 102 * @is_iomem: True if the buffer is located in I/O memory, or false 103 * otherwise. 104 */ 105struct iosys_map { 106 union { 107 void __iomem *vaddr_iomem; 108 void *vaddr; 109 }; 110 bool is_iomem; 111}; 112 113/** 114 * IOSYS_MAP_INIT_VADDR - Initializes struct iosys_map to an address in system memory 115 * @vaddr_: A system-memory address 116 */ 117#define IOSYS_MAP_INIT_VADDR(vaddr_) \ 118 { \ 119 .vaddr = (vaddr_), \ 120 .is_iomem = false, \ 121 } 122 123/** 124 * IOSYS_MAP_INIT_OFFSET - Initializes struct iosys_map from another iosys_map 125 * @map_: The dma-buf mapping structure to copy from 126 * @offset_: Offset to add to the other mapping 127 * 128 * Initializes a new iosys_map struct based on another passed as argument. It 129 * does a shallow copy of the struct so it's possible to update the back storage 130 * without changing where the original map points to. It is the equivalent of 131 * doing: 132 * 133 * .. code-block:: c 134 * 135 * iosys_map map = other_map; 136 * iosys_map_incr(&map, &offset); 137 * 138 * Example usage: 139 * 140 * .. code-block:: c 141 * 142 * void foo(struct device *dev, struct iosys_map *base_map) 143 * { 144 * ... 145 * struct iosys_map map = IOSYS_MAP_INIT_OFFSET(base_map, FIELD_OFFSET); 146 * ... 147 * } 148 * 149 * The advantage of using the initializer over just increasing the offset with 150 * iosys_map_incr() like above is that the new map will always point to the 151 * right place of the buffer during its scope. It reduces the risk of updating 152 * the wrong part of the buffer and having no compiler warning about that. If 153 * the assignment to IOSYS_MAP_INIT_OFFSET() is forgotten, the compiler can warn 154 * about the use of uninitialized variable. 155 */ 156#define IOSYS_MAP_INIT_OFFSET(map_, offset_) ({ \ 157 struct iosys_map copy = *map_; \ 158 iosys_map_incr(©, offset_); \ 159 copy; \ 160}) 161 162/** 163 * iosys_map_set_vaddr - Sets a iosys mapping structure to an address in system memory 164 * @map: The iosys_map structure 165 * @vaddr: A system-memory address 166 * 167 * Sets the address and clears the I/O-memory flag. 168 */ 169static inline void iosys_map_set_vaddr(struct iosys_map *map, void *vaddr) 170{ 171 map->vaddr = vaddr; 172 map->is_iomem = false; 173} 174 175/** 176 * iosys_map_set_vaddr_iomem - Sets a iosys mapping structure to an address in I/O memory 177 * @map: The iosys_map structure 178 * @vaddr_iomem: An I/O-memory address 179 * 180 * Sets the address and the I/O-memory flag. 181 */ 182static inline void iosys_map_set_vaddr_iomem(struct iosys_map *map, 183 void __iomem *vaddr_iomem) 184{ 185 map->vaddr_iomem = vaddr_iomem; 186 map->is_iomem = true; 187} 188 189/** 190 * iosys_map_is_equal - Compares two iosys mapping structures for equality 191 * @lhs: The iosys_map structure 192 * @rhs: A iosys_map structure to compare with 193 * 194 * Two iosys mapping structures are equal if they both refer to the same type of memory 195 * and to the same address within that memory. 196 * 197 * Returns: 198 * True is both structures are equal, or false otherwise. 199 */ 200static inline bool iosys_map_is_equal(const struct iosys_map *lhs, 201 const struct iosys_map *rhs) 202{ 203 if (lhs->is_iomem != rhs->is_iomem) 204 return false; 205 else if (lhs->is_iomem) 206 return lhs->vaddr_iomem == rhs->vaddr_iomem; 207 else 208 return lhs->vaddr == rhs->vaddr; 209} 210 211/** 212 * iosys_map_is_null - Tests for a iosys mapping to be NULL 213 * @map: The iosys_map structure 214 * 215 * Depending on the state of struct iosys_map.is_iomem, tests if the 216 * mapping is NULL. 217 * 218 * Returns: 219 * True if the mapping is NULL, or false otherwise. 220 */ 221static inline bool iosys_map_is_null(const struct iosys_map *map) 222{ 223 if (map->is_iomem) 224 return !map->vaddr_iomem; 225 return !map->vaddr; 226} 227 228/** 229 * iosys_map_is_set - Tests if the iosys mapping has been set 230 * @map: The iosys_map structure 231 * 232 * Depending on the state of struct iosys_map.is_iomem, tests if the 233 * mapping has been set. 234 * 235 * Returns: 236 * True if the mapping is been set, or false otherwise. 237 */ 238static inline bool iosys_map_is_set(const struct iosys_map *map) 239{ 240 return !iosys_map_is_null(map); 241} 242 243/** 244 * iosys_map_clear - Clears a iosys mapping structure 245 * @map: The iosys_map structure 246 * 247 * Clears all fields to zero, including struct iosys_map.is_iomem, so 248 * mapping structures that were set to point to I/O memory are reset for 249 * system memory. Pointers are cleared to NULL. This is the default. 250 */ 251static inline void iosys_map_clear(struct iosys_map *map) 252{ 253 if (map->is_iomem) { 254 map->vaddr_iomem = NULL; 255 map->is_iomem = false; 256 } else { 257 map->vaddr = NULL; 258 } 259} 260 261/** 262 * iosys_map_memcpy_to - Memcpy into offset of iosys_map 263 * @dst: The iosys_map structure 264 * @dst_offset: The offset from which to copy 265 * @src: The source buffer 266 * @len: The number of byte in src 267 * 268 * Copies data into a iosys_map with an offset. The source buffer is in 269 * system memory. Depending on the buffer's location, the helper picks the 270 * correct method of accessing the memory. 271 */ 272static inline void iosys_map_memcpy_to(struct iosys_map *dst, size_t dst_offset, 273 const void *src, size_t len) 274{ 275 if (dst->is_iomem) 276 memcpy_toio(dst->vaddr_iomem + dst_offset, src, len); 277 else 278 memcpy(dst->vaddr + dst_offset, src, len); 279} 280 281/** 282 * iosys_map_memcpy_from - Memcpy from iosys_map into system memory 283 * @dst: Destination in system memory 284 * @src: The iosys_map structure 285 * @src_offset: The offset from which to copy 286 * @len: The number of byte in src 287 * 288 * Copies data from a iosys_map with an offset. The dest buffer is in 289 * system memory. Depending on the mapping location, the helper picks the 290 * correct method of accessing the memory. 291 */ 292static inline void iosys_map_memcpy_from(void *dst, const struct iosys_map *src, 293 size_t src_offset, size_t len) 294{ 295 if (src->is_iomem) 296 memcpy_fromio(dst, src->vaddr_iomem + src_offset, len); 297 else 298 memcpy(dst, src->vaddr + src_offset, len); 299} 300 301/** 302 * iosys_map_incr - Increments the address stored in a iosys mapping 303 * @map: The iosys_map structure 304 * @incr: The number of bytes to increment 305 * 306 * Increments the address stored in a iosys mapping. Depending on the 307 * buffer's location, the correct value will be updated. 308 */ 309static inline void iosys_map_incr(struct iosys_map *map, size_t incr) 310{ 311 if (map->is_iomem) 312 map->vaddr_iomem += incr; 313 else 314 map->vaddr += incr; 315} 316 317/** 318 * iosys_map_memset - Memset iosys_map 319 * @dst: The iosys_map structure 320 * @offset: Offset from dst where to start setting value 321 * @value: The value to set 322 * @len: The number of bytes to set in dst 323 * 324 * Set value in iosys_map. Depending on the buffer's location, the helper 325 * picks the correct method of accessing the memory. 326 */ 327static inline void iosys_map_memset(struct iosys_map *dst, size_t offset, 328 int value, size_t len) 329{ 330 if (dst->is_iomem) 331 memset_io(dst->vaddr_iomem + offset, value, len); 332 else 333 memset(dst->vaddr + offset, value, len); 334} 335 336/** 337 * iosys_map_rd - Read a C-type value from the iosys_map 338 * 339 * @map__: The iosys_map structure 340 * @offset__: The offset from which to read 341 * @type__: Type of the value being read 342 * 343 * Read a C type value from iosys_map, handling possible un-aligned accesses to 344 * the mapping. 345 * 346 * Returns: 347 * The value read from the mapping. 348 */ 349#define iosys_map_rd(map__, offset__, type__) ({ \ 350 type__ val; \ 351 iosys_map_memcpy_from(&val, map__, offset__, sizeof(val)); \ 352 val; \ 353}) 354 355/** 356 * iosys_map_wr - Write a C-type value to the iosys_map 357 * 358 * @map__: The iosys_map structure 359 * @offset__: The offset from the mapping to write to 360 * @type__: Type of the value being written 361 * @val__: Value to write 362 * 363 * Write a C-type value to the iosys_map, handling possible un-aligned accesses 364 * to the mapping. 365 */ 366#define iosys_map_wr(map__, offset__, type__, val__) ({ \ 367 type__ val = (val__); \ 368 iosys_map_memcpy_to(map__, offset__, &val, sizeof(val)); \ 369}) 370 371/** 372 * iosys_map_rd_field - Read a member from a struct in the iosys_map 373 * 374 * @map__: The iosys_map structure 375 * @struct_offset__: Offset from the beggining of the map, where the struct 376 * is located 377 * @struct_type__: The struct describing the layout of the mapping 378 * @field__: Member of the struct to read 379 * 380 * Read a value from iosys_map considering its layout is described by a C struct 381 * starting at @struct_offset__. The field offset and size is calculated and its 382 * value read handling possible un-aligned memory accesses. For example: suppose 383 * there is a @struct foo defined as below and the value ``foo.field2.inner2`` 384 * needs to be read from the iosys_map: 385 * 386 * .. code-block:: c 387 * 388 * struct foo { 389 * int field1; 390 * struct { 391 * int inner1; 392 * int inner2; 393 * } field2; 394 * int field3; 395 * } __packed; 396 * 397 * This is the expected memory layout of a buffer using iosys_map_rd_field(): 398 * 399 * +------------------------------+--------------------------+ 400 * | Address | Content | 401 * +==============================+==========================+ 402 * | buffer + 0000 | start of mmapped buffer | 403 * | | pointed by iosys_map | 404 * +------------------------------+--------------------------+ 405 * | ... | ... | 406 * +------------------------------+--------------------------+ 407 * | buffer + ``struct_offset__`` | start of ``struct foo`` | 408 * +------------------------------+--------------------------+ 409 * | ... | ... | 410 * +------------------------------+--------------------------+ 411 * | buffer + wwww | ``foo.field2.inner2`` | 412 * +------------------------------+--------------------------+ 413 * | ... | ... | 414 * +------------------------------+--------------------------+ 415 * | buffer + yyyy | end of ``struct foo`` | 416 * +------------------------------+--------------------------+ 417 * | ... | ... | 418 * +------------------------------+--------------------------+ 419 * | buffer + zzzz | end of mmaped buffer | 420 * +------------------------------+--------------------------+ 421 * 422 * Values automatically calculated by this macro or not needed are denoted by 423 * wwww, yyyy and zzzz. This is the code to read that value: 424 * 425 * .. code-block:: c 426 * 427 * x = iosys_map_rd_field(&map, offset, struct foo, field2.inner2); 428 * 429 * Returns: 430 * The value read from the mapping. 431 */ 432#define iosys_map_rd_field(map__, struct_offset__, struct_type__, field__) ({ \ 433 struct_type__ *s; \ 434 iosys_map_rd(map__, struct_offset__ + offsetof(struct_type__, field__), \ 435 typeof(s->field__)); \ 436}) 437 438/** 439 * iosys_map_wr_field - Write to a member of a struct in the iosys_map 440 * 441 * @map__: The iosys_map structure 442 * @struct_offset__: Offset from the beggining of the map, where the struct 443 * is located 444 * @struct_type__: The struct describing the layout of the mapping 445 * @field__: Member of the struct to read 446 * @val__: Value to write 447 * 448 * Write a value to the iosys_map considering its layout is described by a C struct 449 * starting at @struct_offset__. The field offset and size is calculated and the 450 * @val__ is written handling possible un-aligned memory accesses. Refer to 451 * iosys_map_rd_field() for expected usage and memory layout. 452 */ 453#define iosys_map_wr_field(map__, struct_offset__, struct_type__, field__, val__) ({ \ 454 struct_type__ *s; \ 455 iosys_map_wr(map__, struct_offset__ + offsetof(struct_type__, field__), \ 456 typeof(s->field__), val__); \ 457}) 458 459#endif /* __IOSYS_MAP_H__ */