libmetal  latest
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 
33 #ifdef __MICROBLAZE__
34 #define NO_ATOMIC_64_SUPPORT
35 #endif
36 
37 struct metal_io_region;
38 
40 struct metal_io_ops {
41  uint64_t (*read)(struct metal_io_region *io,
42  unsigned long offset,
43  memory_order order,
44  int width);
45  void (*write)(struct metal_io_region *io,
46  unsigned long offset,
47  uint64_t value,
48  memory_order order,
49  int width);
50  int (*block_read)(struct metal_io_region *io,
51  unsigned long offset,
52  void *restrict dst,
53  memory_order order,
54  int len);
55  int (*block_write)(struct metal_io_region *io,
56  unsigned long offset,
57  const void *restrict src,
58  memory_order order,
59  int len);
60  void (*block_set)(struct metal_io_region *io,
61  unsigned long offset,
62  unsigned char value,
63  memory_order order,
64  int len);
65  void (*close)(struct metal_io_region *io);
67  unsigned long offset);
68  unsigned long (*phys_to_offset)(struct metal_io_region *io,
69  metal_phys_addr_t phys);
70 };
71 
74  void *virt;
78  size_t size;
79  unsigned long page_shift;
81  unsigned int mem_flags;
83  struct metal_io_ops ops;
84 };
85 
97 void
98 metal_io_init(struct metal_io_region *io, void *virt,
99  const metal_phys_addr_t *physmap, size_t size,
100  unsigned int page_shift, unsigned int mem_flags,
101  const struct metal_io_ops *ops);
102 
107 static inline void metal_io_finish(struct metal_io_region *io)
108 {
109  if (io->ops.close)
110  (*io->ops.close)(io);
111  memset(io, 0, sizeof(*io));
112 }
113 
120 static inline size_t metal_io_region_size(struct metal_io_region *io)
121 {
122  return io->size;
123 }
124 
131 static inline void *
132 metal_io_virt(struct metal_io_region *io, unsigned long offset)
133 {
134  return (io->virt != METAL_BAD_VA && offset < io->size
135  ? (void *)((uintptr_t)io->virt + offset)
136  : NULL);
137 }
138 
145 static inline unsigned long
147 {
148  size_t offset = (uintptr_t)virt - (uintptr_t)io->virt;
149 
150  return (offset < io->size ? offset : METAL_BAD_OFFSET);
151 }
152 
160 static inline metal_phys_addr_t
161 metal_io_phys(struct metal_io_region *io, unsigned long offset)
162 {
163  if (!io->ops.offset_to_phys) {
164  unsigned long page = (io->page_shift >=
165  sizeof(offset) * CHAR_BIT ?
166  0 : offset >> io->page_shift);
167  return (io->physmap && offset < io->size
168  ? io->physmap[page] + (offset & io->page_mask)
169  : METAL_BAD_PHYS);
170  }
171 
172  return io->ops.offset_to_phys(io, offset);
173 }
174 
181 static inline unsigned long
183 {
184  if (!io->ops.phys_to_offset) {
185  unsigned long offset =
186  (io->page_mask == (metal_phys_addr_t)(-1) ?
187  phys - io->physmap[0] : phys & io->page_mask);
188  do {
189  if (metal_io_phys(io, offset) == phys)
190  return offset;
191  offset += io->page_mask + 1;
192  } while (offset < io->size);
193  return METAL_BAD_OFFSET;
194  }
195 
196  return (*io->ops.phys_to_offset)(io, phys);
197 }
198 
205 static inline void *
207 {
208  return metal_io_virt(io, metal_io_phys_to_offset(io, phys));
209 }
210 
218 static inline metal_phys_addr_t
219 metal_io_virt_to_phys(struct metal_io_region *io, void *virt)
220 {
221  return metal_io_phys(io, metal_io_virt_to_offset(io, virt));
222 }
223 
234 static inline uint64_t
235 metal_io_read(struct metal_io_region *io, unsigned long offset,
236  memory_order order, int width)
237 {
238  void *ptr = metal_io_virt(io, offset);
239 
240  if (io->ops.read)
241  return (*io->ops.read)(io, offset, order, width);
242  else if (ptr && sizeof(atomic_uchar) == width)
243  return atomic_load_explicit((atomic_uchar *)ptr, order);
244  else if (ptr && sizeof(atomic_ushort) == width)
245  return atomic_load_explicit((atomic_ushort *)ptr, order);
246  else if (ptr && sizeof(atomic_uint) == width)
247  return atomic_load_explicit((atomic_uint *)ptr, order);
248  else if (ptr && sizeof(atomic_ulong) == width)
249  return atomic_load_explicit((atomic_ulong *)ptr, order);
250 #ifndef NO_ATOMIC_64_SUPPORT
251  else if (ptr && sizeof(atomic_ullong) == width)
252  return atomic_load_explicit((atomic_ullong *)ptr, order);
253 #endif
254  metal_assert(0);
255  return 0; /* quiet compiler */
256 }
257 
268 static inline void
269 metal_io_write(struct metal_io_region *io, unsigned long offset,
270  uint64_t value, memory_order order, int width)
271 {
272  void *ptr = metal_io_virt(io, offset);
273 
274  if (io->ops.write)
275  (*io->ops.write)(io, offset, value, order, width);
276  else if (ptr && sizeof(atomic_uchar) == width)
277  atomic_store_explicit((atomic_uchar *)ptr, (unsigned char)value,
278  order);
279  else if (ptr && sizeof(atomic_ushort) == width)
281  (unsigned short)value, order);
282  else if (ptr && sizeof(atomic_uint) == width)
283  atomic_store_explicit((atomic_uint *)ptr, (unsigned int)value,
284  order);
285  else if (ptr && sizeof(atomic_ulong) == width)
286  atomic_store_explicit((atomic_ulong *)ptr, (unsigned long)value,
287  order);
288 #ifndef NO_ATOMIC_64_SUPPORT
289  else if (ptr && sizeof(atomic_ullong) == width)
291  (unsigned long long)value, order);
292 #endif
293  else
294  metal_assert(0);
295 }
296 
297 #define metal_io_read8_explicit(_io, _ofs, _order) \
298  metal_io_read((_io), (_ofs), (_order), 1)
299 #define metal_io_read8(_io, _ofs) \
300  metal_io_read((_io), (_ofs), memory_order_seq_cst, 1)
301 #define metal_io_write8_explicit(_io, _ofs, _val, _order) \
302  metal_io_write((_io), (_ofs), (_val), (_order), 1)
303 #define metal_io_write8(_io, _ofs, _val) \
304  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 1)
305 
306 #define metal_io_read16_explicit(_io, _ofs, _order) \
307  metal_io_read((_io), (_ofs), (_order), 2)
308 #define metal_io_read16(_io, _ofs) \
309  metal_io_read((_io), (_ofs), memory_order_seq_cst, 2)
310 #define metal_io_write16_explicit(_io, _ofs, _val, _order) \
311  metal_io_write((_io), (_ofs), (_val), (_order), 2)
312 #define metal_io_write16(_io, _ofs, _val) \
313  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 2)
314 
315 #define metal_io_read32_explicit(_io, _ofs, _order) \
316  metal_io_read((_io), (_ofs), (_order), 4)
317 #define metal_io_read32(_io, _ofs) \
318  metal_io_read((_io), (_ofs), memory_order_seq_cst, 4)
319 #define metal_io_write32_explicit(_io, _ofs, _val, _order) \
320  metal_io_write((_io), (_ofs), (_val), (_order), 4)
321 #define metal_io_write32(_io, _ofs, _val) \
322  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 4)
323 
324 #define metal_io_read64_explicit(_io, _ofs, _order) \
325  metal_io_read((_io), (_ofs), (_order), 8)
326 #define metal_io_read64(_io, _ofs) \
327  metal_io_read((_io), (_ofs), memory_order_seq_cst, 8)
328 #define metal_io_write64_explicit(_io, _ofs, _val, _order) \
329  metal_io_write((_io), (_ofs), (_val), (_order), 8)
330 #define metal_io_write64(_io, _ofs, _val) \
331  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 8)
332 
341 int metal_io_block_read(struct metal_io_region *io, unsigned long offset,
342  void *restrict dst, int len);
343 
352 int metal_io_block_write(struct metal_io_region *io, unsigned long offset,
353  const void *restrict src, int len);
354 
363 int metal_io_block_set(struct metal_io_region *io, unsigned long offset,
364  unsigned char value, int len);
365 
368 #ifdef __cplusplus
369 }
370 #endif
371 
372 #include <metal/system/@PROJECT_SYSTEM@/io.h>
373 
374 #endif /* __METAL_IO__H__ */
#define metal_assert(cond)
Assertion macro.
Definition: assert.h:21
memory_order
Definition: atomic.h:35
unsigned long long atomic_ullong
Definition: atomic.h:30
unsigned char atomic_uchar
Definition: atomic.h:21
unsigned int atomic_uint
Definition: atomic.h:25
unsigned short atomic_ushort
Definition: atomic.h:23
unsigned long atomic_ulong
Definition: atomic.h:28
#define atomic_load_explicit(OBJ, MO)
Definition: atomic.h:62
#define atomic_store_explicit(OBJ, VAL, MO)
Definition: atomic.h:58
#define restrict
Definition: compiler.h:19
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:235
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:72
static size_t metal_io_region_size(struct metal_io_region *io)
Get size of I/O region.
Definition: io.h:120
void metal_io_init(struct metal_io_region *io, void *virt, const metal_phys_addr_t *physmap, size_t size, unsigned int page_shift, unsigned int mem_flags, const struct metal_io_ops *ops)
Open a libmetal I/O region.
Definition: io.c:12
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:132
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:35
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:206
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:219
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:269
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:161
static void metal_io_finish(struct metal_io_region *io)
Close a libmetal shared memory segment.
Definition: io.h:107
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:182
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:146
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:109
#define METAL_BAD_VA
Bad virtual address value.
Definition: sys.h:42
#define METAL_BAD_OFFSET
Bad offset into shared memory or I/O region.
Definition: sys.h:36
#define METAL_BAD_PHYS
Bad physical address value.
Definition: sys.h:39
unsigned long metal_phys_addr_t
Physical address type.
Definition: sys.h:30
Generic I/O operations.
Definition: io.h:40
void(* close)(struct metal_io_region *io)
Definition: io.h:65
void(* write)(struct metal_io_region *io, unsigned long offset, uint64_t value, memory_order order, int width)
Definition: io.h:45
uint64_t(* read)(struct metal_io_region *io, unsigned long offset, memory_order order, int width)
Definition: io.h:41
unsigned long(* phys_to_offset)(struct metal_io_region *io, metal_phys_addr_t phys)
Definition: io.h:68
metal_phys_addr_t(* offset_to_phys)(struct metal_io_region *io, unsigned long offset)
Definition: io.h:66
int(* block_write)(struct metal_io_region *io, unsigned long offset, const void *restrict src, memory_order order, int len)
Definition: io.h:55
int(* block_read)(struct metal_io_region *io, unsigned long offset, void *restrict dst, memory_order order, int len)
Definition: io.h:50
void(* block_set)(struct metal_io_region *io, unsigned long offset, unsigned char value, memory_order order, int len)
Definition: io.h:60
Libmetal I/O region structure.
Definition: io.h:73
const metal_phys_addr_t * physmap
table of base physical address of each of the pages in the I/O region
Definition: io.h:75
size_t size
size of the I/O region
Definition: io.h:78
unsigned int mem_flags
memory attribute of the I/O region
Definition: io.h:81
unsigned long page_shift
page shift of I/O region
Definition: io.h:79
struct metal_io_ops ops
I/O region operations.
Definition: io.h:83
void * virt
base virtual address
Definition: io.h:74
metal_phys_addr_t page_mask
page mask of I/O region
Definition: io.h:80