libmetal
io.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 - 2017, Xilinx Inc. and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * @file io.h
9  * @brief I/O access primitives for libmetal.
10  */
11 
12 #ifndef __METAL_IO__H__
13 #define __METAL_IO__H__
14 
15 #include <limits.h>
16 #include <stdint.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <metal/assert.h>
20 #include <metal/compiler.h>
21 #include <metal/atomic.h>
22 #include <metal/sys.h>
23 #include <metal/cpu.h>
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
32 #ifdef __MICROBLAZE__
33 #define NO_ATOMIC_64_SUPPORT
34 #endif
35 
36 struct metal_io_region;
37 
39 struct metal_io_ops {
40  uint64_t (*read)(struct metal_io_region *io,
41  unsigned long offset,
42  memory_order order,
43  int width);
44  void (*write)(struct metal_io_region *io,
45  unsigned long offset,
46  uint64_t value,
47  memory_order order,
48  int width);
49  int (*block_read)(struct metal_io_region *io,
50  unsigned long offset,
51  void *restrict dst,
52  memory_order order,
53  int len);
54  int (*block_write)(struct metal_io_region *io,
55  unsigned long offset,
56  const void *restrict src,
57  memory_order order,
58  int len);
59  void (*block_set)(struct metal_io_region *io,
60  unsigned long offset,
61  unsigned char value,
62  memory_order order,
63  int len);
64  void (*close)(struct metal_io_region *io);
65 };
66 
69  void *virt;
73  size_t size;
74  unsigned long page_shift;
76  unsigned int mem_flags;
78  struct metal_io_ops ops;
79 };
80 
92 void
93 metal_io_init(struct metal_io_region *io, void *virt,
94  const metal_phys_addr_t *physmap, size_t size,
95  unsigned page_shift, unsigned int mem_flags,
96  const struct metal_io_ops *ops);
97 
102 static inline void metal_io_finish(struct metal_io_region *io)
103 {
104  if (io->ops.close)
105  (*io->ops.close)(io);
106  memset(io, 0, sizeof(*io));
107 }
108 
115 static inline size_t metal_io_region_size(struct metal_io_region *io)
116 {
117  return io->size;
118 }
119 
126 static inline void *
127 metal_io_virt(struct metal_io_region *io, unsigned long offset)
128 {
129  return (io->virt != METAL_BAD_VA && offset <= io->size
130  ? (uint8_t *)io->virt + offset
131  : NULL);
132 }
133 
140 static inline unsigned long
142 {
143  size_t offset = (uint8_t *)virt - (uint8_t *)io->virt;
144  return (offset < io->size ? offset : METAL_BAD_OFFSET);
145 }
146 
154 static inline metal_phys_addr_t
155 metal_io_phys(struct metal_io_region *io, unsigned long offset)
156 {
157  unsigned long page = (io->page_shift >=
158  sizeof(offset) * CHAR_BIT ?
159  0 : offset >> io->page_shift);
160  return (io->physmap != NULL && offset <= io->size
161  ? io->physmap[page] + (offset & io->page_mask)
162  : METAL_BAD_PHYS);
163 }
164 
171 static inline unsigned long
173 {
174  unsigned long offset =
175  (io->page_mask == (metal_phys_addr_t)(-1) ?
176  phys - io->physmap[0] : phys & io->page_mask);
177  do {
178  if (metal_io_phys(io, offset) == phys)
179  return offset;
180  offset += io->page_mask + 1;
181  } while (offset < io->size);
182  return METAL_BAD_OFFSET;
183 }
184 
191 static inline void *
193 {
194  return metal_io_virt(io, metal_io_phys_to_offset(io, phys));
195 }
196 
204 static inline metal_phys_addr_t
205 metal_io_virt_to_phys(struct metal_io_region *io, void *virt)
206 {
207  return metal_io_phys(io, metal_io_virt_to_offset(io, virt));
208 }
209 
220 static inline uint64_t
221 metal_io_read(struct metal_io_region *io, unsigned long offset,
222  memory_order order, int width)
223 {
224  void *ptr = metal_io_virt(io, offset);
225 
226  if (io->ops.read)
227  return (*io->ops.read)(io, offset, order, width);
228  else if (ptr && sizeof(atomic_uchar) == width)
229  return atomic_load_explicit((atomic_uchar *)ptr, order);
230  else if (ptr && sizeof(atomic_ushort) == width)
231  return atomic_load_explicit((atomic_ushort *)ptr, order);
232  else if (ptr && sizeof(atomic_uint) == width)
233  return atomic_load_explicit((atomic_uint *)ptr, order);
234  else if (ptr && sizeof(atomic_ulong) == width)
235  return atomic_load_explicit((atomic_ulong *)ptr, order);
236 #ifndef NO_ATOMIC_64_SUPPORT
237  else if (ptr && sizeof(atomic_ullong) == width)
238  return atomic_load_explicit((atomic_ullong *)ptr, order);
239 #endif
240  metal_assert(0);
241  return 0; /* quiet compiler */
242 }
243 
254 static inline void
255 metal_io_write(struct metal_io_region *io, unsigned long offset,
256  uint64_t value, memory_order order, int width)
257 {
258  void *ptr = metal_io_virt(io, offset);
259  if (io->ops.write)
260  (*io->ops.write)(io, offset, value, order, width);
261  else if (ptr && sizeof(atomic_uchar) == width)
262  atomic_store_explicit((atomic_uchar *)ptr, value, order);
263  else if (ptr && sizeof(atomic_ushort) == width)
264  atomic_store_explicit((atomic_ushort *)ptr, value, order);
265  else if (ptr && sizeof(atomic_uint) == width)
266  atomic_store_explicit((atomic_uint *)ptr, value, order);
267  else if (ptr && sizeof(atomic_ulong) == width)
268  atomic_store_explicit((atomic_ulong *)ptr, value, order);
269 #ifndef NO_ATOMIC_64_SUPPORT
270  else if (ptr && sizeof(atomic_ullong) == width)
271  atomic_store_explicit((atomic_ullong *)ptr, value, order);
272 #endif
273  else
274  metal_assert (0);
275 }
276 
277 #define metal_io_read8_explicit(_io, _ofs, _order) \
278  metal_io_read((_io), (_ofs), (_order), 1)
279 #define metal_io_read8(_io, _ofs) \
280  metal_io_read((_io), (_ofs), memory_order_seq_cst, 1)
281 #define metal_io_write8_explicit(_io, _ofs, _val, _order) \
282  metal_io_write((_io), (_ofs), (_val), (_order), 1)
283 #define metal_io_write8(_io, _ofs, _val) \
284  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 1)
285 
286 #define metal_io_read16_explicit(_io, _ofs, _order) \
287  metal_io_read((_io), (_ofs), (_order), 2)
288 #define metal_io_read16(_io, _ofs) \
289  metal_io_read((_io), (_ofs), memory_order_seq_cst, 2)
290 #define metal_io_write16_explicit(_io, _ofs, _val, _order) \
291  metal_io_write((_io), (_ofs), (_val), (_order), 2)
292 #define metal_io_write16(_io, _ofs, _val) \
293  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 2)
294 
295 #define metal_io_read32_explicit(_io, _ofs, _order) \
296  metal_io_read((_io), (_ofs), (_order), 4)
297 #define metal_io_read32(_io, _ofs) \
298  metal_io_read((_io), (_ofs), memory_order_seq_cst, 4)
299 #define metal_io_write32_explicit(_io, _ofs, _val, _order) \
300  metal_io_write((_io), (_ofs), (_val), (_order), 4)
301 #define metal_io_write32(_io, _ofs, _val) \
302  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 4)
303 
304 #define metal_io_read64_explicit(_io, _ofs, _order) \
305  metal_io_read((_io), (_ofs), (_order), 8)
306 #define metal_io_read64(_io, _ofs) \
307  metal_io_read((_io), (_ofs), memory_order_seq_cst, 8)
308 #define metal_io_write64_explicit(_io, _ofs, _val, _order) \
309  metal_io_write((_io), (_ofs), (_val), (_order), 8)
310 #define metal_io_write64(_io, _ofs, _val) \
311  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 8)
312 
321 int metal_io_block_read(struct metal_io_region *io, unsigned long offset,
322  void *restrict dst, int len);
323 
332 int metal_io_block_write(struct metal_io_region *io, unsigned long offset,
333  const void *restrict src, int len);
334 
343 int metal_io_block_set(struct metal_io_region *io, unsigned long offset,
344  unsigned char value, int len);
345 
346 #include <metal/system/@PROJECT_SYSTEM@/io.h>
347 
350 #ifdef __cplusplus
351 }
352 #endif
353 
354 #endif /* __METAL_IO__H__ */
static size_t metal_io_region_size(struct metal_io_region *io)
Get size of I/O region.
Definition: io.h:115
static metal_phys_addr_t metal_io_phys(struct metal_io_region *io, unsigned long offset)
Get physical address for a given offset into the I/O region.
Definition: io.h:155
unsigned short atomic_ushort
Definition: atomic.h:23
static void * metal_io_virt(struct metal_io_region *io, unsigned long offset)
Get virtual address for a given offset into the I/O region.
Definition: io.h:127
metal_phys_addr_t page_mask
Definition: io.h:75
int metal_io_block_write(struct metal_io_region *io, unsigned long offset, const void *restrict src, int len)
Write a block into an I/O region.
Definition: io.c:70
static metal_phys_addr_t metal_io_virt_to_phys(struct metal_io_region *io, void *virt)
Convert a virtual address to physical address.
Definition: io.h:205
uint64_t(* read)(struct metal_io_region *io, unsigned long offset, memory_order order, int width)
Definition: io.h:40
void * virt
Definition: io.h:69
static void * metal_io_phys_to_virt(struct metal_io_region *io, metal_phys_addr_t phys)
Convert a physical address to virtual address.
Definition: io.h:192
unsigned long page_shift
Definition: io.h:74
#define METAL_BAD_OFFSET
Definition: sys.h:35
static unsigned long metal_io_phys_to_offset(struct metal_io_region *io, metal_phys_addr_t phys)
Convert a physical address to offset within I/O region.
Definition: io.h:172
#define atomic_store_explicit(OBJ, VAL, MO)
Definition: atomic.h:57
#define METAL_BAD_VA
Definition: sys.h:41
int(* block_read)(struct metal_io_region *io, unsigned long offset, void *restrict dst, memory_order order, int len)
Definition: io.h:49
int metal_io_block_read(struct metal_io_region *io, unsigned long offset, void *restrict dst, int len)
Read a block from an I/O region.
Definition: io.c:33
memory_order
Definition: atomic.h:34
struct metal_io_ops ops
Definition: io.h:78
#define atomic_load_explicit(OBJ, MO)
Definition: atomic.h:61
void(* close)(struct metal_io_region *io)
Definition: io.h:64
void(* block_set)(struct metal_io_region *io, unsigned long offset, unsigned char value, memory_order order, int len)
Definition: io.h:59
int(* block_write)(struct metal_io_region *io, unsigned long offset, const void *restrict src, memory_order order, int len)
Definition: io.h:54
unsigned int mem_flags
Definition: io.h:76
static void metal_io_write(struct metal_io_region *io, unsigned long offset, uint64_t value, memory_order order, int width)
Write a value into an I/O region.
Definition: io.h:255
void(* write)(struct metal_io_region *io, unsigned long offset, uint64_t value, memory_order order, int width)
Definition: io.h:44
void metal_io_init(struct metal_io_region *io, void *virt, const metal_phys_addr_t *physmap, size_t size, unsigned page_shift, unsigned int mem_flags, const struct metal_io_ops *ops)
Open a libmetal I/O region.
Definition: io.c:12
const metal_phys_addr_t * physmap
Definition: io.h:70
unsigned char atomic_uchar
Definition: atomic.h:21
int metal_io_block_set(struct metal_io_region *io, unsigned long offset, unsigned char value, int len)
fill a block of an I/O region.
Definition: io.c:107
unsigned long atomic_ulong
Definition: atomic.h:27
Definition: io.h:68
#define metal_assert(cond)
Assertion macro.
Definition: assert.h:21
static void metal_io_finish(struct metal_io_region *io)
Close a libmetal shared memory segment.
Definition: io.h:102
Definition: io.h:39
#define restrict
Definition: compiler.h:19
#define METAL_BAD_PHYS
Definition: sys.h:38
static uint64_t metal_io_read(struct metal_io_region *io, unsigned long offset, memory_order order, int width)
Read a value from an I/O region.
Definition: io.h:221
unsigned long long atomic_ullong
Definition: atomic.h:29
unsigned int atomic_uint
Definition: atomic.h:25
static unsigned long metal_io_virt_to_offset(struct metal_io_region *io, void *virt)
Convert a virtual address to offset within I/O region.
Definition: io.h:141
size_t size
Definition: io.h:73
unsigned long metal_phys_addr_t
Definition: sys.h:29