]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
11fdf7f2 | 34 | #include "spdk/stdinc.h" |
7c673cae FG |
35 | |
36 | #include "CUnit/Basic.h" | |
37 | ||
11fdf7f2 TL |
38 | #include "env_dpdk/pci.c" |
39 | ||
7c673cae | 40 | static void |
9f95a23c | 41 | pci_claim_test(void) |
7c673cae FG |
42 | { |
43 | int rc = 0; | |
44 | pid_t childPid; | |
45 | int status, ret; | |
46 | struct spdk_pci_addr pci_addr; | |
47 | ||
48 | pci_addr.domain = 0x0; | |
49 | pci_addr.bus = 0x5; | |
50 | pci_addr.dev = 0x4; | |
51 | pci_addr.func = 1; | |
52 | ||
53 | rc = spdk_pci_device_claim(&pci_addr); | |
11fdf7f2 | 54 | CU_ASSERT(rc >= 0); |
7c673cae FG |
55 | |
56 | childPid = fork(); | |
57 | CU_ASSERT(childPid >= 0); | |
58 | if (childPid == 0) { | |
59 | ret = spdk_pci_device_claim(&pci_addr); | |
60 | CU_ASSERT(ret == -1); | |
61 | exit(0); | |
62 | } else { | |
63 | waitpid(childPid, &status, 0); | |
64 | } | |
65 | } | |
66 | ||
9f95a23c TL |
67 | static struct spdk_pci_driver ut_pci_driver = { |
68 | .is_registered = true, | |
69 | }; | |
70 | ||
71 | struct ut_pci_dev { | |
72 | struct spdk_pci_device pci; | |
73 | char config[16]; | |
74 | char bar[16]; | |
75 | bool attached; | |
76 | }; | |
77 | ||
78 | static int | |
79 | ut_map_bar(struct spdk_pci_device *dev, uint32_t bar, | |
80 | void **mapped_addr, uint64_t *phys_addr, uint64_t *size) | |
81 | { | |
82 | struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev; | |
83 | ||
84 | /* just one bar */ | |
85 | if (bar > 0) { | |
86 | return -1; | |
87 | } | |
88 | ||
89 | *mapped_addr = ut_dev->bar; | |
90 | *phys_addr = 0; | |
91 | *size = sizeof(ut_dev->bar); | |
92 | return 0; | |
93 | } | |
94 | ||
95 | static int | |
96 | ut_unmap_bar(struct spdk_pci_device *device, uint32_t bar, void *addr) | |
97 | { | |
98 | return 0; | |
99 | } | |
100 | ||
101 | static int | |
102 | ut_cfg_read(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset) | |
103 | { | |
104 | struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev; | |
105 | ||
106 | if (len + offset >= sizeof(ut_dev->config)) { | |
107 | return -1; | |
108 | } | |
109 | ||
110 | memcpy(value, (void *)((uintptr_t)ut_dev->config + offset), len); | |
111 | return 0; | |
112 | } | |
113 | ||
114 | static int ut_cfg_write(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset) | |
115 | { | |
116 | struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev; | |
117 | ||
118 | if (len + offset >= sizeof(ut_dev->config)) { | |
119 | return -1; | |
120 | } | |
121 | ||
122 | memcpy((void *)((uintptr_t)ut_dev->config + offset), value, len); | |
123 | return 0; | |
124 | } | |
125 | ||
126 | ||
127 | static int | |
128 | ut_enum_cb(void *ctx, struct spdk_pci_device *dev) | |
129 | { | |
130 | struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev; | |
131 | ||
132 | ut_dev->attached = true; | |
133 | return 0; | |
134 | } | |
135 | ||
136 | static void | |
137 | ut_detach(struct spdk_pci_device *dev) | |
138 | { | |
139 | struct ut_pci_dev *ut_dev = (struct ut_pci_dev *)dev; | |
140 | ||
141 | ut_dev->attached = false; | |
142 | } | |
143 | ||
144 | static void | |
145 | pci_hook_test(void) | |
146 | { | |
147 | struct ut_pci_dev ut_dev = {}; | |
148 | uint32_t value_32; | |
149 | void *bar0_vaddr; | |
150 | uint64_t bar0_paddr, bar0_size; | |
151 | int rc; | |
152 | ||
153 | ut_dev.pci.addr.domain = 0x10000; | |
154 | ut_dev.pci.addr.bus = 0x0; | |
155 | ut_dev.pci.addr.dev = 0x1; | |
156 | ut_dev.pci.addr.func = 0x0; | |
157 | ut_dev.pci.id.vendor_id = 0x4; | |
158 | ut_dev.pci.id.device_id = 0x8; | |
159 | ||
160 | ut_dev.pci.map_bar = ut_map_bar; | |
161 | ut_dev.pci.unmap_bar = ut_unmap_bar; | |
162 | ut_dev.pci.cfg_read = ut_cfg_read; | |
163 | ut_dev.pci.cfg_write = ut_cfg_write; | |
164 | ut_dev.pci.detach = ut_detach; | |
165 | ||
166 | /* hook the device into the PCI layer */ | |
167 | spdk_pci_hook_device(&ut_pci_driver, &ut_dev.pci); | |
168 | ||
169 | /* try to attach a device with the matching driver and bdf */ | |
170 | rc = spdk_pci_device_attach(&ut_pci_driver, ut_enum_cb, NULL, &ut_dev.pci.addr); | |
171 | CU_ASSERT(rc == 0); | |
172 | CU_ASSERT(ut_dev.pci.internal.attached); | |
173 | CU_ASSERT(ut_dev.attached); | |
174 | ||
175 | /* check PCI config writes and reads */ | |
176 | value_32 = 0xDEADBEEF; | |
177 | rc = spdk_pci_device_cfg_write32(&ut_dev.pci, value_32, 0); | |
178 | CU_ASSERT(rc == 0); | |
179 | ||
180 | value_32 = 0x0BADF00D; | |
181 | rc = spdk_pci_device_cfg_write32(&ut_dev.pci, value_32, 4); | |
182 | CU_ASSERT(rc == 0); | |
183 | ||
184 | rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, 0); | |
185 | CU_ASSERT(rc == 0); | |
186 | CU_ASSERT(value_32 == 0xDEADBEEF); | |
187 | CU_ASSERT(memcmp(&value_32, &ut_dev.config[0], 4) == 0); | |
188 | ||
189 | rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, 4); | |
190 | CU_ASSERT(rc == 0); | |
191 | CU_ASSERT(value_32 == 0x0BADF00D); | |
192 | CU_ASSERT(memcmp(&value_32, &ut_dev.config[4], 4) == 0); | |
193 | ||
194 | /* out-of-bounds write */ | |
195 | rc = spdk_pci_device_cfg_read32(&ut_dev.pci, &value_32, sizeof(ut_dev.config)); | |
196 | CU_ASSERT(rc != 0); | |
197 | ||
198 | /* map a bar */ | |
199 | rc = spdk_pci_device_map_bar(&ut_dev.pci, 0, &bar0_vaddr, &bar0_paddr, &bar0_size); | |
200 | CU_ASSERT(rc == 0); | |
201 | CU_ASSERT(bar0_vaddr == ut_dev.bar); | |
202 | CU_ASSERT(bar0_size == sizeof(ut_dev.bar)); | |
203 | spdk_pci_device_unmap_bar(&ut_dev.pci, 0, bar0_vaddr); | |
204 | ||
205 | /* map an inaccessible bar */ | |
206 | rc = spdk_pci_device_map_bar(&ut_dev.pci, 1, &bar0_vaddr, &bar0_paddr, &bar0_size); | |
207 | CU_ASSERT(rc != 0); | |
208 | ||
209 | /* detach and verify our callback was called */ | |
210 | spdk_pci_device_detach(&ut_dev.pci); | |
211 | CU_ASSERT(!ut_dev.attached); | |
212 | CU_ASSERT(!ut_dev.pci.internal.attached); | |
213 | ||
214 | /* unhook the device */ | |
215 | spdk_pci_unhook_device(&ut_dev.pci); | |
216 | ||
217 | /* try to attach the same device again */ | |
218 | rc = spdk_pci_device_attach(&ut_pci_driver, ut_enum_cb, NULL, &ut_dev.pci.addr); | |
219 | CU_ASSERT(rc != 0); | |
220 | } | |
221 | ||
7c673cae FG |
222 | int main(int argc, char **argv) |
223 | { | |
224 | CU_pSuite suite = NULL; | |
225 | unsigned int num_failures; | |
226 | ||
227 | if (CU_initialize_registry() != CUE_SUCCESS) { | |
228 | return CU_get_error(); | |
229 | } | |
230 | ||
231 | suite = CU_add_suite("pci", NULL, NULL); | |
232 | if (suite == NULL) { | |
233 | CU_cleanup_registry(); | |
234 | return CU_get_error(); | |
235 | } | |
236 | ||
237 | if ( | |
9f95a23c TL |
238 | CU_add_test(suite, "pci_claim", pci_claim_test) == NULL || |
239 | CU_add_test(suite, "pci_hook", pci_hook_test) == NULL | |
7c673cae FG |
240 | ) { |
241 | CU_cleanup_registry(); | |
242 | return CU_get_error(); | |
243 | } | |
244 | ||
245 | CU_basic_set_mode(CU_BRM_VERBOSE); | |
246 | CU_basic_run_tests(); | |
247 | num_failures = CU_get_number_of_failures(); | |
248 | CU_cleanup_registry(); | |
249 | return num_failures; | |
250 | } |