New upstream version 18.02
[deb_dpdk.git] / drivers / net / sfc / base / siena_mcdi.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright (c) 2012-2018 Solarflare Communications Inc.
4  * All rights reserved.
5  */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10 #if EFSYS_OPT_SIENA && EFSYS_OPT_MCDI
11
12 #define SIENA_MCDI_PDU(_emip)                   \
13         (((emip)->emi_port == 1)                \
14         ? MC_SMEM_P0_PDU_OFST >> 2              \
15         : MC_SMEM_P1_PDU_OFST >> 2)
16
17 #define SIENA_MCDI_DOORBELL(_emip)              \
18         (((emip)->emi_port == 1)                \
19         ? MC_SMEM_P0_DOORBELL_OFST >> 2         \
20         : MC_SMEM_P1_DOORBELL_OFST >> 2)
21
22 #define SIENA_MCDI_STATUS(_emip)                \
23         (((emip)->emi_port == 1)                \
24         ? MC_SMEM_P0_STATUS_OFST >> 2           \
25         : MC_SMEM_P1_STATUS_OFST >> 2)
26
27
28                         void
29 siena_mcdi_send_request(
30         __in                    efx_nic_t *enp,
31         __in_bcount(hdr_len)    void *hdrp,
32         __in                    size_t hdr_len,
33         __in_bcount(sdu_len)    void *sdup,
34         __in                    size_t sdu_len)
35 {
36         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
37         efx_dword_t dword;
38         unsigned int pdur;
39         unsigned int dbr;
40         unsigned int pos;
41
42         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
43
44         EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
45         pdur = SIENA_MCDI_PDU(emip);
46         dbr = SIENA_MCDI_DOORBELL(emip);
47
48         /* Write the header */
49         EFSYS_ASSERT3U(hdr_len, ==, sizeof (efx_dword_t));
50         dword = *(efx_dword_t *)hdrp;
51         EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_TRUE);
52
53         /* Write the payload */
54         for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) {
55                 dword = *(efx_dword_t *)((uint8_t *)sdup + pos);
56                 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM,
57                     pdur + 1 + (pos >> 2), &dword, B_FALSE);
58         }
59
60         /* Ring the doorbell */
61         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11);
62         EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE);
63 }
64
65                         efx_rc_t
66 siena_mcdi_poll_reboot(
67         __in            efx_nic_t *enp)
68 {
69 #if 1
70         /*
71          * XXX Bug 25922, bug 26099: This function is not being used
72          * properly.  Until its callers are fixed, it should always
73          * return 0.
74          */
75         _NOTE(ARGUNUSED(enp))
76         return (0);
77 #else
78         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
79         unsigned int rebootr;
80         efx_dword_t dword;
81         uint32_t value;
82
83         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
84         EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
85         rebootr = SIENA_MCDI_STATUS(emip);
86
87         EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
88         value = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
89
90         if (value == 0)
91                 return (0);
92
93         EFX_ZERO_DWORD(dword);
94         EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
95
96         if (value == MC_STATUS_DWORD_ASSERT)
97                 return (EINTR);
98         else
99                 return (EIO);
100 #endif
101 }
102
103 extern  __checkReturn   boolean_t
104 siena_mcdi_poll_response(
105         __in            efx_nic_t *enp)
106 {
107         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
108         efx_dword_t hdr;
109         unsigned int pdur;
110
111         EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
112         pdur = SIENA_MCDI_PDU(emip);
113
114         EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &hdr, B_FALSE);
115         return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
116 }
117
118                         void
119 siena_mcdi_read_response(
120         __in                    efx_nic_t *enp,
121         __out_bcount(length)    void *bufferp,
122         __in                    size_t offset,
123         __in                    size_t length)
124 {
125         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
126         unsigned int pdur;
127         unsigned int pos;
128         efx_dword_t data;
129
130         EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
131         pdur = SIENA_MCDI_PDU(emip);
132
133         for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) {
134                 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
135                     pdur + ((offset + pos) >> 2), &data, B_FALSE);
136                 memcpy((uint8_t *)bufferp + pos, &data,
137                     MIN(sizeof (data), length - pos));
138         }
139 }
140
141         __checkReturn   efx_rc_t
142 siena_mcdi_init(
143         __in            efx_nic_t *enp,
144         __in            const efx_mcdi_transport_t *mtp)
145 {
146         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
147         efx_oword_t oword;
148         unsigned int portnum;
149         efx_rc_t rc;
150
151         _NOTE(ARGUNUSED(mtp))
152
153         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
154
155         /* Determine the port number to use for MCDI */
156         EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword);
157         portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
158
159         if (portnum == 0) {
160                 /* Presumably booted from ROM; only MCDI port 1 will work */
161                 emip->emi_port = 1;
162         } else if (portnum <= 2) {
163                 emip->emi_port = portnum;
164         } else {
165                 rc = EINVAL;
166                 goto fail1;
167         }
168
169         /* Siena BootROM and firmware only support MCDIv1 */
170         emip->emi_max_version = 1;
171
172         /*
173          * Wipe the atomic reboot status so subsequent MCDI requests succeed.
174          * BOOT_STATUS is preserved so eno_nic_probe() can boot out of the
175          * assertion handler.
176          */
177         (void) siena_mcdi_poll_reboot(enp);
178
179         return (0);
180
181 fail1:
182         EFSYS_PROBE1(fail1, efx_rc_t, rc);
183
184         return (rc);
185 }
186
187                         void
188 siena_mcdi_fini(
189         __in            efx_nic_t *enp)
190 {
191         _NOTE(ARGUNUSED(enp))
192 }
193
194         __checkReturn   efx_rc_t
195 siena_mcdi_feature_supported(
196         __in            efx_nic_t *enp,
197         __in            efx_mcdi_feature_id_t id,
198         __out           boolean_t *supportedp)
199 {
200         efx_rc_t rc;
201
202         EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
203
204         switch (id) {
205         case EFX_MCDI_FEATURE_FW_UPDATE:
206         case EFX_MCDI_FEATURE_LINK_CONTROL:
207         case EFX_MCDI_FEATURE_MACADDR_CHANGE:
208         case EFX_MCDI_FEATURE_MAC_SPOOFING:
209                 *supportedp = B_TRUE;
210                 break;
211         default:
212                 rc = ENOTSUP;
213                 goto fail1;
214         }
215
216         return (0);
217
218 fail1:
219         EFSYS_PROBE1(fail1, efx_rc_t, rc);
220
221         return (rc);
222 }
223
224 /* Default timeout for MCDI command processing. */
225 #define SIENA_MCDI_CMD_TIMEOUT_US       (10 * 1000 * 1000)
226
227                         void
228 siena_mcdi_get_timeout(
229         __in            efx_nic_t *enp,
230         __in            efx_mcdi_req_t *emrp,
231         __out           uint32_t *timeoutp)
232 {
233         _NOTE(ARGUNUSED(enp, emrp))
234
235         *timeoutp = SIENA_MCDI_CMD_TIMEOUT_US;
236 }
237
238
239 #endif  /* EFSYS_OPT_SIENA && EFSYS_OPT_MCDI */