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