1/*- 2 * Copyright 2009 Solarflare Communications Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD$"); 28 29#include "efsys.h" 30#include "efx.h" 31#include "efx_types.h" 32#include "efx_impl.h" 33 34#if EFSYS_OPT_WOL 35 36 __checkReturn int 37efx_wol_init( 38 __in efx_nic_t *enp) 39{ 40 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 41 int rc; 42 43 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 44 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 45 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_WOL)); 46 47 if (~(encp->enc_features) & EFX_FEATURE_WOL) { 48 rc = ENOTSUP; 49 goto fail1; 50 } 51 52 /* Current implementation is Siena specific */ 53 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 54 55 enp->en_mod_flags |= EFX_MOD_WOL; 56 57 return (0); 58 59fail1: 60 EFSYS_PROBE1(fail1, int, rc); 61 62 return (rc); 63} 64 65 __checkReturn int 66efx_wol_filter_clear( 67 __in efx_nic_t *enp) 68{ 69 efx_mcdi_req_t req; 70 uint8_t payload[MC_CMD_WOL_FILTER_RESET_IN_LEN]; 71 int rc; 72 73 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 74 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL); 75 76 req.emr_cmd = MC_CMD_WOL_FILTER_RESET; 77 req.emr_in_buf = payload; 78 req.emr_in_length = MC_CMD_WOL_FILTER_RESET_IN_LEN; 79 req.emr_out_buf = NULL; 80 req.emr_out_length = 0; 81 82 MCDI_IN_SET_DWORD(req, WOL_FILTER_RESET_IN_MASK, 83 MC_CMD_WOL_FILTER_RESET_IN_WAKE_FILTERS | 84 MC_CMD_WOL_FILTER_RESET_IN_LIGHTSOUT_OFFLOADS); 85 86 efx_mcdi_execute(enp, &req); 87 88 if (req.emr_rc != 0) { 89 rc = req.emr_rc; 90 goto fail1; 91 } 92 93 return (0); 94 95fail1: 96 EFSYS_PROBE1(fail1, int, rc); 97 98 return (rc); 99} 100 101 __checkReturn int 102efx_wol_filter_add( 103 __in efx_nic_t *enp, 104 __in efx_wol_type_t type, 105 __in efx_wol_param_t *paramp, 106 __out uint32_t *filter_idp) 107{ 108 efx_mcdi_req_t req; 109 uint8_t payload[MAX(MC_CMD_WOL_FILTER_SET_IN_LEN, 110 MC_CMD_WOL_FILTER_SET_OUT_LEN)]; 111 efx_byte_t link_mask; 112 int rc; 113 114 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 115 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL); 116 117 req.emr_cmd = MC_CMD_WOL_FILTER_SET; 118 (void) memset(payload, '\0', sizeof (payload)); 119 req.emr_in_buf = payload; 120 req.emr_in_length = MC_CMD_WOL_FILTER_SET_IN_LEN; 121 req.emr_out_buf = payload; 122 req.emr_out_length = MC_CMD_WOL_FILTER_SET_OUT_LEN; 123 124 switch (type) { 125 case EFX_WOL_TYPE_MAGIC: 126 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_FILTER_MODE, 127 MC_CMD_FILTER_MODE_SIMPLE); 128 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_WOL_TYPE, 129 MC_CMD_WOL_TYPE_MAGIC); 130 EFX_MAC_ADDR_COPY( 131 MCDI_IN2(req, uint8_t, WOL_FILTER_SET_IN_MAGIC_MAC), 132 paramp->ewp_magic.mac_addr); 133 break; 134 135 case EFX_WOL_TYPE_BITMAP: { 136 uint32_t swapped = 0; 137 efx_dword_t *dwordp; 138 unsigned int pos, bit; 139 140 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_FILTER_MODE, 141 MC_CMD_FILTER_MODE_SIMPLE); 142 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_WOL_TYPE, 143 MC_CMD_WOL_TYPE_BITMAP); 144 145 /* 146 * MC bitmask is supposed to be bit swapped 147 * amongst 32 bit words(!) 148 */ 149 150 dwordp = MCDI_IN2(req, efx_dword_t, 151 WOL_FILTER_SET_IN_BITMAP_MASK); 152 153 EFSYS_ASSERT3U(EFX_WOL_BITMAP_MASK_SIZE % 4, ==, 0); 154 155 for (pos = 0; pos < EFX_WOL_BITMAP_MASK_SIZE; ++pos) { 156 uint8_t native = paramp->ewp_bitmap.mask[pos]; 157 158 for (bit = 0; bit < 8; ++bit) { 159 swapped <<= 1; 160 swapped |= (native & 0x1); 161 native >>= 1; 162 } 163 164 if ((pos & 3) == 3) { 165 EFX_POPULATE_DWORD_1(dwordp[pos >> 2], 166 EFX_DWORD_0, swapped); 167 swapped = 0; 168 } 169 } 170 171 memcpy(MCDI_IN2(req, uint8_t, WOL_FILTER_SET_IN_BITMAP_BITMAP), 172 paramp->ewp_bitmap.value, 173 sizeof (paramp->ewp_bitmap.value)); 174 175 EFSYS_ASSERT3U(paramp->ewp_bitmap.value_len, <=, 176 sizeof (paramp->ewp_bitmap.value)); 177 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_BITMAP_LEN, 178 paramp->ewp_bitmap.value_len); 179 } 180 break; 181 182 case EFX_WOL_TYPE_LINK: 183 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_FILTER_MODE, 184 MC_CMD_FILTER_MODE_SIMPLE); 185 MCDI_IN_SET_DWORD(req, WOL_FILTER_SET_IN_WOL_TYPE, 186 MC_CMD_WOL_TYPE_LINK); 187 188 EFX_ZERO_BYTE(link_mask); 189 EFX_SET_BYTE_FIELD(link_mask, MC_CMD_WOL_FILTER_SET_IN_LINK_UP, 190 1); 191 MCDI_IN_SET_BYTE(req, WOL_FILTER_SET_IN_LINK_MASK, 192 link_mask.eb_u8[0]); 193 break; 194 195 default: 196 EFSYS_ASSERT3U(type, !=, type); 197 } 198 199 efx_mcdi_execute(enp, &req); 200 201 if (req.emr_rc != 0) { 202 rc = req.emr_rc; 203 goto fail1; 204 } 205 206 if (req.emr_out_length_used < MC_CMD_WOL_FILTER_SET_OUT_LEN) { 207 rc = EMSGSIZE; 208 goto fail2; 209 } 210 211 *filter_idp = MCDI_OUT_DWORD(req, WOL_FILTER_SET_OUT_FILTER_ID); 212 213 return (0); 214 215fail2: 216 EFSYS_PROBE(fail2); 217fail1: 218 EFSYS_PROBE1(fail1, int, rc); 219 220 return (rc); 221} 222 223 __checkReturn int 224efx_wol_filter_remove( 225 __in efx_nic_t *enp, 226 __in uint32_t filter_id) 227{ 228 efx_mcdi_req_t req; 229 uint8_t payload[MC_CMD_WOL_FILTER_REMOVE_IN_LEN]; 230 int rc; 231 232 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 233 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL); 234 235 req.emr_cmd = MC_CMD_WOL_FILTER_REMOVE; 236 req.emr_in_buf = payload; 237 req.emr_in_length = MC_CMD_WOL_FILTER_REMOVE_IN_LEN; 238 EFX_STATIC_ASSERT(MC_CMD_WOL_FILTER_REMOVE_OUT_LEN == 0); 239 req.emr_out_buf = NULL; 240 req.emr_out_length = 0; 241 242 MCDI_IN_SET_DWORD(req, WOL_FILTER_REMOVE_IN_FILTER_ID, filter_id); 243 244 efx_mcdi_execute(enp, &req); 245 246 if (req.emr_rc != 0) { 247 rc = req.emr_rc; 248 goto fail1; 249 } 250 251 return (0); 252 253fail1: 254 EFSYS_PROBE1(fail1, int, rc); 255 256 return (rc); 257} 258 259 260 __checkReturn int 261efx_lightsout_offload_add( 262 __in efx_nic_t *enp, 263 __in efx_lightsout_offload_type_t type, 264 __in efx_lightsout_offload_param_t *paramp, 265 __out uint32_t *filter_idp) 266{ 267 efx_mcdi_req_t req; 268 uint8_t payload[MAX(MAX(MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARP_LEN, 269 MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NS_LEN), 270 MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN)]; 271 int rc; 272 273 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 274 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL); 275 276 req.emr_cmd = MC_CMD_ADD_LIGHTSOUT_OFFLOAD; 277 req.emr_in_buf = payload; 278 req.emr_in_length = sizeof (type); 279 req.emr_out_buf = payload; 280 req.emr_out_length = MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN; 281 282 switch (type) { 283 case EFX_LIGHTSOUT_OFFLOAD_TYPE_ARP: 284 req.emr_in_length = MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARP_LEN; 285 MCDI_IN_SET_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_IN_PROTOCOL, 286 MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_ARP); 287 EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, 288 ADD_LIGHTSOUT_OFFLOAD_IN_ARP_MAC), 289 paramp->elop_arp.mac_addr); 290 MCDI_IN_SET_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_IN_ARP_IP, 291 paramp->elop_arp.ip); 292 break; 293 case EFX_LIGHTSOUT_OFFLOAD_TYPE_NS: 294 req.emr_in_length = MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NS_LEN; 295 MCDI_IN_SET_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_IN_PROTOCOL, 296 MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_NS); 297 EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, 298 ADD_LIGHTSOUT_OFFLOAD_IN_NS_MAC), 299 paramp->elop_ns.mac_addr); 300 memcpy(MCDI_IN2(req, uint8_t, 301 ADD_LIGHTSOUT_OFFLOAD_IN_NS_SNIPV6), 302 paramp->elop_ns.solicited_node, 303 sizeof (paramp->elop_ns.solicited_node)); 304 memcpy(MCDI_IN2(req, uint8_t, ADD_LIGHTSOUT_OFFLOAD_IN_NS_IPV6), 305 paramp->elop_ns.ip, sizeof (paramp->elop_ns.ip)); 306 break; 307 default: 308 EFSYS_ASSERT3U(type, !=, type); 309 } 310 311 efx_mcdi_execute(enp, &req); 312 313 if (req.emr_rc != 0) { 314 rc = req.emr_rc; 315 goto fail1; 316 } 317 318 if (req.emr_out_length_used < MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN) { 319 rc = EMSGSIZE; 320 goto fail2; 321 } 322 323 *filter_idp = MCDI_OUT_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_OUT_FILTER_ID); 324 325 return (0); 326 327fail2: 328 EFSYS_PROBE(fail2); 329fail1: 330 EFSYS_PROBE1(fail1, int, rc); 331 332 return (rc); 333} 334 335 336 __checkReturn int 337efx_lightsout_offload_remove( 338 __in efx_nic_t *enp, 339 __in efx_lightsout_offload_type_t type, 340 __in uint32_t filter_id) 341{ 342 efx_mcdi_req_t req; 343 uint8_t payload[MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN]; 344 int rc; 345 346 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 347 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL); 348 349 req.emr_cmd = MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD; 350 req.emr_in_buf = payload; 351 req.emr_in_length = sizeof (payload); 352 EFX_STATIC_ASSERT(MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_OUT_LEN == 0); 353 req.emr_out_buf = NULL; 354 req.emr_out_length = 0; 355 356 switch (type) { 357 case EFX_LIGHTSOUT_OFFLOAD_TYPE_ARP: 358 MCDI_IN_SET_DWORD(req, REMOVE_LIGHTSOUT_OFFLOAD_IN_PROTOCOL, 359 MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_ARP); 360 break; 361 case EFX_LIGHTSOUT_OFFLOAD_TYPE_NS: 362 MCDI_IN_SET_DWORD(req, REMOVE_LIGHTSOUT_OFFLOAD_IN_PROTOCOL, 363 MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_NS); 364 break; 365 default: 366 EFSYS_ASSERT3U(type, !=, type); 367 } 368 369 MCDI_IN_SET_DWORD(req, REMOVE_LIGHTSOUT_OFFLOAD_IN_FILTER_ID, 370 filter_id); 371 372 efx_mcdi_execute(enp, &req); 373 374 if (req.emr_rc != 0) { 375 rc = req.emr_rc; 376 goto fail1; 377 } 378 379 return (0); 380 381fail1: 382 EFSYS_PROBE1(fail1, int, rc); 383 384 return (rc); 385} 386 387 388 void 389efx_wol_fini( 390 __in efx_nic_t *enp) 391{ 392 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 393 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 394 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL); 395 396 enp->en_mod_flags &= ~EFX_MOD_WOL; 397} 398 399#endif /* EFSYS_OPT_WOL */ 400