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