]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/dev/sfxge/common/efx_wol.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / dev / sfxge / common / efx_wol.c
1 /*-
2  * Copyright (c) 2009-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_types.h"
37 #include "efx_impl.h"
38
39 #if EFSYS_OPT_WOL
40
41         __checkReturn   int
42 efx_wol_init(
43         __in            efx_nic_t *enp)
44 {
45         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
46         int rc;
47
48         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
49         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
50         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_WOL));
51
52         if (~(encp->enc_features) & EFX_FEATURE_WOL) {
53                 rc = ENOTSUP;
54                 goto fail1;
55         }
56
57         /* Current implementation is Siena specific */
58         EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
59
60         enp->en_mod_flags |= EFX_MOD_WOL;
61
62         return (0);
63
64 fail1:
65         EFSYS_PROBE1(fail1, int, rc);
66
67         return (rc);
68 }
69
70         __checkReturn   int
71 efx_wol_filter_clear(
72         __in            efx_nic_t *enp)
73 {
74         efx_mcdi_req_t req;
75         uint8_t payload[MAX(MC_CMD_WOL_FILTER_RESET_IN_LEN,
76                             MC_CMD_WOL_FILTER_RESET_OUT_LEN)];
77         int rc;
78
79         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
80         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
81
82         (void) memset(payload, 0, sizeof (payload));
83         req.emr_cmd = MC_CMD_WOL_FILTER_RESET;
84         req.emr_in_buf = payload;
85         req.emr_in_length = MC_CMD_WOL_FILTER_RESET_IN_LEN;
86         req.emr_out_buf = payload;
87         req.emr_out_length = MC_CMD_WOL_FILTER_RESET_OUT_LEN;
88
89         MCDI_IN_SET_DWORD(req, WOL_FILTER_RESET_IN_MASK,
90                             MC_CMD_WOL_FILTER_RESET_IN_WAKE_FILTERS |
91                             MC_CMD_WOL_FILTER_RESET_IN_LIGHTSOUT_OFFLOADS);
92
93         efx_mcdi_execute(enp, &req);
94
95         if (req.emr_rc != 0) {
96                 rc = req.emr_rc;
97                 goto fail1;
98         }
99
100         return (0);
101
102 fail1:
103         EFSYS_PROBE1(fail1, int, rc);
104
105         return (rc);
106 }
107
108         __checkReturn   int
109 efx_wol_filter_add(
110         __in            efx_nic_t *enp,
111         __in            efx_wol_type_t type,
112         __in            efx_wol_param_t *paramp,
113         __out           uint32_t *filter_idp)
114 {
115         efx_mcdi_req_t req;
116         uint8_t payload[MAX(MC_CMD_WOL_FILTER_SET_IN_LEN,
117                             MC_CMD_WOL_FILTER_SET_OUT_LEN)];
118         efx_byte_t link_mask;
119         int rc;
120
121         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
122         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
123
124         (void) memset(payload, 0, sizeof (payload));
125         req.emr_cmd = MC_CMD_WOL_FILTER_SET;
126         req.emr_in_buf = payload;
127         req.emr_in_length = MC_CMD_WOL_FILTER_SET_IN_LEN;
128         req.emr_out_buf = payload;
129         req.emr_out_length = MC_CMD_WOL_FILTER_SET_OUT_LEN;
130
131         switch (type) {
132         case EFX_WOL_TYPE_MAGIC:
133                 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_FILTER_MODE,
134                                     MC_CMD_FILTER_MODE_SIMPLE);
135                 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_WOL_TYPE,
136                                     MC_CMD_WOL_TYPE_MAGIC);
137                 EFX_MAC_ADDR_COPY(
138                         MCDI_IN2(req, uint8_t, WOL_FILTER_SET_IN_MAGIC_MAC),
139                         paramp->ewp_magic.mac_addr);
140                 break;
141
142         case EFX_WOL_TYPE_BITMAP: {
143                 uint32_t swapped = 0;
144                 efx_dword_t *dwordp;
145                 unsigned int pos, bit;
146
147                 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_FILTER_MODE,
148                                     MC_CMD_FILTER_MODE_SIMPLE);
149                 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_WOL_TYPE,
150                                     MC_CMD_WOL_TYPE_BITMAP);
151
152                 /*
153                  * MC bitmask is supposed to be bit swapped
154                  * amongst 32 bit words(!)
155                  */
156
157                 dwordp = MCDI_IN2(req, efx_dword_t,
158                                     WOL_FILTER_SET_IN_BITMAP_MASK);
159
160                 EFSYS_ASSERT3U(EFX_WOL_BITMAP_MASK_SIZE % 4, ==, 0);
161
162                 for (pos = 0; pos < EFX_WOL_BITMAP_MASK_SIZE; ++pos) {
163                         uint8_t native = paramp->ewp_bitmap.mask[pos];
164
165                         for (bit = 0; bit < 8; ++bit) {
166                                 swapped <<= 1;
167                                 swapped |= (native & 0x1);
168                                 native >>= 1;
169                         }
170
171                         if ((pos & 3) == 3) {
172                                 EFX_POPULATE_DWORD_1(dwordp[pos >> 2],
173                                     EFX_DWORD_0, swapped);
174                                 swapped = 0;
175                         }
176                 }
177
178                 memcpy(MCDI_IN2(req, uint8_t, WOL_FILTER_SET_IN_BITMAP_BITMAP),
179                     paramp->ewp_bitmap.value,
180                     sizeof (paramp->ewp_bitmap.value));
181
182                 EFSYS_ASSERT3U(paramp->ewp_bitmap.value_len, <=,
183                                     sizeof (paramp->ewp_bitmap.value));
184                 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_BITMAP_LEN,
185                                     paramp->ewp_bitmap.value_len);
186                 }
187                 break;
188
189         case EFX_WOL_TYPE_LINK:
190                 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_FILTER_MODE,
191                                     MC_CMD_FILTER_MODE_SIMPLE);
192                 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_WOL_TYPE,
193                                     MC_CMD_WOL_TYPE_LINK);
194
195                 EFX_ZERO_BYTE(link_mask);
196                 EFX_SET_BYTE_FIELD(link_mask, MC_CMD_WOL_FILTER_SET_IN_LINK_UP,
197                     1);
198                 MCDI_IN_SET_BYTE(req, WOL_FILTER_SET_IN_LINK_MASK,
199                     link_mask.eb_u8[0]);
200                 break;
201
202         default:
203                 EFSYS_ASSERT3U(type, !=, type);
204         }
205
206         efx_mcdi_execute(enp, &req);
207
208         if (req.emr_rc != 0) {
209                 rc = req.emr_rc;
210                 goto fail1;
211         }
212
213         if (req.emr_out_length_used < MC_CMD_WOL_FILTER_SET_OUT_LEN) {
214                 rc = EMSGSIZE;
215                 goto fail2;
216         }
217
218         *filter_idp = MCDI_OUT_DWORD(req, WOL_FILTER_SET_OUT_FILTER_ID);
219
220         return (0);
221
222 fail2:
223         EFSYS_PROBE(fail2);
224 fail1:
225         EFSYS_PROBE1(fail1, int, rc);
226
227         return (rc);
228 }
229
230         __checkReturn   int
231 efx_wol_filter_remove(
232         __in            efx_nic_t *enp,
233         __in            uint32_t filter_id)
234 {
235         efx_mcdi_req_t req;
236         uint8_t payload[MAX(MC_CMD_WOL_FILTER_REMOVE_IN_LEN,
237                             MC_CMD_WOL_FILTER_REMOVE_OUT_LEN)];
238         int rc;
239
240         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
241         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
242
243         (void) memset(payload, 0, sizeof (payload));
244         req.emr_cmd = MC_CMD_WOL_FILTER_REMOVE;
245         req.emr_in_buf = payload;
246         req.emr_in_length = MC_CMD_WOL_FILTER_REMOVE_IN_LEN;
247         req.emr_out_buf = payload;
248         req.emr_out_length = MC_CMD_WOL_FILTER_REMOVE_OUT_LEN;
249
250         MCDI_IN_SET_DWORD(req, WOL_FILTER_REMOVE_IN_FILTER_ID, filter_id);
251
252         efx_mcdi_execute(enp, &req);
253
254         if (req.emr_rc != 0) {
255                 rc = req.emr_rc;
256                 goto fail1;
257         }
258
259         return (0);
260
261 fail1:
262         EFSYS_PROBE1(fail1, int, rc);
263
264         return (rc);
265 }
266
267
268         __checkReturn   int
269 efx_lightsout_offload_add(
270         __in            efx_nic_t *enp,
271         __in            efx_lightsout_offload_type_t type,
272         __in            efx_lightsout_offload_param_t *paramp,
273         __out           uint32_t *filter_idp)
274 {
275         efx_mcdi_req_t req;
276         uint8_t payload[MAX(MAX(MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARP_LEN,
277                                 MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NS_LEN),
278                             MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN)];
279         int rc;
280
281         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
282         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
283
284         (void) memset(payload, 0, sizeof (payload));
285         req.emr_cmd = MC_CMD_ADD_LIGHTSOUT_OFFLOAD;
286         req.emr_in_buf = payload;
287         req.emr_in_length = sizeof (type);
288         req.emr_out_buf = payload;
289         req.emr_out_length = MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN;
290
291         switch (type) {
292         case EFX_LIGHTSOUT_OFFLOAD_TYPE_ARP:
293                 req.emr_in_length = MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARP_LEN;
294
295                 MCDI_IN_SET_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_IN_PROTOCOL,
296                                     MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_ARP);
297                 EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t,
298                                             ADD_LIGHTSOUT_OFFLOAD_IN_ARP_MAC),
299                                     paramp->elop_arp.mac_addr);
300                 MCDI_IN_SET_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_IN_ARP_IP,
301                                     paramp->elop_arp.ip);
302                 break;
303         case EFX_LIGHTSOUT_OFFLOAD_TYPE_NS:
304                 req.emr_in_length = MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NS_LEN;
305
306                 MCDI_IN_SET_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_IN_PROTOCOL,
307                                     MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_NS);
308                 EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t,
309                                             ADD_LIGHTSOUT_OFFLOAD_IN_NS_MAC),
310                                     paramp->elop_ns.mac_addr);
311                 memcpy(MCDI_IN2(req, uint8_t,
312                     ADD_LIGHTSOUT_OFFLOAD_IN_NS_SNIPV6),
313                     paramp->elop_ns.solicited_node,
314                     sizeof (paramp->elop_ns.solicited_node));
315                 memcpy(MCDI_IN2(req, uint8_t, ADD_LIGHTSOUT_OFFLOAD_IN_NS_IPV6),
316                     paramp->elop_ns.ip, sizeof (paramp->elop_ns.ip));
317                 break;
318         default:
319                 rc = EINVAL;
320                 goto fail1;
321         }
322
323         efx_mcdi_execute(enp, &req);
324
325         if (req.emr_rc != 0) {
326                 rc = req.emr_rc;
327                 goto fail2;
328         }
329
330         if (req.emr_out_length_used < MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN) {
331                 rc = EMSGSIZE;
332                 goto fail3;
333         }
334
335         *filter_idp = MCDI_OUT_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_OUT_FILTER_ID);
336
337         return (0);
338
339 fail3:
340         EFSYS_PROBE(fail3);
341 fail2:
342         EFSYS_PROBE(fail2);
343 fail1:
344         EFSYS_PROBE1(fail1, int, rc);
345
346         return (rc);
347 }
348
349
350         __checkReturn   int
351 efx_lightsout_offload_remove(
352         __in            efx_nic_t *enp,
353         __in            efx_lightsout_offload_type_t type,
354         __in            uint32_t filter_id)
355 {
356         efx_mcdi_req_t req;
357         uint8_t payload[MAX(MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN,
358                             MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_OUT_LEN)];
359         int rc;
360
361         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
362         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
363
364         (void) memset(payload, 0, sizeof (payload));
365         req.emr_cmd = MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD;
366         req.emr_in_buf = payload;
367         req.emr_in_length = MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN;
368         req.emr_out_buf = payload;
369         req.emr_out_length = MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_OUT_LEN;
370
371         switch (type) {
372         case EFX_LIGHTSOUT_OFFLOAD_TYPE_ARP:
373                 MCDI_IN_SET_DWORD(req, REMOVE_LIGHTSOUT_OFFLOAD_IN_PROTOCOL,
374                                     MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_ARP);
375                 break;
376         case EFX_LIGHTSOUT_OFFLOAD_TYPE_NS:
377                 MCDI_IN_SET_DWORD(req, REMOVE_LIGHTSOUT_OFFLOAD_IN_PROTOCOL,
378                                     MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_NS);
379                 break;
380         default:
381                 rc = EINVAL;
382                 goto fail1;
383         }
384
385         MCDI_IN_SET_DWORD(req, REMOVE_LIGHTSOUT_OFFLOAD_IN_FILTER_ID,
386                             filter_id);
387
388         efx_mcdi_execute(enp, &req);
389
390         if (req.emr_rc != 0) {
391                 rc = req.emr_rc;
392                 goto fail2;
393         }
394
395         return (0);
396
397 fail2:
398         EFSYS_PROBE(fail2);
399 fail1:
400         EFSYS_PROBE1(fail1, int, rc);
401
402         return (rc);
403 }
404
405
406                         void
407 efx_wol_fini(
408         __in            efx_nic_t *enp)
409 {
410         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
411         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
412         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
413
414         enp->en_mod_flags &= ~EFX_MOD_WOL;
415 }
416
417 #endif  /* EFSYS_OPT_WOL */