libmetal
io.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * 3. Neither the name of Xilinx nor the names of its contributors may be used
15  * to endorse or promote products derived from this software without
16  * specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /*
32  * @file io.h
33  * @brief I/O access primitives for libmetal.
34  */
35 
36 #ifndef __METAL_IO__H__
37 #define __METAL_IO__H__
38 
39 #include <assert.h>
40 #include <stdint.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include "metal/compiler.h"
44 #include "metal/atomic.h"
45 #include "metal/sys.h"
46 
47 #ifdef __cplusplus
48 extern "C" {
49 #endif
50 
54 struct metal_io_region;
55 
57 struct metal_io_ops {
58  uint64_t (*read)(struct metal_io_region *io,
59  unsigned long offset,
60  memory_order order,
61  int width);
62  void (*write)(struct metal_io_region *io,
63  unsigned long offset,
64  uint64_t value,
65  memory_order order,
66  int width);
67  int (*block_read)(struct metal_io_region *io,
68  unsigned long offset,
69  void *restrict dst,
70  memory_order order,
71  int len);
72  int (*block_write)(struct metal_io_region *io,
73  unsigned long offset,
74  const void *restrict src,
75  memory_order order,
76  int len);
77  void (*block_set)(struct metal_io_region *io,
78  unsigned long offset,
79  unsigned char value,
80  memory_order order,
81  int len);
82  void (*close)(struct metal_io_region *io);
83 };
84 
87  void *virt;
91  size_t size;
92  unsigned long page_shift;
94  unsigned int mem_flags;
96  struct metal_io_ops ops;
97 };
98 
110 static inline void
111 metal_io_init(struct metal_io_region *io, void *virt,
112  const metal_phys_addr_t *physmap, size_t size,
113  unsigned page_shift, unsigned int mem_flags,
114  const struct metal_io_ops *ops)
115 {
116  const struct metal_io_ops nops = {NULL, NULL, NULL, NULL, NULL, NULL};
117  io->virt = virt;
118  io->physmap = physmap;
119  io->size = size;
120  io->page_shift = page_shift;
121  io->page_mask = (1UL << page_shift) - 1UL;
122  io->mem_flags = mem_flags;
123  io->ops = ops ? *ops : nops;
124 }
125 
130 static inline void metal_io_finish(struct metal_io_region *io)
131 {
132  if (io->ops.close)
133  (*io->ops.close)(io);
134  memset(io, 0, sizeof(*io));
135 }
136 
143 static inline size_t metal_io_region_size(struct metal_io_region *io)
144 {
145  return io->size;
146 }
147 
154 static inline void *
155 metal_io_virt(struct metal_io_region *io, unsigned long offset)
156 {
157  return (io->virt != METAL_BAD_VA && offset <= io->size
158  ? (uint8_t *)io->virt + offset
159  : NULL);
160 }
161 
168 static inline unsigned long
170 {
171  size_t offset = (uint8_t *)virt - (uint8_t *)io->virt;
172  return (offset < io->size ? offset : METAL_BAD_OFFSET);
173 }
174 
182 static inline metal_phys_addr_t
183 metal_io_phys(struct metal_io_region *io, unsigned long offset)
184 {
185  unsigned long page = offset >> io->page_shift;
186  return (io->physmap != NULL && offset <= io->size
187  && io->physmap[page] != METAL_BAD_PHYS
188  ? io->physmap[page] + (offset & io->page_mask)
189  : METAL_BAD_PHYS);
190 }
191 
198 static inline unsigned long
200 {
201  unsigned long offset =
202  (io->page_mask == (metal_phys_addr_t)(-1) ?
203  phys - io->physmap[0] : phys & io->page_mask);
204  do {
205  if (metal_io_phys(io, offset) == phys)
206  return offset;
207  offset += io->page_mask + 1;
208  } while (offset < io->size);
209  return METAL_BAD_OFFSET;
210 }
211 
218 static inline void *
220 {
221  return metal_io_virt(io, metal_io_phys_to_offset(io, phys));
222 }
223 
231 static inline metal_phys_addr_t
232 metal_io_virt_to_phys(struct metal_io_region *io, void *virt)
233 {
234  return metal_io_phys(io, metal_io_virt_to_offset(io, virt));
235 }
236 
247 static inline uint64_t
248 metal_io_read(struct metal_io_region *io, unsigned long offset,
249  memory_order order, int width)
250 {
251  void *ptr = metal_io_virt(io, offset);
252  if (io->ops.read)
253  return (*io->ops.read)(io, offset, order, width);
254  else if (ptr && sizeof(atomic_uchar) == width)
255  return atomic_load_explicit((atomic_uchar *)ptr, order);
256  else if (ptr && sizeof(atomic_ushort) == width)
257  return atomic_load_explicit((atomic_ushort *)ptr, order);
258  else if (ptr && sizeof(atomic_uint) == width)
259  return atomic_load_explicit((atomic_uint *)ptr, order);
260  else if (ptr && sizeof(atomic_ulong) == width)
261  return atomic_load_explicit((atomic_ulong *)ptr, order);
262  else if (ptr && sizeof(atomic_ullong) == width)
263  return atomic_load_explicit((atomic_ullong *)ptr, order);
264 
265  assert(0);
266  return 0; /* quiet compiler */
267 }
268 
279 static inline void
280 metal_io_write(struct metal_io_region *io, unsigned long offset,
281  uint64_t value, memory_order order, int width)
282 {
283  void *ptr = metal_io_virt(io, offset);
284  if (io->ops.write)
285  (*io->ops.write)(io, offset, value, order, width);
286  else if (ptr && sizeof(atomic_uchar) == width)
287  atomic_store_explicit((atomic_uchar *)ptr, value, order);
288  else if (ptr && sizeof(atomic_ushort) == width)
289  atomic_store_explicit((atomic_ushort *)ptr, value, order);
290  else if (ptr && sizeof(atomic_uint) == width)
291  atomic_store_explicit((atomic_uint *)ptr, value, order);
292  else if (ptr && sizeof(atomic_ulong) == width)
293  atomic_store_explicit((atomic_ulong *)ptr, value, order);
294  else if (ptr && sizeof(atomic_ullong) == width)
295  atomic_store_explicit((atomic_ullong *)ptr, value, order);
296  else
297  assert (0);
298 }
299 
300 #define metal_io_read8_explicit(_io, _ofs, _order) \
301  metal_io_read((_io), (_ofs), (_order), 1)
302 #define metal_io_read8(_io, _ofs) \
303  metal_io_read((_io), (_ofs), memory_order_seq_cst, 1)
304 #define metal_io_write8_explicit(_io, _ofs, _val, _order) \
305  metal_io_write((_io), (_ofs), (_val), (_order), 1)
306 #define metal_io_write8(_io, _ofs, _val) \
307  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 1)
308 
309 #define metal_io_read16_explicit(_io, _ofs, _order) \
310  metal_io_read((_io), (_ofs), (_order), 2)
311 #define metal_io_read16(_io, _ofs) \
312  metal_io_read((_io), (_ofs), memory_order_seq_cst, 2)
313 #define metal_io_write16_explicit(_io, _ofs, _val, _order) \
314  metal_io_write((_io), (_ofs), (_val), (_order), 2)
315 #define metal_io_write16(_io, _ofs, _val) \
316  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 2)
317 
318 #define metal_io_read32_explicit(_io, _ofs, _order) \
319  metal_io_read((_io), (_ofs), (_order), 4)
320 #define metal_io_read32(_io, _ofs) \
321  metal_io_read((_io), (_ofs), memory_order_seq_cst, 4)
322 #define metal_io_write32_explicit(_io, _ofs, _val, _order) \
323  metal_io_write((_io), (_ofs), (_val), (_order), 4)
324 #define metal_io_write32(_io, _ofs, _val) \
325  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 4)
326 
327 #define metal_io_read64_explicit(_io, _ofs, _order) \
328  metal_io_read((_io), (_ofs), (_order), 8)
329 #define metal_io_read64(_io, _ofs) \
330  metal_io_read((_io), (_ofs), memory_order_seq_cst, 8)
331 #define metal_io_write64_explicit(_io, _ofs, _val, _order) \
332  metal_io_write((_io), (_ofs), (_val), (_order), 8)
333 #define metal_io_write64(_io, _ofs, _val) \
334  metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 8)
335 
344 int metal_io_block_read(struct metal_io_region *io, unsigned long offset,
345  void *restrict dst, int len);
346 
355 int metal_io_block_write(struct metal_io_region *io, unsigned long offset,
356  const void *restrict src, int len);
357 
366 int metal_io_block_set(struct metal_io_region *io, unsigned long offset,
367  unsigned char value, int len);
368 
371 #ifdef __cplusplus
372 }
373 #endif
374 
375 #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:143
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:183
unsigned short atomic_ushort
Definition: atomic.h:47
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:155
metal_phys_addr_t page_mask
Definition: io.h:93
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:232
uint64_t(* read)(struct metal_io_region *io, unsigned long offset, memory_order order, int width)
Definition: io.h:58
void * virt
Definition: io.h:87
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:219
unsigned long page_shift
Definition: io.h:92
#define METAL_BAD_OFFSET
Definition: sys.h:59
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:199
#define atomic_store_explicit(OBJ, VAL, MO)
Definition: atomic.h:81
#define METAL_BAD_VA
Definition: sys.h:65
int(* block_read)(struct metal_io_region *io, unsigned long offset, void *restrict dst, memory_order order, int len)
Definition: io.h:67
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:34
memory_order
Definition: atomic.h:58
struct metal_io_ops ops
Definition: io.h:96
#define atomic_load_explicit(OBJ, MO)
Definition: atomic.h:85
void(* close)(struct metal_io_region *io)
Definition: io.h:82
static 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.h:111
void(* block_set)(struct metal_io_region *io, unsigned long offset, unsigned char value, memory_order order, int len)
Definition: io.h:77
int(* block_write)(struct metal_io_region *io, unsigned long offset, const void *restrict src, memory_order order, int len)
Definition: io.h:72
unsigned int mem_flags
Definition: io.h:94
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:280
void(* write)(struct metal_io_region *io, unsigned long offset, uint64_t value, memory_order order, int width)
Definition: io.h:62
const metal_phys_addr_t * physmap
Definition: io.h:88
unsigned char atomic_uchar
Definition: atomic.h:45
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:106
unsigned long atomic_ulong
Definition: atomic.h:51
Definition: io.h:86
static void metal_io_finish(struct metal_io_region *io)
Close a libmetal shared memory segment.
Definition: io.h:130
Definition: io.h:57
#define METAL_BAD_PHYS
Definition: sys.h:62
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:248
unsigned long long atomic_ullong
Definition: atomic.h:53
unsigned int atomic_uint
Definition: atomic.h:49
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:169
size_t size
Definition: io.h:91
unsigned long metal_phys_addr_t
Definition: sys.h:53