1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2017 Cavium, Inc 3 */ 4 5 #include <string.h> 6 7 #include <rte_atomic.h> 8 #include <rte_common.h> 9 #include <rte_cycles.h> 10 #include <rte_io.h> 11 #include <rte_spinlock.h> 12 13 #include "octeontx_mbox.h" 14 15 /* Mbox operation timeout in seconds */ 16 #define MBOX_WAIT_TIME_SEC 3 17 #define MAX_RAM_MBOX_LEN ((SSOW_BAR4_LEN >> 1) - 8 /* Mbox header */) 18 19 /* Mbox channel state */ 20 enum { 21 MBOX_CHAN_STATE_REQ = 1, 22 MBOX_CHAN_STATE_RES = 0, 23 }; 24 25 /* Response messages */ 26 enum { 27 MBOX_RET_SUCCESS, 28 MBOX_RET_INVALID, 29 MBOX_RET_INTERNAL_ERR, 30 }; 31 32 struct mbox { 33 int init_once; 34 uint8_t ready; 35 uint8_t *ram_mbox_base; /* Base address of mbox message stored in ram */ 36 uint8_t *reg; /* Store to this register triggers PF mbox interrupt */ 37 uint16_t tag_own; /* Last tag which was written to own channel */ 38 uint16_t domain; /* Domain */ 39 rte_spinlock_t lock; 40 }; 41 42 static struct mbox octeontx_mbox; 43 44 /* 45 * Structure used for mbox synchronization 46 * This structure sits at the begin of Mbox RAM and used as main 47 * synchronization point for channel communication 48 */ 49 struct mbox_ram_hdr { 50 union { 51 uint64_t u64; 52 struct { 53 uint8_t chan_state : 1; 54 uint8_t coproc : 7; 55 uint8_t msg; 56 uint8_t vfid; 57 uint8_t res_code; 58 uint16_t tag; 59 uint16_t len; 60 }; 61 }; 62 }; 63 64 /* MBOX interface version message */ 65 struct mbox_intf_ver { 66 uint32_t platform:12; 67 uint32_t major:10; 68 uint32_t minor:10; 69 }; 70 71 int octeontx_logtype_mbox; 72 73 RTE_INIT(otx_init_log) 74 { 75 octeontx_logtype_mbox = rte_log_register("pmd.octeontx.mbox"); 76 if (octeontx_logtype_mbox >= 0) 77 rte_log_set_level(octeontx_logtype_mbox, RTE_LOG_NOTICE); 78 } 79 80 static inline void 81 mbox_msgcpy(volatile uint8_t *d, volatile const uint8_t *s, uint16_t size) 82 { 83 uint16_t i; 84 85 for (i = 0; i < size; i++) 86 d[i] = s[i]; 87 } 88 89 static inline void 90 mbox_send_request(struct mbox *m, struct octeontx_mbox_hdr *hdr, 91 const void *txmsg, uint16_t txsize) 92 { 93 struct mbox_ram_hdr old_hdr; 94 struct mbox_ram_hdr new_hdr = { {0} }; 95 uint64_t *ram_mbox_hdr = (uint64_t *)m->ram_mbox_base; 96 uint8_t *ram_mbox_msg = m->ram_mbox_base + sizeof(struct mbox_ram_hdr); 97 98 /* 99 * Initialize the channel with the tag left by last send. 100 * On success full mbox send complete, PF increments the tag by one. 101 * The sender can validate integrity of PF message with this scheme 102 */ 103 old_hdr.u64 = rte_read64(ram_mbox_hdr); 104 m->tag_own = (old_hdr.tag + 2) & (~0x1ul); /* next even number */ 105 106 /* Copy msg body */ 107 if (txmsg) 108 mbox_msgcpy(ram_mbox_msg, txmsg, txsize); 109 110 /* Prepare new hdr */ 111 new_hdr.chan_state = MBOX_CHAN_STATE_REQ; 112 new_hdr.coproc = hdr->coproc; 113 new_hdr.msg = hdr->msg; 114 new_hdr.vfid = hdr->vfid; 115 new_hdr.tag = m->tag_own; 116 new_hdr.len = txsize; 117 118 /* Write the msg header */ 119 rte_write64(new_hdr.u64, ram_mbox_hdr); 120 rte_smp_wmb(); 121 /* Notify PF about the new msg - write to MBOX reg generates PF IRQ */ 122 rte_write64(0, m->reg); 123 } 124 125 static inline int 126 mbox_wait_response(struct mbox *m, struct octeontx_mbox_hdr *hdr, 127 void *rxmsg, uint16_t rxsize) 128 { 129 int res = 0, wait; 130 uint16_t len; 131 struct mbox_ram_hdr rx_hdr; 132 uint64_t *ram_mbox_hdr = (uint64_t *)m->ram_mbox_base; 133 uint8_t *ram_mbox_msg = m->ram_mbox_base + sizeof(struct mbox_ram_hdr); 134 135 /* Wait for response */ 136 wait = MBOX_WAIT_TIME_SEC * 1000 * 10; 137 while (wait > 0) { 138 rte_delay_us(100); 139 rx_hdr.u64 = rte_read64(ram_mbox_hdr); 140 if (rx_hdr.chan_state == MBOX_CHAN_STATE_RES) 141 break; 142 --wait; 143 } 144 145 hdr->res_code = rx_hdr.res_code; 146 m->tag_own++; 147 148 /* Timeout */ 149 if (wait <= 0) { 150 res = -ETIMEDOUT; 151 goto error; 152 } 153 154 /* Tag mismatch */ 155 if (m->tag_own != rx_hdr.tag) { 156 res = -EINVAL; 157 goto error; 158 } 159 160 /* PF nacked the msg */ 161 if (rx_hdr.res_code != MBOX_RET_SUCCESS) { 162 res = -EBADMSG; 163 goto error; 164 } 165 166 len = RTE_MIN(rx_hdr.len, rxsize); 167 if (rxmsg) 168 mbox_msgcpy(rxmsg, ram_mbox_msg, len); 169 170 return len; 171 172 error: 173 mbox_log_err("Failed to send mbox(%d/%d) coproc=%d msg=%d ret=(%d,%d)", 174 m->tag_own, rx_hdr.tag, hdr->coproc, hdr->msg, res, 175 hdr->res_code); 176 return res; 177 } 178 179 static inline int 180 mbox_send(struct mbox *m, struct octeontx_mbox_hdr *hdr, const void *txmsg, 181 uint16_t txsize, void *rxmsg, uint16_t rxsize) 182 { 183 int res = -EINVAL; 184 185 if (m->init_once == 0 || hdr == NULL || 186 txsize > MAX_RAM_MBOX_LEN || rxsize > MAX_RAM_MBOX_LEN) { 187 mbox_log_err("Invalid init_once=%d hdr=%p txsz=%d rxsz=%d", 188 m->init_once, hdr, txsize, rxsize); 189 return res; 190 } 191 192 rte_spinlock_lock(&m->lock); 193 194 mbox_send_request(m, hdr, txmsg, txsize); 195 res = mbox_wait_response(m, hdr, rxmsg, rxsize); 196 197 rte_spinlock_unlock(&m->lock); 198 return res; 199 } 200 201 int 202 octeontx_mbox_set_ram_mbox_base(uint8_t *ram_mbox_base, uint16_t domain) 203 { 204 struct mbox *m = &octeontx_mbox; 205 206 if (m->init_once) 207 return -EALREADY; 208 209 if (ram_mbox_base == NULL) { 210 mbox_log_err("Invalid ram_mbox_base=%p", ram_mbox_base); 211 return -EINVAL; 212 } 213 214 m->ram_mbox_base = ram_mbox_base; 215 216 if (m->reg != NULL) { 217 rte_spinlock_init(&m->lock); 218 m->init_once = 1; 219 m->domain = domain; 220 } 221 222 return 0; 223 } 224 225 int 226 octeontx_mbox_set_reg(uint8_t *reg, uint16_t domain) 227 { 228 struct mbox *m = &octeontx_mbox; 229 230 if (m->init_once) 231 return -EALREADY; 232 233 if (reg == NULL) { 234 mbox_log_err("Invalid reg=%p", reg); 235 return -EINVAL; 236 } 237 238 m->reg = reg; 239 240 if (m->ram_mbox_base != NULL) { 241 rte_spinlock_init(&m->lock); 242 m->init_once = 1; 243 m->domain = domain; 244 } 245 246 return 0; 247 } 248 249 int 250 octeontx_mbox_send(struct octeontx_mbox_hdr *hdr, void *txdata, 251 uint16_t txlen, void *rxdata, uint16_t rxlen) 252 { 253 struct mbox *m = &octeontx_mbox; 254 255 RTE_BUILD_BUG_ON(sizeof(struct mbox_ram_hdr) != 8); 256 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 257 return -EINVAL; 258 259 return mbox_send(m, hdr, txdata, txlen, rxdata, rxlen); 260 } 261 262 static int 263 octeontx_start_domain(void) 264 { 265 struct octeontx_mbox_hdr hdr = {0}; 266 int result = -EINVAL; 267 268 hdr.coproc = NO_COPROC; 269 hdr.msg = RM_START_APP; 270 271 result = octeontx_mbox_send(&hdr, NULL, 0, NULL, 0); 272 if (result != 0) { 273 mbox_log_err("Could not start domain. Err=%d. FuncErr=%d\n", 274 result, hdr.res_code); 275 result = -EINVAL; 276 } 277 278 return result; 279 } 280 281 static int 282 octeontx_check_mbox_version(struct mbox_intf_ver app_intf_ver, 283 struct mbox_intf_ver *intf_ver) 284 { 285 struct mbox_intf_ver kernel_intf_ver = {0}; 286 struct octeontx_mbox_hdr hdr = {0}; 287 int result = 0; 288 289 290 hdr.coproc = NO_COPROC; 291 hdr.msg = RM_INTERFACE_VERSION; 292 293 result = octeontx_mbox_send(&hdr, &app_intf_ver, sizeof(app_intf_ver), 294 &kernel_intf_ver, sizeof(kernel_intf_ver)); 295 if (result != sizeof(kernel_intf_ver)) { 296 mbox_log_err("Could not send interface version. Err=%d. FuncErr=%d\n", 297 result, hdr.res_code); 298 result = -EINVAL; 299 } 300 301 if (intf_ver) 302 *intf_ver = kernel_intf_ver; 303 304 if (app_intf_ver.platform != kernel_intf_ver.platform || 305 app_intf_ver.major != kernel_intf_ver.major || 306 app_intf_ver.minor != kernel_intf_ver.minor) 307 result = -EINVAL; 308 309 return result; 310 } 311 312 int 313 octeontx_mbox_init(void) 314 { 315 const struct mbox_intf_ver MBOX_INTERFACE_VERSION = { 316 .platform = 0x01, 317 .major = 0x01, 318 .minor = 0x03 319 }; 320 struct mbox_intf_ver rm_intf_ver = {0}; 321 struct mbox *m = &octeontx_mbox; 322 int ret; 323 324 if (m->ready) 325 return 0; 326 327 ret = octeontx_start_domain(); 328 if (ret < 0) { 329 m->init_once = 0; 330 return ret; 331 } 332 333 ret = octeontx_check_mbox_version(MBOX_INTERFACE_VERSION, 334 &rm_intf_ver); 335 if (ret < 0) { 336 mbox_log_err("MBOX version: Kernel(%d.%d.%d) != DPDK(%d.%d.%d)", 337 rm_intf_ver.platform, rm_intf_ver.major, 338 rm_intf_ver.minor, MBOX_INTERFACE_VERSION.platform, 339 MBOX_INTERFACE_VERSION.major, 340 MBOX_INTERFACE_VERSION.minor); 341 m->init_once = 0; 342 return -EINVAL; 343 } 344 345 m->ready = 1; 346 rte_mb(); 347 348 return 0; 349 } 350 351 uint16_t 352 octeontx_get_global_domain(void) 353 { 354 struct mbox *m = &octeontx_mbox; 355 356 return m->domain; 357 } 358