Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2021,2024-2025 NXP
3 : : */
4 : :
5 : : #include <stdbool.h>
6 : : #include <stdint.h>
7 : : #include <stdio.h>
8 : : #include <unistd.h>
9 : : #include <stdlib.h>
10 : : #include <dirent.h>
11 : : #include <string.h>
12 : : #include <sys/mman.h>
13 : : #include <errno.h>
14 : : #include <fcntl.h>
15 : :
16 : : #include <rte_common.h>
17 : : #include <rte_malloc.h>
18 : : #include "enet_pmd_logs.h"
19 : : #include "enet_uio.h"
20 : :
21 : : static struct uio_job enetfec_uio_job;
22 : : static int enetfec_count;
23 : :
24 : : /** @brief Checks if a file name contains a certain substring.
25 : : * This function assumes a filename format of: [text][number].
26 : : * @param [in] filename File name
27 : : * @param [in] match String to match in file name
28 : : *
29 : : * @retval true if file name matches the criteria
30 : : * @retval false if file name does not match the criteria
31 : : */
32 : : static bool
33 : : file_name_match_extract(const char filename[], const char match[])
34 : : {
35 : : char *substr = NULL;
36 : :
37 : 0 : substr = strstr(filename, match);
38 [ # # # # ]: 0 : if (substr == NULL)
39 : : return false;
40 : :
41 : : return true;
42 : : }
43 : :
44 : : /*
45 : : * @brief Reads first line from a file.
46 : : * Composes file name as: root/subdir/filename
47 : : *
48 : : * @param [in] root Root path
49 : : * @param [in] subdir Subdirectory name
50 : : * @param [in] filename File name
51 : : * @param [out] line The first line read from file.
52 : : *
53 : : * @retval 0 for success
54 : : * @retval other value for error
55 : : */
56 : : static int
57 : 0 : file_read_first_line(const char root[], const char subdir[],
58 : : const char filename[], char *line)
59 : : {
60 : : char absolute_file_name[FEC_UIO_MAX_ATTR_FILE_NAME];
61 : : int fd = 0, ret = 0;
62 : :
63 : : /*compose the file name: root/subdir/filename */
64 : : memset(absolute_file_name, 0, sizeof(absolute_file_name));
65 : : snprintf(absolute_file_name, FEC_UIO_MAX_ATTR_FILE_NAME,
66 : : "%s/%s/%s", root, subdir, filename);
67 : :
68 : : fd = open(absolute_file_name, O_RDONLY);
69 [ # # ]: 0 : if (fd < 0) {
70 : 0 : ENETFEC_PMD_ERR("Error opening file %s", absolute_file_name);
71 : 0 : return fd;
72 : : }
73 : :
74 : : /* read UIO device name from first line in file */
75 : 0 : ret = read(fd, line, FEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH);
76 [ # # ]: 0 : if (ret <= 0) {
77 : 0 : ENETFEC_PMD_ERR("Error reading file %s", absolute_file_name);
78 : 0 : close(fd);
79 : 0 : return ret;
80 : : }
81 : 0 : close(fd);
82 : :
83 : : /* NULL-ify string */
84 : 0 : line[ret] = '\0';
85 : :
86 : 0 : return 0;
87 : : }
88 : :
89 : : /*
90 : : * @brief Maps rx-tx bd range assigned for a bd ring.
91 : : *
92 : : * @param [in] uio_device_fd UIO device file descriptor
93 : : * @param [in] uio_device_id UIO device id
94 : : * @param [in] uio_map_id UIO allows maximum 5 different mapping for
95 : : each device. Maps start with id 0.
96 : : * @param [out] map_size Map size.
97 : : * @param [out] map_addr Map physical address
98 : : *
99 : : * @retval NULL if failed to map registers
100 : : * @retval Virtual address for mapped register address range
101 : : */
102 : : static void *
103 : 0 : uio_map_mem(int uio_device_fd, int uio_device_id,
104 : : int uio_map_id, int *map_size, uint64_t *map_addr)
105 : : {
106 : : void *mapped_address = NULL;
107 : : unsigned int uio_map_size = 0;
108 : : unsigned int uio_map_p_addr = 0;
109 : : char uio_sys_root[FEC_UIO_MAX_ATTR_FILE_NAME];
110 : : char uio_sys_map_subdir[FEC_UIO_MAX_ATTR_FILE_NAME];
111 : : char uio_map_size_str[FEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH + 1];
112 : : char uio_map_p_addr_str[32];
113 : : int ret = 0;
114 : :
115 : : /* compose the file name: root/subdir/filename */
116 : : memset(uio_sys_root, 0, sizeof(uio_sys_root));
117 : : memset(uio_sys_map_subdir, 0, sizeof(uio_sys_map_subdir));
118 : : memset(uio_map_size_str, 0, sizeof(uio_map_size_str));
119 : : memset(uio_map_p_addr_str, 0, sizeof(uio_map_p_addr_str));
120 : :
121 : : /* Compose string: /sys/class/uio/uioX */
122 : : snprintf(uio_sys_root, sizeof(uio_sys_root), "%s/%s%d",
123 : : FEC_UIO_DEVICE_SYS_ATTR_PATH, "uio", uio_device_id);
124 : : /* Compose string: maps/mapY */
125 : : snprintf(uio_sys_map_subdir, sizeof(uio_sys_map_subdir), "%s%d",
126 : : FEC_UIO_DEVICE_SYS_MAP_ATTR, uio_map_id);
127 : :
128 : : /* Read first (and only) line from file
129 : : * /sys/class/uio/uioX/maps/mapY/size
130 : : */
131 : 0 : ret = file_read_first_line(uio_sys_root, uio_sys_map_subdir,
132 : : "size", uio_map_size_str);
133 [ # # ]: 0 : if (ret < 0) {
134 : 0 : ENETFEC_PMD_ERR("file_read_first_line() failed");
135 : 0 : return NULL;
136 : : }
137 : 0 : ret = file_read_first_line(uio_sys_root, uio_sys_map_subdir,
138 : : "addr", uio_map_p_addr_str);
139 [ # # ]: 0 : if (ret < 0) {
140 : 0 : ENETFEC_PMD_ERR("file_read_first_line() failed");
141 : 0 : return NULL;
142 : : }
143 : : /* Read mapping size and physical address expressed in hexa(base 16) */
144 : 0 : uio_map_size = strtol(uio_map_size_str, NULL, 16);
145 [ # # ]: 0 : if (uio_map_size <= 0 || uio_map_size > INT_MAX) {
146 : 0 : ENETFEC_PMD_ERR("Invalid mapping size: %u.", uio_map_size);
147 : 0 : return NULL;
148 : : }
149 : 0 : uio_map_p_addr = strtol(uio_map_p_addr_str, NULL, 16);
150 : :
151 [ # # ]: 0 : if (uio_map_id == 0) {
152 : : /* Map the register address in user space when map_id is 0 */
153 : 0 : mapped_address = mmap(0 /*dynamically choose virtual address */,
154 : : uio_map_size, PROT_READ | PROT_WRITE,
155 : : MAP_SHARED, uio_device_fd, 0);
156 : : } else {
157 : : /* Map the BD memory in user space */
158 : 0 : mapped_address = mmap(NULL, uio_map_size,
159 : : PROT_READ | PROT_WRITE,
160 : : MAP_SHARED, uio_device_fd, (1 * MAP_PAGE_SIZE));
161 : : }
162 : :
163 [ # # ]: 0 : if (mapped_address == MAP_FAILED) {
164 : 0 : ENETFEC_PMD_ERR("Failed to map! errno = %d uio job fd = %d,"
165 : : "uio device id = %d, uio map id = %d", errno,
166 : : uio_device_fd, uio_device_id, uio_map_id);
167 : 0 : return NULL;
168 : : }
169 : :
170 : : /* Save the map size to use it later on for munmap-ing */
171 : 0 : *map_size = uio_map_size;
172 : 0 : *map_addr = uio_map_p_addr;
173 : 0 : ENETFEC_PMD_INFO("UIO dev[%d] mapped region [id =%d] size 0x%x at %p",
174 : : uio_device_id, uio_map_id, uio_map_size, mapped_address);
175 : :
176 : 0 : return mapped_address;
177 : : }
178 : :
179 : : int
180 : 0 : config_enetfec_uio(struct enetfec_private *fep)
181 : : {
182 : : char uio_device_file_name[32];
183 : : struct uio_job *uio_job = NULL;
184 : :
185 : : /* Mapping is done only one time */
186 [ # # ]: 0 : if (enetfec_count > 0) {
187 : 0 : ENETFEC_PMD_INFO("Mapped!");
188 : 0 : return 0;
189 : : }
190 : :
191 : : uio_job = &enetfec_uio_job;
192 : :
193 : : /* Find UIO device created by ENETFEC-UIO kernel driver */
194 : : memset(uio_device_file_name, 0, sizeof(uio_device_file_name));
195 : 0 : snprintf(uio_device_file_name, sizeof(uio_device_file_name), "%s%d",
196 : : FEC_UIO_DEVICE_FILE_NAME, uio_job->uio_minor_number);
197 : :
198 : : /* Open device file */
199 : 0 : uio_job->uio_fd = open(uio_device_file_name, O_RDWR);
200 [ # # ]: 0 : if (uio_job->uio_fd < 0) {
201 : 0 : ENETFEC_PMD_WARN("Unable to open ENETFEC_UIO file");
202 : 0 : return -1;
203 : : }
204 : :
205 : 0 : ENETFEC_PMD_INFO("US_UIO: Open device(%s) file with uio_fd = %d",
206 : : uio_device_file_name, uio_job->uio_fd);
207 : :
208 : 0 : fep->hw_baseaddr_v = uio_map_mem(uio_job->uio_fd,
209 : : uio_job->uio_minor_number, FEC_UIO_REG_MAP_ID,
210 : : &uio_job->map_size, &uio_job->map_addr);
211 [ # # ]: 0 : if (fep->hw_baseaddr_v == NULL)
212 : : return -ENOMEM;
213 : 0 : fep->hw_baseaddr_p = uio_job->map_addr;
214 : 0 : fep->reg_size = uio_job->map_size;
215 : :
216 : 0 : fep->bd_addr_v = uio_map_mem(uio_job->uio_fd,
217 : : uio_job->uio_minor_number, FEC_UIO_BD_MAP_ID,
218 : : &uio_job->map_size, &uio_job->map_addr);
219 [ # # ]: 0 : if (fep->hw_baseaddr_v == NULL)
220 : : return -ENOMEM;
221 : 0 : fep->bd_addr_p = (uint32_t)uio_job->map_addr;
222 : 0 : fep->bd_size = uio_job->map_size;
223 : :
224 : 0 : enetfec_count++;
225 : :
226 : 0 : return 0;
227 : : }
228 : :
229 : : int
230 : 0 : enetfec_configure(void)
231 : : {
232 : : char uio_name[32];
233 : 0 : int uio_minor_number = -1;
234 : : int ret;
235 : : DIR *d = NULL;
236 : : struct dirent *dir;
237 : :
238 : 0 : d = opendir(FEC_UIO_DEVICE_SYS_ATTR_PATH);
239 [ # # ]: 0 : if (d == NULL) {
240 : 0 : ENETFEC_PMD_ERR("Error opening directory '%s': %s",
241 : : FEC_UIO_DEVICE_SYS_ATTR_PATH, strerror(errno));
242 : 0 : return -1;
243 : : }
244 : :
245 : : /* Iterate through all subdirs */
246 [ # # ]: 0 : while ((dir = readdir(d)) != NULL) {
247 [ # # ]: 0 : if (!strncmp(dir->d_name, ".", 1) ||
248 [ # # ]: 0 : !strncmp(dir->d_name, "..", 2))
249 : 0 : continue;
250 : :
251 : : if (file_name_match_extract(dir->d_name, "uio")) {
252 : : /*
253 : : * As substring <uio> was found in <d_name>
254 : : * read number following <uio> substring in <d_name>
255 : : */
256 : 0 : ret = sscanf(dir->d_name + strlen("uio"), "%d",
257 : : &uio_minor_number);
258 [ # # ]: 0 : if (ret < 0)
259 : 0 : ENETFEC_PMD_ERR("Error: not find minor number");
260 : : /*
261 : : * Open file uioX/name and read first line which
262 : : * contains the name for the device. Based on the
263 : : * name check if this UIO device is for enetfec.
264 : : */
265 : : memset(uio_name, 0, sizeof(uio_name));
266 : 0 : ret = file_read_first_line(FEC_UIO_DEVICE_SYS_ATTR_PATH,
267 : : dir->d_name, "name", uio_name);
268 [ # # ]: 0 : if (ret != 0) {
269 : 0 : ENETFEC_PMD_INFO("file_read_first_line failed");
270 : 0 : closedir(d);
271 : 0 : return -1;
272 : : }
273 : :
274 : : if (file_name_match_extract(uio_name,
275 : : FEC_UIO_DEVICE_NAME)) {
276 : 0 : enetfec_uio_job.uio_minor_number =
277 : : uio_minor_number;
278 : 0 : ENETFEC_PMD_INFO("enetfec device uio name: %s",
279 : : uio_name);
280 : : }
281 : : }
282 : : }
283 : 0 : closedir(d);
284 : 0 : return 0;
285 : : }
286 : :
287 : : void
288 : 0 : enetfec_cleanup(struct enetfec_private *fep)
289 : : {
290 : 0 : munmap(fep->hw_baseaddr_v, fep->cbus_size);
291 : 0 : }
|