1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <autoconf.h>
14#include <rumprun/gen_config.h>
15#include <bmk-core/types.h>
16#include <sel4/kernel.h>
17
18#include <bmk-core/pgalloc.h>
19#include <bmk-core/printf.h>
20#include <bmk-core/memalloc.h>
21
22#include <bmk-pcpu/pcpu.h>
23
24#include <platsupport/io.h>
25#include <sel4/helpers.h>
26#include <vspace/vspace.h>
27#include "pci_user.h"
28#include <assert.h>
29
30typedef struct a_list a_list_t;
31
32struct a_list {
33    uintptr_t vaddr;
34    uintptr_t paddr;
35    uintptr_t size;
36};
37#define LIST_LENGTH 30
38a_list_t list[LIST_LENGTH];
39
40int rumpcomp_pci_dmalloc(size_t size, size_t align,
41                         unsigned long *pap, unsigned long *vap)
42{
43    /* alloc and pin using platsupport implementation */
44    void *mem = ps_dma_alloc(&env.io_ops.dma_manager, size, align, 1, PS_MEM_NORMAL);
45    if (mem == NULL) {
46        return 1;
47    }
48    uintptr_t pmem = ps_dma_pin(&env.io_ops.dma_manager, mem, size);
49
50    if (pmem == 0) {
51        /* return error if cannot find paddr */
52        return 1;
53    }
54    /* Add entry to our inefficient entry array */
55    int i = 0;
56    for (i = 0; i < LIST_LENGTH; i++) {
57        if (list[i].vaddr == 0) {
58            break;
59        }
60    }
61    if (i == LIST_LENGTH) {
62        ZF_LOGD("\terror: no_free entries\n");
63        return 1;
64    }
65    list[i].vaddr = (uintptr_t) mem;
66    list[i].paddr = (uintptr_t) pmem;
67    list[i].size = size;
68    /* Return addresses */
69    *pap = (unsigned long)pmem;
70    *vap = (unsigned long)mem;
71
72    return 0;
73}
74
75/* We already mapped in with call above ds_vacookie is *vap return from
76    rumpcomp_pci_dmalloc. */
77int rumpcomp_pci_dmamem_map(struct rumpcomp_pci_dmaseg *dss, size_t nseg,
78                            size_t totlen, void **vap)
79{
80    *vap = (void *)dss[0].ds_vacookie;
81    return 0;
82}
83
84void rumpcomp_pci_dmafree(unsigned long mem, size_t size)
85{
86    /* Unpin and free from our platsupport impl */
87    ps_dma_unpin(&env.io_ops.dma_manager, (void *)mem, size);
88
89    ps_dma_free(&env.io_ops.dma_manager, (void *)mem, size);
90
91    /* Remove from our list */
92    int i;
93    for (i = 0; i < LIST_LENGTH; i++) {
94        if (list[i].vaddr == mem) {
95            break;
96        }
97    }
98    if (i == LIST_LENGTH) {
99        bmk_printf("\terror: cannot find entry\n");
100    }
101    list[i].vaddr = (uintptr_t) 0;
102    list[i].paddr = (uintptr_t) 0;
103    list[i].size = 0;
104}
105
106unsigned long rumpcomp_pci_virt_to_mach(void *virt)
107{
108    /* Try and find if its from something we mapped in previously. */
109    uintptr_t vin = (uintptr_t) virt;
110    for (int i = 0; i < LIST_LENGTH; i++) {
111        if (vin >= list[i].vaddr) {
112            if (vin < (list[i].vaddr + list[i].size)) {
113                return vin - list[i].vaddr + list[i].paddr;
114            }
115        }
116    }
117
118    /* Couldn't find above, try and find in the system allocators */
119    /* This likely means that the upper levels have an mbuf that was not allocated through rumpcomp_pci_dmalloc */
120    /* Apparently this behavior is fine. */
121    uintptr_t paddr = (uintptr_t) vka_utspace_paddr(&env.vka, vspace_get_cookie(&env.vspace, virt),
122                                                    env.rump_mapping_page_type, env.rump_mapping_page_size_bits);
123    return paddr + (vin & MASK((unsigned int) env.rump_mapping_page_size_bits));
124}
125