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