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