]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/test/env/pci/pci_ut.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / test / env / pci / pci_ut.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "spdk/stdinc.h"
35
36 #include "CUnit/Basic.h"
37 #include "spdk_internal/mock.h"
38
39 #include "env_dpdk/pci.c"
40
41 static void
42 pci_claim_test(struct spdk_pci_device *dev)
43 {
44 int rc = 0;
45 pid_t childPid;
46 int status, ret;
47
48 rc = spdk_pci_device_claim(dev);
49 CU_ASSERT(rc >= 0);
50
51 childPid = fork();
52 CU_ASSERT(childPid >= 0);
53 if (childPid == 0) {
54 ret = spdk_pci_device_claim(dev);
55 CU_ASSERT(ret == -1);
56 exit(0);
57 } else {
58 waitpid(childPid, &status, 0);
59 }
60 }
61
62 static struct spdk_pci_driver ut_pci_driver;
63
64 struct ut_pci_dev {
65 struct spdk_pci_device pci;
66 char config[16];
67 char bar[16];
68 bool attached;
69 };
70
71 static int
72 ut_map_bar(struct spdk_pci_device *dev, uint32_t bar,
73 void **mapped_addr, uint64_t *phys_addr, uint64_t *size)
74 {
75 struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev;
76
77 /* just one bar */
78 if (bar > 0) {
79 return -1;
80 }
81
82 *mapped_addr = ut_dev->bar;
83 *phys_addr = 0;
84 *size = sizeof(ut_dev->bar);
85 return 0;
86 }
87
88 static int
89 ut_unmap_bar(struct spdk_pci_device *device, uint32_t bar, void *addr)
90 {
91 return 0;
92 }
93
94 static int
95 ut_cfg_read(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset)
96 {
97 struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev;
98
99 if (len + offset >= sizeof(ut_dev->config)) {
100 return -1;
101 }
102
103 memcpy(value, (void *)((uintptr_t)ut_dev->config + offset), len);
104 return 0;
105 }
106
107 static int ut_cfg_write(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset)
108 {
109 struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev;
110
111 if (len + offset >= sizeof(ut_dev->config)) {
112 return -1;
113 }
114
115 memcpy((void *)((uintptr_t)ut_dev->config + offset), value, len);
116 return 0;
117 }
118
119
120 static int
121 ut_enum_cb(void *ctx, struct spdk_pci_device *dev)
122 {
123 struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev;
124
125 ut_dev->attached = true;
126 return 0;
127 }
128
129 static void
130 pci_hook_test(void)
131 {
132 struct ut_pci_dev ut_dev = {};
133 uint32_t value_32;
134 void *bar0_vaddr;
135 uint64_t bar0_paddr, bar0_size;
136 int rc;
137
138 ut_dev.pci.type = "custom";
139 ut_dev.pci.id.vendor_id = 0x4;
140 ut_dev.pci.id.device_id = 0x8;
141
142 /* Use add parse for initilization */
143 spdk_pci_addr_parse(&ut_dev.pci.addr, "10000:00:01.0");
144 CU_ASSERT(ut_dev.pci.addr.domain == 0x10000);
145 CU_ASSERT(ut_dev.pci.addr.bus == 0x0);
146 CU_ASSERT(ut_dev.pci.addr.dev == 0x1);
147 CU_ASSERT(ut_dev.pci.addr.func == 0x0);
148
149 ut_dev.pci.map_bar = ut_map_bar;
150 ut_dev.pci.unmap_bar = ut_unmap_bar;
151 ut_dev.pci.cfg_read = ut_cfg_read;
152 ut_dev.pci.cfg_write = ut_cfg_write;
153
154 /* hook the device into the PCI layer */
155 spdk_pci_hook_device(&ut_pci_driver, &ut_dev.pci);
156
157 /* try to attach a device with the matching driver and bdf */
158 rc = spdk_pci_device_attach(&ut_pci_driver, ut_enum_cb, NULL, &ut_dev.pci.addr);
159 CU_ASSERT(rc == 0);
160 CU_ASSERT(ut_dev.pci.internal.attached);
161 CU_ASSERT(ut_dev.attached);
162
163 /* check PCI config writes and reads */
164 value_32 = 0xDEADBEEF;
165 rc = spdk_pci_device_cfg_write32(&ut_dev.pci, value_32, 0);
166 CU_ASSERT(rc == 0);
167
168 value_32 = 0x0BADF00D;
169 rc = spdk_pci_device_cfg_write32(&ut_dev.pci, value_32, 4);
170 CU_ASSERT(rc == 0);
171
172 rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, 0);
173 CU_ASSERT(rc == 0);
174 CU_ASSERT(value_32 == 0xDEADBEEF);
175 CU_ASSERT(memcmp(&value_32, &ut_dev.config[0], 4) == 0);
176
177 rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, 4);
178 CU_ASSERT(rc == 0);
179 CU_ASSERT(value_32 == 0x0BADF00D);
180 CU_ASSERT(memcmp(&value_32, &ut_dev.config[4], 4) == 0);
181
182 /* out-of-bounds write */
183 rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, sizeof(ut_dev.config));
184 CU_ASSERT(rc != 0);
185
186 /* map a bar */
187 rc = spdk_pci_device_map_bar(&ut_dev.pci, 0, &bar0_vaddr, &bar0_paddr, &bar0_size);
188 CU_ASSERT(rc == 0);
189 CU_ASSERT(bar0_vaddr == ut_dev.bar);
190 CU_ASSERT(bar0_size == sizeof(ut_dev.bar));
191 spdk_pci_device_unmap_bar(&ut_dev.pci, 0, bar0_vaddr);
192
193 /* map an inaccessible bar */
194 rc = spdk_pci_device_map_bar(&ut_dev.pci, 1, &bar0_vaddr, &bar0_paddr, &bar0_size);
195 CU_ASSERT(rc != 0);
196
197 /* test spdk_pci_device_claim() */
198 pci_claim_test(&ut_dev.pci);
199
200 spdk_pci_device_detach(&ut_dev.pci);
201 CU_ASSERT(!ut_dev.pci.internal.attached);
202
203 /* unhook the device */
204 spdk_pci_unhook_device(&ut_dev.pci);
205
206 /* try to attach the same device again */
207 rc = spdk_pci_device_attach(&ut_pci_driver, ut_enum_cb, NULL, &ut_dev.pci.addr);
208 CU_ASSERT(rc != 0);
209 }
210
211 int main(int argc, char **argv)
212 {
213 CU_pSuite suite = NULL;
214 unsigned int num_failures;
215
216 if (CU_initialize_registry() != CUE_SUCCESS) {
217 return CU_get_error();
218 }
219
220 suite = CU_add_suite("pci", NULL, NULL);
221 if (suite == NULL) {
222 CU_cleanup_registry();
223 return CU_get_error();
224 }
225
226 if (
227 CU_add_test(suite, "pci_hook", pci_hook_test) == NULL
228 ) {
229 CU_cleanup_registry();
230 return CU_get_error();
231 }
232
233 CU_basic_set_mode(CU_BRM_VERBOSE);
234 CU_basic_run_tests();
235 num_failures = CU_get_number_of_failures();
236 CU_cleanup_registry();
237 return num_failures;
238 }