New upstream version 18.02
[deb_dpdk.git] / drivers / mempool / octeontx / octeontx_mbox.c
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 #include "octeontx_pool_logs.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 *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 static inline void
64 mbox_msgcpy(volatile uint8_t *d, volatile const uint8_t *s, uint16_t size)
65 {
66         uint16_t i;
67
68         for (i = 0; i < size; i++)
69                 d[i] = s[i];
70 }
71
72 static inline void
73 mbox_send_request(struct mbox *m, struct octeontx_mbox_hdr *hdr,
74                         const void *txmsg, uint16_t txsize)
75 {
76         struct mbox_ram_hdr old_hdr;
77         struct mbox_ram_hdr new_hdr = { {0} };
78         uint64_t *ram_mbox_hdr = (uint64_t *)m->ram_mbox_base;
79         uint8_t *ram_mbox_msg = m->ram_mbox_base + sizeof(struct mbox_ram_hdr);
80
81         /*
82          * Initialize the channel with the tag left by last send.
83          * On success full mbox send complete, PF increments the tag by one.
84          * The sender can validate integrity of PF message with this scheme
85          */
86         old_hdr.u64 = rte_read64(ram_mbox_hdr);
87         m->tag_own = (old_hdr.tag + 2) & (~0x1ul); /* next even number */
88
89         /* Copy msg body */
90         if (txmsg)
91                 mbox_msgcpy(ram_mbox_msg, txmsg, txsize);
92
93         /* Prepare new hdr */
94         new_hdr.chan_state = MBOX_CHAN_STATE_REQ;
95         new_hdr.coproc = hdr->coproc;
96         new_hdr.msg = hdr->msg;
97         new_hdr.vfid = hdr->vfid;
98         new_hdr.tag = m->tag_own;
99         new_hdr.len = txsize;
100
101         /* Write the msg header */
102         rte_write64(new_hdr.u64, ram_mbox_hdr);
103         rte_smp_wmb();
104         /* Notify PF about the new msg - write to MBOX reg generates PF IRQ */
105         rte_write64(0, m->reg);
106 }
107
108 static inline int
109 mbox_wait_response(struct mbox *m, struct octeontx_mbox_hdr *hdr,
110                         void *rxmsg, uint16_t rxsize)
111 {
112         int res = 0, wait;
113         uint16_t len;
114         struct mbox_ram_hdr rx_hdr;
115         uint64_t *ram_mbox_hdr = (uint64_t *)m->ram_mbox_base;
116         uint8_t *ram_mbox_msg = m->ram_mbox_base + sizeof(struct mbox_ram_hdr);
117
118         /* Wait for response */
119         wait = MBOX_WAIT_TIME_SEC * 1000 * 10;
120         while (wait > 0) {
121                 rte_delay_us(100);
122                 rx_hdr.u64 = rte_read64(ram_mbox_hdr);
123                 if (rx_hdr.chan_state == MBOX_CHAN_STATE_RES)
124                         break;
125                 --wait;
126         }
127
128         hdr->res_code = rx_hdr.res_code;
129         m->tag_own++;
130
131         /* Timeout */
132         if (wait <= 0) {
133                 res = -ETIMEDOUT;
134                 goto error;
135         }
136
137         /* Tag mismatch */
138         if (m->tag_own != rx_hdr.tag) {
139                 res = -EINVAL;
140                 goto error;
141         }
142
143         /* PF nacked the msg */
144         if (rx_hdr.res_code != MBOX_RET_SUCCESS) {
145                 res = -EBADMSG;
146                 goto error;
147         }
148
149         len = RTE_MIN(rx_hdr.len, rxsize);
150         if (rxmsg)
151                 mbox_msgcpy(rxmsg, ram_mbox_msg, len);
152
153         return len;
154
155 error:
156         mbox_log_err("Failed to send mbox(%d/%d) coproc=%d msg=%d ret=(%d,%d)",
157                         m->tag_own, rx_hdr.tag, hdr->coproc, hdr->msg, res,
158                         hdr->res_code);
159         return res;
160 }
161
162 static inline int
163 mbox_send(struct mbox *m, struct octeontx_mbox_hdr *hdr, const void *txmsg,
164                 uint16_t txsize, void *rxmsg, uint16_t rxsize)
165 {
166         int res = -EINVAL;
167
168         if (m->init_once == 0 || hdr == NULL ||
169                 txsize > MAX_RAM_MBOX_LEN || rxsize > MAX_RAM_MBOX_LEN) {
170                 mbox_log_err("Invalid init_once=%d hdr=%p txsz=%d rxsz=%d",
171                                 m->init_once, hdr, txsize, rxsize);
172                 return res;
173         }
174
175         rte_spinlock_lock(&m->lock);
176
177         mbox_send_request(m, hdr, txmsg, txsize);
178         res = mbox_wait_response(m, hdr, rxmsg, rxsize);
179
180         rte_spinlock_unlock(&m->lock);
181         return res;
182 }
183
184 static inline int
185 mbox_setup(struct mbox *m)
186 {
187         if (unlikely(m->init_once == 0)) {
188                 rte_spinlock_init(&m->lock);
189                 m->ram_mbox_base = octeontx_ssovf_bar(OCTEONTX_SSO_HWS, 0, 4);
190                 m->reg = octeontx_ssovf_bar(OCTEONTX_SSO_GROUP, 0, 0);
191                 m->reg += SSO_VHGRP_PF_MBOX(1);
192
193                 if (m->ram_mbox_base == NULL || m->reg == NULL) {
194                         mbox_log_err("Invalid ram_mbox_base=%p or reg=%p",
195                                 m->ram_mbox_base, m->reg);
196                         return -EINVAL;
197                 }
198                 m->init_once = 1;
199         }
200         return 0;
201 }
202
203 int
204 octeontx_ssovf_mbox_send(struct octeontx_mbox_hdr *hdr, void *txdata,
205                                  uint16_t txlen, void *rxdata, uint16_t rxlen)
206 {
207         struct mbox *m = &octeontx_mbox;
208
209         RTE_BUILD_BUG_ON(sizeof(struct mbox_ram_hdr) != 8);
210         if (rte_eal_process_type() != RTE_PROC_PRIMARY || mbox_setup(m))
211                 return -EINVAL;
212
213         return mbox_send(m, hdr, txdata, txlen, rxdata, rxlen);
214 }