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  else if (ptr && sizeof(atomic_ullong) == width)
237 #ifndef NO_ATOMIC_64_SUPPORT
238  return atomic_load_explicit((atomic_ullong *)ptr, order);
239 
240 #else
241  return metal_processor_io_read64((atomic_ullong *)ptr, order);
242 #endif
243  metal_assert(0);
244  return 0; /* quiet compiler */
245 }
246 
257 static inline void
258 metal_io_write(struct metal_io_region *io, unsigned long offset,
259  uint64_t value, memory_order order, int width)
260 {
261  void *ptr = metal_io_virt(io, offset);
262  if (io->ops.write)
263  (*io->ops.write)(io, offset, value, order, width);
264  else if (ptr && sizeof(atomic_uchar) == width)
265  atomic_store_explicit((atomic_uchar *)ptr, value, order);
266  else if (ptr && sizeof(atomic_ushort) == width)
267  atomic_store_explicit((atomic_ushort *)ptr, value, order);
268  else if (ptr && sizeof(atomic_uint) == width)
269  atomic_store_explicit((atomic_uint *)ptr, value, order);
270  else if (ptr && sizeof(atomic_ulong) == width)
271  atomic_store_explicit((atomic_ulong *)ptr, value, order);
272  else if (ptr && sizeof(atomic_ullong) == width)
273 #ifndef NO_ATOMIC_64_SUPPORT
274  atomic_store_explicit((atomic_ullong *)ptr, value, order);
275 #else
276  metal_processor_io_write64((atomic_ullong *)ptr, value, order);
277 #endif
278  else
279  metal_assert (0);
280 }
281 
282 #define metal_io_read8_explicit(_io, _ofs, _order) \
283  metal_io_read((_io), (_ofs), (_order), 1)
284 #define metal_io_read8(_io, _ofs) \
285  metal_io_read((_io), (_ofs), memory_order_seq_cst, 1)
286 #define metal_io_write8_explicit(_io, _ofs, _val, _order) \
287  metal_io_write((_io), (_ofs), (_val), (_order), 1)
288 #define metal_io_write8(_io, _ofs, _val) \
289  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 1)
290 
291 #define metal_io_read16_explicit(_io, _ofs, _order) \
292  metal_io_read((_io), (_ofs), (_order), 2)
293 #define metal_io_read16(_io, _ofs) \
294  metal_io_read((_io), (_ofs), memory_order_seq_cst, 2)
295 #define metal_io_write16_explicit(_io, _ofs, _val, _order) \
296  metal_io_write((_io), (_ofs), (_val), (_order), 2)
297 #define metal_io_write16(_io, _ofs, _val) \
298  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 2)
299 
300 #define metal_io_read32_explicit(_io, _ofs, _order) \
301  metal_io_read((_io), (_ofs), (_order), 4)
302 #define metal_io_read32(_io, _ofs) \
303  metal_io_read((_io), (_ofs), memory_order_seq_cst, 4)
304 #define metal_io_write32_explicit(_io, _ofs, _val, _order) \
305  metal_io_write((_io), (_ofs), (_val), (_order), 4)
306 #define metal_io_write32(_io, _ofs, _val) \
307  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 4)
308 
309 #define metal_io_read64_explicit(_io, _ofs, _order) \
310  metal_io_read((_io), (_ofs), (_order), 8)
311 #define metal_io_read64(_io, _ofs) \
312  metal_io_read((_io), (_ofs), memory_order_seq_cst, 8)
313 #define metal_io_write64_explicit(_io, _ofs, _val, _order) \
314  metal_io_write((_io), (_ofs), (_val), (_order), 8)
315 #define metal_io_write64(_io, _ofs, _val) \
316  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 8)
317 
326 int metal_io_block_read(struct metal_io_region *io, unsigned long offset,
327  void *restrict dst, int len);
328 
337 int metal_io_block_write(struct metal_io_region *io, unsigned long offset,
338  const void *restrict src, int len);
339 
348 int metal_io_block_set(struct metal_io_region *io, unsigned long offset,
349  unsigned char value, int len);
350 
351 #include <metal/system/@PROJECT_SYSTEM@/io.h>
352 
355 #ifdef __cplusplus
356 }
357 #endif
358 
359 #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:69
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
static uint64_t metal_processor_io_read64(void *ptr, memory_order order)
Definition: cpu.h:31
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
static void metal_processor_io_write64(void *ptr, uint64_t value, memory_order order)
Definition: cpu.h:20
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:258
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:105
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