5a26bda22941fbdc8bf192a71d27a979d490e003
[deb_dpdk.git] / drivers / net / sfc / base / ef10_mcdi.c
1 /*
2  * Copyright (c) 2012-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include "efx.h"
32 #include "efx_impl.h"
33
34
35 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
36
37 #if EFSYS_OPT_MCDI
38
39 #ifndef WITH_MCDI_V2
40 #error "WITH_MCDI_V2 required for EF10 MCDIv2 commands."
41 #endif
42
43
44         __checkReturn   efx_rc_t
45 ef10_mcdi_init(
46         __in            efx_nic_t *enp,
47         __in            const efx_mcdi_transport_t *emtp)
48 {
49         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
50         efsys_mem_t *esmp = emtp->emt_dma_mem;
51         efx_dword_t dword;
52         efx_rc_t rc;
53
54         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
55                     enp->en_family == EFX_FAMILY_MEDFORD);
56         EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA);
57
58         /*
59          * All EF10 firmware supports MCDIv2 and MCDIv1.
60          * Medford BootROM supports MCDIv2 and MCDIv1.
61          * Huntington BootROM supports MCDIv1 only.
62          */
63         emip->emi_max_version = 2;
64
65         /* A host DMA buffer is required for EF10 MCDI */
66         if (esmp == NULL) {
67                 rc = EINVAL;
68                 goto fail1;
69         }
70
71         /*
72          * Ensure that the MC doorbell is in a known state before issuing MCDI
73          * commands. The recovery algorithm requires that the MC command buffer
74          * must be 256 byte aligned. See bug24769.
75          */
76         if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) {
77                 rc = EINVAL;
78                 goto fail2;
79         }
80         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1);
81         EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
82
83         /* Save initial MC reboot status */
84         (void) ef10_mcdi_poll_reboot(enp);
85
86         /* Start a new epoch (allow fresh MCDI requests to succeed) */
87         efx_mcdi_new_epoch(enp);
88
89         return (0);
90
91 fail2:
92         EFSYS_PROBE(fail2);
93 fail1:
94         EFSYS_PROBE1(fail1, efx_rc_t, rc);
95
96         return (rc);
97 }
98
99                         void
100 ef10_mcdi_fini(
101         __in            efx_nic_t *enp)
102 {
103         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
104
105         emip->emi_new_epoch = B_FALSE;
106 }
107
108 /*
109  * In older firmware all commands are processed in a single thread, so a long
110  * running command for one PCIe function can block processing for another
111  * function (see bug 61269).
112  *
113  * In newer firmware that supports multithreaded MCDI processing, we can extend
114  * the timeout for long-running requests which we know firmware may choose to
115  * process in a background thread.
116  */
117 #define EF10_MCDI_CMD_TIMEOUT_US        (10 * 1000 * 1000)
118 #define EF10_MCDI_CMD_LONG_TIMEOUT_US   (60 * 1000 * 1000)
119
120                         void
121 ef10_mcdi_get_timeout(
122         __in            efx_nic_t *enp,
123         __in            efx_mcdi_req_t *emrp,
124         __out           uint32_t *timeoutp)
125 {
126         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
127
128         switch (emrp->emr_cmd) {
129         case MC_CMD_POLL_BIST:
130         case MC_CMD_NVRAM_ERASE:
131         case MC_CMD_LICENSING_V3:
132         case MC_CMD_NVRAM_UPDATE_FINISH:
133                 if (encp->enc_fw_verified_nvram_update_required != B_FALSE) {
134                         /*
135                          * Potentially longer running commands, which firmware
136                          * may choose to process in a background thread.
137                          */
138                         *timeoutp = EF10_MCDI_CMD_LONG_TIMEOUT_US;
139                         break;
140                 }
141                 /* FALLTHRU */
142         default:
143                 *timeoutp = EF10_MCDI_CMD_TIMEOUT_US;
144                 break;
145         }
146 }
147
148                         void
149 ef10_mcdi_send_request(
150         __in                    efx_nic_t *enp,
151         __in_bcount(hdr_len)    void *hdrp,
152         __in                    size_t hdr_len,
153         __in_bcount(sdu_len)    void *sdup,
154         __in                    size_t sdu_len)
155 {
156         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
157         efsys_mem_t *esmp = emtp->emt_dma_mem;
158         efx_dword_t dword;
159         unsigned int pos;
160
161         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
162                     enp->en_family == EFX_FAMILY_MEDFORD);
163
164         /* Write the header */
165         for (pos = 0; pos < hdr_len; pos += sizeof (efx_dword_t)) {
166                 dword = *(efx_dword_t *)((uint8_t *)hdrp + pos);
167                 EFSYS_MEM_WRITED(esmp, pos, &dword);
168         }
169
170         /* Write the payload */
171         for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) {
172                 dword = *(efx_dword_t *)((uint8_t *)sdup + pos);
173                 EFSYS_MEM_WRITED(esmp, hdr_len + pos, &dword);
174         }
175
176         /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */
177         EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, hdr_len + sdu_len);
178         EFSYS_PIO_WRITE_BARRIER();
179
180         /* Ring the doorbell to post the command DMA address to the MC */
181         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0,
182             EFSYS_MEM_ADDR(esmp) >> 32);
183         EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE);
184
185         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0,
186             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
187         EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
188 }
189
190         __checkReturn   boolean_t
191 ef10_mcdi_poll_response(
192         __in            efx_nic_t *enp)
193 {
194         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
195         efsys_mem_t *esmp = emtp->emt_dma_mem;
196         efx_dword_t hdr;
197
198         EFSYS_MEM_READD(esmp, 0, &hdr);
199         EFSYS_MEM_READ_BARRIER();
200
201         return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
202 }
203
204                         void
205 ef10_mcdi_read_response(
206         __in                    efx_nic_t *enp,
207         __out_bcount(length)    void *bufferp,
208         __in                    size_t offset,
209         __in                    size_t length)
210 {
211         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
212         efsys_mem_t *esmp = emtp->emt_dma_mem;
213         unsigned int pos;
214         efx_dword_t data;
215
216         for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) {
217                 EFSYS_MEM_READD(esmp, offset + pos, &data);
218                 memcpy((uint8_t *)bufferp + pos, &data,
219                     MIN(sizeof (data), length - pos));
220         }
221 }
222
223                         efx_rc_t
224 ef10_mcdi_poll_reboot(
225         __in            efx_nic_t *enp)
226 {
227         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
228         efx_dword_t dword;
229         uint32_t old_status;
230         uint32_t new_status;
231         efx_rc_t rc;
232
233         old_status = emip->emi_mc_reboot_status;
234
235         /* Update MC reboot status word */
236         EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE);
237         new_status = dword.ed_u32[0];
238
239         /* MC has rebooted if the value has changed */
240         if (new_status != old_status) {
241                 emip->emi_mc_reboot_status = new_status;
242
243                 /*
244                  * FIXME: Ignore detected MC REBOOT for now.
245                  *
246                  * The Siena support for checking for MC reboot from status
247                  * flags is broken - see comments in siena_mcdi_poll_reboot().
248                  * As the generic MCDI code is shared the EF10 reboot
249                  * detection suffers similar problems.
250                  *
251                  * Do not report an error when the boot status changes until
252                  * this can be handled by common code drivers (and reworked to
253                  * support Siena too).
254                  */
255                 _NOTE(CONSTANTCONDITION)
256                 if (B_FALSE) {
257                         rc = EIO;
258                         goto fail1;
259                 }
260         }
261
262         return (0);
263
264 fail1:
265         EFSYS_PROBE1(fail1, efx_rc_t, rc);
266
267         return (rc);
268 }
269
270         __checkReturn   efx_rc_t
271 ef10_mcdi_feature_supported(
272         __in            efx_nic_t *enp,
273         __in            efx_mcdi_feature_id_t id,
274         __out           boolean_t *supportedp)
275 {
276         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
277         uint32_t privilege_mask = encp->enc_privilege_mask;
278         efx_rc_t rc;
279
280         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
281                     enp->en_family == EFX_FAMILY_MEDFORD);
282
283         /*
284          * Use privilege mask state at MCDI attach.
285          */
286
287         switch (id) {
288         case EFX_MCDI_FEATURE_FW_UPDATE:
289                 /*
290                  * Admin privilege must be used prior to introduction of
291                  * specific flag.
292                  */
293                 *supportedp =
294                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
295                 break;
296         case EFX_MCDI_FEATURE_LINK_CONTROL:
297                 /*
298                  * Admin privilege used prior to introduction of
299                  * specific flag.
300                  */
301                 *supportedp =
302                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) ||
303                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
304                 break;
305         case EFX_MCDI_FEATURE_MACADDR_CHANGE:
306                 /*
307                  * Admin privilege must be used prior to introduction of
308                  * mac spoofing privilege (at v4.6), which is used up to
309                  * introduction of change mac spoofing privilege (at v4.7)
310                  */
311                 *supportedp =
312                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) ||
313                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
314                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
315                 break;
316         case EFX_MCDI_FEATURE_MAC_SPOOFING:
317                 /*
318                  * Admin privilege must be used prior to introduction of
319                  * mac spoofing privilege (at v4.6), which is used up to
320                  * introduction of mac spoofing TX privilege (at v4.7)
321                  */
322                 *supportedp =
323                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) ||
324                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
325                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
326                 break;
327         default:
328                 rc = ENOTSUP;
329                 goto fail1;
330         }
331
332         return (0);
333
334 fail1:
335         EFSYS_PROBE1(fail1, efx_rc_t, rc);
336
337         return (rc);
338 }
339
340 #endif  /* EFSYS_OPT_MCDI */
341
342 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */