net/cxgbe: add VF firmware mailbox
[dpdk.git] / drivers / net / cxgbe / base / t4vf_hw.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Chelsio Communications.
3  * All rights reserved.
4  */
5
6 #include <rte_ethdev_driver.h>
7 #include <rte_ether.h>
8
9 #include "common.h"
10 #include "t4_regs.h"
11
12 /*
13  * Get the reply to a mailbox command and store it in @rpl in big-endian order.
14  */
15 static void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit,
16                          u32 mbox_addr)
17 {
18         for ( ; nflit; nflit--, mbox_addr += 8)
19                 *rpl++ = htobe64(t4_read_reg64(adap, mbox_addr));
20 }
21
22 /**
23  * t4vf_wr_mbox_core - send a command to FW through the mailbox
24  * @adapter: the adapter
25  * @cmd: the command to write
26  * @size: command length in bytes
27  * @rpl: where to optionally store the reply
28  * @sleep_ok: if true we may sleep while awaiting command completion
29  *
30  * Sends the given command to FW through the mailbox and waits for the
31  * FW to execute the command.  If @rpl is not %NULL it is used to store
32  * the FW's reply to the command.  The command and its optional reply
33  * are of the same length.  FW can take up to 500 ms to respond.
34  * @sleep_ok determines whether we may sleep while awaiting the response.
35  * If sleeping is allowed we use progressive backoff otherwise we spin.
36  *
37  * The return value is 0 on success or a negative errno on failure.  A
38  * failure can happen either because we are not able to execute the
39  * command or FW executes it but signals an error.  In the latter case
40  * the return value is the error code indicated by FW (negated).
41  */
42 int t4vf_wr_mbox_core(struct adapter *adapter,
43                       const void __attribute__((__may_alias__)) *cmd,
44                       int size, void *rpl, bool sleep_ok)
45 {
46         /*
47          * We delay in small increments at first in an effort to maintain
48          * responsiveness for simple, fast executing commands but then back
49          * off to larger delays to a maximum retry delay.
50          */
51         static const int delay[] = {
52                 1, 1, 3, 5, 10, 10, 20, 50, 100
53         };
54
55
56         u32 mbox_ctl = T4VF_CIM_BASE_ADDR + A_CIM_VF_EXT_MAILBOX_CTRL;
57         __be64 cmd_rpl[MBOX_LEN / 8];
58         struct mbox_entry entry;
59         unsigned int delay_idx;
60         u32 v, mbox_data;
61         const __be64 *p;
62         int i, ret;
63         int ms;
64
65         /* In T6, mailbox size is changed to 128 bytes to avoid
66          * invalidating the entire prefetch buffer.
67          */
68         if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
69                 mbox_data = T4VF_MBDATA_BASE_ADDR;
70         else
71                 mbox_data = T6VF_MBDATA_BASE_ADDR;
72
73         /*
74          * Commands must be multiples of 16 bytes in length and may not be
75          * larger than the size of the Mailbox Data register array.
76          */
77         if ((size % 16) != 0 ||
78                         size > NUM_CIM_VF_MAILBOX_DATA_INSTANCES * 4)
79                 return -EINVAL;
80
81         /*
82          * Queue ourselves onto the mailbox access list.  When our entry is at
83          * the front of the list, we have rights to access the mailbox.  So we
84          * wait [for a while] till we're at the front [or bail out with an
85          * EBUSY] ...
86          */
87         t4_os_atomic_add_tail(&entry, &adapter->mbox_list, &adapter->mbox_lock);
88
89         delay_idx = 0;
90         ms = delay[0];
91
92         for (i = 0; ; i += ms) {
93                 /*
94                  * If we've waited too long, return a busy indication.  This
95                  * really ought to be based on our initial position in the
96                  * mailbox access list but this is a start.  We very rarely
97                  * contend on access to the mailbox ...
98                  */
99                 if (i > (2 * FW_CMD_MAX_TIMEOUT)) {
100                         t4_os_atomic_list_del(&entry, &adapter->mbox_list,
101                                               &adapter->mbox_lock);
102                         ret = -EBUSY;
103                         return ret;
104                 }
105
106                 /*
107                  * If we're at the head, break out and start the mailbox
108                  * protocol.
109                  */
110                 if (t4_os_list_first_entry(&adapter->mbox_list) == &entry)
111                         break;
112
113                 /*
114                  * Delay for a bit before checking again ...
115                  */
116                 if (sleep_ok) {
117                         ms = delay[delay_idx];  /* last element may repeat */
118                         if (delay_idx < ARRAY_SIZE(delay) - 1)
119                                 delay_idx++;
120                         msleep(ms);
121                 } else {
122                         rte_delay_ms(ms);
123                 }
124         }
125
126         /*
127          * Loop trying to get ownership of the mailbox.  Return an error
128          * if we can't gain ownership.
129          */
130         v = G_MBOWNER(t4_read_reg(adapter, mbox_ctl));
131         for (i = 0; v == X_MBOWNER_NONE && i < 3; i++)
132                 v = G_MBOWNER(t4_read_reg(adapter, mbox_ctl));
133
134         if (v != X_MBOWNER_PL) {
135                 t4_os_atomic_list_del(&entry, &adapter->mbox_list,
136                                       &adapter->mbox_lock);
137                 ret = (v == X_MBOWNER_FW) ? -EBUSY : -ETIMEDOUT;
138                 return ret;
139         }
140
141         /*
142          * Write the command array into the Mailbox Data register array and
143          * transfer ownership of the mailbox to the firmware.
144          */
145         for (i = 0, p = cmd; i < size; i += 8)
146                 t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++));
147
148         t4_read_reg(adapter, mbox_data);          /* flush write */
149         t4_write_reg(adapter, mbox_ctl,
150                         F_MBMSGVALID | V_MBOWNER(X_MBOWNER_FW));
151         t4_read_reg(adapter, mbox_ctl);          /* flush write */
152         delay_idx = 0;
153         ms = delay[0];
154
155         /*
156          * Spin waiting for firmware to acknowledge processing our command.
157          */
158         for (i = 0; i < FW_CMD_MAX_TIMEOUT; i++) {
159                 if (sleep_ok) {
160                         ms = delay[delay_idx];  /* last element may repeat */
161                         if (delay_idx < ARRAY_SIZE(delay) - 1)
162                                 delay_idx++;
163                         msleep(ms);
164                 } else {
165                         rte_delay_ms(ms);
166                 }
167
168                 /*
169                  * If we're the owner, see if this is the reply we wanted.
170                  */
171                 v = t4_read_reg(adapter, mbox_ctl);
172                 if (G_MBOWNER(v) == X_MBOWNER_PL) {
173                         /*
174                          * If the Message Valid bit isn't on, revoke ownership
175                          * of the mailbox and continue waiting for our reply.
176                          */
177                         if ((v & F_MBMSGVALID) == 0) {
178                                 t4_write_reg(adapter, mbox_ctl,
179                                              V_MBOWNER(X_MBOWNER_NONE));
180                                 continue;
181                         }
182
183                         /*
184                          * We now have our reply.  Extract the command return
185                          * value, copy the reply back to our caller's buffer
186                          * (if specified) and revoke ownership of the mailbox.
187                          * We return the (negated) firmware command return
188                          * code (this depends on FW_SUCCESS == 0).  (Again we
189                          * avoid clogging the log with FW_VI_STATS_CMD
190                          * reply results.)
191                          */
192
193                         /*
194                          * Retrieve the command reply and release the mailbox.
195                          */
196                         get_mbox_rpl(adapter, cmd_rpl, size / 8, mbox_data);
197                         t4_write_reg(adapter, mbox_ctl,
198                                      V_MBOWNER(X_MBOWNER_NONE));
199                         t4_os_atomic_list_del(&entry, &adapter->mbox_list,
200                                               &adapter->mbox_lock);
201
202                         /* return value in high-order host-endian word */
203                         v = be64_to_cpu(cmd_rpl[0]);
204
205                         if (rpl) {
206                                 /* request bit in high-order BE word */
207                                 WARN_ON((be32_to_cpu(*(const u32 *)cmd)
208                                          & F_FW_CMD_REQUEST) == 0);
209                                 memcpy(rpl, cmd_rpl, size);
210                         }
211                         return -((int)G_FW_CMD_RETVAL(v));
212                 }
213         }
214
215         /*
216          * We timed out.  Return the error ...
217          */
218         dev_err(adapter, "command %#x timed out\n",
219                 *(const u8 *)cmd);
220         dev_err(adapter, "    Control = %#x\n", t4_read_reg(adapter, mbox_ctl));
221         t4_os_atomic_list_del(&entry, &adapter->mbox_list, &adapter->mbox_lock);
222         ret = -ETIMEDOUT;
223         return ret;
224 }