xref: /device/qemu/drivers/char/mmz/mmz.c (revision d6aed566)
1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 *    conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 *    of conditions and the following disclaimer in the documentation and/or other materials
13 *    provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 *    to endorse or promote products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "mmz.h"
33#include "fcntl.h"
34#include "fs/driver.h"
35#include "los_vm_map.h"
36#include "los_vm_phys.h"
37#include "los_vm_lock.h"
38#include "los_hw.h"
39#include "los_atomic.h"
40#include "los_vm_common.h"
41#include "los_process_pri.h"
42#include "target_config.h"
43
44static int MmzOpen(struct file *filep)
45{
46    return 0;
47}
48
49static int MmzClose(struct file *filep)
50{
51    return 0;
52}
53
54static ssize_t MmzAlloc(int cmd, unsigned long arg)
55{
56    UINT32 vmFlags = VM_MAP_REGION_FLAG_PERM_USER |
57                     VM_MAP_REGION_FLAG_PERM_READ |
58                     VM_MAP_REGION_FLAG_PERM_WRITE;
59    STATUS_T status;
60    MmzMemory *mmzm = (MmzMemory *)arg;
61    LosVmSpace *curVmSpace = OsCurrProcessGet()->vmSpace;
62    LosVmMapRegion *vmRegion;
63    VOID *kvaddr;
64    PADDR_T paddr;
65    VADDR_T vaddr;
66    UINT32 size = ROUNDUP(mmzm->size, PAGE_SIZE);
67    LosVmPage *vmPage = NULL;
68
69    switch (cmd) {
70        case MMZ_CACHE_TYPE:
71            vmFlags |= VM_MAP_REGION_FLAG_CACHED;
72            break;
73        case MMZ_NOCACHE_TYPE:
74            vmFlags |= VM_MAP_REGION_FLAG_UNCACHED;
75            break;
76        default:
77            PRINT_ERR("%s %d: %d\n", __func__, __LINE__, cmd);
78            return -EINVAL;
79    }
80    vmRegion = LOS_RegionAlloc(curVmSpace, 0, size, vmFlags, 0);
81    if (vmRegion == NULL) {
82        PRINT_ERR("cmd: %d, size: %#x vaddr alloc failed\n", cmd, size);
83        return -ENOMEM;
84    }
85
86    kvaddr = (void *)LOS_PhysPagesAllocContiguous(size >> PAGE_SHIFT);
87    if (kvaddr == NULL) {
88        LOS_RegionFree(curVmSpace, vmRegion);
89        PRINT_ERR("size: %#x paddr alloc failed\n", size);
90        return -ENOMEM;
91    }
92
93    paddr = LOS_PaddrQuery(kvaddr);
94    mmzm->paddr = paddr;
95    vaddr = vmRegion->range.base;
96    while (size > 0) {
97        vmPage = LOS_VmPageGet(paddr);
98        if (vmPage == NULL) {
99            LOS_RegionFree(curVmSpace, vmRegion);
100            VM_ERR("Page is NULL");
101            return -EINVAL;
102        }
103        LOS_AtomicInc(&vmPage->refCounts);
104
105        status = LOS_ArchMmuMap(&curVmSpace->archMmu, vaddr, paddr, 1, vmFlags);
106        if (status <= 0) {
107            VM_ERR("LOS_ArchMmuMap failed: %d", status);
108            LOS_RegionFree(curVmSpace, vmRegion);
109            return status;
110        }
111
112        paddr += PAGE_SIZE;
113        vaddr += PAGE_SIZE;
114        size -= PAGE_SIZE;
115    }
116    mmzm->vaddr = (void *)vmRegion->range.base;
117    return LOS_OK;
118}
119
120static ssize_t MmzMap(int cmd, unsigned long arg)
121{
122    UINT32 vmFlags = VM_MAP_REGION_FLAG_PERM_USER |
123                     VM_MAP_REGION_FLAG_PERM_READ |
124                     VM_MAP_REGION_FLAG_PERM_WRITE;
125    MmzMemory *mmzm = (MmzMemory *)arg;
126    LosVmSpace *curVmSpace = OsCurrProcessGet()->vmSpace;
127    LosVmMapRegion *vmRegion = NULL;
128    STATUS_T status = LOS_OK;
129    PADDR_T paddr = (PADDR_T)mmzm->paddr;
130    UINT32 size = ROUNDUP(mmzm->size, PAGE_SIZE);
131    VADDR_T vaddr;
132    LosVmPage *vmPage = NULL;
133
134    switch (cmd) {
135        case MMZ_MAP_CACHE_TYPE:
136            vmFlags |= VM_MAP_REGION_FLAG_CACHED;
137            break;
138        case MMZ_MAP_NOCACHE_TYPE:
139            vmFlags |= VM_MAP_REGION_FLAG_UNCACHED;
140            break;
141        default:
142            PRINT_ERR("%s %d: %d\n", __func__, __LINE__, cmd);
143            return -EINVAL;
144    }
145
146    vmRegion = LOS_RegionAlloc(curVmSpace, 0, size, vmFlags, 0);
147    if (vmRegion == NULL) {
148        PRINT_ERR("cmd: %d, size: %#x vaddr alloc failed\n", cmd, size);
149        return -ENOMEM;
150    }
151
152    mmzm->vaddr = (void *)vmRegion->range.base;
153    vaddr = vmRegion->range.base;
154    while (size > 0) {
155        vmPage = LOS_VmPageGet(paddr);
156        if (vmPage == NULL) {
157            LOS_RegionFree(curVmSpace, vmRegion);
158            VM_ERR("Page is NULL");
159            return -EINVAL;
160        }
161        LOS_AtomicInc(&vmPage->refCounts);
162
163        status = LOS_ArchMmuMap(&curVmSpace->archMmu, vaddr, paddr, 1,
164                vmRegion->regionFlags);
165        if (status <= 0) {
166            VM_ERR("LOS_ArchMmuMap failed: %d", status);
167            LOS_RegionFree(curVmSpace, vmRegion);
168            return status;
169        }
170
171        paddr += PAGE_SIZE;
172        vaddr += PAGE_SIZE;
173        size -= PAGE_SIZE;
174    }
175
176    return status;
177}
178
179static ssize_t MmzUnMap(unsigned long arg)
180{
181    LosVmSpace *curVmSpace = OsCurrProcessGet()->vmSpace;
182    MmzMemory *mmzm = (MmzMemory *)arg;
183    return OsUnMMap(curVmSpace, (VADDR_T)mmzm->vaddr, mmzm->size);
184}
185
186static ssize_t MmzFree(unsigned long arg)
187{
188    MmzMemory *mmzm = (MmzMemory *)arg;
189    LosVmSpace *curVmSpace = OsCurrProcessGet()->vmSpace;
190    LosVmMapRegion *region = NULL;
191    STATUS_T ret = LOS_OK;
192
193    (VOID)LOS_MuxAcquire(&curVmSpace->regionMux);
194    if ((PADDR_T)mmzm->paddr != LOS_PaddrQuery(mmzm->vaddr)) {
195        PRINT_ERR("vaddr is not equal to paddr");
196        ret = -EINVAL;
197        goto DONE;
198    }
199
200    region = LOS_RegionFind(curVmSpace, (VADDR_T)(unsigned int)mmzm->vaddr);
201    if (region == NULL) {
202        PRINT_ERR("find region failed");
203        ret = -EINVAL;
204        goto DONE;
205    }
206
207    ret = LOS_RegionFree(curVmSpace, region);
208    if (ret) {
209        PRINT_ERR("free region failed, ret = %d", ret);
210        ret = -EINVAL;
211    }
212
213DONE:
214    (VOID)LOS_MuxRelease(&curVmSpace->regionMux);
215    return ret;
216}
217
218static ssize_t MmzFlush(unsigned long arg)
219{
220    MmzMemory *mmzm = (MmzMemory *)arg;
221    DCacheFlushRange((unsigned int)mmzm->vaddr, (UINT32)mmzm->vaddr + mmzm->size);
222    return LOS_OK;
223}
224
225static ssize_t MmzInvalidate(unsigned long arg)
226{
227    MmzMemory *mmzm = (MmzMemory *)arg;
228    DCacheInvRange((unsigned int)mmzm->vaddr, (UINT32)mmzm->vaddr + mmzm->size);
229    return LOS_OK;
230}
231
232static ssize_t MmzIoctl(struct file *filep, int cmd, unsigned long arg)
233{
234    switch (cmd) {
235        case MMZ_CACHE_TYPE:
236        case MMZ_NOCACHE_TYPE:
237            return MmzAlloc(cmd, arg);
238        case MMZ_FREE_TYPE:
239            return MmzFree(arg);
240        case MMZ_MAP_CACHE_TYPE:
241        case MMZ_MAP_NOCACHE_TYPE:
242            return MmzMap(cmd, arg);
243        case MMZ_UNMAP_TYPE:
244            return MmzUnMap(arg);
245        case MMZ_FLUSH_CACHE_TYPE:
246        case MMZ_FLUSH_NOCACHE_TYPE:
247            return MmzFlush(arg);
248        case MMZ_INVALIDATE_TYPE:
249            return MmzInvalidate(arg);
250        default:
251            PRINT_ERR("%s %d: %d\n", __func__, __LINE__, cmd);
252            return -EINVAL;
253    }
254    return LOS_OK;
255}
256
257static const struct file_operations_vfs g_mmzDevOps = {
258    .open = MmzOpen, /* open */
259    .close = MmzClose, /* close */
260    .ioctl = MmzIoctl, /* ioctl */
261};
262
263int DevMmzRegister(void)
264{
265    return register_driver(MMZ_NODE, &g_mmzDevOps, 0666, 0); /* 0666: file mode */
266}
267