]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/common/siena_mcdi.c
MFC r293765
[FreeBSD/stable/10.git] / sys / dev / sfxge / common / siena_mcdi.c
1 /*-
2  * Copyright (c) 2012-2015 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 <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "efsys.h"
35 #include "efx.h"
36 #include "efx_impl.h"
37
38 #if EFSYS_OPT_SIENA && EFSYS_OPT_MCDI
39
40 #define SIENA_MCDI_PDU(_emip)                   \
41         (((emip)->emi_port == 1)                \
42         ? MC_SMEM_P0_PDU_OFST >> 2              \
43         : MC_SMEM_P1_PDU_OFST >> 2)
44
45 #define SIENA_MCDI_DOORBELL(_emip)              \
46         (((emip)->emi_port == 1)                \
47         ? MC_SMEM_P0_DOORBELL_OFST >> 2         \
48         : MC_SMEM_P1_DOORBELL_OFST >> 2)
49
50 #define SIENA_MCDI_STATUS(_emip)                \
51         (((emip)->emi_port == 1)                \
52         ? MC_SMEM_P0_STATUS_OFST >> 2           \
53         : MC_SMEM_P1_STATUS_OFST >> 2)
54
55
56                         void
57 siena_mcdi_request_copyin(
58         __in            efx_nic_t *enp,
59         __in            efx_mcdi_req_t *emrp,
60         __in            unsigned int seq,
61         __in            boolean_t ev_cpl,
62         __in            boolean_t new_epoch)
63 {
64 #if EFSYS_OPT_MCDI_LOGGING
65         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
66 #endif
67         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
68         efx_dword_t hdr;
69         efx_dword_t dword;
70         unsigned int xflags;
71         unsigned int pdur;
72         unsigned int dbr;
73         unsigned int pos;
74
75         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
76         _NOTE(ARGUNUSED(new_epoch))
77
78         EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
79         pdur = SIENA_MCDI_PDU(emip);
80         dbr = SIENA_MCDI_DOORBELL(emip);
81
82         xflags = 0;
83         if (ev_cpl)
84                 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
85
86         /* Construct the header in shared memory */
87         EFX_POPULATE_DWORD_6(hdr,
88                             MCDI_HEADER_CODE, emrp->emr_cmd,
89                             MCDI_HEADER_RESYNC, 1,
90                             MCDI_HEADER_DATALEN, emrp->emr_in_length,
91                             MCDI_HEADER_SEQ, seq,
92                             MCDI_HEADER_RESPONSE, 0,
93                             MCDI_HEADER_XFLAGS, xflags);
94         EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &hdr, B_TRUE);
95
96 #if EFSYS_OPT_MCDI_LOGGING
97         if (emtp->emt_logger != NULL) {
98                 emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
99                     &hdr, sizeof (hdr),
100                     emrp->emr_in_buf, emrp->emr_in_length);
101         }
102 #endif /* EFSYS_OPT_MCDI_LOGGING */
103
104         /* Construct the payload */
105         for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) {
106                 memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos),
107                     MIN(sizeof (dword), emrp->emr_in_length - pos));
108                 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM,
109                     pdur + 1 + (pos >> 2), &dword, B_FALSE);
110         }
111
112         /* Ring the doorbell */
113         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11);
114         EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE);
115 }
116
117                         void
118 siena_mcdi_request_copyout(
119         __in            efx_nic_t *enp,
120         __in            efx_mcdi_req_t *emrp)
121 {
122 #if EFSYS_OPT_MCDI_LOGGING
123         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
124         efx_dword_t hdr;
125 #endif
126         size_t bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
127
128         /* Copy payload out if caller supplied buffer */
129         if (emrp->emr_out_buf != NULL) {
130                 siena_mcdi_read_response(enp, emrp->emr_out_buf,
131                     sizeof (efx_dword_t), bytes);
132         }
133
134 #if EFSYS_OPT_MCDI_LOGGING
135         if (emtp->emt_logger != NULL) {
136                 siena_mcdi_read_response(enp, &hdr, 0, sizeof (hdr));
137
138                 emtp->emt_logger(emtp->emt_context,
139                     EFX_LOG_MCDI_RESPONSE,
140                     &hdr, sizeof (hdr),
141                     emrp->emr_out_buf, bytes);
142         }
143 #endif /* EFSYS_OPT_MCDI_LOGGING */
144 }
145
146                         efx_rc_t
147 siena_mcdi_poll_reboot(
148         __in            efx_nic_t *enp)
149 {
150 #ifndef EFX_GRACEFUL_MC_REBOOT
151         /*
152          * This function is not being used properly.
153          * Until its callers are fixed, it should always return 0.
154          */
155         _NOTE(ARGUNUSED(enp))
156         return (0);
157 #else
158         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
159         unsigned int rebootr;
160         efx_dword_t dword;
161         uint32_t value;
162
163         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
164         EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
165         rebootr = SIENA_MCDI_STATUS(emip);
166
167         EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
168         value = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
169
170         if (value == 0)
171                 return (0);
172
173         EFX_ZERO_DWORD(dword);
174         EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
175
176         if (value == MC_STATUS_DWORD_ASSERT)
177                 return (EINTR);
178         else
179                 return (EIO);
180 #endif
181 }
182
183 extern  __checkReturn   boolean_t
184 siena_mcdi_poll_response(
185         __in            efx_nic_t *enp)
186 {
187         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
188         efx_dword_t hdr;
189         unsigned int pdur;
190
191         EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
192         pdur = SIENA_MCDI_PDU(emip);
193
194         EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &hdr, B_FALSE);
195         return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
196 }
197
198                         void
199 siena_mcdi_read_response(
200         __in            efx_nic_t *enp,
201         __out           void *bufferp,
202         __in            size_t offset,
203         __in            size_t length)
204 {
205         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
206         unsigned int pdur;
207         unsigned int pos;
208         efx_dword_t data;
209
210         EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
211         pdur = SIENA_MCDI_PDU(emip);
212
213         for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) {
214                 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
215                     pdur + ((offset + pos) >> 2), &data, B_FALSE);
216                 memcpy((uint8_t *)bufferp + pos, &data,
217                     MIN(sizeof (data), length - pos));
218         }
219 }
220
221         __checkReturn   efx_rc_t
222 siena_mcdi_init(
223         __in            efx_nic_t *enp,
224         __in            const efx_mcdi_transport_t *mtp)
225 {
226         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
227         efx_oword_t oword;
228         unsigned int portnum;
229         efx_rc_t rc;
230
231         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
232
233         /* Determine the port number to use for MCDI */
234         EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword);
235         portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
236
237         if (portnum == 0) {
238                 /* Presumably booted from ROM; only MCDI port 1 will work */
239                 emip->emi_port = 1;
240         } else if (portnum <= 2) {
241                 emip->emi_port = portnum;
242         } else {
243                 rc = EINVAL;
244                 goto fail1;
245         }
246
247         /* Siena BootROM and firmware only support MCDIv1 */
248         emip->emi_max_version = 1;
249
250         /*
251          * Wipe the atomic reboot status so subsequent MCDI requests succeed.
252          * BOOT_STATUS is preserved so eno_nic_probe() can boot out of the
253          * assertion handler.
254          */
255         (void) siena_mcdi_poll_reboot(enp);
256
257         return (0);
258
259 fail1:
260         EFSYS_PROBE1(fail1, efx_rc_t, rc);
261
262         return (rc);
263 }
264
265                         void
266 siena_mcdi_fini(
267         __in            efx_nic_t *enp)
268 {
269 }
270
271         __checkReturn   efx_rc_t
272 siena_mcdi_feature_supported(
273         __in            efx_nic_t *enp,
274         __in            efx_mcdi_feature_id_t id,
275         __out           boolean_t *supportedp)
276 {
277         efx_rc_t rc;
278
279         EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
280
281         switch (id) {
282         case EFX_MCDI_FEATURE_FW_UPDATE:
283         case EFX_MCDI_FEATURE_LINK_CONTROL:
284         case EFX_MCDI_FEATURE_MACADDR_CHANGE:
285         case EFX_MCDI_FEATURE_MAC_SPOOFING:
286                 *supportedp = B_TRUE;
287                 break;
288         default:
289                 rc = ENOTSUP;
290                 goto fail1;
291                 break;
292         }
293
294         return (0);
295
296 fail1:
297         EFSYS_PROBE1(fail1, efx_rc_t, rc);
298
299         return (rc);
300 }
301
302 #endif  /* EFSYS_OPT_SIENA && EFSYS_OPT_MCDI */