1/* Public domain. */ 2 3#ifndef _LINUXKPI_LINUX_IOSYS_MAP_H 4#define _LINUXKPI_LINUX_IOSYS_MAP_H 5 6#include <linux/io.h> 7#include <linux/string.h> 8 9struct iosys_map { 10 union { 11 void *vaddr_iomem; 12 void *vaddr; 13 }; 14 bool is_iomem; 15#ifdef __OpenBSD__ 16 bus_space_handle_t bsh; 17 bus_size_t size; 18#endif 19}; 20 21#define IOSYS_MAP_INIT_OFFSET(_ism_src_p, _off) ({ \ 22 struct iosys_map ism_dst = *(_ism_src_p); \ 23 iosys_map_incr(&ism_dst, _off); \ 24 ism_dst; \ 25}) 26 27static inline void 28iosys_map_incr(struct iosys_map *ism, size_t n) 29{ 30 if (ism->is_iomem) 31 ism->vaddr_iomem += n; 32 else 33 ism->vaddr += n; 34} 35 36static inline void 37iosys_map_memcpy_to(struct iosys_map *ism, size_t off, const void *src, 38 size_t len) 39{ 40 if (ism->is_iomem) 41 memcpy_toio(ism->vaddr_iomem + off, src, len); 42 else 43 memcpy(ism->vaddr + off, src, len); 44} 45 46static inline bool 47iosys_map_is_null(const struct iosys_map *ism) 48{ 49 if (ism->is_iomem) 50 return (ism->vaddr_iomem == NULL); 51 else 52 return (ism->vaddr == NULL); 53} 54 55static inline bool 56iosys_map_is_set(const struct iosys_map *ism) 57{ 58 if (ism->is_iomem) 59 return (ism->vaddr_iomem != NULL); 60 else 61 return (ism->vaddr != NULL); 62} 63 64static inline bool 65iosys_map_is_equal(const struct iosys_map *ism_a, 66 const struct iosys_map *ism_b) 67{ 68 if (ism_a->is_iomem != ism_b->is_iomem) 69 return (false); 70 71 if (ism_a->is_iomem) 72 return (ism_a->vaddr_iomem == ism_b->vaddr_iomem); 73 else 74 return (ism_a->vaddr == ism_b->vaddr); 75} 76 77static inline void 78iosys_map_clear(struct iosys_map *ism) 79{ 80 if (ism->is_iomem) { 81 ism->vaddr_iomem = NULL; 82 ism->is_iomem = false; 83 } else { 84 ism->vaddr = NULL; 85 } 86} 87 88static inline void 89iosys_map_set_vaddr_iomem(struct iosys_map *ism, void *addr) 90{ 91 ism->vaddr_iomem = addr; 92 ism->is_iomem = true; 93} 94 95static inline void 96iosys_map_set_vaddr(struct iosys_map *ism, void *addr) 97{ 98 ism->vaddr = addr; 99 ism->is_iomem = false; 100} 101 102static inline void 103iosys_map_memset(struct iosys_map *ism, size_t off, int value, size_t len) 104{ 105 if (ism->is_iomem) 106 memset_io(ism->vaddr_iomem + off, value, len); 107 else 108 memset(ism->vaddr + off, value, len); 109} 110 111#ifdef __LP64__ 112#define _iosys_map_readq(_addr) readq(_addr) 113#define _iosys_map_writeq(_val, _addr) writeq(_val, _addr) 114#else 115#define _iosys_map_readq(_addr) ({ \ 116 uint64_t val; \ 117 memcpy_fromio(&val, _addr, sizeof(uint64_t)); \ 118 val; \ 119}) 120#define _iosys_map_writeq(_val, _addr) \ 121 memcpy_toio(_addr, &(_val), sizeof(uint64_t)) 122#endif 123 124#define iosys_map_rd(_ism, _off, _type) ({ \ 125 _type val; \ 126 if ((_ism)->is_iomem) { \ 127 void *addr = (_ism)->vaddr_iomem + (_off); \ 128 val = _Generic(val, \ 129 uint8_t : readb(addr), \ 130 uint16_t: readw(addr), \ 131 uint32_t: readl(addr), \ 132 uint64_t: _iosys_map_readq(addr)); \ 133 } else \ 134 val = READ_ONCE(*(_type *)((_ism)->vaddr + (_off))); \ 135 val; \ 136}) 137#define iosys_map_wr(_ism, _off, _type, _val) ({ \ 138 _type val = (_val); \ 139 if ((_ism)->is_iomem) { \ 140 void *addr = (_ism)->vaddr_iomem + (_off); \ 141 _Generic(val, \ 142 uint8_t : writeb(val, addr), \ 143 uint16_t: writew(val, addr), \ 144 uint32_t: writel(val, addr), \ 145 uint64_t: _iosys_map_writeq(val, addr)); \ 146 } else \ 147 WRITE_ONCE(*(_type *)((_ism)->vaddr + (_off)), val); \ 148}) 149 150#define iosys_map_rd_field(_ism, _off, _type, _field) ({ \ 151 _type *s; \ 152 iosys_map_rd(_ism, (_off) + offsetof(_type, _field), \ 153 __typeof(s->_field)); \ 154}) 155#define iosys_map_wr_field(_ism, _off, _type, _field, _val) ({ \ 156 _type *s; \ 157 iosys_map_wr(_ism, (_off) + offsetof(_type, _field), \ 158 __typeof(s->_field), _val); \ 159}) 160 161#endif 162