phys_addr_t rgnbase = rgn[i].base;
phys_size_t rgnsize = rgn[i].size;
phys_size_t rgnflags = rgn[i].flags;
- phys_addr_t end = base + size - 1;
- phys_addr_t rgnend = rgnbase + rgnsize - 1;
- if (rgnbase <= base && end <= rgnend) {
- if (flags == rgnflags)
- /* Already have this region, so we're done */
- return 0;
- else
- return -1; /* regions with new flags */
- }
ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize);
if (ret > 0) {
return addr & ~(size - 1);
}
+/*
+ * IOVA LMB memory maps using lmb pointers instead of the global LMB memory map.
+ */
+
+int io_lmb_setup(struct lmb *io_lmb)
+{
+ int ret;
+
+ ret = alist_init(&io_lmb->free_mem, sizeof(struct lmb_region),
+ (uint)LMB_ALIST_INITIAL_SIZE);
+ if (!ret) {
+ log_debug("Unable to initialise the list for LMB free IOVA\n");
+ return -ENOMEM;
+ }
+
+ ret = alist_init(&io_lmb->used_mem, sizeof(struct lmb_region),
+ (uint)LMB_ALIST_INITIAL_SIZE);
+ if (!ret) {
+ log_debug("Unable to initialise the list for LMB used IOVA\n");
+ return -ENOMEM;
+ }
+
+ io_lmb->test = false;
+
+ return 0;
+}
+
+void io_lmb_teardown(struct lmb *io_lmb)
+{
+ alist_uninit(&io_lmb->free_mem);
+ alist_uninit(&io_lmb->used_mem);
+}
+
+long io_lmb_add(struct lmb *io_lmb, phys_addr_t base, phys_size_t size)
+{
+ return lmb_add_region_flags(&io_lmb->free_mem, base, size, LMB_NONE);
+}
+
+/* derived and simplified from _lmb_alloc_base() */
+phys_addr_t io_lmb_alloc(struct lmb *io_lmb, phys_size_t size, ulong align)
+{
+ long i, rgn;
+ phys_addr_t base = 0;
+ phys_addr_t res_base;
+ struct lmb_region *lmb_used = io_lmb->used_mem.data;
+ struct lmb_region *lmb_memory = io_lmb->free_mem.data;
+
+ for (i = io_lmb->free_mem.count - 1; i >= 0; i--) {
+ phys_addr_t lmbbase = lmb_memory[i].base;
+ phys_size_t lmbsize = lmb_memory[i].size;
+
+ if (lmbsize < size)
+ continue;
+ base = lmb_align_down(lmbbase + lmbsize - size, align);
+
+ while (base && lmbbase <= base) {
+ rgn = lmb_overlaps_region(&io_lmb->used_mem, base, size);
+ if (rgn < 0) {
+ /* This area isn't reserved, take it */
+ if (lmb_add_region_flags(&io_lmb->used_mem, base,
+ size, LMB_NONE) < 0)
+ return 0;
+
+ return base;
+ }
+
+ res_base = lmb_used[rgn].base;
+ if (res_base < size)
+ break;
+ base = lmb_align_down(res_base - size, align);
+ }
+ }
+ return 0;
+}
+
+long io_lmb_free(struct lmb *io_lmb, phys_addr_t base, phys_size_t size)
+{
+ return _lmb_free(&io_lmb->used_mem, base, size);
+}
+
/*
* Low level LMB functions are used to manage IOVA memory maps for the Apple
* dart iommu. They must not access the global LMB memory map.
static void lmb_print_region_flags(enum lmb_flags flags)
{
- u64 bitpos;
const char *flag_str[] = { "none", "no-map", "no-overwrite", "no-notify" };
+ unsigned int pflags = flags &
+ (LMB_NOMAP | LMB_NOOVERWRITE | LMB_NONOTIFY);
+
+ if (flags != pflags) {
+ printf("invalid %#x\n", flags);
+ return;
+ }
do {
- bitpos = flags ? fls(flags) - 1 : 0;
- assert_noisy(bitpos < ARRAY_SIZE(flag_str));
+ int bitpos = pflags ? fls(pflags) - 1 : 0;
+
printf("%s", flag_str[bitpos]);
- flags &= ~(1ull << bitpos);
- puts(flags ? ", " : "\n");
- } while (flags);
+ pflags &= ~(1u << bitpos);
+ puts(pflags ? ", " : "\n");
+ } while (pflags);
}
static void lmb_dump_region(struct alist *lmb_rgn_lst, char *name)
enum lmb_flags flags;
int i;
- printf(" %s.count = 0x%x\n", name, lmb_rgn_lst->count);
+ printf(" %s.count = %#x\n", name, lmb_rgn_lst->count);
for (i = 0; i < lmb_rgn_lst->count; i++) {
base = rgn[i].base;
end = base + size - 1;
flags = rgn[i].flags;
- printf(" %s[%d]\t[0x%llx-0x%llx], 0x%08llx bytes flags: ",
+ printf(" %s[%d]\t[%#llx-%#llx], %#llx bytes, flags: ",
name, i, base, end, size);
lmb_print_region_flags(flags);
}
void lmb_add_memory(void)
{
int i;
+ phys_addr_t bank_end;
phys_size_t size;
u64 ram_top = gd->ram_top;
struct bd_info *bd = gd->bd;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
size = bd->bi_dram[i].size;
+ bank_end = bd->bi_dram[i].start + size;
+
if (size) {
lmb_add(bd->bi_dram[i].start, size);
if (bd->bi_dram[i].start >= ram_top)
lmb_reserve_flags(bd->bi_dram[i].start, size,
LMB_NOOVERWRITE);
+ else if (bank_end > ram_top)
+ lmb_reserve_flags(ram_top, bank_end - ram_top,
+ LMB_NOOVERWRITE);
}
}
}