1 /* SPDX-License-Identifier: BSD-3-Clause
16 #include <rte_common.h>
17 #include <rte_malloc.h>
18 #include "enet_pmd_logs.h"
21 static struct uio_job enetfec_uio_job;
22 static int enetfec_count;
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
29 * @retval true if file name matches the criteria
30 * @retval false if file name does not match the criteria
33 file_name_match_extract(const char filename[], const char match[])
37 substr = strstr(filename, match);
45 * @brief Reads first line from a file.
46 * Composes file name as: root/subdir/filename
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.
53 * @retval 0 for success
54 * @retval other value for error
57 file_read_first_line(const char root[], const char subdir[],
58 const char filename[], char *line)
60 char absolute_file_name[FEC_UIO_MAX_ATTR_FILE_NAME];
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);
68 fd = open(absolute_file_name, O_RDONLY);
70 ENETFEC_PMD_ERR("Error opening file %s", absolute_file_name);
72 /* read UIO device name from first line in file */
73 ret = read(fd, line, FEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH);
75 ENETFEC_PMD_ERR("Error reading file %s", absolute_file_name);
87 * @brief Maps rx-tx bd range assigned for a bd ring.
89 * @param [in] uio_device_fd UIO device file descriptor
90 * @param [in] uio_device_id UIO device id
91 * @param [in] uio_map_id UIO allows maximum 5 different mapping for
92 each device. Maps start with id 0.
93 * @param [out] map_size Map size.
94 * @param [out] map_addr Map physical address
96 * @retval NULL if failed to map registers
97 * @retval Virtual address for mapped register address range
100 uio_map_mem(int uio_device_fd, int uio_device_id,
101 int uio_map_id, int *map_size, uint64_t *map_addr)
103 void *mapped_address = NULL;
104 unsigned int uio_map_size = 0;
105 unsigned int uio_map_p_addr = 0;
106 char uio_sys_root[FEC_UIO_MAX_ATTR_FILE_NAME];
107 char uio_sys_map_subdir[FEC_UIO_MAX_ATTR_FILE_NAME];
108 char uio_map_size_str[FEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH + 1];
109 char uio_map_p_addr_str[32];
112 /* compose the file name: root/subdir/filename */
113 memset(uio_sys_root, 0, sizeof(uio_sys_root));
114 memset(uio_sys_map_subdir, 0, sizeof(uio_sys_map_subdir));
115 memset(uio_map_size_str, 0, sizeof(uio_map_size_str));
116 memset(uio_map_p_addr_str, 0, sizeof(uio_map_p_addr_str));
118 /* Compose string: /sys/class/uio/uioX */
119 snprintf(uio_sys_root, sizeof(uio_sys_root), "%s/%s%d",
120 FEC_UIO_DEVICE_SYS_ATTR_PATH, "uio", uio_device_id);
121 /* Compose string: maps/mapY */
122 snprintf(uio_sys_map_subdir, sizeof(uio_sys_map_subdir), "%s%d",
123 FEC_UIO_DEVICE_SYS_MAP_ATTR, uio_map_id);
125 /* Read first (and only) line from file
126 * /sys/class/uio/uioX/maps/mapY/size
128 ret = file_read_first_line(uio_sys_root, uio_sys_map_subdir,
129 "size", uio_map_size_str);
131 ENETFEC_PMD_ERR("file_read_first_line() failed");
134 ret = file_read_first_line(uio_sys_root, uio_sys_map_subdir,
135 "addr", uio_map_p_addr_str);
137 ENETFEC_PMD_ERR("file_read_first_line() failed");
140 /* Read mapping size and physical address expressed in hexa(base 16) */
141 uio_map_size = strtol(uio_map_size_str, NULL, 16);
142 uio_map_p_addr = strtol(uio_map_p_addr_str, NULL, 16);
144 if (uio_map_id == 0) {
145 /* Map the register address in user space when map_id is 0 */
146 mapped_address = mmap(0 /*dynamically choose virtual address */,
147 uio_map_size, PROT_READ | PROT_WRITE,
148 MAP_SHARED, uio_device_fd, 0);
150 /* Map the BD memory in user space */
151 mapped_address = mmap(NULL, uio_map_size,
152 PROT_READ | PROT_WRITE,
153 MAP_SHARED, uio_device_fd, (1 * MAP_PAGE_SIZE));
156 if (mapped_address == MAP_FAILED) {
157 ENETFEC_PMD_ERR("Failed to map! errno = %d uio job fd = %d,"
158 "uio device id = %d, uio map id = %d", errno,
159 uio_device_fd, uio_device_id, uio_map_id);
163 /* Save the map size to use it later on for munmap-ing */
164 *map_size = uio_map_size;
165 *map_addr = uio_map_p_addr;
166 ENETFEC_PMD_INFO("UIO dev[%d] mapped region [id =%d] size 0x%x at %p",
167 uio_device_id, uio_map_id, uio_map_size, mapped_address);
169 return mapped_address;
173 config_enetfec_uio(struct enetfec_private *fep)
175 char uio_device_file_name[32];
176 struct uio_job *uio_job = NULL;
178 /* Mapping is done only one time */
179 if (enetfec_count > 0) {
180 ENETFEC_PMD_INFO("Mapped!\n");
184 uio_job = &enetfec_uio_job;
186 /* Find UIO device created by ENETFEC-UIO kernel driver */
187 memset(uio_device_file_name, 0, sizeof(uio_device_file_name));
188 snprintf(uio_device_file_name, sizeof(uio_device_file_name), "%s%d",
189 FEC_UIO_DEVICE_FILE_NAME, uio_job->uio_minor_number);
191 /* Open device file */
192 uio_job->uio_fd = open(uio_device_file_name, O_RDWR);
193 if (uio_job->uio_fd < 0) {
194 ENETFEC_PMD_WARN("Unable to open ENETFEC_UIO file\n");
198 ENETFEC_PMD_INFO("US_UIO: Open device(%s) file with uio_fd = %d",
199 uio_device_file_name, uio_job->uio_fd);
201 fep->hw_baseaddr_v = uio_map_mem(uio_job->uio_fd,
202 uio_job->uio_minor_number, FEC_UIO_REG_MAP_ID,
203 &uio_job->map_size, &uio_job->map_addr);
204 if (fep->hw_baseaddr_v == NULL)
206 fep->hw_baseaddr_p = uio_job->map_addr;
207 fep->reg_size = uio_job->map_size;
209 fep->bd_addr_v = uio_map_mem(uio_job->uio_fd,
210 uio_job->uio_minor_number, FEC_UIO_BD_MAP_ID,
211 &uio_job->map_size, &uio_job->map_addr);
212 if (fep->hw_baseaddr_v == NULL)
214 fep->bd_addr_p = (uint32_t)uio_job->map_addr;
215 fep->bd_size = uio_job->map_size;
223 enetfec_configure(void)
226 int uio_minor_number = -1;
231 d = opendir(FEC_UIO_DEVICE_SYS_ATTR_PATH);
233 ENETFEC_PMD_ERR("\nError opening directory '%s': %s\n",
234 FEC_UIO_DEVICE_SYS_ATTR_PATH, strerror(errno));
238 /* Iterate through all subdirs */
239 while ((dir = readdir(d)) != NULL) {
240 if (!strncmp(dir->d_name, ".", 1) ||
241 !strncmp(dir->d_name, "..", 2))
244 if (file_name_match_extract(dir->d_name, "uio")) {
246 * As substring <uio> was found in <d_name>
247 * read number following <uio> substring in <d_name>
249 ret = sscanf(dir->d_name + strlen("uio"), "%d",
252 ENETFEC_PMD_ERR("Error: not find minor number\n");
254 * Open file uioX/name and read first line which
255 * contains the name for the device. Based on the
256 * name check if this UIO device is for enetfec.
258 memset(uio_name, 0, sizeof(uio_name));
259 ret = file_read_first_line(FEC_UIO_DEVICE_SYS_ATTR_PATH,
260 dir->d_name, "name", uio_name);
262 ENETFEC_PMD_INFO("file_read_first_line failed\n");
267 if (file_name_match_extract(uio_name,
268 FEC_UIO_DEVICE_NAME)) {
269 enetfec_uio_job.uio_minor_number =
271 ENETFEC_PMD_INFO("enetfec device uio name: %s",
281 enetfec_cleanup(struct enetfec_private *fep)
283 munmap(fep->hw_baseaddr_v, fep->cbus_size);