1 /*
2  * Copyright (C) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <sys/mman.h>
19 #include <sys/ioctl.h>
20 
21 #include "ion_test_fixture.h"
22 #include "ion_test_define.h"
23 
24 static const size_t allocation_sizes[] = {
25     mkb(16, 716), mkb(12, 4), mkb(8, 912), mkb(4, 60), mkb(2, 520), mkb(1, 92),
26     mb(16), mb(12), mb(8), mb(4), mb(2), mb(1), kb(64), kb(4),
27 };
28 
flushShrinker(const char * heapname)29 void flushShrinker(const char *heapname) {
30     std::string pathname = "/sys/kernel/debug/";
31 
32     pathname += heapname;
33     pathname += "_shrink";
34 
35     int fd = open(pathname.c_str(), O_RDWR);
36     if (fd < 0)
37         return;
38 
39     unsigned long val = mb(256); // This is very big enough to flush shrinker
40     if (write(fd, &val, sizeof(val)) < 0)
41         FAIL() << "Failed to write " << val << " to '" << heapname << "_shrink': " << strerror(errno);
42     if (read(fd, &val, sizeof(val)) < 0)
43         FAIL() << "Failed to read from '" << heapname << "_shrink': " << strerror(errno);
44     if (val > 0)
45         FAIL() << heapname << "_shrink still has value " << val;
46     close(fd);
47 }
48 
49 class PhysTest : public IonSpecialTest {
50 protected:
ionTestPhys(int fd,unsigned int cmd)51     void ionTestPhys(int fd, unsigned int cmd) {
52         int ret;
53 
54         EXPECT_EQ(0, ret = ioctl(getTestDevFd(), ION_IOC_TEST_SET_FD, fd));
55 
56         if (ret == 0) {
57             ion_test_phys_data data;
58             data.cmd = cmd;
59             data.arg = 0;
60             data.result = 0;
61 
62             EXPECT_EQ(0, ioctl(getTestDevFd(), ION_IOC_TEST_PHYS, &data));
63 
64             EXPECT_EQ(0, ioctl(getTestDevFd(), ION_IOC_TEST_SET_FD, -1));
65         }
66     }
67 };
68 
TEST_F(PhysTest,Carveout)69 TEST_F(PhysTest, Carveout)
70 {
71     for (unsigned int i = 0; i < getHeapCount(); i++) {
72         if (getHeapType(i) != ION_HEAP_TYPE_CARVEOUT)
73             continue;
74 
75         for (size_t size : allocation_sizes) {
76             if (size > getHeapSize(i))
77                 continue;
78 
79             int fd = ionAlloc(size, getHeapMask(i), 0);
80 
81             SCOPED_TRACE(::testing::Message() << "heap " << getHeapName(i) << " mask " << getHeapMask(i));
82             SCOPED_TRACE(::testing::Message() << "size " << size);
83 
84             EXPECT_LT(2, fd);
85             EXPECT_GT(1024, fd);
86 
87             ionTestPhys(fd, PHYS_IS_RESERVED);
88 
89             EXPECT_EQ(0, close(fd));
90         }
91     }
92 }
93 
TEST_F(PhysTest,Cma)94 TEST_F(PhysTest, Cma)
95 {
96     for (unsigned int i = 0; i < getHeapCount(); i++) {
97         if (getCmaUsed(getHeapName(i)) > 0)
98             continue;
99 
100         if (getHeapType(i) != ION_HEAP_TYPE_DMA)
101             continue;
102 
103         for (size_t size : allocation_sizes) {
104             if (size > getHeapSize(i))
105                 continue;
106 
107             int fd = ionAlloc(size, getHeapMask(i), 0);
108 
109             SCOPED_TRACE(::testing::Message() << "heap " << getHeapName(i) << " mask " << getHeapMask(i));
110             SCOPED_TRACE(::testing::Message() << "size " << size);
111 
112             EXPECT_LT(2, fd);
113             EXPECT_GT(1024, fd);
114 
115             ionTestPhys(fd, PHYS_IS_CMA);
116 
117             EXPECT_EQ(0, close(fd));
118         }
119     }
120 }
121 
TEST_F(PhysTest,Hpa)122 TEST_F(PhysTest, Hpa)
123 {
124     for (unsigned int i = 0; i < getHeapCount(); i++) {
125         if (getHeapType(i) != ION_HEAP_TYPE_CARVEOUT)
126             continue;
127 
128         for (size_t size : allocation_sizes) {
129             if (getHeapFlags(i) & ION_HEAPDATA_FLAGS_DEFER_FREE)
130                 flushShrinker(getHeapName(i));
131 
132             int fd = ionAlloc(size, getHeapMask(i), 0);
133 
134             SCOPED_TRACE(::testing::Message() << "heap " << getHeapName(i) << " mask " << getHeapMask(i));
135             SCOPED_TRACE(::testing::Message() << "size " << size);
136 
137             EXPECT_LT(2, fd);
138             EXPECT_GT(1024, fd);
139 
140             ionTestPhys(fd, PHYS_CHUNK_IS_IDENTICAL_SIZE);
141             ionTestPhys(fd, PHYS_IS_ORDERED_IN_ADDRESS);
142 
143             EXPECT_EQ(0, close(fd));
144         }
145     }
146 }
147