aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c66
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h49
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h2
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 */
80enum iwl_ucode_tlv_flag { 82enum 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,
373static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, 373static 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
408enum iwl_mvm_tcp_packet_type { 440enum 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 */
115struct iwl_proto_offload_cmd { 113struct 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 */
130struct 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 */
148struct 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