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