diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-fw.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/d3.c | 66 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | 49 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 |
4 files changed, 92 insertions, 28 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 46dc38a32115..b766ee9bb05a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -76,6 +76,8 @@ | |||
76 | * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS | 76 | * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS |
77 | * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD | 77 | * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD |
78 | * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api | 78 | * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api |
79 | * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six | ||
80 | * (rather than two) IPv6 addresses | ||
79 | */ | 81 | */ |
80 | enum iwl_ucode_tlv_flag { | 82 | enum iwl_ucode_tlv_flag { |
81 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), | 83 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), |
@@ -85,6 +87,7 @@ enum iwl_ucode_tlv_flag { | |||
85 | IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), | 87 | IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), |
86 | IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), | 88 | IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), |
87 | IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8), | 89 | IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8), |
90 | IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), | ||
88 | }; | 91 | }; |
89 | 92 | ||
90 | /* The default calibrate table size if not specified by firmware file */ | 93 | /* The default calibrate table size if not specified by firmware file */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 7e5e5c2f9f87..ebf7f9468926 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -105,7 +105,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, | |||
105 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 105 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
106 | mvmvif->target_ipv6_addrs[idx] = ifa->addr; | 106 | mvmvif->target_ipv6_addrs[idx] = ifa->addr; |
107 | idx++; | 107 | idx++; |
108 | if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) | 108 | if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX) |
109 | break; | 109 | break; |
110 | } | 110 | } |
111 | read_unlock_bh(&idev->lock); | 111 | read_unlock_bh(&idev->lock); |
@@ -373,36 +373,68 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, | |||
373 | static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | 373 | static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, |
374 | struct ieee80211_vif *vif) | 374 | struct ieee80211_vif *vif) |
375 | { | 375 | { |
376 | struct iwl_proto_offload_cmd cmd = {}; | 376 | union { |
377 | struct iwl_proto_offload_cmd_v1 v1; | ||
378 | struct iwl_proto_offload_cmd_v2 v2; | ||
379 | } cmd = {}; | ||
380 | struct iwl_proto_offload_cmd_common *common; | ||
381 | u32 enabled = 0, size; | ||
377 | #if IS_ENABLED(CONFIG_IPV6) | 382 | #if IS_ENABLED(CONFIG_IPV6) |
378 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 383 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
379 | int i; | 384 | int i; |
380 | 385 | ||
381 | if (mvmvif->num_target_ipv6_addrs) { | 386 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { |
382 | cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_NS); | 387 | if (mvmvif->num_target_ipv6_addrs) { |
383 | memcpy(cmd.ndp_mac_addr, vif->addr, ETH_ALEN); | 388 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; |
384 | } | 389 | memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); |
390 | } | ||
391 | |||
392 | BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) != | ||
393 | sizeof(mvmvif->target_ipv6_addrs[0])); | ||
394 | |||
395 | for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, | ||
396 | IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) | ||
397 | memcpy(cmd.v2.target_ipv6_addr[i], | ||
398 | &mvmvif->target_ipv6_addrs[i], | ||
399 | sizeof(cmd.v2.target_ipv6_addr[i])); | ||
400 | } else { | ||
401 | if (mvmvif->num_target_ipv6_addrs) { | ||
402 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; | ||
403 | memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN); | ||
404 | } | ||
385 | 405 | ||
386 | BUILD_BUG_ON(sizeof(cmd.target_ipv6_addr[i]) != | 406 | BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) != |
387 | sizeof(mvmvif->target_ipv6_addrs[i])); | 407 | sizeof(mvmvif->target_ipv6_addrs[0])); |
388 | 408 | ||
389 | for (i = 0; i < mvmvif->num_target_ipv6_addrs; i++) | 409 | for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, |
390 | memcpy(cmd.target_ipv6_addr[i], | 410 | IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) |
391 | &mvmvif->target_ipv6_addrs[i], | 411 | memcpy(cmd.v1.target_ipv6_addr[i], |
392 | sizeof(cmd.target_ipv6_addr[i])); | 412 | &mvmvif->target_ipv6_addrs[i], |
413 | sizeof(cmd.v1.target_ipv6_addr[i])); | ||
414 | } | ||
393 | #endif | 415 | #endif |
394 | 416 | ||
417 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { | ||
418 | common = &cmd.v2.common; | ||
419 | size = sizeof(cmd.v2); | ||
420 | } else { | ||
421 | common = &cmd.v1.common; | ||
422 | size = sizeof(cmd.v1); | ||
423 | } | ||
424 | |||
395 | if (vif->bss_conf.arp_addr_cnt) { | 425 | if (vif->bss_conf.arp_addr_cnt) { |
396 | cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_ARP); | 426 | enabled |= IWL_D3_PROTO_OFFLOAD_ARP; |
397 | cmd.host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; | 427 | common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; |
398 | memcpy(cmd.arp_mac_addr, vif->addr, ETH_ALEN); | 428 | memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); |
399 | } | 429 | } |
400 | 430 | ||
401 | if (!cmd.enabled) | 431 | if (!enabled) |
402 | return 0; | 432 | return 0; |
403 | 433 | ||
434 | common->enabled = cpu_to_le32(enabled); | ||
435 | |||
404 | return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC, | 436 | return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC, |
405 | sizeof(cmd), &cmd); | 437 | size, &cmd); |
406 | } | 438 | } |
407 | 439 | ||
408 | enum iwl_mvm_tcp_packet_type { | 440 | enum iwl_mvm_tcp_packet_type { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 6f8b2c16ae17..df72fcdf8170 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | |||
@@ -98,34 +98,63 @@ enum iwl_proto_offloads { | |||
98 | IWL_D3_PROTO_OFFLOAD_NS = BIT(1), | 98 | IWL_D3_PROTO_OFFLOAD_NS = BIT(1), |
99 | }; | 99 | }; |
100 | 100 | ||
101 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS 2 | 101 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2 |
102 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2 6 | ||
103 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 6 | ||
102 | 104 | ||
103 | /** | 105 | /** |
104 | * struct iwl_proto_offload_cmd - ARP/NS offload configuration | 106 | * struct iwl_proto_offload_cmd_common - ARP/NS offload common part |
105 | * @enabled: enable flags | 107 | * @enabled: enable flags |
106 | * @remote_ipv4_addr: remote address to answer to (or zero if all) | 108 | * @remote_ipv4_addr: remote address to answer to (or zero if all) |
107 | * @host_ipv4_addr: our IPv4 address to respond to queries for | 109 | * @host_ipv4_addr: our IPv4 address to respond to queries for |
108 | * @arp_mac_addr: our MAC address for ARP responses | 110 | * @arp_mac_addr: our MAC address for ARP responses |
109 | * @remote_ipv6_addr: remote address to answer to (or zero if all) | 111 | * @reserved: unused |
110 | * @solicited_node_ipv6_addr: broken -- solicited node address exists | ||
111 | * for each target address | ||
112 | * @target_ipv6_addr: our target addresses | ||
113 | * @ndp_mac_addr: neighbor soliciation response MAC address | ||
114 | */ | 112 | */ |
115 | struct iwl_proto_offload_cmd { | 113 | struct iwl_proto_offload_cmd_common { |
116 | __le32 enabled; | 114 | __le32 enabled; |
117 | __be32 remote_ipv4_addr; | 115 | __be32 remote_ipv4_addr; |
118 | __be32 host_ipv4_addr; | 116 | __be32 host_ipv4_addr; |
119 | u8 arp_mac_addr[ETH_ALEN]; | 117 | u8 arp_mac_addr[ETH_ALEN]; |
120 | __le16 reserved1; | 118 | __le16 reserved; |
119 | } __packed; | ||
121 | 120 | ||
121 | /** | ||
122 | * struct iwl_proto_offload_cmd_v1 - ARP/NS offload configuration | ||
123 | * @common: common/IPv4 configuration | ||
124 | * @remote_ipv6_addr: remote address to answer to (or zero if all) | ||
125 | * @solicited_node_ipv6_addr: broken -- solicited node address exists | ||
126 | * for each target address | ||
127 | * @target_ipv6_addr: our target addresses | ||
128 | * @ndp_mac_addr: neighbor soliciation response MAC address | ||
129 | */ | ||
130 | struct iwl_proto_offload_cmd_v1 { | ||
131 | struct iwl_proto_offload_cmd_common common; | ||
122 | u8 remote_ipv6_addr[16]; | 132 | u8 remote_ipv6_addr[16]; |
123 | u8 solicited_node_ipv6_addr[16]; | 133 | u8 solicited_node_ipv6_addr[16]; |
124 | u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS][16]; | 134 | u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1][16]; |
125 | u8 ndp_mac_addr[ETH_ALEN]; | 135 | u8 ndp_mac_addr[ETH_ALEN]; |
126 | __le16 reserved2; | 136 | __le16 reserved2; |
127 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */ | 137 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */ |
128 | 138 | ||
139 | /** | ||
140 | * struct iwl_proto_offload_cmd_v2 - ARP/NS offload configuration | ||
141 | * @common: common/IPv4 configuration | ||
142 | * @remote_ipv6_addr: remote address to answer to (or zero if all) | ||
143 | * @solicited_node_ipv6_addr: broken -- solicited node address exists | ||
144 | * for each target address | ||
145 | * @target_ipv6_addr: our target addresses | ||
146 | * @ndp_mac_addr: neighbor soliciation response MAC address | ||
147 | */ | ||
148 | struct iwl_proto_offload_cmd_v2 { | ||
149 | struct iwl_proto_offload_cmd_common common; | ||
150 | u8 remote_ipv6_addr[16]; | ||
151 | u8 solicited_node_ipv6_addr[16]; | ||
152 | u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2][16]; | ||
153 | u8 ndp_mac_addr[ETH_ALEN]; | ||
154 | u8 numValidIPv6Addresses; | ||
155 | u8 reserved2[3]; | ||
156 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */ | ||
157 | |||
129 | 158 | ||
130 | /* | 159 | /* |
131 | * WOWLAN_PATTERNS | 160 | * WOWLAN_PATTERNS |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index caa6a1758172..879fb01da40c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -282,7 +282,7 @@ struct iwl_mvm_vif { | |||
282 | 282 | ||
283 | #if IS_ENABLED(CONFIG_IPV6) | 283 | #if IS_ENABLED(CONFIG_IPV6) |
284 | /* IPv6 addresses for WoWLAN */ | 284 | /* IPv6 addresses for WoWLAN */ |
285 | struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS]; | 285 | struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX]; |
286 | int num_target_ipv6_addrs; | 286 | int num_target_ipv6_addrs; |
287 | #endif | 287 | #endif |
288 | #endif | 288 | #endif |