1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2020 Broadcom. 3 * All rights reserved. 4 */ 5 6 #include <dirent.h> 7 #include <stdbool.h> 8 #include <sys/queue.h> 9 10 #include <rte_malloc.h> 11 #include <rte_string_fns.h> 12 13 #include "bcmfs_device.h" 14 #include "bcmfs_logs.h" 15 #include "bcmfs_qp.h" 16 #include "bcmfs_vfio.h" 17 #include "bcmfs_sym_pmd.h" 18 19 struct bcmfs_device_attr { 20 const char name[BCMFS_MAX_PATH_LEN]; 21 const char suffix[BCMFS_DEV_NAME_LEN]; 22 const enum bcmfs_device_type type; 23 const uint32_t offset; 24 const uint32_t version; 25 }; 26 27 /* BCMFS supported devices */ 28 static struct bcmfs_device_attr dev_table[] = { 29 { 30 .name = "fs4", 31 .suffix = "crypto_mbox", 32 .type = BCMFS_SYM_FS4, 33 .offset = 0, 34 .version = BCMFS_SYM_FS4_VERSION 35 }, 36 { 37 .name = "fs5", 38 .suffix = "mbox", 39 .type = BCMFS_SYM_FS5, 40 .offset = 0, 41 .version = BCMFS_SYM_FS5_VERSION 42 }, 43 { 44 /* sentinel */ 45 } 46 }; 47 48 struct bcmfs_hw_queue_pair_ops_table bcmfs_hw_queue_pair_ops_table = { 49 .tl = RTE_SPINLOCK_INITIALIZER, 50 .num_ops = 0 51 }; 52 53 int bcmfs_hw_queue_pair_register_ops(const struct bcmfs_hw_queue_pair_ops *h) 54 { 55 struct bcmfs_hw_queue_pair_ops *ops; 56 int16_t ops_index; 57 58 rte_spinlock_lock(&bcmfs_hw_queue_pair_ops_table.tl); 59 60 if (h->enq_one_req == NULL || h->dequeue == NULL || 61 h->ring_db == NULL || h->startq == NULL || h->stopq == NULL) { 62 rte_spinlock_unlock(&bcmfs_hw_queue_pair_ops_table.tl); 63 BCMFS_LOG(ERR, 64 "Missing callback while registering device ops"); 65 return -EINVAL; 66 } 67 68 if (strlen(h->name) >= sizeof(ops->name) - 1) { 69 rte_spinlock_unlock(&bcmfs_hw_queue_pair_ops_table.tl); 70 BCMFS_LOG(ERR, "%s(): fs device_ops <%s>: name too long", 71 __func__, h->name); 72 return -EEXIST; 73 } 74 75 ops_index = bcmfs_hw_queue_pair_ops_table.num_ops++; 76 ops = &bcmfs_hw_queue_pair_ops_table.qp_ops[ops_index]; 77 strlcpy(ops->name, h->name, sizeof(ops->name)); 78 ops->enq_one_req = h->enq_one_req; 79 ops->dequeue = h->dequeue; 80 ops->ring_db = h->ring_db; 81 ops->startq = h->startq; 82 ops->stopq = h->stopq; 83 84 rte_spinlock_unlock(&bcmfs_hw_queue_pair_ops_table.tl); 85 86 return ops_index; 87 } 88 89 TAILQ_HEAD(fsdev_list, bcmfs_device); 90 static struct fsdev_list fsdev_list = TAILQ_HEAD_INITIALIZER(fsdev_list); 91 92 static struct bcmfs_device * 93 fsdev_allocate_one_dev(struct rte_vdev_device *vdev, 94 char *dirpath, 95 char *devname, 96 enum bcmfs_device_type dev_type __rte_unused) 97 { 98 struct bcmfs_device *fsdev; 99 uint32_t i; 100 101 fsdev = rte_calloc(__func__, 1, sizeof(*fsdev), 0); 102 if (!fsdev) 103 return NULL; 104 105 if (strlen(dirpath) > sizeof(fsdev->dirname)) { 106 BCMFS_LOG(ERR, "dir path name is too long"); 107 goto cleanup; 108 } 109 110 if (strlen(devname) > sizeof(fsdev->name)) { 111 BCMFS_LOG(ERR, "devname is too long"); 112 goto cleanup; 113 } 114 115 /* check if registered ops name is present in directory path */ 116 for (i = 0; i < bcmfs_hw_queue_pair_ops_table.num_ops; i++) 117 if (strstr(dirpath, 118 bcmfs_hw_queue_pair_ops_table.qp_ops[i].name)) 119 fsdev->sym_hw_qp_ops = 120 &bcmfs_hw_queue_pair_ops_table.qp_ops[i]; 121 if (!fsdev->sym_hw_qp_ops) 122 goto cleanup; 123 124 strcpy(fsdev->dirname, dirpath); 125 strcpy(fsdev->name, devname); 126 127 fsdev->vdev = vdev; 128 129 /* attach to VFIO */ 130 if (bcmfs_attach_vfio(fsdev)) 131 goto cleanup; 132 133 /* Maximum number of QPs supported */ 134 fsdev->max_hw_qps = fsdev->mmap_size / BCMFS_HW_QUEUE_IO_ADDR_LEN; 135 136 TAILQ_INSERT_TAIL(&fsdev_list, fsdev, next); 137 138 return fsdev; 139 140 cleanup: 141 free(fsdev); 142 143 return NULL; 144 } 145 146 static struct bcmfs_device * 147 find_fsdev(struct rte_vdev_device *vdev) 148 { 149 struct bcmfs_device *fsdev; 150 151 TAILQ_FOREACH(fsdev, &fsdev_list, next) 152 if (fsdev->vdev == vdev) 153 return fsdev; 154 155 return NULL; 156 } 157 158 static void 159 fsdev_release(struct bcmfs_device *fsdev) 160 { 161 if (fsdev == NULL) 162 return; 163 164 TAILQ_REMOVE(&fsdev_list, fsdev, next); 165 free(fsdev); 166 } 167 168 static int 169 cmprator(const void *a, const void *b) 170 { 171 return (*(const unsigned int *)a - *(const unsigned int *)b); 172 } 173 174 static int 175 fsdev_find_all_devs(const char *path, const char *search, 176 uint32_t *devs) 177 { 178 DIR *dir; 179 struct dirent *entry; 180 int count = 0; 181 char addr[BCMFS_MAX_NODES][BCMFS_MAX_PATH_LEN]; 182 int i; 183 184 dir = opendir(path); 185 if (dir == NULL) { 186 BCMFS_LOG(ERR, "Unable to open directory"); 187 return 0; 188 } 189 190 while ((entry = readdir(dir)) != NULL) { 191 if (strstr(entry->d_name, search)) { 192 strlcpy(addr[count], entry->d_name, 193 BCMFS_MAX_PATH_LEN); 194 count++; 195 } 196 } 197 198 closedir(dir); 199 200 for (i = 0 ; i < count; i++) 201 devs[i] = (uint32_t)strtoul(addr[i], NULL, 16); 202 /* sort the devices based on IO addresses */ 203 qsort(devs, count, sizeof(uint32_t), cmprator); 204 205 return count; 206 } 207 208 static bool 209 fsdev_find_sub_dir(char *path, const char *search, char *output) 210 { 211 DIR *dir; 212 struct dirent *entry; 213 214 dir = opendir(path); 215 if (dir == NULL) { 216 BCMFS_LOG(ERR, "Unable to open directory"); 217 return -ENODEV; 218 } 219 220 while ((entry = readdir(dir)) != NULL) { 221 if (!strcmp(entry->d_name, search)) { 222 strlcpy(output, entry->d_name, BCMFS_MAX_PATH_LEN); 223 closedir(dir); 224 return true; 225 } 226 } 227 228 closedir(dir); 229 230 return false; 231 } 232 233 234 static int 235 bcmfs_vdev_probe(struct rte_vdev_device *vdev) 236 { 237 struct bcmfs_device *fsdev; 238 char top_dirpath[BCMFS_MAX_PATH_LEN]; 239 char sub_dirpath[BCMFS_MAX_PATH_LEN]; 240 char out_dirpath[BCMFS_MAX_PATH_LEN]; 241 char out_dirname[BCMFS_MAX_PATH_LEN]; 242 uint32_t fsdev_dev[BCMFS_MAX_NODES]; 243 enum bcmfs_device_type dtype; 244 int err; 245 int i = 0; 246 int dev_idx; 247 int count = 0; 248 bool found = false; 249 250 sprintf(top_dirpath, "%s", SYSFS_BCM_PLTFORM_DEVICES); 251 while (strlen(dev_table[i].name)) { 252 found = fsdev_find_sub_dir(top_dirpath, 253 dev_table[i].name, 254 sub_dirpath); 255 if (found) 256 break; 257 i++; 258 } 259 if (!found) { 260 BCMFS_LOG(ERR, "No supported bcmfs dev found"); 261 return -ENODEV; 262 } 263 264 dev_idx = i; 265 dtype = dev_table[i].type; 266 267 snprintf(out_dirpath, sizeof(out_dirpath), "%s/%s", 268 top_dirpath, sub_dirpath); 269 count = fsdev_find_all_devs(out_dirpath, 270 dev_table[dev_idx].suffix, 271 fsdev_dev); 272 if (!count) { 273 BCMFS_LOG(ERR, "No supported bcmfs dev found"); 274 return -ENODEV; 275 } 276 277 i = 0; 278 while (count) { 279 /* format the device name present in the patch */ 280 snprintf(out_dirname, sizeof(out_dirname), "%x.%s", 281 fsdev_dev[i], dev_table[dev_idx].suffix); 282 fsdev = fsdev_allocate_one_dev(vdev, out_dirpath, 283 out_dirname, dtype); 284 if (!fsdev) { 285 count--; 286 i++; 287 continue; 288 } 289 break; 290 } 291 if (fsdev == NULL) { 292 BCMFS_LOG(ERR, "All supported devs busy"); 293 return -ENODEV; 294 } 295 296 err = bcmfs_sym_dev_create(fsdev); 297 if (err) { 298 BCMFS_LOG(WARNING, 299 "Failed to create BCMFS SYM PMD for device %s", 300 fsdev->name); 301 goto pmd_create_fail; 302 } 303 304 return 0; 305 306 pmd_create_fail: 307 fsdev_release(fsdev); 308 309 return err; 310 } 311 312 static int 313 bcmfs_vdev_remove(struct rte_vdev_device *vdev) 314 { 315 struct bcmfs_device *fsdev; 316 317 fsdev = find_fsdev(vdev); 318 if (fsdev == NULL) 319 return -ENODEV; 320 321 fsdev_release(fsdev); 322 return 0; 323 } 324 325 /* Register with vdev */ 326 static struct rte_vdev_driver rte_bcmfs_pmd = { 327 .probe = bcmfs_vdev_probe, 328 .remove = bcmfs_vdev_remove 329 }; 330 331 RTE_PMD_REGISTER_VDEV(bcmfs_pmd, 332 rte_bcmfs_pmd); 333