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