1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2022 Intel Corporation 3 */ 4 5 #include <errno.h> 6 #include <stdio.h> 7 #include <stdint.h> 8 #include <stdlib.h> 9 #include <inttypes.h> 10 #include <unistd.h> 11 #include <fcntl.h> 12 #include <poll.h> 13 #include <sys/eventfd.h> 14 #include <sys/ioctl.h> 15 16 #include <rte_eal.h> 17 #include <rte_malloc.h> 18 #include <rte_memcpy.h> 19 #include <rte_io.h> 20 #include <rte_vfio.h> 21 #include <bus_pci_driver.h> 22 #include <bus_ifpga_driver.h> 23 #include <rte_rawdev.h> 24 25 #include "afu_pmd_core.h" 26 #include "afu_pmd_he_hssi.h" 27 28 static int he_hssi_indirect_write(struct he_hssi_ctx *ctx, uint32_t addr, 29 uint32_t value) 30 { 31 struct traffic_ctrl_cmd cmd; 32 struct traffic_ctrl_data data; 33 uint32_t i = 0; 34 35 IFPGA_RAWDEV_PMD_DEBUG("Indirect write 0x%x, value 0x%08x", addr, value); 36 37 if (!ctx) 38 return -EINVAL; 39 40 data.write_data = value; 41 rte_write64(data.csr, ctx->addr + TRAFFIC_CTRL_DATA); 42 43 cmd.csr = 0; 44 cmd.write_cmd = 1; 45 cmd.afu_cmd_addr = addr; 46 rte_write64(cmd.csr, ctx->addr + TRAFFIC_CTRL_CMD); 47 48 while (i < MAILBOX_TIMEOUT_MS) { 49 rte_delay_ms(MAILBOX_POLL_INTERVAL_MS); 50 cmd.csr = rte_read64(ctx->addr + TRAFFIC_CTRL_CMD); 51 if (cmd.ack_trans) 52 break; 53 i += MAILBOX_POLL_INTERVAL_MS; 54 } 55 if (i >= MAILBOX_TIMEOUT_MS) 56 return -ETIMEDOUT; 57 58 i = 0; 59 cmd.csr = 0; 60 while (i < MAILBOX_TIMEOUT_MS) { 61 cmd.ack_trans = 1; 62 rte_write64(cmd.csr, ctx->addr + TRAFFIC_CTRL_CMD); 63 rte_delay_ms(MAILBOX_POLL_INTERVAL_MS); 64 cmd.csr = rte_read64(ctx->addr + TRAFFIC_CTRL_CMD); 65 if (!cmd.ack_trans) 66 break; 67 i += MAILBOX_POLL_INTERVAL_MS; 68 } 69 if (i >= MAILBOX_TIMEOUT_MS) 70 return -ETIMEDOUT; 71 72 return 0; 73 } 74 75 static int he_hssi_indirect_read(struct he_hssi_ctx *ctx, uint32_t addr, 76 uint32_t *value) 77 { 78 struct traffic_ctrl_cmd cmd; 79 struct traffic_ctrl_data data; 80 uint32_t i = 0; 81 82 if (!ctx) 83 return -EINVAL; 84 85 cmd.csr = 0; 86 cmd.read_cmd = 1; 87 cmd.afu_cmd_addr = addr; 88 rte_write64(cmd.csr, ctx->addr + TRAFFIC_CTRL_CMD); 89 90 while (i < MAILBOX_TIMEOUT_MS) { 91 rte_delay_ms(MAILBOX_POLL_INTERVAL_MS); 92 cmd.csr = rte_read64(ctx->addr + TRAFFIC_CTRL_CMD); 93 if (cmd.ack_trans) { 94 data.csr = rte_read64(ctx->addr + TRAFFIC_CTRL_DATA); 95 *value = data.read_data; 96 break; 97 } 98 i += MAILBOX_POLL_INTERVAL_MS; 99 } 100 if (i >= MAILBOX_TIMEOUT_MS) 101 return -ETIMEDOUT; 102 103 i = 0; 104 cmd.csr = 0; 105 while (i < MAILBOX_TIMEOUT_MS) { 106 cmd.ack_trans = 1; 107 rte_write64(cmd.csr, ctx->addr + TRAFFIC_CTRL_CMD); 108 rte_delay_ms(MAILBOX_POLL_INTERVAL_MS); 109 cmd.csr = rte_read64(ctx->addr + TRAFFIC_CTRL_CMD); 110 if (!cmd.ack_trans) 111 break; 112 i += MAILBOX_POLL_INTERVAL_MS; 113 } 114 if (i >= MAILBOX_TIMEOUT_MS) 115 return -ETIMEDOUT; 116 117 IFPGA_RAWDEV_PMD_DEBUG("Indirect read 0x%x, value 0x%08x", addr, *value); 118 return 0; 119 } 120 121 static void he_hssi_report(struct he_hssi_ctx *ctx) 122 { 123 uint32_t val = 0; 124 uint64_t v64 = 0; 125 int ret = 0; 126 127 ret = he_hssi_indirect_read(ctx, TM_PKT_GOOD, &val); 128 if (ret) 129 return; 130 printf("Number of good packets received: %u\n", val); 131 132 ret = he_hssi_indirect_read(ctx, TM_PKT_BAD, &val); 133 if (ret) 134 return; 135 printf("Number of bad packets received: %u\n", val); 136 137 ret = he_hssi_indirect_read(ctx, TM_BYTE_CNT1, &val); 138 if (ret) 139 return; 140 v64 = val; 141 ret = he_hssi_indirect_read(ctx, TM_BYTE_CNT0, &val); 142 if (ret) 143 return; 144 v64 = (v64 << 32) | val; 145 printf("Number of bytes received: %"PRIu64"\n", v64); 146 147 ret = he_hssi_indirect_read(ctx, TM_AVST_RX_ERR, &val); 148 if (ret) 149 return; 150 if (val & ERR_VALID) { 151 printf("AVST rx error:"); 152 if (val & OVERFLOW_ERR) 153 printf(" overflow"); 154 if (val & LENGTH_ERR) 155 printf(" length"); 156 if (val & OVERSIZE_ERR) 157 printf(" oversize"); 158 if (val & UNDERSIZE_ERR) 159 printf(" undersize"); 160 if (val & MAC_CRC_ERR) 161 printf(" crc"); 162 if (val & PHY_ERR) 163 printf(" phy"); 164 printf("\n"); 165 } 166 167 ret = he_hssi_indirect_read(ctx, LOOPBACK_FIFO_STATUS, &val); 168 if (ret) 169 return; 170 if (val & (ALMOST_EMPTY | ALMOST_FULL)) { 171 printf("FIFO status:"); 172 if (val & ALMOST_EMPTY) 173 printf(" almost empty"); 174 if (val & ALMOST_FULL) 175 printf(" almost full"); 176 printf("\n"); 177 } 178 } 179 180 static int he_hssi_test(struct afu_rawdev *dev) 181 { 182 struct he_hssi_priv *priv = NULL; 183 struct rte_pmd_afu_he_hssi_cfg *cfg = NULL; 184 struct he_hssi_ctx *ctx = NULL; 185 struct traffic_ctrl_ch_sel sel; 186 uint32_t val = 0; 187 uint32_t i = 0; 188 int ret = 0; 189 190 if (!dev) 191 return -EINVAL; 192 193 priv = (struct he_hssi_priv *)dev->priv; 194 if (!priv) 195 return -ENOENT; 196 197 cfg = &priv->he_hssi_cfg; 198 ctx = &priv->he_hssi_ctx; 199 200 ret = he_hssi_indirect_write(ctx, TG_STOP_XFR, 0); 201 if (ret) 202 return ret; 203 204 sel.channel_sel = cfg->port; 205 rte_write64(sel.csr, ctx->addr + TRAFFIC_CTRL_CH_SEL); 206 207 if (cfg->he_loopback >= 0) { 208 val = cfg->he_loopback ? 1 : 0; 209 IFPGA_RAWDEV_PMD_INFO("%s HE loopback on port %u", 210 val ? "Enable" : "Disable", cfg->port); 211 return he_hssi_indirect_write(ctx, LOOPBACK_EN, val); 212 } 213 214 ret = he_hssi_indirect_write(ctx, TG_NUM_PKT, cfg->num_packets); 215 if (ret) 216 return ret; 217 218 ret = he_hssi_indirect_write(ctx, TG_PKT_LEN, cfg->packet_length); 219 if (ret) 220 return ret; 221 222 val = cfg->src_addr & 0xffffffff; 223 ret = he_hssi_indirect_write(ctx, TG_SRC_MAC_L, val); 224 if (ret) 225 return ret; 226 val = (cfg->src_addr >> 32) & 0xffff; 227 ret = he_hssi_indirect_write(ctx, TG_SRC_MAC_H, val); 228 if (ret) 229 return ret; 230 231 val = cfg->dest_addr & 0xffffffff; 232 ret = he_hssi_indirect_write(ctx, TG_DST_MAC_L, val); 233 if (ret) 234 return ret; 235 val = (cfg->dest_addr >> 32) & 0xffff; 236 ret = he_hssi_indirect_write(ctx, TG_DST_MAC_H, val); 237 if (ret) 238 return ret; 239 240 val = cfg->random_length ? 1 : 0; 241 ret = he_hssi_indirect_write(ctx, TG_PKT_LEN_TYPE, val); 242 if (ret) 243 return ret; 244 245 val = cfg->random_payload ? 1 : 0; 246 ret = he_hssi_indirect_write(ctx, TG_DATA_PATTERN, val); 247 if (ret) 248 return ret; 249 250 for (i = 0; i < TG_NUM_RND_SEEDS; i++) { 251 ret = he_hssi_indirect_write(ctx, TG_RANDOM_SEED(i), 252 cfg->rnd_seed[i]); 253 if (ret) 254 return ret; 255 } 256 257 ret = he_hssi_indirect_write(ctx, TG_START_XFR, 1); 258 if (ret) 259 return ret; 260 261 while (i++ < cfg->timeout) { 262 ret = he_hssi_indirect_read(ctx, TG_PKT_XFRD, &val); 263 if (ret) 264 break; 265 if (val == cfg->num_packets) 266 break; 267 sleep(1); 268 } 269 270 he_hssi_report(ctx); 271 272 return ret; 273 } 274 275 static int he_hssi_init(struct afu_rawdev *dev) 276 { 277 struct he_hssi_priv *priv = NULL; 278 struct he_hssi_ctx *ctx = NULL; 279 280 if (!dev) 281 return -EINVAL; 282 283 priv = (struct he_hssi_priv *)dev->priv; 284 if (!priv) { 285 priv = rte_zmalloc(NULL, sizeof(struct he_hssi_priv), 0); 286 if (!priv) 287 return -ENOMEM; 288 dev->priv = priv; 289 } 290 291 ctx = &priv->he_hssi_ctx; 292 ctx->addr = (uint8_t *)dev->addr; 293 294 return 0; 295 } 296 297 static int he_hssi_config(struct afu_rawdev *dev, void *config, 298 size_t config_size) 299 { 300 struct he_hssi_priv *priv = NULL; 301 struct rte_pmd_afu_he_hssi_cfg *cfg = NULL; 302 303 if (!dev || !config || !config_size) 304 return -EINVAL; 305 306 priv = (struct he_hssi_priv *)dev->priv; 307 if (!priv) 308 return -ENOENT; 309 310 if (config_size != sizeof(struct rte_pmd_afu_he_hssi_cfg)) 311 return -EINVAL; 312 313 cfg = (struct rte_pmd_afu_he_hssi_cfg *)config; 314 if (cfg->port >= NUM_HE_HSSI_PORTS) 315 return -EINVAL; 316 317 rte_memcpy(&priv->he_hssi_cfg, cfg, sizeof(priv->he_hssi_cfg)); 318 319 return 0; 320 } 321 322 static int he_hssi_close(struct afu_rawdev *dev) 323 { 324 if (!dev) 325 return -EINVAL; 326 327 rte_free(dev->priv); 328 dev->priv = NULL; 329 330 return 0; 331 } 332 333 static int he_hssi_dump(struct afu_rawdev *dev, FILE *f) 334 { 335 struct he_hssi_priv *priv = NULL; 336 struct he_hssi_ctx *ctx = NULL; 337 338 if (!dev) 339 return -EINVAL; 340 341 priv = (struct he_hssi_priv *)dev->priv; 342 if (!priv) 343 return -ENOENT; 344 345 if (!f) 346 f = stdout; 347 348 ctx = &priv->he_hssi_ctx; 349 350 fprintf(f, "addr:\t\t%p\n", (void *)ctx->addr); 351 352 return 0; 353 } 354 355 static struct afu_ops he_hssi_ops = { 356 .init = he_hssi_init, 357 .config = he_hssi_config, 358 .start = NULL, 359 .stop = NULL, 360 .test = he_hssi_test, 361 .close = he_hssi_close, 362 .dump = he_hssi_dump, 363 .reset = NULL 364 }; 365 366 struct afu_rawdev_drv he_hssi_drv = { 367 .uuid = { HE_HSSI_UUID_L, HE_HSSI_UUID_H }, 368 .ops = &he_hssi_ops 369 }; 370 371 AFU_PMD_REGISTER(he_hssi_drv); 372