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