1
2
3
4
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
29siena_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
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
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
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
66siena_mcdi_poll_reboot(
67 __in efx_nic_t *enp)
68{
69#if 1
70
71
72
73
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
103extern __checkReturn boolean_t
104siena_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
119siena_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 = 0;
128 efx_dword_t data;
129 size_t remaining = length;
130
131 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
132 pdur = SIENA_MCDI_PDU(emip);
133
134 while (remaining > 0) {
135 size_t chunk = MIN(remaining, sizeof (data));
136
137 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
138 pdur + ((offset + pos) >> 2), &data, B_FALSE);
139 memcpy((uint8_t *)bufferp + pos, &data, chunk);
140 pos += chunk;
141 remaining -= chunk;
142 }
143}
144
145 __checkReturn efx_rc_t
146siena_mcdi_init(
147 __in efx_nic_t *enp,
148 __in const efx_mcdi_transport_t *mtp)
149{
150 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
151 efx_oword_t oword;
152 unsigned int portnum;
153 efx_rc_t rc;
154
155 _NOTE(ARGUNUSED(mtp))
156
157 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
158
159
160 EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword);
161 portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
162
163 if (portnum == 0) {
164
165 emip->emi_port = 1;
166 } else if (portnum <= 2) {
167 emip->emi_port = portnum;
168 } else {
169 rc = EINVAL;
170 goto fail1;
171 }
172
173
174 emip->emi_max_version = 1;
175
176
177
178
179
180
181 (void) siena_mcdi_poll_reboot(enp);
182
183 return (0);
184
185fail1:
186 EFSYS_PROBE1(fail1, efx_rc_t, rc);
187
188 return (rc);
189}
190
191 void
192siena_mcdi_fini(
193 __in efx_nic_t *enp)
194{
195 _NOTE(ARGUNUSED(enp))
196}
197
198 __checkReturn efx_rc_t
199siena_mcdi_feature_supported(
200 __in efx_nic_t *enp,
201 __in efx_mcdi_feature_id_t id,
202 __out boolean_t *supportedp)
203{
204 efx_rc_t rc;
205
206 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
207
208 switch (id) {
209 case EFX_MCDI_FEATURE_FW_UPDATE:
210 case EFX_MCDI_FEATURE_LINK_CONTROL:
211 case EFX_MCDI_FEATURE_MACADDR_CHANGE:
212 case EFX_MCDI_FEATURE_MAC_SPOOFING:
213 *supportedp = B_TRUE;
214 break;
215 default:
216 rc = ENOTSUP;
217 goto fail1;
218 }
219
220 return (0);
221
222fail1:
223 EFSYS_PROBE1(fail1, efx_rc_t, rc);
224
225 return (rc);
226}
227
228
229#define SIENA_MCDI_CMD_TIMEOUT_US (10 * 1000 * 1000)
230
231 void
232siena_mcdi_get_timeout(
233 __in efx_nic_t *enp,
234 __in efx_mcdi_req_t *emrp,
235 __out uint32_t *timeoutp)
236{
237 _NOTE(ARGUNUSED(enp, emrp))
238
239 *timeoutp = SIENA_MCDI_CMD_TIMEOUT_US;
240}
241
242
243#endif
244