1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2021 Marvell. 3 */ 4 5 #include <cnxk_ethdev.h> 6 7 #define CNXK_NIX_INL_SELFTEST "selftest" 8 #define CNXK_NIX_INL_IPSEC_IN_MAX_SPI "ipsec_in_max_spi" 9 #define CNXK_INL_CPT_CHANNEL "inl_cpt_channel" 10 11 struct inl_cpt_channel { 12 bool is_multi_channel; 13 uint16_t channel; 14 uint16_t mask; 15 }; 16 17 #define CNXK_NIX_INL_DEV_NAME RTE_STR(cnxk_nix_inl_dev_) 18 #define CNXK_NIX_INL_DEV_NAME_LEN \ 19 (sizeof(CNXK_NIX_INL_DEV_NAME) + PCI_PRI_STR_SIZE) 20 21 static inline int 22 bitmap_ctzll(uint64_t slab) 23 { 24 if (slab == 0) 25 return 0; 26 27 return __builtin_ctzll(slab); 28 } 29 30 int 31 cnxk_eth_outb_sa_idx_get(struct cnxk_eth_dev *dev, uint32_t *idx_p) 32 { 33 uint32_t pos, idx; 34 uint64_t slab; 35 int rc; 36 37 if (!dev->outb.sa_bmap) 38 return -ENOTSUP; 39 40 pos = 0; 41 slab = 0; 42 /* Scan from the beginning */ 43 plt_bitmap_scan_init(dev->outb.sa_bmap); 44 /* Scan bitmap to get the free sa index */ 45 rc = plt_bitmap_scan(dev->outb.sa_bmap, &pos, &slab); 46 /* Empty bitmap */ 47 if (rc == 0) { 48 plt_err("Outbound SA' exhausted, use 'ipsec_out_max_sa' " 49 "devargs to increase"); 50 return -ERANGE; 51 } 52 53 /* Get free SA index */ 54 idx = pos + bitmap_ctzll(slab); 55 plt_bitmap_clear(dev->outb.sa_bmap, idx); 56 *idx_p = idx; 57 return 0; 58 } 59 60 int 61 cnxk_eth_outb_sa_idx_put(struct cnxk_eth_dev *dev, uint32_t idx) 62 { 63 if (idx >= dev->outb.max_sa) 64 return -EINVAL; 65 66 /* Check if it is already free */ 67 if (plt_bitmap_get(dev->outb.sa_bmap, idx)) 68 return -EINVAL; 69 70 /* Mark index as free */ 71 plt_bitmap_set(dev->outb.sa_bmap, idx); 72 return 0; 73 } 74 75 struct cnxk_eth_sec_sess * 76 cnxk_eth_sec_sess_get_by_spi(struct cnxk_eth_dev *dev, uint32_t spi, bool inb) 77 { 78 struct cnxk_eth_sec_sess_list *list; 79 struct cnxk_eth_sec_sess *eth_sec; 80 81 list = inb ? &dev->inb.list : &dev->outb.list; 82 TAILQ_FOREACH(eth_sec, list, entry) { 83 if (eth_sec->spi == spi) 84 return eth_sec; 85 } 86 87 return NULL; 88 } 89 90 struct cnxk_eth_sec_sess * 91 cnxk_eth_sec_sess_get_by_sess(struct cnxk_eth_dev *dev, 92 struct rte_security_session *sess) 93 { 94 struct cnxk_eth_sec_sess *eth_sec = NULL; 95 96 /* Search in inbound list */ 97 TAILQ_FOREACH(eth_sec, &dev->inb.list, entry) { 98 if (eth_sec->sess == sess) 99 return eth_sec; 100 } 101 102 /* Search in outbound list */ 103 TAILQ_FOREACH(eth_sec, &dev->outb.list, entry) { 104 if (eth_sec->sess == sess) 105 return eth_sec; 106 } 107 108 return NULL; 109 } 110 111 static unsigned int 112 cnxk_eth_sec_session_get_size(void *device __rte_unused) 113 { 114 return sizeof(struct cnxk_eth_sec_sess); 115 } 116 117 struct rte_security_ops cnxk_eth_sec_ops = { 118 .session_get_size = cnxk_eth_sec_session_get_size 119 }; 120 121 static int 122 parse_ipsec_in_max_spi(const char *key, const char *value, void *extra_args) 123 { 124 RTE_SET_USED(key); 125 uint32_t val; 126 127 val = atoi(value); 128 129 *(uint16_t *)extra_args = val; 130 131 return 0; 132 } 133 134 static int 135 parse_selftest(const char *key, const char *value, void *extra_args) 136 { 137 RTE_SET_USED(key); 138 uint32_t val; 139 140 val = atoi(value); 141 142 *(uint8_t *)extra_args = !!(val == 1); 143 return 0; 144 } 145 146 static int 147 parse_inl_cpt_channel(const char *key, const char *value, void *extra_args) 148 { 149 RTE_SET_USED(key); 150 uint16_t chan = 0, mask = 0; 151 char *next = 0; 152 153 /* next will point to the separator '/' */ 154 chan = strtol(value, &next, 16); 155 mask = strtol(++next, 0, 16); 156 157 if (chan > GENMASK(12, 0) || mask > GENMASK(12, 0)) 158 return -EINVAL; 159 160 ((struct inl_cpt_channel *)extra_args)->channel = chan; 161 ((struct inl_cpt_channel *)extra_args)->mask = mask; 162 ((struct inl_cpt_channel *)extra_args)->is_multi_channel = true; 163 164 return 0; 165 } 166 167 static int 168 nix_inl_parse_devargs(struct rte_devargs *devargs, 169 struct roc_nix_inl_dev *inl_dev) 170 { 171 uint32_t ipsec_in_max_spi = BIT(8) - 1; 172 struct inl_cpt_channel cpt_channel; 173 struct rte_kvargs *kvlist; 174 uint8_t selftest = 0; 175 176 memset(&cpt_channel, 0, sizeof(cpt_channel)); 177 178 if (devargs == NULL) 179 goto null_devargs; 180 181 kvlist = rte_kvargs_parse(devargs->args, NULL); 182 if (kvlist == NULL) 183 goto exit; 184 185 rte_kvargs_process(kvlist, CNXK_NIX_INL_SELFTEST, &parse_selftest, 186 &selftest); 187 rte_kvargs_process(kvlist, CNXK_NIX_INL_IPSEC_IN_MAX_SPI, 188 &parse_ipsec_in_max_spi, &ipsec_in_max_spi); 189 rte_kvargs_process(kvlist, CNXK_INL_CPT_CHANNEL, &parse_inl_cpt_channel, 190 &cpt_channel); 191 rte_kvargs_free(kvlist); 192 193 null_devargs: 194 inl_dev->ipsec_in_max_spi = ipsec_in_max_spi; 195 inl_dev->selftest = selftest; 196 inl_dev->channel = cpt_channel.channel; 197 inl_dev->chan_mask = cpt_channel.mask; 198 inl_dev->is_multi_channel = cpt_channel.is_multi_channel; 199 return 0; 200 exit: 201 return -EINVAL; 202 } 203 204 static inline char * 205 nix_inl_dev_to_name(struct rte_pci_device *pci_dev, char *name) 206 { 207 snprintf(name, CNXK_NIX_INL_DEV_NAME_LEN, 208 CNXK_NIX_INL_DEV_NAME PCI_PRI_FMT, pci_dev->addr.domain, 209 pci_dev->addr.bus, pci_dev->addr.devid, 210 pci_dev->addr.function); 211 212 return name; 213 } 214 215 static int 216 cnxk_nix_inl_dev_remove(struct rte_pci_device *pci_dev) 217 { 218 char name[CNXK_NIX_INL_DEV_NAME_LEN]; 219 const struct rte_memzone *mz; 220 struct roc_nix_inl_dev *dev; 221 int rc; 222 223 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 224 return 0; 225 226 mz = rte_memzone_lookup(nix_inl_dev_to_name(pci_dev, name)); 227 if (!mz) 228 return 0; 229 230 dev = mz->addr; 231 232 /* Cleanup inline dev */ 233 rc = roc_nix_inl_dev_fini(dev); 234 if (rc) { 235 plt_err("Failed to cleanup inl dev, rc=%d(%s)", rc, 236 roc_error_msg_get(rc)); 237 return rc; 238 } 239 240 rte_memzone_free(mz); 241 return 0; 242 } 243 244 static int 245 cnxk_nix_inl_dev_probe(struct rte_pci_driver *pci_drv, 246 struct rte_pci_device *pci_dev) 247 { 248 char name[CNXK_NIX_INL_DEV_NAME_LEN]; 249 struct roc_nix_inl_dev *inl_dev; 250 const struct rte_memzone *mz; 251 int rc = -ENOMEM; 252 253 RTE_SET_USED(pci_drv); 254 255 rc = roc_plt_init(); 256 if (rc) { 257 plt_err("Failed to initialize platform model, rc=%d", rc); 258 return rc; 259 } 260 261 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 262 return 0; 263 264 mz = rte_memzone_reserve_aligned(nix_inl_dev_to_name(pci_dev, name), 265 sizeof(*inl_dev), SOCKET_ID_ANY, 0, 266 RTE_CACHE_LINE_SIZE); 267 if (mz == NULL) 268 return rc; 269 270 inl_dev = mz->addr; 271 inl_dev->pci_dev = pci_dev; 272 273 /* Parse devargs string */ 274 rc = nix_inl_parse_devargs(pci_dev->device.devargs, inl_dev); 275 if (rc) { 276 plt_err("Failed to parse devargs rc=%d", rc); 277 goto free_mem; 278 } 279 280 inl_dev->attach_cptlf = true; 281 rc = roc_nix_inl_dev_init(inl_dev); 282 if (rc) { 283 plt_err("Failed to init nix inl device, rc=%d(%s)", rc, 284 roc_error_msg_get(rc)); 285 goto free_mem; 286 } 287 288 return 0; 289 free_mem: 290 rte_memzone_free(mz); 291 return rc; 292 } 293 294 static const struct rte_pci_id cnxk_nix_inl_pci_map[] = { 295 {RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CNXK_RVU_NIX_INL_PF)}, 296 {RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CNXK_RVU_NIX_INL_VF)}, 297 { 298 .vendor_id = 0, 299 }, 300 }; 301 302 static struct rte_pci_driver cnxk_nix_inl_pci = { 303 .id_table = cnxk_nix_inl_pci_map, 304 .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_NEED_IOVA_AS_VA, 305 .probe = cnxk_nix_inl_dev_probe, 306 .remove = cnxk_nix_inl_dev_remove, 307 }; 308 309 RTE_PMD_REGISTER_PCI(cnxk_nix_inl, cnxk_nix_inl_pci); 310 RTE_PMD_REGISTER_PCI_TABLE(cnxk_nix_inl, cnxk_nix_inl_pci_map); 311 RTE_PMD_REGISTER_KMOD_DEP(cnxk_nix_inl, "vfio-pci"); 312 313 RTE_PMD_REGISTER_PARAM_STRING(cnxk_nix_inl, 314 CNXK_NIX_INL_SELFTEST "=1" 315 CNXK_NIX_INL_IPSEC_IN_MAX_SPI "=<1-65535>" 316 CNXK_INL_CPT_CHANNEL "=<1-4095>/<1-4095>"); 317