blob: f4a80a43c94595f94e391625ddc586c2b308ba5e [file] [log] [blame]
/*
* Copyright 2019 The Hafnium Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "hf/arch/barriers.h"
#include "hf/check.h"
/* Opaque types for different sized fields of memory mapped IO. */
typedef struct {
volatile uint8_t *ptr;
} io8_t;
typedef struct {
volatile uint16_t *ptr;
} io16_t;
typedef struct {
volatile uint32_t *ptr;
} io32_t;
typedef struct {
volatile uint64_t *ptr;
} io64_t;
typedef struct {
volatile uint8_t *base;
size_t count;
} io8_array_t;
typedef struct {
volatile uint16_t *base;
size_t count;
} io16_array_t;
typedef struct {
volatile uint32_t *base;
size_t count;
} io32_array_t;
typedef struct {
volatile uint64_t *base;
size_t count;
} io64_array_t;
/* Contructors for literals. */
#define IO8_C(addr) ((io8_t){.ptr = (volatile uint8_t *)(addr)})
#define IO16_C(addr) ((io16_t){.ptr = (volatile uint16_t *)(addr)})
#define IO32_C(addr) ((io32_t){.ptr = (volatile uint32_t *)(addr)})
#define IO64_C(addr) ((io64_t){.ptr = (volatile uint64_t *)(addr)})
#define IO8_ARRAY_C(addr, cnt) \
((io8_array_t){.base = (volatile uint8_t *)(addr), .count = (cnt)})
#define IO16_ARRAY_C(addr, cnt) \
((io16_array_t){.base = (volatile uint16_t *)(addr), .count = (cnt)})
#define IO32_ARRAY_C(addr, cnt) \
((io32_array_t){.base = (volatile uint32_t *)(addr), .count = (cnt)})
#define IO64_ARRAY_C(addr, cnt) \
((io64_array_t){.base = (volatile uint64_t *)(addr), .count = (cnt)})
/** Read from memory-mapped IO. */
static inline uint8_t io_read8(io8_t io)
{
return *io.ptr;
}
static inline uint16_t io_read16(io16_t io)
{
return *io.ptr;
}
static inline uint32_t io_read32(io32_t io)
{
return *io.ptr;
}
static inline uint64_t io_read64(io64_t io)
{
return *io.ptr;
}
static inline uint8_t io_read8_array(io8_array_t io, size_t n)
{
CHECK(n < io.count);
return io.base[n];
}
static inline uint16_t io_read16_array(io16_array_t io, size_t n)
{
CHECK(n < io.count);
return io.base[n];
}
static inline uint32_t io_read32_array(io32_array_t io, size_t n)
{
CHECK(n < io.count);
return io.base[n];
}
static inline uint64_t io_read64_array(io64_array_t io, size_t n)
{
CHECK(n < io.count);
return io.base[n];
}
/**
* Read from memory-mapped IO with memory barrier.
*
* The read is ordered before subsequent memory accesses.
*/
static inline uint8_t io_read8_mb(io8_t io)
{
uint8_t v = io_read8(io);
data_sync_barrier();
return v;
}
static inline uint16_t io_read16_mb(io16_t io)
{
uint16_t v = io_read16(io);
data_sync_barrier();
return v;
}
static inline uint32_t io_read32_mb(io32_t io)
{
uint32_t v = io_read32(io);
data_sync_barrier();
return v;
}
static inline uint64_t io_read64_mb(io64_t io)
{
uint64_t v = io_read64(io);
data_sync_barrier();
return v;
}
static inline uint8_t io_read8_array_mb(io8_array_t io, size_t n)
{
uint8_t v = io_read8_array(io, n);
data_sync_barrier();
return v;
}
static inline uint16_t io_read16_array_mb(io16_array_t io, size_t n)
{
uint16_t v = io_read16_array(io, n);
data_sync_barrier();
return v;
}
static inline uint32_t io_read32_array_mb(io32_array_t io, size_t n)
{
uint32_t v = io_read32_array(io, n);
data_sync_barrier();
return v;
}
static inline uint64_t io_read64_array_mb(io64_array_t io, size_t n)
{
uint64_t v = io_read64_array(io, n);
data_sync_barrier();
return v;
}
/* Write to memory-mapped IO. */
static inline void io_write8(io8_t io, uint8_t v)
{
*io.ptr = v;
}
static inline void io_write16(io16_t io, uint16_t v)
{
*io.ptr = v;
}
static inline void io_write32(io32_t io, uint32_t v)
{
*io.ptr = v;
}
static inline void io_write64(io64_t io, uint64_t v)
{
*io.ptr = v;
}
static inline void io_write8_array(io8_array_t io, size_t n, uint8_t v)
{
CHECK(n < io.count);
io.base[n] = v;
}
static inline void io_write16_array(io16_array_t io, size_t n, uint16_t v)
{
CHECK(n < io.count);
io.base[n] = v;
}
static inline void io_write32_array(io32_array_t io, size_t n, uint32_t v)
{
CHECK(n < io.count);
io.base[n] = v;
}
static inline void io_write64_array(io64_array_t io, size_t n, uint64_t v)
{
CHECK(n < io.count);
io.base[n] = v;
}
/*
* Write to memory-mapped IO with memory barrier.
*
* The write is ordered after previous memory accesses.
*/
static inline void io_write8_mb(io8_t io, uint8_t v)
{
data_sync_barrier();
io_write8(io, v);
}
static inline void io_write16_mb(io16_t io, uint16_t v)
{
data_sync_barrier();
io_write16(io, v);
}
static inline void io_write32_mb(io32_t io, uint32_t v)
{
data_sync_barrier();
io_write32(io, v);
}
static inline void io_write64_mb(io64_t io, uint64_t v)
{
data_sync_barrier();
io_write64(io, v);
}
static inline void io_write8_array_mb(io8_array_t io, size_t n, uint8_t v)
{
data_sync_barrier();
io_write8_array(io, n, v);
}
static inline void io_write16_array_mb(io16_array_t io, size_t n, uint16_t v)
{
data_sync_barrier();
io_write16_array(io, n, v);
}
static inline void io_write32_array_mb(io32_array_t io, size_t n, uint32_t v)
{
data_sync_barrier();
io_write32_array(io, n, v);
}
static inline void io_write64_array_mb(io64_array_t io, size_t n, uint64_t v)
{
data_sync_barrier();
io_write64_array(io, n, v);
}