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