Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2021 Marvell.
3 : : */
4 : :
5 : : #include <fcntl.h>
6 : : #include <sys/ioctl.h>
7 : : #include <sys/stat.h>
8 : : #include <unistd.h>
9 : :
10 : : #include <rte_cycles.h>
11 : : #include <rte_rawdev.h>
12 : : #include <rte_rawdev_pmd.h>
13 : : #include <rte_service.h>
14 : :
15 : : #include "cnxk_gpio.h"
16 : : #include "rte_pmd_cnxk_gpio.h"
17 : :
18 : : #define CNXK_GPIO_BUFSZ 128
19 : :
20 : : #define OTX_IOC_MAGIC 0xF2
21 : : #define OTX_IOC_TRIGGER_GPIO_HANDLER \
22 : : _IO(OTX_IOC_MAGIC, 3)
23 : :
24 : : static int fd;
25 : :
26 : : static int
27 : : cnxk_gpio_attr_exists(const char *attr)
28 : : {
29 : : struct stat st;
30 : :
31 : 0 : return !stat(attr, &st);
32 : : }
33 : :
34 : : static int
35 : 0 : cnxk_gpio_read_attr(char *attr, char *val)
36 : : {
37 : : FILE *fp;
38 : : int ret;
39 : :
40 : 0 : fp = fopen(attr, "r");
41 [ # # ]: 0 : if (!fp)
42 : 0 : return -errno;
43 : :
44 : 0 : ret = fscanf(fp, "%s", val);
45 [ # # ]: 0 : if (ret < 0)
46 : 0 : return -errno;
47 [ # # ]: 0 : if (ret != 1)
48 : : return -EIO;
49 : :
50 : 0 : ret = fclose(fp);
51 [ # # ]: 0 : if (ret)
52 : 0 : return -errno;
53 : :
54 : : return 0;
55 : : }
56 : :
57 : : #define CNXK_GPIO_ERR_STR(err, str, ...) do { \
58 : : if (err) { \
59 : : RTE_LOG(ERR, PMD, "%s:%d: " str " (%d)\n", __func__, __LINE__, \
60 : : ##__VA_ARGS__, err); \
61 : : goto out; \
62 : : } \
63 : : } while (0)
64 : :
65 : : static int
66 : 0 : cnxk_gpio_validate_attr(char *attr, const char *expected)
67 : : {
68 : : char buf[CNXK_GPIO_BUFSZ];
69 : : int ret;
70 : :
71 : 0 : ret = cnxk_gpio_read_attr(attr, buf);
72 [ # # ]: 0 : if (ret)
73 : : return ret;
74 : :
75 [ # # ]: 0 : if (strncmp(buf, expected, sizeof(buf)))
76 : 0 : return -EIO;
77 : :
78 : : return 0;
79 : : }
80 : :
81 : : #define CNXK_GPIO_PATH_FMT "/sys/class/gpio/gpio%d"
82 : :
83 : : static int
84 : 0 : cnxk_gpio_test_input(uint16_t dev_id, int base, int gpio)
85 : : {
86 : : char buf[CNXK_GPIO_BUFSZ];
87 : : int ret, n;
88 : :
89 : 0 : n = snprintf(buf, sizeof(buf), CNXK_GPIO_PATH_FMT, base + gpio);
90 : 0 : snprintf(buf + n, sizeof(buf) - n, "/direction");
91 : :
92 : 0 : ret = rte_pmd_gpio_set_pin_dir(dev_id, gpio, CNXK_GPIO_PIN_DIR_IN);
93 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set dir to input");
94 : 0 : ret = cnxk_gpio_validate_attr(buf, "in");
95 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
96 : :
97 : 0 : ret = rte_pmd_gpio_set_pin_value(dev_id, gpio, 1) |
98 : 0 : rte_pmd_gpio_set_pin_value(dev_id, gpio, 0);
99 [ # # ]: 0 : if (!ret) {
100 : : ret = -EIO;
101 : 0 : CNXK_GPIO_ERR_STR(ret, "input pin overwritten");
102 : : }
103 : :
104 : : snprintf(buf + n, sizeof(buf) - n, "/edge");
105 : :
106 : 0 : ret = rte_pmd_gpio_set_pin_edge(dev_id, gpio,
107 : : CNXK_GPIO_PIN_EDGE_FALLING);
108 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set edge to falling");
109 : 0 : ret = cnxk_gpio_validate_attr(buf, "falling");
110 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
111 : :
112 : 0 : ret = rte_pmd_gpio_set_pin_edge(dev_id, gpio,
113 : : CNXK_GPIO_PIN_EDGE_RISING);
114 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to change edge to rising");
115 : 0 : ret = cnxk_gpio_validate_attr(buf, "rising");
116 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
117 : :
118 : 0 : ret = rte_pmd_gpio_set_pin_edge(dev_id, gpio, CNXK_GPIO_PIN_EDGE_BOTH);
119 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to change edge to both");
120 : 0 : ret = cnxk_gpio_validate_attr(buf, "both");
121 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
122 : :
123 : 0 : ret = rte_pmd_gpio_set_pin_edge(dev_id, gpio, CNXK_GPIO_PIN_EDGE_NONE);
124 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set edge to none");
125 : 0 : ret = cnxk_gpio_validate_attr(buf, "none");
126 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
127 : :
128 : : /*
129 : : * calling this makes sure kernel driver switches off inverted
130 : : * logic
131 : : */
132 : 0 : rte_pmd_gpio_set_pin_dir(dev_id, gpio, CNXK_GPIO_PIN_DIR_IN);
133 : :
134 : 0 : out:
135 : 0 : return ret;
136 : : }
137 : :
138 : : static int
139 : 0 : cnxk_gpio_trigger_irq(int gpio)
140 : : {
141 : : int ret;
142 : :
143 : 0 : ret = ioctl(fd, OTX_IOC_TRIGGER_GPIO_HANDLER, gpio);
144 : :
145 [ # # ]: 0 : return ret == -1 ? -errno : 0;
146 : : }
147 : :
148 : : static void
149 : 0 : cnxk_gpio_irq_handler(int gpio, void *data)
150 : : {
151 : 0 : *(int *)data = gpio;
152 : 0 : }
153 : :
154 : : static int
155 : 0 : cnxk_gpio_test_irq(uint16_t dev_id, int gpio)
156 : : {
157 : : int irq_data, ret;
158 : :
159 : 0 : ret = rte_pmd_gpio_set_pin_dir(dev_id, gpio, CNXK_GPIO_PIN_DIR_IN);
160 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set dir to input");
161 : :
162 : 0 : irq_data = 0;
163 : 0 : ret = rte_pmd_gpio_register_irq(dev_id, gpio, rte_lcore_id(),
164 : : cnxk_gpio_irq_handler, &irq_data);
165 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to register irq handler");
166 : :
167 : : ret = rte_pmd_gpio_enable_interrupt(dev_id, gpio,
168 : : CNXK_GPIO_PIN_EDGE_RISING);
169 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to enable interrupt");
170 : :
171 : 0 : ret = cnxk_gpio_trigger_irq(gpio);
172 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to trigger irq");
173 : : rte_delay_ms(1);
174 [ # # ]: 0 : ret = *(volatile int *)&irq_data == gpio ? 0 : -EIO;
175 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to test irq");
176 : :
177 : : ret = rte_pmd_gpio_disable_interrupt(dev_id, gpio);
178 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to disable interrupt");
179 : :
180 : 0 : ret = rte_pmd_gpio_unregister_irq(dev_id, gpio);
181 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to unregister irq handler");
182 : 0 : out:
183 : : rte_pmd_gpio_disable_interrupt(dev_id, gpio);
184 : 0 : rte_pmd_gpio_unregister_irq(dev_id, gpio);
185 : :
186 : 0 : return ret;
187 : : }
188 : :
189 : : static int
190 : 0 : cnxk_gpio_test_output(uint16_t dev_id, int base, int gpio)
191 : : {
192 : : char buf[CNXK_GPIO_BUFSZ];
193 : : int ret, val, n;
194 : :
195 : 0 : n = snprintf(buf, sizeof(buf), CNXK_GPIO_PATH_FMT, base + gpio);
196 : :
197 : 0 : snprintf(buf + n, sizeof(buf) - n, "/direction");
198 : 0 : ret = rte_pmd_gpio_set_pin_dir(dev_id, gpio, CNXK_GPIO_PIN_DIR_OUT);
199 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set dir to out");
200 : 0 : ret = cnxk_gpio_validate_attr(buf, "out");
201 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
202 : :
203 : : snprintf(buf + n, sizeof(buf) - n, "/value");
204 : 0 : ret = rte_pmd_gpio_set_pin_value(dev_id, gpio, 0);
205 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set value to 0");
206 : 0 : ret = cnxk_gpio_validate_attr(buf, "0");
207 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
208 : : ret = rte_pmd_gpio_get_pin_value(dev_id, gpio, &val);
209 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to read value");
210 [ # # ]: 0 : if (val)
211 : : ret = -EIO;
212 : 0 : CNXK_GPIO_ERR_STR(ret, "read %d instead of 0", val);
213 : :
214 : 0 : ret = rte_pmd_gpio_set_pin_value(dev_id, gpio, 1);
215 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set value to 1");
216 : 0 : ret = cnxk_gpio_validate_attr(buf, "1");
217 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
218 : : ret = rte_pmd_gpio_get_pin_value(dev_id, gpio, &val);
219 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to read value");
220 [ # # ]: 0 : if (val != 1)
221 : : ret = -EIO;
222 : 0 : CNXK_GPIO_ERR_STR(ret, "read %d instead of 1", val);
223 : :
224 : : snprintf(buf + n, sizeof(buf) - n, "/direction");
225 : 0 : ret = rte_pmd_gpio_set_pin_dir(dev_id, gpio, CNXK_GPIO_PIN_DIR_LOW);
226 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set dir to low");
227 : 0 : ret = cnxk_gpio_validate_attr(buf, "out");
228 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
229 : : snprintf(buf + n, sizeof(buf) - n, "/value");
230 : 0 : ret = cnxk_gpio_validate_attr(buf, "0");
231 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
232 : :
233 : : snprintf(buf + n, sizeof(buf) - n, "/direction");
234 : 0 : ret = rte_pmd_gpio_set_pin_dir(dev_id, gpio, CNXK_GPIO_PIN_DIR_HIGH);
235 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set dir to high");
236 : 0 : ret = cnxk_gpio_validate_attr(buf, "out");
237 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
238 : : snprintf(buf + n, sizeof(buf) - n, "/value");
239 : 0 : ret = cnxk_gpio_validate_attr(buf, "1");
240 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
241 : :
242 : : snprintf(buf + n, sizeof(buf) - n, "/edge");
243 : 0 : ret = rte_pmd_gpio_set_pin_edge(dev_id, gpio,
244 : : CNXK_GPIO_PIN_EDGE_FALLING);
245 : : ret = ret == 0 ? -EIO : 0;
246 : 0 : CNXK_GPIO_ERR_STR(ret, "changed edge to falling");
247 : 0 : ret = cnxk_gpio_validate_attr(buf, "none");
248 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
249 : :
250 : 0 : ret = rte_pmd_gpio_set_pin_edge(dev_id, gpio,
251 : : CNXK_GPIO_PIN_EDGE_RISING);
252 : : ret = ret == 0 ? -EIO : 0;
253 : 0 : CNXK_GPIO_ERR_STR(ret, "changed edge to rising");
254 : 0 : ret = cnxk_gpio_validate_attr(buf, "none");
255 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
256 : :
257 : 0 : ret = rte_pmd_gpio_set_pin_edge(dev_id, gpio, CNXK_GPIO_PIN_EDGE_BOTH);
258 : : ret = ret == 0 ? -EIO : 0;
259 : 0 : CNXK_GPIO_ERR_STR(ret, "changed edge to both");
260 : 0 : ret = cnxk_gpio_validate_attr(buf, "none");
261 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
262 : :
263 : : /* this one should succeed */
264 : 0 : ret = rte_pmd_gpio_set_pin_edge(dev_id, gpio, CNXK_GPIO_PIN_EDGE_NONE);
265 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to change edge to none");
266 : 0 : ret = cnxk_gpio_validate_attr(buf, "none");
267 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
268 : :
269 : : snprintf(buf + n, sizeof(buf) - n, "/active_low");
270 : 0 : ret = rte_pmd_gpio_set_pin_active_low(dev_id, gpio, 1);
271 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set active_low to 1");
272 : 0 : ret = cnxk_gpio_validate_attr(buf, "1");
273 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
274 : :
275 : 0 : ret = rte_pmd_gpio_get_pin_active_low(dev_id, gpio, &val);
276 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to read active_low");
277 [ # # ]: 0 : if (val != 1)
278 : : ret = -EIO;
279 : 0 : CNXK_GPIO_ERR_STR(ret, "read %d instead of 1", val);
280 : :
281 : : snprintf(buf + n, sizeof(buf) - n, "/value");
282 : 0 : ret = rte_pmd_gpio_set_pin_value(dev_id, gpio, 1);
283 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set value to 1");
284 : 0 : ret = cnxk_gpio_validate_attr(buf, "1");
285 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
286 : :
287 : 0 : ret = rte_pmd_gpio_set_pin_value(dev_id, gpio, 0);
288 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set value to 0");
289 : 0 : ret = cnxk_gpio_validate_attr(buf, "0");
290 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
291 : :
292 : : snprintf(buf + n, sizeof(buf) - n, "/active_low");
293 : 0 : ret = rte_pmd_gpio_set_pin_active_low(dev_id, gpio, 0);
294 : 0 : CNXK_GPIO_ERR_STR(ret, "failed to set active_low to 0");
295 : 0 : ret = cnxk_gpio_validate_attr(buf, "0");
296 [ # # ]: 0 : CNXK_GPIO_ERR_STR(ret, "failed to validate %s", buf);
297 : :
298 : 0 : out:
299 : 0 : return ret;
300 : : }
301 : :
302 : : int
303 : 0 : cnxk_gpio_selftest(uint16_t dev_id)
304 : : {
305 : : struct cnxk_gpio_queue_conf conf;
306 : : struct cnxk_gpiochip *gpiochip;
307 : : char buf[CNXK_GPIO_BUFSZ];
308 : : struct rte_rawdev *rawdev;
309 : : unsigned int queues, i;
310 : : struct cnxk_gpio *gpio;
311 : : int ret, ret2;
312 : :
313 : 0 : rawdev = rte_rawdev_pmd_get_named_dev("cnxk_gpio");
314 [ # # ]: 0 : if (!rawdev)
315 : : return -ENODEV;
316 : 0 : gpiochip = rawdev->dev_private;
317 : :
318 : 0 : queues = rte_rawdev_queue_count(dev_id);
319 [ # # ]: 0 : if (queues == 0)
320 : : return -ENODEV;
321 : :
322 : 0 : ret = rte_rawdev_start(dev_id);
323 [ # # ]: 0 : if (ret)
324 : : return ret;
325 : :
326 : 0 : fd = open("/dev/otx-gpio-ctr", O_RDWR | O_SYNC);
327 [ # # ]: 0 : if (fd < 0)
328 : 0 : return -errno;
329 : :
330 [ # # ]: 0 : for (i = 0; i < queues; i++) {
331 : 0 : ret = rte_rawdev_queue_conf_get(dev_id, i, &conf, sizeof(conf));
332 [ # # ]: 0 : if (ret) {
333 : 0 : RTE_LOG(ERR, PMD,
334 : : "failed to read queue configuration (%d)\n",
335 : : ret);
336 : 0 : goto out;
337 : : }
338 : :
339 : 0 : RTE_LOG(INFO, PMD, "testing queue%d (gpio%d)\n", i, conf.gpio);
340 : :
341 [ # # ]: 0 : if (conf.size != 1) {
342 : 0 : RTE_LOG(ERR, PMD, "wrong queue size received\n");
343 : : ret = -EIO;
344 : 0 : goto out;
345 : : }
346 : :
347 : 0 : ret = rte_rawdev_queue_setup(dev_id, i, NULL, 0);
348 [ # # ]: 0 : if (ret) {
349 : 0 : RTE_LOG(ERR, PMD, "failed to setup queue (%d)\n", ret);
350 : 0 : goto out;
351 : : }
352 : :
353 : 0 : gpio = gpiochip->gpios[conf.gpio];
354 : 0 : snprintf(buf, sizeof(buf), CNXK_GPIO_PATH_FMT, gpio->num);
355 [ # # ]: 0 : if (!cnxk_gpio_attr_exists(buf)) {
356 : 0 : RTE_LOG(ERR, PMD, "%s does not exist\n", buf);
357 : : ret = -ENOENT;
358 : 0 : goto release;
359 : : }
360 : :
361 : 0 : ret = cnxk_gpio_test_input(dev_id, gpiochip->base, conf.gpio);
362 [ # # ]: 0 : if (ret)
363 : 0 : goto release;
364 : :
365 : 0 : ret = cnxk_gpio_test_irq(dev_id, conf.gpio);
366 [ # # ]: 0 : if (ret)
367 : 0 : goto release;
368 : :
369 : 0 : ret = cnxk_gpio_test_output(dev_id, gpiochip->base, conf.gpio);
370 : 0 : release:
371 : : ret2 = ret;
372 : 0 : ret = rte_rawdev_queue_release(dev_id, i);
373 [ # # ]: 0 : if (ret) {
374 : 0 : RTE_LOG(ERR, PMD, "failed to release queue (%d)\n",
375 : : ret);
376 : 0 : break;
377 : : }
378 : :
379 [ # # ]: 0 : if (cnxk_gpio_attr_exists(buf)) {
380 : 0 : RTE_LOG(ERR, PMD, "%s still exists\n", buf);
381 : : ret = -EIO;
382 : 0 : break;
383 : : }
384 : :
385 [ # # ]: 0 : if (ret2) {
386 : : ret = ret2;
387 : : break;
388 : : }
389 : : }
390 : :
391 : 0 : out:
392 : 0 : close(fd);
393 : 0 : rte_rawdev_stop(dev_id);
394 : :
395 : 0 : return ret;
396 : : }
|