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
9 struct 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
27 static inline void
iosys_map_incr(struct iosys_map * ism,size_t n)28 iosys_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
36 static inline void
iosys_map_memcpy_to(struct iosys_map * ism,size_t off,const void * src,size_t len)37 iosys_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
46 static inline bool
iosys_map_is_null(const struct iosys_map * ism)47 iosys_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
55 static inline bool
iosys_map_is_set(const struct iosys_map * ism)56 iosys_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
64 static inline bool
iosys_map_is_equal(const struct iosys_map * ism_a,const struct iosys_map * ism_b)65 iosys_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
77 static inline void
iosys_map_clear(struct iosys_map * ism)78 iosys_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
88 static inline void
iosys_map_set_vaddr_iomem(struct iosys_map * ism,void * addr)89 iosys_map_set_vaddr_iomem(struct iosys_map *ism, void *addr)
90 {
91 ism->vaddr_iomem = addr;
92 ism->is_iomem = true;
93 }
94
95 static inline void
iosys_map_set_vaddr(struct iosys_map * ism,void * addr)96 iosys_map_set_vaddr(struct iosys_map *ism, void *addr)
97 {
98 ism->vaddr = addr;
99 ism->is_iomem = false;
100 }
101
102 static inline void
iosys_map_memset(struct iosys_map * ism,size_t off,int value,size_t len)103 iosys_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