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