diff options
315 files changed, 16521 insertions, 4441 deletions
diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt index 62a48348ac15..edd44d802139 100644 --- a/Documentation/devicetree/bindings/bus/bcma.txt +++ b/Documentation/devicetree/bindings/bus/bcma.txt | |||
@@ -8,6 +8,11 @@ Required properties: | |||
8 | 8 | ||
9 | The cores on the AXI bus are automatically detected by bcma with the | 9 | The cores on the AXI bus are automatically detected by bcma with the |
10 | memory ranges they are using and they get registered afterwards. | 10 | memory ranges they are using and they get registered afterwards. |
11 | Automatic detection of the IRQ number is not working on | ||
12 | BCM47xx/BCM53xx ARM SoCs. To assign IRQ numbers to the cores, provide | ||
13 | them manually through device tree. Use an interrupt-map to specify the | ||
14 | IRQ used by the devices on the bus. The first address is just an index, | ||
15 | because we do not have any special register. | ||
11 | 16 | ||
12 | The top-level axi bus may contain children representing attached cores | 17 | The top-level axi bus may contain children representing attached cores |
13 | (devices). This is needed since some hardware details can't be auto | 18 | (devices). This is needed since some hardware details can't be auto |
@@ -22,6 +27,22 @@ Example: | |||
22 | ranges = <0x00000000 0x18000000 0x00100000>; | 27 | ranges = <0x00000000 0x18000000 0x00100000>; |
23 | #address-cells = <1>; | 28 | #address-cells = <1>; |
24 | #size-cells = <1>; | 29 | #size-cells = <1>; |
30 | #interrupt-cells = <1>; | ||
31 | interrupt-map-mask = <0x000fffff 0xffff>; | ||
32 | interrupt-map = | ||
33 | /* Ethernet Controller 0 */ | ||
34 | <0x00024000 0 &gic GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>, | ||
35 | |||
36 | /* Ethernet Controller 1 */ | ||
37 | <0x00025000 0 &gic GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; | ||
38 | |||
39 | /* PCIe Controller 0 */ | ||
40 | <0x00012000 0 &gic GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>, | ||
41 | <0x00012000 1 &gic GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>, | ||
42 | <0x00012000 2 &gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, | ||
43 | <0x00012000 3 &gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>, | ||
44 | <0x00012000 4 &gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, | ||
45 | <0x00012000 5 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; | ||
25 | 46 | ||
26 | chipcommon { | 47 | chipcommon { |
27 | reg = <0x00000000 0x1000>; | 48 | reg = <0x00000000 0x1000>; |
diff --git a/MAINTAINERS b/MAINTAINERS index 7ec37a396ffe..e3f40df47513 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -7845,11 +7845,10 @@ S: Maintained | |||
7845 | F: drivers/media/dvb-frontends/rtl2832_sdr* | 7845 | F: drivers/media/dvb-frontends/rtl2832_sdr* |
7846 | 7846 | ||
7847 | RTL8180 WIRELESS DRIVER | 7847 | RTL8180 WIRELESS DRIVER |
7848 | M: "John W. Linville" <linville@tuxdriver.com> | ||
7849 | L: linux-wireless@vger.kernel.org | 7848 | L: linux-wireless@vger.kernel.org |
7850 | W: http://wireless.kernel.org/ | 7849 | W: http://wireless.kernel.org/ |
7851 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git | 7850 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git |
7852 | S: Maintained | 7851 | S: Orphan |
7853 | F: drivers/net/wireless/rtl818x/rtl8180/ | 7852 | F: drivers/net/wireless/rtl818x/rtl8180/ |
7854 | 7853 | ||
7855 | RTL8187 WIRELESS DRIVER | 7854 | RTL8187 WIRELESS DRIVER |
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index b068f98920a8..19f679667ca4 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c | |||
@@ -339,7 +339,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc) | |||
339 | return; | 339 | return; |
340 | } | 340 | } |
341 | 341 | ||
342 | irq = bcma_core_irq(cc->core); | 342 | irq = bcma_core_irq(cc->core, 0); |
343 | 343 | ||
344 | /* Determine the registers of the UARTs */ | 344 | /* Determine the registers of the UARTs */ |
345 | cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART); | 345 | cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART); |
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c index 706b9ae0dcfb..598a6cd9028a 100644 --- a/drivers/bcma/driver_gpio.c +++ b/drivers/bcma/driver_gpio.c | |||
@@ -152,7 +152,7 @@ static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc) | |||
152 | handle_simple_irq); | 152 | handle_simple_irq); |
153 | } | 153 | } |
154 | 154 | ||
155 | hwirq = bcma_core_irq(cc->core); | 155 | hwirq = bcma_core_irq(cc->core, 0); |
156 | err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio", | 156 | err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio", |
157 | cc); | 157 | cc); |
158 | if (err) | 158 | if (err) |
@@ -183,7 +183,7 @@ static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc) | |||
183 | return; | 183 | return; |
184 | 184 | ||
185 | bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO); | 185 | bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO); |
186 | free_irq(bcma_core_irq(cc->core), cc); | 186 | free_irq(bcma_core_irq(cc->core, 0), cc); |
187 | for (gpio = 0; gpio < chip->ngpio; gpio++) { | 187 | for (gpio = 0; gpio < chip->ngpio; gpio++) { |
188 | int irq = irq_find_mapping(cc->irq_domain, gpio); | 188 | int irq = irq_find_mapping(cc->irq_domain, gpio); |
189 | 189 | ||
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index 004d6aa671ce..5ec69c3d409d 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c | |||
@@ -115,7 +115,7 @@ static u32 bcma_core_mips_irqflag(struct bcma_device *dev) | |||
115 | * If disabled, 5 is returned. | 115 | * If disabled, 5 is returned. |
116 | * If not supported, 6 is returned. | 116 | * If not supported, 6 is returned. |
117 | */ | 117 | */ |
118 | static unsigned int bcma_core_mips_irq(struct bcma_device *dev) | 118 | unsigned int bcma_core_mips_irq(struct bcma_device *dev) |
119 | { | 119 | { |
120 | struct bcma_device *mdev = dev->bus->drv_mips.core; | 120 | struct bcma_device *mdev = dev->bus->drv_mips.core; |
121 | u32 irqflag; | 121 | u32 irqflag; |
@@ -133,13 +133,6 @@ static unsigned int bcma_core_mips_irq(struct bcma_device *dev) | |||
133 | return 5; | 133 | return 5; |
134 | } | 134 | } |
135 | 135 | ||
136 | unsigned int bcma_core_irq(struct bcma_device *dev) | ||
137 | { | ||
138 | unsigned int mips_irq = bcma_core_mips_irq(dev); | ||
139 | return mips_irq <= 4 ? mips_irq + 2 : 0; | ||
140 | } | ||
141 | EXPORT_SYMBOL(bcma_core_irq); | ||
142 | |||
143 | static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) | 136 | static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) |
144 | { | 137 | { |
145 | unsigned int oldirq = bcma_core_mips_irq(dev); | 138 | unsigned int oldirq = bcma_core_mips_irq(dev); |
@@ -423,7 +416,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore) | |||
423 | break; | 416 | break; |
424 | default: | 417 | default: |
425 | list_for_each_entry(core, &bus->cores, list) { | 418 | list_for_each_entry(core, &bus->cores, list) { |
426 | core->irq = bcma_core_irq(core); | 419 | core->irq = bcma_core_irq(core, 0); |
427 | } | 420 | } |
428 | bcma_err(bus, | 421 | bcma_err(bus, |
429 | "Unknown device (0x%x) found, can not configure IRQs\n", | 422 | "Unknown device (0x%x) found, can not configure IRQs\n", |
diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c index c3d7b03c2fdc..c8a6b741967b 100644 --- a/drivers/bcma/driver_pci_host.c +++ b/drivers/bcma/driver_pci_host.c | |||
@@ -593,7 +593,7 @@ int bcma_core_pci_plat_dev_init(struct pci_dev *dev) | |||
593 | pr_info("PCI: Fixing up device %s\n", pci_name(dev)); | 593 | pr_info("PCI: Fixing up device %s\n", pci_name(dev)); |
594 | 594 | ||
595 | /* Fix up interrupt lines */ | 595 | /* Fix up interrupt lines */ |
596 | dev->irq = bcma_core_irq(pc_host->pdev->core); | 596 | dev->irq = bcma_core_irq(pc_host->pdev->core, 0); |
597 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | 597 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); |
598 | 598 | ||
599 | readrq = pcie_get_readrq(dev); | 599 | readrq = pcie_get_readrq(dev); |
@@ -617,6 +617,6 @@ int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev) | |||
617 | 617 | ||
618 | pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host, | 618 | pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host, |
619 | pci_ops); | 619 | pci_ops); |
620 | return bcma_core_irq(pc_host->pdev->core); | 620 | return bcma_core_irq(pc_host->pdev->core, 0); |
621 | } | 621 | } |
622 | EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq); | 622 | EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq); |
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index 1e5ac0a79696..cd9161a8b3a1 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c | |||
@@ -275,7 +275,7 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend, | |||
275 | static const struct pci_device_id bcma_pci_bridge_tbl[] = { | 275 | static const struct pci_device_id bcma_pci_bridge_tbl[] = { |
276 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, | 276 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, |
277 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4313) }, | 277 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4313) }, |
278 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) }, | 278 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) }, /* 0xa8d8 */ |
279 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, | 279 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, |
280 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, | 280 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, |
281 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, | 281 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, |
@@ -285,7 +285,8 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = { | |||
285 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) }, | 285 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) }, |
286 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) }, | 286 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) }, |
287 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, | 287 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, |
288 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) }, /* 0xA8DB */ | 288 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) }, /* 0xa8db, BCM43217 (sic!) */ |
289 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43228) }, /* 0xa8dc */ | ||
289 | { 0, }, | 290 | { 0, }, |
290 | }; | 291 | }; |
291 | MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl); | 292 | MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl); |
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 9b229c9c35e5..534e1337766d 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/bcma/bcma.h> | 11 | #include <linux/bcma/bcma.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/of_address.h> | 13 | #include <linux/of_address.h> |
14 | #include <linux/of_irq.h> | ||
14 | 15 | ||
15 | MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); | 16 | MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); |
16 | MODULE_LICENSE("GPL"); | 17 | MODULE_LICENSE("GPL"); |
@@ -132,7 +133,7 @@ static bool bcma_is_core_needed_early(u16 core_id) | |||
132 | return false; | 133 | return false; |
133 | } | 134 | } |
134 | 135 | ||
135 | #ifdef CONFIG_OF | 136 | #if defined(CONFIG_OF) && defined(CONFIG_OF_ADDRESS) |
136 | static struct device_node *bcma_of_find_child_device(struct platform_device *parent, | 137 | static struct device_node *bcma_of_find_child_device(struct platform_device *parent, |
137 | struct bcma_device *core) | 138 | struct bcma_device *core) |
138 | { | 139 | { |
@@ -153,6 +154,46 @@ static struct device_node *bcma_of_find_child_device(struct platform_device *par | |||
153 | return NULL; | 154 | return NULL; |
154 | } | 155 | } |
155 | 156 | ||
157 | static int bcma_of_irq_parse(struct platform_device *parent, | ||
158 | struct bcma_device *core, | ||
159 | struct of_phandle_args *out_irq, int num) | ||
160 | { | ||
161 | __be32 laddr[1]; | ||
162 | int rc; | ||
163 | |||
164 | if (core->dev.of_node) { | ||
165 | rc = of_irq_parse_one(core->dev.of_node, num, out_irq); | ||
166 | if (!rc) | ||
167 | return rc; | ||
168 | } | ||
169 | |||
170 | out_irq->np = parent->dev.of_node; | ||
171 | out_irq->args_count = 1; | ||
172 | out_irq->args[0] = num; | ||
173 | |||
174 | laddr[0] = cpu_to_be32(core->addr); | ||
175 | return of_irq_parse_raw(laddr, out_irq); | ||
176 | } | ||
177 | |||
178 | static unsigned int bcma_of_get_irq(struct platform_device *parent, | ||
179 | struct bcma_device *core, int num) | ||
180 | { | ||
181 | struct of_phandle_args out_irq; | ||
182 | int ret; | ||
183 | |||
184 | if (!parent || !parent->dev.of_node) | ||
185 | return 0; | ||
186 | |||
187 | ret = bcma_of_irq_parse(parent, core, &out_irq, num); | ||
188 | if (ret) { | ||
189 | bcma_debug(core->bus, "bcma_of_get_irq() failed with rc=%d\n", | ||
190 | ret); | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | return irq_create_of_mapping(&out_irq); | ||
195 | } | ||
196 | |||
156 | static void bcma_of_fill_device(struct platform_device *parent, | 197 | static void bcma_of_fill_device(struct platform_device *parent, |
157 | struct bcma_device *core) | 198 | struct bcma_device *core) |
158 | { | 199 | { |
@@ -161,14 +202,45 @@ static void bcma_of_fill_device(struct platform_device *parent, | |||
161 | node = bcma_of_find_child_device(parent, core); | 202 | node = bcma_of_find_child_device(parent, core); |
162 | if (node) | 203 | if (node) |
163 | core->dev.of_node = node; | 204 | core->dev.of_node = node; |
205 | |||
206 | core->irq = bcma_of_get_irq(parent, core, 0); | ||
164 | } | 207 | } |
165 | #else | 208 | #else |
166 | static void bcma_of_fill_device(struct platform_device *parent, | 209 | static void bcma_of_fill_device(struct platform_device *parent, |
167 | struct bcma_device *core) | 210 | struct bcma_device *core) |
168 | { | 211 | { |
169 | } | 212 | } |
213 | static inline unsigned int bcma_of_get_irq(struct platform_device *parent, | ||
214 | struct bcma_device *core, int num) | ||
215 | { | ||
216 | return 0; | ||
217 | } | ||
170 | #endif /* CONFIG_OF */ | 218 | #endif /* CONFIG_OF */ |
171 | 219 | ||
220 | unsigned int bcma_core_irq(struct bcma_device *core, int num) | ||
221 | { | ||
222 | struct bcma_bus *bus = core->bus; | ||
223 | unsigned int mips_irq; | ||
224 | |||
225 | switch (bus->hosttype) { | ||
226 | case BCMA_HOSTTYPE_PCI: | ||
227 | return bus->host_pci->irq; | ||
228 | case BCMA_HOSTTYPE_SOC: | ||
229 | if (bus->drv_mips.core && num == 0) { | ||
230 | mips_irq = bcma_core_mips_irq(core); | ||
231 | return mips_irq <= 4 ? mips_irq + 2 : 0; | ||
232 | } | ||
233 | if (bus->host_pdev) | ||
234 | return bcma_of_get_irq(bus->host_pdev, core, num); | ||
235 | return 0; | ||
236 | case BCMA_HOSTTYPE_SDIO: | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | EXPORT_SYMBOL(bcma_core_irq); | ||
243 | |||
172 | void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) | 244 | void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) |
173 | { | 245 | { |
174 | core->dev.release = bcma_release_core_dev; | 246 | core->dev.release = bcma_release_core_dev; |
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index 416620fa8fac..ffeaf476a120 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c | |||
@@ -2104,6 +2104,7 @@ static int b44_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |||
2104 | bp->flags &= ~B44_FLAG_WOL_ENABLE; | 2104 | bp->flags &= ~B44_FLAG_WOL_ENABLE; |
2105 | spin_unlock_irq(&bp->lock); | 2105 | spin_unlock_irq(&bp->lock); |
2106 | 2106 | ||
2107 | device_set_wakeup_enable(bp->sdev->dev, wol->wolopts & WAKE_MAGIC); | ||
2107 | return 0; | 2108 | return 0; |
2108 | } | 2109 | } |
2109 | 2110 | ||
@@ -2452,6 +2453,7 @@ static int b44_init_one(struct ssb_device *sdev, | |||
2452 | } | 2453 | } |
2453 | } | 2454 | } |
2454 | 2455 | ||
2456 | device_set_wakeup_capable(sdev->dev, true); | ||
2455 | netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr); | 2457 | netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr); |
2456 | 2458 | ||
2457 | return 0; | 2459 | return 0; |
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 9c56ecbae37f..ccba4fea7269 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h | |||
@@ -80,6 +80,7 @@ struct reg_dmn_pair_mapping { | |||
80 | 80 | ||
81 | struct ath_regulatory { | 81 | struct ath_regulatory { |
82 | char alpha2[2]; | 82 | char alpha2[2]; |
83 | enum nl80211_dfs_regions region; | ||
83 | u16 country_code; | 84 | u16 country_code; |
84 | u16 max_power_level; | 85 | u16 max_power_level; |
85 | u16 current_rd; | 86 | u16 current_rd; |
@@ -134,6 +135,11 @@ struct ath_ops { | |||
134 | struct ath_common; | 135 | struct ath_common; |
135 | struct ath_bus_ops; | 136 | struct ath_bus_ops; |
136 | 137 | ||
138 | struct ath_ps_ops { | ||
139 | void (*wakeup)(struct ath_common *common); | ||
140 | void (*restore)(struct ath_common *common); | ||
141 | }; | ||
142 | |||
137 | struct ath_common { | 143 | struct ath_common { |
138 | void *ah; | 144 | void *ah; |
139 | void *priv; | 145 | void *priv; |
@@ -168,6 +174,7 @@ struct ath_common { | |||
168 | struct ath_regulatory reg_world_copy; | 174 | struct ath_regulatory reg_world_copy; |
169 | const struct ath_ops *ops; | 175 | const struct ath_ops *ops; |
170 | const struct ath_bus_ops *bus_ops; | 176 | const struct ath_bus_ops *bus_ops; |
177 | const struct ath_ps_ops *ps_ops; | ||
171 | 178 | ||
172 | bool btcoex_enabled; | 179 | bool btcoex_enabled; |
173 | bool disable_ani; | 180 | bool disable_ani; |
@@ -177,6 +184,11 @@ struct ath_common { | |||
177 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; | 184 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; |
178 | }; | 185 | }; |
179 | 186 | ||
187 | static inline const struct ath_ps_ops *ath_ps_ops(struct ath_common *common) | ||
188 | { | ||
189 | return common->ps_ops; | ||
190 | } | ||
191 | |||
180 | struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, | 192 | struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, |
181 | u32 len, | 193 | u32 len, |
182 | gfp_t gfp_mask); | 194 | gfp_t gfp_mask); |
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 9b89ac133946..a156e6e48708 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c | |||
@@ -558,6 +558,7 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, | |||
558 | 558 | ||
559 | /* sanity */ | 559 | /* sanity */ |
560 | dest_ring->per_transfer_context[sw_index] = NULL; | 560 | dest_ring->per_transfer_context[sw_index] = NULL; |
561 | desc->nbytes = 0; | ||
561 | 562 | ||
562 | /* Update sw_index */ | 563 | /* Update sw_index */ |
563 | sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); | 564 | sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); |
@@ -835,8 +836,8 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, | |||
835 | 836 | ||
836 | nentries = roundup_pow_of_two(attr->src_nentries); | 837 | nentries = roundup_pow_of_two(attr->src_nentries); |
837 | 838 | ||
838 | memset(src_ring->per_transfer_context, 0, | 839 | memset(src_ring->base_addr_owner_space, 0, |
839 | nentries * sizeof(*src_ring->per_transfer_context)); | 840 | nentries * sizeof(struct ce_desc)); |
840 | 841 | ||
841 | src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); | 842 | src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); |
842 | src_ring->sw_index &= src_ring->nentries_mask; | 843 | src_ring->sw_index &= src_ring->nentries_mask; |
@@ -872,8 +873,8 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, | |||
872 | 873 | ||
873 | nentries = roundup_pow_of_two(attr->dest_nentries); | 874 | nentries = roundup_pow_of_two(attr->dest_nentries); |
874 | 875 | ||
875 | memset(dest_ring->per_transfer_context, 0, | 876 | memset(dest_ring->base_addr_owner_space, 0, |
876 | nentries * sizeof(*dest_ring->per_transfer_context)); | 877 | nentries * sizeof(struct ce_desc)); |
877 | 878 | ||
878 | dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); | 879 | dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); |
879 | dest_ring->sw_index &= dest_ring->nentries_mask; | 880 | dest_ring->sw_index &= dest_ring->nentries_mask; |
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 5c23d00f7d60..7762061a1944 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c | |||
@@ -31,12 +31,17 @@ | |||
31 | unsigned int ath10k_debug_mask; | 31 | unsigned int ath10k_debug_mask; |
32 | static bool uart_print; | 32 | static bool uart_print; |
33 | static unsigned int ath10k_p2p; | 33 | static unsigned int ath10k_p2p; |
34 | static bool skip_otp; | ||
35 | |||
34 | module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); | 36 | module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); |
35 | module_param(uart_print, bool, 0644); | 37 | module_param(uart_print, bool, 0644); |
36 | module_param_named(p2p, ath10k_p2p, uint, 0644); | 38 | module_param_named(p2p, ath10k_p2p, uint, 0644); |
39 | module_param(skip_otp, bool, 0644); | ||
40 | |||
37 | MODULE_PARM_DESC(debug_mask, "Debugging mask"); | 41 | MODULE_PARM_DESC(debug_mask, "Debugging mask"); |
38 | MODULE_PARM_DESC(uart_print, "Uart target debugging"); | 42 | MODULE_PARM_DESC(uart_print, "Uart target debugging"); |
39 | MODULE_PARM_DESC(p2p, "Enable ath10k P2P support"); | 43 | MODULE_PARM_DESC(p2p, "Enable ath10k P2P support"); |
44 | MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); | ||
40 | 45 | ||
41 | static const struct ath10k_hw_params ath10k_hw_params_list[] = { | 46 | static const struct ath10k_hw_params ath10k_hw_params_list[] = { |
42 | { | 47 | { |
@@ -280,7 +285,7 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) | |||
280 | 285 | ||
281 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); | 286 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); |
282 | 287 | ||
283 | if (result != 0) { | 288 | if (!skip_otp && result != 0) { |
284 | ath10k_err(ar, "otp calibration failed: %d", result); | 289 | ath10k_err(ar, "otp calibration failed: %d", result); |
285 | return -EINVAL; | 290 | return -EINVAL; |
286 | } | 291 | } |
@@ -744,6 +749,25 @@ static void ath10k_core_restart(struct work_struct *work) | |||
744 | { | 749 | { |
745 | struct ath10k *ar = container_of(work, struct ath10k, restart_work); | 750 | struct ath10k *ar = container_of(work, struct ath10k, restart_work); |
746 | 751 | ||
752 | set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); | ||
753 | |||
754 | /* Place a barrier to make sure the compiler doesn't reorder | ||
755 | * CRASH_FLUSH and calling other functions. | ||
756 | */ | ||
757 | barrier(); | ||
758 | |||
759 | ieee80211_stop_queues(ar->hw); | ||
760 | ath10k_drain_tx(ar); | ||
761 | complete_all(&ar->scan.started); | ||
762 | complete_all(&ar->scan.completed); | ||
763 | complete_all(&ar->scan.on_channel); | ||
764 | complete_all(&ar->offchan_tx_completed); | ||
765 | complete_all(&ar->install_key_done); | ||
766 | complete_all(&ar->vdev_setup_done); | ||
767 | wake_up(&ar->htt.empty_tx_wq); | ||
768 | wake_up(&ar->wmi.tx_credits_wq); | ||
769 | wake_up(&ar->peer_mapping_wq); | ||
770 | |||
747 | mutex_lock(&ar->conf_mutex); | 771 | mutex_lock(&ar->conf_mutex); |
748 | 772 | ||
749 | switch (ar->state) { | 773 | switch (ar->state) { |
@@ -775,12 +799,25 @@ static void ath10k_core_restart(struct work_struct *work) | |||
775 | mutex_unlock(&ar->conf_mutex); | 799 | mutex_unlock(&ar->conf_mutex); |
776 | } | 800 | } |
777 | 801 | ||
802 | static void ath10k_core_init_max_sta_count(struct ath10k *ar) | ||
803 | { | ||
804 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { | ||
805 | ar->max_num_peers = TARGET_10X_NUM_PEERS; | ||
806 | ar->max_num_stations = TARGET_10X_NUM_STATIONS; | ||
807 | } else { | ||
808 | ar->max_num_peers = TARGET_NUM_PEERS; | ||
809 | ar->max_num_stations = TARGET_NUM_STATIONS; | ||
810 | } | ||
811 | } | ||
812 | |||
778 | int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) | 813 | int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) |
779 | { | 814 | { |
780 | int status; | 815 | int status; |
781 | 816 | ||
782 | lockdep_assert_held(&ar->conf_mutex); | 817 | lockdep_assert_held(&ar->conf_mutex); |
783 | 818 | ||
819 | clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); | ||
820 | |||
784 | ath10k_bmi_start(ar); | 821 | ath10k_bmi_start(ar); |
785 | 822 | ||
786 | if (ath10k_init_configure_target(ar)) { | 823 | if (ath10k_init_configure_target(ar)) { |
@@ -1009,6 +1046,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar) | |||
1009 | return ret; | 1046 | return ret; |
1010 | } | 1047 | } |
1011 | 1048 | ||
1049 | ath10k_core_init_max_sta_count(ar); | ||
1050 | |||
1012 | mutex_lock(&ar->conf_mutex); | 1051 | mutex_lock(&ar->conf_mutex); |
1013 | 1052 | ||
1014 | ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); | 1053 | ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); |
@@ -1185,6 +1224,8 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, | |||
1185 | 1224 | ||
1186 | INIT_LIST_HEAD(&ar->peers); | 1225 | INIT_LIST_HEAD(&ar->peers); |
1187 | init_waitqueue_head(&ar->peer_mapping_wq); | 1226 | init_waitqueue_head(&ar->peer_mapping_wq); |
1227 | init_waitqueue_head(&ar->htt.empty_tx_wq); | ||
1228 | init_waitqueue_head(&ar->wmi.tx_credits_wq); | ||
1188 | 1229 | ||
1189 | init_completion(&ar->offchan_tx_completed); | 1230 | init_completion(&ar->offchan_tx_completed); |
1190 | INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); | 1231 | INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); |
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 1e3fd1013b70..514c219263a5 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
@@ -79,10 +79,12 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus) | |||
79 | 79 | ||
80 | struct ath10k_skb_cb { | 80 | struct ath10k_skb_cb { |
81 | dma_addr_t paddr; | 81 | dma_addr_t paddr; |
82 | u8 eid; | ||
82 | u8 vdev_id; | 83 | u8 vdev_id; |
83 | 84 | ||
84 | struct { | 85 | struct { |
85 | u8 tid; | 86 | u8 tid; |
87 | u16 freq; | ||
86 | bool is_offchan; | 88 | bool is_offchan; |
87 | struct ath10k_htt_txbuf *txbuf; | 89 | struct ath10k_htt_txbuf *txbuf; |
88 | u32 txbuf_paddr; | 90 | u32 txbuf_paddr; |
@@ -122,6 +124,7 @@ struct ath10k_wmi { | |||
122 | struct completion service_ready; | 124 | struct completion service_ready; |
123 | struct completion unified_ready; | 125 | struct completion unified_ready; |
124 | wait_queue_head_t tx_credits_wq; | 126 | wait_queue_head_t tx_credits_wq; |
127 | DECLARE_BITMAP(svc_map, WMI_SERVICE_MAX); | ||
125 | struct wmi_cmd_map *cmd; | 128 | struct wmi_cmd_map *cmd; |
126 | struct wmi_vdev_param_map *vdev_param; | 129 | struct wmi_vdev_param_map *vdev_param; |
127 | struct wmi_pdev_param_map *pdev_param; | 130 | struct wmi_pdev_param_map *pdev_param; |
@@ -218,6 +221,8 @@ struct ath10k_peer { | |||
218 | int vdev_id; | 221 | int vdev_id; |
219 | u8 addr[ETH_ALEN]; | 222 | u8 addr[ETH_ALEN]; |
220 | DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS); | 223 | DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS); |
224 | |||
225 | /* protected by ar->data_lock */ | ||
221 | struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; | 226 | struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; |
222 | }; | 227 | }; |
223 | 228 | ||
@@ -310,7 +315,6 @@ struct ath10k_debug { | |||
310 | struct ath10k_fw_stats fw_stats; | 315 | struct ath10k_fw_stats fw_stats; |
311 | struct completion fw_stats_complete; | 316 | struct completion fw_stats_complete; |
312 | bool fw_stats_done; | 317 | bool fw_stats_done; |
313 | DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_MAX); | ||
314 | 318 | ||
315 | unsigned long htt_stats_mask; | 319 | unsigned long htt_stats_mask; |
316 | struct delayed_work htt_stats_dwork; | 320 | struct delayed_work htt_stats_dwork; |
@@ -320,6 +324,7 @@ struct ath10k_debug { | |||
320 | /* protected by conf_mutex */ | 324 | /* protected by conf_mutex */ |
321 | u32 fw_dbglog_mask; | 325 | u32 fw_dbglog_mask; |
322 | u32 pktlog_filter; | 326 | u32 pktlog_filter; |
327 | u32 reg_addr; | ||
323 | 328 | ||
324 | u8 htt_max_amsdu; | 329 | u8 htt_max_amsdu; |
325 | u8 htt_max_ampdu; | 330 | u8 htt_max_ampdu; |
@@ -338,7 +343,7 @@ enum ath10k_state { | |||
338 | * stopped in ath10k_core_restart() work holding conf_mutex. The state | 343 | * stopped in ath10k_core_restart() work holding conf_mutex. The state |
339 | * RESTARTED means that the device is up and mac80211 has started hw | 344 | * RESTARTED means that the device is up and mac80211 has started hw |
340 | * reconfiguration. Once mac80211 is done with the reconfiguration we | 345 | * reconfiguration. Once mac80211 is done with the reconfiguration we |
341 | * set the state to STATE_ON in restart_complete(). */ | 346 | * set the state to STATE_ON in reconfig_complete(). */ |
342 | ATH10K_STATE_RESTARTING, | 347 | ATH10K_STATE_RESTARTING, |
343 | ATH10K_STATE_RESTARTED, | 348 | ATH10K_STATE_RESTARTED, |
344 | 349 | ||
@@ -386,6 +391,11 @@ enum ath10k_dev_flags { | |||
386 | /* Indicates that ath10k device is during CAC phase of DFS */ | 391 | /* Indicates that ath10k device is during CAC phase of DFS */ |
387 | ATH10K_CAC_RUNNING, | 392 | ATH10K_CAC_RUNNING, |
388 | ATH10K_FLAG_CORE_REGISTERED, | 393 | ATH10K_FLAG_CORE_REGISTERED, |
394 | |||
395 | /* Device has crashed and needs to restart. This indicates any pending | ||
396 | * waiters should immediately cancel instead of waiting for a time out. | ||
397 | */ | ||
398 | ATH10K_FLAG_CRASH_FLUSH, | ||
389 | }; | 399 | }; |
390 | 400 | ||
391 | enum ath10k_cal_mode { | 401 | enum ath10k_cal_mode { |
@@ -555,8 +565,12 @@ struct ath10k { | |||
555 | struct list_head peers; | 565 | struct list_head peers; |
556 | wait_queue_head_t peer_mapping_wq; | 566 | wait_queue_head_t peer_mapping_wq; |
557 | 567 | ||
558 | /* number of created peers; protected by data_lock */ | 568 | /* protected by conf_mutex */ |
559 | int num_peers; | 569 | int num_peers; |
570 | int num_stations; | ||
571 | |||
572 | int max_num_peers; | ||
573 | int max_num_stations; | ||
560 | 574 | ||
561 | struct work_struct offchan_tx_work; | 575 | struct work_struct offchan_tx_work; |
562 | struct sk_buff_head offchan_tx_queue; | 576 | struct sk_buff_head offchan_tx_queue; |
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 9147dd36dcdd..a716758f14b0 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c | |||
@@ -17,9 +17,8 @@ | |||
17 | 17 | ||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/debugfs.h> | 19 | #include <linux/debugfs.h> |
20 | #include <linux/version.h> | ||
21 | #include <linux/vermagic.h> | ||
22 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
21 | #include <linux/utsname.h> | ||
23 | 22 | ||
24 | #include "core.h" | 23 | #include "core.h" |
25 | #include "debug.h" | 24 | #include "debug.h" |
@@ -124,7 +123,7 @@ EXPORT_SYMBOL(ath10k_info); | |||
124 | 123 | ||
125 | void ath10k_print_driver_info(struct ath10k *ar) | 124 | void ath10k_print_driver_info(struct ath10k *ar) |
126 | { | 125 | { |
127 | ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s\n", | 126 | ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s max_sta %d\n", |
128 | ar->hw_params.name, | 127 | ar->hw_params.name, |
129 | ar->target_version, | 128 | ar->target_version, |
130 | ar->chip_id, | 129 | ar->chip_id, |
@@ -136,7 +135,8 @@ void ath10k_print_driver_info(struct ath10k *ar) | |||
136 | ar->fw_version_minor, | 135 | ar->fw_version_minor, |
137 | ar->fw_version_release, | 136 | ar->fw_version_release, |
138 | ar->fw_version_build, | 137 | ar->fw_version_build, |
139 | ath10k_cal_mode_str(ar->cal_mode)); | 138 | ath10k_cal_mode_str(ar->cal_mode), |
139 | ar->max_num_stations); | ||
140 | ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", | 140 | ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", |
141 | config_enabled(CONFIG_ATH10K_DEBUG), | 141 | config_enabled(CONFIG_ATH10K_DEBUG), |
142 | config_enabled(CONFIG_ATH10K_DEBUGFS), | 142 | config_enabled(CONFIG_ATH10K_DEBUGFS), |
@@ -179,13 +179,6 @@ EXPORT_SYMBOL(ath10k_warn); | |||
179 | 179 | ||
180 | #ifdef CONFIG_ATH10K_DEBUGFS | 180 | #ifdef CONFIG_ATH10K_DEBUGFS |
181 | 181 | ||
182 | void ath10k_debug_read_service_map(struct ath10k *ar, | ||
183 | const void *service_map, | ||
184 | size_t map_size) | ||
185 | { | ||
186 | memcpy(ar->debug.wmi_service_bitmap, service_map, map_size); | ||
187 | } | ||
188 | |||
189 | static ssize_t ath10k_read_wmi_services(struct file *file, | 182 | static ssize_t ath10k_read_wmi_services(struct file *file, |
190 | char __user *user_buf, | 183 | char __user *user_buf, |
191 | size_t count, loff_t *ppos) | 184 | size_t count, loff_t *ppos) |
@@ -207,8 +200,9 @@ static ssize_t ath10k_read_wmi_services(struct file *file, | |||
207 | if (len > buf_len) | 200 | if (len > buf_len) |
208 | len = buf_len; | 201 | len = buf_len; |
209 | 202 | ||
203 | spin_lock_bh(&ar->data_lock); | ||
210 | for (i = 0; i < WMI_SERVICE_MAX; i++) { | 204 | for (i = 0; i < WMI_SERVICE_MAX; i++) { |
211 | enabled = test_bit(i, ar->debug.wmi_service_bitmap); | 205 | enabled = test_bit(i, ar->wmi.svc_map); |
212 | name = wmi_service_name(i); | 206 | name = wmi_service_name(i); |
213 | 207 | ||
214 | if (!name) { | 208 | if (!name) { |
@@ -224,6 +218,7 @@ static ssize_t ath10k_read_wmi_services(struct file *file, | |||
224 | "%-40s %s\n", | 218 | "%-40s %s\n", |
225 | name, enabled ? "enabled" : "-"); | 219 | name, enabled ? "enabled" : "-"); |
226 | } | 220 | } |
221 | spin_unlock_bh(&ar->data_lock); | ||
227 | 222 | ||
228 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); | 223 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); |
229 | 224 | ||
@@ -695,7 +690,8 @@ static ssize_t ath10k_read_simulate_fw_crash(struct file *file, | |||
695 | "To simulate firmware crash write one of the keywords to this file:\n" | 690 | "To simulate firmware crash write one of the keywords to this file:\n" |
696 | "`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n" | 691 | "`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n" |
697 | "`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n" | 692 | "`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n" |
698 | "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n"; | 693 | "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n" |
694 | "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n"; | ||
699 | 695 | ||
700 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | 696 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); |
701 | } | 697 | } |
@@ -748,6 +744,10 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, | |||
748 | } else if (!strcmp(buf, "assert")) { | 744 | } else if (!strcmp(buf, "assert")) { |
749 | ath10k_info(ar, "simulating firmware assert crash\n"); | 745 | ath10k_info(ar, "simulating firmware assert crash\n"); |
750 | ret = ath10k_debug_fw_assert(ar); | 746 | ret = ath10k_debug_fw_assert(ar); |
747 | } else if (!strcmp(buf, "hw-restart")) { | ||
748 | ath10k_info(ar, "user requested hw restart\n"); | ||
749 | queue_work(ar->workqueue, &ar->restart_work); | ||
750 | ret = 0; | ||
751 | } else { | 751 | } else { |
752 | ret = -EINVAL; | 752 | ret = -EINVAL; |
753 | goto exit; | 753 | goto exit; |
@@ -861,8 +861,8 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar) | |||
861 | strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version, | 861 | strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version, |
862 | sizeof(dump_data->fw_ver)); | 862 | sizeof(dump_data->fw_ver)); |
863 | 863 | ||
864 | dump_data->kernel_ver_code = cpu_to_le32(LINUX_VERSION_CODE); | 864 | dump_data->kernel_ver_code = 0; |
865 | strlcpy(dump_data->kernel_ver, VERMAGIC_STRING, | 865 | strlcpy(dump_data->kernel_ver, init_utsname()->release, |
866 | sizeof(dump_data->kernel_ver)); | 866 | sizeof(dump_data->kernel_ver)); |
867 | 867 | ||
868 | dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec); | 868 | dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec); |
@@ -924,6 +924,236 @@ static const struct file_operations fops_fw_crash_dump = { | |||
924 | .llseek = default_llseek, | 924 | .llseek = default_llseek, |
925 | }; | 925 | }; |
926 | 926 | ||
927 | static ssize_t ath10k_reg_addr_read(struct file *file, | ||
928 | char __user *user_buf, | ||
929 | size_t count, loff_t *ppos) | ||
930 | { | ||
931 | struct ath10k *ar = file->private_data; | ||
932 | u8 buf[32]; | ||
933 | unsigned int len = 0; | ||
934 | u32 reg_addr; | ||
935 | |||
936 | mutex_lock(&ar->conf_mutex); | ||
937 | reg_addr = ar->debug.reg_addr; | ||
938 | mutex_unlock(&ar->conf_mutex); | ||
939 | |||
940 | len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr); | ||
941 | |||
942 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
943 | } | ||
944 | |||
945 | static ssize_t ath10k_reg_addr_write(struct file *file, | ||
946 | const char __user *user_buf, | ||
947 | size_t count, loff_t *ppos) | ||
948 | { | ||
949 | struct ath10k *ar = file->private_data; | ||
950 | u32 reg_addr; | ||
951 | int ret; | ||
952 | |||
953 | ret = kstrtou32_from_user(user_buf, count, 0, ®_addr); | ||
954 | if (ret) | ||
955 | return ret; | ||
956 | |||
957 | if (!IS_ALIGNED(reg_addr, 4)) | ||
958 | return -EFAULT; | ||
959 | |||
960 | mutex_lock(&ar->conf_mutex); | ||
961 | ar->debug.reg_addr = reg_addr; | ||
962 | mutex_unlock(&ar->conf_mutex); | ||
963 | |||
964 | return count; | ||
965 | } | ||
966 | |||
967 | static const struct file_operations fops_reg_addr = { | ||
968 | .read = ath10k_reg_addr_read, | ||
969 | .write = ath10k_reg_addr_write, | ||
970 | .open = simple_open, | ||
971 | .owner = THIS_MODULE, | ||
972 | .llseek = default_llseek, | ||
973 | }; | ||
974 | |||
975 | static ssize_t ath10k_reg_value_read(struct file *file, | ||
976 | char __user *user_buf, | ||
977 | size_t count, loff_t *ppos) | ||
978 | { | ||
979 | struct ath10k *ar = file->private_data; | ||
980 | u8 buf[48]; | ||
981 | unsigned int len; | ||
982 | u32 reg_addr, reg_val; | ||
983 | int ret; | ||
984 | |||
985 | mutex_lock(&ar->conf_mutex); | ||
986 | |||
987 | if (ar->state != ATH10K_STATE_ON && | ||
988 | ar->state != ATH10K_STATE_UTF) { | ||
989 | ret = -ENETDOWN; | ||
990 | goto exit; | ||
991 | } | ||
992 | |||
993 | reg_addr = ar->debug.reg_addr; | ||
994 | |||
995 | reg_val = ath10k_hif_read32(ar, reg_addr); | ||
996 | len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val); | ||
997 | |||
998 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
999 | |||
1000 | exit: | ||
1001 | mutex_unlock(&ar->conf_mutex); | ||
1002 | |||
1003 | return ret; | ||
1004 | } | ||
1005 | |||
1006 | static ssize_t ath10k_reg_value_write(struct file *file, | ||
1007 | const char __user *user_buf, | ||
1008 | size_t count, loff_t *ppos) | ||
1009 | { | ||
1010 | struct ath10k *ar = file->private_data; | ||
1011 | u32 reg_addr, reg_val; | ||
1012 | int ret; | ||
1013 | |||
1014 | mutex_lock(&ar->conf_mutex); | ||
1015 | |||
1016 | if (ar->state != ATH10K_STATE_ON && | ||
1017 | ar->state != ATH10K_STATE_UTF) { | ||
1018 | ret = -ENETDOWN; | ||
1019 | goto exit; | ||
1020 | } | ||
1021 | |||
1022 | reg_addr = ar->debug.reg_addr; | ||
1023 | |||
1024 | ret = kstrtou32_from_user(user_buf, count, 0, ®_val); | ||
1025 | if (ret) | ||
1026 | goto exit; | ||
1027 | |||
1028 | ath10k_hif_write32(ar, reg_addr, reg_val); | ||
1029 | |||
1030 | ret = count; | ||
1031 | |||
1032 | exit: | ||
1033 | mutex_unlock(&ar->conf_mutex); | ||
1034 | |||
1035 | return ret; | ||
1036 | } | ||
1037 | |||
1038 | static const struct file_operations fops_reg_value = { | ||
1039 | .read = ath10k_reg_value_read, | ||
1040 | .write = ath10k_reg_value_write, | ||
1041 | .open = simple_open, | ||
1042 | .owner = THIS_MODULE, | ||
1043 | .llseek = default_llseek, | ||
1044 | }; | ||
1045 | |||
1046 | static ssize_t ath10k_mem_value_read(struct file *file, | ||
1047 | char __user *user_buf, | ||
1048 | size_t count, loff_t *ppos) | ||
1049 | { | ||
1050 | struct ath10k *ar = file->private_data; | ||
1051 | u8 *buf; | ||
1052 | int ret; | ||
1053 | |||
1054 | if (*ppos < 0) | ||
1055 | return -EINVAL; | ||
1056 | |||
1057 | if (!count) | ||
1058 | return 0; | ||
1059 | |||
1060 | mutex_lock(&ar->conf_mutex); | ||
1061 | |||
1062 | buf = vmalloc(count); | ||
1063 | if (!buf) { | ||
1064 | ret = -ENOMEM; | ||
1065 | goto exit; | ||
1066 | } | ||
1067 | |||
1068 | if (ar->state != ATH10K_STATE_ON && | ||
1069 | ar->state != ATH10K_STATE_UTF) { | ||
1070 | ret = -ENETDOWN; | ||
1071 | goto exit; | ||
1072 | } | ||
1073 | |||
1074 | ret = ath10k_hif_diag_read(ar, *ppos, buf, count); | ||
1075 | if (ret) { | ||
1076 | ath10k_warn(ar, "failed to read address 0x%08x via diagnose window fnrom debugfs: %d\n", | ||
1077 | (u32)(*ppos), ret); | ||
1078 | goto exit; | ||
1079 | } | ||
1080 | |||
1081 | ret = copy_to_user(user_buf, buf, count); | ||
1082 | if (ret) { | ||
1083 | ret = -EFAULT; | ||
1084 | goto exit; | ||
1085 | } | ||
1086 | |||
1087 | count -= ret; | ||
1088 | *ppos += count; | ||
1089 | ret = count; | ||
1090 | |||
1091 | exit: | ||
1092 | vfree(buf); | ||
1093 | mutex_unlock(&ar->conf_mutex); | ||
1094 | |||
1095 | return ret; | ||
1096 | } | ||
1097 | |||
1098 | static ssize_t ath10k_mem_value_write(struct file *file, | ||
1099 | const char __user *user_buf, | ||
1100 | size_t count, loff_t *ppos) | ||
1101 | { | ||
1102 | struct ath10k *ar = file->private_data; | ||
1103 | u8 *buf; | ||
1104 | int ret; | ||
1105 | |||
1106 | if (*ppos < 0) | ||
1107 | return -EINVAL; | ||
1108 | |||
1109 | if (!count) | ||
1110 | return 0; | ||
1111 | |||
1112 | mutex_lock(&ar->conf_mutex); | ||
1113 | |||
1114 | buf = vmalloc(count); | ||
1115 | if (!buf) { | ||
1116 | ret = -ENOMEM; | ||
1117 | goto exit; | ||
1118 | } | ||
1119 | |||
1120 | if (ar->state != ATH10K_STATE_ON && | ||
1121 | ar->state != ATH10K_STATE_UTF) { | ||
1122 | ret = -ENETDOWN; | ||
1123 | goto exit; | ||
1124 | } | ||
1125 | |||
1126 | ret = copy_from_user(buf, user_buf, count); | ||
1127 | if (ret) { | ||
1128 | ret = -EFAULT; | ||
1129 | goto exit; | ||
1130 | } | ||
1131 | |||
1132 | ret = ath10k_hif_diag_write(ar, *ppos, buf, count); | ||
1133 | if (ret) { | ||
1134 | ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n", | ||
1135 | (u32)(*ppos), ret); | ||
1136 | goto exit; | ||
1137 | } | ||
1138 | |||
1139 | *ppos += count; | ||
1140 | ret = count; | ||
1141 | |||
1142 | exit: | ||
1143 | vfree(buf); | ||
1144 | mutex_unlock(&ar->conf_mutex); | ||
1145 | |||
1146 | return ret; | ||
1147 | } | ||
1148 | |||
1149 | static const struct file_operations fops_mem_value = { | ||
1150 | .read = ath10k_mem_value_read, | ||
1151 | .write = ath10k_mem_value_write, | ||
1152 | .open = simple_open, | ||
1153 | .owner = THIS_MODULE, | ||
1154 | .llseek = default_llseek, | ||
1155 | }; | ||
1156 | |||
927 | static int ath10k_debug_htt_stats_req(struct ath10k *ar) | 1157 | static int ath10k_debug_htt_stats_req(struct ath10k *ar) |
928 | { | 1158 | { |
929 | u64 cookie; | 1159 | u64 cookie; |
@@ -1625,6 +1855,15 @@ int ath10k_debug_register(struct ath10k *ar) | |||
1625 | debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy, | 1855 | debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy, |
1626 | ar, &fops_fw_crash_dump); | 1856 | ar, &fops_fw_crash_dump); |
1627 | 1857 | ||
1858 | debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, | ||
1859 | ar->debug.debugfs_phy, ar, &fops_reg_addr); | ||
1860 | |||
1861 | debugfs_create_file("reg_value", S_IRUSR | S_IWUSR, | ||
1862 | ar->debug.debugfs_phy, ar, &fops_reg_value); | ||
1863 | |||
1864 | debugfs_create_file("mem_value", S_IRUSR | S_IWUSR, | ||
1865 | ar->debug.debugfs_phy, ar, &fops_mem_value); | ||
1866 | |||
1628 | debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy, | 1867 | debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy, |
1629 | ar, &fops_chip_id); | 1868 | ar, &fops_chip_id); |
1630 | 1869 | ||
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 0c934a8378db..1b87a5dbec53 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h | |||
@@ -35,6 +35,7 @@ enum ath10k_debug_mask { | |||
35 | ATH10K_DBG_BMI = 0x00000400, | 35 | ATH10K_DBG_BMI = 0x00000400, |
36 | ATH10K_DBG_REGULATORY = 0x00000800, | 36 | ATH10K_DBG_REGULATORY = 0x00000800, |
37 | ATH10K_DBG_TESTMODE = 0x00001000, | 37 | ATH10K_DBG_TESTMODE = 0x00001000, |
38 | ATH10K_DBG_WMI_PRINT = 0x00002000, | ||
38 | ATH10K_DBG_ANY = 0xffffffff, | 39 | ATH10K_DBG_ANY = 0xffffffff, |
39 | }; | 40 | }; |
40 | 41 | ||
@@ -61,9 +62,6 @@ int ath10k_debug_create(struct ath10k *ar); | |||
61 | void ath10k_debug_destroy(struct ath10k *ar); | 62 | void ath10k_debug_destroy(struct ath10k *ar); |
62 | int ath10k_debug_register(struct ath10k *ar); | 63 | int ath10k_debug_register(struct ath10k *ar); |
63 | void ath10k_debug_unregister(struct ath10k *ar); | 64 | void ath10k_debug_unregister(struct ath10k *ar); |
64 | void ath10k_debug_read_service_map(struct ath10k *ar, | ||
65 | const void *service_map, | ||
66 | size_t map_size); | ||
67 | void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); | 65 | void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); |
68 | struct ath10k_fw_crash_data * | 66 | struct ath10k_fw_crash_data * |
69 | ath10k_debug_get_new_fw_crash_data(struct ath10k *ar); | 67 | ath10k_debug_get_new_fw_crash_data(struct ath10k *ar); |
@@ -108,12 +106,6 @@ static inline void ath10k_debug_unregister(struct ath10k *ar) | |||
108 | { | 106 | { |
109 | } | 107 | } |
110 | 108 | ||
111 | static inline void ath10k_debug_read_service_map(struct ath10k *ar, | ||
112 | const void *service_map, | ||
113 | size_t map_size) | ||
114 | { | ||
115 | } | ||
116 | |||
117 | static inline void ath10k_debug_fw_stats_process(struct ath10k *ar, | 109 | static inline void ath10k_debug_fw_stats_process(struct ath10k *ar, |
118 | struct sk_buff *skb) | 110 | struct sk_buff *skb) |
119 | { | 111 | { |
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 30301f5b6051..0c92e0251e84 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include "core.h" | 22 | #include "core.h" |
23 | #include "debug.h" | ||
23 | 24 | ||
24 | struct ath10k_hif_sg_item { | 25 | struct ath10k_hif_sg_item { |
25 | u16 transfer_id; | 26 | u16 transfer_id; |
@@ -31,11 +32,9 @@ struct ath10k_hif_sg_item { | |||
31 | 32 | ||
32 | struct ath10k_hif_cb { | 33 | struct ath10k_hif_cb { |
33 | int (*tx_completion)(struct ath10k *ar, | 34 | int (*tx_completion)(struct ath10k *ar, |
34 | struct sk_buff *wbuf, | 35 | struct sk_buff *wbuf); |
35 | unsigned transfer_id); | ||
36 | int (*rx_completion)(struct ath10k *ar, | 36 | int (*rx_completion)(struct ath10k *ar, |
37 | struct sk_buff *wbuf, | 37 | struct sk_buff *wbuf); |
38 | u8 pipe_id); | ||
39 | }; | 38 | }; |
40 | 39 | ||
41 | struct ath10k_hif_ops { | 40 | struct ath10k_hif_ops { |
@@ -47,6 +46,8 @@ struct ath10k_hif_ops { | |||
47 | int (*diag_read)(struct ath10k *ar, u32 address, void *buf, | 46 | int (*diag_read)(struct ath10k *ar, u32 address, void *buf, |
48 | size_t buf_len); | 47 | size_t buf_len); |
49 | 48 | ||
49 | int (*diag_write)(struct ath10k *ar, u32 address, const void *data, | ||
50 | int nbytes); | ||
50 | /* | 51 | /* |
51 | * API to handle HIF-specific BMI message exchanges, this API is | 52 | * API to handle HIF-specific BMI message exchanges, this API is |
52 | * synchronous and only allowed to be called from a context that | 53 | * synchronous and only allowed to be called from a context that |
@@ -84,6 +85,10 @@ struct ath10k_hif_ops { | |||
84 | 85 | ||
85 | u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); | 86 | u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); |
86 | 87 | ||
88 | u32 (*read32)(struct ath10k *ar, u32 address); | ||
89 | |||
90 | void (*write32)(struct ath10k *ar, u32 address, u32 value); | ||
91 | |||
87 | /* Power up the device and enter BMI transfer mode for FW download */ | 92 | /* Power up the device and enter BMI transfer mode for FW download */ |
88 | int (*power_up)(struct ath10k *ar); | 93 | int (*power_up)(struct ath10k *ar); |
89 | 94 | ||
@@ -108,6 +113,15 @@ static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf | |||
108 | return ar->hif.ops->diag_read(ar, address, buf, buf_len); | 113 | return ar->hif.ops->diag_read(ar, address, buf, buf_len); |
109 | } | 114 | } |
110 | 115 | ||
116 | static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address, | ||
117 | const void *data, int nbytes) | ||
118 | { | ||
119 | if (!ar->hif.ops->diag_write) | ||
120 | return -EOPNOTSUPP; | ||
121 | |||
122 | return ar->hif.ops->diag_write(ar, address, data, nbytes); | ||
123 | } | ||
124 | |||
111 | static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar, | 125 | static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar, |
112 | void *request, u32 request_len, | 126 | void *request, u32 request_len, |
113 | void *response, u32 *response_len) | 127 | void *response, u32 *response_len) |
@@ -187,4 +201,25 @@ static inline int ath10k_hif_resume(struct ath10k *ar) | |||
187 | return ar->hif.ops->resume(ar); | 201 | return ar->hif.ops->resume(ar); |
188 | } | 202 | } |
189 | 203 | ||
204 | static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address) | ||
205 | { | ||
206 | if (!ar->hif.ops->read32) { | ||
207 | ath10k_warn(ar, "hif read32 not supported\n"); | ||
208 | return 0xdeaddead; | ||
209 | } | ||
210 | |||
211 | return ar->hif.ops->read32(ar, address); | ||
212 | } | ||
213 | |||
214 | static inline void ath10k_hif_write32(struct ath10k *ar, | ||
215 | u32 address, u32 data) | ||
216 | { | ||
217 | if (!ar->hif.ops->write32) { | ||
218 | ath10k_warn(ar, "hif write32 not supported\n"); | ||
219 | return; | ||
220 | } | ||
221 | |||
222 | ar->hif.ops->write32(ar, address, data); | ||
223 | } | ||
224 | |||
190 | #endif /* _HIF_H_ */ | 225 | #endif /* _HIF_H_ */ |
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 676bd4ed969b..f1946a6be442 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c | |||
@@ -160,6 +160,7 @@ int ath10k_htc_send(struct ath10k_htc *htc, | |||
160 | 160 | ||
161 | ath10k_htc_prepare_tx_skb(ep, skb); | 161 | ath10k_htc_prepare_tx_skb(ep, skb); |
162 | 162 | ||
163 | skb_cb->eid = eid; | ||
163 | skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); | 164 | skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); |
164 | ret = dma_mapping_error(dev, skb_cb->paddr); | 165 | ret = dma_mapping_error(dev, skb_cb->paddr); |
165 | if (ret) | 166 | if (ret) |
@@ -197,15 +198,18 @@ err_pull: | |||
197 | } | 198 | } |
198 | 199 | ||
199 | static int ath10k_htc_tx_completion_handler(struct ath10k *ar, | 200 | static int ath10k_htc_tx_completion_handler(struct ath10k *ar, |
200 | struct sk_buff *skb, | 201 | struct sk_buff *skb) |
201 | unsigned int eid) | ||
202 | { | 202 | { |
203 | struct ath10k_htc *htc = &ar->htc; | 203 | struct ath10k_htc *htc = &ar->htc; |
204 | struct ath10k_htc_ep *ep = &htc->endpoint[eid]; | 204 | struct ath10k_skb_cb *skb_cb; |
205 | struct ath10k_htc_ep *ep; | ||
205 | 206 | ||
206 | if (WARN_ON_ONCE(!skb)) | 207 | if (WARN_ON_ONCE(!skb)) |
207 | return 0; | 208 | return 0; |
208 | 209 | ||
210 | skb_cb = ATH10K_SKB_CB(skb); | ||
211 | ep = &htc->endpoint[skb_cb->eid]; | ||
212 | |||
209 | ath10k_htc_notify_tx_completion(ep, skb); | 213 | ath10k_htc_notify_tx_completion(ep, skb); |
210 | /* the skb now belongs to the completion handler */ | 214 | /* the skb now belongs to the completion handler */ |
211 | 215 | ||
@@ -317,8 +321,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, | |||
317 | } | 321 | } |
318 | 322 | ||
319 | static int ath10k_htc_rx_completion_handler(struct ath10k *ar, | 323 | static int ath10k_htc_rx_completion_handler(struct ath10k *ar, |
320 | struct sk_buff *skb, | 324 | struct sk_buff *skb) |
321 | u8 pipe_id) | ||
322 | { | 325 | { |
323 | int status = 0; | 326 | int status = 0; |
324 | struct ath10k_htc *htc = &ar->htc; | 327 | struct ath10k_htc *htc = &ar->htc; |
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 15c58e884b6a..1bd5545af903 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h | |||
@@ -126,6 +126,7 @@ enum htt_data_tx_ext_tid { | |||
126 | * (HL hosts manage queues on the host ) | 126 | * (HL hosts manage queues on the host ) |
127 | * more_in_batch: only for HL hosts. indicates if more packets are | 127 | * more_in_batch: only for HL hosts. indicates if more packets are |
128 | * pending. this allows target to wait and aggregate | 128 | * pending. this allows target to wait and aggregate |
129 | * freq: 0 means home channel of given vdev. intended for offchannel | ||
129 | */ | 130 | */ |
130 | struct htt_data_tx_desc { | 131 | struct htt_data_tx_desc { |
131 | u8 flags0; /* %HTT_DATA_TX_DESC_FLAGS0_ */ | 132 | u8 flags0; /* %HTT_DATA_TX_DESC_FLAGS0_ */ |
@@ -133,7 +134,8 @@ struct htt_data_tx_desc { | |||
133 | __le16 len; | 134 | __le16 len; |
134 | __le16 id; | 135 | __le16 id; |
135 | __le32 frags_paddr; | 136 | __le32 frags_paddr; |
136 | __le32 peerid; | 137 | __le16 peerid; |
138 | __le16 freq; | ||
137 | u8 prefetch[0]; /* start of frame, for FW classification engine */ | 139 | u8 prefetch[0]; /* start of frame, for FW classification engine */ |
138 | } __packed; | 140 | } __packed; |
139 | 141 | ||
@@ -156,6 +158,9 @@ enum htt_rx_ring_flags { | |||
156 | HTT_RX_RING_FLAGS_PHY_DATA_RX = 1 << 15 | 158 | HTT_RX_RING_FLAGS_PHY_DATA_RX = 1 << 15 |
157 | }; | 159 | }; |
158 | 160 | ||
161 | #define HTT_RX_RING_SIZE_MIN 128 | ||
162 | #define HTT_RX_RING_SIZE_MAX 2048 | ||
163 | |||
159 | struct htt_rx_ring_setup_ring { | 164 | struct htt_rx_ring_setup_ring { |
160 | __le32 fw_idx_shadow_reg_paddr; | 165 | __le32 fw_idx_shadow_reg_paddr; |
161 | __le32 rx_ring_base_paddr; | 166 | __le32 rx_ring_base_paddr; |
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index fbb3175d4d6e..9c782a42665e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c | |||
@@ -25,19 +25,8 @@ | |||
25 | 25 | ||
26 | #include <linux/log2.h> | 26 | #include <linux/log2.h> |
27 | 27 | ||
28 | /* slightly larger than one large A-MPDU */ | 28 | #define HTT_RX_RING_SIZE 1024 |
29 | #define HTT_RX_RING_SIZE_MIN 128 | 29 | #define HTT_RX_RING_FILL_LEVEL 1000 |
30 | |||
31 | /* roughly 20 ms @ 1 Gbps of 1500B MSDUs */ | ||
32 | #define HTT_RX_RING_SIZE_MAX 2048 | ||
33 | |||
34 | #define HTT_RX_AVG_FRM_BYTES 1000 | ||
35 | |||
36 | /* ms, very conservative */ | ||
37 | #define HTT_RX_HOST_LATENCY_MAX_MS 20 | ||
38 | |||
39 | /* ms, conservative */ | ||
40 | #define HTT_RX_HOST_LATENCY_WORST_LIKELY_MS 10 | ||
41 | 30 | ||
42 | /* when under memory pressure rx ring refill may fail and needs a retry */ | 31 | /* when under memory pressure rx ring refill may fail and needs a retry */ |
43 | #define HTT_RX_RING_REFILL_RETRY_MS 50 | 32 | #define HTT_RX_RING_REFILL_RETRY_MS 50 |
@@ -45,68 +34,6 @@ | |||
45 | static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb); | 34 | static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb); |
46 | static void ath10k_htt_txrx_compl_task(unsigned long ptr); | 35 | static void ath10k_htt_txrx_compl_task(unsigned long ptr); |
47 | 36 | ||
48 | static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt) | ||
49 | { | ||
50 | int size; | ||
51 | |||
52 | /* | ||
53 | * It is expected that the host CPU will typically be able to | ||
54 | * service the rx indication from one A-MPDU before the rx | ||
55 | * indication from the subsequent A-MPDU happens, roughly 1-2 ms | ||
56 | * later. However, the rx ring should be sized very conservatively, | ||
57 | * to accomodate the worst reasonable delay before the host CPU | ||
58 | * services a rx indication interrupt. | ||
59 | * | ||
60 | * The rx ring need not be kept full of empty buffers. In theory, | ||
61 | * the htt host SW can dynamically track the low-water mark in the | ||
62 | * rx ring, and dynamically adjust the level to which the rx ring | ||
63 | * is filled with empty buffers, to dynamically meet the desired | ||
64 | * low-water mark. | ||
65 | * | ||
66 | * In contrast, it's difficult to resize the rx ring itself, once | ||
67 | * it's in use. Thus, the ring itself should be sized very | ||
68 | * conservatively, while the degree to which the ring is filled | ||
69 | * with empty buffers should be sized moderately conservatively. | ||
70 | */ | ||
71 | |||
72 | /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ | ||
73 | size = | ||
74 | htt->max_throughput_mbps + | ||
75 | 1000 / | ||
76 | (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_MAX_MS; | ||
77 | |||
78 | if (size < HTT_RX_RING_SIZE_MIN) | ||
79 | size = HTT_RX_RING_SIZE_MIN; | ||
80 | |||
81 | if (size > HTT_RX_RING_SIZE_MAX) | ||
82 | size = HTT_RX_RING_SIZE_MAX; | ||
83 | |||
84 | size = roundup_pow_of_two(size); | ||
85 | |||
86 | return size; | ||
87 | } | ||
88 | |||
89 | static int ath10k_htt_rx_ring_fill_level(struct ath10k_htt *htt) | ||
90 | { | ||
91 | int size; | ||
92 | |||
93 | /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ | ||
94 | size = | ||
95 | htt->max_throughput_mbps * | ||
96 | 1000 / | ||
97 | (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_WORST_LIKELY_MS; | ||
98 | |||
99 | /* | ||
100 | * Make sure the fill level is at least 1 less than the ring size. | ||
101 | * Leaving 1 element empty allows the SW to easily distinguish | ||
102 | * between a full ring vs. an empty ring. | ||
103 | */ | ||
104 | if (size >= htt->rx_ring.size) | ||
105 | size = htt->rx_ring.size - 1; | ||
106 | |||
107 | return size; | ||
108 | } | ||
109 | |||
110 | static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt) | 37 | static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt) |
111 | { | 38 | { |
112 | struct sk_buff *skb; | 39 | struct sk_buff *skb; |
@@ -291,54 +218,38 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) | |||
291 | htt->rx_ring.sw_rd_idx.msdu_payld = idx; | 218 | htt->rx_ring.sw_rd_idx.msdu_payld = idx; |
292 | htt->rx_ring.fill_cnt--; | 219 | htt->rx_ring.fill_cnt--; |
293 | 220 | ||
294 | trace_ath10k_htt_rx_pop_msdu(ar, msdu->data, msdu->len + | 221 | dma_unmap_single(htt->ar->dev, |
295 | skb_tailroom(msdu)); | 222 | ATH10K_SKB_CB(msdu)->paddr, |
223 | msdu->len + skb_tailroom(msdu), | ||
224 | DMA_FROM_DEVICE); | ||
225 | ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ", | ||
226 | msdu->data, msdu->len + skb_tailroom(msdu)); | ||
296 | 227 | ||
297 | return msdu; | 228 | return msdu; |
298 | } | 229 | } |
299 | 230 | ||
300 | static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb) | ||
301 | { | ||
302 | struct sk_buff *next; | ||
303 | |||
304 | while (skb) { | ||
305 | next = skb->next; | ||
306 | dev_kfree_skb_any(skb); | ||
307 | skb = next; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | /* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */ | 231 | /* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */ |
312 | static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, | 232 | static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, |
313 | u8 **fw_desc, int *fw_desc_len, | 233 | u8 **fw_desc, int *fw_desc_len, |
314 | struct sk_buff **head_msdu, | 234 | struct sk_buff_head *amsdu) |
315 | struct sk_buff **tail_msdu, | ||
316 | u32 *attention) | ||
317 | { | 235 | { |
318 | struct ath10k *ar = htt->ar; | 236 | struct ath10k *ar = htt->ar; |
319 | int msdu_len, msdu_chaining = 0; | 237 | int msdu_len, msdu_chaining = 0; |
320 | struct sk_buff *msdu, *next; | 238 | struct sk_buff *msdu; |
321 | struct htt_rx_desc *rx_desc; | 239 | struct htt_rx_desc *rx_desc; |
322 | u32 tsf; | ||
323 | 240 | ||
324 | lockdep_assert_held(&htt->rx_ring.lock); | 241 | lockdep_assert_held(&htt->rx_ring.lock); |
325 | 242 | ||
326 | if (htt->rx_confused) { | 243 | for (;;) { |
327 | ath10k_warn(ar, "htt is confused. refusing rx\n"); | ||
328 | return -1; | ||
329 | } | ||
330 | |||
331 | msdu = *head_msdu = ath10k_htt_rx_netbuf_pop(htt); | ||
332 | while (msdu) { | ||
333 | int last_msdu, msdu_len_invalid, msdu_chained; | 244 | int last_msdu, msdu_len_invalid, msdu_chained; |
334 | 245 | ||
335 | dma_unmap_single(htt->ar->dev, | 246 | msdu = ath10k_htt_rx_netbuf_pop(htt); |
336 | ATH10K_SKB_CB(msdu)->paddr, | 247 | if (!msdu) { |
337 | msdu->len + skb_tailroom(msdu), | 248 | __skb_queue_purge(amsdu); |
338 | DMA_FROM_DEVICE); | 249 | return -ENOENT; |
250 | } | ||
339 | 251 | ||
340 | ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ", | 252 | __skb_queue_tail(amsdu, msdu); |
341 | msdu->data, msdu->len + skb_tailroom(msdu)); | ||
342 | 253 | ||
343 | rx_desc = (struct htt_rx_desc *)msdu->data; | 254 | rx_desc = (struct htt_rx_desc *)msdu->data; |
344 | 255 | ||
@@ -357,19 +268,10 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, | |||
357 | */ | 268 | */ |
358 | if (!(__le32_to_cpu(rx_desc->attention.flags) | 269 | if (!(__le32_to_cpu(rx_desc->attention.flags) |
359 | & RX_ATTENTION_FLAGS_MSDU_DONE)) { | 270 | & RX_ATTENTION_FLAGS_MSDU_DONE)) { |
360 | ath10k_htt_rx_free_msdu_chain(*head_msdu); | 271 | __skb_queue_purge(amsdu); |
361 | *head_msdu = NULL; | 272 | return -EIO; |
362 | msdu = NULL; | ||
363 | ath10k_err(ar, "htt rx stopped. cannot recover\n"); | ||
364 | htt->rx_confused = true; | ||
365 | break; | ||
366 | } | 273 | } |
367 | 274 | ||
368 | *attention |= __le32_to_cpu(rx_desc->attention.flags) & | ||
369 | (RX_ATTENTION_FLAGS_TKIP_MIC_ERR | | ||
370 | RX_ATTENTION_FLAGS_DECRYPT_ERR | | ||
371 | RX_ATTENTION_FLAGS_FCS_ERR | | ||
372 | RX_ATTENTION_FLAGS_MGMT_TYPE); | ||
373 | /* | 275 | /* |
374 | * Copy the FW rx descriptor for this MSDU from the rx | 276 | * Copy the FW rx descriptor for this MSDU from the rx |
375 | * indication message into the MSDU's netbuf. HL uses the | 277 | * indication message into the MSDU's netbuf. HL uses the |
@@ -426,46 +328,32 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, | |||
426 | skb_put(msdu, min(msdu_len, HTT_RX_MSDU_SIZE)); | 328 | skb_put(msdu, min(msdu_len, HTT_RX_MSDU_SIZE)); |
427 | msdu_len -= msdu->len; | 329 | msdu_len -= msdu->len; |
428 | 330 | ||
429 | /* FIXME: Do chained buffers include htt_rx_desc or not? */ | 331 | /* Note: Chained buffers do not contain rx descriptor */ |
430 | while (msdu_chained--) { | 332 | while (msdu_chained--) { |
431 | struct sk_buff *next = ath10k_htt_rx_netbuf_pop(htt); | 333 | msdu = ath10k_htt_rx_netbuf_pop(htt); |
432 | 334 | if (!msdu) { | |
433 | dma_unmap_single(htt->ar->dev, | 335 | __skb_queue_purge(amsdu); |
434 | ATH10K_SKB_CB(next)->paddr, | 336 | return -ENOENT; |
435 | next->len + skb_tailroom(next), | 337 | } |
436 | DMA_FROM_DEVICE); | ||
437 | |||
438 | ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, | ||
439 | "htt rx chained: ", next->data, | ||
440 | next->len + skb_tailroom(next)); | ||
441 | |||
442 | skb_trim(next, 0); | ||
443 | skb_put(next, min(msdu_len, HTT_RX_BUF_SIZE)); | ||
444 | msdu_len -= next->len; | ||
445 | 338 | ||
446 | msdu->next = next; | 339 | __skb_queue_tail(amsdu, msdu); |
447 | msdu = next; | 340 | skb_trim(msdu, 0); |
341 | skb_put(msdu, min(msdu_len, HTT_RX_BUF_SIZE)); | ||
342 | msdu_len -= msdu->len; | ||
448 | msdu_chaining = 1; | 343 | msdu_chaining = 1; |
449 | } | 344 | } |
450 | 345 | ||
451 | last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & | 346 | last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & |
452 | RX_MSDU_END_INFO0_LAST_MSDU; | 347 | RX_MSDU_END_INFO0_LAST_MSDU; |
453 | 348 | ||
454 | tsf = __le32_to_cpu(rx_desc->ppdu_end.tsf_timestamp); | 349 | trace_ath10k_htt_rx_desc(ar, &rx_desc->attention, |
455 | trace_ath10k_htt_rx_desc(ar, tsf, &rx_desc->attention, | ||
456 | sizeof(*rx_desc) - sizeof(u32)); | 350 | sizeof(*rx_desc) - sizeof(u32)); |
457 | if (last_msdu) { | ||
458 | msdu->next = NULL; | ||
459 | break; | ||
460 | } | ||
461 | 351 | ||
462 | next = ath10k_htt_rx_netbuf_pop(htt); | 352 | if (last_msdu) |
463 | msdu->next = next; | 353 | break; |
464 | msdu = next; | ||
465 | } | 354 | } |
466 | *tail_msdu = msdu; | ||
467 | 355 | ||
468 | if (*head_msdu == NULL) | 356 | if (skb_queue_empty(amsdu)) |
469 | msdu_chaining = -1; | 357 | msdu_chaining = -1; |
470 | 358 | ||
471 | /* | 359 | /* |
@@ -499,25 +387,20 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) | |||
499 | size_t size; | 387 | size_t size; |
500 | struct timer_list *timer = &htt->rx_ring.refill_retry_timer; | 388 | struct timer_list *timer = &htt->rx_ring.refill_retry_timer; |
501 | 389 | ||
502 | htt->rx_ring.size = ath10k_htt_rx_ring_size(htt); | 390 | htt->rx_confused = false; |
391 | |||
392 | /* XXX: The fill level could be changed during runtime in response to | ||
393 | * the host processing latency. Is this really worth it? | ||
394 | */ | ||
395 | htt->rx_ring.size = HTT_RX_RING_SIZE; | ||
396 | htt->rx_ring.size_mask = htt->rx_ring.size - 1; | ||
397 | htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL; | ||
398 | |||
503 | if (!is_power_of_2(htt->rx_ring.size)) { | 399 | if (!is_power_of_2(htt->rx_ring.size)) { |
504 | ath10k_warn(ar, "htt rx ring size is not power of 2\n"); | 400 | ath10k_warn(ar, "htt rx ring size is not power of 2\n"); |
505 | return -EINVAL; | 401 | return -EINVAL; |
506 | } | 402 | } |
507 | 403 | ||
508 | htt->rx_ring.size_mask = htt->rx_ring.size - 1; | ||
509 | |||
510 | /* | ||
511 | * Set the initial value for the level to which the rx ring | ||
512 | * should be filled, based on the max throughput and the | ||
513 | * worst likely latency for the host to fill the rx ring | ||
514 | * with new buffers. In theory, this fill level can be | ||
515 | * dynamically adjusted from the initial value set here, to | ||
516 | * reflect the actual host latency rather than a | ||
517 | * conservative assumption about the host latency. | ||
518 | */ | ||
519 | htt->rx_ring.fill_level = ath10k_htt_rx_ring_fill_level(htt); | ||
520 | |||
521 | htt->rx_ring.netbufs_ring = | 404 | htt->rx_ring.netbufs_ring = |
522 | kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *), | 405 | kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *), |
523 | GFP_KERNEL); | 406 | GFP_KERNEL); |
@@ -588,73 +471,50 @@ static int ath10k_htt_rx_crypto_param_len(struct ath10k *ar, | |||
588 | enum htt_rx_mpdu_encrypt_type type) | 471 | enum htt_rx_mpdu_encrypt_type type) |
589 | { | 472 | { |
590 | switch (type) { | 473 | switch (type) { |
474 | case HTT_RX_MPDU_ENCRYPT_NONE: | ||
475 | return 0; | ||
591 | case HTT_RX_MPDU_ENCRYPT_WEP40: | 476 | case HTT_RX_MPDU_ENCRYPT_WEP40: |
592 | case HTT_RX_MPDU_ENCRYPT_WEP104: | 477 | case HTT_RX_MPDU_ENCRYPT_WEP104: |
593 | return 4; | 478 | return IEEE80211_WEP_IV_LEN; |
594 | case HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC: | 479 | case HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC: |
595 | case HTT_RX_MPDU_ENCRYPT_WEP128: /* not tested */ | ||
596 | case HTT_RX_MPDU_ENCRYPT_TKIP_WPA: | 480 | case HTT_RX_MPDU_ENCRYPT_TKIP_WPA: |
597 | case HTT_RX_MPDU_ENCRYPT_WAPI: /* not tested */ | 481 | return IEEE80211_TKIP_IV_LEN; |
598 | case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2: | 482 | case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2: |
599 | return 8; | 483 | return IEEE80211_CCMP_HDR_LEN; |
600 | case HTT_RX_MPDU_ENCRYPT_NONE: | 484 | case HTT_RX_MPDU_ENCRYPT_WEP128: |
601 | return 0; | 485 | case HTT_RX_MPDU_ENCRYPT_WAPI: |
486 | break; | ||
602 | } | 487 | } |
603 | 488 | ||
604 | ath10k_warn(ar, "unknown encryption type %d\n", type); | 489 | ath10k_warn(ar, "unsupported encryption type %d\n", type); |
605 | return 0; | 490 | return 0; |
606 | } | 491 | } |
607 | 492 | ||
493 | #define MICHAEL_MIC_LEN 8 | ||
494 | |||
608 | static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar, | 495 | static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar, |
609 | enum htt_rx_mpdu_encrypt_type type) | 496 | enum htt_rx_mpdu_encrypt_type type) |
610 | { | 497 | { |
611 | switch (type) { | 498 | switch (type) { |
612 | case HTT_RX_MPDU_ENCRYPT_NONE: | 499 | case HTT_RX_MPDU_ENCRYPT_NONE: |
500 | return 0; | ||
613 | case HTT_RX_MPDU_ENCRYPT_WEP40: | 501 | case HTT_RX_MPDU_ENCRYPT_WEP40: |
614 | case HTT_RX_MPDU_ENCRYPT_WEP104: | 502 | case HTT_RX_MPDU_ENCRYPT_WEP104: |
615 | case HTT_RX_MPDU_ENCRYPT_WEP128: | 503 | return IEEE80211_WEP_ICV_LEN; |
616 | case HTT_RX_MPDU_ENCRYPT_WAPI: | ||
617 | return 0; | ||
618 | case HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC: | 504 | case HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC: |
619 | case HTT_RX_MPDU_ENCRYPT_TKIP_WPA: | 505 | case HTT_RX_MPDU_ENCRYPT_TKIP_WPA: |
620 | return 4; | 506 | return IEEE80211_TKIP_ICV_LEN; |
621 | case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2: | 507 | case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2: |
622 | return 8; | 508 | return IEEE80211_CCMP_MIC_LEN; |
509 | case HTT_RX_MPDU_ENCRYPT_WEP128: | ||
510 | case HTT_RX_MPDU_ENCRYPT_WAPI: | ||
511 | break; | ||
623 | } | 512 | } |
624 | 513 | ||
625 | ath10k_warn(ar, "unknown encryption type %d\n", type); | 514 | ath10k_warn(ar, "unsupported encryption type %d\n", type); |
626 | return 0; | 515 | return 0; |
627 | } | 516 | } |
628 | 517 | ||
629 | /* Applies for first msdu in chain, before altering it. */ | ||
630 | static struct ieee80211_hdr *ath10k_htt_rx_skb_get_hdr(struct sk_buff *skb) | ||
631 | { | ||
632 | struct htt_rx_desc *rxd; | ||
633 | enum rx_msdu_decap_format fmt; | ||
634 | |||
635 | rxd = (void *)skb->data - sizeof(*rxd); | ||
636 | fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), | ||
637 | RX_MSDU_START_INFO1_DECAP_FORMAT); | ||
638 | |||
639 | if (fmt == RX_MSDU_DECAP_RAW) | ||
640 | return (void *)skb->data; | ||
641 | |||
642 | return (void *)skb->data - RX_HTT_HDR_STATUS_LEN; | ||
643 | } | ||
644 | |||
645 | /* This function only applies for first msdu in an msdu chain */ | ||
646 | static bool ath10k_htt_rx_hdr_is_amsdu(struct ieee80211_hdr *hdr) | ||
647 | { | ||
648 | u8 *qc; | ||
649 | |||
650 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
651 | qc = ieee80211_get_qos_ctl(hdr); | ||
652 | if (qc[0] & 0x80) | ||
653 | return true; | ||
654 | } | ||
655 | return false; | ||
656 | } | ||
657 | |||
658 | struct rfc1042_hdr { | 518 | struct rfc1042_hdr { |
659 | u8 llc_dsap; | 519 | u8 llc_dsap; |
660 | u8 llc_ssap; | 520 | u8 llc_ssap; |
@@ -689,23 +549,34 @@ static const u8 rx_legacy_rate_idx[] = { | |||
689 | }; | 549 | }; |
690 | 550 | ||
691 | static void ath10k_htt_rx_h_rates(struct ath10k *ar, | 551 | static void ath10k_htt_rx_h_rates(struct ath10k *ar, |
692 | enum ieee80211_band band, | 552 | struct ieee80211_rx_status *status, |
693 | u8 info0, u32 info1, u32 info2, | 553 | struct htt_rx_desc *rxd) |
694 | struct ieee80211_rx_status *status) | ||
695 | { | 554 | { |
555 | enum ieee80211_band band; | ||
696 | u8 cck, rate, rate_idx, bw, sgi, mcs, nss; | 556 | u8 cck, rate, rate_idx, bw, sgi, mcs, nss; |
697 | u8 preamble = 0; | 557 | u8 preamble = 0; |
558 | u32 info1, info2, info3; | ||
698 | 559 | ||
699 | /* Check if valid fields */ | 560 | /* Band value can't be set as undefined but freq can be 0 - use that to |
700 | if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID)) | 561 | * determine whether band is provided. |
562 | * | ||
563 | * FIXME: Perhaps this can go away if CCK rate reporting is a little | ||
564 | * reworked? | ||
565 | */ | ||
566 | if (!status->freq) | ||
701 | return; | 567 | return; |
702 | 568 | ||
703 | preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE); | 569 | band = status->band; |
570 | info1 = __le32_to_cpu(rxd->ppdu_start.info1); | ||
571 | info2 = __le32_to_cpu(rxd->ppdu_start.info2); | ||
572 | info3 = __le32_to_cpu(rxd->ppdu_start.info3); | ||
573 | |||
574 | preamble = MS(info1, RX_PPDU_START_INFO1_PREAMBLE_TYPE); | ||
704 | 575 | ||
705 | switch (preamble) { | 576 | switch (preamble) { |
706 | case HTT_RX_LEGACY: | 577 | case HTT_RX_LEGACY: |
707 | cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK; | 578 | cck = info1 & RX_PPDU_START_INFO1_L_SIG_RATE_SELECT; |
708 | rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE); | 579 | rate = MS(info1, RX_PPDU_START_INFO1_L_SIG_RATE); |
709 | rate_idx = 0; | 580 | rate_idx = 0; |
710 | 581 | ||
711 | if (rate < 0x08 || rate > 0x0F) | 582 | if (rate < 0x08 || rate > 0x0F) |
@@ -732,11 +603,11 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, | |||
732 | break; | 603 | break; |
733 | case HTT_RX_HT: | 604 | case HTT_RX_HT: |
734 | case HTT_RX_HT_WITH_TXBF: | 605 | case HTT_RX_HT_WITH_TXBF: |
735 | /* HT-SIG - Table 20-11 in info1 and info2 */ | 606 | /* HT-SIG - Table 20-11 in info2 and info3 */ |
736 | mcs = info1 & 0x1F; | 607 | mcs = info2 & 0x1F; |
737 | nss = mcs >> 3; | 608 | nss = mcs >> 3; |
738 | bw = (info1 >> 7) & 1; | 609 | bw = (info2 >> 7) & 1; |
739 | sgi = (info2 >> 7) & 1; | 610 | sgi = (info3 >> 7) & 1; |
740 | 611 | ||
741 | status->rate_idx = mcs; | 612 | status->rate_idx = mcs; |
742 | status->flag |= RX_FLAG_HT; | 613 | status->flag |= RX_FLAG_HT; |
@@ -747,12 +618,12 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, | |||
747 | break; | 618 | break; |
748 | case HTT_RX_VHT: | 619 | case HTT_RX_VHT: |
749 | case HTT_RX_VHT_WITH_TXBF: | 620 | case HTT_RX_VHT_WITH_TXBF: |
750 | /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2 | 621 | /* VHT-SIG-A1 in info2, VHT-SIG-A2 in info3 |
751 | TODO check this */ | 622 | TODO check this */ |
752 | mcs = (info2 >> 4) & 0x0F; | 623 | mcs = (info3 >> 4) & 0x0F; |
753 | nss = ((info1 >> 10) & 0x07) + 1; | 624 | nss = ((info2 >> 10) & 0x07) + 1; |
754 | bw = info1 & 3; | 625 | bw = info2 & 3; |
755 | sgi = info2 & 1; | 626 | sgi = info3 & 1; |
756 | 627 | ||
757 | status->rate_idx = mcs; | 628 | status->rate_idx = mcs; |
758 | status->vht_nss = nss; | 629 | status->vht_nss = nss; |
@@ -780,41 +651,6 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, | |||
780 | } | 651 | } |
781 | } | 652 | } |
782 | 653 | ||
783 | static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt, | ||
784 | struct ieee80211_rx_status *rx_status, | ||
785 | struct sk_buff *skb, | ||
786 | enum htt_rx_mpdu_encrypt_type enctype, | ||
787 | enum rx_msdu_decap_format fmt, | ||
788 | bool dot11frag) | ||
789 | { | ||
790 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
791 | |||
792 | rx_status->flag &= ~(RX_FLAG_DECRYPTED | | ||
793 | RX_FLAG_IV_STRIPPED | | ||
794 | RX_FLAG_MMIC_STRIPPED); | ||
795 | |||
796 | if (enctype == HTT_RX_MPDU_ENCRYPT_NONE) | ||
797 | return; | ||
798 | |||
799 | /* | ||
800 | * There's no explicit rx descriptor flag to indicate whether a given | ||
801 | * frame has been decrypted or not. We're forced to use the decap | ||
802 | * format as an implicit indication. However fragmentation rx is always | ||
803 | * raw and it probably never reports undecrypted raws. | ||
804 | * | ||
805 | * This makes sure sniffed frames are reported as-is without stripping | ||
806 | * the protected flag. | ||
807 | */ | ||
808 | if (fmt == RX_MSDU_DECAP_RAW && !dot11frag) | ||
809 | return; | ||
810 | |||
811 | rx_status->flag |= RX_FLAG_DECRYPTED | | ||
812 | RX_FLAG_IV_STRIPPED | | ||
813 | RX_FLAG_MMIC_STRIPPED; | ||
814 | hdr->frame_control = __cpu_to_le16(__le16_to_cpu(hdr->frame_control) & | ||
815 | ~IEEE80211_FCTL_PROTECTED); | ||
816 | } | ||
817 | |||
818 | static bool ath10k_htt_rx_h_channel(struct ath10k *ar, | 654 | static bool ath10k_htt_rx_h_channel(struct ath10k *ar, |
819 | struct ieee80211_rx_status *status) | 655 | struct ieee80211_rx_status *status) |
820 | { | 656 | { |
@@ -835,6 +671,72 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar, | |||
835 | return true; | 671 | return true; |
836 | } | 672 | } |
837 | 673 | ||
674 | static void ath10k_htt_rx_h_signal(struct ath10k *ar, | ||
675 | struct ieee80211_rx_status *status, | ||
676 | struct htt_rx_desc *rxd) | ||
677 | { | ||
678 | /* FIXME: Get real NF */ | ||
679 | status->signal = ATH10K_DEFAULT_NOISE_FLOOR + | ||
680 | rxd->ppdu_start.rssi_comb; | ||
681 | status->flag &= ~RX_FLAG_NO_SIGNAL_VAL; | ||
682 | } | ||
683 | |||
684 | static void ath10k_htt_rx_h_mactime(struct ath10k *ar, | ||
685 | struct ieee80211_rx_status *status, | ||
686 | struct htt_rx_desc *rxd) | ||
687 | { | ||
688 | /* FIXME: TSF is known only at the end of PPDU, in the last MPDU. This | ||
689 | * means all prior MSDUs in a PPDU are reported to mac80211 without the | ||
690 | * TSF. Is it worth holding frames until end of PPDU is known? | ||
691 | * | ||
692 | * FIXME: Can we get/compute 64bit TSF? | ||
693 | */ | ||
694 | status->mactime = __le32_to_cpu(rxd->ppdu_end.tsf_timestamp); | ||
695 | status->flag |= RX_FLAG_MACTIME_END; | ||
696 | } | ||
697 | |||
698 | static void ath10k_htt_rx_h_ppdu(struct ath10k *ar, | ||
699 | struct sk_buff_head *amsdu, | ||
700 | struct ieee80211_rx_status *status) | ||
701 | { | ||
702 | struct sk_buff *first; | ||
703 | struct htt_rx_desc *rxd; | ||
704 | bool is_first_ppdu; | ||
705 | bool is_last_ppdu; | ||
706 | |||
707 | if (skb_queue_empty(amsdu)) | ||
708 | return; | ||
709 | |||
710 | first = skb_peek(amsdu); | ||
711 | rxd = (void *)first->data - sizeof(*rxd); | ||
712 | |||
713 | is_first_ppdu = !!(rxd->attention.flags & | ||
714 | __cpu_to_le32(RX_ATTENTION_FLAGS_FIRST_MPDU)); | ||
715 | is_last_ppdu = !!(rxd->attention.flags & | ||
716 | __cpu_to_le32(RX_ATTENTION_FLAGS_LAST_MPDU)); | ||
717 | |||
718 | if (is_first_ppdu) { | ||
719 | /* New PPDU starts so clear out the old per-PPDU status. */ | ||
720 | status->freq = 0; | ||
721 | status->rate_idx = 0; | ||
722 | status->vht_nss = 0; | ||
723 | status->vht_flag &= ~RX_VHT_FLAG_80MHZ; | ||
724 | status->flag &= ~(RX_FLAG_HT | | ||
725 | RX_FLAG_VHT | | ||
726 | RX_FLAG_SHORT_GI | | ||
727 | RX_FLAG_40MHZ | | ||
728 | RX_FLAG_MACTIME_END); | ||
729 | status->flag |= RX_FLAG_NO_SIGNAL_VAL; | ||
730 | |||
731 | ath10k_htt_rx_h_signal(ar, status, rxd); | ||
732 | ath10k_htt_rx_h_channel(ar, status); | ||
733 | ath10k_htt_rx_h_rates(ar, status, rxd); | ||
734 | } | ||
735 | |||
736 | if (is_last_ppdu) | ||
737 | ath10k_htt_rx_h_mactime(ar, status, rxd); | ||
738 | } | ||
739 | |||
838 | static const char * const tid_to_ac[] = { | 740 | static const char * const tid_to_ac[] = { |
839 | "BE", | 741 | "BE", |
840 | "BK", | 742 | "BK", |
@@ -899,6 +801,8 @@ static void ath10k_process_rx(struct ath10k *ar, | |||
899 | !!(status->flag & RX_FLAG_AMSDU_MORE)); | 801 | !!(status->flag & RX_FLAG_AMSDU_MORE)); |
900 | ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", | 802 | ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", |
901 | skb->data, skb->len); | 803 | skb->data, skb->len); |
804 | trace_ath10k_rx_hdr(ar, skb->data, skb->len); | ||
805 | trace_ath10k_rx_payload(ar, skb->data, skb->len); | ||
902 | 806 | ||
903 | ieee80211_rx(ar->hw, skb); | 807 | ieee80211_rx(ar->hw, skb); |
904 | } | 808 | } |
@@ -909,187 +813,263 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr) | |||
909 | return round_up(ieee80211_hdrlen(hdr->frame_control), 4); | 813 | return round_up(ieee80211_hdrlen(hdr->frame_control), 4); |
910 | } | 814 | } |
911 | 815 | ||
912 | static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, | 816 | static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, |
913 | struct ieee80211_rx_status *rx_status, | 817 | struct sk_buff *msdu, |
914 | struct sk_buff *skb_in) | 818 | struct ieee80211_rx_status *status, |
819 | enum htt_rx_mpdu_encrypt_type enctype, | ||
820 | bool is_decrypted) | ||
915 | { | 821 | { |
916 | struct ath10k *ar = htt->ar; | 822 | struct ieee80211_hdr *hdr; |
917 | struct htt_rx_desc *rxd; | 823 | struct htt_rx_desc *rxd; |
918 | struct sk_buff *skb = skb_in; | 824 | size_t hdr_len; |
919 | struct sk_buff *first; | 825 | size_t crypto_len; |
920 | enum rx_msdu_decap_format fmt; | 826 | bool is_first; |
921 | enum htt_rx_mpdu_encrypt_type enctype; | 827 | bool is_last; |
828 | |||
829 | rxd = (void *)msdu->data - sizeof(*rxd); | ||
830 | is_first = !!(rxd->msdu_end.info0 & | ||
831 | __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); | ||
832 | is_last = !!(rxd->msdu_end.info0 & | ||
833 | __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); | ||
834 | |||
835 | /* Delivered decapped frame: | ||
836 | * [802.11 header] | ||
837 | * [crypto param] <-- can be trimmed if !fcs_err && | ||
838 | * !decrypt_err && !peer_idx_invalid | ||
839 | * [amsdu header] <-- only if A-MSDU | ||
840 | * [rfc1042/llc] | ||
841 | * [payload] | ||
842 | * [FCS] <-- at end, needs to be trimmed | ||
843 | */ | ||
844 | |||
845 | /* This probably shouldn't happen but warn just in case */ | ||
846 | if (unlikely(WARN_ON_ONCE(!is_first))) | ||
847 | return; | ||
848 | |||
849 | /* This probably shouldn't happen but warn just in case */ | ||
850 | if (unlikely(WARN_ON_ONCE(!(is_first && is_last)))) | ||
851 | return; | ||
852 | |||
853 | skb_trim(msdu, msdu->len - FCS_LEN); | ||
854 | |||
855 | /* In most cases this will be true for sniffed frames. It makes sense | ||
856 | * to deliver them as-is without stripping the crypto param. This would | ||
857 | * also make sense for software based decryption (which is not | ||
858 | * implemented in ath10k). | ||
859 | * | ||
860 | * If there's no error then the frame is decrypted. At least that is | ||
861 | * the case for frames that come in via fragmented rx indication. | ||
862 | */ | ||
863 | if (!is_decrypted) | ||
864 | return; | ||
865 | |||
866 | /* The payload is decrypted so strip crypto params. Start from tail | ||
867 | * since hdr is used to compute some stuff. | ||
868 | */ | ||
869 | |||
870 | hdr = (void *)msdu->data; | ||
871 | |||
872 | /* Tail */ | ||
873 | skb_trim(msdu, msdu->len - ath10k_htt_rx_crypto_tail_len(ar, enctype)); | ||
874 | |||
875 | /* MMIC */ | ||
876 | if (!ieee80211_has_morefrags(hdr->frame_control) && | ||
877 | enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) | ||
878 | skb_trim(msdu, msdu->len - 8); | ||
879 | |||
880 | /* Head */ | ||
881 | hdr_len = ieee80211_hdrlen(hdr->frame_control); | ||
882 | crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype); | ||
883 | |||
884 | memmove((void *)msdu->data + crypto_len, | ||
885 | (void *)msdu->data, hdr_len); | ||
886 | skb_pull(msdu, crypto_len); | ||
887 | } | ||
888 | |||
889 | static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar, | ||
890 | struct sk_buff *msdu, | ||
891 | struct ieee80211_rx_status *status, | ||
892 | const u8 first_hdr[64]) | ||
893 | { | ||
922 | struct ieee80211_hdr *hdr; | 894 | struct ieee80211_hdr *hdr; |
923 | u8 hdr_buf[64], da[ETH_ALEN], sa[ETH_ALEN], *qos; | 895 | size_t hdr_len; |
924 | unsigned int hdr_len; | 896 | u8 da[ETH_ALEN]; |
897 | u8 sa[ETH_ALEN]; | ||
925 | 898 | ||
926 | rxd = (void *)skb->data - sizeof(*rxd); | 899 | /* Delivered decapped frame: |
927 | enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), | 900 | * [nwifi 802.11 header] <-- replaced with 802.11 hdr |
928 | RX_MPDU_START_INFO0_ENCRYPT_TYPE); | 901 | * [rfc1042/llc] |
902 | * | ||
903 | * Note: The nwifi header doesn't have QoS Control and is | ||
904 | * (always?) a 3addr frame. | ||
905 | * | ||
906 | * Note2: There's no A-MSDU subframe header. Even if it's part | ||
907 | * of an A-MSDU. | ||
908 | */ | ||
909 | |||
910 | /* pull decapped header and copy SA & DA */ | ||
911 | hdr = (struct ieee80211_hdr *)msdu->data; | ||
912 | hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); | ||
913 | ether_addr_copy(da, ieee80211_get_DA(hdr)); | ||
914 | ether_addr_copy(sa, ieee80211_get_SA(hdr)); | ||
915 | skb_pull(msdu, hdr_len); | ||
929 | 916 | ||
930 | hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; | 917 | /* push original 802.11 header */ |
918 | hdr = (struct ieee80211_hdr *)first_hdr; | ||
931 | hdr_len = ieee80211_hdrlen(hdr->frame_control); | 919 | hdr_len = ieee80211_hdrlen(hdr->frame_control); |
932 | memcpy(hdr_buf, hdr, hdr_len); | 920 | memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); |
933 | hdr = (struct ieee80211_hdr *)hdr_buf; | ||
934 | |||
935 | first = skb; | ||
936 | while (skb) { | ||
937 | void *decap_hdr; | ||
938 | int len; | ||
939 | |||
940 | rxd = (void *)skb->data - sizeof(*rxd); | ||
941 | fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), | ||
942 | RX_MSDU_START_INFO1_DECAP_FORMAT); | ||
943 | decap_hdr = (void *)rxd->rx_hdr_status; | ||
944 | |||
945 | skb->ip_summed = ath10k_htt_rx_get_csum_state(skb); | ||
946 | |||
947 | /* First frame in an A-MSDU chain has more decapped data. */ | ||
948 | if (skb == first) { | ||
949 | len = round_up(ieee80211_hdrlen(hdr->frame_control), 4); | ||
950 | len += round_up(ath10k_htt_rx_crypto_param_len(ar, | ||
951 | enctype), 4); | ||
952 | decap_hdr += len; | ||
953 | } | ||
954 | 921 | ||
955 | switch (fmt) { | 922 | /* original 802.11 header has a different DA and in |
956 | case RX_MSDU_DECAP_RAW: | 923 | * case of 4addr it may also have different SA |
957 | /* remove trailing FCS */ | 924 | */ |
958 | skb_trim(skb, skb->len - FCS_LEN); | 925 | hdr = (struct ieee80211_hdr *)msdu->data; |
959 | break; | 926 | ether_addr_copy(ieee80211_get_DA(hdr), da); |
960 | case RX_MSDU_DECAP_NATIVE_WIFI: | 927 | ether_addr_copy(ieee80211_get_SA(hdr), sa); |
961 | /* pull decapped header and copy SA & DA */ | 928 | } |
962 | hdr = (struct ieee80211_hdr *)skb->data; | 929 | |
963 | hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); | 930 | static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar, |
964 | ether_addr_copy(da, ieee80211_get_DA(hdr)); | 931 | struct sk_buff *msdu, |
965 | ether_addr_copy(sa, ieee80211_get_SA(hdr)); | 932 | enum htt_rx_mpdu_encrypt_type enctype) |
966 | skb_pull(skb, hdr_len); | 933 | { |
967 | 934 | struct ieee80211_hdr *hdr; | |
968 | /* push original 802.11 header */ | 935 | struct htt_rx_desc *rxd; |
969 | hdr = (struct ieee80211_hdr *)hdr_buf; | 936 | size_t hdr_len, crypto_len; |
970 | hdr_len = ieee80211_hdrlen(hdr->frame_control); | 937 | void *rfc1042; |
971 | memcpy(skb_push(skb, hdr_len), hdr, hdr_len); | 938 | bool is_first, is_last, is_amsdu; |
972 | |||
973 | /* original A-MSDU header has the bit set but we're | ||
974 | * not including A-MSDU subframe header */ | ||
975 | hdr = (struct ieee80211_hdr *)skb->data; | ||
976 | qos = ieee80211_get_qos_ctl(hdr); | ||
977 | qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; | ||
978 | |||
979 | /* original 802.11 header has a different DA and in | ||
980 | * case of 4addr it may also have different SA | ||
981 | */ | ||
982 | ether_addr_copy(ieee80211_get_DA(hdr), da); | ||
983 | ether_addr_copy(ieee80211_get_SA(hdr), sa); | ||
984 | break; | ||
985 | case RX_MSDU_DECAP_ETHERNET2_DIX: | ||
986 | /* strip ethernet header and insert decapped 802.11 | ||
987 | * header, amsdu subframe header and rfc1042 header */ | ||
988 | 939 | ||
989 | len = 0; | 940 | rxd = (void *)msdu->data - sizeof(*rxd); |
990 | len += sizeof(struct rfc1042_hdr); | 941 | hdr = (void *)rxd->rx_hdr_status; |
991 | len += sizeof(struct amsdu_subframe_hdr); | ||
992 | 942 | ||
993 | skb_pull(skb, sizeof(struct ethhdr)); | 943 | is_first = !!(rxd->msdu_end.info0 & |
994 | memcpy(skb_push(skb, len), decap_hdr, len); | 944 | __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); |
995 | memcpy(skb_push(skb, hdr_len), hdr, hdr_len); | 945 | is_last = !!(rxd->msdu_end.info0 & |
996 | break; | 946 | __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); |
997 | case RX_MSDU_DECAP_8023_SNAP_LLC: | 947 | is_amsdu = !(is_first && is_last); |
998 | /* insert decapped 802.11 header making a singly | ||
999 | * A-MSDU */ | ||
1000 | memcpy(skb_push(skb, hdr_len), hdr, hdr_len); | ||
1001 | break; | ||
1002 | } | ||
1003 | 948 | ||
1004 | skb_in = skb; | 949 | rfc1042 = hdr; |
1005 | ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype, fmt, | ||
1006 | false); | ||
1007 | skb = skb->next; | ||
1008 | skb_in->next = NULL; | ||
1009 | 950 | ||
1010 | if (skb) | 951 | if (is_first) { |
1011 | rx_status->flag |= RX_FLAG_AMSDU_MORE; | 952 | hdr_len = ieee80211_hdrlen(hdr->frame_control); |
1012 | else | 953 | crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype); |
1013 | rx_status->flag &= ~RX_FLAG_AMSDU_MORE; | ||
1014 | 954 | ||
1015 | ath10k_process_rx(htt->ar, rx_status, skb_in); | 955 | rfc1042 += round_up(hdr_len, 4) + |
956 | round_up(crypto_len, 4); | ||
1016 | } | 957 | } |
1017 | 958 | ||
1018 | /* FIXME: It might be nice to re-assemble the A-MSDU when there's a | 959 | if (is_amsdu) |
1019 | * monitor interface active for sniffing purposes. */ | 960 | rfc1042 += sizeof(struct amsdu_subframe_hdr); |
961 | |||
962 | return rfc1042; | ||
1020 | } | 963 | } |
1021 | 964 | ||
1022 | static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, | 965 | static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar, |
1023 | struct ieee80211_rx_status *rx_status, | 966 | struct sk_buff *msdu, |
1024 | struct sk_buff *skb) | 967 | struct ieee80211_rx_status *status, |
968 | const u8 first_hdr[64], | ||
969 | enum htt_rx_mpdu_encrypt_type enctype) | ||
1025 | { | 970 | { |
1026 | struct ath10k *ar = htt->ar; | ||
1027 | struct htt_rx_desc *rxd; | ||
1028 | struct ieee80211_hdr *hdr; | 971 | struct ieee80211_hdr *hdr; |
1029 | enum rx_msdu_decap_format fmt; | 972 | struct ethhdr *eth; |
1030 | enum htt_rx_mpdu_encrypt_type enctype; | 973 | size_t hdr_len; |
1031 | int hdr_len; | ||
1032 | void *rfc1042; | 974 | void *rfc1042; |
975 | u8 da[ETH_ALEN]; | ||
976 | u8 sa[ETH_ALEN]; | ||
1033 | 977 | ||
1034 | /* This shouldn't happen. If it does than it may be a FW bug. */ | 978 | /* Delivered decapped frame: |
1035 | if (skb->next) { | 979 | * [eth header] <-- replaced with 802.11 hdr & rfc1042/llc |
1036 | ath10k_warn(ar, "htt rx received chained non A-MSDU frame\n"); | 980 | * [payload] |
1037 | ath10k_htt_rx_free_msdu_chain(skb->next); | 981 | */ |
1038 | skb->next = NULL; | ||
1039 | } | ||
1040 | 982 | ||
1041 | rxd = (void *)skb->data - sizeof(*rxd); | 983 | rfc1042 = ath10k_htt_rx_h_find_rfc1042(ar, msdu, enctype); |
1042 | fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), | 984 | if (WARN_ON_ONCE(!rfc1042)) |
1043 | RX_MSDU_START_INFO1_DECAP_FORMAT); | 985 | return; |
1044 | enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), | 986 | |
1045 | RX_MPDU_START_INFO0_ENCRYPT_TYPE); | 987 | /* pull decapped header and copy SA & DA */ |
1046 | hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; | 988 | eth = (struct ethhdr *)msdu->data; |
989 | ether_addr_copy(da, eth->h_dest); | ||
990 | ether_addr_copy(sa, eth->h_source); | ||
991 | skb_pull(msdu, sizeof(struct ethhdr)); | ||
992 | |||
993 | /* push rfc1042/llc/snap */ | ||
994 | memcpy(skb_push(msdu, sizeof(struct rfc1042_hdr)), rfc1042, | ||
995 | sizeof(struct rfc1042_hdr)); | ||
996 | |||
997 | /* push original 802.11 header */ | ||
998 | hdr = (struct ieee80211_hdr *)first_hdr; | ||
999 | hdr_len = ieee80211_hdrlen(hdr->frame_control); | ||
1000 | memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); | ||
1001 | |||
1002 | /* original 802.11 header has a different DA and in | ||
1003 | * case of 4addr it may also have different SA | ||
1004 | */ | ||
1005 | hdr = (struct ieee80211_hdr *)msdu->data; | ||
1006 | ether_addr_copy(ieee80211_get_DA(hdr), da); | ||
1007 | ether_addr_copy(ieee80211_get_SA(hdr), sa); | ||
1008 | } | ||
1009 | |||
1010 | static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar, | ||
1011 | struct sk_buff *msdu, | ||
1012 | struct ieee80211_rx_status *status, | ||
1013 | const u8 first_hdr[64]) | ||
1014 | { | ||
1015 | struct ieee80211_hdr *hdr; | ||
1016 | size_t hdr_len; | ||
1017 | |||
1018 | /* Delivered decapped frame: | ||
1019 | * [amsdu header] <-- replaced with 802.11 hdr | ||
1020 | * [rfc1042/llc] | ||
1021 | * [payload] | ||
1022 | */ | ||
1023 | |||
1024 | skb_pull(msdu, sizeof(struct amsdu_subframe_hdr)); | ||
1025 | |||
1026 | hdr = (struct ieee80211_hdr *)first_hdr; | ||
1047 | hdr_len = ieee80211_hdrlen(hdr->frame_control); | 1027 | hdr_len = ieee80211_hdrlen(hdr->frame_control); |
1028 | memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); | ||
1029 | } | ||
1048 | 1030 | ||
1049 | skb->ip_summed = ath10k_htt_rx_get_csum_state(skb); | 1031 | static void ath10k_htt_rx_h_undecap(struct ath10k *ar, |
1032 | struct sk_buff *msdu, | ||
1033 | struct ieee80211_rx_status *status, | ||
1034 | u8 first_hdr[64], | ||
1035 | enum htt_rx_mpdu_encrypt_type enctype, | ||
1036 | bool is_decrypted) | ||
1037 | { | ||
1038 | struct htt_rx_desc *rxd; | ||
1039 | enum rx_msdu_decap_format decap; | ||
1040 | struct ieee80211_hdr *hdr; | ||
1041 | |||
1042 | /* First msdu's decapped header: | ||
1043 | * [802.11 header] <-- padded to 4 bytes long | ||
1044 | * [crypto param] <-- padded to 4 bytes long | ||
1045 | * [amsdu header] <-- only if A-MSDU | ||
1046 | * [rfc1042/llc] | ||
1047 | * | ||
1048 | * Other (2nd, 3rd, ..) msdu's decapped header: | ||
1049 | * [amsdu header] <-- only if A-MSDU | ||
1050 | * [rfc1042/llc] | ||
1051 | */ | ||
1050 | 1052 | ||
1051 | switch (fmt) { | 1053 | rxd = (void *)msdu->data - sizeof(*rxd); |
1054 | hdr = (void *)rxd->rx_hdr_status; | ||
1055 | decap = MS(__le32_to_cpu(rxd->msdu_start.info1), | ||
1056 | RX_MSDU_START_INFO1_DECAP_FORMAT); | ||
1057 | |||
1058 | switch (decap) { | ||
1052 | case RX_MSDU_DECAP_RAW: | 1059 | case RX_MSDU_DECAP_RAW: |
1053 | /* remove trailing FCS */ | 1060 | ath10k_htt_rx_h_undecap_raw(ar, msdu, status, enctype, |
1054 | skb_trim(skb, skb->len - FCS_LEN); | 1061 | is_decrypted); |
1055 | break; | 1062 | break; |
1056 | case RX_MSDU_DECAP_NATIVE_WIFI: | 1063 | case RX_MSDU_DECAP_NATIVE_WIFI: |
1057 | /* Pull decapped header */ | 1064 | ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr); |
1058 | hdr = (struct ieee80211_hdr *)skb->data; | ||
1059 | hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); | ||
1060 | skb_pull(skb, hdr_len); | ||
1061 | |||
1062 | /* Push original header */ | ||
1063 | hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; | ||
1064 | hdr_len = ieee80211_hdrlen(hdr->frame_control); | ||
1065 | memcpy(skb_push(skb, hdr_len), hdr, hdr_len); | ||
1066 | break; | 1065 | break; |
1067 | case RX_MSDU_DECAP_ETHERNET2_DIX: | 1066 | case RX_MSDU_DECAP_ETHERNET2_DIX: |
1068 | /* strip ethernet header and insert decapped 802.11 header and | 1067 | ath10k_htt_rx_h_undecap_eth(ar, msdu, status, first_hdr, enctype); |
1069 | * rfc1042 header */ | ||
1070 | |||
1071 | rfc1042 = hdr; | ||
1072 | rfc1042 += roundup(hdr_len, 4); | ||
1073 | rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(ar, | ||
1074 | enctype), 4); | ||
1075 | |||
1076 | skb_pull(skb, sizeof(struct ethhdr)); | ||
1077 | memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)), | ||
1078 | rfc1042, sizeof(struct rfc1042_hdr)); | ||
1079 | memcpy(skb_push(skb, hdr_len), hdr, hdr_len); | ||
1080 | break; | 1068 | break; |
1081 | case RX_MSDU_DECAP_8023_SNAP_LLC: | 1069 | case RX_MSDU_DECAP_8023_SNAP_LLC: |
1082 | /* remove A-MSDU subframe header and insert | 1070 | ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr); |
1083 | * decapped 802.11 header. rfc1042 header is already there */ | ||
1084 | |||
1085 | skb_pull(skb, sizeof(struct amsdu_subframe_hdr)); | ||
1086 | memcpy(skb_push(skb, hdr_len), hdr, hdr_len); | ||
1087 | break; | 1071 | break; |
1088 | } | 1072 | } |
1089 | |||
1090 | ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype, fmt, false); | ||
1091 | |||
1092 | ath10k_process_rx(htt->ar, rx_status, skb); | ||
1093 | } | 1073 | } |
1094 | 1074 | ||
1095 | static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) | 1075 | static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) |
@@ -1123,10 +1103,128 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) | |||
1123 | return CHECKSUM_UNNECESSARY; | 1103 | return CHECKSUM_UNNECESSARY; |
1124 | } | 1104 | } |
1125 | 1105 | ||
1126 | static int ath10k_unchain_msdu(struct sk_buff *msdu_head) | 1106 | static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu) |
1107 | { | ||
1108 | msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu); | ||
1109 | } | ||
1110 | |||
1111 | static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, | ||
1112 | struct sk_buff_head *amsdu, | ||
1113 | struct ieee80211_rx_status *status) | ||
1114 | { | ||
1115 | struct sk_buff *first; | ||
1116 | struct sk_buff *last; | ||
1117 | struct sk_buff *msdu; | ||
1118 | struct htt_rx_desc *rxd; | ||
1119 | struct ieee80211_hdr *hdr; | ||
1120 | enum htt_rx_mpdu_encrypt_type enctype; | ||
1121 | u8 first_hdr[64]; | ||
1122 | u8 *qos; | ||
1123 | size_t hdr_len; | ||
1124 | bool has_fcs_err; | ||
1125 | bool has_crypto_err; | ||
1126 | bool has_tkip_err; | ||
1127 | bool has_peer_idx_invalid; | ||
1128 | bool is_decrypted; | ||
1129 | u32 attention; | ||
1130 | |||
1131 | if (skb_queue_empty(amsdu)) | ||
1132 | return; | ||
1133 | |||
1134 | first = skb_peek(amsdu); | ||
1135 | rxd = (void *)first->data - sizeof(*rxd); | ||
1136 | |||
1137 | enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), | ||
1138 | RX_MPDU_START_INFO0_ENCRYPT_TYPE); | ||
1139 | |||
1140 | /* First MSDU's Rx descriptor in an A-MSDU contains full 802.11 | ||
1141 | * decapped header. It'll be used for undecapping of each MSDU. | ||
1142 | */ | ||
1143 | hdr = (void *)rxd->rx_hdr_status; | ||
1144 | hdr_len = ieee80211_hdrlen(hdr->frame_control); | ||
1145 | memcpy(first_hdr, hdr, hdr_len); | ||
1146 | |||
1147 | /* Each A-MSDU subframe will use the original header as the base and be | ||
1148 | * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl. | ||
1149 | */ | ||
1150 | hdr = (void *)first_hdr; | ||
1151 | qos = ieee80211_get_qos_ctl(hdr); | ||
1152 | qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; | ||
1153 | |||
1154 | /* Some attention flags are valid only in the last MSDU. */ | ||
1155 | last = skb_peek_tail(amsdu); | ||
1156 | rxd = (void *)last->data - sizeof(*rxd); | ||
1157 | attention = __le32_to_cpu(rxd->attention.flags); | ||
1158 | |||
1159 | has_fcs_err = !!(attention & RX_ATTENTION_FLAGS_FCS_ERR); | ||
1160 | has_crypto_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR); | ||
1161 | has_tkip_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR); | ||
1162 | has_peer_idx_invalid = !!(attention & RX_ATTENTION_FLAGS_PEER_IDX_INVALID); | ||
1163 | |||
1164 | /* Note: If hardware captures an encrypted frame that it can't decrypt, | ||
1165 | * e.g. due to fcs error, missing peer or invalid key data it will | ||
1166 | * report the frame as raw. | ||
1167 | */ | ||
1168 | is_decrypted = (enctype != HTT_RX_MPDU_ENCRYPT_NONE && | ||
1169 | !has_fcs_err && | ||
1170 | !has_crypto_err && | ||
1171 | !has_peer_idx_invalid); | ||
1172 | |||
1173 | /* Clear per-MPDU flags while leaving per-PPDU flags intact. */ | ||
1174 | status->flag &= ~(RX_FLAG_FAILED_FCS_CRC | | ||
1175 | RX_FLAG_MMIC_ERROR | | ||
1176 | RX_FLAG_DECRYPTED | | ||
1177 | RX_FLAG_IV_STRIPPED | | ||
1178 | RX_FLAG_MMIC_STRIPPED); | ||
1179 | |||
1180 | if (has_fcs_err) | ||
1181 | status->flag |= RX_FLAG_FAILED_FCS_CRC; | ||
1182 | |||
1183 | if (has_tkip_err) | ||
1184 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
1185 | |||
1186 | if (is_decrypted) | ||
1187 | status->flag |= RX_FLAG_DECRYPTED | | ||
1188 | RX_FLAG_IV_STRIPPED | | ||
1189 | RX_FLAG_MMIC_STRIPPED; | ||
1190 | |||
1191 | skb_queue_walk(amsdu, msdu) { | ||
1192 | ath10k_htt_rx_h_csum_offload(msdu); | ||
1193 | ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype, | ||
1194 | is_decrypted); | ||
1195 | |||
1196 | /* Undecapping involves copying the original 802.11 header back | ||
1197 | * to sk_buff. If frame is protected and hardware has decrypted | ||
1198 | * it then remove the protected bit. | ||
1199 | */ | ||
1200 | if (!is_decrypted) | ||
1201 | continue; | ||
1202 | |||
1203 | hdr = (void *)msdu->data; | ||
1204 | hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
1205 | } | ||
1206 | } | ||
1207 | |||
1208 | static void ath10k_htt_rx_h_deliver(struct ath10k *ar, | ||
1209 | struct sk_buff_head *amsdu, | ||
1210 | struct ieee80211_rx_status *status) | ||
1127 | { | 1211 | { |
1128 | struct sk_buff *next = msdu_head->next; | 1212 | struct sk_buff *msdu; |
1129 | struct sk_buff *to_free = next; | 1213 | |
1214 | while ((msdu = __skb_dequeue(amsdu))) { | ||
1215 | /* Setup per-MSDU flags */ | ||
1216 | if (skb_queue_empty(amsdu)) | ||
1217 | status->flag &= ~RX_FLAG_AMSDU_MORE; | ||
1218 | else | ||
1219 | status->flag |= RX_FLAG_AMSDU_MORE; | ||
1220 | |||
1221 | ath10k_process_rx(ar, status, msdu); | ||
1222 | } | ||
1223 | } | ||
1224 | |||
1225 | static int ath10k_unchain_msdu(struct sk_buff_head *amsdu) | ||
1226 | { | ||
1227 | struct sk_buff *skb, *first; | ||
1130 | int space; | 1228 | int space; |
1131 | int total_len = 0; | 1229 | int total_len = 0; |
1132 | 1230 | ||
@@ -1137,113 +1235,142 @@ static int ath10k_unchain_msdu(struct sk_buff *msdu_head) | |||
1137 | * skb? | 1235 | * skb? |
1138 | */ | 1236 | */ |
1139 | 1237 | ||
1140 | msdu_head->next = NULL; | 1238 | first = __skb_dequeue(amsdu); |
1141 | 1239 | ||
1142 | /* Allocate total length all at once. */ | 1240 | /* Allocate total length all at once. */ |
1143 | while (next) { | 1241 | skb_queue_walk(amsdu, skb) |
1144 | total_len += next->len; | 1242 | total_len += skb->len; |
1145 | next = next->next; | ||
1146 | } | ||
1147 | 1243 | ||
1148 | space = total_len - skb_tailroom(msdu_head); | 1244 | space = total_len - skb_tailroom(first); |
1149 | if ((space > 0) && | 1245 | if ((space > 0) && |
1150 | (pskb_expand_head(msdu_head, 0, space, GFP_ATOMIC) < 0)) { | 1246 | (pskb_expand_head(first, 0, space, GFP_ATOMIC) < 0)) { |
1151 | /* TODO: bump some rx-oom error stat */ | 1247 | /* TODO: bump some rx-oom error stat */ |
1152 | /* put it back together so we can free the | 1248 | /* put it back together so we can free the |
1153 | * whole list at once. | 1249 | * whole list at once. |
1154 | */ | 1250 | */ |
1155 | msdu_head->next = to_free; | 1251 | __skb_queue_head(amsdu, first); |
1156 | return -1; | 1252 | return -1; |
1157 | } | 1253 | } |
1158 | 1254 | ||
1159 | /* Walk list again, copying contents into | 1255 | /* Walk list again, copying contents into |
1160 | * msdu_head | 1256 | * msdu_head |
1161 | */ | 1257 | */ |
1162 | next = to_free; | 1258 | while ((skb = __skb_dequeue(amsdu))) { |
1163 | while (next) { | 1259 | skb_copy_from_linear_data(skb, skb_put(first, skb->len), |
1164 | skb_copy_from_linear_data(next, skb_put(msdu_head, next->len), | 1260 | skb->len); |
1165 | next->len); | 1261 | dev_kfree_skb_any(skb); |
1166 | next = next->next; | ||
1167 | } | 1262 | } |
1168 | 1263 | ||
1169 | /* If here, we have consolidated skb. Free the | 1264 | __skb_queue_head(amsdu, first); |
1170 | * fragments and pass the main skb on up the | ||
1171 | * stack. | ||
1172 | */ | ||
1173 | ath10k_htt_rx_free_msdu_chain(to_free); | ||
1174 | return 0; | 1265 | return 0; |
1175 | } | 1266 | } |
1176 | 1267 | ||
1177 | static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, | 1268 | static void ath10k_htt_rx_h_unchain(struct ath10k *ar, |
1178 | struct sk_buff *head, | 1269 | struct sk_buff_head *amsdu, |
1179 | enum htt_rx_mpdu_status status, | 1270 | bool chained) |
1180 | bool channel_set, | ||
1181 | u32 attention) | ||
1182 | { | 1271 | { |
1183 | struct ath10k *ar = htt->ar; | 1272 | struct sk_buff *first; |
1273 | struct htt_rx_desc *rxd; | ||
1274 | enum rx_msdu_decap_format decap; | ||
1184 | 1275 | ||
1185 | if (head->len == 0) { | 1276 | first = skb_peek(amsdu); |
1186 | ath10k_dbg(ar, ATH10K_DBG_HTT, | 1277 | rxd = (void *)first->data - sizeof(*rxd); |
1187 | "htt rx dropping due to zero-len\n"); | 1278 | decap = MS(__le32_to_cpu(rxd->msdu_start.info1), |
1188 | return false; | 1279 | RX_MSDU_START_INFO1_DECAP_FORMAT); |
1189 | } | ||
1190 | 1280 | ||
1191 | if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) { | 1281 | if (!chained) |
1192 | ath10k_dbg(ar, ATH10K_DBG_HTT, | 1282 | return; |
1193 | "htt rx dropping due to decrypt-err\n"); | ||
1194 | return false; | ||
1195 | } | ||
1196 | 1283 | ||
1197 | if (!channel_set) { | 1284 | /* FIXME: Current unchaining logic can only handle simple case of raw |
1198 | ath10k_warn(ar, "no channel configured; ignoring frame!\n"); | 1285 | * msdu chaining. If decapping is other than raw the chaining may be |
1199 | return false; | 1286 | * more complex and this isn't handled by the current code. Don't even |
1287 | * try re-constructing such frames - it'll be pretty much garbage. | ||
1288 | */ | ||
1289 | if (decap != RX_MSDU_DECAP_RAW || | ||
1290 | skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) { | ||
1291 | __skb_queue_purge(amsdu); | ||
1292 | return; | ||
1200 | } | 1293 | } |
1201 | 1294 | ||
1202 | /* Skip mgmt frames while we handle this in WMI */ | 1295 | ath10k_unchain_msdu(amsdu); |
1203 | if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL || | 1296 | } |
1204 | attention & RX_ATTENTION_FLAGS_MGMT_TYPE) { | 1297 | |
1205 | ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); | 1298 | static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, |
1299 | struct sk_buff_head *amsdu, | ||
1300 | struct ieee80211_rx_status *rx_status) | ||
1301 | { | ||
1302 | struct sk_buff *msdu; | ||
1303 | struct htt_rx_desc *rxd; | ||
1304 | bool is_mgmt; | ||
1305 | bool has_fcs_err; | ||
1306 | |||
1307 | msdu = skb_peek(amsdu); | ||
1308 | rxd = (void *)msdu->data - sizeof(*rxd); | ||
1309 | |||
1310 | /* FIXME: It might be a good idea to do some fuzzy-testing to drop | ||
1311 | * invalid/dangerous frames. | ||
1312 | */ | ||
1313 | |||
1314 | if (!rx_status->freq) { | ||
1315 | ath10k_warn(ar, "no channel configured; ignoring frame(s)!\n"); | ||
1206 | return false; | 1316 | return false; |
1207 | } | 1317 | } |
1208 | 1318 | ||
1209 | if (status != HTT_RX_IND_MPDU_STATUS_OK && | 1319 | is_mgmt = !!(rxd->attention.flags & |
1210 | status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && | 1320 | __cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE)); |
1211 | status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER && | 1321 | has_fcs_err = !!(rxd->attention.flags & |
1212 | !htt->ar->monitor_started) { | 1322 | __cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR)); |
1213 | ath10k_dbg(ar, ATH10K_DBG_HTT, | 1323 | |
1214 | "htt rx ignoring frame w/ status %d\n", | 1324 | /* Management frames are handled via WMI events. The pros of such |
1215 | status); | 1325 | * approach is that channel is explicitly provided in WMI events |
1326 | * whereas HTT doesn't provide channel information for Rxed frames. | ||
1327 | * | ||
1328 | * However some firmware revisions don't report corrupted frames via | ||
1329 | * WMI so don't drop them. | ||
1330 | */ | ||
1331 | if (is_mgmt && !has_fcs_err) { | ||
1332 | ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); | ||
1216 | return false; | 1333 | return false; |
1217 | } | 1334 | } |
1218 | 1335 | ||
1219 | if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { | 1336 | if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) { |
1220 | ath10k_dbg(ar, ATH10K_DBG_HTT, | 1337 | ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx cac running\n"); |
1221 | "htt rx CAC running\n"); | ||
1222 | return false; | 1338 | return false; |
1223 | } | 1339 | } |
1224 | 1340 | ||
1225 | return true; | 1341 | return true; |
1226 | } | 1342 | } |
1227 | 1343 | ||
1344 | static void ath10k_htt_rx_h_filter(struct ath10k *ar, | ||
1345 | struct sk_buff_head *amsdu, | ||
1346 | struct ieee80211_rx_status *rx_status) | ||
1347 | { | ||
1348 | if (skb_queue_empty(amsdu)) | ||
1349 | return; | ||
1350 | |||
1351 | if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status)) | ||
1352 | return; | ||
1353 | |||
1354 | __skb_queue_purge(amsdu); | ||
1355 | } | ||
1356 | |||
1228 | static void ath10k_htt_rx_handler(struct ath10k_htt *htt, | 1357 | static void ath10k_htt_rx_handler(struct ath10k_htt *htt, |
1229 | struct htt_rx_indication *rx) | 1358 | struct htt_rx_indication *rx) |
1230 | { | 1359 | { |
1231 | struct ath10k *ar = htt->ar; | 1360 | struct ath10k *ar = htt->ar; |
1232 | struct ieee80211_rx_status *rx_status = &htt->rx_status; | 1361 | struct ieee80211_rx_status *rx_status = &htt->rx_status; |
1233 | struct htt_rx_indication_mpdu_range *mpdu_ranges; | 1362 | struct htt_rx_indication_mpdu_range *mpdu_ranges; |
1234 | struct htt_rx_desc *rxd; | 1363 | struct sk_buff_head amsdu; |
1235 | enum htt_rx_mpdu_status status; | ||
1236 | struct ieee80211_hdr *hdr; | ||
1237 | int num_mpdu_ranges; | 1364 | int num_mpdu_ranges; |
1238 | u32 attention; | ||
1239 | int fw_desc_len; | 1365 | int fw_desc_len; |
1240 | u8 *fw_desc; | 1366 | u8 *fw_desc; |
1241 | bool channel_set; | 1367 | int i, ret, mpdu_count = 0; |
1242 | int i, j; | ||
1243 | int ret; | ||
1244 | 1368 | ||
1245 | lockdep_assert_held(&htt->rx_ring.lock); | 1369 | lockdep_assert_held(&htt->rx_ring.lock); |
1246 | 1370 | ||
1371 | if (htt->rx_confused) | ||
1372 | return; | ||
1373 | |||
1247 | fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes); | 1374 | fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes); |
1248 | fw_desc = (u8 *)&rx->fw_desc; | 1375 | fw_desc = (u8 *)&rx->fw_desc; |
1249 | 1376 | ||
@@ -1251,92 +1378,33 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, | |||
1251 | HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); | 1378 | HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); |
1252 | mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx); | 1379 | mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx); |
1253 | 1380 | ||
1254 | /* Fill this once, while this is per-ppdu */ | ||
1255 | if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) { | ||
1256 | memset(rx_status, 0, sizeof(*rx_status)); | ||
1257 | rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR + | ||
1258 | rx->ppdu.combined_rssi; | ||
1259 | } | ||
1260 | |||
1261 | if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) { | ||
1262 | /* TSF available only in 32-bit */ | ||
1263 | rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff; | ||
1264 | rx_status->flag |= RX_FLAG_MACTIME_END; | ||
1265 | } | ||
1266 | |||
1267 | channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status); | ||
1268 | |||
1269 | if (channel_set) { | ||
1270 | ath10k_htt_rx_h_rates(htt->ar, rx_status->band, | ||
1271 | rx->ppdu.info0, | ||
1272 | __le32_to_cpu(rx->ppdu.info1), | ||
1273 | __le32_to_cpu(rx->ppdu.info2), | ||
1274 | rx_status); | ||
1275 | } | ||
1276 | |||
1277 | ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", | 1381 | ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", |
1278 | rx, sizeof(*rx) + | 1382 | rx, sizeof(*rx) + |
1279 | (sizeof(struct htt_rx_indication_mpdu_range) * | 1383 | (sizeof(struct htt_rx_indication_mpdu_range) * |
1280 | num_mpdu_ranges)); | 1384 | num_mpdu_ranges)); |
1281 | 1385 | ||
1282 | for (i = 0; i < num_mpdu_ranges; i++) { | 1386 | for (i = 0; i < num_mpdu_ranges; i++) |
1283 | status = mpdu_ranges[i].mpdu_range_status; | 1387 | mpdu_count += mpdu_ranges[i].mpdu_count; |
1284 | 1388 | ||
1285 | for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { | 1389 | while (mpdu_count--) { |
1286 | struct sk_buff *msdu_head, *msdu_tail; | 1390 | __skb_queue_head_init(&amsdu); |
1287 | 1391 | ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, | |
1288 | attention = 0; | 1392 | &fw_desc_len, &amsdu); |
1289 | msdu_head = NULL; | 1393 | if (ret < 0) { |
1290 | msdu_tail = NULL; | 1394 | ath10k_warn(ar, "rx ring became corrupted: %d\n", ret); |
1291 | ret = ath10k_htt_rx_amsdu_pop(htt, | 1395 | __skb_queue_purge(&amsdu); |
1292 | &fw_desc, | 1396 | /* FIXME: It's probably a good idea to reboot the |
1293 | &fw_desc_len, | 1397 | * device instead of leaving it inoperable. |
1294 | &msdu_head, | 1398 | */ |
1295 | &msdu_tail, | 1399 | htt->rx_confused = true; |
1296 | &attention); | 1400 | break; |
1297 | |||
1298 | if (ret < 0) { | ||
1299 | ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n", | ||
1300 | ret); | ||
1301 | ath10k_htt_rx_free_msdu_chain(msdu_head); | ||
1302 | continue; | ||
1303 | } | ||
1304 | |||
1305 | rxd = container_of((void *)msdu_head->data, | ||
1306 | struct htt_rx_desc, | ||
1307 | msdu_payload); | ||
1308 | |||
1309 | if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, | ||
1310 | status, | ||
1311 | channel_set, | ||
1312 | attention)) { | ||
1313 | ath10k_htt_rx_free_msdu_chain(msdu_head); | ||
1314 | continue; | ||
1315 | } | ||
1316 | |||
1317 | if (ret > 0 && | ||
1318 | ath10k_unchain_msdu(msdu_head) < 0) { | ||
1319 | ath10k_htt_rx_free_msdu_chain(msdu_head); | ||
1320 | continue; | ||
1321 | } | ||
1322 | |||
1323 | if (attention & RX_ATTENTION_FLAGS_FCS_ERR) | ||
1324 | rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; | ||
1325 | else | ||
1326 | rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC; | ||
1327 | |||
1328 | if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR) | ||
1329 | rx_status->flag |= RX_FLAG_MMIC_ERROR; | ||
1330 | else | ||
1331 | rx_status->flag &= ~RX_FLAG_MMIC_ERROR; | ||
1332 | |||
1333 | hdr = ath10k_htt_rx_skb_get_hdr(msdu_head); | ||
1334 | |||
1335 | if (ath10k_htt_rx_hdr_is_amsdu(hdr)) | ||
1336 | ath10k_htt_rx_amsdu(htt, rx_status, msdu_head); | ||
1337 | else | ||
1338 | ath10k_htt_rx_msdu(htt, rx_status, msdu_head); | ||
1339 | } | 1401 | } |
1402 | |||
1403 | ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status); | ||
1404 | ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0); | ||
1405 | ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); | ||
1406 | ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); | ||
1407 | ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); | ||
1340 | } | 1408 | } |
1341 | 1409 | ||
1342 | tasklet_schedule(&htt->rx_replenish_task); | 1410 | tasklet_schedule(&htt->rx_replenish_task); |
@@ -1346,108 +1414,44 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, | |||
1346 | struct htt_rx_fragment_indication *frag) | 1414 | struct htt_rx_fragment_indication *frag) |
1347 | { | 1415 | { |
1348 | struct ath10k *ar = htt->ar; | 1416 | struct ath10k *ar = htt->ar; |
1349 | struct sk_buff *msdu_head, *msdu_tail; | ||
1350 | enum htt_rx_mpdu_encrypt_type enctype; | ||
1351 | struct htt_rx_desc *rxd; | ||
1352 | enum rx_msdu_decap_format fmt; | ||
1353 | struct ieee80211_rx_status *rx_status = &htt->rx_status; | 1417 | struct ieee80211_rx_status *rx_status = &htt->rx_status; |
1354 | struct ieee80211_hdr *hdr; | 1418 | struct sk_buff_head amsdu; |
1355 | int ret; | 1419 | int ret; |
1356 | bool tkip_mic_err; | ||
1357 | bool decrypt_err; | ||
1358 | u8 *fw_desc; | 1420 | u8 *fw_desc; |
1359 | int fw_desc_len, hdrlen, paramlen; | 1421 | int fw_desc_len; |
1360 | int trim; | ||
1361 | u32 attention = 0; | ||
1362 | 1422 | ||
1363 | fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes); | 1423 | fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes); |
1364 | fw_desc = (u8 *)frag->fw_msdu_rx_desc; | 1424 | fw_desc = (u8 *)frag->fw_msdu_rx_desc; |
1365 | 1425 | ||
1366 | msdu_head = NULL; | 1426 | __skb_queue_head_init(&amsdu); |
1367 | msdu_tail = NULL; | ||
1368 | 1427 | ||
1369 | spin_lock_bh(&htt->rx_ring.lock); | 1428 | spin_lock_bh(&htt->rx_ring.lock); |
1370 | ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, | 1429 | ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, |
1371 | &msdu_head, &msdu_tail, | 1430 | &amsdu); |
1372 | &attention); | ||
1373 | spin_unlock_bh(&htt->rx_ring.lock); | 1431 | spin_unlock_bh(&htt->rx_ring.lock); |
1374 | 1432 | ||
1433 | tasklet_schedule(&htt->rx_replenish_task); | ||
1434 | |||
1375 | ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); | 1435 | ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); |
1376 | 1436 | ||
1377 | if (ret) { | 1437 | if (ret) { |
1378 | ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n", | 1438 | ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n", |
1379 | ret); | 1439 | ret); |
1380 | ath10k_htt_rx_free_msdu_chain(msdu_head); | 1440 | __skb_queue_purge(&amsdu); |
1381 | return; | 1441 | return; |
1382 | } | 1442 | } |
1383 | 1443 | ||
1384 | /* FIXME: implement signal strength */ | 1444 | if (skb_queue_len(&amsdu) != 1) { |
1385 | rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; | 1445 | ath10k_warn(ar, "failed to pop frag amsdu: too many msdus\n"); |
1386 | 1446 | __skb_queue_purge(&amsdu); | |
1387 | hdr = (struct ieee80211_hdr *)msdu_head->data; | 1447 | return; |
1388 | rxd = (void *)msdu_head->data - sizeof(*rxd); | ||
1389 | tkip_mic_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR); | ||
1390 | decrypt_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR); | ||
1391 | fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), | ||
1392 | RX_MSDU_START_INFO1_DECAP_FORMAT); | ||
1393 | |||
1394 | if (fmt != RX_MSDU_DECAP_RAW) { | ||
1395 | ath10k_warn(ar, "we dont support non-raw fragmented rx yet\n"); | ||
1396 | dev_kfree_skb_any(msdu_head); | ||
1397 | goto end; | ||
1398 | } | ||
1399 | |||
1400 | enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), | ||
1401 | RX_MPDU_START_INFO0_ENCRYPT_TYPE); | ||
1402 | ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype, fmt, | ||
1403 | true); | ||
1404 | msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head); | ||
1405 | |||
1406 | if (tkip_mic_err) | ||
1407 | ath10k_warn(ar, "tkip mic error\n"); | ||
1408 | |||
1409 | if (decrypt_err) { | ||
1410 | ath10k_warn(ar, "decryption err in fragmented rx\n"); | ||
1411 | dev_kfree_skb_any(msdu_head); | ||
1412 | goto end; | ||
1413 | } | ||
1414 | |||
1415 | if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) { | ||
1416 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
1417 | paramlen = ath10k_htt_rx_crypto_param_len(ar, enctype); | ||
1418 | |||
1419 | /* It is more efficient to move the header than the payload */ | ||
1420 | memmove((void *)msdu_head->data + paramlen, | ||
1421 | (void *)msdu_head->data, | ||
1422 | hdrlen); | ||
1423 | skb_pull(msdu_head, paramlen); | ||
1424 | hdr = (struct ieee80211_hdr *)msdu_head->data; | ||
1425 | } | ||
1426 | |||
1427 | /* remove trailing FCS */ | ||
1428 | trim = 4; | ||
1429 | |||
1430 | /* remove crypto trailer */ | ||
1431 | trim += ath10k_htt_rx_crypto_tail_len(ar, enctype); | ||
1432 | |||
1433 | /* last fragment of TKIP frags has MIC */ | ||
1434 | if (!ieee80211_has_morefrags(hdr->frame_control) && | ||
1435 | enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) | ||
1436 | trim += 8; | ||
1437 | |||
1438 | if (trim > msdu_head->len) { | ||
1439 | ath10k_warn(ar, "htt rx fragment: trailer longer than the frame itself? drop\n"); | ||
1440 | dev_kfree_skb_any(msdu_head); | ||
1441 | goto end; | ||
1442 | } | 1448 | } |
1443 | 1449 | ||
1444 | skb_trim(msdu_head, msdu_head->len - trim); | 1450 | ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status); |
1445 | 1451 | ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); | |
1446 | ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ", | 1452 | ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); |
1447 | msdu_head->data, msdu_head->len); | 1453 | ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); |
1448 | ath10k_process_rx(htt->ar, rx_status, msdu_head); | ||
1449 | 1454 | ||
1450 | end: | ||
1451 | if (fw_desc_len > 0) { | 1455 | if (fw_desc_len > 0) { |
1452 | ath10k_dbg(ar, ATH10K_DBG_HTT, | 1456 | ath10k_dbg(ar, ATH10K_DBG_HTT, |
1453 | "expecting more fragmented rx in one indication %d\n", | 1457 | "expecting more fragmented rx in one indication %d\n", |
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index b0df470250a2..4bc51d8a14a3 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c | |||
@@ -92,7 +92,6 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) | |||
92 | struct ath10k *ar = htt->ar; | 92 | struct ath10k *ar = htt->ar; |
93 | 93 | ||
94 | spin_lock_init(&htt->tx_lock); | 94 | spin_lock_init(&htt->tx_lock); |
95 | init_waitqueue_head(&htt->empty_tx_wq); | ||
96 | 95 | ||
97 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features)) | 96 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features)) |
98 | htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; | 97 | htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; |
@@ -555,16 +554,18 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
555 | skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); | 554 | skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); |
556 | skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); | 555 | skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); |
557 | skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); | 556 | skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); |
558 | skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); | 557 | skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID); |
558 | skb_cb->htt.txbuf->cmd_tx.freq = __cpu_to_le16(skb_cb->htt.freq); | ||
559 | 559 | ||
560 | trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid); | 560 | trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid); |
561 | ath10k_dbg(ar, ATH10K_DBG_HTT, | 561 | ath10k_dbg(ar, ATH10K_DBG_HTT, |
562 | "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n", | 562 | "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu freq %hu\n", |
563 | flags0, flags1, msdu->len, msdu_id, frags_paddr, | 563 | flags0, flags1, msdu->len, msdu_id, frags_paddr, |
564 | (u32)skb_cb->paddr, vdev_id, tid); | 564 | (u32)skb_cb->paddr, vdev_id, tid, skb_cb->htt.freq); |
565 | ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", | 565 | ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", |
566 | msdu->data, msdu->len); | 566 | msdu->data, msdu->len); |
567 | trace_ath10k_htt_tx_msdu(ar, msdu->data, msdu->len); | 567 | trace_ath10k_tx_hdr(ar, msdu->data, msdu->len); |
568 | trace_ath10k_tx_payload(ar, msdu->data, msdu->len); | ||
568 | 569 | ||
569 | sg_items[0].transfer_id = 0; | 570 | sg_items[0].transfer_id = 0; |
570 | sg_items[0].transfer_context = NULL; | 571 | sg_items[0].transfer_context = NULL; |
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 392c2501d0a1..dfedfd0e0f34 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h | |||
@@ -97,11 +97,13 @@ struct ath10k_pktlog_hdr { | |||
97 | #define TARGET_DMA_BURST_SIZE 0 | 97 | #define TARGET_DMA_BURST_SIZE 0 |
98 | #define TARGET_MAC_AGGR_DELIM 0 | 98 | #define TARGET_MAC_AGGR_DELIM 0 |
99 | #define TARGET_AST_SKID_LIMIT 16 | 99 | #define TARGET_AST_SKID_LIMIT 16 |
100 | #define TARGET_NUM_PEERS 16 | 100 | #define TARGET_NUM_STATIONS 16 |
101 | #define TARGET_NUM_PEERS ((TARGET_NUM_STATIONS) + \ | ||
102 | (TARGET_NUM_VDEVS)) | ||
101 | #define TARGET_NUM_OFFLOAD_PEERS 0 | 103 | #define TARGET_NUM_OFFLOAD_PEERS 0 |
102 | #define TARGET_NUM_OFFLOAD_REORDER_BUFS 0 | 104 | #define TARGET_NUM_OFFLOAD_REORDER_BUFS 0 |
103 | #define TARGET_NUM_PEER_KEYS 2 | 105 | #define TARGET_NUM_PEER_KEYS 2 |
104 | #define TARGET_NUM_TIDS (2 * ((TARGET_NUM_PEERS) + (TARGET_NUM_VDEVS))) | 106 | #define TARGET_NUM_TIDS ((TARGET_NUM_PEERS) * 2) |
105 | #define TARGET_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) | 107 | #define TARGET_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) |
106 | #define TARGET_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) | 108 | #define TARGET_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) |
107 | #define TARGET_RX_TIMEOUT_LO_PRI 100 | 109 | #define TARGET_RX_TIMEOUT_LO_PRI 100 |
@@ -132,12 +134,15 @@ struct ath10k_pktlog_hdr { | |||
132 | #define TARGET_10X_DMA_BURST_SIZE 0 | 134 | #define TARGET_10X_DMA_BURST_SIZE 0 |
133 | #define TARGET_10X_MAC_AGGR_DELIM 0 | 135 | #define TARGET_10X_MAC_AGGR_DELIM 0 |
134 | #define TARGET_10X_AST_SKID_LIMIT 16 | 136 | #define TARGET_10X_AST_SKID_LIMIT 16 |
135 | #define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS)) | 137 | #define TARGET_10X_NUM_STATIONS 128 |
136 | #define TARGET_10X_NUM_PEERS_MAX 128 | 138 | #define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \ |
139 | (TARGET_10X_NUM_VDEVS)) | ||
137 | #define TARGET_10X_NUM_OFFLOAD_PEERS 0 | 140 | #define TARGET_10X_NUM_OFFLOAD_PEERS 0 |
138 | #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0 | 141 | #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0 |
139 | #define TARGET_10X_NUM_PEER_KEYS 2 | 142 | #define TARGET_10X_NUM_PEER_KEYS 2 |
140 | #define TARGET_10X_NUM_TIDS 256 | 143 | #define TARGET_10X_NUM_TIDS_MAX 256 |
144 | #define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \ | ||
145 | (TARGET_10X_NUM_PEERS) * 2) | ||
141 | #define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) | 146 | #define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) |
142 | #define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) | 147 | #define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) |
143 | #define TARGET_10X_RX_TIMEOUT_LO_PRI 100 | 148 | #define TARGET_10X_RX_TIMEOUT_LO_PRI 100 |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index f6d2fd0887d3..c4005670cba2 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -136,7 +136,9 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, | |||
136 | if (ret) | 136 | if (ret) |
137 | return ret; | 137 | return ret; |
138 | 138 | ||
139 | spin_lock_bh(&ar->data_lock); | ||
139 | peer->keys[i] = arvif->wep_keys[i]; | 140 | peer->keys[i] = arvif->wep_keys[i]; |
141 | spin_unlock_bh(&ar->data_lock); | ||
140 | } | 142 | } |
141 | 143 | ||
142 | return 0; | 144 | return 0; |
@@ -173,12 +175,39 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, | |||
173 | ath10k_warn(ar, "failed to remove peer wep key %d: %d\n", | 175 | ath10k_warn(ar, "failed to remove peer wep key %d: %d\n", |
174 | i, ret); | 176 | i, ret); |
175 | 177 | ||
178 | spin_lock_bh(&ar->data_lock); | ||
176 | peer->keys[i] = NULL; | 179 | peer->keys[i] = NULL; |
180 | spin_unlock_bh(&ar->data_lock); | ||
177 | } | 181 | } |
178 | 182 | ||
179 | return first_errno; | 183 | return first_errno; |
180 | } | 184 | } |
181 | 185 | ||
186 | bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr, | ||
187 | u8 keyidx) | ||
188 | { | ||
189 | struct ath10k_peer *peer; | ||
190 | int i; | ||
191 | |||
192 | lockdep_assert_held(&ar->data_lock); | ||
193 | |||
194 | /* We don't know which vdev this peer belongs to, | ||
195 | * since WMI doesn't give us that information. | ||
196 | * | ||
197 | * FIXME: multi-bss needs to be handled. | ||
198 | */ | ||
199 | peer = ath10k_peer_find(ar, 0, addr); | ||
200 | if (!peer) | ||
201 | return false; | ||
202 | |||
203 | for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { | ||
204 | if (peer->keys[i] && peer->keys[i]->keyidx == keyidx) | ||
205 | return true; | ||
206 | } | ||
207 | |||
208 | return false; | ||
209 | } | ||
210 | |||
182 | static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, | 211 | static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, |
183 | struct ieee80211_key_conf *key) | 212 | struct ieee80211_key_conf *key) |
184 | { | 213 | { |
@@ -326,6 +355,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) | |||
326 | 355 | ||
327 | lockdep_assert_held(&ar->conf_mutex); | 356 | lockdep_assert_held(&ar->conf_mutex); |
328 | 357 | ||
358 | if (ar->num_peers >= ar->max_num_peers) | ||
359 | return -ENOBUFS; | ||
360 | |||
329 | ret = ath10k_wmi_peer_create(ar, vdev_id, addr); | 361 | ret = ath10k_wmi_peer_create(ar, vdev_id, addr); |
330 | if (ret) { | 362 | if (ret) { |
331 | ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n", | 363 | ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n", |
@@ -339,9 +371,8 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) | |||
339 | addr, vdev_id, ret); | 371 | addr, vdev_id, ret); |
340 | return ret; | 372 | return ret; |
341 | } | 373 | } |
342 | spin_lock_bh(&ar->data_lock); | 374 | |
343 | ar->num_peers++; | 375 | ar->num_peers++; |
344 | spin_unlock_bh(&ar->data_lock); | ||
345 | 376 | ||
346 | return 0; | 377 | return 0; |
347 | } | 378 | } |
@@ -391,15 +422,11 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) | |||
391 | return 0; | 422 | return 0; |
392 | } | 423 | } |
393 | 424 | ||
394 | static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) | 425 | static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) |
395 | { | 426 | { |
396 | struct ath10k *ar = arvif->ar; | 427 | struct ath10k *ar = arvif->ar; |
397 | u32 vdev_param; | 428 | u32 vdev_param; |
398 | 429 | ||
399 | if (value != 0xFFFFFFFF) | ||
400 | value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold, | ||
401 | ATH10K_RTS_MAX); | ||
402 | |||
403 | vdev_param = ar->wmi.vdev_param->rts_threshold; | 430 | vdev_param = ar->wmi.vdev_param->rts_threshold; |
404 | return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); | 431 | return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); |
405 | } | 432 | } |
@@ -432,9 +459,7 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) | |||
432 | if (ret) | 459 | if (ret) |
433 | return ret; | 460 | return ret; |
434 | 461 | ||
435 | spin_lock_bh(&ar->data_lock); | ||
436 | ar->num_peers--; | 462 | ar->num_peers--; |
437 | spin_unlock_bh(&ar->data_lock); | ||
438 | 463 | ||
439 | return 0; | 464 | return 0; |
440 | } | 465 | } |
@@ -471,8 +496,10 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar) | |||
471 | list_del(&peer->list); | 496 | list_del(&peer->list); |
472 | kfree(peer); | 497 | kfree(peer); |
473 | } | 498 | } |
474 | ar->num_peers = 0; | ||
475 | spin_unlock_bh(&ar->data_lock); | 499 | spin_unlock_bh(&ar->data_lock); |
500 | |||
501 | ar->num_peers = 0; | ||
502 | ar->num_stations = 0; | ||
476 | } | 503 | } |
477 | 504 | ||
478 | /************************/ | 505 | /************************/ |
@@ -519,6 +546,9 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) | |||
519 | 546 | ||
520 | lockdep_assert_held(&ar->conf_mutex); | 547 | lockdep_assert_held(&ar->conf_mutex); |
521 | 548 | ||
549 | if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) | ||
550 | return -ESHUTDOWN; | ||
551 | |||
522 | ret = wait_for_completion_timeout(&ar->vdev_setup_done, | 552 | ret = wait_for_completion_timeout(&ar->vdev_setup_done, |
523 | ATH10K_VDEV_SETUP_TIMEOUT_HZ); | 553 | ATH10K_VDEV_SETUP_TIMEOUT_HZ); |
524 | if (ret == 0) | 554 | if (ret == 0) |
@@ -551,6 +581,8 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) | |||
551 | arg.channel.max_reg_power = channel->max_reg_power * 2; | 581 | arg.channel.max_reg_power = channel->max_reg_power * 2; |
552 | arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; | 582 | arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; |
553 | 583 | ||
584 | reinit_completion(&ar->vdev_setup_done); | ||
585 | |||
554 | ret = ath10k_wmi_vdev_start(ar, &arg); | 586 | ret = ath10k_wmi_vdev_start(ar, &arg); |
555 | if (ret) { | 587 | if (ret) { |
556 | ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n", | 588 | ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n", |
@@ -598,6 +630,8 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar) | |||
598 | ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n", | 630 | ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n", |
599 | ar->monitor_vdev_id, ret); | 631 | ar->monitor_vdev_id, ret); |
600 | 632 | ||
633 | reinit_completion(&ar->vdev_setup_done); | ||
634 | |||
601 | ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); | 635 | ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); |
602 | if (ret) | 636 | if (ret) |
603 | ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n", | 637 | ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n", |
@@ -1990,6 +2024,18 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, | |||
1990 | } | 2024 | } |
1991 | } | 2025 | } |
1992 | 2026 | ||
2027 | static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar) | ||
2028 | { | ||
2029 | /* FIXME: Not really sure since when the behaviour changed. At some | ||
2030 | * point new firmware stopped requiring creation of peer entries for | ||
2031 | * offchannel tx (and actually creating them causes issues with wmi-htc | ||
2032 | * tx credit replenishment and reliability). Assuming it's at least 3.4 | ||
2033 | * because that's when the `freq` was introduced to TX_FRM HTT command. | ||
2034 | */ | ||
2035 | return !(ar->htt.target_version_major >= 3 && | ||
2036 | ar->htt.target_version_minor >= 4); | ||
2037 | } | ||
2038 | |||
1993 | static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) | 2039 | static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) |
1994 | { | 2040 | { |
1995 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 2041 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
@@ -2165,10 +2211,10 @@ void __ath10k_scan_finish(struct ath10k *ar) | |||
2165 | case ATH10K_SCAN_IDLE: | 2211 | case ATH10K_SCAN_IDLE: |
2166 | break; | 2212 | break; |
2167 | case ATH10K_SCAN_RUNNING: | 2213 | case ATH10K_SCAN_RUNNING: |
2168 | case ATH10K_SCAN_ABORTING: | ||
2169 | if (ar->scan.is_roc) | 2214 | if (ar->scan.is_roc) |
2170 | ieee80211_remain_on_channel_expired(ar->hw); | 2215 | ieee80211_remain_on_channel_expired(ar->hw); |
2171 | else | 2216 | case ATH10K_SCAN_ABORTING: |
2217 | if (!ar->scan.is_roc) | ||
2172 | ieee80211_scan_completed(ar->hw, | 2218 | ieee80211_scan_completed(ar->hw, |
2173 | (ar->scan.state == | 2219 | (ar->scan.state == |
2174 | ATH10K_SCAN_ABORTING)); | 2220 | ATH10K_SCAN_ABORTING)); |
@@ -2334,23 +2380,28 @@ static void ath10k_tx(struct ieee80211_hw *hw, | |||
2334 | 2380 | ||
2335 | if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { | 2381 | if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { |
2336 | spin_lock_bh(&ar->data_lock); | 2382 | spin_lock_bh(&ar->data_lock); |
2337 | ATH10K_SKB_CB(skb)->htt.is_offchan = true; | 2383 | ATH10K_SKB_CB(skb)->htt.freq = ar->scan.roc_freq; |
2338 | ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id; | 2384 | ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id; |
2339 | spin_unlock_bh(&ar->data_lock); | 2385 | spin_unlock_bh(&ar->data_lock); |
2340 | 2386 | ||
2341 | ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n", | 2387 | if (ath10k_mac_need_offchan_tx_work(ar)) { |
2342 | skb); | 2388 | ATH10K_SKB_CB(skb)->htt.freq = 0; |
2389 | ATH10K_SKB_CB(skb)->htt.is_offchan = true; | ||
2343 | 2390 | ||
2344 | skb_queue_tail(&ar->offchan_tx_queue, skb); | 2391 | ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n", |
2345 | ieee80211_queue_work(hw, &ar->offchan_tx_work); | 2392 | skb); |
2346 | return; | 2393 | |
2394 | skb_queue_tail(&ar->offchan_tx_queue, skb); | ||
2395 | ieee80211_queue_work(hw, &ar->offchan_tx_work); | ||
2396 | return; | ||
2397 | } | ||
2347 | } | 2398 | } |
2348 | 2399 | ||
2349 | ath10k_tx_htt(ar, skb); | 2400 | ath10k_tx_htt(ar, skb); |
2350 | } | 2401 | } |
2351 | 2402 | ||
2352 | /* Must not be called with conf_mutex held as workers can use that also. */ | 2403 | /* Must not be called with conf_mutex held as workers can use that also. */ |
2353 | static void ath10k_drain_tx(struct ath10k *ar) | 2404 | void ath10k_drain_tx(struct ath10k *ar) |
2354 | { | 2405 | { |
2355 | /* make sure rcu-protected mac80211 tx path itself is drained */ | 2406 | /* make sure rcu-protected mac80211 tx path itself is drained */ |
2356 | synchronize_net(); | 2407 | synchronize_net(); |
@@ -2407,12 +2458,28 @@ static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) | |||
2407 | return 0; | 2458 | return 0; |
2408 | } | 2459 | } |
2409 | 2460 | ||
2461 | static void ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg) | ||
2462 | { | ||
2463 | /* It is not clear that allowing gaps in chainmask | ||
2464 | * is helpful. Probably it will not do what user | ||
2465 | * is hoping for, so warn in that case. | ||
2466 | */ | ||
2467 | if (cm == 15 || cm == 7 || cm == 3 || cm == 1 || cm == 0) | ||
2468 | return; | ||
2469 | |||
2470 | ath10k_warn(ar, "mac %s antenna chainmask may be invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.\n", | ||
2471 | dbg, cm); | ||
2472 | } | ||
2473 | |||
2410 | static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant) | 2474 | static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant) |
2411 | { | 2475 | { |
2412 | int ret; | 2476 | int ret; |
2413 | 2477 | ||
2414 | lockdep_assert_held(&ar->conf_mutex); | 2478 | lockdep_assert_held(&ar->conf_mutex); |
2415 | 2479 | ||
2480 | ath10k_check_chain_mask(ar, tx_ant, "tx"); | ||
2481 | ath10k_check_chain_mask(ar, rx_ant, "rx"); | ||
2482 | |||
2416 | ar->cfg_tx_chainmask = tx_ant; | 2483 | ar->cfg_tx_chainmask = tx_ant; |
2417 | ar->cfg_rx_chainmask = rx_ant; | 2484 | ar->cfg_rx_chainmask = rx_ant; |
2418 | 2485 | ||
@@ -2775,6 +2842,17 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) | |||
2775 | return ret; | 2842 | return ret; |
2776 | } | 2843 | } |
2777 | 2844 | ||
2845 | static u32 get_nss_from_chainmask(u16 chain_mask) | ||
2846 | { | ||
2847 | if ((chain_mask & 0x15) == 0x15) | ||
2848 | return 4; | ||
2849 | else if ((chain_mask & 0x7) == 0x7) | ||
2850 | return 3; | ||
2851 | else if ((chain_mask & 0x3) == 0x3) | ||
2852 | return 2; | ||
2853 | return 1; | ||
2854 | } | ||
2855 | |||
2778 | /* | 2856 | /* |
2779 | * TODO: | 2857 | * TODO: |
2780 | * Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE, | 2858 | * Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE, |
@@ -2907,6 +2985,20 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, | |||
2907 | goto err_vdev_delete; | 2985 | goto err_vdev_delete; |
2908 | } | 2986 | } |
2909 | 2987 | ||
2988 | if (ar->cfg_tx_chainmask) { | ||
2989 | u16 nss = get_nss_from_chainmask(ar->cfg_tx_chainmask); | ||
2990 | |||
2991 | vdev_param = ar->wmi.vdev_param->nss; | ||
2992 | ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, | ||
2993 | nss); | ||
2994 | if (ret) { | ||
2995 | ath10k_warn(ar, "failed to set vdev %i chainmask 0x%x, nss %i: %d\n", | ||
2996 | arvif->vdev_id, ar->cfg_tx_chainmask, nss, | ||
2997 | ret); | ||
2998 | goto err_vdev_delete; | ||
2999 | } | ||
3000 | } | ||
3001 | |||
2910 | if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { | 3002 | if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { |
2911 | ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr); | 3003 | ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr); |
2912 | if (ret) { | 3004 | if (ret) { |
@@ -3007,10 +3099,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, | |||
3007 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | 3099 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); |
3008 | int ret; | 3100 | int ret; |
3009 | 3101 | ||
3010 | mutex_lock(&ar->conf_mutex); | ||
3011 | |||
3012 | cancel_work_sync(&arvif->wep_key_work); | 3102 | cancel_work_sync(&arvif->wep_key_work); |
3013 | 3103 | ||
3104 | mutex_lock(&ar->conf_mutex); | ||
3105 | |||
3014 | spin_lock_bh(&ar->data_lock); | 3106 | spin_lock_bh(&ar->data_lock); |
3015 | ath10k_mac_vif_beacon_cleanup(arvif); | 3107 | ath10k_mac_vif_beacon_cleanup(arvif); |
3016 | spin_unlock_bh(&ar->data_lock); | 3108 | spin_unlock_bh(&ar->data_lock); |
@@ -3307,9 +3399,10 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw, | |||
3307 | struct ath10k *ar = hw->priv; | 3399 | struct ath10k *ar = hw->priv; |
3308 | 3400 | ||
3309 | mutex_lock(&ar->conf_mutex); | 3401 | mutex_lock(&ar->conf_mutex); |
3310 | cancel_delayed_work_sync(&ar->scan.timeout); | ||
3311 | ath10k_scan_abort(ar); | 3402 | ath10k_scan_abort(ar); |
3312 | mutex_unlock(&ar->conf_mutex); | 3403 | mutex_unlock(&ar->conf_mutex); |
3404 | |||
3405 | cancel_delayed_work_sync(&ar->scan.timeout); | ||
3313 | } | 3406 | } |
3314 | 3407 | ||
3315 | static void ath10k_set_key_h_def_keyidx(struct ath10k *ar, | 3408 | static void ath10k_set_key_h_def_keyidx(struct ath10k *ar, |
@@ -3503,6 +3596,37 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) | |||
3503 | mutex_unlock(&ar->conf_mutex); | 3596 | mutex_unlock(&ar->conf_mutex); |
3504 | } | 3597 | } |
3505 | 3598 | ||
3599 | static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif) | ||
3600 | { | ||
3601 | struct ath10k *ar = arvif->ar; | ||
3602 | |||
3603 | lockdep_assert_held(&ar->conf_mutex); | ||
3604 | |||
3605 | if (arvif->vdev_type != WMI_VDEV_TYPE_AP && | ||
3606 | arvif->vdev_type != WMI_VDEV_TYPE_IBSS) | ||
3607 | return 0; | ||
3608 | |||
3609 | if (ar->num_stations >= ar->max_num_stations) | ||
3610 | return -ENOBUFS; | ||
3611 | |||
3612 | ar->num_stations++; | ||
3613 | |||
3614 | return 0; | ||
3615 | } | ||
3616 | |||
3617 | static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif) | ||
3618 | { | ||
3619 | struct ath10k *ar = arvif->ar; | ||
3620 | |||
3621 | lockdep_assert_held(&ar->conf_mutex); | ||
3622 | |||
3623 | if (arvif->vdev_type != WMI_VDEV_TYPE_AP && | ||
3624 | arvif->vdev_type != WMI_VDEV_TYPE_IBSS) | ||
3625 | return; | ||
3626 | |||
3627 | ar->num_stations--; | ||
3628 | } | ||
3629 | |||
3506 | static int ath10k_sta_state(struct ieee80211_hw *hw, | 3630 | static int ath10k_sta_state(struct ieee80211_hw *hw, |
3507 | struct ieee80211_vif *vif, | 3631 | struct ieee80211_vif *vif, |
3508 | struct ieee80211_sta *sta, | 3632 | struct ieee80211_sta *sta, |
@@ -3512,7 +3636,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, | |||
3512 | struct ath10k *ar = hw->priv; | 3636 | struct ath10k *ar = hw->priv; |
3513 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | 3637 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); |
3514 | struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; | 3638 | struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; |
3515 | int max_num_peers; | ||
3516 | int ret = 0; | 3639 | int ret = 0; |
3517 | 3640 | ||
3518 | if (old_state == IEEE80211_STA_NOTEXIST && | 3641 | if (old_state == IEEE80211_STA_NOTEXIST && |
@@ -3534,26 +3657,26 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, | |||
3534 | /* | 3657 | /* |
3535 | * New station addition. | 3658 | * New station addition. |
3536 | */ | 3659 | */ |
3537 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) | 3660 | ath10k_dbg(ar, ATH10K_DBG_MAC, |
3538 | max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1; | 3661 | "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n", |
3539 | else | 3662 | arvif->vdev_id, sta->addr, |
3540 | max_num_peers = TARGET_NUM_PEERS; | 3663 | ar->num_stations + 1, ar->max_num_stations, |
3664 | ar->num_peers + 1, ar->max_num_peers); | ||
3541 | 3665 | ||
3542 | if (ar->num_peers >= max_num_peers) { | 3666 | ret = ath10k_mac_inc_num_stations(arvif); |
3543 | ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n", | 3667 | if (ret) { |
3544 | ar->num_peers, max_num_peers); | 3668 | ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n", |
3545 | ret = -ENOBUFS; | 3669 | ar->max_num_stations); |
3546 | goto exit; | 3670 | goto exit; |
3547 | } | 3671 | } |
3548 | 3672 | ||
3549 | ath10k_dbg(ar, ATH10K_DBG_MAC, | ||
3550 | "mac vdev %d peer create %pM (new sta) num_peers %d\n", | ||
3551 | arvif->vdev_id, sta->addr, ar->num_peers); | ||
3552 | |||
3553 | ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); | 3673 | ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); |
3554 | if (ret) | 3674 | if (ret) { |
3555 | ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n", | 3675 | ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n", |
3556 | sta->addr, arvif->vdev_id, ret); | 3676 | sta->addr, arvif->vdev_id, ret); |
3677 | ath10k_mac_dec_num_stations(arvif); | ||
3678 | goto exit; | ||
3679 | } | ||
3557 | 3680 | ||
3558 | if (vif->type == NL80211_IFTYPE_STATION) { | 3681 | if (vif->type == NL80211_IFTYPE_STATION) { |
3559 | WARN_ON(arvif->is_started); | 3682 | WARN_ON(arvif->is_started); |
@@ -3564,6 +3687,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, | |||
3564 | arvif->vdev_id, ret); | 3687 | arvif->vdev_id, ret); |
3565 | WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id, | 3688 | WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id, |
3566 | sta->addr)); | 3689 | sta->addr)); |
3690 | ath10k_mac_dec_num_stations(arvif); | ||
3567 | goto exit; | 3691 | goto exit; |
3568 | } | 3692 | } |
3569 | 3693 | ||
@@ -3594,6 +3718,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, | |||
3594 | ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", | 3718 | ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", |
3595 | sta->addr, arvif->vdev_id, ret); | 3719 | sta->addr, arvif->vdev_id, ret); |
3596 | 3720 | ||
3721 | ath10k_mac_dec_num_stations(arvif); | ||
3597 | } else if (old_state == IEEE80211_STA_AUTH && | 3722 | } else if (old_state == IEEE80211_STA_AUTH && |
3598 | new_state == IEEE80211_STA_ASSOC && | 3723 | new_state == IEEE80211_STA_ASSOC && |
3599 | (vif->type == NL80211_IFTYPE_AP || | 3724 | (vif->type == NL80211_IFTYPE_AP || |
@@ -3782,6 +3907,8 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, | |||
3782 | if (ret) | 3907 | if (ret) |
3783 | goto exit; | 3908 | goto exit; |
3784 | 3909 | ||
3910 | duration = max(duration, WMI_SCAN_CHAN_MIN_TIME_MSEC); | ||
3911 | |||
3785 | memset(&arg, 0, sizeof(arg)); | 3912 | memset(&arg, 0, sizeof(arg)); |
3786 | ath10k_wmi_start_scan_init(ar, &arg); | 3913 | ath10k_wmi_start_scan_init(ar, &arg); |
3787 | arg.vdev_id = arvif->vdev_id; | 3914 | arg.vdev_id = arvif->vdev_id; |
@@ -3826,10 +3953,11 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw) | |||
3826 | struct ath10k *ar = hw->priv; | 3953 | struct ath10k *ar = hw->priv; |
3827 | 3954 | ||
3828 | mutex_lock(&ar->conf_mutex); | 3955 | mutex_lock(&ar->conf_mutex); |
3829 | cancel_delayed_work_sync(&ar->scan.timeout); | ||
3830 | ath10k_scan_abort(ar); | 3956 | ath10k_scan_abort(ar); |
3831 | mutex_unlock(&ar->conf_mutex); | 3957 | mutex_unlock(&ar->conf_mutex); |
3832 | 3958 | ||
3959 | cancel_delayed_work_sync(&ar->scan.timeout); | ||
3960 | |||
3833 | return 0; | 3961 | return 0; |
3834 | } | 3962 | } |
3835 | 3963 | ||
@@ -3872,7 +4000,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) | |||
3872 | ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n", | 4000 | ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n", |
3873 | arvif->vdev_id, value); | 4001 | arvif->vdev_id, value); |
3874 | 4002 | ||
3875 | ret = ath10k_mac_set_rts(arvif, value); | 4003 | ret = ath10k_mac_set_frag(arvif, value); |
3876 | if (ret) { | 4004 | if (ret) { |
3877 | ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n", | 4005 | ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n", |
3878 | arvif->vdev_id, ret); | 4006 | arvif->vdev_id, ret); |
@@ -3908,7 +4036,9 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
3908 | empty = (ar->htt.num_pending_tx == 0); | 4036 | empty = (ar->htt.num_pending_tx == 0); |
3909 | spin_unlock_bh(&ar->htt.tx_lock); | 4037 | spin_unlock_bh(&ar->htt.tx_lock); |
3910 | 4038 | ||
3911 | skip = (ar->state == ATH10K_STATE_WEDGED); | 4039 | skip = (ar->state == ATH10K_STATE_WEDGED) || |
4040 | test_bit(ATH10K_FLAG_CRASH_FLUSH, | ||
4041 | &ar->dev_flags); | ||
3912 | 4042 | ||
3913 | (empty || skip); | 4043 | (empty || skip); |
3914 | }), ATH10K_FLUSH_TIMEOUT_HZ); | 4044 | }), ATH10K_FLUSH_TIMEOUT_HZ); |
@@ -3994,10 +4124,14 @@ exit: | |||
3994 | } | 4124 | } |
3995 | #endif | 4125 | #endif |
3996 | 4126 | ||
3997 | static void ath10k_restart_complete(struct ieee80211_hw *hw) | 4127 | static void ath10k_reconfig_complete(struct ieee80211_hw *hw, |
4128 | enum ieee80211_reconfig_type reconfig_type) | ||
3998 | { | 4129 | { |
3999 | struct ath10k *ar = hw->priv; | 4130 | struct ath10k *ar = hw->priv; |
4000 | 4131 | ||
4132 | if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) | ||
4133 | return; | ||
4134 | |||
4001 | mutex_lock(&ar->conf_mutex); | 4135 | mutex_lock(&ar->conf_mutex); |
4002 | 4136 | ||
4003 | /* If device failed to restart it will be in a different state, e.g. | 4137 | /* If device failed to restart it will be in a different state, e.g. |
@@ -4005,6 +4139,7 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw) | |||
4005 | if (ar->state == ATH10K_STATE_RESTARTED) { | 4139 | if (ar->state == ATH10K_STATE_RESTARTED) { |
4006 | ath10k_info(ar, "device successfully recovered\n"); | 4140 | ath10k_info(ar, "device successfully recovered\n"); |
4007 | ar->state = ATH10K_STATE_ON; | 4141 | ar->state = ATH10K_STATE_ON; |
4142 | ieee80211_wake_queues(ar->hw); | ||
4008 | } | 4143 | } |
4009 | 4144 | ||
4010 | mutex_unlock(&ar->conf_mutex); | 4145 | mutex_unlock(&ar->conf_mutex); |
@@ -4040,6 +4175,9 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx, | |||
4040 | 4175 | ||
4041 | survey->channel = &sband->channels[idx]; | 4176 | survey->channel = &sband->channels[idx]; |
4042 | 4177 | ||
4178 | if (ar->rx_channel == survey->channel) | ||
4179 | survey->filled |= SURVEY_INFO_IN_USE; | ||
4180 | |||
4043 | exit: | 4181 | exit: |
4044 | mutex_unlock(&ar->conf_mutex); | 4182 | mutex_unlock(&ar->conf_mutex); |
4045 | return ret; | 4183 | return ret; |
@@ -4087,6 +4225,10 @@ ath10k_default_bitrate_mask(struct ath10k *ar, | |||
4087 | u32 legacy = 0x00ff; | 4225 | u32 legacy = 0x00ff; |
4088 | u8 ht = 0xff, i; | 4226 | u8 ht = 0xff, i; |
4089 | u16 vht = 0x3ff; | 4227 | u16 vht = 0x3ff; |
4228 | u16 nrf = ar->num_rf_chains; | ||
4229 | |||
4230 | if (ar->cfg_tx_chainmask) | ||
4231 | nrf = get_nss_from_chainmask(ar->cfg_tx_chainmask); | ||
4090 | 4232 | ||
4091 | switch (band) { | 4233 | switch (band) { |
4092 | case IEEE80211_BAND_2GHZ: | 4234 | case IEEE80211_BAND_2GHZ: |
@@ -4102,11 +4244,11 @@ ath10k_default_bitrate_mask(struct ath10k *ar, | |||
4102 | if (mask->control[band].legacy != legacy) | 4244 | if (mask->control[band].legacy != legacy) |
4103 | return false; | 4245 | return false; |
4104 | 4246 | ||
4105 | for (i = 0; i < ar->num_rf_chains; i++) | 4247 | for (i = 0; i < nrf; i++) |
4106 | if (mask->control[band].ht_mcs[i] != ht) | 4248 | if (mask->control[band].ht_mcs[i] != ht) |
4107 | return false; | 4249 | return false; |
4108 | 4250 | ||
4109 | for (i = 0; i < ar->num_rf_chains; i++) | 4251 | for (i = 0; i < nrf; i++) |
4110 | if (mask->control[band].vht_mcs[i] != vht) | 4252 | if (mask->control[band].vht_mcs[i] != vht) |
4111 | return false; | 4253 | return false; |
4112 | 4254 | ||
@@ -4357,6 +4499,9 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, | |||
4357 | u8 fixed_nss = ar->num_rf_chains; | 4499 | u8 fixed_nss = ar->num_rf_chains; |
4358 | u8 force_sgi; | 4500 | u8 force_sgi; |
4359 | 4501 | ||
4502 | if (ar->cfg_tx_chainmask) | ||
4503 | fixed_nss = get_nss_from_chainmask(ar->cfg_tx_chainmask); | ||
4504 | |||
4360 | force_sgi = mask->control[band].gi; | 4505 | force_sgi = mask->control[band].gi; |
4361 | if (force_sgi == NL80211_TXRATE_FORCE_LGI) | 4506 | if (force_sgi == NL80211_TXRATE_FORCE_LGI) |
4362 | return -EINVAL; | 4507 | return -EINVAL; |
@@ -4515,7 +4660,7 @@ static const struct ieee80211_ops ath10k_ops = { | |||
4515 | .tx_last_beacon = ath10k_tx_last_beacon, | 4660 | .tx_last_beacon = ath10k_tx_last_beacon, |
4516 | .set_antenna = ath10k_set_antenna, | 4661 | .set_antenna = ath10k_set_antenna, |
4517 | .get_antenna = ath10k_get_antenna, | 4662 | .get_antenna = ath10k_get_antenna, |
4518 | .restart_complete = ath10k_restart_complete, | 4663 | .reconfig_complete = ath10k_reconfig_complete, |
4519 | .get_survey = ath10k_get_survey, | 4664 | .get_survey = ath10k_get_survey, |
4520 | .set_bitrate_mask = ath10k_set_bitrate_mask, | 4665 | .set_bitrate_mask = ath10k_set_bitrate_mask, |
4521 | .sta_rc_update = ath10k_sta_rc_update, | 4666 | .sta_rc_update = ath10k_sta_rc_update, |
@@ -4886,10 +5031,6 @@ int ath10k_mac_register(struct ath10k *ar) | |||
4886 | IEEE80211_HW_AP_LINK_PS | | 5031 | IEEE80211_HW_AP_LINK_PS | |
4887 | IEEE80211_HW_SPECTRUM_MGMT; | 5032 | IEEE80211_HW_SPECTRUM_MGMT; |
4888 | 5033 | ||
4889 | /* MSDU can have HTT TX fragment pushed in front. The additional 4 | ||
4890 | * bytes is used for padding/alignment if necessary. */ | ||
4891 | ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4; | ||
4892 | |||
4893 | ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; | 5034 | ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; |
4894 | 5035 | ||
4895 | if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) | 5036 | if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) |
@@ -4913,6 +5054,8 @@ int ath10k_mac_register(struct ath10k *ar) | |||
4913 | ar->hw->wiphy->max_remain_on_channel_duration = 5000; | 5054 | ar->hw->wiphy->max_remain_on_channel_duration = 5000; |
4914 | 5055 | ||
4915 | ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | 5056 | ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; |
5057 | ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; | ||
5058 | |||
4916 | /* | 5059 | /* |
4917 | * on LL hardware queues are managed entirely by the FW | 5060 | * on LL hardware queues are managed entirely by the FW |
4918 | * so we only advertise to mac we can do the queues thing | 5061 | * so we only advertise to mac we can do the queues thing |
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index 965c51117499..68296117d203 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <net/mac80211.h> | 21 | #include <net/mac80211.h> |
22 | #include "core.h" | 22 | #include "core.h" |
23 | 23 | ||
24 | #define WEP_KEYID_SHIFT 6 | ||
25 | |||
24 | struct ath10k_generic_iter { | 26 | struct ath10k_generic_iter { |
25 | struct ath10k *ar; | 27 | struct ath10k *ar; |
26 | int ret; | 28 | int ret; |
@@ -40,6 +42,9 @@ void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar); | |||
40 | void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work); | 42 | void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work); |
41 | void ath10k_halt(struct ath10k *ar); | 43 | void ath10k_halt(struct ath10k *ar); |
42 | void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif); | 44 | void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif); |
45 | void ath10k_drain_tx(struct ath10k *ar); | ||
46 | bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr, | ||
47 | u8 keyidx); | ||
43 | 48 | ||
44 | static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) | 49 | static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) |
45 | { | 50 | { |
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 4a4740b4bdc0..7abb8367119a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c | |||
@@ -823,20 +823,24 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) | |||
823 | struct ath10k *ar = ce_state->ar; | 823 | struct ath10k *ar = ce_state->ar; |
824 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 824 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
825 | struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; | 825 | struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; |
826 | void *transfer_context; | 826 | struct sk_buff_head list; |
827 | struct sk_buff *skb; | ||
827 | u32 ce_data; | 828 | u32 ce_data; |
828 | unsigned int nbytes; | 829 | unsigned int nbytes; |
829 | unsigned int transfer_id; | 830 | unsigned int transfer_id; |
830 | 831 | ||
831 | while (ath10k_ce_completed_send_next(ce_state, &transfer_context, | 832 | __skb_queue_head_init(&list); |
832 | &ce_data, &nbytes, | 833 | while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data, |
833 | &transfer_id) == 0) { | 834 | &nbytes, &transfer_id) == 0) { |
834 | /* no need to call tx completion for NULL pointers */ | 835 | /* no need to call tx completion for NULL pointers */ |
835 | if (transfer_context == NULL) | 836 | if (skb == NULL) |
836 | continue; | 837 | continue; |
837 | 838 | ||
838 | cb->tx_completion(ar, transfer_context, transfer_id); | 839 | __skb_queue_tail(&list, skb); |
839 | } | 840 | } |
841 | |||
842 | while ((skb = __skb_dequeue(&list))) | ||
843 | cb->tx_completion(ar, skb); | ||
840 | } | 844 | } |
841 | 845 | ||
842 | /* Called by lower (CE) layer when data is received from the Target. */ | 846 | /* Called by lower (CE) layer when data is received from the Target. */ |
@@ -847,12 +851,14 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) | |||
847 | struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; | 851 | struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; |
848 | struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; | 852 | struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; |
849 | struct sk_buff *skb; | 853 | struct sk_buff *skb; |
854 | struct sk_buff_head list; | ||
850 | void *transfer_context; | 855 | void *transfer_context; |
851 | u32 ce_data; | 856 | u32 ce_data; |
852 | unsigned int nbytes, max_nbytes; | 857 | unsigned int nbytes, max_nbytes; |
853 | unsigned int transfer_id; | 858 | unsigned int transfer_id; |
854 | unsigned int flags; | 859 | unsigned int flags; |
855 | 860 | ||
861 | __skb_queue_head_init(&list); | ||
856 | while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, | 862 | while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, |
857 | &ce_data, &nbytes, &transfer_id, | 863 | &ce_data, &nbytes, &transfer_id, |
858 | &flags) == 0) { | 864 | &flags) == 0) { |
@@ -869,13 +875,16 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) | |||
869 | } | 875 | } |
870 | 876 | ||
871 | skb_put(skb, nbytes); | 877 | skb_put(skb, nbytes); |
878 | __skb_queue_tail(&list, skb); | ||
879 | } | ||
872 | 880 | ||
881 | while ((skb = __skb_dequeue(&list))) { | ||
873 | ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n", | 882 | ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n", |
874 | ce_state->id, skb->len); | 883 | ce_state->id, skb->len); |
875 | ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", | 884 | ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", |
876 | skb->data, skb->len); | 885 | skb->data, skb->len); |
877 | 886 | ||
878 | cb->rx_completion(ar, skb, pipe_info->pipe_num); | 887 | cb->rx_completion(ar, skb); |
879 | } | 888 | } |
880 | 889 | ||
881 | ath10k_pci_rx_post_pipe(pipe_info); | 890 | ath10k_pci_rx_post_pipe(pipe_info); |
@@ -1196,64 +1205,74 @@ static int ath10k_pci_hif_start(struct ath10k *ar) | |||
1196 | return 0; | 1205 | return 0; |
1197 | } | 1206 | } |
1198 | 1207 | ||
1199 | static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) | 1208 | static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) |
1200 | { | 1209 | { |
1201 | struct ath10k *ar; | 1210 | struct ath10k *ar; |
1202 | struct ath10k_pci *ar_pci; | 1211 | struct ath10k_ce_pipe *ce_pipe; |
1203 | struct ath10k_ce_pipe *ce_hdl; | 1212 | struct ath10k_ce_ring *ce_ring; |
1204 | u32 buf_sz; | 1213 | struct sk_buff *skb; |
1205 | struct sk_buff *netbuf; | 1214 | int i; |
1206 | u32 ce_data; | ||
1207 | 1215 | ||
1208 | buf_sz = pipe_info->buf_sz; | 1216 | ar = pci_pipe->hif_ce_state; |
1217 | ce_pipe = pci_pipe->ce_hdl; | ||
1218 | ce_ring = ce_pipe->dest_ring; | ||
1209 | 1219 | ||
1210 | /* Unused Copy Engine */ | 1220 | if (!ce_ring) |
1211 | if (buf_sz == 0) | ||
1212 | return; | 1221 | return; |
1213 | 1222 | ||
1214 | ar = pipe_info->hif_ce_state; | 1223 | if (!pci_pipe->buf_sz) |
1215 | ar_pci = ath10k_pci_priv(ar); | 1224 | return; |
1216 | ce_hdl = pipe_info->ce_hdl; | 1225 | |
1226 | for (i = 0; i < ce_ring->nentries; i++) { | ||
1227 | skb = ce_ring->per_transfer_context[i]; | ||
1228 | if (!skb) | ||
1229 | continue; | ||
1230 | |||
1231 | ce_ring->per_transfer_context[i] = NULL; | ||
1217 | 1232 | ||
1218 | while (ath10k_ce_revoke_recv_next(ce_hdl, (void **)&netbuf, | 1233 | dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, |
1219 | &ce_data) == 0) { | 1234 | skb->len + skb_tailroom(skb), |
1220 | dma_unmap_single(ar->dev, ATH10K_SKB_CB(netbuf)->paddr, | ||
1221 | netbuf->len + skb_tailroom(netbuf), | ||
1222 | DMA_FROM_DEVICE); | 1235 | DMA_FROM_DEVICE); |
1223 | dev_kfree_skb_any(netbuf); | 1236 | dev_kfree_skb_any(skb); |
1224 | } | 1237 | } |
1225 | } | 1238 | } |
1226 | 1239 | ||
1227 | static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) | 1240 | static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) |
1228 | { | 1241 | { |
1229 | struct ath10k *ar; | 1242 | struct ath10k *ar; |
1230 | struct ath10k_pci *ar_pci; | 1243 | struct ath10k_pci *ar_pci; |
1231 | struct ath10k_ce_pipe *ce_hdl; | 1244 | struct ath10k_ce_pipe *ce_pipe; |
1232 | struct sk_buff *netbuf; | 1245 | struct ath10k_ce_ring *ce_ring; |
1233 | u32 ce_data; | 1246 | struct ce_desc *ce_desc; |
1234 | unsigned int nbytes; | 1247 | struct sk_buff *skb; |
1235 | unsigned int id; | 1248 | unsigned int id; |
1236 | u32 buf_sz; | 1249 | int i; |
1237 | 1250 | ||
1238 | buf_sz = pipe_info->buf_sz; | 1251 | ar = pci_pipe->hif_ce_state; |
1252 | ar_pci = ath10k_pci_priv(ar); | ||
1253 | ce_pipe = pci_pipe->ce_hdl; | ||
1254 | ce_ring = ce_pipe->src_ring; | ||
1239 | 1255 | ||
1240 | /* Unused Copy Engine */ | 1256 | if (!ce_ring) |
1241 | if (buf_sz == 0) | ||
1242 | return; | 1257 | return; |
1243 | 1258 | ||
1244 | ar = pipe_info->hif_ce_state; | 1259 | if (!pci_pipe->buf_sz) |
1245 | ar_pci = ath10k_pci_priv(ar); | 1260 | return; |
1246 | ce_hdl = pipe_info->ce_hdl; | ||
1247 | 1261 | ||
1248 | while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf, | 1262 | ce_desc = ce_ring->shadow_base; |
1249 | &ce_data, &nbytes, &id) == 0) { | 1263 | if (WARN_ON(!ce_desc)) |
1250 | /* no need to call tx completion for NULL pointers */ | 1264 | return; |
1251 | if (!netbuf) | 1265 | |
1266 | for (i = 0; i < ce_ring->nentries; i++) { | ||
1267 | skb = ce_ring->per_transfer_context[i]; | ||
1268 | if (!skb) | ||
1252 | continue; | 1269 | continue; |
1253 | 1270 | ||
1254 | ar_pci->msg_callbacks_current.tx_completion(ar, | 1271 | ce_ring->per_transfer_context[i] = NULL; |
1255 | netbuf, | 1272 | id = MS(__le16_to_cpu(ce_desc[i].flags), |
1256 | id); | 1273 | CE_DESC_FLAGS_META_DATA); |
1274 | |||
1275 | ar_pci->msg_callbacks_current.tx_completion(ar, skb); | ||
1257 | } | 1276 | } |
1258 | } | 1277 | } |
1259 | 1278 | ||
@@ -1432,6 +1451,9 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) | |||
1432 | &nbytes, &transfer_id, &flags)) | 1451 | &nbytes, &transfer_id, &flags)) |
1433 | return; | 1452 | return; |
1434 | 1453 | ||
1454 | if (WARN_ON_ONCE(!xfer)) | ||
1455 | return; | ||
1456 | |||
1435 | if (!xfer->wait_for_resp) { | 1457 | if (!xfer->wait_for_resp) { |
1436 | ath10k_warn(ar, "unexpected: BMI data received; ignoring\n"); | 1458 | ath10k_warn(ar, "unexpected: BMI data received; ignoring\n"); |
1437 | return; | 1459 | return; |
@@ -1707,99 +1729,167 @@ static void ath10k_pci_warm_reset_si0(struct ath10k *ar) | |||
1707 | msleep(10); | 1729 | msleep(10); |
1708 | } | 1730 | } |
1709 | 1731 | ||
1710 | static int ath10k_pci_warm_reset(struct ath10k *ar) | 1732 | static void ath10k_pci_warm_reset_cpu(struct ath10k *ar) |
1711 | { | 1733 | { |
1712 | u32 val; | 1734 | u32 val; |
1713 | 1735 | ||
1714 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n"); | 1736 | ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); |
1715 | |||
1716 | spin_lock_bh(&ar->data_lock); | ||
1717 | |||
1718 | ar->stats.fw_warm_reset_counter++; | ||
1719 | |||
1720 | spin_unlock_bh(&ar->data_lock); | ||
1721 | |||
1722 | /* debug */ | ||
1723 | val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + | ||
1724 | PCIE_INTR_CAUSE_ADDRESS); | ||
1725 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", | ||
1726 | val); | ||
1727 | 1737 | ||
1728 | val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + | 1738 | val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + |
1729 | CPU_INTR_ADDRESS); | 1739 | SOC_RESET_CONTROL_ADDRESS); |
1730 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", | 1740 | ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, |
1731 | val); | 1741 | val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); |
1742 | } | ||
1732 | 1743 | ||
1733 | /* disable pending irqs */ | 1744 | static void ath10k_pci_warm_reset_ce(struct ath10k *ar) |
1734 | ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + | 1745 | { |
1735 | PCIE_INTR_ENABLE_ADDRESS, 0); | 1746 | u32 val; |
1736 | 1747 | ||
1737 | ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + | 1748 | val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + |
1738 | PCIE_INTR_CLR_ADDRESS, ~0); | 1749 | SOC_RESET_CONTROL_ADDRESS); |
1739 | 1750 | ||
1740 | msleep(100); | 1751 | ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, |
1752 | val | SOC_RESET_CONTROL_CE_RST_MASK); | ||
1753 | msleep(10); | ||
1754 | ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, | ||
1755 | val & ~SOC_RESET_CONTROL_CE_RST_MASK); | ||
1756 | } | ||
1741 | 1757 | ||
1742 | /* clear fw indicator */ | 1758 | static void ath10k_pci_warm_reset_clear_lf(struct ath10k *ar) |
1743 | ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); | 1759 | { |
1760 | u32 val; | ||
1744 | 1761 | ||
1745 | /* clear target LF timer interrupts */ | ||
1746 | val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + | 1762 | val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + |
1747 | SOC_LF_TIMER_CONTROL0_ADDRESS); | 1763 | SOC_LF_TIMER_CONTROL0_ADDRESS); |
1748 | ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + | 1764 | ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + |
1749 | SOC_LF_TIMER_CONTROL0_ADDRESS, | 1765 | SOC_LF_TIMER_CONTROL0_ADDRESS, |
1750 | val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); | 1766 | val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); |
1767 | } | ||
1751 | 1768 | ||
1752 | /* reset CE */ | 1769 | static int ath10k_pci_warm_reset(struct ath10k *ar) |
1753 | val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + | 1770 | { |
1754 | SOC_RESET_CONTROL_ADDRESS); | 1771 | int ret; |
1755 | ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, | ||
1756 | val | SOC_RESET_CONTROL_CE_RST_MASK); | ||
1757 | val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + | ||
1758 | SOC_RESET_CONTROL_ADDRESS); | ||
1759 | msleep(10); | ||
1760 | 1772 | ||
1761 | /* unreset CE */ | 1773 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n"); |
1762 | ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, | 1774 | |
1763 | val & ~SOC_RESET_CONTROL_CE_RST_MASK); | 1775 | spin_lock_bh(&ar->data_lock); |
1764 | val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + | 1776 | ar->stats.fw_warm_reset_counter++; |
1765 | SOC_RESET_CONTROL_ADDRESS); | 1777 | spin_unlock_bh(&ar->data_lock); |
1766 | msleep(10); | ||
1767 | 1778 | ||
1779 | ath10k_pci_irq_disable(ar); | ||
1780 | |||
1781 | /* Make sure the target CPU is not doing anything dangerous, e.g. if it | ||
1782 | * were to access copy engine while host performs copy engine reset | ||
1783 | * then it is possible for the device to confuse pci-e controller to | ||
1784 | * the point of bringing host system to a complete stop (i.e. hang). | ||
1785 | */ | ||
1768 | ath10k_pci_warm_reset_si0(ar); | 1786 | ath10k_pci_warm_reset_si0(ar); |
1787 | ath10k_pci_warm_reset_cpu(ar); | ||
1788 | ath10k_pci_init_pipes(ar); | ||
1789 | ath10k_pci_wait_for_target_init(ar); | ||
1769 | 1790 | ||
1770 | /* debug */ | 1791 | ath10k_pci_warm_reset_clear_lf(ar); |
1771 | val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + | 1792 | ath10k_pci_warm_reset_ce(ar); |
1772 | PCIE_INTR_CAUSE_ADDRESS); | 1793 | ath10k_pci_warm_reset_cpu(ar); |
1773 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", | 1794 | ath10k_pci_init_pipes(ar); |
1774 | val); | ||
1775 | 1795 | ||
1776 | val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + | 1796 | ret = ath10k_pci_wait_for_target_init(ar); |
1777 | CPU_INTR_ADDRESS); | 1797 | if (ret) { |
1778 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", | 1798 | ath10k_warn(ar, "failed to wait for target init: %d\n", ret); |
1779 | val); | 1799 | return ret; |
1800 | } | ||
1780 | 1801 | ||
1781 | /* CPU warm reset */ | 1802 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n"); |
1782 | val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + | ||
1783 | SOC_RESET_CONTROL_ADDRESS); | ||
1784 | ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, | ||
1785 | val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); | ||
1786 | 1803 | ||
1787 | val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + | 1804 | return 0; |
1788 | SOC_RESET_CONTROL_ADDRESS); | 1805 | } |
1789 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", | ||
1790 | val); | ||
1791 | 1806 | ||
1792 | msleep(100); | 1807 | static int ath10k_pci_chip_reset(struct ath10k *ar) |
1808 | { | ||
1809 | int i, ret; | ||
1810 | u32 val; | ||
1793 | 1811 | ||
1794 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n"); | 1812 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset\n"); |
1813 | |||
1814 | /* Some hardware revisions (e.g. CUS223v2) has issues with cold reset. | ||
1815 | * It is thus preferred to use warm reset which is safer but may not be | ||
1816 | * able to recover the device from all possible fail scenarios. | ||
1817 | * | ||
1818 | * Warm reset doesn't always work on first try so attempt it a few | ||
1819 | * times before giving up. | ||
1820 | */ | ||
1821 | for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) { | ||
1822 | ret = ath10k_pci_warm_reset(ar); | ||
1823 | if (ret) { | ||
1824 | ath10k_warn(ar, "failed to warm reset attempt %d of %d: %d\n", | ||
1825 | i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, | ||
1826 | ret); | ||
1827 | continue; | ||
1828 | } | ||
1829 | |||
1830 | /* FIXME: Sometimes copy engine doesn't recover after warm | ||
1831 | * reset. In most cases this needs cold reset. In some of these | ||
1832 | * cases the device is in such a state that a cold reset may | ||
1833 | * lock up the host. | ||
1834 | * | ||
1835 | * Reading any host interest register via copy engine is | ||
1836 | * sufficient to verify if device is capable of booting | ||
1837 | * firmware blob. | ||
1838 | */ | ||
1839 | ret = ath10k_pci_init_pipes(ar); | ||
1840 | if (ret) { | ||
1841 | ath10k_warn(ar, "failed to init copy engine: %d\n", | ||
1842 | ret); | ||
1843 | continue; | ||
1844 | } | ||
1845 | |||
1846 | ret = ath10k_pci_diag_read32(ar, QCA988X_HOST_INTEREST_ADDRESS, | ||
1847 | &val); | ||
1848 | if (ret) { | ||
1849 | ath10k_warn(ar, "failed to poke copy engine: %d\n", | ||
1850 | ret); | ||
1851 | continue; | ||
1852 | } | ||
1853 | |||
1854 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (warm)\n"); | ||
1855 | return 0; | ||
1856 | } | ||
1857 | |||
1858 | if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) { | ||
1859 | ath10k_warn(ar, "refusing cold reset as requested\n"); | ||
1860 | return -EPERM; | ||
1861 | } | ||
1862 | |||
1863 | ret = ath10k_pci_cold_reset(ar); | ||
1864 | if (ret) { | ||
1865 | ath10k_warn(ar, "failed to cold reset: %d\n", ret); | ||
1866 | return ret; | ||
1867 | } | ||
1868 | |||
1869 | ret = ath10k_pci_wait_for_target_init(ar); | ||
1870 | if (ret) { | ||
1871 | ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", | ||
1872 | ret); | ||
1873 | return ret; | ||
1874 | } | ||
1875 | |||
1876 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (cold)\n"); | ||
1795 | 1877 | ||
1796 | return 0; | 1878 | return 0; |
1797 | } | 1879 | } |
1798 | 1880 | ||
1799 | static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) | 1881 | static int ath10k_pci_hif_power_up(struct ath10k *ar) |
1800 | { | 1882 | { |
1801 | int ret; | 1883 | int ret; |
1802 | 1884 | ||
1885 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n"); | ||
1886 | |||
1887 | ret = ath10k_pci_wake(ar); | ||
1888 | if (ret) { | ||
1889 | ath10k_err(ar, "failed to wake up target: %d\n", ret); | ||
1890 | return ret; | ||
1891 | } | ||
1892 | |||
1803 | /* | 1893 | /* |
1804 | * Bring the target up cleanly. | 1894 | * Bring the target up cleanly. |
1805 | * | 1895 | * |
@@ -1810,26 +1900,16 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) | |||
1810 | * is in an unexpected state. We try to catch that here in order to | 1900 | * is in an unexpected state. We try to catch that here in order to |
1811 | * reset the Target and retry the probe. | 1901 | * reset the Target and retry the probe. |
1812 | */ | 1902 | */ |
1813 | if (cold_reset) | 1903 | ret = ath10k_pci_chip_reset(ar); |
1814 | ret = ath10k_pci_cold_reset(ar); | ||
1815 | else | ||
1816 | ret = ath10k_pci_warm_reset(ar); | ||
1817 | |||
1818 | if (ret) { | 1904 | if (ret) { |
1819 | ath10k_err(ar, "failed to reset target: %d\n", ret); | 1905 | ath10k_err(ar, "failed to reset chip: %d\n", ret); |
1820 | goto err; | 1906 | goto err_sleep; |
1821 | } | 1907 | } |
1822 | 1908 | ||
1823 | ret = ath10k_pci_init_pipes(ar); | 1909 | ret = ath10k_pci_init_pipes(ar); |
1824 | if (ret) { | 1910 | if (ret) { |
1825 | ath10k_err(ar, "failed to initialize CE: %d\n", ret); | 1911 | ath10k_err(ar, "failed to initialize CE: %d\n", ret); |
1826 | goto err; | 1912 | goto err_sleep; |
1827 | } | ||
1828 | |||
1829 | ret = ath10k_pci_wait_for_target_init(ar); | ||
1830 | if (ret) { | ||
1831 | ath10k_err(ar, "failed to wait for target to init: %d\n", ret); | ||
1832 | goto err_ce; | ||
1833 | } | 1913 | } |
1834 | 1914 | ||
1835 | ret = ath10k_pci_init_config(ar); | 1915 | ret = ath10k_pci_init_config(ar); |
@@ -1848,73 +1928,21 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) | |||
1848 | 1928 | ||
1849 | err_ce: | 1929 | err_ce: |
1850 | ath10k_pci_ce_deinit(ar); | 1930 | ath10k_pci_ce_deinit(ar); |
1851 | ath10k_pci_warm_reset(ar); | ||
1852 | err: | ||
1853 | return ret; | ||
1854 | } | ||
1855 | |||
1856 | static int ath10k_pci_hif_power_up_warm(struct ath10k *ar) | ||
1857 | { | ||
1858 | int i, ret; | ||
1859 | |||
1860 | /* | ||
1861 | * Sometime warm reset succeeds after retries. | ||
1862 | * | ||
1863 | * FIXME: It might be possible to tune ath10k_pci_warm_reset() to work | ||
1864 | * at first try. | ||
1865 | */ | ||
1866 | for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) { | ||
1867 | ret = __ath10k_pci_hif_power_up(ar, false); | ||
1868 | if (ret == 0) | ||
1869 | break; | ||
1870 | |||
1871 | ath10k_warn(ar, "failed to warm reset (attempt %d out of %d): %d\n", | ||
1872 | i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret); | ||
1873 | } | ||
1874 | 1931 | ||
1932 | err_sleep: | ||
1933 | ath10k_pci_sleep(ar); | ||
1875 | return ret; | 1934 | return ret; |
1876 | } | 1935 | } |
1877 | 1936 | ||
1878 | static int ath10k_pci_hif_power_up(struct ath10k *ar) | ||
1879 | { | ||
1880 | int ret; | ||
1881 | |||
1882 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n"); | ||
1883 | |||
1884 | /* | ||
1885 | * Hardware CUS232 version 2 has some issues with cold reset and the | ||
1886 | * preferred (and safer) way to perform a device reset is through a | ||
1887 | * warm reset. | ||
1888 | * | ||
1889 | * Warm reset doesn't always work though so fall back to cold reset may | ||
1890 | * be necessary. | ||
1891 | */ | ||
1892 | ret = ath10k_pci_hif_power_up_warm(ar); | ||
1893 | if (ret) { | ||
1894 | ath10k_warn(ar, "failed to power up target using warm reset: %d\n", | ||
1895 | ret); | ||
1896 | |||
1897 | if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) | ||
1898 | return ret; | ||
1899 | |||
1900 | ath10k_warn(ar, "trying cold reset\n"); | ||
1901 | |||
1902 | ret = __ath10k_pci_hif_power_up(ar, true); | ||
1903 | if (ret) { | ||
1904 | ath10k_err(ar, "failed to power up target using cold reset too (%d)\n", | ||
1905 | ret); | ||
1906 | return ret; | ||
1907 | } | ||
1908 | } | ||
1909 | |||
1910 | return 0; | ||
1911 | } | ||
1912 | |||
1913 | static void ath10k_pci_hif_power_down(struct ath10k *ar) | 1937 | static void ath10k_pci_hif_power_down(struct ath10k *ar) |
1914 | { | 1938 | { |
1915 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); | 1939 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); |
1916 | 1940 | ||
1917 | ath10k_pci_warm_reset(ar); | 1941 | /* Currently hif_power_up performs effectively a reset and hif_stop |
1942 | * resets the chip as well so there's no point in resetting here. | ||
1943 | */ | ||
1944 | |||
1945 | ath10k_pci_sleep(ar); | ||
1918 | } | 1946 | } |
1919 | 1947 | ||
1920 | #ifdef CONFIG_PM | 1948 | #ifdef CONFIG_PM |
@@ -1969,6 +1997,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) | |||
1969 | static const struct ath10k_hif_ops ath10k_pci_hif_ops = { | 1997 | static const struct ath10k_hif_ops ath10k_pci_hif_ops = { |
1970 | .tx_sg = ath10k_pci_hif_tx_sg, | 1998 | .tx_sg = ath10k_pci_hif_tx_sg, |
1971 | .diag_read = ath10k_pci_hif_diag_read, | 1999 | .diag_read = ath10k_pci_hif_diag_read, |
2000 | .diag_write = ath10k_pci_diag_write_mem, | ||
1972 | .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, | 2001 | .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, |
1973 | .start = ath10k_pci_hif_start, | 2002 | .start = ath10k_pci_hif_start, |
1974 | .stop = ath10k_pci_hif_stop, | 2003 | .stop = ath10k_pci_hif_stop, |
@@ -1979,6 +2008,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { | |||
1979 | .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, | 2008 | .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, |
1980 | .power_up = ath10k_pci_hif_power_up, | 2009 | .power_up = ath10k_pci_hif_power_up, |
1981 | .power_down = ath10k_pci_hif_power_down, | 2010 | .power_down = ath10k_pci_hif_power_down, |
2011 | .read32 = ath10k_pci_read32, | ||
2012 | .write32 = ath10k_pci_write32, | ||
1982 | #ifdef CONFIG_PM | 2013 | #ifdef CONFIG_PM |
1983 | .suspend = ath10k_pci_hif_suspend, | 2014 | .suspend = ath10k_pci_hif_suspend, |
1984 | .resume = ath10k_pci_hif_resume, | 2015 | .resume = ath10k_pci_hif_resume, |
@@ -2516,6 +2547,8 @@ static int ath10k_pci_probe(struct pci_dev *pdev, | |||
2516 | goto err_deinit_irq; | 2547 | goto err_deinit_irq; |
2517 | } | 2548 | } |
2518 | 2549 | ||
2550 | ath10k_pci_sleep(ar); | ||
2551 | |||
2519 | ret = ath10k_core_register(ar, chip_id); | 2552 | ret = ath10k_core_register(ar, chip_id); |
2520 | if (ret) { | 2553 | if (ret) { |
2521 | ath10k_err(ar, "failed to register driver core: %d\n", ret); | 2554 | ath10k_err(ar, "failed to register driver core: %d\n", ret); |
@@ -2567,7 +2600,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev) | |||
2567 | ath10k_pci_deinit_irq(ar); | 2600 | ath10k_pci_deinit_irq(ar); |
2568 | ath10k_pci_ce_deinit(ar); | 2601 | ath10k_pci_ce_deinit(ar); |
2569 | ath10k_pci_free_pipes(ar); | 2602 | ath10k_pci_free_pipes(ar); |
2570 | ath10k_pci_sleep(ar); | ||
2571 | ath10k_pci_release(ar); | 2603 | ath10k_pci_release(ar); |
2572 | ath10k_core_destroy(ar); | 2604 | ath10k_core_destroy(ar); |
2573 | } | 2605 | } |
diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index 9d34e7f6c455..b289378b6e3e 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h | |||
@@ -20,6 +20,15 @@ | |||
20 | #include <linux/tracepoint.h> | 20 | #include <linux/tracepoint.h> |
21 | #include "core.h" | 21 | #include "core.h" |
22 | 22 | ||
23 | #if !defined(_TRACE_H_) | ||
24 | static inline u32 ath10k_frm_hdr_len(const void *buf) | ||
25 | { | ||
26 | const struct ieee80211_hdr *hdr = buf; | ||
27 | |||
28 | return ieee80211_hdrlen(hdr->frame_control); | ||
29 | } | ||
30 | #endif | ||
31 | |||
23 | #define _TRACE_H_ | 32 | #define _TRACE_H_ |
24 | 33 | ||
25 | /* create empty functions when tracing is disabled */ | 34 | /* create empty functions when tracing is disabled */ |
@@ -138,7 +147,8 @@ TRACE_EVENT(ath10k_log_dbg_dump, | |||
138 | ); | 147 | ); |
139 | 148 | ||
140 | TRACE_EVENT(ath10k_wmi_cmd, | 149 | TRACE_EVENT(ath10k_wmi_cmd, |
141 | TP_PROTO(struct ath10k *ar, int id, void *buf, size_t buf_len, int ret), | 150 | TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len, |
151 | int ret), | ||
142 | 152 | ||
143 | TP_ARGS(ar, id, buf, buf_len, ret), | 153 | TP_ARGS(ar, id, buf, buf_len, ret), |
144 | 154 | ||
@@ -171,7 +181,7 @@ TRACE_EVENT(ath10k_wmi_cmd, | |||
171 | ); | 181 | ); |
172 | 182 | ||
173 | TRACE_EVENT(ath10k_wmi_event, | 183 | TRACE_EVENT(ath10k_wmi_event, |
174 | TP_PROTO(struct ath10k *ar, int id, void *buf, size_t buf_len), | 184 | TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len), |
175 | 185 | ||
176 | TP_ARGS(ar, id, buf, buf_len), | 186 | TP_ARGS(ar, id, buf, buf_len), |
177 | 187 | ||
@@ -201,7 +211,7 @@ TRACE_EVENT(ath10k_wmi_event, | |||
201 | ); | 211 | ); |
202 | 212 | ||
203 | TRACE_EVENT(ath10k_htt_stats, | 213 | TRACE_EVENT(ath10k_htt_stats, |
204 | TP_PROTO(struct ath10k *ar, void *buf, size_t buf_len), | 214 | TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len), |
205 | 215 | ||
206 | TP_ARGS(ar, buf, buf_len), | 216 | TP_ARGS(ar, buf, buf_len), |
207 | 217 | ||
@@ -228,7 +238,7 @@ TRACE_EVENT(ath10k_htt_stats, | |||
228 | ); | 238 | ); |
229 | 239 | ||
230 | TRACE_EVENT(ath10k_wmi_dbglog, | 240 | TRACE_EVENT(ath10k_wmi_dbglog, |
231 | TP_PROTO(struct ath10k *ar, void *buf, size_t buf_len), | 241 | TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len), |
232 | 242 | ||
233 | TP_ARGS(ar, buf, buf_len), | 243 | TP_ARGS(ar, buf, buf_len), |
234 | 244 | ||
@@ -255,7 +265,7 @@ TRACE_EVENT(ath10k_wmi_dbglog, | |||
255 | ); | 265 | ); |
256 | 266 | ||
257 | TRACE_EVENT(ath10k_htt_pktlog, | 267 | TRACE_EVENT(ath10k_htt_pktlog, |
258 | TP_PROTO(struct ath10k *ar, void *buf, u16 buf_len), | 268 | TP_PROTO(struct ath10k *ar, const void *buf, u16 buf_len), |
259 | 269 | ||
260 | TP_ARGS(ar, buf, buf_len), | 270 | TP_ARGS(ar, buf, buf_len), |
261 | 271 | ||
@@ -281,36 +291,6 @@ TRACE_EVENT(ath10k_htt_pktlog, | |||
281 | ) | 291 | ) |
282 | ); | 292 | ); |
283 | 293 | ||
284 | TRACE_EVENT(ath10k_htt_rx_desc, | ||
285 | TP_PROTO(struct ath10k *ar, u32 tsf, void *rxdesc, u16 len), | ||
286 | |||
287 | TP_ARGS(ar, tsf, rxdesc, len), | ||
288 | |||
289 | TP_STRUCT__entry( | ||
290 | __string(device, dev_name(ar->dev)) | ||
291 | __string(driver, dev_driver_string(ar->dev)) | ||
292 | __field(u32, tsf) | ||
293 | __field(u16, len) | ||
294 | __dynamic_array(u8, rxdesc, len) | ||
295 | ), | ||
296 | |||
297 | TP_fast_assign( | ||
298 | __assign_str(device, dev_name(ar->dev)); | ||
299 | __assign_str(driver, dev_driver_string(ar->dev)); | ||
300 | __entry->tsf = tsf; | ||
301 | __entry->len = len; | ||
302 | memcpy(__get_dynamic_array(rxdesc), rxdesc, len); | ||
303 | ), | ||
304 | |||
305 | TP_printk( | ||
306 | "%s %s %u len %hu", | ||
307 | __get_str(driver), | ||
308 | __get_str(device), | ||
309 | __entry->tsf, | ||
310 | __entry->len | ||
311 | ) | ||
312 | ); | ||
313 | |||
314 | TRACE_EVENT(ath10k_htt_tx, | 294 | TRACE_EVENT(ath10k_htt_tx, |
315 | TP_PROTO(struct ath10k *ar, u16 msdu_id, u16 msdu_len, | 295 | TP_PROTO(struct ath10k *ar, u16 msdu_id, u16 msdu_len, |
316 | u8 vdev_id, u8 tid), | 296 | u8 vdev_id, u8 tid), |
@@ -371,8 +351,8 @@ TRACE_EVENT(ath10k_txrx_tx_unref, | |||
371 | ) | 351 | ) |
372 | ); | 352 | ); |
373 | 353 | ||
374 | DECLARE_EVENT_CLASS(ath10k_data_event, | 354 | DECLARE_EVENT_CLASS(ath10k_hdr_event, |
375 | TP_PROTO(struct ath10k *ar, void *data, size_t len), | 355 | TP_PROTO(struct ath10k *ar, const void *data, size_t len), |
376 | 356 | ||
377 | TP_ARGS(ar, data, len), | 357 | TP_ARGS(ar, data, len), |
378 | 358 | ||
@@ -380,14 +360,14 @@ DECLARE_EVENT_CLASS(ath10k_data_event, | |||
380 | __string(device, dev_name(ar->dev)) | 360 | __string(device, dev_name(ar->dev)) |
381 | __string(driver, dev_driver_string(ar->dev)) | 361 | __string(driver, dev_driver_string(ar->dev)) |
382 | __field(size_t, len) | 362 | __field(size_t, len) |
383 | __dynamic_array(u8, data, len) | 363 | __dynamic_array(u8, data, ath10k_frm_hdr_len(data)) |
384 | ), | 364 | ), |
385 | 365 | ||
386 | TP_fast_assign( | 366 | TP_fast_assign( |
387 | __assign_str(device, dev_name(ar->dev)); | 367 | __assign_str(device, dev_name(ar->dev)); |
388 | __assign_str(driver, dev_driver_string(ar->dev)); | 368 | __assign_str(driver, dev_driver_string(ar->dev)); |
389 | __entry->len = len; | 369 | __entry->len = ath10k_frm_hdr_len(data); |
390 | memcpy(__get_dynamic_array(data), data, len); | 370 | memcpy(__get_dynamic_array(data), data, __entry->len); |
391 | ), | 371 | ), |
392 | 372 | ||
393 | TP_printk( | 373 | TP_printk( |
@@ -398,25 +378,81 @@ DECLARE_EVENT_CLASS(ath10k_data_event, | |||
398 | ) | 378 | ) |
399 | ); | 379 | ); |
400 | 380 | ||
401 | DEFINE_EVENT(ath10k_data_event, ath10k_htt_tx_msdu, | 381 | DECLARE_EVENT_CLASS(ath10k_payload_event, |
402 | TP_PROTO(struct ath10k *ar, void *data, size_t len), | 382 | TP_PROTO(struct ath10k *ar, const void *data, size_t len), |
383 | |||
384 | TP_ARGS(ar, data, len), | ||
385 | |||
386 | TP_STRUCT__entry( | ||
387 | __string(device, dev_name(ar->dev)) | ||
388 | __string(driver, dev_driver_string(ar->dev)) | ||
389 | __field(size_t, len) | ||
390 | __dynamic_array(u8, payload, (len - ath10k_frm_hdr_len(data))) | ||
391 | ), | ||
392 | |||
393 | TP_fast_assign( | ||
394 | __assign_str(device, dev_name(ar->dev)); | ||
395 | __assign_str(driver, dev_driver_string(ar->dev)); | ||
396 | __entry->len = len - ath10k_frm_hdr_len(data); | ||
397 | memcpy(__get_dynamic_array(payload), | ||
398 | data + ath10k_frm_hdr_len(data), __entry->len); | ||
399 | ), | ||
400 | |||
401 | TP_printk( | ||
402 | "%s %s len %zu\n", | ||
403 | __get_str(driver), | ||
404 | __get_str(device), | ||
405 | __entry->len | ||
406 | ) | ||
407 | ); | ||
408 | |||
409 | DEFINE_EVENT(ath10k_hdr_event, ath10k_tx_hdr, | ||
410 | TP_PROTO(struct ath10k *ar, const void *data, size_t len), | ||
403 | TP_ARGS(ar, data, len) | 411 | TP_ARGS(ar, data, len) |
404 | ); | 412 | ); |
405 | 413 | ||
406 | DEFINE_EVENT(ath10k_data_event, ath10k_htt_rx_pop_msdu, | 414 | DEFINE_EVENT(ath10k_payload_event, ath10k_tx_payload, |
407 | TP_PROTO(struct ath10k *ar, void *data, size_t len), | 415 | TP_PROTO(struct ath10k *ar, const void *data, size_t len), |
408 | TP_ARGS(ar, data, len) | 416 | TP_ARGS(ar, data, len) |
409 | ); | 417 | ); |
410 | 418 | ||
411 | DEFINE_EVENT(ath10k_data_event, ath10k_wmi_mgmt_tx, | 419 | DEFINE_EVENT(ath10k_hdr_event, ath10k_rx_hdr, |
412 | TP_PROTO(struct ath10k *ar, void *data, size_t len), | 420 | TP_PROTO(struct ath10k *ar, const void *data, size_t len), |
413 | TP_ARGS(ar, data, len) | 421 | TP_ARGS(ar, data, len) |
414 | ); | 422 | ); |
415 | 423 | ||
416 | DEFINE_EVENT(ath10k_data_event, ath10k_wmi_bcn_tx, | 424 | DEFINE_EVENT(ath10k_payload_event, ath10k_rx_payload, |
417 | TP_PROTO(struct ath10k *ar, void *data, size_t len), | 425 | TP_PROTO(struct ath10k *ar, const void *data, size_t len), |
418 | TP_ARGS(ar, data, len) | 426 | TP_ARGS(ar, data, len) |
419 | ); | 427 | ); |
428 | |||
429 | TRACE_EVENT(ath10k_htt_rx_desc, | ||
430 | TP_PROTO(struct ath10k *ar, const void *data, size_t len), | ||
431 | |||
432 | TP_ARGS(ar, data, len), | ||
433 | |||
434 | TP_STRUCT__entry( | ||
435 | __string(device, dev_name(ar->dev)) | ||
436 | __string(driver, dev_driver_string(ar->dev)) | ||
437 | __field(u16, len) | ||
438 | __dynamic_array(u8, rxdesc, len) | ||
439 | ), | ||
440 | |||
441 | TP_fast_assign( | ||
442 | __assign_str(device, dev_name(ar->dev)); | ||
443 | __assign_str(driver, dev_driver_string(ar->dev)); | ||
444 | __entry->len = len; | ||
445 | memcpy(__get_dynamic_array(rxdesc), data, len); | ||
446 | ), | ||
447 | |||
448 | TP_printk( | ||
449 | "%s %s rxdesc len %d", | ||
450 | __get_str(driver), | ||
451 | __get_str(device), | ||
452 | __entry->len | ||
453 | ) | ||
454 | ); | ||
455 | |||
420 | #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ | 456 | #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ |
421 | 457 | ||
422 | /* we don't want to use include/trace/events */ | 458 | /* we don't want to use include/trace/events */ |
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index f9c90e37bc7c..7579de8e7a8c 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c | |||
@@ -146,7 +146,8 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, | |||
146 | mapped = !!ath10k_peer_find(ar, vdev_id, addr); | 146 | mapped = !!ath10k_peer_find(ar, vdev_id, addr); |
147 | spin_unlock_bh(&ar->data_lock); | 147 | spin_unlock_bh(&ar->data_lock); |
148 | 148 | ||
149 | mapped == expect_mapped; | 149 | (mapped == expect_mapped || |
150 | test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)); | ||
150 | }), 3*HZ); | 151 | }), 3*HZ); |
151 | 152 | ||
152 | if (ret <= 0) | 153 | if (ret <= 0) |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index ae746cece211..c0f3e4d09263 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c | |||
@@ -779,6 +779,10 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) | |||
779 | ath10k_wmi_tx_beacons_nowait(ar); | 779 | ath10k_wmi_tx_beacons_nowait(ar); |
780 | 780 | ||
781 | ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id); | 781 | ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id); |
782 | |||
783 | if (ret && test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) | ||
784 | ret = -ESHUTDOWN; | ||
785 | |||
782 | (ret != -EAGAIN); | 786 | (ret != -EAGAIN); |
783 | }), 3*HZ); | 787 | }), 3*HZ); |
784 | 788 | ||
@@ -834,7 +838,8 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) | |||
834 | ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", | 838 | ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", |
835 | wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE, | 839 | wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE, |
836 | fc & IEEE80211_FCTL_STYPE); | 840 | fc & IEEE80211_FCTL_STYPE); |
837 | trace_ath10k_wmi_mgmt_tx(ar, skb->data, skb->len); | 841 | trace_ath10k_tx_hdr(ar, skb->data, skb->len); |
842 | trace_ath10k_tx_payload(ar, skb->data, skb->len); | ||
838 | 843 | ||
839 | /* Send the management frame buffer to the target */ | 844 | /* Send the management frame buffer to the target */ |
840 | ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid); | 845 | ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid); |
@@ -1108,6 +1113,40 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band) | |||
1108 | return rate_idx; | 1113 | return rate_idx; |
1109 | } | 1114 | } |
1110 | 1115 | ||
1116 | /* If keys are configured, HW decrypts all frames | ||
1117 | * with protected bit set. Mark such frames as decrypted. | ||
1118 | */ | ||
1119 | static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar, | ||
1120 | struct sk_buff *skb, | ||
1121 | struct ieee80211_rx_status *status) | ||
1122 | { | ||
1123 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
1124 | unsigned int hdrlen; | ||
1125 | bool peer_key; | ||
1126 | u8 *addr, keyidx; | ||
1127 | |||
1128 | if (!ieee80211_is_auth(hdr->frame_control) || | ||
1129 | !ieee80211_has_protected(hdr->frame_control)) | ||
1130 | return; | ||
1131 | |||
1132 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
1133 | if (skb->len < (hdrlen + IEEE80211_WEP_IV_LEN)) | ||
1134 | return; | ||
1135 | |||
1136 | keyidx = skb->data[hdrlen + (IEEE80211_WEP_IV_LEN - 1)] >> WEP_KEYID_SHIFT; | ||
1137 | addr = ieee80211_get_SA(hdr); | ||
1138 | |||
1139 | spin_lock_bh(&ar->data_lock); | ||
1140 | peer_key = ath10k_mac_is_peer_wep_key_set(ar, addr, keyidx); | ||
1141 | spin_unlock_bh(&ar->data_lock); | ||
1142 | |||
1143 | if (peer_key) { | ||
1144 | ath10k_dbg(ar, ATH10K_DBG_MAC, | ||
1145 | "mac wep key present for peer %pM\n", addr); | ||
1146 | status->flag |= RX_FLAG_DECRYPTED; | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1111 | static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) | 1150 | static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) |
1112 | { | 1151 | { |
1113 | struct wmi_mgmt_rx_event_v1 *ev_v1; | 1152 | struct wmi_mgmt_rx_event_v1 *ev_v1; |
@@ -1161,8 +1200,11 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) | |||
1161 | return 0; | 1200 | return 0; |
1162 | } | 1201 | } |
1163 | 1202 | ||
1164 | if (rx_status & WMI_RX_STATUS_ERR_CRC) | 1203 | if (rx_status & WMI_RX_STATUS_ERR_CRC) { |
1165 | status->flag |= RX_FLAG_FAILED_FCS_CRC; | 1204 | dev_kfree_skb(skb); |
1205 | return 0; | ||
1206 | } | ||
1207 | |||
1166 | if (rx_status & WMI_RX_STATUS_ERR_MIC) | 1208 | if (rx_status & WMI_RX_STATUS_ERR_MIC) |
1167 | status->flag |= RX_FLAG_MMIC_ERROR; | 1209 | status->flag |= RX_FLAG_MMIC_ERROR; |
1168 | 1210 | ||
@@ -1195,6 +1237,8 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) | |||
1195 | hdr = (struct ieee80211_hdr *)skb->data; | 1237 | hdr = (struct ieee80211_hdr *)skb->data; |
1196 | fc = le16_to_cpu(hdr->frame_control); | 1238 | fc = le16_to_cpu(hdr->frame_control); |
1197 | 1239 | ||
1240 | ath10k_wmi_handle_wep_reauth(ar, skb, status); | ||
1241 | |||
1198 | /* FW delivers WEP Shared Auth frame with Protected Bit set and | 1242 | /* FW delivers WEP Shared Auth frame with Protected Bit set and |
1199 | * encrypted payload. However in case of PMF it delivers decrypted | 1243 | * encrypted payload. However in case of PMF it delivers decrypted |
1200 | * frames with Protected Bit set. */ | 1244 | * frames with Protected Bit set. */ |
@@ -1893,7 +1937,9 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) | |||
1893 | arvif->beacon = bcn; | 1937 | arvif->beacon = bcn; |
1894 | arvif->beacon_sent = false; | 1938 | arvif->beacon_sent = false; |
1895 | 1939 | ||
1896 | trace_ath10k_wmi_bcn_tx(ar, bcn->data, bcn->len); | 1940 | trace_ath10k_tx_hdr(ar, bcn->data, bcn->len); |
1941 | trace_ath10k_tx_payload(ar, bcn->data, bcn->len); | ||
1942 | |||
1897 | ath10k_wmi_tx_beacon_nowait(arvif); | 1943 | ath10k_wmi_tx_beacon_nowait(arvif); |
1898 | skip: | 1944 | skip: |
1899 | spin_unlock_bh(&ar->data_lock); | 1945 | spin_unlock_bh(&ar->data_lock); |
@@ -2254,7 +2300,7 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar, | |||
2254 | /* the last byte is always reserved for the null character */ | 2300 | /* the last byte is always reserved for the null character */ |
2255 | buf[i] = '\0'; | 2301 | buf[i] = '\0'; |
2256 | 2302 | ||
2257 | ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf); | 2303 | ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf); |
2258 | } | 2304 | } |
2259 | 2305 | ||
2260 | static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) | 2306 | static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) |
@@ -2411,6 +2457,7 @@ static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb, | |||
2411 | arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; | 2457 | arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; |
2412 | arg->num_mem_reqs = ev->num_mem_reqs; | 2458 | arg->num_mem_reqs = ev->num_mem_reqs; |
2413 | arg->service_map = ev->wmi_service_bitmap; | 2459 | arg->service_map = ev->wmi_service_bitmap; |
2460 | arg->service_map_len = sizeof(ev->wmi_service_bitmap); | ||
2414 | 2461 | ||
2415 | n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), | 2462 | n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), |
2416 | ARRAY_SIZE(arg->mem_reqs)); | 2463 | ARRAY_SIZE(arg->mem_reqs)); |
@@ -2445,6 +2492,7 @@ static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb, | |||
2445 | arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; | 2492 | arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; |
2446 | arg->num_mem_reqs = ev->num_mem_reqs; | 2493 | arg->num_mem_reqs = ev->num_mem_reqs; |
2447 | arg->service_map = ev->wmi_service_bitmap; | 2494 | arg->service_map = ev->wmi_service_bitmap; |
2495 | arg->service_map_len = sizeof(ev->wmi_service_bitmap); | ||
2448 | 2496 | ||
2449 | n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), | 2497 | n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), |
2450 | ARRAY_SIZE(arg->mem_reqs)); | 2498 | ARRAY_SIZE(arg->mem_reqs)); |
@@ -2463,15 +2511,18 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar, | |||
2463 | { | 2511 | { |
2464 | struct wmi_svc_rdy_ev_arg arg = {}; | 2512 | struct wmi_svc_rdy_ev_arg arg = {}; |
2465 | u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; | 2513 | u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; |
2466 | DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {}; | ||
2467 | int ret; | 2514 | int ret; |
2468 | 2515 | ||
2516 | memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); | ||
2517 | |||
2469 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { | 2518 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { |
2470 | ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg); | 2519 | ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg); |
2471 | wmi_10x_svc_map(arg.service_map, svc_bmap); | 2520 | wmi_10x_svc_map(arg.service_map, ar->wmi.svc_map, |
2521 | arg.service_map_len); | ||
2472 | } else { | 2522 | } else { |
2473 | ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg); | 2523 | ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg); |
2474 | wmi_main_svc_map(arg.service_map, svc_bmap); | 2524 | wmi_main_svc_map(arg.service_map, ar->wmi.svc_map, |
2525 | arg.service_map_len); | ||
2475 | } | 2526 | } |
2476 | 2527 | ||
2477 | if (ret) { | 2528 | if (ret) { |
@@ -2493,9 +2544,8 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar, | |||
2493 | ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains); | 2544 | ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains); |
2494 | ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd); | 2545 | ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd); |
2495 | 2546 | ||
2496 | ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); | ||
2497 | ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", | 2547 | ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", |
2498 | arg.service_map, sizeof(arg.service_map)); | 2548 | arg.service_map, arg.service_map_len); |
2499 | 2549 | ||
2500 | /* only manually set fw features when not using FW IE format */ | 2550 | /* only manually set fw features when not using FW IE format */ |
2501 | if (ar->fw_api == 1 && ar->fw_version_build > 636) | 2551 | if (ar->fw_api == 1 && ar->fw_version_build > 636) |
@@ -3135,7 +3185,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) | |||
3135 | u32 len, val; | 3185 | u32 len, val; |
3136 | 3186 | ||
3137 | config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); | 3187 | config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); |
3138 | config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS); | 3188 | config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS); |
3139 | config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS); | 3189 | config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS); |
3140 | 3190 | ||
3141 | config.num_offload_reorder_bufs = | 3191 | config.num_offload_reorder_bufs = |
@@ -4187,9 +4237,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, | |||
4187 | 4237 | ||
4188 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { | 4238 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { |
4189 | if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) | 4239 | if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) |
4190 | ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg); | ||
4191 | else | ||
4192 | ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg); | 4240 | ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg); |
4241 | else | ||
4242 | ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg); | ||
4193 | } else { | 4243 | } else { |
4194 | ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg); | 4244 | ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg); |
4195 | } | 4245 | } |
@@ -4398,7 +4448,6 @@ int ath10k_wmi_attach(struct ath10k *ar) | |||
4398 | 4448 | ||
4399 | init_completion(&ar->wmi.service_ready); | 4449 | init_completion(&ar->wmi.service_ready); |
4400 | init_completion(&ar->wmi.unified_ready); | 4450 | init_completion(&ar->wmi.unified_ready); |
4401 | init_waitqueue_head(&ar->wmi.tx_credits_wq); | ||
4402 | 4451 | ||
4403 | return 0; | 4452 | return 0; |
4404 | } | 4453 | } |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index a38d788a6101..21391929d318 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h | |||
@@ -222,128 +222,131 @@ static inline char *wmi_service_name(int service_id) | |||
222 | #undef SVCSTR | 222 | #undef SVCSTR |
223 | } | 223 | } |
224 | 224 | ||
225 | #define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \ | 225 | #define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ |
226 | (__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ | 226 | ((svc_id) < (len) && \ |
227 | __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ | ||
227 | BIT((svc_id)%(sizeof(u32)))) | 228 | BIT((svc_id)%(sizeof(u32)))) |
228 | 229 | ||
229 | #define SVCMAP(x, y) \ | 230 | #define SVCMAP(x, y, len) \ |
230 | do { \ | 231 | do { \ |
231 | if (WMI_SERVICE_IS_ENABLED((in), (x))) \ | 232 | if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \ |
232 | __set_bit(y, out); \ | 233 | __set_bit(y, out); \ |
233 | } while (0) | 234 | } while (0) |
234 | 235 | ||
235 | static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out) | 236 | static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out, |
237 | size_t len) | ||
236 | { | 238 | { |
237 | SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD, | 239 | SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD, |
238 | WMI_SERVICE_BEACON_OFFLOAD); | 240 | WMI_SERVICE_BEACON_OFFLOAD, len); |
239 | SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD, | 241 | SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD, |
240 | WMI_SERVICE_SCAN_OFFLOAD); | 242 | WMI_SERVICE_SCAN_OFFLOAD, len); |
241 | SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD, | 243 | SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD, |
242 | WMI_SERVICE_ROAM_OFFLOAD); | 244 | WMI_SERVICE_ROAM_OFFLOAD, len); |
243 | SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD, | 245 | SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD, |
244 | WMI_SERVICE_BCN_MISS_OFFLOAD); | 246 | WMI_SERVICE_BCN_MISS_OFFLOAD, len); |
245 | SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE, | 247 | SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE, |
246 | WMI_SERVICE_STA_PWRSAVE); | 248 | WMI_SERVICE_STA_PWRSAVE, len); |
247 | SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE, | 249 | SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE, |
248 | WMI_SERVICE_STA_ADVANCED_PWRSAVE); | 250 | WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); |
249 | SVCMAP(WMI_10X_SERVICE_AP_UAPSD, | 251 | SVCMAP(WMI_10X_SERVICE_AP_UAPSD, |
250 | WMI_SERVICE_AP_UAPSD); | 252 | WMI_SERVICE_AP_UAPSD, len); |
251 | SVCMAP(WMI_10X_SERVICE_AP_DFS, | 253 | SVCMAP(WMI_10X_SERVICE_AP_DFS, |
252 | WMI_SERVICE_AP_DFS); | 254 | WMI_SERVICE_AP_DFS, len); |
253 | SVCMAP(WMI_10X_SERVICE_11AC, | 255 | SVCMAP(WMI_10X_SERVICE_11AC, |
254 | WMI_SERVICE_11AC); | 256 | WMI_SERVICE_11AC, len); |
255 | SVCMAP(WMI_10X_SERVICE_BLOCKACK, | 257 | SVCMAP(WMI_10X_SERVICE_BLOCKACK, |
256 | WMI_SERVICE_BLOCKACK); | 258 | WMI_SERVICE_BLOCKACK, len); |
257 | SVCMAP(WMI_10X_SERVICE_PHYERR, | 259 | SVCMAP(WMI_10X_SERVICE_PHYERR, |
258 | WMI_SERVICE_PHYERR); | 260 | WMI_SERVICE_PHYERR, len); |
259 | SVCMAP(WMI_10X_SERVICE_BCN_FILTER, | 261 | SVCMAP(WMI_10X_SERVICE_BCN_FILTER, |
260 | WMI_SERVICE_BCN_FILTER); | 262 | WMI_SERVICE_BCN_FILTER, len); |
261 | SVCMAP(WMI_10X_SERVICE_RTT, | 263 | SVCMAP(WMI_10X_SERVICE_RTT, |
262 | WMI_SERVICE_RTT); | 264 | WMI_SERVICE_RTT, len); |
263 | SVCMAP(WMI_10X_SERVICE_RATECTRL, | 265 | SVCMAP(WMI_10X_SERVICE_RATECTRL, |
264 | WMI_SERVICE_RATECTRL); | 266 | WMI_SERVICE_RATECTRL, len); |
265 | SVCMAP(WMI_10X_SERVICE_WOW, | 267 | SVCMAP(WMI_10X_SERVICE_WOW, |
266 | WMI_SERVICE_WOW); | 268 | WMI_SERVICE_WOW, len); |
267 | SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE, | 269 | SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE, |
268 | WMI_SERVICE_RATECTRL_CACHE); | 270 | WMI_SERVICE_RATECTRL_CACHE, len); |
269 | SVCMAP(WMI_10X_SERVICE_IRAM_TIDS, | 271 | SVCMAP(WMI_10X_SERVICE_IRAM_TIDS, |
270 | WMI_SERVICE_IRAM_TIDS); | 272 | WMI_SERVICE_IRAM_TIDS, len); |
271 | SVCMAP(WMI_10X_SERVICE_BURST, | 273 | SVCMAP(WMI_10X_SERVICE_BURST, |
272 | WMI_SERVICE_BURST); | 274 | WMI_SERVICE_BURST, len); |
273 | SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT, | 275 | SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT, |
274 | WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT); | 276 | WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, len); |
275 | SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG, | 277 | SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG, |
276 | WMI_SERVICE_FORCE_FW_HANG); | 278 | WMI_SERVICE_FORCE_FW_HANG, len); |
277 | SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT, | 279 | SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT, |
278 | WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT); | 280 | WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len); |
279 | } | 281 | } |
280 | 282 | ||
281 | static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out) | 283 | static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out, |
284 | size_t len) | ||
282 | { | 285 | { |
283 | SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD, | 286 | SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD, |
284 | WMI_SERVICE_BEACON_OFFLOAD); | 287 | WMI_SERVICE_BEACON_OFFLOAD, len); |
285 | SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD, | 288 | SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD, |
286 | WMI_SERVICE_SCAN_OFFLOAD); | 289 | WMI_SERVICE_SCAN_OFFLOAD, len); |
287 | SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD, | 290 | SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD, |
288 | WMI_SERVICE_ROAM_OFFLOAD); | 291 | WMI_SERVICE_ROAM_OFFLOAD, len); |
289 | SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD, | 292 | SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD, |
290 | WMI_SERVICE_BCN_MISS_OFFLOAD); | 293 | WMI_SERVICE_BCN_MISS_OFFLOAD, len); |
291 | SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE, | 294 | SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE, |
292 | WMI_SERVICE_STA_PWRSAVE); | 295 | WMI_SERVICE_STA_PWRSAVE, len); |
293 | SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE, | 296 | SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE, |
294 | WMI_SERVICE_STA_ADVANCED_PWRSAVE); | 297 | WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); |
295 | SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD, | 298 | SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD, |
296 | WMI_SERVICE_AP_UAPSD); | 299 | WMI_SERVICE_AP_UAPSD, len); |
297 | SVCMAP(WMI_MAIN_SERVICE_AP_DFS, | 300 | SVCMAP(WMI_MAIN_SERVICE_AP_DFS, |
298 | WMI_SERVICE_AP_DFS); | 301 | WMI_SERVICE_AP_DFS, len); |
299 | SVCMAP(WMI_MAIN_SERVICE_11AC, | 302 | SVCMAP(WMI_MAIN_SERVICE_11AC, |
300 | WMI_SERVICE_11AC); | 303 | WMI_SERVICE_11AC, len); |
301 | SVCMAP(WMI_MAIN_SERVICE_BLOCKACK, | 304 | SVCMAP(WMI_MAIN_SERVICE_BLOCKACK, |
302 | WMI_SERVICE_BLOCKACK); | 305 | WMI_SERVICE_BLOCKACK, len); |
303 | SVCMAP(WMI_MAIN_SERVICE_PHYERR, | 306 | SVCMAP(WMI_MAIN_SERVICE_PHYERR, |
304 | WMI_SERVICE_PHYERR); | 307 | WMI_SERVICE_PHYERR, len); |
305 | SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER, | 308 | SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER, |
306 | WMI_SERVICE_BCN_FILTER); | 309 | WMI_SERVICE_BCN_FILTER, len); |
307 | SVCMAP(WMI_MAIN_SERVICE_RTT, | 310 | SVCMAP(WMI_MAIN_SERVICE_RTT, |
308 | WMI_SERVICE_RTT); | 311 | WMI_SERVICE_RTT, len); |
309 | SVCMAP(WMI_MAIN_SERVICE_RATECTRL, | 312 | SVCMAP(WMI_MAIN_SERVICE_RATECTRL, |
310 | WMI_SERVICE_RATECTRL); | 313 | WMI_SERVICE_RATECTRL, len); |
311 | SVCMAP(WMI_MAIN_SERVICE_WOW, | 314 | SVCMAP(WMI_MAIN_SERVICE_WOW, |
312 | WMI_SERVICE_WOW); | 315 | WMI_SERVICE_WOW, len); |
313 | SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE, | 316 | SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE, |
314 | WMI_SERVICE_RATECTRL_CACHE); | 317 | WMI_SERVICE_RATECTRL_CACHE, len); |
315 | SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS, | 318 | SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS, |
316 | WMI_SERVICE_IRAM_TIDS); | 319 | WMI_SERVICE_IRAM_TIDS, len); |
317 | SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD, | 320 | SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD, |
318 | WMI_SERVICE_ARPNS_OFFLOAD); | 321 | WMI_SERVICE_ARPNS_OFFLOAD, len); |
319 | SVCMAP(WMI_MAIN_SERVICE_NLO, | 322 | SVCMAP(WMI_MAIN_SERVICE_NLO, |
320 | WMI_SERVICE_NLO); | 323 | WMI_SERVICE_NLO, len); |
321 | SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD, | 324 | SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD, |
322 | WMI_SERVICE_GTK_OFFLOAD); | 325 | WMI_SERVICE_GTK_OFFLOAD, len); |
323 | SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH, | 326 | SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH, |
324 | WMI_SERVICE_SCAN_SCH); | 327 | WMI_SERVICE_SCAN_SCH, len); |
325 | SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD, | 328 | SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD, |
326 | WMI_SERVICE_CSA_OFFLOAD); | 329 | WMI_SERVICE_CSA_OFFLOAD, len); |
327 | SVCMAP(WMI_MAIN_SERVICE_CHATTER, | 330 | SVCMAP(WMI_MAIN_SERVICE_CHATTER, |
328 | WMI_SERVICE_CHATTER); | 331 | WMI_SERVICE_CHATTER, len); |
329 | SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID, | 332 | SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID, |
330 | WMI_SERVICE_COEX_FREQAVOID); | 333 | WMI_SERVICE_COEX_FREQAVOID, len); |
331 | SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE, | 334 | SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE, |
332 | WMI_SERVICE_PACKET_POWER_SAVE); | 335 | WMI_SERVICE_PACKET_POWER_SAVE, len); |
333 | SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG, | 336 | SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG, |
334 | WMI_SERVICE_FORCE_FW_HANG); | 337 | WMI_SERVICE_FORCE_FW_HANG, len); |
335 | SVCMAP(WMI_MAIN_SERVICE_GPIO, | 338 | SVCMAP(WMI_MAIN_SERVICE_GPIO, |
336 | WMI_SERVICE_GPIO); | 339 | WMI_SERVICE_GPIO, len); |
337 | SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM, | 340 | SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM, |
338 | WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM); | 341 | WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len); |
339 | SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, | 342 | SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, |
340 | WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG); | 343 | WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len); |
341 | SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, | 344 | SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, |
342 | WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG); | 345 | WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len); |
343 | SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE, | 346 | SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE, |
344 | WMI_SERVICE_STA_KEEP_ALIVE); | 347 | WMI_SERVICE_STA_KEEP_ALIVE, len); |
345 | SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP, | 348 | SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP, |
346 | WMI_SERVICE_TX_ENCAP); | 349 | WMI_SERVICE_TX_ENCAP, len); |
347 | } | 350 | } |
348 | 351 | ||
349 | #undef SVCMAP | 352 | #undef SVCMAP |
@@ -1952,6 +1955,11 @@ struct wmi_ssid_list { | |||
1952 | #define WLAN_SCAN_PARAMS_MAX_BSSID 4 | 1955 | #define WLAN_SCAN_PARAMS_MAX_BSSID 4 |
1953 | #define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 | 1956 | #define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 |
1954 | 1957 | ||
1958 | /* Values lower than this may be refused by some firmware revisions with a scan | ||
1959 | * completion with a timedout reason. | ||
1960 | */ | ||
1961 | #define WMI_SCAN_CHAN_MIN_TIME_MSEC 40 | ||
1962 | |||
1955 | /* Scan priority numbers must be sequential, starting with 0 */ | 1963 | /* Scan priority numbers must be sequential, starting with 0 */ |
1956 | enum wmi_scan_priority { | 1964 | enum wmi_scan_priority { |
1957 | WMI_SCAN_PRIORITY_VERY_LOW = 0, | 1965 | WMI_SCAN_PRIORITY_VERY_LOW = 0, |
@@ -4547,7 +4555,6 @@ struct wmi_dbglog_cfg_cmd { | |||
4547 | __le32 config_valid; | 4555 | __le32 config_valid; |
4548 | } __packed; | 4556 | } __packed; |
4549 | 4557 | ||
4550 | #define ATH10K_RTS_MAX 2347 | ||
4551 | #define ATH10K_FRAGMT_THRESHOLD_MIN 540 | 4558 | #define ATH10K_FRAGMT_THRESHOLD_MIN 540 |
4552 | #define ATH10K_FRAGMT_THRESHOLD_MAX 2346 | 4559 | #define ATH10K_FRAGMT_THRESHOLD_MAX 2346 |
4553 | 4560 | ||
@@ -4572,6 +4579,7 @@ struct wmi_svc_rdy_ev_arg { | |||
4572 | __le32 eeprom_rd; | 4579 | __le32 eeprom_rd; |
4573 | __le32 num_mem_reqs; | 4580 | __le32 num_mem_reqs; |
4574 | const __le32 *service_map; | 4581 | const __le32 *service_map; |
4582 | size_t service_map_len; | ||
4575 | const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; | 4583 | const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; |
4576 | }; | 4584 | }; |
4577 | 4585 | ||
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index ab2709a43768..19eab2a69ad5 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | |||
@@ -547,7 +547,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
547 | 547 | ||
548 | 548 | ||
549 | static void | 549 | static void |
550 | ath5k_sw_scan_start(struct ieee80211_hw *hw) | 550 | ath5k_sw_scan_start(struct ieee80211_hw *hw, |
551 | struct ieee80211_vif *vif, | ||
552 | const u8 *mac_addr) | ||
551 | { | 553 | { |
552 | struct ath5k_hw *ah = hw->priv; | 554 | struct ath5k_hw *ah = hw->priv; |
553 | if (!ah->assoc) | 555 | if (!ah->assoc) |
@@ -556,7 +558,7 @@ ath5k_sw_scan_start(struct ieee80211_hw *hw) | |||
556 | 558 | ||
557 | 559 | ||
558 | static void | 560 | static void |
559 | ath5k_sw_scan_complete(struct ieee80211_hw *hw) | 561 | ath5k_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
560 | { | 562 | { |
561 | struct ath5k_hw *ah = hw->priv; | 563 | struct ath5k_hw *ah = hw->priv; |
562 | ath5k_hw_set_ledstate(ah, ah->assoc ? | 564 | ath5k_hw_set_ledstate(ah, ah->assoc ? |
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 0583c69d26db..ddaad712c59a 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c | |||
@@ -225,13 +225,7 @@ ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, | |||
225 | } else { | 225 | } else { |
226 | switch (queue_type) { | 226 | switch (queue_type) { |
227 | case AR5K_TX_QUEUE_DATA: | 227 | case AR5K_TX_QUEUE_DATA: |
228 | for (queue = AR5K_TX_QUEUE_ID_DATA_MIN; | 228 | queue = queue_info->tqi_subtype; |
229 | ah->ah_txq[queue].tqi_type != | ||
230 | AR5K_TX_QUEUE_INACTIVE; queue++) { | ||
231 | |||
232 | if (queue > AR5K_TX_QUEUE_ID_DATA_MAX) | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | break; | 229 | break; |
236 | case AR5K_TX_QUEUE_UAPSD: | 230 | case AR5K_TX_QUEUE_UAPSD: |
237 | queue = AR5K_TX_QUEUE_ID_UAPSD; | 231 | queue = AR5K_TX_QUEUE_ID_UAPSD; |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index ba60e37213eb..7a5337877a0c 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -2976,11 +2976,11 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
2976 | static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | 2976 | static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
2977 | 2977 | ||
2978 | static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev, | 2978 | static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev, |
2979 | const u8 *mac) | 2979 | struct station_del_parameters *params) |
2980 | { | 2980 | { |
2981 | struct ath6kl *ar = ath6kl_priv(dev); | 2981 | struct ath6kl *ar = ath6kl_priv(dev); |
2982 | struct ath6kl_vif *vif = netdev_priv(dev); | 2982 | struct ath6kl_vif *vif = netdev_priv(dev); |
2983 | const u8 *addr = mac ? mac : bcast_addr; | 2983 | const u8 *addr = params->mac ? params->mac : bcast_addr; |
2984 | 2984 | ||
2985 | return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH, | 2985 | return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH, |
2986 | addr, WLAN_REASON_PREV_AUTH_NOT_VALID); | 2986 | addr, WLAN_REASON_PREV_AUTH_NOT_VALID); |
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index a6a5e40b3e98..9da3594fd010 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c | |||
@@ -1193,18 +1193,10 @@ static int ath6kl_usb_pm_resume(struct usb_interface *interface) | |||
1193 | return 0; | 1193 | return 0; |
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | static int ath6kl_usb_pm_reset_resume(struct usb_interface *intf) | ||
1197 | { | ||
1198 | if (usb_get_intfdata(intf)) | ||
1199 | ath6kl_usb_remove(intf); | ||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | #else | 1196 | #else |
1204 | 1197 | ||
1205 | #define ath6kl_usb_pm_suspend NULL | 1198 | #define ath6kl_usb_pm_suspend NULL |
1206 | #define ath6kl_usb_pm_resume NULL | 1199 | #define ath6kl_usb_pm_resume NULL |
1207 | #define ath6kl_usb_pm_reset_resume NULL | ||
1208 | 1200 | ||
1209 | #endif | 1201 | #endif |
1210 | 1202 | ||
@@ -1222,7 +1214,6 @@ static struct usb_driver ath6kl_usb_driver = { | |||
1222 | .probe = ath6kl_usb_probe, | 1214 | .probe = ath6kl_usb_probe, |
1223 | .suspend = ath6kl_usb_pm_suspend, | 1215 | .suspend = ath6kl_usb_pm_suspend, |
1224 | .resume = ath6kl_usb_pm_resume, | 1216 | .resume = ath6kl_usb_pm_resume, |
1225 | .reset_resume = ath6kl_usb_pm_reset_resume, | ||
1226 | .disconnect = ath6kl_usb_remove, | 1217 | .disconnect = ath6kl_usb_remove, |
1227 | .id_table = ath6kl_usb_ids, | 1218 | .id_table = ath6kl_usb_ids, |
1228 | .supports_autosuspend = true, | 1219 | .supports_autosuspend = true, |
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index ca101d7cb99f..fee0cadb0f5e 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig | |||
@@ -3,6 +3,8 @@ config ATH9K_HW | |||
3 | config ATH9K_COMMON | 3 | config ATH9K_COMMON |
4 | tristate | 4 | tristate |
5 | select ATH_COMMON | 5 | select ATH_COMMON |
6 | select DEBUG_FS | ||
7 | select RELAY | ||
6 | config ATH9K_DFS_DEBUGFS | 8 | config ATH9K_DFS_DEBUGFS |
7 | def_bool y | 9 | def_bool y |
8 | depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED | 10 | depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED |
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 22b934b07bd4..473972288a84 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile | |||
@@ -16,8 +16,7 @@ ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o | |||
16 | ath9k-$(CONFIG_ATH9K_TX99) += tx99.o | 16 | ath9k-$(CONFIG_ATH9K_TX99) += tx99.o |
17 | ath9k-$(CONFIG_ATH9K_WOW) += wow.o | 17 | ath9k-$(CONFIG_ATH9K_WOW) += wow.o |
18 | 18 | ||
19 | ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o \ | 19 | ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o |
20 | spectral.o | ||
21 | 20 | ||
22 | ath9k-$(CONFIG_ATH9K_STATION_STATISTICS) += debug_sta.o | 21 | ath9k-$(CONFIG_ATH9K_STATION_STATISTICS) += debug_sta.o |
23 | 22 | ||
@@ -59,7 +58,8 @@ obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o | |||
59 | ath9k_common-y:= common.o \ | 58 | ath9k_common-y:= common.o \ |
60 | common-init.o \ | 59 | common-init.o \ |
61 | common-beacon.o \ | 60 | common-beacon.o \ |
62 | common-debug.o | 61 | common-debug.o \ |
62 | common-spectral.o | ||
63 | 63 | ||
64 | ath9k_htc-y += htc_hst.o \ | 64 | ath9k_htc-y += htc_hst.o \ |
65 | hif_usb.o \ | 65 | hif_usb.o \ |
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 2a93519f4bdf..f816909d9474 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c | |||
@@ -281,7 +281,7 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | |||
281 | 281 | ||
282 | ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen) | 282 | ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen) |
283 | | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | 283 | | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) |
284 | | SM(i->txpower, AR_XmitPower0) | 284 | | SM(i->txpower[0], AR_XmitPower0) |
285 | | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | 285 | | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) |
286 | | (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) | 286 | | (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) |
287 | | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | 287 | | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) |
@@ -307,9 +307,9 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | |||
307 | | set11nRateFlags(i->rates, 3) | 307 | | set11nRateFlags(i->rates, 3) |
308 | | SM(i->rtscts_rate, AR_RTSCTSRate); | 308 | | SM(i->rtscts_rate, AR_RTSCTSRate); |
309 | 309 | ||
310 | ACCESS_ONCE(ads->ds_ctl9) = SM(i->txpower, AR_XmitPower1); | 310 | ACCESS_ONCE(ads->ds_ctl9) = SM(i->txpower[1], AR_XmitPower1); |
311 | ACCESS_ONCE(ads->ds_ctl10) = SM(i->txpower, AR_XmitPower2); | 311 | ACCESS_ONCE(ads->ds_ctl10) = SM(i->txpower[2], AR_XmitPower2); |
312 | ACCESS_ONCE(ads->ds_ctl11) = SM(i->txpower, AR_XmitPower3); | 312 | ACCESS_ONCE(ads->ds_ctl11) = SM(i->txpower[3], AR_XmitPower3); |
313 | } | 313 | } |
314 | 314 | ||
315 | static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, | 315 | static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, |
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 9a2afa2c690b..fc08162b5820 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c | |||
@@ -643,9 +643,12 @@ static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, | |||
643 | * and fix otherwise. | 643 | * and fix otherwise. |
644 | */ | 644 | */ |
645 | count = param->count; | 645 | count = param->count; |
646 | if (param->endless) | 646 | if (param->endless) { |
647 | count = 0x80; | 647 | if (AR_SREV_9271(ah)) |
648 | else if (count & 0x80) | 648 | count = 0; |
649 | else | ||
650 | count = 0x80; | ||
651 | } else if (count & 0x80) | ||
649 | count = 0x7f; | 652 | count = 0x7f; |
650 | 653 | ||
651 | REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, | 654 | REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 80c6eacbda53..08225a0067c2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | |||
@@ -4079,27 +4079,28 @@ static int ar9003_hw_get_thermometer(struct ath_hw *ah) | |||
4079 | 4079 | ||
4080 | static void ar9003_hw_thermometer_apply(struct ath_hw *ah) | 4080 | static void ar9003_hw_thermometer_apply(struct ath_hw *ah) |
4081 | { | 4081 | { |
4082 | struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
4082 | int thermometer = ar9003_hw_get_thermometer(ah); | 4083 | int thermometer = ar9003_hw_get_thermometer(ah); |
4083 | u8 therm_on = (thermometer < 0) ? 0 : 1; | 4084 | u8 therm_on = (thermometer < 0) ? 0 : 1; |
4084 | 4085 | ||
4085 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX4, | 4086 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX4, |
4086 | AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); | 4087 | AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); |
4087 | if (ah->caps.tx_chainmask & BIT(1)) | 4088 | if (pCap->chip_chainmask & BIT(1)) |
4088 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX4, | 4089 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX4, |
4089 | AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); | 4090 | AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); |
4090 | if (ah->caps.tx_chainmask & BIT(2)) | 4091 | if (pCap->chip_chainmask & BIT(2)) |
4091 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, | 4092 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, |
4092 | AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); | 4093 | AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); |
4093 | 4094 | ||
4094 | therm_on = (thermometer < 0) ? 0 : (thermometer == 0); | 4095 | therm_on = (thermometer < 0) ? 0 : (thermometer == 0); |
4095 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX4, | 4096 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX4, |
4096 | AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); | 4097 | AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); |
4097 | if (ah->caps.tx_chainmask & BIT(1)) { | 4098 | if (pCap->chip_chainmask & BIT(1)) { |
4098 | therm_on = (thermometer < 0) ? 0 : (thermometer == 1); | 4099 | therm_on = (thermometer < 0) ? 0 : (thermometer == 1); |
4099 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX4, | 4100 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX4, |
4100 | AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); | 4101 | AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); |
4101 | } | 4102 | } |
4102 | if (ah->caps.tx_chainmask & BIT(2)) { | 4103 | if (pCap->chip_chainmask & BIT(2)) { |
4103 | therm_on = (thermometer < 0) ? 0 : (thermometer == 2); | 4104 | therm_on = (thermometer < 0) ? 0 : (thermometer == 2); |
4104 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, | 4105 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, |
4105 | AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); | 4106 | AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); |
@@ -4376,6 +4377,25 @@ static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah, | |||
4376 | targetPowerArray, numPiers); | 4377 | targetPowerArray, numPiers); |
4377 | } | 4378 | } |
4378 | 4379 | ||
4380 | static void ar9003_hw_selfgen_tpc_txpower(struct ath_hw *ah, | ||
4381 | struct ath9k_channel *chan, | ||
4382 | u8 *pwr_array) | ||
4383 | { | ||
4384 | u32 val; | ||
4385 | |||
4386 | /* target power values for self generated frames (ACK,RTS/CTS) */ | ||
4387 | if (IS_CHAN_2GHZ(chan)) { | ||
4388 | val = SM(pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_ACK) | | ||
4389 | SM(pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_CTS) | | ||
4390 | SM(0x3f, AR_TPC_CHIRP) | SM(0x3f, AR_TPC_RPT); | ||
4391 | } else { | ||
4392 | val = SM(pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_ACK) | | ||
4393 | SM(pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_CTS) | | ||
4394 | SM(0x3f, AR_TPC_CHIRP) | SM(0x3f, AR_TPC_RPT); | ||
4395 | } | ||
4396 | REG_WRITE(ah, AR_TPC, val); | ||
4397 | } | ||
4398 | |||
4379 | /* Set tx power registers to array of values passed in */ | 4399 | /* Set tx power registers to array of values passed in */ |
4380 | static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) | 4400 | static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) |
4381 | { | 4401 | { |
@@ -5311,6 +5331,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, | |||
5311 | struct ar9300_modal_eep_header *modal_hdr; | 5331 | struct ar9300_modal_eep_header *modal_hdr; |
5312 | u8 targetPowerValT2[ar9300RateSize]; | 5332 | u8 targetPowerValT2[ar9300RateSize]; |
5313 | u8 target_power_val_t2_eep[ar9300RateSize]; | 5333 | u8 target_power_val_t2_eep[ar9300RateSize]; |
5334 | u8 targetPowerValT2_tpc[ar9300RateSize]; | ||
5314 | unsigned int i = 0, paprd_scale_factor = 0; | 5335 | unsigned int i = 0, paprd_scale_factor = 0; |
5315 | u8 pwr_idx, min_pwridx = 0; | 5336 | u8 pwr_idx, min_pwridx = 0; |
5316 | 5337 | ||
@@ -5362,6 +5383,9 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, | |||
5362 | twiceAntennaReduction, | 5383 | twiceAntennaReduction, |
5363 | powerLimit); | 5384 | powerLimit); |
5364 | 5385 | ||
5386 | memcpy(targetPowerValT2_tpc, targetPowerValT2, | ||
5387 | sizeof(targetPowerValT2)); | ||
5388 | |||
5365 | if (ar9003_is_paprd_enabled(ah)) { | 5389 | if (ar9003_is_paprd_enabled(ah)) { |
5366 | for (i = 0; i < ar9300RateSize; i++) { | 5390 | for (i = 0; i < ar9300RateSize; i++) { |
5367 | if ((ah->paprd_ratemask & (1 << i)) && | 5391 | if ((ah->paprd_ratemask & (1 << i)) && |
@@ -5395,6 +5419,30 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, | |||
5395 | ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); | 5419 | ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); |
5396 | ar9003_hw_calibration_apply(ah, chan->channel); | 5420 | ar9003_hw_calibration_apply(ah, chan->channel); |
5397 | ar9003_paprd_set_txpower(ah, chan, targetPowerValT2); | 5421 | ar9003_paprd_set_txpower(ah, chan, targetPowerValT2); |
5422 | |||
5423 | ar9003_hw_selfgen_tpc_txpower(ah, chan, targetPowerValT2); | ||
5424 | |||
5425 | /* TPC initializations */ | ||
5426 | if (ah->tpc_enabled) { | ||
5427 | u32 val; | ||
5428 | |||
5429 | ar9003_hw_init_rate_txpower(ah, targetPowerValT2_tpc, chan); | ||
5430 | |||
5431 | /* Enable TPC */ | ||
5432 | REG_WRITE(ah, AR_PHY_PWRTX_MAX, | ||
5433 | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); | ||
5434 | /* Disable per chain power reduction */ | ||
5435 | val = REG_READ(ah, AR_PHY_POWER_TX_SUB); | ||
5436 | if (AR_SREV_9340(ah)) | ||
5437 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, | ||
5438 | val & 0xFFFFFFC0); | ||
5439 | else | ||
5440 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, | ||
5441 | val & 0xFFFFF000); | ||
5442 | } else { | ||
5443 | /* Disable TPC */ | ||
5444 | REG_WRITE(ah, AR_PHY_PWRTX_MAX, 0); | ||
5445 | } | ||
5398 | } | 5446 | } |
5399 | 5447 | ||
5400 | static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah, | 5448 | static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah, |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index cb09102245b2..06ad2172030e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c | |||
@@ -333,12 +333,29 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) | |||
333 | qca953x_1p0_soc_preamble); | 333 | qca953x_1p0_soc_preamble); |
334 | INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], | 334 | INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], |
335 | qca953x_1p0_soc_postamble); | 335 | qca953x_1p0_soc_postamble); |
336 | INIT_INI_ARRAY(&ah->iniModesRxGain, | 336 | |
337 | qca953x_1p0_common_wo_xlna_rx_gain_table); | 337 | if (AR_SREV_9531_20(ah)) { |
338 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, | 338 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
339 | qca953x_1p0_common_wo_xlna_rx_gain_bounds); | 339 | qca953x_2p0_common_wo_xlna_rx_gain_table); |
340 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 340 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, |
341 | qca953x_1p0_modes_no_xpa_tx_gain_table); | 341 | qca953x_2p0_common_wo_xlna_rx_gain_bounds); |
342 | } else { | ||
343 | INIT_INI_ARRAY(&ah->iniModesRxGain, | ||
344 | qca953x_1p0_common_wo_xlna_rx_gain_table); | ||
345 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, | ||
346 | qca953x_1p0_common_wo_xlna_rx_gain_bounds); | ||
347 | } | ||
348 | |||
349 | if (AR_SREV_9531_20(ah)) | ||
350 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
351 | qca953x_2p0_modes_no_xpa_tx_gain_table); | ||
352 | else if (AR_SREV_9531_11(ah)) | ||
353 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
354 | qca953x_1p1_modes_no_xpa_tx_gain_table); | ||
355 | else | ||
356 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
357 | qca953x_1p0_modes_no_xpa_tx_gain_table); | ||
358 | |||
342 | INIT_INI_ARRAY(&ah->iniModesFastClock, | 359 | INIT_INI_ARRAY(&ah->iniModesFastClock, |
343 | qca953x_1p0_modes_fast_clock); | 360 | qca953x_1p0_modes_fast_clock); |
344 | } else if (AR_SREV_9580(ah)) { | 361 | } else if (AR_SREV_9580(ah)) { |
@@ -518,9 +535,15 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) | |||
518 | else if (AR_SREV_9550(ah)) | 535 | else if (AR_SREV_9550(ah)) |
519 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 536 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
520 | ar955x_1p0_modes_xpa_tx_gain_table); | 537 | ar955x_1p0_modes_xpa_tx_gain_table); |
521 | else if (AR_SREV_9531(ah)) | 538 | else if (AR_SREV_9531_10(ah)) |
539 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
540 | qca953x_1p0_modes_xpa_tx_gain_table); | ||
541 | else if (AR_SREV_9531_11(ah)) | ||
522 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 542 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
523 | qca953x_1p0_modes_xpa_tx_gain_table); | 543 | qca953x_1p1_modes_xpa_tx_gain_table); |
544 | else if (AR_SREV_9531_20(ah)) | ||
545 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
546 | qca953x_2p0_modes_xpa_tx_gain_table); | ||
524 | else if (AR_SREV_9580(ah)) | 547 | else if (AR_SREV_9580(ah)) |
525 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 548 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
526 | ar9580_1p0_lowest_ob_db_tx_gain_table); | 549 | ar9580_1p0_lowest_ob_db_tx_gain_table); |
@@ -562,7 +585,10 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) | |||
562 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 585 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
563 | ar955x_1p0_modes_no_xpa_tx_gain_table); | 586 | ar955x_1p0_modes_no_xpa_tx_gain_table); |
564 | else if (AR_SREV_9531(ah)) { | 587 | else if (AR_SREV_9531(ah)) { |
565 | if (AR_SREV_9531_11(ah)) | 588 | if (AR_SREV_9531_20(ah)) |
589 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
590 | qca953x_2p0_modes_no_xpa_tx_gain_table); | ||
591 | else if (AR_SREV_9531_11(ah)) | ||
566 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 592 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
567 | qca953x_1p1_modes_no_xpa_tx_gain_table); | 593 | qca953x_1p1_modes_no_xpa_tx_gain_table); |
568 | else | 594 | else |
@@ -789,11 +815,16 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) | |||
789 | ar955x_1p0_common_wo_xlna_rx_gain_table); | 815 | ar955x_1p0_common_wo_xlna_rx_gain_table); |
790 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, | 816 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, |
791 | ar955x_1p0_common_wo_xlna_rx_gain_bounds); | 817 | ar955x_1p0_common_wo_xlna_rx_gain_bounds); |
792 | } else if (AR_SREV_9531(ah)) { | 818 | } else if (AR_SREV_9531_10(ah) || AR_SREV_9531_11(ah)) { |
793 | INIT_INI_ARRAY(&ah->iniModesRxGain, | 819 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
794 | qca953x_1p0_common_wo_xlna_rx_gain_table); | 820 | qca953x_1p0_common_wo_xlna_rx_gain_table); |
795 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, | 821 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, |
796 | qca953x_1p0_common_wo_xlna_rx_gain_bounds); | 822 | qca953x_1p0_common_wo_xlna_rx_gain_bounds); |
823 | } else if (AR_SREV_9531_20(ah)) { | ||
824 | INIT_INI_ARRAY(&ah->iniModesRxGain, | ||
825 | qca953x_2p0_common_wo_xlna_rx_gain_table); | ||
826 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, | ||
827 | qca953x_2p0_common_wo_xlna_rx_gain_bounds); | ||
797 | } else if (AR_SREV_9580(ah)) | 828 | } else if (AR_SREV_9580(ah)) |
798 | INIT_INI_ARRAY(&ah->iniModesRxGain, | 829 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
799 | ar9580_1p0_wo_xlna_rx_gain_table); | 830 | ar9580_1p0_wo_xlna_rx_gain_table); |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 057b1657c428..da84b705cbcd 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c | |||
@@ -101,7 +101,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | |||
101 | 101 | ||
102 | ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen) | 102 | ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen) |
103 | | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | 103 | | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) |
104 | | SM(i->txpower, AR_XmitPower0) | 104 | | SM(i->txpower[0], AR_XmitPower0) |
105 | | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | 105 | | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) |
106 | | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | 106 | | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) |
107 | | (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0) | 107 | | (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0) |
@@ -152,9 +152,9 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | |||
152 | 152 | ||
153 | ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding; | 153 | ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding; |
154 | 154 | ||
155 | ACCESS_ONCE(ads->ctl20) = SM(i->txpower, AR_XmitPower1); | 155 | ACCESS_ONCE(ads->ctl20) = SM(i->txpower[1], AR_XmitPower1); |
156 | ACCESS_ONCE(ads->ctl21) = SM(i->txpower, AR_XmitPower2); | 156 | ACCESS_ONCE(ads->ctl21) = SM(i->txpower[2], AR_XmitPower2); |
157 | ACCESS_ONCE(ads->ctl22) = SM(i->txpower, AR_XmitPower3); | 157 | ACCESS_ONCE(ads->ctl22) = SM(i->txpower[3], AR_XmitPower3); |
158 | } | 158 | } |
159 | 159 | ||
160 | static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) | 160 | static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 9bdaa0afc37f..ae6cde273414 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c | |||
@@ -18,6 +18,21 @@ | |||
18 | #include "hw.h" | 18 | #include "hw.h" |
19 | #include "ar9003_phy.h" | 19 | #include "ar9003_phy.h" |
20 | 20 | ||
21 | #define AR9300_OFDM_RATES 8 | ||
22 | #define AR9300_HT_SS_RATES 8 | ||
23 | #define AR9300_HT_DS_RATES 8 | ||
24 | #define AR9300_HT_TS_RATES 8 | ||
25 | |||
26 | #define AR9300_11NA_OFDM_SHIFT 0 | ||
27 | #define AR9300_11NA_HT_SS_SHIFT 8 | ||
28 | #define AR9300_11NA_HT_DS_SHIFT 16 | ||
29 | #define AR9300_11NA_HT_TS_SHIFT 24 | ||
30 | |||
31 | #define AR9300_11NG_OFDM_SHIFT 4 | ||
32 | #define AR9300_11NG_HT_SS_SHIFT 12 | ||
33 | #define AR9300_11NG_HT_DS_SHIFT 20 | ||
34 | #define AR9300_11NG_HT_TS_SHIFT 28 | ||
35 | |||
21 | static const int firstep_table[] = | 36 | static const int firstep_table[] = |
22 | /* level: 0 1 2 3 4 5 6 7 8 */ | 37 | /* level: 0 1 2 3 4 5 6 7 8 */ |
23 | { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */ | 38 | { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */ |
@@ -40,6 +55,71 @@ static const int m2ThreshLowExt_off = 127; | |||
40 | static const int m1ThreshExt_off = 127; | 55 | static const int m1ThreshExt_off = 127; |
41 | static const int m2ThreshExt_off = 127; | 56 | static const int m2ThreshExt_off = 127; |
42 | 57 | ||
58 | static const u8 ofdm2pwr[] = { | ||
59 | ALL_TARGET_LEGACY_6_24, | ||
60 | ALL_TARGET_LEGACY_6_24, | ||
61 | ALL_TARGET_LEGACY_6_24, | ||
62 | ALL_TARGET_LEGACY_6_24, | ||
63 | ALL_TARGET_LEGACY_6_24, | ||
64 | ALL_TARGET_LEGACY_36, | ||
65 | ALL_TARGET_LEGACY_48, | ||
66 | ALL_TARGET_LEGACY_54 | ||
67 | }; | ||
68 | |||
69 | static const u8 mcs2pwr_ht20[] = { | ||
70 | ALL_TARGET_HT20_0_8_16, | ||
71 | ALL_TARGET_HT20_1_3_9_11_17_19, | ||
72 | ALL_TARGET_HT20_1_3_9_11_17_19, | ||
73 | ALL_TARGET_HT20_1_3_9_11_17_19, | ||
74 | ALL_TARGET_HT20_4, | ||
75 | ALL_TARGET_HT20_5, | ||
76 | ALL_TARGET_HT20_6, | ||
77 | ALL_TARGET_HT20_7, | ||
78 | ALL_TARGET_HT20_0_8_16, | ||
79 | ALL_TARGET_HT20_1_3_9_11_17_19, | ||
80 | ALL_TARGET_HT20_1_3_9_11_17_19, | ||
81 | ALL_TARGET_HT20_1_3_9_11_17_19, | ||
82 | ALL_TARGET_HT20_12, | ||
83 | ALL_TARGET_HT20_13, | ||
84 | ALL_TARGET_HT20_14, | ||
85 | ALL_TARGET_HT20_15, | ||
86 | ALL_TARGET_HT20_0_8_16, | ||
87 | ALL_TARGET_HT20_1_3_9_11_17_19, | ||
88 | ALL_TARGET_HT20_1_3_9_11_17_19, | ||
89 | ALL_TARGET_HT20_1_3_9_11_17_19, | ||
90 | ALL_TARGET_HT20_20, | ||
91 | ALL_TARGET_HT20_21, | ||
92 | ALL_TARGET_HT20_22, | ||
93 | ALL_TARGET_HT20_23 | ||
94 | }; | ||
95 | |||
96 | static const u8 mcs2pwr_ht40[] = { | ||
97 | ALL_TARGET_HT40_0_8_16, | ||
98 | ALL_TARGET_HT40_1_3_9_11_17_19, | ||
99 | ALL_TARGET_HT40_1_3_9_11_17_19, | ||
100 | ALL_TARGET_HT40_1_3_9_11_17_19, | ||
101 | ALL_TARGET_HT40_4, | ||
102 | ALL_TARGET_HT40_5, | ||
103 | ALL_TARGET_HT40_6, | ||
104 | ALL_TARGET_HT40_7, | ||
105 | ALL_TARGET_HT40_0_8_16, | ||
106 | ALL_TARGET_HT40_1_3_9_11_17_19, | ||
107 | ALL_TARGET_HT40_1_3_9_11_17_19, | ||
108 | ALL_TARGET_HT40_1_3_9_11_17_19, | ||
109 | ALL_TARGET_HT40_12, | ||
110 | ALL_TARGET_HT40_13, | ||
111 | ALL_TARGET_HT40_14, | ||
112 | ALL_TARGET_HT40_15, | ||
113 | ALL_TARGET_HT40_0_8_16, | ||
114 | ALL_TARGET_HT40_1_3_9_11_17_19, | ||
115 | ALL_TARGET_HT40_1_3_9_11_17_19, | ||
116 | ALL_TARGET_HT40_1_3_9_11_17_19, | ||
117 | ALL_TARGET_HT40_20, | ||
118 | ALL_TARGET_HT40_21, | ||
119 | ALL_TARGET_HT40_22, | ||
120 | ALL_TARGET_HT40_23, | ||
121 | }; | ||
122 | |||
43 | /** | 123 | /** |
44 | * ar9003_hw_set_channel - set channel on single-chip device | 124 | * ar9003_hw_set_channel - set channel on single-chip device |
45 | * @ah: atheros hardware structure | 125 | * @ah: atheros hardware structure |
@@ -664,6 +744,19 @@ static void ar9003_hw_override_ini(struct ath_hw *ah) | |||
664 | ah->enabled_cals |= TX_CL_CAL; | 744 | ah->enabled_cals |= TX_CL_CAL; |
665 | else | 745 | else |
666 | ah->enabled_cals &= ~TX_CL_CAL; | 746 | ah->enabled_cals &= ~TX_CL_CAL; |
747 | |||
748 | if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) { | ||
749 | if (ah->is_clk_25mhz) { | ||
750 | REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); | ||
751 | REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); | ||
752 | REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); | ||
753 | } else { | ||
754 | REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1); | ||
755 | REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); | ||
756 | REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); | ||
757 | } | ||
758 | udelay(100); | ||
759 | } | ||
667 | } | 760 | } |
668 | 761 | ||
669 | static void ar9003_hw_prog_ini(struct ath_hw *ah, | 762 | static void ar9003_hw_prog_ini(struct ath_hw *ah, |
@@ -1786,6 +1879,100 @@ static void ar9003_hw_tx99_set_txpower(struct ath_hw *ah, u8 txpower) | |||
1786 | ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_14], 0)); | 1879 | ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_14], 0)); |
1787 | } | 1880 | } |
1788 | 1881 | ||
1882 | static void ar9003_hw_init_txpower_cck(struct ath_hw *ah, u8 *rate_array) | ||
1883 | { | ||
1884 | ah->tx_power[0] = rate_array[ALL_TARGET_LEGACY_1L_5L]; | ||
1885 | ah->tx_power[1] = rate_array[ALL_TARGET_LEGACY_1L_5L]; | ||
1886 | ah->tx_power[2] = min(rate_array[ALL_TARGET_LEGACY_1L_5L], | ||
1887 | rate_array[ALL_TARGET_LEGACY_5S]); | ||
1888 | ah->tx_power[3] = min(rate_array[ALL_TARGET_LEGACY_11L], | ||
1889 | rate_array[ALL_TARGET_LEGACY_11S]); | ||
1890 | } | ||
1891 | |||
1892 | static void ar9003_hw_init_txpower_ofdm(struct ath_hw *ah, u8 *rate_array, | ||
1893 | int offset) | ||
1894 | { | ||
1895 | int i, j; | ||
1896 | |||
1897 | for (i = offset; i < offset + AR9300_OFDM_RATES; i++) { | ||
1898 | /* OFDM rate to power table idx */ | ||
1899 | j = ofdm2pwr[i - offset]; | ||
1900 | ah->tx_power[i] = rate_array[j]; | ||
1901 | } | ||
1902 | } | ||
1903 | |||
1904 | static void ar9003_hw_init_txpower_ht(struct ath_hw *ah, u8 *rate_array, | ||
1905 | int ss_offset, int ds_offset, | ||
1906 | int ts_offset, bool is_40) | ||
1907 | { | ||
1908 | int i, j, mcs_idx = 0; | ||
1909 | const u8 *mcs2pwr = (is_40) ? mcs2pwr_ht40 : mcs2pwr_ht20; | ||
1910 | |||
1911 | for (i = ss_offset; i < ss_offset + AR9300_HT_SS_RATES; i++) { | ||
1912 | j = mcs2pwr[mcs_idx]; | ||
1913 | ah->tx_power[i] = rate_array[j]; | ||
1914 | mcs_idx++; | ||
1915 | } | ||
1916 | |||
1917 | for (i = ds_offset; i < ds_offset + AR9300_HT_DS_RATES; i++) { | ||
1918 | j = mcs2pwr[mcs_idx]; | ||
1919 | ah->tx_power[i] = rate_array[j]; | ||
1920 | mcs_idx++; | ||
1921 | } | ||
1922 | |||
1923 | for (i = ts_offset; i < ts_offset + AR9300_HT_TS_RATES; i++) { | ||
1924 | j = mcs2pwr[mcs_idx]; | ||
1925 | ah->tx_power[i] = rate_array[j]; | ||
1926 | mcs_idx++; | ||
1927 | } | ||
1928 | } | ||
1929 | |||
1930 | static void ar9003_hw_init_txpower_stbc(struct ath_hw *ah, int ss_offset, | ||
1931 | int ds_offset, int ts_offset) | ||
1932 | { | ||
1933 | memcpy(&ah->tx_power_stbc[ss_offset], &ah->tx_power[ss_offset], | ||
1934 | AR9300_HT_SS_RATES); | ||
1935 | memcpy(&ah->tx_power_stbc[ds_offset], &ah->tx_power[ds_offset], | ||
1936 | AR9300_HT_DS_RATES); | ||
1937 | memcpy(&ah->tx_power_stbc[ts_offset], &ah->tx_power[ts_offset], | ||
1938 | AR9300_HT_TS_RATES); | ||
1939 | } | ||
1940 | |||
1941 | void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array, | ||
1942 | struct ath9k_channel *chan) | ||
1943 | { | ||
1944 | if (IS_CHAN_5GHZ(chan)) { | ||
1945 | ar9003_hw_init_txpower_ofdm(ah, rate_array, | ||
1946 | AR9300_11NA_OFDM_SHIFT); | ||
1947 | if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) { | ||
1948 | ar9003_hw_init_txpower_ht(ah, rate_array, | ||
1949 | AR9300_11NA_HT_SS_SHIFT, | ||
1950 | AR9300_11NA_HT_DS_SHIFT, | ||
1951 | AR9300_11NA_HT_TS_SHIFT, | ||
1952 | IS_CHAN_HT40(chan)); | ||
1953 | ar9003_hw_init_txpower_stbc(ah, | ||
1954 | AR9300_11NA_HT_SS_SHIFT, | ||
1955 | AR9300_11NA_HT_DS_SHIFT, | ||
1956 | AR9300_11NA_HT_TS_SHIFT); | ||
1957 | } | ||
1958 | } else { | ||
1959 | ar9003_hw_init_txpower_cck(ah, rate_array); | ||
1960 | ar9003_hw_init_txpower_ofdm(ah, rate_array, | ||
1961 | AR9300_11NG_OFDM_SHIFT); | ||
1962 | if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) { | ||
1963 | ar9003_hw_init_txpower_ht(ah, rate_array, | ||
1964 | AR9300_11NG_HT_SS_SHIFT, | ||
1965 | AR9300_11NG_HT_DS_SHIFT, | ||
1966 | AR9300_11NG_HT_TS_SHIFT, | ||
1967 | IS_CHAN_HT40(chan)); | ||
1968 | ar9003_hw_init_txpower_stbc(ah, | ||
1969 | AR9300_11NG_HT_SS_SHIFT, | ||
1970 | AR9300_11NG_HT_DS_SHIFT, | ||
1971 | AR9300_11NG_HT_TS_SHIFT); | ||
1972 | } | ||
1973 | } | ||
1974 | } | ||
1975 | |||
1789 | void ar9003_hw_attach_phy_ops(struct ath_hw *ah) | 1976 | void ar9003_hw_attach_phy_ops(struct ath_hw *ah) |
1790 | { | 1977 | { |
1791 | struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); | 1978 | struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); |
diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h index 812a9d787bf3..159cc6fd2362 100644 --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h | |||
@@ -20,6 +20,8 @@ | |||
20 | 20 | ||
21 | #define qca953x_1p0_mac_postamble ar9300_2p2_mac_postamble | 21 | #define qca953x_1p0_mac_postamble ar9300_2p2_mac_postamble |
22 | 22 | ||
23 | #define qca953x_1p0_soc_preamble ar955x_1p0_soc_preamble | ||
24 | |||
23 | #define qca953x_1p0_soc_postamble ar9300_2p2_soc_postamble | 25 | #define qca953x_1p0_soc_postamble ar9300_2p2_soc_postamble |
24 | 26 | ||
25 | #define qca953x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2 | 27 | #define qca953x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2 |
@@ -28,6 +30,10 @@ | |||
28 | 30 | ||
29 | #define qca953x_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 | 31 | #define qca953x_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 |
30 | 32 | ||
33 | #define qca953x_1p0_common_wo_xlna_rx_gain_bounds ar955x_1p0_common_wo_xlna_rx_gain_bounds | ||
34 | |||
35 | #define qca953x_1p0_common_rx_gain_bounds ar955x_1p0_common_rx_gain_bounds | ||
36 | |||
31 | static const u32 qca953x_1p0_mac_core[][2] = { | 37 | static const u32 qca953x_1p0_mac_core[][2] = { |
32 | /* Addr allmodes */ | 38 | /* Addr allmodes */ |
33 | {0x00000008, 0x00000000}, | 39 | {0x00000008, 0x00000000}, |
@@ -490,35 +496,6 @@ static const u32 qca953x_1p0_radio_postamble[][5] = { | |||
490 | {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, | 496 | {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, |
491 | }; | 497 | }; |
492 | 498 | ||
493 | static const u32 qca953x_1p0_soc_preamble[][2] = { | ||
494 | /* Addr allmodes */ | ||
495 | {0x00007000, 0x00000000}, | ||
496 | {0x00007004, 0x00000000}, | ||
497 | {0x00007008, 0x00000000}, | ||
498 | {0x0000700c, 0x00000000}, | ||
499 | {0x0000701c, 0x00000000}, | ||
500 | {0x00007020, 0x00000000}, | ||
501 | {0x00007024, 0x00000000}, | ||
502 | {0x00007028, 0x00000000}, | ||
503 | {0x0000702c, 0x00000000}, | ||
504 | {0x00007030, 0x00000000}, | ||
505 | {0x00007034, 0x00000002}, | ||
506 | {0x00007038, 0x000004c2}, | ||
507 | {0x00007048, 0x00000000}, | ||
508 | }; | ||
509 | |||
510 | static const u32 qca953x_1p0_common_rx_gain_bounds[][5] = { | ||
511 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
512 | {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, | ||
513 | {0x00009e48, 0x5030201a, 0x5030201a, 0x50302018, 0x50302018}, | ||
514 | }; | ||
515 | |||
516 | static const u32 qca953x_1p0_common_wo_xlna_rx_gain_bounds[][5] = { | ||
517 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
518 | {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, | ||
519 | {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, | ||
520 | }; | ||
521 | |||
522 | static const u32 qca953x_1p0_modes_xpa_tx_gain_table[][2] = { | 499 | static const u32 qca953x_1p0_modes_xpa_tx_gain_table[][2] = { |
523 | /* Addr allmodes */ | 500 | /* Addr allmodes */ |
524 | {0x0000a2dc, 0xfffd5aaa}, | 501 | {0x0000a2dc, 0xfffd5aaa}, |
@@ -715,8 +692,73 @@ static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = { | |||
715 | {0x00016448, 0x6c927a70}, | 692 | {0x00016448, 0x6c927a70}, |
716 | }; | 693 | }; |
717 | 694 | ||
695 | static const u32 qca953x_1p1_modes_xpa_tx_gain_table[][2] = { | ||
696 | /* Addr allmodes */ | ||
697 | {0x0000a2dc, 0xfffb52aa}, | ||
698 | {0x0000a2e0, 0xfffd64cc}, | ||
699 | {0x0000a2e4, 0xfffe80f0}, | ||
700 | {0x0000a2e8, 0xffffff00}, | ||
701 | {0x0000a410, 0x000050d5}, | ||
702 | {0x0000a500, 0x00000000}, | ||
703 | {0x0000a504, 0x04000002}, | ||
704 | {0x0000a508, 0x08000004}, | ||
705 | {0x0000a50c, 0x0c000006}, | ||
706 | {0x0000a510, 0x1000000a}, | ||
707 | {0x0000a514, 0x1400000c}, | ||
708 | {0x0000a518, 0x1800000e}, | ||
709 | {0x0000a51c, 0x1c000048}, | ||
710 | {0x0000a520, 0x2000004a}, | ||
711 | {0x0000a524, 0x2400004c}, | ||
712 | {0x0000a528, 0x2800004e}, | ||
713 | {0x0000a52c, 0x2b00024a}, | ||
714 | {0x0000a530, 0x2f00024c}, | ||
715 | {0x0000a534, 0x3300024e}, | ||
716 | {0x0000a538, 0x36000668}, | ||
717 | {0x0000a53c, 0x38000669}, | ||
718 | {0x0000a540, 0x3a000868}, | ||
719 | {0x0000a544, 0x3d00086a}, | ||
720 | {0x0000a548, 0x4000086c}, | ||
721 | {0x0000a54c, 0x4200086e}, | ||
722 | {0x0000a550, 0x43000a6e}, | ||
723 | {0x0000a554, 0x43000a6e}, | ||
724 | {0x0000a558, 0x43000a6e}, | ||
725 | {0x0000a55c, 0x43000a6e}, | ||
726 | {0x0000a560, 0x43000a6e}, | ||
727 | {0x0000a564, 0x43000a6e}, | ||
728 | {0x0000a568, 0x43000a6e}, | ||
729 | {0x0000a56c, 0x43000a6e}, | ||
730 | {0x0000a570, 0x43000a6e}, | ||
731 | {0x0000a574, 0x43000a6e}, | ||
732 | {0x0000a578, 0x43000a6e}, | ||
733 | {0x0000a57c, 0x43000a6e}, | ||
734 | {0x0000a600, 0x00000000}, | ||
735 | {0x0000a604, 0x00000000}, | ||
736 | {0x0000a608, 0x00000000}, | ||
737 | {0x0000a60c, 0x03804000}, | ||
738 | {0x0000a610, 0x03804e01}, | ||
739 | {0x0000a614, 0x03804e01}, | ||
740 | {0x0000a618, 0x03804e01}, | ||
741 | {0x0000a61c, 0x04009002}, | ||
742 | {0x0000a620, 0x04009002}, | ||
743 | {0x0000a624, 0x04009002}, | ||
744 | {0x0000a628, 0x04009002}, | ||
745 | {0x0000a62c, 0x04009002}, | ||
746 | {0x0000a630, 0x04009002}, | ||
747 | {0x0000a634, 0x04009002}, | ||
748 | {0x0000a638, 0x04009002}, | ||
749 | {0x0000a63c, 0x04009002}, | ||
750 | {0x0000b2dc, 0xfffb52aa}, | ||
751 | {0x0000b2e0, 0xfffd64cc}, | ||
752 | {0x0000b2e4, 0xfffe80f0}, | ||
753 | {0x0000b2e8, 0xffffff00}, | ||
754 | {0x00016044, 0x024922db}, | ||
755 | {0x00016048, 0x6c927a70}, | ||
756 | {0x00016444, 0x024922db}, | ||
757 | {0x00016448, 0x6c927a70}, | ||
758 | }; | ||
759 | |||
718 | static const u32 qca953x_2p0_baseband_core[][2] = { | 760 | static const u32 qca953x_2p0_baseband_core[][2] = { |
719 | /* Addr allmodes */ | 761 | /* Addr allmodes */ |
720 | {0x00009800, 0xafe68e30}, | 762 | {0x00009800, 0xafe68e30}, |
721 | {0x00009804, 0xfd14e000}, | 763 | {0x00009804, 0xfd14e000}, |
722 | {0x00009808, 0x9c0a9f6b}, | 764 | {0x00009808, 0x9c0a9f6b}, |
@@ -914,4 +956,400 @@ static const u32 qca953x_2p0_baseband_postamble[][5] = { | |||
914 | {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, | 956 | {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, |
915 | }; | 957 | }; |
916 | 958 | ||
959 | static const u32 qca953x_2p0_common_wo_xlna_rx_gain_table[][2] = { | ||
960 | /* Addr allmodes */ | ||
961 | {0x0000a000, 0x00010000}, | ||
962 | {0x0000a004, 0x00030002}, | ||
963 | {0x0000a008, 0x00050004}, | ||
964 | {0x0000a00c, 0x00810080}, | ||
965 | {0x0000a010, 0x00830082}, | ||
966 | {0x0000a014, 0x01810180}, | ||
967 | {0x0000a018, 0x01830182}, | ||
968 | {0x0000a01c, 0x01850184}, | ||
969 | {0x0000a020, 0x01890188}, | ||
970 | {0x0000a024, 0x018b018a}, | ||
971 | {0x0000a028, 0x018d018c}, | ||
972 | {0x0000a02c, 0x03820190}, | ||
973 | {0x0000a030, 0x03840383}, | ||
974 | {0x0000a034, 0x03880385}, | ||
975 | {0x0000a038, 0x038a0389}, | ||
976 | {0x0000a03c, 0x038c038b}, | ||
977 | {0x0000a040, 0x0390038d}, | ||
978 | {0x0000a044, 0x03920391}, | ||
979 | {0x0000a048, 0x03940393}, | ||
980 | {0x0000a04c, 0x03960395}, | ||
981 | {0x0000a050, 0x00000000}, | ||
982 | {0x0000a054, 0x00000000}, | ||
983 | {0x0000a058, 0x00000000}, | ||
984 | {0x0000a05c, 0x00000000}, | ||
985 | {0x0000a060, 0x00000000}, | ||
986 | {0x0000a064, 0x00000000}, | ||
987 | {0x0000a068, 0x00000000}, | ||
988 | {0x0000a06c, 0x00000000}, | ||
989 | {0x0000a070, 0x00000000}, | ||
990 | {0x0000a074, 0x00000000}, | ||
991 | {0x0000a078, 0x00000000}, | ||
992 | {0x0000a07c, 0x00000000}, | ||
993 | {0x0000a080, 0x29292929}, | ||
994 | {0x0000a084, 0x29292929}, | ||
995 | {0x0000a088, 0x29292929}, | ||
996 | {0x0000a08c, 0x29292929}, | ||
997 | {0x0000a090, 0x22292929}, | ||
998 | {0x0000a094, 0x1d1d2222}, | ||
999 | {0x0000a098, 0x0c111117}, | ||
1000 | {0x0000a09c, 0x00030303}, | ||
1001 | {0x0000a0a0, 0x00000000}, | ||
1002 | {0x0000a0a4, 0x00000000}, | ||
1003 | {0x0000a0a8, 0x00000000}, | ||
1004 | {0x0000a0ac, 0x00000000}, | ||
1005 | {0x0000a0b0, 0x00000000}, | ||
1006 | {0x0000a0b4, 0x00000000}, | ||
1007 | {0x0000a0b8, 0x00000000}, | ||
1008 | {0x0000a0bc, 0x00000000}, | ||
1009 | {0x0000a0c0, 0x001f0000}, | ||
1010 | {0x0000a0c4, 0x01000101}, | ||
1011 | {0x0000a0c8, 0x011e011f}, | ||
1012 | {0x0000a0cc, 0x011c011d}, | ||
1013 | {0x0000a0d0, 0x02030204}, | ||
1014 | {0x0000a0d4, 0x02010202}, | ||
1015 | {0x0000a0d8, 0x021f0200}, | ||
1016 | {0x0000a0dc, 0x0302021e}, | ||
1017 | {0x0000a0e0, 0x03000301}, | ||
1018 | {0x0000a0e4, 0x031e031f}, | ||
1019 | {0x0000a0e8, 0x0402031d}, | ||
1020 | {0x0000a0ec, 0x04000401}, | ||
1021 | {0x0000a0f0, 0x041e041f}, | ||
1022 | {0x0000a0f4, 0x0502041d}, | ||
1023 | {0x0000a0f8, 0x05000501}, | ||
1024 | {0x0000a0fc, 0x051e051f}, | ||
1025 | {0x0000a100, 0x06010602}, | ||
1026 | {0x0000a104, 0x061f0600}, | ||
1027 | {0x0000a108, 0x061d061e}, | ||
1028 | {0x0000a10c, 0x07020703}, | ||
1029 | {0x0000a110, 0x07000701}, | ||
1030 | {0x0000a114, 0x00000000}, | ||
1031 | {0x0000a118, 0x00000000}, | ||
1032 | {0x0000a11c, 0x00000000}, | ||
1033 | {0x0000a120, 0x00000000}, | ||
1034 | {0x0000a124, 0x00000000}, | ||
1035 | {0x0000a128, 0x00000000}, | ||
1036 | {0x0000a12c, 0x00000000}, | ||
1037 | {0x0000a130, 0x00000000}, | ||
1038 | {0x0000a134, 0x00000000}, | ||
1039 | {0x0000a138, 0x00000000}, | ||
1040 | {0x0000a13c, 0x00000000}, | ||
1041 | {0x0000a140, 0x001f0000}, | ||
1042 | {0x0000a144, 0x01000101}, | ||
1043 | {0x0000a148, 0x011e011f}, | ||
1044 | {0x0000a14c, 0x011c011d}, | ||
1045 | {0x0000a150, 0x02030204}, | ||
1046 | {0x0000a154, 0x02010202}, | ||
1047 | {0x0000a158, 0x021f0200}, | ||
1048 | {0x0000a15c, 0x0302021e}, | ||
1049 | {0x0000a160, 0x03000301}, | ||
1050 | {0x0000a164, 0x031e031f}, | ||
1051 | {0x0000a168, 0x0402031d}, | ||
1052 | {0x0000a16c, 0x04000401}, | ||
1053 | {0x0000a170, 0x041e041f}, | ||
1054 | {0x0000a174, 0x0502041d}, | ||
1055 | {0x0000a178, 0x05000501}, | ||
1056 | {0x0000a17c, 0x051e051f}, | ||
1057 | {0x0000a180, 0x06010602}, | ||
1058 | {0x0000a184, 0x061f0600}, | ||
1059 | {0x0000a188, 0x061d061e}, | ||
1060 | {0x0000a18c, 0x07020703}, | ||
1061 | {0x0000a190, 0x07000701}, | ||
1062 | {0x0000a194, 0x00000000}, | ||
1063 | {0x0000a198, 0x00000000}, | ||
1064 | {0x0000a19c, 0x00000000}, | ||
1065 | {0x0000a1a0, 0x00000000}, | ||
1066 | {0x0000a1a4, 0x00000000}, | ||
1067 | {0x0000a1a8, 0x00000000}, | ||
1068 | {0x0000a1ac, 0x00000000}, | ||
1069 | {0x0000a1b0, 0x00000000}, | ||
1070 | {0x0000a1b4, 0x00000000}, | ||
1071 | {0x0000a1b8, 0x00000000}, | ||
1072 | {0x0000a1bc, 0x00000000}, | ||
1073 | {0x0000a1c0, 0x00000000}, | ||
1074 | {0x0000a1c4, 0x00000000}, | ||
1075 | {0x0000a1c8, 0x00000000}, | ||
1076 | {0x0000a1cc, 0x00000000}, | ||
1077 | {0x0000a1d0, 0x00000000}, | ||
1078 | {0x0000a1d4, 0x00000000}, | ||
1079 | {0x0000a1d8, 0x00000000}, | ||
1080 | {0x0000a1dc, 0x00000000}, | ||
1081 | {0x0000a1e0, 0x00000000}, | ||
1082 | {0x0000a1e4, 0x00000000}, | ||
1083 | {0x0000a1e8, 0x00000000}, | ||
1084 | {0x0000a1ec, 0x00000000}, | ||
1085 | {0x0000a1f0, 0x00000396}, | ||
1086 | {0x0000a1f4, 0x00000396}, | ||
1087 | {0x0000a1f8, 0x00000396}, | ||
1088 | {0x0000a1fc, 0x00000196}, | ||
1089 | {0x0000b000, 0x00010000}, | ||
1090 | {0x0000b004, 0x00030002}, | ||
1091 | {0x0000b008, 0x00050004}, | ||
1092 | {0x0000b00c, 0x00810080}, | ||
1093 | {0x0000b010, 0x00830082}, | ||
1094 | {0x0000b014, 0x01810180}, | ||
1095 | {0x0000b018, 0x01830182}, | ||
1096 | {0x0000b01c, 0x01850184}, | ||
1097 | {0x0000b020, 0x02810280}, | ||
1098 | {0x0000b024, 0x02830282}, | ||
1099 | {0x0000b028, 0x02850284}, | ||
1100 | {0x0000b02c, 0x02890288}, | ||
1101 | {0x0000b030, 0x028b028a}, | ||
1102 | {0x0000b034, 0x0388028c}, | ||
1103 | {0x0000b038, 0x038a0389}, | ||
1104 | {0x0000b03c, 0x038c038b}, | ||
1105 | {0x0000b040, 0x0390038d}, | ||
1106 | {0x0000b044, 0x03920391}, | ||
1107 | {0x0000b048, 0x03940393}, | ||
1108 | {0x0000b04c, 0x03960395}, | ||
1109 | {0x0000b050, 0x00000000}, | ||
1110 | {0x0000b054, 0x00000000}, | ||
1111 | {0x0000b058, 0x00000000}, | ||
1112 | {0x0000b05c, 0x00000000}, | ||
1113 | {0x0000b060, 0x00000000}, | ||
1114 | {0x0000b064, 0x00000000}, | ||
1115 | {0x0000b068, 0x00000000}, | ||
1116 | {0x0000b06c, 0x00000000}, | ||
1117 | {0x0000b070, 0x00000000}, | ||
1118 | {0x0000b074, 0x00000000}, | ||
1119 | {0x0000b078, 0x00000000}, | ||
1120 | {0x0000b07c, 0x00000000}, | ||
1121 | {0x0000b080, 0x32323232}, | ||
1122 | {0x0000b084, 0x2f2f3232}, | ||
1123 | {0x0000b088, 0x23282a2d}, | ||
1124 | {0x0000b08c, 0x1c1e2123}, | ||
1125 | {0x0000b090, 0x14171919}, | ||
1126 | {0x0000b094, 0x0e0e1214}, | ||
1127 | {0x0000b098, 0x03050707}, | ||
1128 | {0x0000b09c, 0x00030303}, | ||
1129 | {0x0000b0a0, 0x00000000}, | ||
1130 | {0x0000b0a4, 0x00000000}, | ||
1131 | {0x0000b0a8, 0x00000000}, | ||
1132 | {0x0000b0ac, 0x00000000}, | ||
1133 | {0x0000b0b0, 0x00000000}, | ||
1134 | {0x0000b0b4, 0x00000000}, | ||
1135 | {0x0000b0b8, 0x00000000}, | ||
1136 | {0x0000b0bc, 0x00000000}, | ||
1137 | {0x0000b0c0, 0x003f0020}, | ||
1138 | {0x0000b0c4, 0x00400041}, | ||
1139 | {0x0000b0c8, 0x0140005f}, | ||
1140 | {0x0000b0cc, 0x0160015f}, | ||
1141 | {0x0000b0d0, 0x017e017f}, | ||
1142 | {0x0000b0d4, 0x02410242}, | ||
1143 | {0x0000b0d8, 0x025f0240}, | ||
1144 | {0x0000b0dc, 0x027f0260}, | ||
1145 | {0x0000b0e0, 0x0341027e}, | ||
1146 | {0x0000b0e4, 0x035f0340}, | ||
1147 | {0x0000b0e8, 0x037f0360}, | ||
1148 | {0x0000b0ec, 0x04400441}, | ||
1149 | {0x0000b0f0, 0x0460045f}, | ||
1150 | {0x0000b0f4, 0x0541047f}, | ||
1151 | {0x0000b0f8, 0x055f0540}, | ||
1152 | {0x0000b0fc, 0x057f0560}, | ||
1153 | {0x0000b100, 0x06400641}, | ||
1154 | {0x0000b104, 0x0660065f}, | ||
1155 | {0x0000b108, 0x067e067f}, | ||
1156 | {0x0000b10c, 0x07410742}, | ||
1157 | {0x0000b110, 0x075f0740}, | ||
1158 | {0x0000b114, 0x077f0760}, | ||
1159 | {0x0000b118, 0x07800781}, | ||
1160 | {0x0000b11c, 0x07a0079f}, | ||
1161 | {0x0000b120, 0x07c107bf}, | ||
1162 | {0x0000b124, 0x000007c0}, | ||
1163 | {0x0000b128, 0x00000000}, | ||
1164 | {0x0000b12c, 0x00000000}, | ||
1165 | {0x0000b130, 0x00000000}, | ||
1166 | {0x0000b134, 0x00000000}, | ||
1167 | {0x0000b138, 0x00000000}, | ||
1168 | {0x0000b13c, 0x00000000}, | ||
1169 | {0x0000b140, 0x003f0020}, | ||
1170 | {0x0000b144, 0x00400041}, | ||
1171 | {0x0000b148, 0x0140005f}, | ||
1172 | {0x0000b14c, 0x0160015f}, | ||
1173 | {0x0000b150, 0x017e017f}, | ||
1174 | {0x0000b154, 0x02410242}, | ||
1175 | {0x0000b158, 0x025f0240}, | ||
1176 | {0x0000b15c, 0x027f0260}, | ||
1177 | {0x0000b160, 0x0341027e}, | ||
1178 | {0x0000b164, 0x035f0340}, | ||
1179 | {0x0000b168, 0x037f0360}, | ||
1180 | {0x0000b16c, 0x04400441}, | ||
1181 | {0x0000b170, 0x0460045f}, | ||
1182 | {0x0000b174, 0x0541047f}, | ||
1183 | {0x0000b178, 0x055f0540}, | ||
1184 | {0x0000b17c, 0x057f0560}, | ||
1185 | {0x0000b180, 0x06400641}, | ||
1186 | {0x0000b184, 0x0660065f}, | ||
1187 | {0x0000b188, 0x067e067f}, | ||
1188 | {0x0000b18c, 0x07410742}, | ||
1189 | {0x0000b190, 0x075f0740}, | ||
1190 | {0x0000b194, 0x077f0760}, | ||
1191 | {0x0000b198, 0x07800781}, | ||
1192 | {0x0000b19c, 0x07a0079f}, | ||
1193 | {0x0000b1a0, 0x07c107bf}, | ||
1194 | {0x0000b1a4, 0x000007c0}, | ||
1195 | {0x0000b1a8, 0x00000000}, | ||
1196 | {0x0000b1ac, 0x00000000}, | ||
1197 | {0x0000b1b0, 0x00000000}, | ||
1198 | {0x0000b1b4, 0x00000000}, | ||
1199 | {0x0000b1b8, 0x00000000}, | ||
1200 | {0x0000b1bc, 0x00000000}, | ||
1201 | {0x0000b1c0, 0x00000000}, | ||
1202 | {0x0000b1c4, 0x00000000}, | ||
1203 | {0x0000b1c8, 0x00000000}, | ||
1204 | {0x0000b1cc, 0x00000000}, | ||
1205 | {0x0000b1d0, 0x00000000}, | ||
1206 | {0x0000b1d4, 0x00000000}, | ||
1207 | {0x0000b1d8, 0x00000000}, | ||
1208 | {0x0000b1dc, 0x00000000}, | ||
1209 | {0x0000b1e0, 0x00000000}, | ||
1210 | {0x0000b1e4, 0x00000000}, | ||
1211 | {0x0000b1e8, 0x00000000}, | ||
1212 | {0x0000b1ec, 0x00000000}, | ||
1213 | {0x0000b1f0, 0x00000396}, | ||
1214 | {0x0000b1f4, 0x00000396}, | ||
1215 | {0x0000b1f8, 0x00000396}, | ||
1216 | {0x0000b1fc, 0x00000196}, | ||
1217 | }; | ||
1218 | |||
1219 | static const u32 qca953x_2p0_common_wo_xlna_rx_gain_bounds[][5] = { | ||
1220 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
1221 | {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, | ||
1222 | {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, | ||
1223 | }; | ||
1224 | |||
1225 | static const u32 qca953x_2p0_modes_xpa_tx_gain_table[][2] = { | ||
1226 | /* Addr allmodes */ | ||
1227 | {0x0000a2dc, 0xfffb52aa}, | ||
1228 | {0x0000a2e0, 0xfffd64cc}, | ||
1229 | {0x0000a2e4, 0xfffe80f0}, | ||
1230 | {0x0000a2e8, 0xffffff00}, | ||
1231 | {0x0000a410, 0x000050d5}, | ||
1232 | {0x0000a500, 0x00000000}, | ||
1233 | {0x0000a504, 0x04000002}, | ||
1234 | {0x0000a508, 0x08000004}, | ||
1235 | {0x0000a50c, 0x0c000006}, | ||
1236 | {0x0000a510, 0x1000000a}, | ||
1237 | {0x0000a514, 0x1400000c}, | ||
1238 | {0x0000a518, 0x1800000e}, | ||
1239 | {0x0000a51c, 0x1c000048}, | ||
1240 | {0x0000a520, 0x2000004a}, | ||
1241 | {0x0000a524, 0x2400004c}, | ||
1242 | {0x0000a528, 0x2800004e}, | ||
1243 | {0x0000a52c, 0x2b00024a}, | ||
1244 | {0x0000a530, 0x2f00024c}, | ||
1245 | {0x0000a534, 0x3300024e}, | ||
1246 | {0x0000a538, 0x36000668}, | ||
1247 | {0x0000a53c, 0x38000669}, | ||
1248 | {0x0000a540, 0x3a000868}, | ||
1249 | {0x0000a544, 0x3d00086a}, | ||
1250 | {0x0000a548, 0x4000086c}, | ||
1251 | {0x0000a54c, 0x4200086e}, | ||
1252 | {0x0000a550, 0x43000a6e}, | ||
1253 | {0x0000a554, 0x43000a6e}, | ||
1254 | {0x0000a558, 0x43000a6e}, | ||
1255 | {0x0000a55c, 0x43000a6e}, | ||
1256 | {0x0000a560, 0x43000a6e}, | ||
1257 | {0x0000a564, 0x43000a6e}, | ||
1258 | {0x0000a568, 0x43000a6e}, | ||
1259 | {0x0000a56c, 0x43000a6e}, | ||
1260 | {0x0000a570, 0x43000a6e}, | ||
1261 | {0x0000a574, 0x43000a6e}, | ||
1262 | {0x0000a578, 0x43000a6e}, | ||
1263 | {0x0000a57c, 0x43000a6e}, | ||
1264 | {0x0000a600, 0x00000000}, | ||
1265 | {0x0000a604, 0x00000000}, | ||
1266 | {0x0000a608, 0x00000000}, | ||
1267 | {0x0000a60c, 0x03804000}, | ||
1268 | {0x0000a610, 0x03804e01}, | ||
1269 | {0x0000a614, 0x03804e01}, | ||
1270 | {0x0000a618, 0x03804e01}, | ||
1271 | {0x0000a61c, 0x04009002}, | ||
1272 | {0x0000a620, 0x04009002}, | ||
1273 | {0x0000a624, 0x04009002}, | ||
1274 | {0x0000a628, 0x04009002}, | ||
1275 | {0x0000a62c, 0x04009002}, | ||
1276 | {0x0000a630, 0x04009002}, | ||
1277 | {0x0000a634, 0x04009002}, | ||
1278 | {0x0000a638, 0x04009002}, | ||
1279 | {0x0000a63c, 0x04009002}, | ||
1280 | {0x0000b2dc, 0xfffb52aa}, | ||
1281 | {0x0000b2e0, 0xfffd64cc}, | ||
1282 | {0x0000b2e4, 0xfffe80f0}, | ||
1283 | {0x0000b2e8, 0xffffff00}, | ||
1284 | {0x00016044, 0x024922db}, | ||
1285 | {0x00016048, 0x6c927a70}, | ||
1286 | {0x00016444, 0x024922db}, | ||
1287 | {0x00016448, 0x6c927a70}, | ||
1288 | }; | ||
1289 | |||
1290 | static const u32 qca953x_2p0_modes_no_xpa_tx_gain_table[][2] = { | ||
1291 | /* Addr allmodes */ | ||
1292 | {0x0000a2dc, 0xffd5f552}, | ||
1293 | {0x0000a2e0, 0xffe60664}, | ||
1294 | {0x0000a2e4, 0xfff80780}, | ||
1295 | {0x0000a2e8, 0xfffff800}, | ||
1296 | {0x0000a410, 0x000050de}, | ||
1297 | {0x0000a500, 0x00000061}, | ||
1298 | {0x0000a504, 0x04000063}, | ||
1299 | {0x0000a508, 0x08000065}, | ||
1300 | {0x0000a50c, 0x0c000261}, | ||
1301 | {0x0000a510, 0x10000263}, | ||
1302 | {0x0000a514, 0x14000265}, | ||
1303 | {0x0000a518, 0x18000482}, | ||
1304 | {0x0000a51c, 0x1b000484}, | ||
1305 | {0x0000a520, 0x1f000486}, | ||
1306 | {0x0000a524, 0x240008c2}, | ||
1307 | {0x0000a528, 0x28000cc1}, | ||
1308 | {0x0000a52c, 0x2d000ce3}, | ||
1309 | {0x0000a530, 0x31000ce5}, | ||
1310 | {0x0000a534, 0x350010e5}, | ||
1311 | {0x0000a538, 0x360012e5}, | ||
1312 | {0x0000a53c, 0x380014e5}, | ||
1313 | {0x0000a540, 0x3b0018e5}, | ||
1314 | {0x0000a544, 0x3d001d04}, | ||
1315 | {0x0000a548, 0x3e001d05}, | ||
1316 | {0x0000a54c, 0x40001d07}, | ||
1317 | {0x0000a550, 0x42001f27}, | ||
1318 | {0x0000a554, 0x43001f67}, | ||
1319 | {0x0000a558, 0x46001fe7}, | ||
1320 | {0x0000a55c, 0x47001f2b}, | ||
1321 | {0x0000a560, 0x49001f0d}, | ||
1322 | {0x0000a564, 0x4b001ed2}, | ||
1323 | {0x0000a568, 0x4c001ed4}, | ||
1324 | {0x0000a56c, 0x4e001f15}, | ||
1325 | {0x0000a570, 0x4f001ff6}, | ||
1326 | {0x0000a574, 0x4f001ff6}, | ||
1327 | {0x0000a578, 0x4f001ff6}, | ||
1328 | {0x0000a57c, 0x4f001ff6}, | ||
1329 | {0x0000a600, 0x00000000}, | ||
1330 | {0x0000a604, 0x00000000}, | ||
1331 | {0x0000a608, 0x00000000}, | ||
1332 | {0x0000a60c, 0x00804201}, | ||
1333 | {0x0000a610, 0x01008201}, | ||
1334 | {0x0000a614, 0x0180c402}, | ||
1335 | {0x0000a618, 0x0180c603}, | ||
1336 | {0x0000a61c, 0x0180c603}, | ||
1337 | {0x0000a620, 0x01c10603}, | ||
1338 | {0x0000a624, 0x01c10704}, | ||
1339 | {0x0000a628, 0x02c18b05}, | ||
1340 | {0x0000a62c, 0x02c14c07}, | ||
1341 | {0x0000a630, 0x01008704}, | ||
1342 | {0x0000a634, 0x01c10402}, | ||
1343 | {0x0000a638, 0x0301cc07}, | ||
1344 | {0x0000a63c, 0x0301cc07}, | ||
1345 | {0x0000b2dc, 0xffd5f552}, | ||
1346 | {0x0000b2e0, 0xffe60664}, | ||
1347 | {0x0000b2e4, 0xfff80780}, | ||
1348 | {0x0000b2e8, 0xfffff800}, | ||
1349 | {0x00016044, 0x049242db}, | ||
1350 | {0x00016048, 0x6c927a70}, | ||
1351 | {0x00016444, 0x049242db}, | ||
1352 | {0x00016448, 0x6c927a70}, | ||
1353 | }; | ||
1354 | |||
917 | #endif /* INITVALS_953X_H */ | 1355 | #endif /* INITVALS_953X_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 85d74ff0767c..1a9fe0983a6b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -28,7 +28,6 @@ | |||
28 | #include "debug.h" | 28 | #include "debug.h" |
29 | #include "mci.h" | 29 | #include "mci.h" |
30 | #include "dfs.h" | 30 | #include "dfs.h" |
31 | #include "spectral.h" | ||
32 | 31 | ||
33 | struct ath_node; | 32 | struct ath_node; |
34 | struct ath_vif; | 33 | struct ath_vif; |
@@ -190,6 +189,7 @@ struct ath_frame_info { | |||
190 | u8 rtscts_rate; | 189 | u8 rtscts_rate; |
191 | u8 retries : 7; | 190 | u8 retries : 7; |
192 | u8 baw_tracked : 1; | 191 | u8 baw_tracked : 1; |
192 | u8 tx_power; | ||
193 | }; | 193 | }; |
194 | 194 | ||
195 | struct ath_rxbuf { | 195 | struct ath_rxbuf { |
@@ -347,6 +347,7 @@ struct ath_chanctx { | |||
347 | 347 | ||
348 | int flush_timeout; | 348 | int flush_timeout; |
349 | u16 txpower; | 349 | u16 txpower; |
350 | u16 cur_txpower; | ||
350 | bool offchannel; | 351 | bool offchannel; |
351 | bool stopped; | 352 | bool stopped; |
352 | bool active; | 353 | bool active; |
@@ -381,6 +382,7 @@ enum ath_chanctx_state { | |||
381 | 382 | ||
382 | struct ath_chanctx_sched { | 383 | struct ath_chanctx_sched { |
383 | bool beacon_pending; | 384 | bool beacon_pending; |
385 | bool beacon_adjust; | ||
384 | bool offchannel_pending; | 386 | bool offchannel_pending; |
385 | bool wait_switch; | 387 | bool wait_switch; |
386 | bool force_noa_update; | 388 | bool force_noa_update; |
@@ -931,6 +933,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); | |||
931 | #define ATH9K_PCI_AR9565_2ANT 0x0100 | 933 | #define ATH9K_PCI_AR9565_2ANT 0x0100 |
932 | #define ATH9K_PCI_NO_PLL_PWRSAVE 0x0200 | 934 | #define ATH9K_PCI_NO_PLL_PWRSAVE 0x0200 |
933 | #define ATH9K_PCI_KILLER 0x0400 | 935 | #define ATH9K_PCI_KILLER 0x0400 |
936 | #define ATH9K_PCI_LED_ACT_HI 0x0800 | ||
934 | 937 | ||
935 | /* | 938 | /* |
936 | * Default cache line size, in bytes. | 939 | * Default cache line size, in bytes. |
@@ -987,7 +990,6 @@ struct ath_softc { | |||
987 | u8 gtt_cnt; | 990 | u8 gtt_cnt; |
988 | u32 intrstatus; | 991 | u32 intrstatus; |
989 | u16 ps_flags; /* PS_* */ | 992 | u16 ps_flags; /* PS_* */ |
990 | u16 curtxpow; | ||
991 | bool ps_enabled; | 993 | bool ps_enabled; |
992 | bool ps_idle; | 994 | bool ps_idle; |
993 | short nbcnvifs; | 995 | short nbcnvifs; |
@@ -1028,10 +1030,8 @@ struct ath_softc { | |||
1028 | struct dfs_pattern_detector *dfs_detector; | 1030 | struct dfs_pattern_detector *dfs_detector; |
1029 | u64 dfs_prev_pulse_ts; | 1031 | u64 dfs_prev_pulse_ts; |
1030 | u32 wow_enabled; | 1032 | u32 wow_enabled; |
1031 | /* relay(fs) channel for spectral scan */ | 1033 | |
1032 | struct rchan *rfs_chan_spec_scan; | 1034 | struct ath_spec_scan_priv spec_priv; |
1033 | enum spectral_mode spectral_mode; | ||
1034 | struct ath_spec_scan spec_config; | ||
1035 | 1035 | ||
1036 | struct ieee80211_vif *tx99_vif; | 1036 | struct ieee80211_vif *tx99_vif; |
1037 | struct sk_buff *tx99_skb; | 1037 | struct sk_buff *tx99_skb; |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index ecb783beeec2..cb366adc820b 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -78,7 +78,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
78 | struct ath_tx_info info; | 78 | struct ath_tx_info info; |
79 | struct ieee80211_supported_band *sband; | 79 | struct ieee80211_supported_band *sband; |
80 | u8 chainmask = ah->txchainmask; | 80 | u8 chainmask = ah->txchainmask; |
81 | u8 rate = 0; | 81 | u8 i, rate = 0; |
82 | 82 | ||
83 | sband = &common->sbands[sc->cur_chandef.chan->band]; | 83 | sband = &common->sbands[sc->cur_chandef.chan->band]; |
84 | rate = sband->bitrates[rateidx].hw_value; | 84 | rate = sband->bitrates[rateidx].hw_value; |
@@ -88,7 +88,8 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
88 | memset(&info, 0, sizeof(info)); | 88 | memset(&info, 0, sizeof(info)); |
89 | info.pkt_len = skb->len + FCS_LEN; | 89 | info.pkt_len = skb->len + FCS_LEN; |
90 | info.type = ATH9K_PKT_TYPE_BEACON; | 90 | info.type = ATH9K_PKT_TYPE_BEACON; |
91 | info.txpower = MAX_RATE_POWER; | 91 | for (i = 0; i < 4; i++) |
92 | info.txpower[i] = MAX_RATE_POWER; | ||
92 | info.keyix = ATH9K_TXKEYIX_INVALID; | 93 | info.keyix = ATH9K_TXKEYIX_INVALID; |
93 | info.keytype = ATH9K_KEY_TYPE_CLEAR; | 94 | info.keytype = ATH9K_KEY_TYPE_CLEAR; |
94 | info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK; | 95 | info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK; |
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index c7234d5dda34..206665059d66 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c | |||
@@ -92,8 +92,8 @@ static int ath_set_channel(struct ath_softc *sc) | |||
92 | } else { | 92 | } else { |
93 | /* perform spectral scan if requested. */ | 93 | /* perform spectral scan if requested. */ |
94 | if (test_bit(ATH_OP_SCANNING, &common->op_flags) && | 94 | if (test_bit(ATH_OP_SCANNING, &common->op_flags) && |
95 | sc->spectral_mode == SPECTRAL_CHANSCAN) | 95 | sc->spec_priv.spectral_mode == SPECTRAL_CHANSCAN) |
96 | ath9k_spectral_scan_trigger(hw); | 96 | ath9k_cmn_spectral_scan_trigger(common, &sc->spec_priv); |
97 | } | 97 | } |
98 | 98 | ||
99 | return 0; | 99 | return 0; |
@@ -659,6 +659,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
659 | sc->sched.beacon_miss = 0; | 659 | sc->sched.beacon_miss = 0; |
660 | 660 | ||
661 | if (sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE || | 661 | if (sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE || |
662 | !sc->sched.beacon_adjust || | ||
662 | !sc->cur_chan->tsf_val) | 663 | !sc->cur_chan->tsf_val) |
663 | break; | 664 | break; |
664 | 665 | ||
@@ -672,7 +673,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
672 | ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL); | 673 | ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL); |
673 | tsf_time += ath9k_hw_gettsf32(ah); | 674 | tsf_time += ath9k_hw_gettsf32(ah); |
674 | 675 | ||
675 | 676 | sc->sched.beacon_adjust = false; | |
676 | ath_chanctx_setup_timer(sc, tsf_time); | 677 | ath_chanctx_setup_timer(sc, tsf_time); |
677 | break; | 678 | break; |
678 | case ATH_CHANCTX_EVENT_AUTHORIZED: | 679 | case ATH_CHANCTX_EVENT_AUTHORIZED: |
@@ -717,6 +718,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
717 | 718 | ||
718 | ath_chanctx_setup_timer(sc, tsf_time); | 719 | ath_chanctx_setup_timer(sc, tsf_time); |
719 | sc->sched.beacon_pending = true; | 720 | sc->sched.beacon_pending = true; |
721 | sc->sched.beacon_adjust = true; | ||
720 | break; | 722 | break; |
721 | case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL: | 723 | case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL: |
722 | if (sc->cur_chan == &sc->offchannel.chan || | 724 | if (sc->cur_chan == &sc->offchannel.chan || |
@@ -900,6 +902,11 @@ void ath_offchannel_next(struct ath_softc *sc) | |||
900 | sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; | 902 | sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; |
901 | ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); | 903 | ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); |
902 | } else { | 904 | } else { |
905 | spin_lock_bh(&sc->chan_lock); | ||
906 | sc->sched.offchannel_pending = false; | ||
907 | sc->sched.wait_switch = false; | ||
908 | spin_unlock_bh(&sc->chan_lock); | ||
909 | |||
903 | ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), | 910 | ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), |
904 | NULL); | 911 | NULL); |
905 | sc->offchannel.state = ATH_OFFCHANNEL_IDLE; | 912 | sc->offchannel.state = ATH_OFFCHANNEL_IDLE; |
@@ -919,8 +926,7 @@ void ath_roc_complete(struct ath_softc *sc, bool abort) | |||
919 | 926 | ||
920 | sc->offchannel.roc_vif = NULL; | 927 | sc->offchannel.roc_vif = NULL; |
921 | sc->offchannel.roc_chan = NULL; | 928 | sc->offchannel.roc_chan = NULL; |
922 | if (abort) | 929 | ieee80211_remain_on_channel_expired(sc->hw); |
923 | ieee80211_remain_on_channel_expired(sc->hw); | ||
924 | ath_offchannel_next(sc); | 930 | ath_offchannel_next(sc); |
925 | ath9k_ps_restore(sc); | 931 | ath9k_ps_restore(sc); |
926 | } | 932 | } |
@@ -957,7 +963,7 @@ static void ath_scan_send_probe(struct ath_softc *sc, | |||
957 | struct ieee80211_tx_info *info; | 963 | struct ieee80211_tx_info *info; |
958 | int band = sc->offchannel.chan.chandef.chan->band; | 964 | int band = sc->offchannel.chan.chandef.chan->band; |
959 | 965 | ||
960 | skb = ieee80211_probereq_get(sc->hw, vif, | 966 | skb = ieee80211_probereq_get(sc->hw, vif->addr, |
961 | ssid->ssid, ssid->ssid_len, req->ie_len); | 967 | ssid->ssid, ssid->ssid_len, req->ie_len); |
962 | if (!skb) | 968 | if (!skb) |
963 | return; | 969 | return; |
@@ -1051,10 +1057,8 @@ static void ath_offchannel_timer(unsigned long data) | |||
1051 | break; | 1057 | break; |
1052 | case ATH_OFFCHANNEL_ROC_START: | 1058 | case ATH_OFFCHANNEL_ROC_START: |
1053 | case ATH_OFFCHANNEL_ROC_WAIT: | 1059 | case ATH_OFFCHANNEL_ROC_WAIT: |
1054 | ctx = ath_chanctx_get_oper_chan(sc, false); | ||
1055 | sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; | 1060 | sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; |
1056 | ieee80211_remain_on_channel_expired(sc->hw); | 1061 | ath_roc_complete(sc, false); |
1057 | ath_chanctx_switch(sc, ctx, NULL); | ||
1058 | break; | 1062 | break; |
1059 | default: | 1063 | default: |
1060 | break; | 1064 | break; |
@@ -1184,7 +1188,6 @@ static void ath_offchannel_channel_change(struct ath_softc *sc) | |||
1184 | ieee80211_ready_on_channel(sc->hw); | 1188 | ieee80211_ready_on_channel(sc->hw); |
1185 | break; | 1189 | break; |
1186 | case ATH_OFFCHANNEL_ROC_DONE: | 1190 | case ATH_OFFCHANNEL_ROC_DONE: |
1187 | ath_roc_complete(sc, false); | ||
1188 | break; | 1191 | break; |
1189 | default: | 1192 | default: |
1190 | break; | 1193 | break; |
diff --git a/drivers/net/wireless/ath/ath9k/spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 8f68426ca653..ec93ddf0863a 100644 --- a/drivers/net/wireless/ath/ath9k/spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c | |||
@@ -24,23 +24,24 @@ static s8 fix_rssi_inv_only(u8 rssi_val) | |||
24 | return (s8) rssi_val; | 24 | return (s8) rssi_val; |
25 | } | 25 | } |
26 | 26 | ||
27 | static void ath_debug_send_fft_sample(struct ath_softc *sc, | 27 | static void ath_debug_send_fft_sample(struct ath_spec_scan_priv *spec_priv, |
28 | struct fft_sample_tlv *fft_sample_tlv) | 28 | struct fft_sample_tlv *fft_sample_tlv) |
29 | { | 29 | { |
30 | int length; | 30 | int length; |
31 | if (!sc->rfs_chan_spec_scan) | 31 | if (!spec_priv->rfs_chan_spec_scan) |
32 | return; | 32 | return; |
33 | 33 | ||
34 | length = __be16_to_cpu(fft_sample_tlv->length) + | 34 | length = __be16_to_cpu(fft_sample_tlv->length) + |
35 | sizeof(*fft_sample_tlv); | 35 | sizeof(*fft_sample_tlv); |
36 | relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length); | 36 | relay_write(spec_priv->rfs_chan_spec_scan, fft_sample_tlv, length); |
37 | } | 37 | } |
38 | 38 | ||
39 | /* returns 1 if this was a spectral frame, even if not handled. */ | 39 | /* returns 1 if this was a spectral frame, even if not handled. */ |
40 | int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | 40 | int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr, |
41 | struct ath_rx_status *rs, u64 tsf) | 41 | struct ath_rx_status *rs, u64 tsf) |
42 | { | 42 | { |
43 | struct ath_hw *ah = sc->sc_ah; | 43 | struct ath_hw *ah = spec_priv->ah; |
44 | struct ath_common *common = ath9k_hw_common(spec_priv->ah); | ||
44 | u8 num_bins, *bins, *vdata = (u8 *)hdr; | 45 | u8 num_bins, *bins, *vdata = (u8 *)hdr; |
45 | struct fft_sample_ht20 fft_sample_20; | 46 | struct fft_sample_ht20 fft_sample_20; |
46 | struct fft_sample_ht20_40 fft_sample_40; | 47 | struct fft_sample_ht20_40 fft_sample_40; |
@@ -67,7 +68,7 @@ int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | |||
67 | if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) | 68 | if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) |
68 | return 0; | 69 | return 0; |
69 | 70 | ||
70 | chan_type = cfg80211_get_chandef_type(&sc->hw->conf.chandef); | 71 | chan_type = cfg80211_get_chandef_type(&common->hw->conf.chandef); |
71 | if ((chan_type == NL80211_CHAN_HT40MINUS) || | 72 | if ((chan_type == NL80211_CHAN_HT40MINUS) || |
72 | (chan_type == NL80211_CHAN_HT40PLUS)) { | 73 | (chan_type == NL80211_CHAN_HT40PLUS)) { |
73 | fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN; | 74 | fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN; |
@@ -199,10 +200,11 @@ int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | |||
199 | tlv = (struct fft_sample_tlv *)&fft_sample_20; | 200 | tlv = (struct fft_sample_tlv *)&fft_sample_20; |
200 | } | 201 | } |
201 | 202 | ||
202 | ath_debug_send_fft_sample(sc, tlv); | 203 | ath_debug_send_fft_sample(spec_priv, tlv); |
203 | 204 | ||
204 | return 1; | 205 | return 1; |
205 | } | 206 | } |
207 | EXPORT_SYMBOL(ath_cmn_process_fft); | ||
206 | 208 | ||
207 | /*********************/ | 209 | /*********************/ |
208 | /* spectral_scan_ctl */ | 210 | /* spectral_scan_ctl */ |
@@ -211,11 +213,11 @@ int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | |||
211 | static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, | 213 | static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, |
212 | size_t count, loff_t *ppos) | 214 | size_t count, loff_t *ppos) |
213 | { | 215 | { |
214 | struct ath_softc *sc = file->private_data; | 216 | struct ath_spec_scan_priv *spec_priv = file->private_data; |
215 | char *mode = ""; | 217 | char *mode = ""; |
216 | unsigned int len; | 218 | unsigned int len; |
217 | 219 | ||
218 | switch (sc->spectral_mode) { | 220 | switch (spec_priv->spectral_mode) { |
219 | case SPECTRAL_DISABLED: | 221 | case SPECTRAL_DISABLED: |
220 | mode = "disable"; | 222 | mode = "disable"; |
221 | break; | 223 | break; |
@@ -233,12 +235,84 @@ static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, | |||
233 | return simple_read_from_buffer(user_buf, count, ppos, mode, len); | 235 | return simple_read_from_buffer(user_buf, count, ppos, mode, len); |
234 | } | 236 | } |
235 | 237 | ||
238 | void ath9k_cmn_spectral_scan_trigger(struct ath_common *common, | ||
239 | struct ath_spec_scan_priv *spec_priv) | ||
240 | { | ||
241 | struct ath_hw *ah = spec_priv->ah; | ||
242 | u32 rxfilter; | ||
243 | |||
244 | if (config_enabled(CONFIG_ATH9K_TX99)) | ||
245 | return; | ||
246 | |||
247 | if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { | ||
248 | ath_err(common, "spectrum analyzer not implemented on this hardware\n"); | ||
249 | return; | ||
250 | } | ||
251 | |||
252 | ath_ps_ops(common)->wakeup(common); | ||
253 | rxfilter = ath9k_hw_getrxfilter(ah); | ||
254 | ath9k_hw_setrxfilter(ah, rxfilter | | ||
255 | ATH9K_RX_FILTER_PHYRADAR | | ||
256 | ATH9K_RX_FILTER_PHYERR); | ||
257 | |||
258 | /* TODO: usually this should not be neccesary, but for some reason | ||
259 | * (or in some mode?) the trigger must be called after the | ||
260 | * configuration, otherwise the register will have its values reset | ||
261 | * (on my ar9220 to value 0x01002310) | ||
262 | */ | ||
263 | ath9k_cmn_spectral_scan_config(common, spec_priv, spec_priv->spectral_mode); | ||
264 | ath9k_hw_ops(ah)->spectral_scan_trigger(ah); | ||
265 | ath_ps_ops(common)->restore(common); | ||
266 | } | ||
267 | EXPORT_SYMBOL(ath9k_cmn_spectral_scan_trigger); | ||
268 | |||
269 | int ath9k_cmn_spectral_scan_config(struct ath_common *common, | ||
270 | struct ath_spec_scan_priv *spec_priv, | ||
271 | enum spectral_mode spectral_mode) | ||
272 | { | ||
273 | struct ath_hw *ah = spec_priv->ah; | ||
274 | |||
275 | if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { | ||
276 | ath_err(common, "spectrum analyzer not implemented on this hardware\n"); | ||
277 | return -1; | ||
278 | } | ||
279 | |||
280 | switch (spectral_mode) { | ||
281 | case SPECTRAL_DISABLED: | ||
282 | spec_priv->spec_config.enabled = 0; | ||
283 | break; | ||
284 | case SPECTRAL_BACKGROUND: | ||
285 | /* send endless samples. | ||
286 | * TODO: is this really useful for "background"? | ||
287 | */ | ||
288 | spec_priv->spec_config.endless = 1; | ||
289 | spec_priv->spec_config.enabled = 1; | ||
290 | break; | ||
291 | case SPECTRAL_CHANSCAN: | ||
292 | case SPECTRAL_MANUAL: | ||
293 | spec_priv->spec_config.endless = 0; | ||
294 | spec_priv->spec_config.enabled = 1; | ||
295 | break; | ||
296 | default: | ||
297 | return -1; | ||
298 | } | ||
299 | |||
300 | ath_ps_ops(common)->wakeup(common); | ||
301 | ath9k_hw_ops(ah)->spectral_scan_config(ah, &spec_priv->spec_config); | ||
302 | ath_ps_ops(common)->restore(common); | ||
303 | |||
304 | spec_priv->spectral_mode = spectral_mode; | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | EXPORT_SYMBOL(ath9k_cmn_spectral_scan_config); | ||
309 | |||
236 | static ssize_t write_file_spec_scan_ctl(struct file *file, | 310 | static ssize_t write_file_spec_scan_ctl(struct file *file, |
237 | const char __user *user_buf, | 311 | const char __user *user_buf, |
238 | size_t count, loff_t *ppos) | 312 | size_t count, loff_t *ppos) |
239 | { | 313 | { |
240 | struct ath_softc *sc = file->private_data; | 314 | struct ath_spec_scan_priv *spec_priv = file->private_data; |
241 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 315 | struct ath_common *common = ath9k_hw_common(spec_priv->ah); |
242 | char buf[32]; | 316 | char buf[32]; |
243 | ssize_t len; | 317 | ssize_t len; |
244 | 318 | ||
@@ -252,18 +326,18 @@ static ssize_t write_file_spec_scan_ctl(struct file *file, | |||
252 | buf[len] = '\0'; | 326 | buf[len] = '\0'; |
253 | 327 | ||
254 | if (strncmp("trigger", buf, 7) == 0) { | 328 | if (strncmp("trigger", buf, 7) == 0) { |
255 | ath9k_spectral_scan_trigger(sc->hw); | 329 | ath9k_cmn_spectral_scan_trigger(common, spec_priv); |
256 | } else if (strncmp("background", buf, 10) == 0) { | 330 | } else if (strncmp("background", buf, 10) == 0) { |
257 | ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND); | 331 | ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_BACKGROUND); |
258 | ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n"); | 332 | ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n"); |
259 | } else if (strncmp("chanscan", buf, 8) == 0) { | 333 | } else if (strncmp("chanscan", buf, 8) == 0) { |
260 | ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN); | 334 | ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_CHANSCAN); |
261 | ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n"); | 335 | ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n"); |
262 | } else if (strncmp("manual", buf, 6) == 0) { | 336 | } else if (strncmp("manual", buf, 6) == 0) { |
263 | ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL); | 337 | ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_MANUAL); |
264 | ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n"); | 338 | ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n"); |
265 | } else if (strncmp("disable", buf, 7) == 0) { | 339 | } else if (strncmp("disable", buf, 7) == 0) { |
266 | ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED); | 340 | ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_DISABLED); |
267 | ath_dbg(common, CONFIG, "spectral scan: disabled\n"); | 341 | ath_dbg(common, CONFIG, "spectral scan: disabled\n"); |
268 | } else { | 342 | } else { |
269 | return -EINVAL; | 343 | return -EINVAL; |
@@ -288,11 +362,11 @@ static ssize_t read_file_spectral_short_repeat(struct file *file, | |||
288 | char __user *user_buf, | 362 | char __user *user_buf, |
289 | size_t count, loff_t *ppos) | 363 | size_t count, loff_t *ppos) |
290 | { | 364 | { |
291 | struct ath_softc *sc = file->private_data; | 365 | struct ath_spec_scan_priv *spec_priv = file->private_data; |
292 | char buf[32]; | 366 | char buf[32]; |
293 | unsigned int len; | 367 | unsigned int len; |
294 | 368 | ||
295 | len = sprintf(buf, "%d\n", sc->spec_config.short_repeat); | 369 | len = sprintf(buf, "%d\n", spec_priv->spec_config.short_repeat); |
296 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 370 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); |
297 | } | 371 | } |
298 | 372 | ||
@@ -300,7 +374,7 @@ static ssize_t write_file_spectral_short_repeat(struct file *file, | |||
300 | const char __user *user_buf, | 374 | const char __user *user_buf, |
301 | size_t count, loff_t *ppos) | 375 | size_t count, loff_t *ppos) |
302 | { | 376 | { |
303 | struct ath_softc *sc = file->private_data; | 377 | struct ath_spec_scan_priv *spec_priv = file->private_data; |
304 | unsigned long val; | 378 | unsigned long val; |
305 | char buf[32]; | 379 | char buf[32]; |
306 | ssize_t len; | 380 | ssize_t len; |
@@ -316,7 +390,7 @@ static ssize_t write_file_spectral_short_repeat(struct file *file, | |||
316 | if (val > 1) | 390 | if (val > 1) |
317 | return -EINVAL; | 391 | return -EINVAL; |
318 | 392 | ||
319 | sc->spec_config.short_repeat = val; | 393 | spec_priv->spec_config.short_repeat = val; |
320 | return count; | 394 | return count; |
321 | } | 395 | } |
322 | 396 | ||
@@ -336,11 +410,11 @@ static ssize_t read_file_spectral_count(struct file *file, | |||
336 | char __user *user_buf, | 410 | char __user *user_buf, |
337 | size_t count, loff_t *ppos) | 411 | size_t count, loff_t *ppos) |
338 | { | 412 | { |
339 | struct ath_softc *sc = file->private_data; | 413 | struct ath_spec_scan_priv *spec_priv = file->private_data; |
340 | char buf[32]; | 414 | char buf[32]; |
341 | unsigned int len; | 415 | unsigned int len; |
342 | 416 | ||
343 | len = sprintf(buf, "%d\n", sc->spec_config.count); | 417 | len = sprintf(buf, "%d\n", spec_priv->spec_config.count); |
344 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 418 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); |
345 | } | 419 | } |
346 | 420 | ||
@@ -348,7 +422,7 @@ static ssize_t write_file_spectral_count(struct file *file, | |||
348 | const char __user *user_buf, | 422 | const char __user *user_buf, |
349 | size_t count, loff_t *ppos) | 423 | size_t count, loff_t *ppos) |
350 | { | 424 | { |
351 | struct ath_softc *sc = file->private_data; | 425 | struct ath_spec_scan_priv *spec_priv = file->private_data; |
352 | unsigned long val; | 426 | unsigned long val; |
353 | char buf[32]; | 427 | char buf[32]; |
354 | ssize_t len; | 428 | ssize_t len; |
@@ -364,7 +438,7 @@ static ssize_t write_file_spectral_count(struct file *file, | |||
364 | if (val > 255) | 438 | if (val > 255) |
365 | return -EINVAL; | 439 | return -EINVAL; |
366 | 440 | ||
367 | sc->spec_config.count = val; | 441 | spec_priv->spec_config.count = val; |
368 | return count; | 442 | return count; |
369 | } | 443 | } |
370 | 444 | ||
@@ -384,11 +458,11 @@ static ssize_t read_file_spectral_period(struct file *file, | |||
384 | char __user *user_buf, | 458 | char __user *user_buf, |
385 | size_t count, loff_t *ppos) | 459 | size_t count, loff_t *ppos) |
386 | { | 460 | { |
387 | struct ath_softc *sc = file->private_data; | 461 | struct ath_spec_scan_priv *spec_priv = file->private_data; |
388 | char buf[32]; | 462 | char buf[32]; |
389 | unsigned int len; | 463 | unsigned int len; |
390 | 464 | ||
391 | len = sprintf(buf, "%d\n", sc->spec_config.period); | 465 | len = sprintf(buf, "%d\n", spec_priv->spec_config.period); |
392 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 466 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); |
393 | } | 467 | } |
394 | 468 | ||
@@ -396,7 +470,7 @@ static ssize_t write_file_spectral_period(struct file *file, | |||
396 | const char __user *user_buf, | 470 | const char __user *user_buf, |
397 | size_t count, loff_t *ppos) | 471 | size_t count, loff_t *ppos) |
398 | { | 472 | { |
399 | struct ath_softc *sc = file->private_data; | 473 | struct ath_spec_scan_priv *spec_priv = file->private_data; |
400 | unsigned long val; | 474 | unsigned long val; |
401 | char buf[32]; | 475 | char buf[32]; |
402 | ssize_t len; | 476 | ssize_t len; |
@@ -412,7 +486,7 @@ static ssize_t write_file_spectral_period(struct file *file, | |||
412 | if (val > 255) | 486 | if (val > 255) |
413 | return -EINVAL; | 487 | return -EINVAL; |
414 | 488 | ||
415 | sc->spec_config.period = val; | 489 | spec_priv->spec_config.period = val; |
416 | return count; | 490 | return count; |
417 | } | 491 | } |
418 | 492 | ||
@@ -432,11 +506,11 @@ static ssize_t read_file_spectral_fft_period(struct file *file, | |||
432 | char __user *user_buf, | 506 | char __user *user_buf, |
433 | size_t count, loff_t *ppos) | 507 | size_t count, loff_t *ppos) |
434 | { | 508 | { |
435 | struct ath_softc *sc = file->private_data; | 509 | struct ath_spec_scan_priv *spec_priv = file->private_data; |
436 | char buf[32]; | 510 | char buf[32]; |
437 | unsigned int len; | 511 | unsigned int len; |
438 | 512 | ||
439 | len = sprintf(buf, "%d\n", sc->spec_config.fft_period); | 513 | len = sprintf(buf, "%d\n", spec_priv->spec_config.fft_period); |
440 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 514 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); |
441 | } | 515 | } |
442 | 516 | ||
@@ -444,7 +518,7 @@ static ssize_t write_file_spectral_fft_period(struct file *file, | |||
444 | const char __user *user_buf, | 518 | const char __user *user_buf, |
445 | size_t count, loff_t *ppos) | 519 | size_t count, loff_t *ppos) |
446 | { | 520 | { |
447 | struct ath_softc *sc = file->private_data; | 521 | struct ath_spec_scan_priv *spec_priv = file->private_data; |
448 | unsigned long val; | 522 | unsigned long val; |
449 | char buf[32]; | 523 | char buf[32]; |
450 | ssize_t len; | 524 | ssize_t len; |
@@ -460,7 +534,7 @@ static ssize_t write_file_spectral_fft_period(struct file *file, | |||
460 | if (val > 15) | 534 | if (val > 15) |
461 | return -EINVAL; | 535 | return -EINVAL; |
462 | 536 | ||
463 | sc->spec_config.fft_period = val; | 537 | spec_priv->spec_config.fft_period = val; |
464 | return count; | 538 | return count; |
465 | } | 539 | } |
466 | 540 | ||
@@ -506,38 +580,41 @@ static struct rchan_callbacks rfs_spec_scan_cb = { | |||
506 | /* Debug Init/Deinit */ | 580 | /* Debug Init/Deinit */ |
507 | /*********************/ | 581 | /*********************/ |
508 | 582 | ||
509 | void ath9k_spectral_deinit_debug(struct ath_softc *sc) | 583 | void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv) |
510 | { | 584 | { |
511 | if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) { | 585 | if (config_enabled(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) { |
512 | relay_close(sc->rfs_chan_spec_scan); | 586 | relay_close(spec_priv->rfs_chan_spec_scan); |
513 | sc->rfs_chan_spec_scan = NULL; | 587 | spec_priv->rfs_chan_spec_scan = NULL; |
514 | } | 588 | } |
515 | } | 589 | } |
590 | EXPORT_SYMBOL(ath9k_cmn_spectral_deinit_debug); | ||
516 | 591 | ||
517 | void ath9k_spectral_init_debug(struct ath_softc *sc) | 592 | void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, |
593 | struct dentry *debugfs_phy) | ||
518 | { | 594 | { |
519 | sc->rfs_chan_spec_scan = relay_open("spectral_scan", | 595 | spec_priv->rfs_chan_spec_scan = relay_open("spectral_scan", |
520 | sc->debug.debugfs_phy, | 596 | debugfs_phy, |
521 | 1024, 256, &rfs_spec_scan_cb, | 597 | 1024, 256, &rfs_spec_scan_cb, |
522 | NULL); | 598 | NULL); |
523 | debugfs_create_file("spectral_scan_ctl", | 599 | debugfs_create_file("spectral_scan_ctl", |
524 | S_IRUSR | S_IWUSR, | 600 | S_IRUSR | S_IWUSR, |
525 | sc->debug.debugfs_phy, sc, | 601 | debugfs_phy, spec_priv, |
526 | &fops_spec_scan_ctl); | 602 | &fops_spec_scan_ctl); |
527 | debugfs_create_file("spectral_short_repeat", | 603 | debugfs_create_file("spectral_short_repeat", |
528 | S_IRUSR | S_IWUSR, | 604 | S_IRUSR | S_IWUSR, |
529 | sc->debug.debugfs_phy, sc, | 605 | debugfs_phy, spec_priv, |
530 | &fops_spectral_short_repeat); | 606 | &fops_spectral_short_repeat); |
531 | debugfs_create_file("spectral_count", | 607 | debugfs_create_file("spectral_count", |
532 | S_IRUSR | S_IWUSR, | 608 | S_IRUSR | S_IWUSR, |
533 | sc->debug.debugfs_phy, sc, | 609 | debugfs_phy, spec_priv, |
534 | &fops_spectral_count); | 610 | &fops_spectral_count); |
535 | debugfs_create_file("spectral_period", | 611 | debugfs_create_file("spectral_period", |
536 | S_IRUSR | S_IWUSR, | 612 | S_IRUSR | S_IWUSR, |
537 | sc->debug.debugfs_phy, sc, | 613 | debugfs_phy, spec_priv, |
538 | &fops_spectral_period); | 614 | &fops_spectral_period); |
539 | debugfs_create_file("spectral_fft_period", | 615 | debugfs_create_file("spectral_fft_period", |
540 | S_IRUSR | S_IWUSR, | 616 | S_IRUSR | S_IWUSR, |
541 | sc->debug.debugfs_phy, sc, | 617 | debugfs_phy, spec_priv, |
542 | &fops_spectral_fft_period); | 618 | &fops_spectral_fft_period); |
543 | } | 619 | } |
620 | EXPORT_SYMBOL(ath9k_cmn_spectral_init_debug); | ||
diff --git a/drivers/net/wireless/ath/ath9k/spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h index 7b410c6858b0..82d9dd29652c 100644 --- a/drivers/net/wireless/ath/ath9k/spectral.h +++ b/drivers/net/wireless/ath/ath9k/common-spectral.h | |||
@@ -92,6 +92,13 @@ struct ath_ht20_40_fft_packet { | |||
92 | struct ath_radar_info radar_info; | 92 | struct ath_radar_info radar_info; |
93 | } __packed; | 93 | } __packed; |
94 | 94 | ||
95 | struct ath_spec_scan_priv { | ||
96 | struct ath_hw *ah; | ||
97 | /* relay(fs) channel for spectral scan */ | ||
98 | struct rchan *rfs_chan_spec_scan; | ||
99 | enum spectral_mode spectral_mode; | ||
100 | struct ath_spec_scan spec_config; | ||
101 | }; | ||
95 | 102 | ||
96 | #define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet)) | 103 | #define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet)) |
97 | 104 | ||
@@ -123,23 +130,15 @@ static inline u8 spectral_bitmap_weight(u8 *bins) | |||
123 | return bins[0] & 0x3f; | 130 | return bins[0] & 0x3f; |
124 | } | 131 | } |
125 | 132 | ||
126 | void ath9k_spectral_init_debug(struct ath_softc *sc); | 133 | void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, struct dentry *debugfs_phy); |
127 | void ath9k_spectral_deinit_debug(struct ath_softc *sc); | 134 | void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv); |
128 | 135 | ||
129 | void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw); | 136 | void ath9k_cmn_spectral_scan_trigger(struct ath_common *common, |
130 | int ath9k_spectral_scan_config(struct ieee80211_hw *hw, | 137 | struct ath_spec_scan_priv *spec_priv); |
138 | int ath9k_cmn_spectral_scan_config(struct ath_common *common, | ||
139 | struct ath_spec_scan_priv *spec_priv, | ||
131 | enum spectral_mode spectral_mode); | 140 | enum spectral_mode spectral_mode); |
132 | 141 | int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr, | |
133 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
134 | int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | ||
135 | struct ath_rx_status *rs, u64 tsf); | 142 | struct ath_rx_status *rs, u64 tsf); |
136 | #else | ||
137 | static inline int ath_process_fft(struct ath_softc *sc, | ||
138 | struct ieee80211_hdr *hdr, | ||
139 | struct ath_rx_status *rs, u64 tsf) | ||
140 | { | ||
141 | return 0; | ||
142 | } | ||
143 | #endif /* CONFIG_ATH9K_DEBUGFS */ | ||
144 | 143 | ||
145 | #endif /* SPECTRAL_H */ | 144 | #endif /* SPECTRAL_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index c6dd7f1fed65..e8c699446470 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c | |||
@@ -159,7 +159,7 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, | |||
159 | if (test_bit(keyix, common->keymap)) | 159 | if (test_bit(keyix, common->keymap)) |
160 | rxs->flag |= RX_FLAG_DECRYPTED; | 160 | rxs->flag |= RX_FLAG_DECRYPTED; |
161 | } | 161 | } |
162 | if (ah->sw_mgmt_crypto && | 162 | if (ah->sw_mgmt_crypto_rx && |
163 | (rxs->flag & RX_FLAG_DECRYPTED) && | 163 | (rxs->flag & RX_FLAG_DECRYPTED) && |
164 | ieee80211_is_mgmt(fc)) | 164 | ieee80211_is_mgmt(fc)) |
165 | /* Use software decrypt for management frames. */ | 165 | /* Use software decrypt for management frames. */ |
@@ -368,11 +368,11 @@ void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, | |||
368 | { | 368 | { |
369 | struct ath_regulatory *reg = ath9k_hw_regulatory(ah); | 369 | struct ath_regulatory *reg = ath9k_hw_regulatory(ah); |
370 | 370 | ||
371 | if (reg->power_limit != new_txpow) { | 371 | if (reg->power_limit != new_txpow) |
372 | ath9k_hw_set_txpowerlimit(ah, new_txpow, false); | 372 | ath9k_hw_set_txpowerlimit(ah, new_txpow, false); |
373 | /* read back in case value is clamped */ | 373 | |
374 | *txpower = reg->max_power_level; | 374 | /* read back in case value is clamped */ |
375 | } | 375 | *txpower = reg->max_power_level; |
376 | } | 376 | } |
377 | EXPORT_SYMBOL(ath9k_cmn_update_txpow); | 377 | EXPORT_SYMBOL(ath9k_cmn_update_txpow); |
378 | 378 | ||
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index ffc454b18637..2b79a568e803 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "common-init.h" | 24 | #include "common-init.h" |
25 | #include "common-beacon.h" | 25 | #include "common-beacon.h" |
26 | #include "common-debug.h" | 26 | #include "common-debug.h" |
27 | #include "common-spectral.h" | ||
27 | 28 | ||
28 | /* Common header for Atheros 802.11n base driver cores */ | 29 | /* Common header for Atheros 802.11n base driver cores */ |
29 | 30 | ||
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 2a2a17df5fb3..696e3d5309c6 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
@@ -455,7 +455,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, | |||
455 | "%2d %2x %1x %2x %2x\n", | 455 | "%2d %2x %1x %2x %2x\n", |
456 | i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, | 456 | i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, |
457 | (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), | 457 | (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), |
458 | val[2] & (0x7 << (i * 3)) >> (i * 3), | 458 | (val[2] & (0x7 << (i * 3))) >> (i * 3), |
459 | (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); | 459 | (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); |
460 | } | 460 | } |
461 | 461 | ||
@@ -828,13 +828,14 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, | |||
828 | 828 | ||
829 | i = 0; | 829 | i = 0; |
830 | ath_for_each_chanctx(sc, ctx) { | 830 | ath_for_each_chanctx(sc, ctx) { |
831 | if (!ctx->assigned || list_empty(&ctx->vifs)) | 831 | if (list_empty(&ctx->vifs)) |
832 | continue; | 832 | continue; |
833 | ath9k_calculate_iter_data(sc, ctx, &iter_data); | 833 | ath9k_calculate_iter_data(sc, ctx, &iter_data); |
834 | 834 | ||
835 | len += scnprintf(buf + len, sizeof(buf) - len, | 835 | len += scnprintf(buf + len, sizeof(buf) - len, |
836 | "VIF-COUNTS: CTX %i AP: %i STA: %i MESH: %i WDS: %i", | 836 | "VIFS: CTX %i(%i) AP: %i STA: %i MESH: %i WDS: %i", |
837 | i++, iter_data.naps, iter_data.nstations, | 837 | i++, (int)(ctx->assigned), iter_data.naps, |
838 | iter_data.nstations, | ||
838 | iter_data.nmeshes, iter_data.nwds); | 839 | iter_data.nmeshes, iter_data.nwds); |
839 | len += scnprintf(buf + len, sizeof(buf) - len, | 840 | len += scnprintf(buf + len, sizeof(buf) - len, |
840 | " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", | 841 | " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", |
@@ -1310,7 +1311,7 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw, | |||
1310 | 1311 | ||
1311 | void ath9k_deinit_debug(struct ath_softc *sc) | 1312 | void ath9k_deinit_debug(struct ath_softc *sc) |
1312 | { | 1313 | { |
1313 | ath9k_spectral_deinit_debug(sc); | 1314 | ath9k_cmn_spectral_deinit_debug(&sc->spec_priv); |
1314 | } | 1315 | } |
1315 | 1316 | ||
1316 | int ath9k_init_debug(struct ath_hw *ah) | 1317 | int ath9k_init_debug(struct ath_hw *ah) |
@@ -1330,7 +1331,7 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
1330 | 1331 | ||
1331 | ath9k_dfs_init_debug(sc); | 1332 | ath9k_dfs_init_debug(sc); |
1332 | ath9k_tx99_init_debug(sc); | 1333 | ath9k_tx99_init_debug(sc); |
1333 | ath9k_spectral_init_debug(sc); | 1334 | ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy); |
1334 | 1335 | ||
1335 | debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, | 1336 | debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, |
1336 | &fops_dma); | 1337 | &fops_dma); |
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index b1956bf6e01e..2fef7a480fec 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
@@ -25,7 +25,12 @@ static void ath_led_brightness(struct led_classdev *led_cdev, | |||
25 | enum led_brightness brightness) | 25 | enum led_brightness brightness) |
26 | { | 26 | { |
27 | struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev); | 27 | struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev); |
28 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF)); | 28 | u32 val = (brightness == LED_OFF); |
29 | |||
30 | if (sc->sc_ah->config.led_active_high) | ||
31 | val = !val; | ||
32 | |||
33 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val); | ||
29 | } | 34 | } |
30 | 35 | ||
31 | void ath_deinit_leds(struct ath_softc *sc) | 36 | void ath_deinit_leds(struct ath_softc *sc) |
@@ -82,7 +87,7 @@ void ath_fill_led_pin(struct ath_softc *sc) | |||
82 | ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 87 | ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
83 | 88 | ||
84 | /* LED off, active low */ | 89 | /* LED off, active low */ |
85 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | 90 | ath9k_hw_set_gpio(ah, ah->led_pin, (ah->config.led_active_high) ? 0 : 1); |
86 | } | 91 | } |
87 | #endif | 92 | #endif |
88 | 93 | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 09a5d72f3ff5..9dde265d3f84 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -481,6 +481,7 @@ struct ath9k_htc_priv { | |||
481 | unsigned long op_flags; | 481 | unsigned long op_flags; |
482 | 482 | ||
483 | struct ath9k_hw_cal_data caldata; | 483 | struct ath9k_hw_cal_data caldata; |
484 | struct ath_spec_scan_priv spec_priv; | ||
484 | 485 | ||
485 | spinlock_t beacon_lock; | 486 | spinlock_t beacon_lock; |
486 | struct ath_beacon_config cur_beacon_conf; | 487 | struct ath_beacon_config cur_beacon_conf; |
@@ -625,8 +626,12 @@ int ath9k_htc_resume(struct htc_target *htc_handle); | |||
625 | #endif | 626 | #endif |
626 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS | 627 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS |
627 | int ath9k_htc_init_debug(struct ath_hw *ah); | 628 | int ath9k_htc_init_debug(struct ath_hw *ah); |
629 | void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv); | ||
628 | #else | 630 | #else |
629 | static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; }; | 631 | static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; }; |
632 | static inline void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) | ||
633 | { | ||
634 | } | ||
630 | #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ | 635 | #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ |
631 | 636 | ||
632 | #endif /* HTC_H */ | 637 | #endif /* HTC_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 8b529e4b8ac4..8cef1edcc621 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c | |||
@@ -490,6 +490,10 @@ void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, | |||
490 | WARN_ON(i != ATH9K_HTC_SSTATS_LEN); | 490 | WARN_ON(i != ATH9K_HTC_SSTATS_LEN); |
491 | } | 491 | } |
492 | 492 | ||
493 | void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) | ||
494 | { | ||
495 | ath9k_cmn_spectral_deinit_debug(&priv->spec_priv); | ||
496 | } | ||
493 | 497 | ||
494 | int ath9k_htc_init_debug(struct ath_hw *ah) | 498 | int ath9k_htc_init_debug(struct ath_hw *ah) |
495 | { | 499 | { |
@@ -501,6 +505,8 @@ int ath9k_htc_init_debug(struct ath_hw *ah) | |||
501 | if (!priv->debug.debugfs_phy) | 505 | if (!priv->debug.debugfs_phy) |
502 | return -ENOMEM; | 506 | return -ENOMEM; |
503 | 507 | ||
508 | ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy); | ||
509 | |||
504 | debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, | 510 | debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, |
505 | priv, &fops_tgt_int_stats); | 511 | priv, &fops_tgt_int_stats); |
506 | debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, | 512 | debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 4014c4be6e79..e8fa9448da24 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |||
@@ -53,6 +53,21 @@ static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { | |||
53 | }; | 53 | }; |
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | static void ath9k_htc_op_ps_wakeup(struct ath_common *common) | ||
57 | { | ||
58 | ath9k_htc_ps_wakeup((struct ath9k_htc_priv *) common->priv); | ||
59 | } | ||
60 | |||
61 | static void ath9k_htc_op_ps_restore(struct ath_common *common) | ||
62 | { | ||
63 | ath9k_htc_ps_restore((struct ath9k_htc_priv *) common->priv); | ||
64 | } | ||
65 | |||
66 | static struct ath_ps_ops ath9k_htc_ps_ops = { | ||
67 | .wakeup = ath9k_htc_op_ps_wakeup, | ||
68 | .restore = ath9k_htc_op_ps_restore, | ||
69 | }; | ||
70 | |||
56 | static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) | 71 | static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) |
57 | { | 72 | { |
58 | int time_left; | 73 | int time_left; |
@@ -87,6 +102,7 @@ static void ath9k_deinit_device(struct ath9k_htc_priv *priv) | |||
87 | 102 | ||
88 | wiphy_rfkill_stop_polling(hw->wiphy); | 103 | wiphy_rfkill_stop_polling(hw->wiphy); |
89 | ath9k_deinit_leds(priv); | 104 | ath9k_deinit_leds(priv); |
105 | ath9k_htc_deinit_debug(priv); | ||
90 | ieee80211_unregister_hw(hw); | 106 | ieee80211_unregister_hw(hw); |
91 | ath9k_rx_cleanup(priv); | 107 | ath9k_rx_cleanup(priv); |
92 | ath9k_tx_cleanup(priv); | 108 | ath9k_tx_cleanup(priv); |
@@ -449,6 +465,14 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) | |||
449 | 465 | ||
450 | common->last_rssi = ATH_RSSI_DUMMY_MARKER; | 466 | common->last_rssi = ATH_RSSI_DUMMY_MARKER; |
451 | priv->ah->opmode = NL80211_IFTYPE_STATION; | 467 | priv->ah->opmode = NL80211_IFTYPE_STATION; |
468 | |||
469 | priv->spec_priv.ah = priv->ah; | ||
470 | priv->spec_priv.spec_config.enabled = 0; | ||
471 | priv->spec_priv.spec_config.short_repeat = false; | ||
472 | priv->spec_priv.spec_config.count = 8; | ||
473 | priv->spec_priv.spec_config.endless = false; | ||
474 | priv->spec_priv.spec_config.period = 0x12; | ||
475 | priv->spec_priv.spec_config.fft_period = 0x02; | ||
452 | } | 476 | } |
453 | 477 | ||
454 | static int ath9k_init_priv(struct ath9k_htc_priv *priv, | 478 | static int ath9k_init_priv(struct ath9k_htc_priv *priv, |
@@ -478,6 +502,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, | |||
478 | 502 | ||
479 | common = ath9k_hw_common(ah); | 503 | common = ath9k_hw_common(ah); |
480 | common->ops = &ah->reg_ops; | 504 | common->ops = &ah->reg_ops; |
505 | common->ps_ops = &ath9k_htc_ps_ops; | ||
481 | common->bus_ops = &ath9k_usb_bus_ops; | 506 | common->bus_ops = &ath9k_usb_bus_ops; |
482 | common->ah = ah; | 507 | common->ah = ah; |
483 | common->hw = priv->hw; | 508 | common->hw = priv->hw; |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 994fff1ff519..92d5a6c5a225 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -314,6 +314,10 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
314 | mod_timer(&priv->tx.cleanup_timer, | 314 | mod_timer(&priv->tx.cleanup_timer, |
315 | jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); | 315 | jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); |
316 | 316 | ||
317 | /* perform spectral scan if requested. */ | ||
318 | if (test_bit(ATH_OP_SCANNING, &common->op_flags) && | ||
319 | priv->spec_priv.spectral_mode == SPECTRAL_CHANSCAN) | ||
320 | ath9k_cmn_spectral_scan_trigger(common, &priv->spec_priv); | ||
317 | err: | 321 | err: |
318 | ath9k_htc_ps_restore(priv); | 322 | ath9k_htc_ps_restore(priv); |
319 | return ret; | 323 | return ret; |
@@ -1443,7 +1447,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw, | |||
1443 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 1447 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
1444 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) | 1448 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) |
1445 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 1449 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
1446 | if (priv->ah->sw_mgmt_crypto && | 1450 | if (priv->ah->sw_mgmt_crypto_tx && |
1447 | key->cipher == WLAN_CIPHER_SUITE_CCMP) | 1451 | key->cipher == WLAN_CIPHER_SUITE_CCMP) |
1448 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; | 1452 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; |
1449 | ret = 0; | 1453 | ret = 0; |
@@ -1687,7 +1691,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, | |||
1687 | return ret; | 1691 | return ret; |
1688 | } | 1692 | } |
1689 | 1693 | ||
1690 | static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) | 1694 | static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw, |
1695 | struct ieee80211_vif *vif, | ||
1696 | const u8 *mac_addr) | ||
1691 | { | 1697 | { |
1692 | struct ath9k_htc_priv *priv = hw->priv; | 1698 | struct ath9k_htc_priv *priv = hw->priv; |
1693 | struct ath_common *common = ath9k_hw_common(priv->ah); | 1699 | struct ath_common *common = ath9k_hw_common(priv->ah); |
@@ -1701,7 +1707,8 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) | |||
1701 | mutex_unlock(&priv->mutex); | 1707 | mutex_unlock(&priv->mutex); |
1702 | } | 1708 | } |
1703 | 1709 | ||
1704 | static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) | 1710 | static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw, |
1711 | struct ieee80211_vif *vif) | ||
1705 | { | 1712 | { |
1706 | struct ath9k_htc_priv *priv = hw->priv; | 1713 | struct ath9k_htc_priv *priv = hw->priv; |
1707 | struct ath_common *common = ath9k_hw_common(priv->ah); | 1714 | struct ath_common *common = ath9k_hw_common(priv->ah); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index f0484b1b617e..a0f58e2aa553 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |||
@@ -946,7 +946,7 @@ static inline void convert_htc_flag(struct ath_rx_status *rx_stats, | |||
946 | static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats, | 946 | static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats, |
947 | struct ath_htc_rx_status *rxstatus) | 947 | struct ath_htc_rx_status *rxstatus) |
948 | { | 948 | { |
949 | rx_stats->rs_datalen = rxstatus->rs_datalen; | 949 | rx_stats->rs_datalen = be16_to_cpu(rxstatus->rs_datalen); |
950 | rx_stats->rs_status = rxstatus->rs_status; | 950 | rx_stats->rs_status = rxstatus->rs_status; |
951 | rx_stats->rs_phyerr = rxstatus->rs_phyerr; | 951 | rx_stats->rs_phyerr = rxstatus->rs_phyerr; |
952 | rx_stats->rs_rssi = rxstatus->rs_rssi; | 952 | rx_stats->rs_rssi = rxstatus->rs_rssi; |
@@ -1012,6 +1012,20 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, | |||
1012 | * separately to avoid doing two lookups for a rate for each frame. | 1012 | * separately to avoid doing two lookups for a rate for each frame. |
1013 | */ | 1013 | */ |
1014 | hdr = (struct ieee80211_hdr *)skb->data; | 1014 | hdr = (struct ieee80211_hdr *)skb->data; |
1015 | |||
1016 | /* | ||
1017 | * Process PHY errors and return so that the packet | ||
1018 | * can be dropped. | ||
1019 | */ | ||
1020 | if (rx_stats.rs_status & ATH9K_RXERR_PHY) { | ||
1021 | /* TODO: Not using DFS processing now. */ | ||
1022 | if (ath_cmn_process_fft(&priv->spec_priv, hdr, | ||
1023 | &rx_stats, rx_status->mactime)) { | ||
1024 | /* TODO: Code to collect spectral scan statistics */ | ||
1025 | } | ||
1026 | goto rx_next; | ||
1027 | } | ||
1028 | |||
1015 | if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats, | 1029 | if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats, |
1016 | &decrypt_error, priv->rxfilter)) | 1030 | &decrypt_error, priv->rxfilter)) |
1017 | goto rx_next; | 1031 | goto rx_next; |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ee9fb52cec62..6d4b273469b1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -870,19 +870,6 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, | |||
870 | udelay(RTC_PLL_SETTLE_DELAY); | 870 | udelay(RTC_PLL_SETTLE_DELAY); |
871 | 871 | ||
872 | REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); | 872 | REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); |
873 | |||
874 | if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { | ||
875 | if (ah->is_clk_25mhz) { | ||
876 | REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); | ||
877 | REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); | ||
878 | REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); | ||
879 | } else { | ||
880 | REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1); | ||
881 | REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); | ||
882 | REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); | ||
883 | } | ||
884 | udelay(100); | ||
885 | } | ||
886 | } | 873 | } |
887 | 874 | ||
888 | static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, | 875 | static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, |
@@ -1598,16 +1585,22 @@ static void ath9k_hw_init_mfp(struct ath_hw *ah) | |||
1598 | * frames when constructing CCMP AAD. */ | 1585 | * frames when constructing CCMP AAD. */ |
1599 | REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, | 1586 | REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, |
1600 | 0xc7ff); | 1587 | 0xc7ff); |
1601 | ah->sw_mgmt_crypto = false; | 1588 | if (AR_SREV_9271(ah) || AR_DEVID_7010(ah)) |
1589 | ah->sw_mgmt_crypto_tx = true; | ||
1590 | else | ||
1591 | ah->sw_mgmt_crypto_tx = false; | ||
1592 | ah->sw_mgmt_crypto_rx = false; | ||
1602 | } else if (AR_SREV_9160_10_OR_LATER(ah)) { | 1593 | } else if (AR_SREV_9160_10_OR_LATER(ah)) { |
1603 | /* Disable hardware crypto for management frames */ | 1594 | /* Disable hardware crypto for management frames */ |
1604 | REG_CLR_BIT(ah, AR_PCU_MISC_MODE2, | 1595 | REG_CLR_BIT(ah, AR_PCU_MISC_MODE2, |
1605 | AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE); | 1596 | AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE); |
1606 | REG_SET_BIT(ah, AR_PCU_MISC_MODE2, | 1597 | REG_SET_BIT(ah, AR_PCU_MISC_MODE2, |
1607 | AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT); | 1598 | AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT); |
1608 | ah->sw_mgmt_crypto = true; | 1599 | ah->sw_mgmt_crypto_tx = true; |
1600 | ah->sw_mgmt_crypto_rx = true; | ||
1609 | } else { | 1601 | } else { |
1610 | ah->sw_mgmt_crypto = true; | 1602 | ah->sw_mgmt_crypto_tx = true; |
1603 | ah->sw_mgmt_crypto_rx = true; | ||
1611 | } | 1604 | } |
1612 | } | 1605 | } |
1613 | 1606 | ||
@@ -1954,6 +1947,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1954 | 1947 | ||
1955 | REGWRITE_BUFFER_FLUSH(ah); | 1948 | REGWRITE_BUFFER_FLUSH(ah); |
1956 | 1949 | ||
1950 | ath9k_hw_gen_timer_start_tsf2(ah); | ||
1951 | |||
1957 | ath9k_hw_init_desc(ah); | 1952 | ath9k_hw_init_desc(ah); |
1958 | 1953 | ||
1959 | if (ath9k_hw_btcoex_is_enabled(ah)) | 1954 | if (ath9k_hw_btcoex_is_enabled(ah)) |
@@ -2333,7 +2328,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
2333 | struct ath9k_hw_capabilities *pCap = &ah->caps; | 2328 | struct ath9k_hw_capabilities *pCap = &ah->caps; |
2334 | struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); | 2329 | struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); |
2335 | struct ath_common *common = ath9k_hw_common(ah); | 2330 | struct ath_common *common = ath9k_hw_common(ah); |
2336 | unsigned int chip_chainmask; | ||
2337 | 2331 | ||
2338 | u16 eeval; | 2332 | u16 eeval; |
2339 | u8 ant_div_ctl1, tx_chainmask, rx_chainmask; | 2333 | u8 ant_div_ctl1, tx_chainmask, rx_chainmask; |
@@ -2377,15 +2371,16 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
2377 | AR_SREV_9285(ah) || | 2371 | AR_SREV_9285(ah) || |
2378 | AR_SREV_9330(ah) || | 2372 | AR_SREV_9330(ah) || |
2379 | AR_SREV_9565(ah)) | 2373 | AR_SREV_9565(ah)) |
2380 | chip_chainmask = 1; | 2374 | pCap->chip_chainmask = 1; |
2381 | else if (AR_SREV_9462(ah)) | ||
2382 | chip_chainmask = 3; | ||
2383 | else if (!AR_SREV_9280_20_OR_LATER(ah)) | 2375 | else if (!AR_SREV_9280_20_OR_LATER(ah)) |
2384 | chip_chainmask = 7; | 2376 | pCap->chip_chainmask = 7; |
2385 | else if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9340(ah)) | 2377 | else if (!AR_SREV_9300_20_OR_LATER(ah) || |
2386 | chip_chainmask = 3; | 2378 | AR_SREV_9340(ah) || |
2379 | AR_SREV_9462(ah) || | ||
2380 | AR_SREV_9531(ah)) | ||
2381 | pCap->chip_chainmask = 3; | ||
2387 | else | 2382 | else |
2388 | chip_chainmask = 7; | 2383 | pCap->chip_chainmask = 7; |
2389 | 2384 | ||
2390 | pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); | 2385 | pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); |
2391 | /* | 2386 | /* |
@@ -2403,8 +2398,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
2403 | /* Use rx_chainmask from EEPROM. */ | 2398 | /* Use rx_chainmask from EEPROM. */ |
2404 | pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); | 2399 | pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); |
2405 | 2400 | ||
2406 | pCap->tx_chainmask = fixup_chainmask(chip_chainmask, pCap->tx_chainmask); | 2401 | pCap->tx_chainmask = fixup_chainmask(pCap->chip_chainmask, pCap->tx_chainmask); |
2407 | pCap->rx_chainmask = fixup_chainmask(chip_chainmask, pCap->rx_chainmask); | 2402 | pCap->rx_chainmask = fixup_chainmask(pCap->chip_chainmask, pCap->rx_chainmask); |
2408 | ah->txchainmask = pCap->tx_chainmask; | 2403 | ah->txchainmask = pCap->tx_chainmask; |
2409 | ah->rxchainmask = pCap->rx_chainmask; | 2404 | ah->rxchainmask = pCap->rx_chainmask; |
2410 | 2405 | ||
@@ -2918,6 +2913,16 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah) | |||
2918 | } | 2913 | } |
2919 | EXPORT_SYMBOL(ath9k_hw_gettsf32); | 2914 | EXPORT_SYMBOL(ath9k_hw_gettsf32); |
2920 | 2915 | ||
2916 | void ath9k_hw_gen_timer_start_tsf2(struct ath_hw *ah) | ||
2917 | { | ||
2918 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; | ||
2919 | |||
2920 | if (timer_table->tsf2_enabled) { | ||
2921 | REG_SET_BIT(ah, AR_DIRECT_CONNECT, AR_DC_AP_STA_EN); | ||
2922 | REG_SET_BIT(ah, AR_RESET_TSF, AR_RESET_TSF2_ONCE); | ||
2923 | } | ||
2924 | } | ||
2925 | |||
2921 | struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, | 2926 | struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, |
2922 | void (*trigger)(void *), | 2927 | void (*trigger)(void *), |
2923 | void (*overflow)(void *), | 2928 | void (*overflow)(void *), |
@@ -2928,7 +2933,11 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, | |||
2928 | struct ath_gen_timer *timer; | 2933 | struct ath_gen_timer *timer; |
2929 | 2934 | ||
2930 | if ((timer_index < AR_FIRST_NDP_TIMER) || | 2935 | if ((timer_index < AR_FIRST_NDP_TIMER) || |
2931 | (timer_index >= ATH_MAX_GEN_TIMER)) | 2936 | (timer_index >= ATH_MAX_GEN_TIMER)) |
2937 | return NULL; | ||
2938 | |||
2939 | if ((timer_index > AR_FIRST_NDP_TIMER) && | ||
2940 | !AR_SREV_9300_20_OR_LATER(ah)) | ||
2932 | return NULL; | 2941 | return NULL; |
2933 | 2942 | ||
2934 | timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL); | 2943 | timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL); |
@@ -2942,6 +2951,11 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, | |||
2942 | timer->overflow = overflow; | 2951 | timer->overflow = overflow; |
2943 | timer->arg = arg; | 2952 | timer->arg = arg; |
2944 | 2953 | ||
2954 | if ((timer_index > AR_FIRST_NDP_TIMER) && !timer_table->tsf2_enabled) { | ||
2955 | timer_table->tsf2_enabled = true; | ||
2956 | ath9k_hw_gen_timer_start_tsf2(ah); | ||
2957 | } | ||
2958 | |||
2945 | return timer; | 2959 | return timer; |
2946 | } | 2960 | } |
2947 | EXPORT_SYMBOL(ath_gen_timer_alloc); | 2961 | EXPORT_SYMBOL(ath_gen_timer_alloc); |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e49721e85f6a..1cbd33551513 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -217,8 +217,8 @@ | |||
217 | #define AH_WOW_BEACON_MISS BIT(3) | 217 | #define AH_WOW_BEACON_MISS BIT(3) |
218 | 218 | ||
219 | enum ath_hw_txq_subtype { | 219 | enum ath_hw_txq_subtype { |
220 | ATH_TXQ_AC_BE = 0, | 220 | ATH_TXQ_AC_BK = 0, |
221 | ATH_TXQ_AC_BK = 1, | 221 | ATH_TXQ_AC_BE = 1, |
222 | ATH_TXQ_AC_VI = 2, | 222 | ATH_TXQ_AC_VI = 2, |
223 | ATH_TXQ_AC_VO = 3, | 223 | ATH_TXQ_AC_VO = 3, |
224 | }; | 224 | }; |
@@ -276,6 +276,7 @@ struct ath9k_hw_capabilities { | |||
276 | u16 rts_aggr_limit; | 276 | u16 rts_aggr_limit; |
277 | u8 tx_chainmask; | 277 | u8 tx_chainmask; |
278 | u8 rx_chainmask; | 278 | u8 rx_chainmask; |
279 | u8 chip_chainmask; | ||
279 | u8 max_txchains; | 280 | u8 max_txchains; |
280 | u8 max_rxchains; | 281 | u8 max_rxchains; |
281 | u8 num_gpio_pins; | 282 | u8 num_gpio_pins; |
@@ -329,6 +330,7 @@ struct ath9k_ops_config { | |||
329 | bool alt_mingainidx; | 330 | bool alt_mingainidx; |
330 | bool no_pll_pwrsave; | 331 | bool no_pll_pwrsave; |
331 | bool tx_gain_buffalo; | 332 | bool tx_gain_buffalo; |
333 | bool led_active_high; | ||
332 | }; | 334 | }; |
333 | 335 | ||
334 | enum ath9k_int { | 336 | enum ath9k_int { |
@@ -524,6 +526,7 @@ struct ath_gen_timer { | |||
524 | struct ath_gen_timer_table { | 526 | struct ath_gen_timer_table { |
525 | struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER]; | 527 | struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER]; |
526 | u16 timer_mask; | 528 | u16 timer_mask; |
529 | bool tsf2_enabled; | ||
527 | }; | 530 | }; |
528 | 531 | ||
529 | struct ath_hw_antcomb_conf { | 532 | struct ath_hw_antcomb_conf { |
@@ -753,7 +756,8 @@ struct ath_hw { | |||
753 | } eeprom; | 756 | } eeprom; |
754 | const struct eeprom_ops *eep_ops; | 757 | const struct eeprom_ops *eep_ops; |
755 | 758 | ||
756 | bool sw_mgmt_crypto; | 759 | bool sw_mgmt_crypto_tx; |
760 | bool sw_mgmt_crypto_rx; | ||
757 | bool is_pciexpress; | 761 | bool is_pciexpress; |
758 | bool aspm_enabled; | 762 | bool aspm_enabled; |
759 | bool is_monitoring; | 763 | bool is_monitoring; |
@@ -936,6 +940,10 @@ struct ath_hw { | |||
936 | const struct firmware *eeprom_blob; | 940 | const struct firmware *eeprom_blob; |
937 | 941 | ||
938 | struct ath_dynack dynack; | 942 | struct ath_dynack dynack; |
943 | |||
944 | bool tpc_enabled; | ||
945 | u8 tx_power[Ar5416RateSize]; | ||
946 | u8 tx_power_stbc[Ar5416RateSize]; | ||
939 | }; | 947 | }; |
940 | 948 | ||
941 | struct ath_bus_ops { | 949 | struct ath_bus_ops { |
@@ -1035,6 +1043,7 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, | |||
1035 | struct ath_gen_timer *timer, | 1043 | struct ath_gen_timer *timer, |
1036 | u32 timer_next, | 1044 | u32 timer_next, |
1037 | u32 timer_period); | 1045 | u32 timer_period); |
1046 | void ath9k_hw_gen_timer_start_tsf2(struct ath_hw *ah); | ||
1038 | void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); | 1047 | void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); |
1039 | 1048 | ||
1040 | void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); | 1049 | void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); |
@@ -1075,6 +1084,8 @@ int ar9003_paprd_init_table(struct ath_hw *ah); | |||
1075 | bool ar9003_paprd_is_done(struct ath_hw *ah); | 1084 | bool ar9003_paprd_is_done(struct ath_hw *ah); |
1076 | bool ar9003_is_paprd_enabled(struct ath_hw *ah); | 1085 | bool ar9003_is_paprd_enabled(struct ath_hw *ah); |
1077 | void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); | 1086 | void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); |
1087 | void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array, | ||
1088 | struct ath9k_channel *chan); | ||
1078 | 1089 | ||
1079 | /* Hardware family op attach helpers */ | 1090 | /* Hardware family op attach helpers */ |
1080 | int ar5008_hw_attach_phy_ops(struct ath_hw *ah); | 1091 | int ar5008_hw_attach_phy_ops(struct ath_hw *ah); |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 2294109f79e9..d1c39346b264 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -88,6 +88,21 @@ static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { | |||
88 | 88 | ||
89 | static void ath9k_deinit_softc(struct ath_softc *sc); | 89 | static void ath9k_deinit_softc(struct ath_softc *sc); |
90 | 90 | ||
91 | static void ath9k_op_ps_wakeup(struct ath_common *common) | ||
92 | { | ||
93 | ath9k_ps_wakeup((struct ath_softc *) common->priv); | ||
94 | } | ||
95 | |||
96 | static void ath9k_op_ps_restore(struct ath_common *common) | ||
97 | { | ||
98 | ath9k_ps_restore((struct ath_softc *) common->priv); | ||
99 | } | ||
100 | |||
101 | static struct ath_ps_ops ath9k_ps_ops = { | ||
102 | .wakeup = ath9k_op_ps_wakeup, | ||
103 | .restore = ath9k_op_ps_restore, | ||
104 | }; | ||
105 | |||
91 | /* | 106 | /* |
92 | * Read and write, they both share the same lock. We do this to serialize | 107 | * Read and write, they both share the same lock. We do this to serialize |
93 | * reads and writes on Atheros 802.11n PCI devices only. This is required | 108 | * reads and writes on Atheros 802.11n PCI devices only. This is required |
@@ -172,17 +187,20 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, | |||
172 | ath_reg_notifier_apply(wiphy, request, reg); | 187 | ath_reg_notifier_apply(wiphy, request, reg); |
173 | 188 | ||
174 | /* Set tx power */ | 189 | /* Set tx power */ |
175 | if (ah->curchan) { | 190 | if (!ah->curchan) |
176 | sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power; | 191 | return; |
177 | ath9k_ps_wakeup(sc); | 192 | |
178 | ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); | 193 | sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power; |
179 | sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; | 194 | ath9k_ps_wakeup(sc); |
180 | /* synchronize DFS detector if regulatory domain changed */ | 195 | ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); |
181 | if (sc->dfs_detector != NULL) | 196 | ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, |
182 | sc->dfs_detector->set_dfs_domain(sc->dfs_detector, | 197 | sc->cur_chan->txpower, |
183 | request->dfs_region); | 198 | &sc->cur_chan->cur_txpower); |
184 | ath9k_ps_restore(sc); | 199 | /* synchronize DFS detector if regulatory domain changed */ |
185 | } | 200 | if (sc->dfs_detector != NULL) |
201 | sc->dfs_detector->set_dfs_domain(sc->dfs_detector, | ||
202 | request->dfs_region); | ||
203 | ath9k_ps_restore(sc); | ||
186 | } | 204 | } |
187 | 205 | ||
188 | /* | 206 | /* |
@@ -348,12 +366,13 @@ static void ath9k_init_misc(struct ath_softc *sc) | |||
348 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) | 366 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) |
349 | sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; | 367 | sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; |
350 | 368 | ||
351 | sc->spec_config.enabled = 0; | 369 | sc->spec_priv.ah = sc->sc_ah; |
352 | sc->spec_config.short_repeat = true; | 370 | sc->spec_priv.spec_config.enabled = 0; |
353 | sc->spec_config.count = 8; | 371 | sc->spec_priv.spec_config.short_repeat = true; |
354 | sc->spec_config.endless = false; | 372 | sc->spec_priv.spec_config.count = 8; |
355 | sc->spec_config.period = 0xFF; | 373 | sc->spec_priv.spec_config.endless = false; |
356 | sc->spec_config.fft_period = 0xF; | 374 | sc->spec_priv.spec_config.period = 0xFF; |
375 | sc->spec_priv.spec_config.fft_period = 0xF; | ||
357 | } | 376 | } |
358 | 377 | ||
359 | static void ath9k_init_pcoem_platform(struct ath_softc *sc) | 378 | static void ath9k_init_pcoem_platform(struct ath_softc *sc) |
@@ -422,6 +441,9 @@ static void ath9k_init_pcoem_platform(struct ath_softc *sc) | |||
422 | ah->config.no_pll_pwrsave = true; | 441 | ah->config.no_pll_pwrsave = true; |
423 | ath_info(common, "Disable PLL PowerSave\n"); | 442 | ath_info(common, "Disable PLL PowerSave\n"); |
424 | } | 443 | } |
444 | |||
445 | if (sc->driver_data & ATH9K_PCI_LED_ACT_HI) | ||
446 | ah->config.led_active_high = true; | ||
425 | } | 447 | } |
426 | 448 | ||
427 | static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, | 449 | static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, |
@@ -510,10 +532,14 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, | |||
510 | ah->reg_ops.read = ath9k_ioread32; | 532 | ah->reg_ops.read = ath9k_ioread32; |
511 | ah->reg_ops.write = ath9k_iowrite32; | 533 | ah->reg_ops.write = ath9k_iowrite32; |
512 | ah->reg_ops.rmw = ath9k_reg_rmw; | 534 | ah->reg_ops.rmw = ath9k_reg_rmw; |
513 | sc->sc_ah = ah; | ||
514 | pCap = &ah->caps; | 535 | pCap = &ah->caps; |
515 | 536 | ||
516 | common = ath9k_hw_common(ah); | 537 | common = ath9k_hw_common(ah); |
538 | |||
539 | /* Will be cleared in ath9k_start() */ | ||
540 | set_bit(ATH_OP_INVALID, &common->op_flags); | ||
541 | |||
542 | sc->sc_ah = ah; | ||
517 | sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); | 543 | sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); |
518 | sc->tx99_power = MAX_RATE_POWER + 1; | 544 | sc->tx99_power = MAX_RATE_POWER + 1; |
519 | init_waitqueue_head(&sc->tx_wait); | 545 | init_waitqueue_head(&sc->tx_wait); |
@@ -539,6 +565,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, | |||
539 | 565 | ||
540 | common->ops = &ah->reg_ops; | 566 | common->ops = &ah->reg_ops; |
541 | common->bus_ops = bus_ops; | 567 | common->bus_ops = bus_ops; |
568 | common->ps_ops = &ath9k_ps_ops; | ||
542 | common->ah = ah; | 569 | common->ah = ah; |
543 | common->hw = sc->hw; | 570 | common->hw = sc->hw; |
544 | common->priv = sc; | 571 | common->priv = sc; |
@@ -741,6 +768,32 @@ static const struct ieee80211_iface_combination if_comb[] = { | |||
741 | #endif | 768 | #endif |
742 | }; | 769 | }; |
743 | 770 | ||
771 | #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT | ||
772 | static void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | ||
773 | { | ||
774 | struct ath_hw *ah = sc->sc_ah; | ||
775 | struct ath_common *common = ath9k_hw_common(ah); | ||
776 | |||
777 | if (!ath9k_is_chanctx_enabled()) | ||
778 | return; | ||
779 | |||
780 | hw->flags |= IEEE80211_HW_QUEUE_CONTROL; | ||
781 | hw->queues = ATH9K_NUM_TX_QUEUES; | ||
782 | hw->offchannel_tx_hw_queue = hw->queues - 1; | ||
783 | hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS); | ||
784 | hw->wiphy->iface_combinations = if_comb_multi; | ||
785 | hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi); | ||
786 | hw->wiphy->max_scan_ssids = 255; | ||
787 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
788 | hw->wiphy->max_remain_on_channel_duration = 10000; | ||
789 | hw->chanctx_data_size = sizeof(void *); | ||
790 | hw->extra_beacon_tailroom = | ||
791 | sizeof(struct ieee80211_p2p_noa_attr) + 9; | ||
792 | |||
793 | ath_dbg(common, CHAN_CTX, "Use channel contexts\n"); | ||
794 | } | ||
795 | #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ | ||
796 | |||
744 | static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | 797 | static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) |
745 | { | 798 | { |
746 | struct ath_hw *ah = sc->sc_ah; | 799 | struct ath_hw *ah = sc->sc_ah; |
@@ -753,7 +806,6 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
753 | IEEE80211_HW_SPECTRUM_MGMT | | 806 | IEEE80211_HW_SPECTRUM_MGMT | |
754 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 807 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | |
755 | IEEE80211_HW_SUPPORTS_RC_TABLE | | 808 | IEEE80211_HW_SUPPORTS_RC_TABLE | |
756 | IEEE80211_HW_QUEUE_CONTROL | | ||
757 | IEEE80211_HW_SUPPORTS_HT_CCK_RATES; | 809 | IEEE80211_HW_SUPPORTS_HT_CCK_RATES; |
758 | 810 | ||
759 | if (ath9k_ps_enable) | 811 | if (ath9k_ps_enable) |
@@ -788,24 +840,6 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
788 | hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); | 840 | hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); |
789 | } | 841 | } |
790 | 842 | ||
791 | #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT | ||
792 | |||
793 | if (ath9k_is_chanctx_enabled()) { | ||
794 | hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS); | ||
795 | hw->wiphy->iface_combinations = if_comb_multi; | ||
796 | hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi); | ||
797 | hw->wiphy->max_scan_ssids = 255; | ||
798 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
799 | hw->wiphy->max_remain_on_channel_duration = 10000; | ||
800 | hw->chanctx_data_size = sizeof(void *); | ||
801 | hw->extra_beacon_tailroom = | ||
802 | sizeof(struct ieee80211_p2p_noa_attr) + 9; | ||
803 | |||
804 | ath_dbg(common, CHAN_CTX, "Use channel contexts\n"); | ||
805 | } | ||
806 | |||
807 | #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ | ||
808 | |||
809 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | 843 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; |
810 | 844 | ||
811 | hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | 845 | hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; |
@@ -815,12 +849,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
815 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; | 849 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; |
816 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | 850 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; |
817 | 851 | ||
818 | /* allow 4 queues per channel context + | 852 | hw->queues = 4; |
819 | * 1 cab queue + 1 offchannel tx queue | ||
820 | */ | ||
821 | hw->queues = ATH9K_NUM_TX_QUEUES; | ||
822 | /* last queue for offchannel */ | ||
823 | hw->offchannel_tx_hw_queue = hw->queues - 1; | ||
824 | hw->max_rates = 4; | 853 | hw->max_rates = 4; |
825 | hw->max_listen_interval = 10; | 854 | hw->max_listen_interval = 10; |
826 | hw->max_rate_tries = 10; | 855 | hw->max_rate_tries = 10; |
@@ -844,6 +873,9 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
844 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | 873 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = |
845 | &common->sbands[IEEE80211_BAND_5GHZ]; | 874 | &common->sbands[IEEE80211_BAND_5GHZ]; |
846 | 875 | ||
876 | #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT | ||
877 | ath9k_set_mcc_capab(sc, hw); | ||
878 | #endif | ||
847 | ath9k_init_wow(hw); | 879 | ath9k_init_wow(hw); |
848 | ath9k_cmn_reload_chainmask(ah); | 880 | ath9k_cmn_reload_chainmask(ah); |
849 | 881 | ||
@@ -868,9 +900,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, | |||
868 | common = ath9k_hw_common(ah); | 900 | common = ath9k_hw_common(ah); |
869 | ath9k_set_hw_capab(sc, hw); | 901 | ath9k_set_hw_capab(sc, hw); |
870 | 902 | ||
871 | /* Will be cleared in ath9k_start() */ | ||
872 | set_bit(ATH_OP_INVALID, &common->op_flags); | ||
873 | |||
874 | /* Initialize regulatory */ | 903 | /* Initialize regulatory */ |
875 | error = ath_regd_init(&common->regulatory, sc->hw->wiphy, | 904 | error = ath_regd_init(&common->regulatory, sc->hw->wiphy, |
876 | ath9k_reg_notifier); | 905 | ath9k_reg_notifier); |
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 275205ab5f15..3e58bfa0c1fd 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
@@ -311,14 +311,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, | |||
311 | q = ATH9K_NUM_TX_QUEUES - 3; | 311 | q = ATH9K_NUM_TX_QUEUES - 3; |
312 | break; | 312 | break; |
313 | case ATH9K_TX_QUEUE_DATA: | 313 | case ATH9K_TX_QUEUE_DATA: |
314 | for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) | 314 | q = qinfo->tqi_subtype; |
315 | if (ah->txq[q].tqi_type == | ||
316 | ATH9K_TX_QUEUE_INACTIVE) | ||
317 | break; | ||
318 | if (q == ATH9K_NUM_TX_QUEUES) { | ||
319 | ath_err(common, "No available TX queue\n"); | ||
320 | return -1; | ||
321 | } | ||
322 | break; | 315 | break; |
323 | default: | 316 | default: |
324 | ath_err(common, "Invalid TX queue type: %u\n", type); | 317 | ath_err(common, "Invalid TX queue type: %u\n", type); |
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index aa69ceaad0be..e55fa11894b6 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h | |||
@@ -704,7 +704,7 @@ struct ath_tx_info { | |||
704 | enum ath9k_pkt_type type; | 704 | enum ath9k_pkt_type type; |
705 | enum ath9k_key_type keytype; | 705 | enum ath9k_key_type keytype; |
706 | u8 keyix; | 706 | u8 keyix; |
707 | u8 txpower; | 707 | u8 txpower[4]; |
708 | }; | 708 | }; |
709 | 709 | ||
710 | struct ath_hw; | 710 | struct ath_hw; |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 45465d8e3f0a..cff070d7a325 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -233,8 +233,9 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) | |||
233 | 233 | ||
234 | ath9k_calculate_summary_state(sc, sc->cur_chan); | 234 | ath9k_calculate_summary_state(sc, sc->cur_chan); |
235 | ath_startrecv(sc); | 235 | ath_startrecv(sc); |
236 | ath9k_cmn_update_txpow(ah, sc->curtxpow, | 236 | ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, |
237 | sc->cur_chan->txpower, &sc->curtxpow); | 237 | sc->cur_chan->txpower, |
238 | &sc->cur_chan->cur_txpower); | ||
238 | clear_bit(ATH_OP_HW_RESET, &common->op_flags); | 239 | clear_bit(ATH_OP_HW_RESET, &common->op_flags); |
239 | 240 | ||
240 | if (!sc->cur_chan->offchannel && start) { | 241 | if (!sc->cur_chan->offchannel && start) { |
@@ -511,16 +512,13 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
511 | if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags)) | 512 | if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags)) |
512 | return IRQ_NONE; | 513 | return IRQ_NONE; |
513 | 514 | ||
514 | /* shared irq, not for us */ | 515 | if (!AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags)) |
516 | return IRQ_NONE; | ||
515 | 517 | ||
518 | /* shared irq, not for us */ | ||
516 | if (!ath9k_hw_intrpend(ah)) | 519 | if (!ath9k_hw_intrpend(ah)) |
517 | return IRQ_NONE; | 520 | return IRQ_NONE; |
518 | 521 | ||
519 | if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { | ||
520 | ath9k_hw_kill_interrupts(ah); | ||
521 | return IRQ_HANDLED; | ||
522 | } | ||
523 | |||
524 | /* | 522 | /* |
525 | * Figure out the reason(s) for the interrupt. Note | 523 | * Figure out the reason(s) for the interrupt. Note |
526 | * that the hal returns a pseudo-ISR that may include | 524 | * that the hal returns a pseudo-ISR that may include |
@@ -531,6 +529,9 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
531 | ath9k_debug_sync_cause(sc, sync_cause); | 529 | ath9k_debug_sync_cause(sc, sync_cause); |
532 | status &= ah->imask; /* discard unasked-for bits */ | 530 | status &= ah->imask; /* discard unasked-for bits */ |
533 | 531 | ||
532 | if (AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags)) | ||
533 | return IRQ_HANDLED; | ||
534 | |||
534 | /* | 535 | /* |
535 | * If there are no status bits set, then this interrupt was not | 536 | * If there are no status bits set, then this interrupt was not |
536 | * for me (should have been caught above). | 537 | * for me (should have been caught above). |
@@ -612,6 +613,7 @@ int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan) | |||
612 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 613 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
613 | int r; | 614 | int r; |
614 | 615 | ||
616 | ath9k_hw_kill_interrupts(sc->sc_ah); | ||
615 | set_bit(ATH_OP_HW_RESET, &common->op_flags); | 617 | set_bit(ATH_OP_HW_RESET, &common->op_flags); |
616 | 618 | ||
617 | ath9k_ps_wakeup(sc); | 619 | ath9k_ps_wakeup(sc); |
@@ -632,6 +634,7 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) | |||
632 | #ifdef CONFIG_ATH9K_DEBUGFS | 634 | #ifdef CONFIG_ATH9K_DEBUGFS |
633 | RESET_STAT_INC(sc, type); | 635 | RESET_STAT_INC(sc, type); |
634 | #endif | 636 | #endif |
637 | ath9k_hw_kill_interrupts(sc->sc_ah); | ||
635 | set_bit(ATH_OP_HW_RESET, &common->op_flags); | 638 | set_bit(ATH_OP_HW_RESET, &common->op_flags); |
636 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | 639 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); |
637 | } | 640 | } |
@@ -726,7 +729,8 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
726 | if (ah->led_pin >= 0) { | 729 | if (ah->led_pin >= 0) { |
727 | ath9k_hw_cfg_output(ah, ah->led_pin, | 730 | ath9k_hw_cfg_output(ah, ah->led_pin, |
728 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 731 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
729 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); | 732 | ath9k_hw_set_gpio(ah, ah->led_pin, |
733 | (ah->config.led_active_high) ? 1 : 0); | ||
730 | } | 734 | } |
731 | 735 | ||
732 | /* | 736 | /* |
@@ -868,7 +872,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
868 | spin_lock_bh(&sc->sc_pcu_lock); | 872 | spin_lock_bh(&sc->sc_pcu_lock); |
869 | 873 | ||
870 | if (ah->led_pin >= 0) { | 874 | if (ah->led_pin >= 0) { |
871 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | 875 | ath9k_hw_set_gpio(ah, ah->led_pin, |
876 | (ah->config.led_active_high) ? 0 : 1); | ||
872 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | 877 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); |
873 | } | 878 | } |
874 | 879 | ||
@@ -884,6 +889,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
884 | &sc->cur_chan->chandef); | 889 | &sc->cur_chan->chandef); |
885 | 890 | ||
886 | ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | 891 | ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); |
892 | |||
893 | set_bit(ATH_OP_INVALID, &common->op_flags); | ||
894 | |||
887 | ath9k_hw_phy_disable(ah); | 895 | ath9k_hw_phy_disable(ah); |
888 | 896 | ||
889 | ath9k_hw_configpcipowersave(ah, true); | 897 | ath9k_hw_configpcipowersave(ah, true); |
@@ -892,7 +900,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
892 | 900 | ||
893 | ath9k_ps_restore(sc); | 901 | ath9k_ps_restore(sc); |
894 | 902 | ||
895 | set_bit(ATH_OP_INVALID, &common->op_flags); | ||
896 | sc->ps_idle = prev_idle; | 903 | sc->ps_idle = prev_idle; |
897 | 904 | ||
898 | mutex_unlock(&sc->mutex); | 905 | mutex_unlock(&sc->mutex); |
@@ -1181,10 +1188,14 @@ static void ath9k_assign_hw_queues(struct ieee80211_hw *hw, | |||
1181 | { | 1188 | { |
1182 | int i; | 1189 | int i; |
1183 | 1190 | ||
1191 | if (!ath9k_is_chanctx_enabled()) | ||
1192 | return; | ||
1193 | |||
1184 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | 1194 | for (i = 0; i < IEEE80211_NUM_ACS; i++) |
1185 | vif->hw_queue[i] = i; | 1195 | vif->hw_queue[i] = i; |
1186 | 1196 | ||
1187 | if (vif->type == NL80211_IFTYPE_AP) | 1197 | if (vif->type == NL80211_IFTYPE_AP || |
1198 | vif->type == NL80211_IFTYPE_MESH_POINT) | ||
1188 | vif->cab_queue = hw->queues - 2; | 1199 | vif->cab_queue = hw->queues - 2; |
1189 | else | 1200 | else |
1190 | vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; | 1201 | vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; |
@@ -1336,78 +1347,6 @@ static void ath9k_disable_ps(struct ath_softc *sc) | |||
1336 | ath_dbg(common, PS, "PowerSave disabled\n"); | 1347 | ath_dbg(common, PS, "PowerSave disabled\n"); |
1337 | } | 1348 | } |
1338 | 1349 | ||
1339 | void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw) | ||
1340 | { | ||
1341 | struct ath_softc *sc = hw->priv; | ||
1342 | struct ath_hw *ah = sc->sc_ah; | ||
1343 | struct ath_common *common = ath9k_hw_common(ah); | ||
1344 | u32 rxfilter; | ||
1345 | |||
1346 | if (config_enabled(CONFIG_ATH9K_TX99)) | ||
1347 | return; | ||
1348 | |||
1349 | if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { | ||
1350 | ath_err(common, "spectrum analyzer not implemented on this hardware\n"); | ||
1351 | return; | ||
1352 | } | ||
1353 | |||
1354 | ath9k_ps_wakeup(sc); | ||
1355 | rxfilter = ath9k_hw_getrxfilter(ah); | ||
1356 | ath9k_hw_setrxfilter(ah, rxfilter | | ||
1357 | ATH9K_RX_FILTER_PHYRADAR | | ||
1358 | ATH9K_RX_FILTER_PHYERR); | ||
1359 | |||
1360 | /* TODO: usually this should not be neccesary, but for some reason | ||
1361 | * (or in some mode?) the trigger must be called after the | ||
1362 | * configuration, otherwise the register will have its values reset | ||
1363 | * (on my ar9220 to value 0x01002310) | ||
1364 | */ | ||
1365 | ath9k_spectral_scan_config(hw, sc->spectral_mode); | ||
1366 | ath9k_hw_ops(ah)->spectral_scan_trigger(ah); | ||
1367 | ath9k_ps_restore(sc); | ||
1368 | } | ||
1369 | |||
1370 | int ath9k_spectral_scan_config(struct ieee80211_hw *hw, | ||
1371 | enum spectral_mode spectral_mode) | ||
1372 | { | ||
1373 | struct ath_softc *sc = hw->priv; | ||
1374 | struct ath_hw *ah = sc->sc_ah; | ||
1375 | struct ath_common *common = ath9k_hw_common(ah); | ||
1376 | |||
1377 | if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { | ||
1378 | ath_err(common, "spectrum analyzer not implemented on this hardware\n"); | ||
1379 | return -1; | ||
1380 | } | ||
1381 | |||
1382 | switch (spectral_mode) { | ||
1383 | case SPECTRAL_DISABLED: | ||
1384 | sc->spec_config.enabled = 0; | ||
1385 | break; | ||
1386 | case SPECTRAL_BACKGROUND: | ||
1387 | /* send endless samples. | ||
1388 | * TODO: is this really useful for "background"? | ||
1389 | */ | ||
1390 | sc->spec_config.endless = 1; | ||
1391 | sc->spec_config.enabled = 1; | ||
1392 | break; | ||
1393 | case SPECTRAL_CHANSCAN: | ||
1394 | case SPECTRAL_MANUAL: | ||
1395 | sc->spec_config.endless = 0; | ||
1396 | sc->spec_config.enabled = 1; | ||
1397 | break; | ||
1398 | default: | ||
1399 | return -1; | ||
1400 | } | ||
1401 | |||
1402 | ath9k_ps_wakeup(sc); | ||
1403 | ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config); | ||
1404 | ath9k_ps_restore(sc); | ||
1405 | |||
1406 | sc->spectral_mode = spectral_mode; | ||
1407 | |||
1408 | return 0; | ||
1409 | } | ||
1410 | |||
1411 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | 1350 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) |
1412 | { | 1351 | { |
1413 | struct ath_softc *sc = hw->priv; | 1352 | struct ath_softc *sc = hw->priv; |
@@ -1468,8 +1407,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
1468 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | 1407 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |
1469 | ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level); | 1408 | ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level); |
1470 | sc->cur_chan->txpower = 2 * conf->power_level; | 1409 | sc->cur_chan->txpower = 2 * conf->power_level; |
1471 | ath9k_cmn_update_txpow(ah, sc->curtxpow, | 1410 | ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, |
1472 | sc->cur_chan->txpower, &sc->curtxpow); | 1411 | sc->cur_chan->txpower, |
1412 | &sc->cur_chan->cur_txpower); | ||
1473 | } | 1413 | } |
1474 | 1414 | ||
1475 | mutex_unlock(&sc->mutex); | 1415 | mutex_unlock(&sc->mutex); |
@@ -1724,7 +1664,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
1724 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 1664 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
1725 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) | 1665 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) |
1726 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 1666 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
1727 | if (sc->sc_ah->sw_mgmt_crypto && | 1667 | if (sc->sc_ah->sw_mgmt_crypto_tx && |
1728 | key->cipher == WLAN_CIPHER_SUITE_CCMP) | 1668 | key->cipher == WLAN_CIPHER_SUITE_CCMP) |
1729 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; | 1669 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; |
1730 | ret = 0; | 1670 | ret = 0; |
@@ -2247,14 +2187,17 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) | |||
2247 | return 0; | 2187 | return 0; |
2248 | } | 2188 | } |
2249 | 2189 | ||
2250 | static void ath9k_sw_scan_start(struct ieee80211_hw *hw) | 2190 | static void ath9k_sw_scan_start(struct ieee80211_hw *hw, |
2191 | struct ieee80211_vif *vif, | ||
2192 | const u8 *mac_addr) | ||
2251 | { | 2193 | { |
2252 | struct ath_softc *sc = hw->priv; | 2194 | struct ath_softc *sc = hw->priv; |
2253 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 2195 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
2254 | set_bit(ATH_OP_SCANNING, &common->op_flags); | 2196 | set_bit(ATH_OP_SCANNING, &common->op_flags); |
2255 | } | 2197 | } |
2256 | 2198 | ||
2257 | static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) | 2199 | static void ath9k_sw_scan_complete(struct ieee80211_hw *hw, |
2200 | struct ieee80211_vif *vif) | ||
2258 | { | 2201 | { |
2259 | struct ath_softc *sc = hw->priv; | 2202 | struct ath_softc *sc = hw->priv; |
2260 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 2203 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
@@ -2263,6 +2206,28 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) | |||
2263 | 2206 | ||
2264 | #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT | 2207 | #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT |
2265 | 2208 | ||
2209 | static void ath9k_cancel_pending_offchannel(struct ath_softc *sc) | ||
2210 | { | ||
2211 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
2212 | |||
2213 | if (sc->offchannel.roc_vif) { | ||
2214 | ath_dbg(common, CHAN_CTX, | ||
2215 | "%s: Aborting RoC\n", __func__); | ||
2216 | |||
2217 | del_timer_sync(&sc->offchannel.timer); | ||
2218 | if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) | ||
2219 | ath_roc_complete(sc, true); | ||
2220 | } | ||
2221 | |||
2222 | if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { | ||
2223 | ath_dbg(common, CHAN_CTX, | ||
2224 | "%s: Aborting HW scan\n", __func__); | ||
2225 | |||
2226 | del_timer_sync(&sc->offchannel.timer); | ||
2227 | ath_scan_complete(sc, true); | ||
2228 | } | ||
2229 | } | ||
2230 | |||
2266 | static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 2231 | static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2267 | struct ieee80211_scan_request *hw_req) | 2232 | struct ieee80211_scan_request *hw_req) |
2268 | { | 2233 | { |
@@ -2449,6 +2414,8 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, | |||
2449 | struct ath_chanctx *ctx = ath_chanctx_get(conf); | 2414 | struct ath_chanctx *ctx = ath_chanctx_get(conf); |
2450 | int i; | 2415 | int i; |
2451 | 2416 | ||
2417 | ath9k_cancel_pending_offchannel(sc); | ||
2418 | |||
2452 | mutex_lock(&sc->mutex); | 2419 | mutex_lock(&sc->mutex); |
2453 | 2420 | ||
2454 | ath_dbg(common, CHAN_CTX, | 2421 | ath_dbg(common, CHAN_CTX, |
@@ -2478,6 +2445,8 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, | |||
2478 | struct ath_chanctx *ctx = ath_chanctx_get(conf); | 2445 | struct ath_chanctx *ctx = ath_chanctx_get(conf); |
2479 | int ac; | 2446 | int ac; |
2480 | 2447 | ||
2448 | ath9k_cancel_pending_offchannel(sc); | ||
2449 | |||
2481 | mutex_lock(&sc->mutex); | 2450 | mutex_lock(&sc->mutex); |
2482 | 2451 | ||
2483 | ath_dbg(common, CHAN_CTX, | 2452 | ath_dbg(common, CHAN_CTX, |
@@ -2523,18 +2492,7 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, | |||
2523 | if (!changed) | 2492 | if (!changed) |
2524 | goto out; | 2493 | goto out; |
2525 | 2494 | ||
2526 | if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { | 2495 | ath9k_cancel_pending_offchannel(sc); |
2527 | ath_dbg(common, CHAN_CTX, | ||
2528 | "%s: Aborting HW scan\n", __func__); | ||
2529 | |||
2530 | mutex_unlock(&sc->mutex); | ||
2531 | |||
2532 | del_timer_sync(&sc->offchannel.timer); | ||
2533 | ath_scan_complete(sc, true); | ||
2534 | flush_work(&sc->chanctx_work); | ||
2535 | |||
2536 | mutex_lock(&sc->mutex); | ||
2537 | } | ||
2538 | 2496 | ||
2539 | go_ctx = ath_is_go_chanctx_present(sc); | 2497 | go_ctx = ath_is_go_chanctx_present(sc); |
2540 | 2498 | ||
@@ -2549,13 +2507,22 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, | |||
2549 | beacon_int = TU_TO_USEC(cur_conf->beacon_interval); | 2507 | beacon_int = TU_TO_USEC(cur_conf->beacon_interval); |
2550 | spin_unlock_bh(&sc->chan_lock); | 2508 | spin_unlock_bh(&sc->chan_lock); |
2551 | 2509 | ||
2552 | timeout = usecs_to_jiffies(beacon_int); | 2510 | timeout = usecs_to_jiffies(beacon_int * 2); |
2553 | init_completion(&sc->go_beacon); | 2511 | init_completion(&sc->go_beacon); |
2554 | 2512 | ||
2513 | mutex_unlock(&sc->mutex); | ||
2514 | |||
2555 | if (wait_for_completion_timeout(&sc->go_beacon, | 2515 | if (wait_for_completion_timeout(&sc->go_beacon, |
2556 | timeout) == 0) | 2516 | timeout) == 0) { |
2557 | ath_dbg(common, CHAN_CTX, | 2517 | ath_dbg(common, CHAN_CTX, |
2558 | "Failed to send new NoA\n"); | 2518 | "Failed to send new NoA\n"); |
2519 | |||
2520 | spin_lock_bh(&sc->chan_lock); | ||
2521 | sc->sched.mgd_prepare_tx = false; | ||
2522 | spin_unlock_bh(&sc->chan_lock); | ||
2523 | } | ||
2524 | |||
2525 | mutex_lock(&sc->mutex); | ||
2559 | } | 2526 | } |
2560 | 2527 | ||
2561 | ath_dbg(common, CHAN_CTX, | 2528 | ath_dbg(common, CHAN_CTX, |
@@ -2591,6 +2558,24 @@ void ath9k_fill_chanctx_ops(void) | |||
2591 | 2558 | ||
2592 | #endif | 2559 | #endif |
2593 | 2560 | ||
2561 | static int ath9k_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
2562 | int *dbm) | ||
2563 | { | ||
2564 | struct ath_softc *sc = hw->priv; | ||
2565 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
2566 | |||
2567 | mutex_lock(&sc->mutex); | ||
2568 | if (avp->chanctx) | ||
2569 | *dbm = avp->chanctx->cur_txpower; | ||
2570 | else | ||
2571 | *dbm = sc->cur_chan->cur_txpower; | ||
2572 | mutex_unlock(&sc->mutex); | ||
2573 | |||
2574 | *dbm /= 2; | ||
2575 | |||
2576 | return 0; | ||
2577 | } | ||
2578 | |||
2594 | struct ieee80211_ops ath9k_ops = { | 2579 | struct ieee80211_ops ath9k_ops = { |
2595 | .tx = ath9k_tx, | 2580 | .tx = ath9k_tx, |
2596 | .start = ath9k_start, | 2581 | .start = ath9k_start, |
@@ -2637,4 +2622,5 @@ struct ieee80211_ops ath9k_ops = { | |||
2637 | #endif | 2622 | #endif |
2638 | .sw_scan_start = ath9k_sw_scan_start, | 2623 | .sw_scan_start = ath9k_sw_scan_start, |
2639 | .sw_scan_complete = ath9k_sw_scan_complete, | 2624 | .sw_scan_complete = ath9k_sw_scan_complete, |
2625 | .get_txpower = ath9k_get_txpower, | ||
2640 | }; | 2626 | }; |
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index e3f60d5c5263..f009b5b57e5e 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -657,7 +657,9 @@ static const struct pci_device_id ath_pci_id_table[] = { | |||
657 | 0x0036, | 657 | 0x0036, |
658 | PCI_VENDOR_ID_DELL, | 658 | PCI_VENDOR_ID_DELL, |
659 | 0x020E), | 659 | 0x020E), |
660 | .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, | 660 | .driver_data = ATH9K_PCI_AR9565_2ANT | |
661 | ATH9K_PCI_BT_ANT_DIV | | ||
662 | ATH9K_PCI_LED_ACT_HI}, | ||
661 | 663 | ||
662 | /* PCI-E AR9565 (WB335) */ | 664 | /* PCI-E AR9565 (WB335) */ |
663 | { PCI_VDEVICE(ATHEROS, 0x0036), | 665 | { PCI_VDEVICE(ATHEROS, 0x0036), |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6914e21816e4..7395afbc5124 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -870,7 +870,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, | |||
870 | */ | 870 | */ |
871 | if (rx_stats->rs_status & ATH9K_RXERR_PHY) { | 871 | if (rx_stats->rs_status & ATH9K_RXERR_PHY) { |
872 | ath9k_dfs_process_phyerr(sc, hdr, rx_stats, rx_status->mactime); | 872 | ath9k_dfs_process_phyerr(sc, hdr, rx_stats, rx_status->mactime); |
873 | if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime)) | 873 | if (ath_cmn_process_fft(&sc->spec_priv, hdr, rx_stats, rx_status->mactime)) |
874 | RX_STAT_INC(rx_spectral); | 874 | RX_STAT_INC(rx_spectral); |
875 | 875 | ||
876 | return -EINVAL; | 876 | return -EINVAL; |
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 1c0b1c1c5350..fb11a9172f38 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h | |||
@@ -1605,6 +1605,7 @@ enum { | |||
1605 | 1605 | ||
1606 | #define AR_RESET_TSF 0x8020 | 1606 | #define AR_RESET_TSF 0x8020 |
1607 | #define AR_RESET_TSF_ONCE 0x01000000 | 1607 | #define AR_RESET_TSF_ONCE 0x01000000 |
1608 | #define AR_RESET_TSF2_ONCE 0x02000000 | ||
1608 | 1609 | ||
1609 | #define AR_MAX_CFP_DUR 0x8038 | 1610 | #define AR_MAX_CFP_DUR 0x8038 |
1610 | #define AR_CFP_VAL 0x0000FFFF | 1611 | #define AR_CFP_VAL 0x0000FFFF |
@@ -1723,6 +1724,8 @@ enum { | |||
1723 | #define AR_TPC_CTS_S 8 | 1724 | #define AR_TPC_CTS_S 8 |
1724 | #define AR_TPC_CHIRP 0x003f0000 | 1725 | #define AR_TPC_CHIRP 0x003f0000 |
1725 | #define AR_TPC_CHIRP_S 16 | 1726 | #define AR_TPC_CHIRP_S 16 |
1727 | #define AR_TPC_RPT 0x3f000000 | ||
1728 | #define AR_TPC_RPT_S 24 | ||
1726 | 1729 | ||
1727 | #define AR_QUIET1 0x80fc | 1730 | #define AR_QUIET1 0x80fc |
1728 | #define AR_QUIET1_NEXT_QUIET_S 0 | 1731 | #define AR_QUIET1_NEXT_QUIET_S 0 |
@@ -1966,6 +1969,8 @@ enum { | |||
1966 | #define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000 | 1969 | #define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000 |
1967 | #define AR_MAC_PCU_GEN_TIMER_TSF_SEL 0x83d8 | 1970 | #define AR_MAC_PCU_GEN_TIMER_TSF_SEL 0x83d8 |
1968 | 1971 | ||
1972 | #define AR_DIRECT_CONNECT 0x83a0 | ||
1973 | #define AR_DC_AP_STA_EN 0x00000001 | ||
1969 | 1974 | ||
1970 | #define AR_AES_MUTE_MASK0 0x805c | 1975 | #define AR_AES_MUTE_MASK0 0x805c |
1971 | #define AR_AES_MUTE_MASK0_FC 0x0000FFFF | 1976 | #define AR_AES_MUTE_MASK0_FC 0x0000FFFF |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 493a183d0aaf..e9bd02c2e844 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -169,7 +169,10 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, | |||
169 | 169 | ||
170 | if (txq->stopped && | 170 | if (txq->stopped && |
171 | txq->pending_frames < sc->tx.txq_max_pending[q]) { | 171 | txq->pending_frames < sc->tx.txq_max_pending[q]) { |
172 | ieee80211_wake_queue(sc->hw, info->hw_queue); | 172 | if (ath9k_is_chanctx_enabled()) |
173 | ieee80211_wake_queue(sc->hw, info->hw_queue); | ||
174 | else | ||
175 | ieee80211_wake_queue(sc->hw, q); | ||
173 | txq->stopped = false; | 176 | txq->stopped = false; |
174 | } | 177 | } |
175 | } | 178 | } |
@@ -1093,6 +1096,37 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop) | |||
1093 | } | 1096 | } |
1094 | } | 1097 | } |
1095 | 1098 | ||
1099 | static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, | ||
1100 | u8 rateidx) | ||
1101 | { | ||
1102 | u8 max_power; | ||
1103 | struct ath_hw *ah = sc->sc_ah; | ||
1104 | |||
1105 | if (sc->tx99_state) | ||
1106 | return MAX_RATE_POWER; | ||
1107 | |||
1108 | if (!AR_SREV_9300_20_OR_LATER(ah)) { | ||
1109 | /* ar9002 is not sipported for the moment */ | ||
1110 | return MAX_RATE_POWER; | ||
1111 | } | ||
1112 | |||
1113 | if (!bf->bf_state.bfs_paprd) { | ||
1114 | struct sk_buff *skb = bf->bf_mpdu; | ||
1115 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1116 | struct ath_frame_info *fi = get_frame_info(skb); | ||
1117 | |||
1118 | if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC)) | ||
1119 | max_power = min(ah->tx_power_stbc[rateidx], | ||
1120 | fi->tx_power); | ||
1121 | else | ||
1122 | max_power = min(ah->tx_power[rateidx], fi->tx_power); | ||
1123 | } else { | ||
1124 | max_power = ah->paprd_training_power; | ||
1125 | } | ||
1126 | |||
1127 | return max_power; | ||
1128 | } | ||
1129 | |||
1096 | static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, | 1130 | static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, |
1097 | struct ath_tx_info *info, int len, bool rts) | 1131 | struct ath_tx_info *info, int len, bool rts) |
1098 | { | 1132 | { |
@@ -1163,6 +1197,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, | |||
1163 | is_40, is_sgi, is_sp); | 1197 | is_40, is_sgi, is_sp); |
1164 | if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) | 1198 | if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) |
1165 | info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC; | 1199 | info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC; |
1200 | |||
1201 | info->txpower[i] = ath_get_rate_txpower(sc, bf, rix); | ||
1166 | continue; | 1202 | continue; |
1167 | } | 1203 | } |
1168 | 1204 | ||
@@ -1190,6 +1226,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, | |||
1190 | 1226 | ||
1191 | info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, | 1227 | info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, |
1192 | phy, rate->bitrate * 100, len, rix, is_sp); | 1228 | phy, rate->bitrate * 100, len, rix, is_sp); |
1229 | |||
1230 | info->txpower[i] = ath_get_rate_txpower(sc, bf, rix); | ||
1193 | } | 1231 | } |
1194 | 1232 | ||
1195 | /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ | 1233 | /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ |
@@ -1236,7 +1274,6 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, | |||
1236 | memset(&info, 0, sizeof(info)); | 1274 | memset(&info, 0, sizeof(info)); |
1237 | info.is_first = true; | 1275 | info.is_first = true; |
1238 | info.is_last = true; | 1276 | info.is_last = true; |
1239 | info.txpower = MAX_RATE_POWER; | ||
1240 | info.qcu = txq->axq_qnum; | 1277 | info.qcu = txq->axq_qnum; |
1241 | 1278 | ||
1242 | while (bf) { | 1279 | while (bf) { |
@@ -2060,6 +2097,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, | |||
2060 | fi->keyix = ATH9K_TXKEYIX_INVALID; | 2097 | fi->keyix = ATH9K_TXKEYIX_INVALID; |
2061 | fi->keytype = keytype; | 2098 | fi->keytype = keytype; |
2062 | fi->framelen = framelen; | 2099 | fi->framelen = framelen; |
2100 | fi->tx_power = MAX_RATE_POWER; | ||
2063 | 2101 | ||
2064 | if (!rate) | 2102 | if (!rate) |
2065 | return; | 2103 | return; |
@@ -2247,7 +2285,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
2247 | fi->txq = q; | 2285 | fi->txq = q; |
2248 | if (++txq->pending_frames > sc->tx.txq_max_pending[q] && | 2286 | if (++txq->pending_frames > sc->tx.txq_max_pending[q] && |
2249 | !txq->stopped) { | 2287 | !txq->stopped) { |
2250 | ieee80211_stop_queue(sc->hw, info->hw_queue); | 2288 | if (ath9k_is_chanctx_enabled()) |
2289 | ieee80211_stop_queue(sc->hw, info->hw_queue); | ||
2290 | else | ||
2291 | ieee80211_stop_queue(sc->hw, q); | ||
2251 | txq->stopped = true; | 2292 | txq->stopped = true; |
2252 | } | 2293 | } |
2253 | } | 2294 | } |
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index 650be79c7ac9..cfd0554cf140 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c | |||
@@ -86,7 +86,7 @@ static const struct radar_detector_specs fcc_radar_ref_types[] = { | |||
86 | FCC_PATTERN(1, 0, 5, 150, 230, 1, 23), | 86 | FCC_PATTERN(1, 0, 5, 150, 230, 1, 23), |
87 | FCC_PATTERN(2, 6, 10, 200, 500, 1, 16), | 87 | FCC_PATTERN(2, 6, 10, 200, 500, 1, 16), |
88 | FCC_PATTERN(3, 11, 20, 200, 500, 1, 12), | 88 | FCC_PATTERN(3, 11, 20, 200, 500, 1, 12), |
89 | FCC_PATTERN(4, 50, 100, 1000, 2000, 20, 1), | 89 | FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 20), |
90 | FCC_PATTERN(5, 0, 1, 333, 333, 1, 9), | 90 | FCC_PATTERN(5, 0, 1, 333, 333, 1, 9), |
91 | }; | 91 | }; |
92 | 92 | ||
@@ -105,7 +105,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = { | |||
105 | JP_PATTERN(4, 0, 5, 150, 230, 1, 23), | 105 | JP_PATTERN(4, 0, 5, 150, 230, 1, 23), |
106 | JP_PATTERN(5, 6, 10, 200, 500, 1, 16), | 106 | JP_PATTERN(5, 6, 10, 200, 500, 1, 16), |
107 | JP_PATTERN(6, 11, 20, 200, 500, 1, 12), | 107 | JP_PATTERN(6, 11, 20, 200, 500, 1, 12), |
108 | JP_PATTERN(7, 50, 100, 1000, 2000, 20, 1), | 108 | JP_PATTERN(7, 50, 100, 1000, 2000, 1, 20), |
109 | JP_PATTERN(5, 0, 1, 333, 333, 1, 9), | 109 | JP_PATTERN(5, 0, 1, 333, 333, 1, 9), |
110 | }; | 110 | }; |
111 | 111 | ||
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 415393dfb6fc..06ea6cc9e30a 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c | |||
@@ -515,6 +515,7 @@ void ath_reg_notifier_apply(struct wiphy *wiphy, | |||
515 | if (!request) | 515 | if (!request) |
516 | return; | 516 | return; |
517 | 517 | ||
518 | reg->region = request->dfs_region; | ||
518 | switch (request->initiator) { | 519 | switch (request->initiator) { |
519 | case NL80211_REGDOM_SET_BY_CORE: | 520 | case NL80211_REGDOM_SET_BY_CORE: |
520 | /* | 521 | /* |
@@ -779,6 +780,19 @@ u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, | |||
779 | return SD_NO_CTL; | 780 | return SD_NO_CTL; |
780 | } | 781 | } |
781 | 782 | ||
783 | if (ath_regd_get_eepromRD(reg) == CTRY_DEFAULT) { | ||
784 | switch (reg->region) { | ||
785 | case NL80211_DFS_FCC: | ||
786 | return CTL_FCC; | ||
787 | case NL80211_DFS_ETSI: | ||
788 | return CTL_ETSI; | ||
789 | case NL80211_DFS_JP: | ||
790 | return CTL_MKK; | ||
791 | default: | ||
792 | break; | ||
793 | } | ||
794 | } | ||
795 | |||
782 | switch (band) { | 796 | switch (band) { |
783 | case IEEE80211_BAND_2GHZ: | 797 | case IEEE80211_BAND_2GHZ: |
784 | return reg->regpair->reg_2ghz_ctl; | 798 | return reg->regpair->reg_2ghz_ctl; |
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index b71d2b33532d..267c35d1f699 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c | |||
@@ -494,7 +494,9 @@ out: | |||
494 | return ret; | 494 | return ret; |
495 | } | 495 | } |
496 | 496 | ||
497 | static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw) | 497 | static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw, |
498 | struct ieee80211_vif *vif, | ||
499 | const u8 *mac_addr) | ||
498 | { | 500 | { |
499 | struct wcn36xx *wcn = hw->priv; | 501 | struct wcn36xx *wcn = hw->priv; |
500 | 502 | ||
@@ -502,7 +504,8 @@ static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw) | |||
502 | wcn36xx_smd_start_scan(wcn); | 504 | wcn36xx_smd_start_scan(wcn); |
503 | } | 505 | } |
504 | 506 | ||
505 | static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw) | 507 | static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw, |
508 | struct ieee80211_vif *vif) | ||
506 | { | 509 | { |
507 | struct wcn36xx *wcn = hw->priv; | 510 | struct wcn36xx *wcn = hw->priv; |
508 | 511 | ||
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 4248fb3352d2..38332a6dfb3a 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c | |||
@@ -792,12 +792,13 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, | |||
792 | } | 792 | } |
793 | 793 | ||
794 | static int wil_cfg80211_del_station(struct wiphy *wiphy, | 794 | static int wil_cfg80211_del_station(struct wiphy *wiphy, |
795 | struct net_device *dev, const u8 *mac) | 795 | struct net_device *dev, |
796 | struct station_del_parameters *params) | ||
796 | { | 797 | { |
797 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | 798 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); |
798 | 799 | ||
799 | mutex_lock(&wil->mutex); | 800 | mutex_lock(&wil->mutex); |
800 | wil6210_disconnect(wil, mac, false); | 801 | wil6210_disconnect(wil, params->mac, params->reason_code, false); |
801 | mutex_unlock(&wil->mutex); | 802 | mutex_unlock(&wil->mutex); |
802 | 803 | ||
803 | return 0; | 804 | return 0; |
diff --git a/drivers/net/wireless/ath/wil6210/debug.c b/drivers/net/wireless/ath/wil6210/debug.c index 8d99021d27a8..3249562d93b4 100644 --- a/drivers/net/wireless/ath/wil6210/debug.c +++ b/drivers/net/wireless/ath/wil6210/debug.c | |||
@@ -32,6 +32,23 @@ void wil_err(struct wil6210_priv *wil, const char *fmt, ...) | |||
32 | va_end(args); | 32 | va_end(args); |
33 | } | 33 | } |
34 | 34 | ||
35 | void wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...) | ||
36 | { | ||
37 | if (net_ratelimit()) { | ||
38 | struct net_device *ndev = wil_to_ndev(wil); | ||
39 | struct va_format vaf = { | ||
40 | .fmt = fmt, | ||
41 | }; | ||
42 | va_list args; | ||
43 | |||
44 | va_start(args, fmt); | ||
45 | vaf.va = &args; | ||
46 | netdev_err(ndev, "%pV", &vaf); | ||
47 | trace_wil6210_log_err(&vaf); | ||
48 | va_end(args); | ||
49 | } | ||
50 | } | ||
51 | |||
35 | void wil_info(struct wil6210_priv *wil, const char *fmt, ...) | 52 | void wil_info(struct wil6210_priv *wil, const char *fmt, ...) |
36 | { | 53 | { |
37 | struct net_device *ndev = wil_to_ndev(wil); | 54 | struct net_device *ndev = wil_to_ndev(wil); |
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 54a6ddc6301b..4e6e14501c2f 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c | |||
@@ -573,8 +573,10 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, | |||
573 | if (!frame) | 573 | if (!frame) |
574 | return -ENOMEM; | 574 | return -ENOMEM; |
575 | 575 | ||
576 | if (copy_from_user(frame, buf, len)) | 576 | if (copy_from_user(frame, buf, len)) { |
577 | kfree(frame); | ||
577 | return -EIO; | 578 | return -EIO; |
579 | } | ||
578 | 580 | ||
579 | params.buf = frame; | 581 | params.buf = frame; |
580 | params.len = len; | 582 | params.len = len; |
@@ -614,8 +616,10 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, | |||
614 | return -ENOMEM; | 616 | return -ENOMEM; |
615 | 617 | ||
616 | rc = simple_write_to_buffer(wmi, len, ppos, buf, len); | 618 | rc = simple_write_to_buffer(wmi, len, ppos, buf, len); |
617 | if (rc < 0) | 619 | if (rc < 0) { |
620 | kfree(wmi); | ||
618 | return rc; | 621 | return rc; |
622 | } | ||
619 | 623 | ||
620 | cmd = &wmi[1]; | 624 | cmd = &wmi[1]; |
621 | cmdid = le16_to_cpu(wmi->id); | 625 | cmdid = le16_to_cpu(wmi->id); |
diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c index 8c6f3b041f77..93c5cc16c515 100644 --- a/drivers/net/wireless/ath/wil6210/fw.c +++ b/drivers/net/wireless/ath/wil6210/fw.c | |||
@@ -15,7 +15,6 @@ | |||
15 | */ | 15 | */ |
16 | #include <linux/firmware.h> | 16 | #include <linux/firmware.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/pci.h> | ||
19 | #include <linux/crc32.h> | 18 | #include <linux/crc32.h> |
20 | #include "wil6210.h" | 19 | #include "wil6210.h" |
21 | #include "fw.h" | 20 | #include "fw.h" |
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index 44cb71f5ea5b..d4acf93a9a02 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c | |||
@@ -446,7 +446,7 @@ static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size) | |||
446 | if (size >= sizeof(*hdr)) { | 446 | if (size >= sizeof(*hdr)) { |
447 | wil_err_fw(wil, "Stop at offset %ld" | 447 | wil_err_fw(wil, "Stop at offset %ld" |
448 | " record type %d [%zd bytes]\n", | 448 | " record type %d [%zd bytes]\n", |
449 | (const void *)hdr - data, | 449 | (long)((const void *)hdr - data), |
450 | le16_to_cpu(hdr->type), hdr_sz); | 450 | le16_to_cpu(hdr->type), hdr_sz); |
451 | } | 451 | } |
452 | return -EINVAL; | 452 | return -EINVAL; |
@@ -471,7 +471,7 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name) | |||
471 | size_t sz; | 471 | size_t sz; |
472 | const void *d; | 472 | const void *d; |
473 | 473 | ||
474 | rc = request_firmware(&fw, name, wil_to_pcie_dev(wil)); | 474 | rc = request_firmware(&fw, name, wil_to_dev(wil)); |
475 | if (rc) { | 475 | if (rc) { |
476 | wil_err_fw(wil, "Failed to load firmware %s\n", name); | 476 | wil_err_fw(wil, "Failed to load firmware %s\n", name); |
477 | return rc; | 477 | return rc; |
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 90f416f239bd..4bcbd6297b3e 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c | |||
@@ -36,7 +36,8 @@ | |||
36 | */ | 36 | */ |
37 | 37 | ||
38 | #define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL) | 38 | #define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL) |
39 | #define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE | 39 | #define WIL6210_IMC_RX (BIT_DMA_EP_RX_ICR_RX_DONE | \ |
40 | BIT_DMA_EP_RX_ICR_RX_HTRSH) | ||
40 | #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ | 41 | #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ |
41 | BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) | 42 | BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) |
42 | #define WIL6210_IMC_MISC (ISR_MISC_FW_READY | \ | 43 | #define WIL6210_IMC_MISC (ISR_MISC_FW_READY | \ |
@@ -171,6 +172,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | |||
171 | u32 isr = wil_ioread32_and_clear(wil->csr + | 172 | u32 isr = wil_ioread32_and_clear(wil->csr + |
172 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | 173 | HOSTADDR(RGF_DMA_EP_RX_ICR) + |
173 | offsetof(struct RGF_ICR, ICR)); | 174 | offsetof(struct RGF_ICR, ICR)); |
175 | bool need_unmask = true; | ||
174 | 176 | ||
175 | trace_wil6210_irq_rx(isr); | 177 | trace_wil6210_irq_rx(isr); |
176 | wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); | 178 | wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); |
@@ -182,12 +184,24 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | |||
182 | 184 | ||
183 | wil6210_mask_irq_rx(wil); | 185 | wil6210_mask_irq_rx(wil); |
184 | 186 | ||
185 | if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { | 187 | /* RX_DONE and RX_HTRSH interrupts are the same if interrupt |
188 | * moderation is not used. Interrupt moderation may cause RX | ||
189 | * buffer overflow while RX_DONE is delayed. The required | ||
190 | * action is always the same - should empty the accumulated | ||
191 | * packets from the RX ring. | ||
192 | */ | ||
193 | if (isr & (BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH)) { | ||
186 | wil_dbg_irq(wil, "RX done\n"); | 194 | wil_dbg_irq(wil, "RX done\n"); |
187 | isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; | 195 | |
196 | if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH) | ||
197 | wil_err_ratelimited(wil, "Received \"Rx buffer is in risk " | ||
198 | "of overflow\" interrupt\n"); | ||
199 | |||
200 | isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH); | ||
188 | if (test_bit(wil_status_reset_done, &wil->status)) { | 201 | if (test_bit(wil_status_reset_done, &wil->status)) { |
189 | if (test_bit(wil_status_napi_en, &wil->status)) { | 202 | if (test_bit(wil_status_napi_en, &wil->status)) { |
190 | wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); | 203 | wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); |
204 | need_unmask = false; | ||
191 | napi_schedule(&wil->napi_rx); | 205 | napi_schedule(&wil->napi_rx); |
192 | } else { | 206 | } else { |
193 | wil_err(wil, "Got Rx interrupt while " | 207 | wil_err(wil, "Got Rx interrupt while " |
@@ -204,6 +218,10 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | |||
204 | /* Rx IRQ will be enabled when NAPI processing finished */ | 218 | /* Rx IRQ will be enabled when NAPI processing finished */ |
205 | 219 | ||
206 | atomic_inc(&wil->isr_count_rx); | 220 | atomic_inc(&wil->isr_count_rx); |
221 | |||
222 | if (unlikely(need_unmask)) | ||
223 | wil6210_unmask_irq_rx(wil); | ||
224 | |||
207 | return IRQ_HANDLED; | 225 | return IRQ_HANDLED; |
208 | } | 226 | } |
209 | 227 | ||
@@ -213,6 +231,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | |||
213 | u32 isr = wil_ioread32_and_clear(wil->csr + | 231 | u32 isr = wil_ioread32_and_clear(wil->csr + |
214 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | 232 | HOSTADDR(RGF_DMA_EP_TX_ICR) + |
215 | offsetof(struct RGF_ICR, ICR)); | 233 | offsetof(struct RGF_ICR, ICR)); |
234 | bool need_unmask = true; | ||
216 | 235 | ||
217 | trace_wil6210_irq_tx(isr); | 236 | trace_wil6210_irq_tx(isr); |
218 | wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); | 237 | wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); |
@@ -231,6 +250,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | |||
231 | isr &= ~(BIT(25) - 1UL); | 250 | isr &= ~(BIT(25) - 1UL); |
232 | if (test_bit(wil_status_reset_done, &wil->status)) { | 251 | if (test_bit(wil_status_reset_done, &wil->status)) { |
233 | wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); | 252 | wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); |
253 | need_unmask = false; | ||
234 | napi_schedule(&wil->napi_tx); | 254 | napi_schedule(&wil->napi_tx); |
235 | } else { | 255 | } else { |
236 | wil_err(wil, "Got Tx interrupt while in reset\n"); | 256 | wil_err(wil, "Got Tx interrupt while in reset\n"); |
@@ -243,6 +263,10 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | |||
243 | /* Tx IRQ will be enabled when NAPI processing finished */ | 263 | /* Tx IRQ will be enabled when NAPI processing finished */ |
244 | 264 | ||
245 | atomic_inc(&wil->isr_count_tx); | 265 | atomic_inc(&wil->isr_count_tx); |
266 | |||
267 | if (unlikely(need_unmask)) | ||
268 | wil6210_unmask_irq_tx(wil); | ||
269 | |||
246 | return IRQ_HANDLED; | 270 | return IRQ_HANDLED; |
247 | } | 271 | } |
248 | 272 | ||
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 6212983fede2..8ff3fe34fe05 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c | |||
@@ -67,6 +67,36 @@ static struct kernel_param_ops mtu_max_ops = { | |||
67 | module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, S_IRUGO); | 67 | module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, S_IRUGO); |
68 | MODULE_PARM_DESC(mtu_max, " Max MTU value."); | 68 | MODULE_PARM_DESC(mtu_max, " Max MTU value."); |
69 | 69 | ||
70 | static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; | ||
71 | static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; | ||
72 | |||
73 | static int ring_order_set(const char *val, const struct kernel_param *kp) | ||
74 | { | ||
75 | int ret; | ||
76 | uint x; | ||
77 | |||
78 | ret = kstrtouint(val, 0, &x); | ||
79 | if (ret) | ||
80 | return ret; | ||
81 | |||
82 | if ((x < WIL_RING_SIZE_ORDER_MIN) || (x > WIL_RING_SIZE_ORDER_MAX)) | ||
83 | return -EINVAL; | ||
84 | |||
85 | *((uint *)kp->arg) = x; | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static struct kernel_param_ops ring_order_ops = { | ||
91 | .set = ring_order_set, | ||
92 | .get = param_get_uint, | ||
93 | }; | ||
94 | |||
95 | module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO); | ||
96 | MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order"); | ||
97 | module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO); | ||
98 | MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order"); | ||
99 | |||
70 | #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ | 100 | #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ |
71 | #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ | 101 | #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ |
72 | 102 | ||
@@ -104,7 +134,7 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, | |||
104 | } | 134 | } |
105 | 135 | ||
106 | static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, | 136 | static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, |
107 | bool from_event) | 137 | u16 reason_code, bool from_event) |
108 | { | 138 | { |
109 | uint i; | 139 | uint i; |
110 | struct net_device *ndev = wil_to_ndev(wil); | 140 | struct net_device *ndev = wil_to_ndev(wil); |
@@ -117,8 +147,7 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, | |||
117 | sta->data_port_open = false; | 147 | sta->data_port_open = false; |
118 | if (sta->status != wil_sta_unused) { | 148 | if (sta->status != wil_sta_unused) { |
119 | if (!from_event) | 149 | if (!from_event) |
120 | wmi_disconnect_sta(wil, sta->addr, | 150 | wmi_disconnect_sta(wil, sta->addr, reason_code); |
121 | WLAN_REASON_DEAUTH_LEAVING); | ||
122 | 151 | ||
123 | switch (wdev->iftype) { | 152 | switch (wdev->iftype) { |
124 | case NL80211_IFTYPE_AP: | 153 | case NL80211_IFTYPE_AP: |
@@ -152,7 +181,7 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, | |||
152 | } | 181 | } |
153 | 182 | ||
154 | static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, | 183 | static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, |
155 | bool from_event) | 184 | u16 reason_code, bool from_event) |
156 | { | 185 | { |
157 | int cid = -ENOENT; | 186 | int cid = -ENOENT; |
158 | struct net_device *ndev = wil_to_ndev(wil); | 187 | struct net_device *ndev = wil_to_ndev(wil); |
@@ -167,10 +196,10 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, | |||
167 | } | 196 | } |
168 | 197 | ||
169 | if (cid >= 0) /* disconnect 1 peer */ | 198 | if (cid >= 0) /* disconnect 1 peer */ |
170 | wil_disconnect_cid(wil, cid, from_event); | 199 | wil_disconnect_cid(wil, cid, reason_code, from_event); |
171 | else /* disconnect all */ | 200 | else /* disconnect all */ |
172 | for (cid = 0; cid < WIL6210_MAX_CID; cid++) | 201 | for (cid = 0; cid < WIL6210_MAX_CID; cid++) |
173 | wil_disconnect_cid(wil, cid, from_event); | 202 | wil_disconnect_cid(wil, cid, reason_code, from_event); |
174 | 203 | ||
175 | /* link state */ | 204 | /* link state */ |
176 | switch (wdev->iftype) { | 205 | switch (wdev->iftype) { |
@@ -179,8 +208,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, | |||
179 | wil_link_off(wil); | 208 | wil_link_off(wil); |
180 | if (test_bit(wil_status_fwconnected, &wil->status)) { | 209 | if (test_bit(wil_status_fwconnected, &wil->status)) { |
181 | clear_bit(wil_status_fwconnected, &wil->status); | 210 | clear_bit(wil_status_fwconnected, &wil->status); |
182 | cfg80211_disconnected(ndev, | 211 | cfg80211_disconnected(ndev, reason_code, |
183 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
184 | NULL, 0, GFP_KERNEL); | 212 | NULL, 0, GFP_KERNEL); |
185 | } else if (test_bit(wil_status_fwconnecting, &wil->status)) { | 213 | } else if (test_bit(wil_status_fwconnecting, &wil->status)) { |
186 | cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, | 214 | cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, |
@@ -200,7 +228,7 @@ static void wil_disconnect_worker(struct work_struct *work) | |||
200 | struct wil6210_priv, disconnect_worker); | 228 | struct wil6210_priv, disconnect_worker); |
201 | 229 | ||
202 | mutex_lock(&wil->mutex); | 230 | mutex_lock(&wil->mutex); |
203 | _wil6210_disconnect(wil, NULL, false); | 231 | _wil6210_disconnect(wil, NULL, WLAN_REASON_UNSPECIFIED, false); |
204 | mutex_unlock(&wil->mutex); | 232 | mutex_unlock(&wil->mutex); |
205 | } | 233 | } |
206 | 234 | ||
@@ -222,6 +250,7 @@ static void wil_scan_timer_fn(ulong x) | |||
222 | 250 | ||
223 | clear_bit(wil_status_fwready, &wil->status); | 251 | clear_bit(wil_status_fwready, &wil->status); |
224 | wil_err(wil, "Scan timeout detected, start fw error recovery\n"); | 252 | wil_err(wil, "Scan timeout detected, start fw error recovery\n"); |
253 | wil->recovery_state = fw_recovery_pending; | ||
225 | schedule_work(&wil->fw_error_worker); | 254 | schedule_work(&wil->fw_error_worker); |
226 | } | 255 | } |
227 | 256 | ||
@@ -333,7 +362,7 @@ static void wil_connect_worker(struct work_struct *work) | |||
333 | 362 | ||
334 | wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid); | 363 | wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid); |
335 | 364 | ||
336 | rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0); | 365 | rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0); |
337 | wil->pending_connect_cid = -1; | 366 | wil->pending_connect_cid = -1; |
338 | if (rc == 0) { | 367 | if (rc == 0) { |
339 | wil->sta[cid].status = wil_sta_connected; | 368 | wil->sta[cid].status = wil_sta_connected; |
@@ -392,18 +421,19 @@ int wil_priv_init(struct wil6210_priv *wil) | |||
392 | * wil6210_disconnect - disconnect one connection | 421 | * wil6210_disconnect - disconnect one connection |
393 | * @wil: driver context | 422 | * @wil: driver context |
394 | * @bssid: peer to disconnect, NULL to disconnect all | 423 | * @bssid: peer to disconnect, NULL to disconnect all |
424 | * @reason_code: Reason code for the Disassociation frame | ||
395 | * @from_event: whether is invoked from FW event handler | 425 | * @from_event: whether is invoked from FW event handler |
396 | * | 426 | * |
397 | * Disconnect and release associated resources. If invoked not from the | 427 | * Disconnect and release associated resources. If invoked not from the |
398 | * FW event handler, issue WMI command(s) to trigger MAC disconnect. | 428 | * FW event handler, issue WMI command(s) to trigger MAC disconnect. |
399 | */ | 429 | */ |
400 | void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, | 430 | void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, |
401 | bool from_event) | 431 | u16 reason_code, bool from_event) |
402 | { | 432 | { |
403 | wil_dbg_misc(wil, "%s()\n", __func__); | 433 | wil_dbg_misc(wil, "%s()\n", __func__); |
404 | 434 | ||
405 | del_timer_sync(&wil->connect_timer); | 435 | del_timer_sync(&wil->connect_timer); |
406 | _wil6210_disconnect(wil, bssid, from_event); | 436 | _wil6210_disconnect(wil, bssid, reason_code, from_event); |
407 | } | 437 | } |
408 | 438 | ||
409 | void wil_priv_deinit(struct wil6210_priv *wil) | 439 | void wil_priv_deinit(struct wil6210_priv *wil) |
@@ -415,7 +445,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) | |||
415 | cancel_work_sync(&wil->disconnect_worker); | 445 | cancel_work_sync(&wil->disconnect_worker); |
416 | cancel_work_sync(&wil->fw_error_worker); | 446 | cancel_work_sync(&wil->fw_error_worker); |
417 | mutex_lock(&wil->mutex); | 447 | mutex_lock(&wil->mutex); |
418 | wil6210_disconnect(wil, NULL, false); | 448 | wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); |
419 | mutex_unlock(&wil->mutex); | 449 | mutex_unlock(&wil->mutex); |
420 | wmi_event_flush(wil); | 450 | wmi_event_flush(wil); |
421 | destroy_workqueue(wil->wmi_wq_conn); | 451 | destroy_workqueue(wil->wmi_wq_conn); |
@@ -463,6 +493,9 @@ static int wil_target_reset(struct wil6210_priv *wil) | |||
463 | 493 | ||
464 | wil_halt_cpu(wil); | 494 | wil_halt_cpu(wil); |
465 | 495 | ||
496 | /* Clear Fw Download notification */ | ||
497 | C(RGF_USER_USAGE_6, BIT(0)); | ||
498 | |||
466 | if (is_sparrow) { | 499 | if (is_sparrow) { |
467 | S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); | 500 | S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); |
468 | /* XTAL stabilization should take about 3ms */ | 501 | /* XTAL stabilization should take about 3ms */ |
@@ -600,7 +633,7 @@ int wil_reset(struct wil6210_priv *wil) | |||
600 | WARN_ON(test_bit(wil_status_napi_en, &wil->status)); | 633 | WARN_ON(test_bit(wil_status_napi_en, &wil->status)); |
601 | 634 | ||
602 | cancel_work_sync(&wil->disconnect_worker); | 635 | cancel_work_sync(&wil->disconnect_worker); |
603 | wil6210_disconnect(wil, NULL, false); | 636 | wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); |
604 | 637 | ||
605 | wil->status = 0; /* prevent NAPI from being scheduled */ | 638 | wil->status = 0; /* prevent NAPI from being scheduled */ |
606 | 639 | ||
@@ -705,7 +738,7 @@ int __wil_up(struct wil6210_priv *wil) | |||
705 | return rc; | 738 | return rc; |
706 | 739 | ||
707 | /* Rx VRING. After MAC and beacon */ | 740 | /* Rx VRING. After MAC and beacon */ |
708 | rc = wil_rx_init(wil); | 741 | rc = wil_rx_init(wil, 1 << rx_ring_order); |
709 | if (rc) | 742 | if (rc) |
710 | return rc; | 743 | return rc; |
711 | 744 | ||
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index c680906bc0dc..e3f8bdce5abc 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c | |||
@@ -210,8 +210,6 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, | |||
210 | struct vring_rx_desc dd, *d = ⅆ | 210 | struct vring_rx_desc dd, *d = ⅆ |
211 | volatile struct vring_rx_desc *_d = &vring->va[i].rx; | 211 | volatile struct vring_rx_desc *_d = &vring->va[i].rx; |
212 | dma_addr_t pa; | 212 | dma_addr_t pa; |
213 | |||
214 | /* TODO align */ | ||
215 | struct sk_buff *skb = dev_alloc_skb(sz + headroom); | 213 | struct sk_buff *skb = dev_alloc_skb(sz + headroom); |
216 | 214 | ||
217 | if (unlikely(!skb)) | 215 | if (unlikely(!skb)) |
@@ -596,7 +594,7 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) | |||
596 | wil_rx_refill(wil, v->size); | 594 | wil_rx_refill(wil, v->size); |
597 | } | 595 | } |
598 | 596 | ||
599 | int wil_rx_init(struct wil6210_priv *wil) | 597 | int wil_rx_init(struct wil6210_priv *wil, u16 size) |
600 | { | 598 | { |
601 | struct vring *vring = &wil->vring_rx; | 599 | struct vring *vring = &wil->vring_rx; |
602 | int rc; | 600 | int rc; |
@@ -608,7 +606,7 @@ int wil_rx_init(struct wil6210_priv *wil) | |||
608 | return -EINVAL; | 606 | return -EINVAL; |
609 | } | 607 | } |
610 | 608 | ||
611 | vring->size = WIL6210_RX_RING_SIZE; | 609 | vring->size = size; |
612 | rc = wil_vring_alloc(wil, vring); | 610 | rc = wil_vring_alloc(wil, vring); |
613 | if (rc) | 611 | if (rc) |
614 | return rc; | 612 | return rc; |
@@ -928,8 +926,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
928 | wil_dbg_txrx(wil, "%s()\n", __func__); | 926 | wil_dbg_txrx(wil, "%s()\n", __func__); |
929 | 927 | ||
930 | if (avail < 1 + nr_frags) { | 928 | if (avail < 1 + nr_frags) { |
931 | wil_err(wil, "Tx ring full. No space for %d fragments\n", | 929 | wil_err_ratelimited(wil, |
932 | 1 + nr_frags); | 930 | "Tx ring full. No space for %d fragments\n", |
931 | 1 + nr_frags); | ||
933 | return -ENOMEM; | 932 | return -ENOMEM; |
934 | } | 933 | } |
935 | _d = &vring->va[i].tx; | 934 | _d = &vring->va[i].tx; |
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 95d3a062d35c..c6ec5b99ac7d 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h | |||
@@ -49,8 +49,11 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) | |||
49 | 49 | ||
50 | #define WIL6210_MEM_SIZE (2*1024*1024UL) | 50 | #define WIL6210_MEM_SIZE (2*1024*1024UL) |
51 | 51 | ||
52 | #define WIL6210_RX_RING_SIZE (128) | 52 | #define WIL_RX_RING_SIZE_ORDER_DEFAULT (9) |
53 | #define WIL6210_TX_RING_SIZE (512) | 53 | #define WIL_TX_RING_SIZE_ORDER_DEFAULT (9) |
54 | /* limit ring size in range [32..32k] */ | ||
55 | #define WIL_RING_SIZE_ORDER_MIN (5) | ||
56 | #define WIL_RING_SIZE_ORDER_MAX (15) | ||
54 | #define WIL6210_MAX_TX_RINGS (24) /* HW limit */ | 57 | #define WIL6210_MAX_TX_RINGS (24) /* HW limit */ |
55 | #define WIL6210_MAX_CID (8) /* HW limit */ | 58 | #define WIL6210_MAX_CID (8) /* HW limit */ |
56 | #define WIL6210_NAPI_BUDGET (16) /* arbitrary */ | 59 | #define WIL6210_NAPI_BUDGET (16) /* arbitrary */ |
@@ -126,6 +129,7 @@ struct RGF_ICR { | |||
126 | #define BIT_DMA_EP_TX_ICR_TX_DONE_N(n) BIT(n+1) /* n = [0..23] */ | 129 | #define BIT_DMA_EP_TX_ICR_TX_DONE_N(n) BIT(n+1) /* n = [0..23] */ |
127 | #define RGF_DMA_EP_RX_ICR (0x881bd0) /* struct RGF_ICR */ | 130 | #define RGF_DMA_EP_RX_ICR (0x881bd0) /* struct RGF_ICR */ |
128 | #define BIT_DMA_EP_RX_ICR_RX_DONE BIT(0) | 131 | #define BIT_DMA_EP_RX_ICR_RX_DONE BIT(0) |
132 | #define BIT_DMA_EP_RX_ICR_RX_HTRSH BIT(1) | ||
129 | #define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */ | 133 | #define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */ |
130 | #define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0) | 134 | #define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0) |
131 | #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) | 135 | #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) |
@@ -468,13 +472,14 @@ struct wil6210_priv { | |||
468 | #define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w)) | 472 | #define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w)) |
469 | #define wil_to_ndev(i) (wil_to_wdev(i)->netdev) | 473 | #define wil_to_ndev(i) (wil_to_wdev(i)->netdev) |
470 | #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) | 474 | #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) |
471 | #define wil_to_pcie_dev(i) (&i->pdev->dev) | ||
472 | 475 | ||
473 | __printf(2, 3) | 476 | __printf(2, 3) |
474 | void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...); | 477 | void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...); |
475 | __printf(2, 3) | 478 | __printf(2, 3) |
476 | void wil_err(struct wil6210_priv *wil, const char *fmt, ...); | 479 | void wil_err(struct wil6210_priv *wil, const char *fmt, ...); |
477 | __printf(2, 3) | 480 | __printf(2, 3) |
481 | void wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...); | ||
482 | __printf(2, 3) | ||
478 | void wil_info(struct wil6210_priv *wil, const char *fmt, ...); | 483 | void wil_info(struct wil6210_priv *wil, const char *fmt, ...); |
479 | #define wil_dbg(wil, fmt, arg...) do { \ | 484 | #define wil_dbg(wil, fmt, arg...) do { \ |
480 | netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \ | 485 | netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \ |
@@ -586,9 +591,9 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr); | |||
586 | int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); | 591 | int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); |
587 | int wmi_pcp_stop(struct wil6210_priv *wil); | 592 | int wmi_pcp_stop(struct wil6210_priv *wil); |
588 | void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, | 593 | void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, |
589 | bool from_event); | 594 | u16 reason_code, bool from_event); |
590 | 595 | ||
591 | int wil_rx_init(struct wil6210_priv *wil); | 596 | int wil_rx_init(struct wil6210_priv *wil, u16 size); |
592 | void wil_rx_fini(struct wil6210_priv *wil); | 597 | void wil_rx_fini(struct wil6210_priv *wil); |
593 | 598 | ||
594 | /* TX API */ | 599 | /* TX API */ |
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index bb1e066f756a..63476c86cd0e 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
@@ -478,15 +478,15 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, | |||
478 | void *d, int len) | 478 | void *d, int len) |
479 | { | 479 | { |
480 | struct wmi_disconnect_event *evt = d; | 480 | struct wmi_disconnect_event *evt = d; |
481 | u16 reason_code = le16_to_cpu(evt->protocol_reason_status); | ||
481 | 482 | ||
482 | wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n", | 483 | wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n", |
483 | evt->bssid, | 484 | evt->bssid, reason_code, evt->disconnect_reason); |
484 | evt->protocol_reason_status, evt->disconnect_reason); | ||
485 | 485 | ||
486 | wil->sinfo_gen++; | 486 | wil->sinfo_gen++; |
487 | 487 | ||
488 | mutex_lock(&wil->mutex); | 488 | mutex_lock(&wil->mutex); |
489 | wil6210_disconnect(wil, evt->bssid, true); | 489 | wil6210_disconnect(wil, evt->bssid, reason_code, true); |
490 | mutex_unlock(&wil->mutex); | 490 | mutex_unlock(&wil->mutex); |
491 | } | 491 | } |
492 | 492 | ||
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 5d4173ee55bc..47731cb0d815 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -5110,7 +5110,9 @@ static void b43_op_sta_notify(struct ieee80211_hw *hw, | |||
5110 | B43_WARN_ON(!vif || wl->vif != vif); | 5110 | B43_WARN_ON(!vif || wl->vif != vif); |
5111 | } | 5111 | } |
5112 | 5112 | ||
5113 | static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw) | 5113 | static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw, |
5114 | struct ieee80211_vif *vif, | ||
5115 | const u8 *mac_addr) | ||
5114 | { | 5116 | { |
5115 | struct b43_wl *wl = hw_to_b43_wl(hw); | 5117 | struct b43_wl *wl = hw_to_b43_wl(hw); |
5116 | struct b43_wldev *dev; | 5118 | struct b43_wldev *dev; |
@@ -5124,7 +5126,8 @@ static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw) | |||
5124 | mutex_unlock(&wl->mutex); | 5126 | mutex_unlock(&wl->mutex); |
5125 | } | 5127 | } |
5126 | 5128 | ||
5127 | static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw) | 5129 | static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw, |
5130 | struct ieee80211_vif *vif) | ||
5128 | { | 5131 | { |
5129 | struct b43_wl *wl = hw_to_b43_wl(hw); | 5132 | struct b43_wl *wl = hw_to_b43_wl(hw); |
5130 | struct b43_wldev *dev; | 5133 | struct b43_wldev *dev; |
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 1dfc682a8055..ee27b06074e1 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c | |||
@@ -300,9 +300,7 @@ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) | |||
300 | 300 | ||
301 | void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg) | 301 | void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg) |
302 | { | 302 | { |
303 | assert_mac_suspended(dev); | 303 | b43_phy_write(dev, destreg, b43_phy_read(dev, srcreg)); |
304 | dev->phy.ops->phy_write(dev, destreg, | ||
305 | dev->phy.ops->phy_read(dev, srcreg)); | ||
306 | } | 304 | } |
307 | 305 | ||
308 | void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) | 306 | void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 8822f2b8d74d..3aecc5f48719 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | |||
@@ -299,6 +299,7 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf, | |||
299 | primary_offset = ch->center_freq1 - ch->chan->center_freq; | 299 | primary_offset = ch->center_freq1 - ch->chan->center_freq; |
300 | switch (ch->width) { | 300 | switch (ch->width) { |
301 | case NL80211_CHAN_WIDTH_20: | 301 | case NL80211_CHAN_WIDTH_20: |
302 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
302 | ch_inf.bw = BRCMU_CHAN_BW_20; | 303 | ch_inf.bw = BRCMU_CHAN_BW_20; |
303 | WARN_ON(primary_offset != 0); | 304 | WARN_ON(primary_offset != 0); |
304 | break; | 305 | break; |
@@ -323,6 +324,10 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf, | |||
323 | ch_inf.sb = BRCMU_CHAN_SB_LU; | 324 | ch_inf.sb = BRCMU_CHAN_SB_LU; |
324 | } | 325 | } |
325 | break; | 326 | break; |
327 | case NL80211_CHAN_WIDTH_80P80: | ||
328 | case NL80211_CHAN_WIDTH_160: | ||
329 | case NL80211_CHAN_WIDTH_5: | ||
330 | case NL80211_CHAN_WIDTH_10: | ||
326 | default: | 331 | default: |
327 | WARN_ON_ONCE(1); | 332 | WARN_ON_ONCE(1); |
328 | } | 333 | } |
@@ -333,6 +338,7 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf, | |||
333 | case IEEE80211_BAND_5GHZ: | 338 | case IEEE80211_BAND_5GHZ: |
334 | ch_inf.band = BRCMU_CHAN_BAND_5G; | 339 | ch_inf.band = BRCMU_CHAN_BAND_5G; |
335 | break; | 340 | break; |
341 | case IEEE80211_BAND_60GHZ: | ||
336 | default: | 342 | default: |
337 | WARN_ON_ONCE(1); | 343 | WARN_ON_ONCE(1); |
338 | } | 344 | } |
@@ -514,6 +520,95 @@ brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev) | |||
514 | ADDR_INDIRECT); | 520 | ADDR_INDIRECT); |
515 | } | 521 | } |
516 | 522 | ||
523 | static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp) | ||
524 | { | ||
525 | struct brcmf_mbss_ssid_le mbss_ssid_le; | ||
526 | int bsscfgidx; | ||
527 | int err; | ||
528 | |||
529 | memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le)); | ||
530 | bsscfgidx = brcmf_get_next_free_bsscfgidx(ifp->drvr); | ||
531 | if (bsscfgidx < 0) | ||
532 | return bsscfgidx; | ||
533 | |||
534 | mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx); | ||
535 | mbss_ssid_le.SSID_len = cpu_to_le32(5); | ||
536 | sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx); | ||
537 | |||
538 | err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le, | ||
539 | sizeof(mbss_ssid_le)); | ||
540 | if (err < 0) | ||
541 | brcmf_err("setting ssid failed %d\n", err); | ||
542 | |||
543 | return err; | ||
544 | } | ||
545 | |||
546 | /** | ||
547 | * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS | ||
548 | * | ||
549 | * @wiphy: wiphy device of new interface. | ||
550 | * @name: name of the new interface. | ||
551 | * @flags: not used. | ||
552 | * @params: contains mac address for AP device. | ||
553 | */ | ||
554 | static | ||
555 | struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name, | ||
556 | u32 *flags, struct vif_params *params) | ||
557 | { | ||
558 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
559 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); | ||
560 | struct brcmf_cfg80211_vif *vif; | ||
561 | int err; | ||
562 | |||
563 | if (brcmf_cfg80211_vif_event_armed(cfg)) | ||
564 | return ERR_PTR(-EBUSY); | ||
565 | |||
566 | brcmf_dbg(INFO, "Adding vif \"%s\"\n", name); | ||
567 | |||
568 | vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP, false); | ||
569 | if (IS_ERR(vif)) | ||
570 | return (struct wireless_dev *)vif; | ||
571 | |||
572 | brcmf_cfg80211_arm_vif_event(cfg, vif); | ||
573 | |||
574 | err = brcmf_cfg80211_request_ap_if(ifp); | ||
575 | if (err) { | ||
576 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
577 | goto fail; | ||
578 | } | ||
579 | |||
580 | /* wait for firmware event */ | ||
581 | err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD, | ||
582 | msecs_to_jiffies(1500)); | ||
583 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
584 | if (!err) { | ||
585 | brcmf_err("timeout occurred\n"); | ||
586 | err = -EIO; | ||
587 | goto fail; | ||
588 | } | ||
589 | |||
590 | /* interface created in firmware */ | ||
591 | ifp = vif->ifp; | ||
592 | if (!ifp) { | ||
593 | brcmf_err("no if pointer provided\n"); | ||
594 | err = -ENOENT; | ||
595 | goto fail; | ||
596 | } | ||
597 | |||
598 | strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); | ||
599 | err = brcmf_net_attach(ifp, true); | ||
600 | if (err) { | ||
601 | brcmf_err("Registering netdevice failed\n"); | ||
602 | goto fail; | ||
603 | } | ||
604 | |||
605 | return &ifp->vif->wdev; | ||
606 | |||
607 | fail: | ||
608 | brcmf_free_vif(vif); | ||
609 | return ERR_PTR(err); | ||
610 | } | ||
611 | |||
517 | static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif) | 612 | static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif) |
518 | { | 613 | { |
519 | enum nl80211_iftype iftype; | 614 | enum nl80211_iftype iftype; |
@@ -539,12 +634,16 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, | |||
539 | switch (type) { | 634 | switch (type) { |
540 | case NL80211_IFTYPE_ADHOC: | 635 | case NL80211_IFTYPE_ADHOC: |
541 | case NL80211_IFTYPE_STATION: | 636 | case NL80211_IFTYPE_STATION: |
542 | case NL80211_IFTYPE_AP: | ||
543 | case NL80211_IFTYPE_AP_VLAN: | 637 | case NL80211_IFTYPE_AP_VLAN: |
544 | case NL80211_IFTYPE_WDS: | 638 | case NL80211_IFTYPE_WDS: |
545 | case NL80211_IFTYPE_MONITOR: | 639 | case NL80211_IFTYPE_MONITOR: |
546 | case NL80211_IFTYPE_MESH_POINT: | 640 | case NL80211_IFTYPE_MESH_POINT: |
547 | return ERR_PTR(-EOPNOTSUPP); | 641 | return ERR_PTR(-EOPNOTSUPP); |
642 | case NL80211_IFTYPE_AP: | ||
643 | wdev = brcmf_ap_add_vif(wiphy, name, flags, params); | ||
644 | if (!IS_ERR(wdev)) | ||
645 | brcmf_cfg80211_update_proto_addr_mode(wdev); | ||
646 | return wdev; | ||
548 | case NL80211_IFTYPE_P2P_CLIENT: | 647 | case NL80211_IFTYPE_P2P_CLIENT: |
549 | case NL80211_IFTYPE_P2P_GO: | 648 | case NL80211_IFTYPE_P2P_GO: |
550 | case NL80211_IFTYPE_P2P_DEVICE: | 649 | case NL80211_IFTYPE_P2P_DEVICE: |
@@ -1809,6 +1908,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, | |||
1809 | return -EIO; | 1908 | return -EIO; |
1810 | 1909 | ||
1811 | clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); | 1910 | clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); |
1911 | clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); | ||
1812 | cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL); | 1912 | cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL); |
1813 | 1913 | ||
1814 | memcpy(&scbval.ea, &profile->bssid, ETH_ALEN); | 1914 | memcpy(&scbval.ea, &profile->bssid, ETH_ALEN); |
@@ -2926,7 +3026,7 @@ brcmf_update_pmklist(struct net_device *ndev, | |||
2926 | struct brcmf_cfg80211_pmk_list *pmk_list, s32 err) | 3026 | struct brcmf_cfg80211_pmk_list *pmk_list, s32 err) |
2927 | { | 3027 | { |
2928 | int i, j; | 3028 | int i, j; |
2929 | int pmkid_len; | 3029 | u32 pmkid_len; |
2930 | 3030 | ||
2931 | pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid); | 3031 | pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid); |
2932 | 3032 | ||
@@ -2954,8 +3054,7 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, | |||
2954 | struct brcmf_if *ifp = netdev_priv(ndev); | 3054 | struct brcmf_if *ifp = netdev_priv(ndev); |
2955 | struct pmkid_list *pmkids = &cfg->pmk_list->pmkids; | 3055 | struct pmkid_list *pmkids = &cfg->pmk_list->pmkids; |
2956 | s32 err = 0; | 3056 | s32 err = 0; |
2957 | int i; | 3057 | u32 pmkid_len, i; |
2958 | int pmkid_len; | ||
2959 | 3058 | ||
2960 | brcmf_dbg(TRACE, "Enter\n"); | 3059 | brcmf_dbg(TRACE, "Enter\n"); |
2961 | if (!check_vif_up(ifp->vif)) | 3060 | if (!check_vif_up(ifp->vif)) |
@@ -2994,7 +3093,7 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, | |||
2994 | struct brcmf_if *ifp = netdev_priv(ndev); | 3093 | struct brcmf_if *ifp = netdev_priv(ndev); |
2995 | struct pmkid_list pmkid; | 3094 | struct pmkid_list pmkid; |
2996 | s32 err = 0; | 3095 | s32 err = 0; |
2997 | int i, pmkid_len; | 3096 | u32 pmkid_len, i; |
2998 | 3097 | ||
2999 | brcmf_dbg(TRACE, "Enter\n"); | 3098 | brcmf_dbg(TRACE, "Enter\n"); |
3000 | if (!check_vif_up(ifp->vif)) | 3099 | if (!check_vif_up(ifp->vif)) |
@@ -3355,11 +3454,10 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie) | |||
3355 | } | 3454 | } |
3356 | 3455 | ||
3357 | static s32 | 3456 | static s32 |
3358 | brcmf_configure_wpaie(struct net_device *ndev, | 3457 | brcmf_configure_wpaie(struct brcmf_if *ifp, |
3359 | const struct brcmf_vs_tlv *wpa_ie, | 3458 | const struct brcmf_vs_tlv *wpa_ie, |
3360 | bool is_rsn_ie) | 3459 | bool is_rsn_ie) |
3361 | { | 3460 | { |
3362 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
3363 | u32 auth = 0; /* d11 open authentication */ | 3461 | u32 auth = 0; /* d11 open authentication */ |
3364 | u16 count; | 3462 | u16 count; |
3365 | s32 err = 0; | 3463 | s32 err = 0; |
@@ -3834,6 +3932,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3834 | enum nl80211_iftype dev_role; | 3932 | enum nl80211_iftype dev_role; |
3835 | struct brcmf_fil_bss_enable_le bss_enable; | 3933 | struct brcmf_fil_bss_enable_le bss_enable; |
3836 | u16 chanspec; | 3934 | u16 chanspec; |
3935 | bool mbss; | ||
3837 | 3936 | ||
3838 | brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n", | 3937 | brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n", |
3839 | settings->chandef.chan->hw_value, | 3938 | settings->chandef.chan->hw_value, |
@@ -3844,6 +3943,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3844 | settings->inactivity_timeout); | 3943 | settings->inactivity_timeout); |
3845 | 3944 | ||
3846 | dev_role = ifp->vif->wdev.iftype; | 3945 | dev_role = ifp->vif->wdev.iftype; |
3946 | mbss = ifp->vif->mbss; | ||
3847 | 3947 | ||
3848 | memset(&ssid_le, 0, sizeof(ssid_le)); | 3948 | memset(&ssid_le, 0, sizeof(ssid_le)); |
3849 | if (settings->ssid == NULL || settings->ssid_len == 0) { | 3949 | if (settings->ssid == NULL || settings->ssid_len == 0) { |
@@ -3863,8 +3963,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3863 | ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len); | 3963 | ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len); |
3864 | } | 3964 | } |
3865 | 3965 | ||
3866 | brcmf_set_mpc(ifp, 0); | 3966 | if (!mbss) { |
3867 | brcmf_configure_arp_offload(ifp, false); | 3967 | brcmf_set_mpc(ifp, 0); |
3968 | brcmf_configure_arp_offload(ifp, false); | ||
3969 | } | ||
3868 | 3970 | ||
3869 | /* find the RSN_IE */ | 3971 | /* find the RSN_IE */ |
3870 | rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, | 3972 | rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, |
@@ -3878,13 +3980,16 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3878 | brcmf_dbg(TRACE, "WPA(2) IE is found\n"); | 3980 | brcmf_dbg(TRACE, "WPA(2) IE is found\n"); |
3879 | if (wpa_ie != NULL) { | 3981 | if (wpa_ie != NULL) { |
3880 | /* WPA IE */ | 3982 | /* WPA IE */ |
3881 | err = brcmf_configure_wpaie(ndev, wpa_ie, false); | 3983 | err = brcmf_configure_wpaie(ifp, wpa_ie, false); |
3882 | if (err < 0) | 3984 | if (err < 0) |
3883 | goto exit; | 3985 | goto exit; |
3884 | } else { | 3986 | } else { |
3987 | struct brcmf_vs_tlv *tmp_ie; | ||
3988 | |||
3989 | tmp_ie = (struct brcmf_vs_tlv *)rsn_ie; | ||
3990 | |||
3885 | /* RSN IE */ | 3991 | /* RSN IE */ |
3886 | err = brcmf_configure_wpaie(ndev, | 3992 | err = brcmf_configure_wpaie(ifp, tmp_ie, true); |
3887 | (struct brcmf_vs_tlv *)rsn_ie, true); | ||
3888 | if (err < 0) | 3993 | if (err < 0) |
3889 | goto exit; | 3994 | goto exit; |
3890 | } | 3995 | } |
@@ -3895,45 +4000,53 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3895 | 4000 | ||
3896 | brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); | 4001 | brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); |
3897 | 4002 | ||
3898 | chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef); | 4003 | if (!mbss) { |
3899 | err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); | 4004 | chanspec = chandef_to_chanspec(&cfg->d11inf, |
3900 | if (err < 0) { | 4005 | &settings->chandef); |
3901 | brcmf_err("Set Channel failed: chspec=%d, %d\n", chanspec, err); | 4006 | err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); |
3902 | goto exit; | ||
3903 | } | ||
3904 | |||
3905 | if (settings->beacon_interval) { | ||
3906 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, | ||
3907 | settings->beacon_interval); | ||
3908 | if (err < 0) { | 4007 | if (err < 0) { |
3909 | brcmf_err("Beacon Interval Set Error, %d\n", err); | 4008 | brcmf_err("Set Channel failed: chspec=%d, %d\n", |
4009 | chanspec, err); | ||
3910 | goto exit; | 4010 | goto exit; |
3911 | } | 4011 | } |
3912 | } | 4012 | |
3913 | if (settings->dtim_period) { | 4013 | if (settings->beacon_interval) { |
3914 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD, | 4014 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, |
3915 | settings->dtim_period); | 4015 | settings->beacon_interval); |
3916 | if (err < 0) { | 4016 | if (err < 0) { |
3917 | brcmf_err("DTIM Interval Set Error, %d\n", err); | 4017 | brcmf_err("Beacon Interval Set Error, %d\n", |
3918 | goto exit; | 4018 | err); |
4019 | goto exit; | ||
4020 | } | ||
4021 | } | ||
4022 | if (settings->dtim_period) { | ||
4023 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD, | ||
4024 | settings->dtim_period); | ||
4025 | if (err < 0) { | ||
4026 | brcmf_err("DTIM Interval Set Error, %d\n", err); | ||
4027 | goto exit; | ||
4028 | } | ||
3919 | } | 4029 | } |
3920 | } | ||
3921 | 4030 | ||
3922 | if (dev_role == NL80211_IFTYPE_AP) { | 4031 | if (dev_role == NL80211_IFTYPE_AP) { |
3923 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); | 4032 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); |
4033 | if (err < 0) { | ||
4034 | brcmf_err("BRCMF_C_DOWN error %d\n", err); | ||
4035 | goto exit; | ||
4036 | } | ||
4037 | brcmf_fil_iovar_int_set(ifp, "apsta", 0); | ||
4038 | } | ||
4039 | |||
4040 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); | ||
3924 | if (err < 0) { | 4041 | if (err < 0) { |
3925 | brcmf_err("BRCMF_C_DOWN error %d\n", err); | 4042 | brcmf_err("SET INFRA error %d\n", err); |
3926 | goto exit; | 4043 | goto exit; |
3927 | } | 4044 | } |
3928 | brcmf_fil_iovar_int_set(ifp, "apsta", 0); | ||
3929 | } | ||
3930 | |||
3931 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); | ||
3932 | if (err < 0) { | ||
3933 | brcmf_err("SET INFRA error %d\n", err); | ||
3934 | goto exit; | ||
3935 | } | 4045 | } |
3936 | if (dev_role == NL80211_IFTYPE_AP) { | 4046 | if (dev_role == NL80211_IFTYPE_AP) { |
4047 | if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss)) | ||
4048 | brcmf_fil_iovar_int_set(ifp, "mbss", 1); | ||
4049 | |||
3937 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); | 4050 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); |
3938 | if (err < 0) { | 4051 | if (err < 0) { |
3939 | brcmf_err("setting AP mode failed %d\n", err); | 4052 | brcmf_err("setting AP mode failed %d\n", err); |
@@ -3978,7 +4091,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3978 | set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); | 4091 | set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); |
3979 | 4092 | ||
3980 | exit: | 4093 | exit: |
3981 | if (err) { | 4094 | if ((err) && (!mbss)) { |
3982 | brcmf_set_mpc(ifp, 1); | 4095 | brcmf_set_mpc(ifp, 1); |
3983 | brcmf_configure_arp_offload(ifp, true); | 4096 | brcmf_configure_arp_offload(ifp, true); |
3984 | } | 4097 | } |
@@ -3999,20 +4112,31 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) | |||
3999 | /* first to make sure they get processed by fw. */ | 4112 | /* first to make sure they get processed by fw. */ |
4000 | msleep(400); | 4113 | msleep(400); |
4001 | 4114 | ||
4115 | if (ifp->vif->mbss) { | ||
4116 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); | ||
4117 | return err; | ||
4118 | } | ||
4119 | |||
4002 | memset(&join_params, 0, sizeof(join_params)); | 4120 | memset(&join_params, 0, sizeof(join_params)); |
4003 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, | 4121 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, |
4004 | &join_params, sizeof(join_params)); | 4122 | &join_params, sizeof(join_params)); |
4005 | if (err < 0) | 4123 | if (err < 0) |
4006 | brcmf_err("SET SSID error (%d)\n", err); | 4124 | brcmf_err("SET SSID error (%d)\n", err); |
4007 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); | 4125 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); |
4008 | if (err < 0) | 4126 | if (err < 0) |
4009 | brcmf_err("BRCMF_C_UP error %d\n", err); | 4127 | brcmf_err("BRCMF_C_DOWN error %d\n", err); |
4010 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); | 4128 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); |
4011 | if (err < 0) | 4129 | if (err < 0) |
4012 | brcmf_err("setting AP mode failed %d\n", err); | 4130 | brcmf_err("setting AP mode failed %d\n", err); |
4013 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0); | 4131 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0); |
4014 | if (err < 0) | 4132 | if (err < 0) |
4015 | brcmf_err("setting INFRA mode failed %d\n", err); | 4133 | brcmf_err("setting INFRA mode failed %d\n", err); |
4134 | if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) | ||
4135 | brcmf_fil_iovar_int_set(ifp, "mbss", 0); | ||
4136 | /* Bring device back up so it can be used again */ | ||
4137 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); | ||
4138 | if (err < 0) | ||
4139 | brcmf_err("BRCMF_C_UP error %d\n", err); | ||
4016 | } else { | 4140 | } else { |
4017 | bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); | 4141 | bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); |
4018 | bss_enable.enable = cpu_to_le32(0); | 4142 | bss_enable.enable = cpu_to_le32(0); |
@@ -4045,24 +4169,24 @@ brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, | |||
4045 | 4169 | ||
4046 | static int | 4170 | static int |
4047 | brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, | 4171 | brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, |
4048 | const u8 *mac) | 4172 | struct station_del_parameters *params) |
4049 | { | 4173 | { |
4050 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | 4174 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); |
4051 | struct brcmf_scb_val_le scbval; | 4175 | struct brcmf_scb_val_le scbval; |
4052 | struct brcmf_if *ifp = netdev_priv(ndev); | 4176 | struct brcmf_if *ifp = netdev_priv(ndev); |
4053 | s32 err; | 4177 | s32 err; |
4054 | 4178 | ||
4055 | if (!mac) | 4179 | if (!params->mac) |
4056 | return -EFAULT; | 4180 | return -EFAULT; |
4057 | 4181 | ||
4058 | brcmf_dbg(TRACE, "Enter %pM\n", mac); | 4182 | brcmf_dbg(TRACE, "Enter %pM\n", params->mac); |
4059 | 4183 | ||
4060 | if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) | 4184 | if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) |
4061 | ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | 4185 | ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; |
4062 | if (!check_vif_up(ifp->vif)) | 4186 | if (!check_vif_up(ifp->vif)) |
4063 | return -EIO; | 4187 | return -EIO; |
4064 | 4188 | ||
4065 | memcpy(&scbval.ea, mac, ETH_ALEN); | 4189 | memcpy(&scbval.ea, params->mac, ETH_ALEN); |
4066 | scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING); | 4190 | scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING); |
4067 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, | 4191 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, |
4068 | &scbval, sizeof(scbval)); | 4192 | &scbval, sizeof(scbval)); |
@@ -4364,7 +4488,9 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | |||
4364 | enum nl80211_iftype type, | 4488 | enum nl80211_iftype type, |
4365 | bool pm_block) | 4489 | bool pm_block) |
4366 | { | 4490 | { |
4491 | struct brcmf_cfg80211_vif *vif_walk; | ||
4367 | struct brcmf_cfg80211_vif *vif; | 4492 | struct brcmf_cfg80211_vif *vif; |
4493 | bool mbss; | ||
4368 | 4494 | ||
4369 | brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n", | 4495 | brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n", |
4370 | sizeof(*vif)); | 4496 | sizeof(*vif)); |
@@ -4380,6 +4506,17 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | |||
4380 | 4506 | ||
4381 | brcmf_init_prof(&vif->profile); | 4507 | brcmf_init_prof(&vif->profile); |
4382 | 4508 | ||
4509 | if (type == NL80211_IFTYPE_AP) { | ||
4510 | mbss = false; | ||
4511 | list_for_each_entry(vif_walk, &cfg->vif_list, list) { | ||
4512 | if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) { | ||
4513 | mbss = true; | ||
4514 | break; | ||
4515 | } | ||
4516 | } | ||
4517 | vif->mbss = mbss; | ||
4518 | } | ||
4519 | |||
4383 | list_add_tail(&vif->list, &cfg->vif_list); | 4520 | list_add_tail(&vif->list, &cfg->vif_list); |
4384 | return vif; | 4521 | return vif; |
4385 | } | 4522 | } |
@@ -4622,6 +4759,7 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, | |||
4622 | struct net_device *ndev, | 4759 | struct net_device *ndev, |
4623 | const struct brcmf_event_msg *e, void *data) | 4760 | const struct brcmf_event_msg *e, void *data) |
4624 | { | 4761 | { |
4762 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
4625 | static int generation; | 4763 | static int generation; |
4626 | u32 event = e->event_code; | 4764 | u32 event = e->event_code; |
4627 | u32 reason = e->reason; | 4765 | u32 reason = e->reason; |
@@ -4632,6 +4770,8 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, | |||
4632 | ndev != cfg_to_ndev(cfg)) { | 4770 | ndev != cfg_to_ndev(cfg)) { |
4633 | brcmf_dbg(CONN, "AP mode link down\n"); | 4771 | brcmf_dbg(CONN, "AP mode link down\n"); |
4634 | complete(&cfg->vif_disabled); | 4772 | complete(&cfg->vif_disabled); |
4773 | if (ifp->vif->mbss) | ||
4774 | brcmf_remove_interface(ifp->drvr, ifp->bssidx); | ||
4635 | return 0; | 4775 | return 0; |
4636 | } | 4776 | } |
4637 | 4777 | ||
@@ -5423,7 +5563,28 @@ static int brcmf_setup_wiphybands(struct wiphy *wiphy) | |||
5423 | return 0; | 5563 | return 0; |
5424 | } | 5564 | } |
5425 | 5565 | ||
5426 | static const struct ieee80211_iface_limit brcmf_iface_limits[] = { | 5566 | static const struct ieee80211_iface_limit brcmf_iface_limits_mbss[] = { |
5567 | { | ||
5568 | .max = 1, | ||
5569 | .types = BIT(NL80211_IFTYPE_STATION) | | ||
5570 | BIT(NL80211_IFTYPE_ADHOC) | ||
5571 | }, | ||
5572 | { | ||
5573 | .max = 4, | ||
5574 | .types = BIT(NL80211_IFTYPE_AP) | ||
5575 | }, | ||
5576 | { | ||
5577 | .max = 1, | ||
5578 | .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
5579 | BIT(NL80211_IFTYPE_P2P_GO) | ||
5580 | }, | ||
5581 | { | ||
5582 | .max = 1, | ||
5583 | .types = BIT(NL80211_IFTYPE_P2P_DEVICE) | ||
5584 | } | ||
5585 | }; | ||
5586 | |||
5587 | static const struct ieee80211_iface_limit brcmf_iface_limits_sbss[] = { | ||
5427 | { | 5588 | { |
5428 | .max = 2, | 5589 | .max = 2, |
5429 | .types = BIT(NL80211_IFTYPE_STATION) | | 5590 | .types = BIT(NL80211_IFTYPE_STATION) | |
@@ -5444,8 +5605,8 @@ static struct ieee80211_iface_combination brcmf_iface_combos[] = { | |||
5444 | { | 5605 | { |
5445 | .max_interfaces = BRCMF_IFACE_MAX_CNT, | 5606 | .max_interfaces = BRCMF_IFACE_MAX_CNT, |
5446 | .num_different_channels = 1, | 5607 | .num_different_channels = 1, |
5447 | .n_limits = ARRAY_SIZE(brcmf_iface_limits), | 5608 | .n_limits = ARRAY_SIZE(brcmf_iface_limits_sbss), |
5448 | .limits = brcmf_iface_limits | 5609 | .limits = brcmf_iface_limits_sbss, |
5449 | } | 5610 | } |
5450 | }; | 5611 | }; |
5451 | 5612 | ||
@@ -5521,6 +5682,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) | |||
5521 | ifc_combo = brcmf_iface_combos[0]; | 5682 | ifc_combo = brcmf_iface_combos[0]; |
5522 | if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) | 5683 | if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) |
5523 | ifc_combo.num_different_channels = 2; | 5684 | ifc_combo.num_different_channels = 2; |
5685 | if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) { | ||
5686 | ifc_combo.n_limits = ARRAY_SIZE(brcmf_iface_limits_mbss), | ||
5687 | ifc_combo.limits = brcmf_iface_limits_mbss; | ||
5688 | } | ||
5524 | wiphy->iface_combinations = kmemdup(&ifc_combo, | 5689 | wiphy->iface_combinations = kmemdup(&ifc_combo, |
5525 | sizeof(ifc_combo), | 5690 | sizeof(ifc_combo), |
5526 | GFP_KERNEL); | 5691 | GFP_KERNEL); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h index 2a5b22cb3fef..9e98b8d52757 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h | |||
@@ -183,6 +183,7 @@ struct vif_saved_ie { | |||
183 | * @pm_block: power-management blocked. | 183 | * @pm_block: power-management blocked. |
184 | * @list: linked list. | 184 | * @list: linked list. |
185 | * @mgmt_rx_reg: registered rx mgmt frame types. | 185 | * @mgmt_rx_reg: registered rx mgmt frame types. |
186 | * @mbss: Multiple BSS type, set if not first AP (not relevant for P2P). | ||
186 | */ | 187 | */ |
187 | struct brcmf_cfg80211_vif { | 188 | struct brcmf_cfg80211_vif { |
188 | struct brcmf_if *ifp; | 189 | struct brcmf_if *ifp; |
@@ -194,6 +195,7 @@ struct brcmf_cfg80211_vif { | |||
194 | struct vif_saved_ie saved_ie; | 195 | struct vif_saved_ie saved_ie; |
195 | struct list_head list; | 196 | struct list_head list; |
196 | u16 mgmt_rx_reg; | 197 | u16 mgmt_rx_reg; |
198 | bool mbss; | ||
197 | }; | 199 | }; |
198 | 200 | ||
199 | /* association inform */ | 201 | /* association inform */ |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index f407665cb1ea..effe6d7831d9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c | |||
@@ -836,7 +836,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, | |||
836 | return ifp; | 836 | return ifp; |
837 | } | 837 | } |
838 | 838 | ||
839 | void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) | 839 | static void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) |
840 | { | 840 | { |
841 | struct brcmf_if *ifp; | 841 | struct brcmf_if *ifp; |
842 | 842 | ||
@@ -869,6 +869,38 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) | |||
869 | } | 869 | } |
870 | } | 870 | } |
871 | 871 | ||
872 | void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx) | ||
873 | { | ||
874 | if (drvr->iflist[bssidx]) { | ||
875 | brcmf_fws_del_interface(drvr->iflist[bssidx]); | ||
876 | brcmf_del_if(drvr, bssidx); | ||
877 | } | ||
878 | } | ||
879 | |||
880 | int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr) | ||
881 | { | ||
882 | int ifidx; | ||
883 | int bsscfgidx; | ||
884 | bool available; | ||
885 | int highest; | ||
886 | |||
887 | available = false; | ||
888 | bsscfgidx = 2; | ||
889 | highest = 2; | ||
890 | for (ifidx = 0; ifidx < BRCMF_MAX_IFS; ifidx++) { | ||
891 | if (drvr->iflist[ifidx]) { | ||
892 | if (drvr->iflist[ifidx]->bssidx == bsscfgidx) | ||
893 | bsscfgidx = highest + 1; | ||
894 | else if (drvr->iflist[ifidx]->bssidx > highest) | ||
895 | highest = drvr->iflist[ifidx]->bssidx; | ||
896 | } else { | ||
897 | available = true; | ||
898 | } | ||
899 | } | ||
900 | |||
901 | return available ? bsscfgidx : -ENOMEM; | ||
902 | } | ||
903 | |||
872 | int brcmf_attach(struct device *dev) | 904 | int brcmf_attach(struct device *dev) |
873 | { | 905 | { |
874 | struct brcmf_pub *drvr = NULL; | 906 | struct brcmf_pub *drvr = NULL; |
@@ -1033,10 +1065,7 @@ void brcmf_detach(struct device *dev) | |||
1033 | 1065 | ||
1034 | /* make sure primary interface removed last */ | 1066 | /* make sure primary interface removed last */ |
1035 | for (i = BRCMF_MAX_IFS-1; i > -1; i--) | 1067 | for (i = BRCMF_MAX_IFS-1; i > -1; i--) |
1036 | if (drvr->iflist[i]) { | 1068 | brcmf_remove_interface(drvr, i); |
1037 | brcmf_fws_del_interface(drvr->iflist[i]); | ||
1038 | brcmf_del_if(drvr, i); | ||
1039 | } | ||
1040 | 1069 | ||
1041 | brcmf_cfg80211_detach(drvr->config); | 1070 | brcmf_cfg80211_detach(drvr->config); |
1042 | 1071 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index 98228e922d3a..23f74b139cc8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h | |||
@@ -175,7 +175,8 @@ char *brcmf_ifname(struct brcmf_pub *drvr, int idx); | |||
175 | int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); | 175 | int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); |
176 | struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, | 176 | struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, |
177 | char *name, u8 *mac_addr); | 177 | char *name, u8 *mac_addr); |
178 | void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx); | 178 | void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx); |
179 | int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); | ||
179 | void brcmf_txflowblock_if(struct brcmf_if *ifp, | 180 | void brcmf_txflowblock_if(struct brcmf_if *ifp, |
180 | enum brcmf_netif_stop_reason reason, bool state); | 181 | enum brcmf_netif_stop_reason reason, bool state); |
181 | void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx, | 182 | void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx, |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/brcm80211/brcmfmac/feature.c index 931f68aefaa4..defb7a44e0bc 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c | |||
@@ -97,6 +97,28 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, | |||
97 | } | 97 | } |
98 | } | 98 | } |
99 | 99 | ||
100 | /** | ||
101 | * brcmf_feat_iovar_int_set() - determine feature through iovar set. | ||
102 | * | ||
103 | * @ifp: interface to query. | ||
104 | * @id: feature id. | ||
105 | * @name: iovar name. | ||
106 | */ | ||
107 | static void brcmf_feat_iovar_int_set(struct brcmf_if *ifp, | ||
108 | enum brcmf_feat_id id, char *name, u32 val) | ||
109 | { | ||
110 | int err; | ||
111 | |||
112 | err = brcmf_fil_iovar_int_set(ifp, name, val); | ||
113 | if (err == 0) { | ||
114 | brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); | ||
115 | ifp->drvr->feat_flags |= BIT(id); | ||
116 | } else { | ||
117 | brcmf_dbg(TRACE, "%s feature check failed: %d\n", | ||
118 | brcmf_feat_names[id], err); | ||
119 | } | ||
120 | } | ||
121 | |||
100 | void brcmf_feat_attach(struct brcmf_pub *drvr) | 122 | void brcmf_feat_attach(struct brcmf_pub *drvr) |
101 | { | 123 | { |
102 | struct brcmf_if *ifp = drvr->iflist[0]; | 124 | struct brcmf_if *ifp = drvr->iflist[0]; |
@@ -104,6 +126,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) | |||
104 | brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan"); | 126 | brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan"); |
105 | if (drvr->bus_if->wowl_supported) | 127 | if (drvr->bus_if->wowl_supported) |
106 | brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); | 128 | brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); |
129 | brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0); | ||
107 | 130 | ||
108 | /* set chip related quirks */ | 131 | /* set chip related quirks */ |
109 | switch (drvr->bus_if->chip) { | 132 | switch (drvr->bus_if->chip) { |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/brcm80211/brcmfmac/feature.h index b9a796d0a44d..f5832e077bb7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h | |||
@@ -22,6 +22,7 @@ | |||
22 | * MCHAN: multi-channel for concurrent P2P. | 22 | * MCHAN: multi-channel for concurrent P2P. |
23 | */ | 23 | */ |
24 | #define BRCMF_FEAT_LIST \ | 24 | #define BRCMF_FEAT_LIST \ |
25 | BRCMF_FEAT_DEF(MBSS) \ | ||
25 | BRCMF_FEAT_DEF(MCHAN) \ | 26 | BRCMF_FEAT_DEF(MCHAN) \ |
26 | BRCMF_FEAT_DEF(WOWL) | 27 | BRCMF_FEAT_DEF(WOWL) |
27 | /* | 28 | /* |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c index 0f157f151282..1ff787d1a36b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c | |||
@@ -262,8 +262,7 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) | |||
262 | 262 | ||
263 | fail: | 263 | fail: |
264 | brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); | 264 | brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); |
265 | if (fwctx->code) | 265 | release_firmware(fwctx->code); |
266 | release_firmware(fwctx->code); | ||
267 | device_release_driver(fwctx->dev); | 266 | device_release_driver(fwctx->dev); |
268 | kfree(fwctx); | 267 | kfree(fwctx); |
269 | } | 268 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c index 7338b335e153..ec62492ffa69 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c | |||
@@ -221,10 +221,8 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, | |||
221 | 221 | ||
222 | err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); | 222 | err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); |
223 | 223 | ||
224 | if (ifp && ifevent->action == BRCMF_E_IF_DEL) { | 224 | if (ifp && ifevent->action == BRCMF_E_IF_DEL) |
225 | brcmf_fws_del_interface(ifp); | 225 | brcmf_remove_interface(drvr, ifevent->bssidx); |
226 | brcmf_del_if(drvr, ifevent->bssidx); | ||
227 | } | ||
228 | } | 226 | } |
229 | 227 | ||
230 | /** | 228 | /** |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 51f88c11e642..03f2c406a17b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c | |||
@@ -136,7 +136,7 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) | |||
136 | 136 | ||
137 | mutex_lock(&ifp->drvr->proto_block); | 137 | mutex_lock(&ifp->drvr->proto_block); |
138 | 138 | ||
139 | brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len); | 139 | brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len); |
140 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, | 140 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
141 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); | 141 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
142 | 142 | ||
@@ -154,7 +154,7 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) | |||
154 | mutex_lock(&ifp->drvr->proto_block); | 154 | mutex_lock(&ifp->drvr->proto_block); |
155 | err = brcmf_fil_cmd_data(ifp, cmd, data, len, false); | 155 | err = brcmf_fil_cmd_data(ifp, cmd, data, len, false); |
156 | 156 | ||
157 | brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len); | 157 | brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len); |
158 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, | 158 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
159 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); | 159 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
160 | 160 | ||
@@ -171,7 +171,7 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) | |||
171 | __le32 data_le = cpu_to_le32(data); | 171 | __le32 data_le = cpu_to_le32(data); |
172 | 172 | ||
173 | mutex_lock(&ifp->drvr->proto_block); | 173 | mutex_lock(&ifp->drvr->proto_block); |
174 | brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data); | 174 | brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data); |
175 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); | 175 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); |
176 | mutex_unlock(&ifp->drvr->proto_block); | 176 | mutex_unlock(&ifp->drvr->proto_block); |
177 | 177 | ||
@@ -188,7 +188,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) | |||
188 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); | 188 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); |
189 | mutex_unlock(&ifp->drvr->proto_block); | 189 | mutex_unlock(&ifp->drvr->proto_block); |
190 | *data = le32_to_cpu(data_le); | 190 | *data = le32_to_cpu(data_le); |
191 | brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data); | 191 | brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data); |
192 | 192 | ||
193 | return err; | 193 | return err; |
194 | } | 194 | } |
@@ -224,7 +224,7 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data, | |||
224 | 224 | ||
225 | mutex_lock(&drvr->proto_block); | 225 | mutex_lock(&drvr->proto_block); |
226 | 226 | ||
227 | brcmf_dbg(FIL, "name=%s, len=%d\n", name, len); | 227 | brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len); |
228 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, | 228 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
229 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); | 229 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
230 | 230 | ||
@@ -264,7 +264,7 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, | |||
264 | brcmf_err("Creating iovar failed\n"); | 264 | brcmf_err("Creating iovar failed\n"); |
265 | } | 265 | } |
266 | 266 | ||
267 | brcmf_dbg(FIL, "name=%s, len=%d\n", name, len); | 267 | brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len); |
268 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, | 268 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
269 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); | 269 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
270 | 270 | ||
@@ -347,7 +347,8 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name, | |||
347 | 347 | ||
348 | mutex_lock(&drvr->proto_block); | 348 | mutex_lock(&drvr->proto_block); |
349 | 349 | ||
350 | brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len); | 350 | brcmf_dbg(FIL, "ifidx=%d, bssidx=%d, name=%s, len=%d\n", ifp->ifidx, |
351 | ifp->bssidx, name, len); | ||
351 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, | 352 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
352 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); | 353 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
353 | 354 | ||
@@ -386,7 +387,8 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, | |||
386 | err = -EPERM; | 387 | err = -EPERM; |
387 | brcmf_err("Creating bsscfg failed\n"); | 388 | brcmf_err("Creating bsscfg failed\n"); |
388 | } | 389 | } |
389 | brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len); | 390 | brcmf_dbg(FIL, "ifidx=%d, bssidx=%d, name=%s, len=%d\n", ifp->ifidx, |
391 | ifp->bssidx, name, len); | ||
390 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, | 392 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
391 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); | 393 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
392 | 394 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index ba64b292f7a5..50891c02c4c1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h | |||
@@ -519,4 +519,10 @@ struct brcmf_fil_wowl_pattern_le { | |||
519 | /* u8 pattern[] - Pattern follows the mask is at 'patternoffset' */ | 519 | /* u8 pattern[] - Pattern follows the mask is at 'patternoffset' */ |
520 | }; | 520 | }; |
521 | 521 | ||
522 | struct brcmf_mbss_ssid_le { | ||
523 | __le32 bsscfgidx; | ||
524 | __le32 SSID_len; | ||
525 | unsigned char SSID[32]; | ||
526 | }; | ||
527 | |||
522 | #endif /* FWIL_TYPES_H_ */ | 528 | #endif /* FWIL_TYPES_H_ */ |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index 02d39ce8dbca..456944a6a2db 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | |||
@@ -518,8 +518,7 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx, | |||
518 | memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ? | 518 | memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ? |
519 | len : msgbuf->ioctl_resp_ret_len); | 519 | len : msgbuf->ioctl_resp_ret_len); |
520 | } | 520 | } |
521 | if (skb) | 521 | brcmu_pkt_buf_free_skb(skb); |
522 | brcmu_pkt_buf_free_skb(skb); | ||
523 | 522 | ||
524 | return msgbuf->ioctl_resp_status; | 523 | return msgbuf->ioctl_resp_status; |
525 | } | 524 | } |
@@ -1081,8 +1080,17 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb, | |||
1081 | { | 1080 | { |
1082 | struct brcmf_if *ifp; | 1081 | struct brcmf_if *ifp; |
1083 | 1082 | ||
1083 | /* The ifidx is the idx to map to matching netdev/ifp. When receiving | ||
1084 | * events this is easy because it contains the bssidx which maps | ||
1085 | * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. | ||
1086 | * bssidx 1 is used for p2p0 and no data can be received or | ||
1087 | * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 | ||
1088 | */ | ||
1089 | if (ifidx) | ||
1090 | (ifidx)++; | ||
1084 | ifp = msgbuf->drvr->iflist[ifidx]; | 1091 | ifp = msgbuf->drvr->iflist[ifidx]; |
1085 | if (!ifp || !ifp->ndev) { | 1092 | if (!ifp || !ifp->ndev) { |
1093 | brcmf_err("Received pkt for invalid ifidx %d\n", ifidx); | ||
1086 | brcmu_pkt_buf_free_skb(skb); | 1094 | brcmu_pkt_buf_free_skb(skb); |
1087 | return; | 1095 | return; |
1088 | } | 1096 | } |
@@ -1355,6 +1363,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) | |||
1355 | } | 1363 | } |
1356 | INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker); | 1364 | INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker); |
1357 | count = BITS_TO_LONGS(if_msgbuf->nrof_flowrings); | 1365 | count = BITS_TO_LONGS(if_msgbuf->nrof_flowrings); |
1366 | count = count * sizeof(unsigned long); | ||
1358 | msgbuf->flow_map = kzalloc(count, GFP_KERNEL); | 1367 | msgbuf->flow_map = kzalloc(count, GFP_KERNEL); |
1359 | if (!msgbuf->flow_map) | 1368 | if (!msgbuf->flow_map) |
1360 | goto fail; | 1369 | goto fail; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index b0ae7993e2e8..a66481976d5c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c | |||
@@ -798,12 +798,14 @@ static int brcmf_pcie_request_irq(struct brcmf_pciedev_info *devinfo) | |||
798 | brcmf_dbg(PCIE, "Enter\n"); | 798 | brcmf_dbg(PCIE, "Enter\n"); |
799 | /* is it a v1 or v2 implementation */ | 799 | /* is it a v1 or v2 implementation */ |
800 | devinfo->irq_requested = false; | 800 | devinfo->irq_requested = false; |
801 | pci_enable_msi(pdev); | ||
801 | if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) { | 802 | if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) { |
802 | if (request_threaded_irq(pdev->irq, | 803 | if (request_threaded_irq(pdev->irq, |
803 | brcmf_pcie_quick_check_isr_v1, | 804 | brcmf_pcie_quick_check_isr_v1, |
804 | brcmf_pcie_isr_thread_v1, | 805 | brcmf_pcie_isr_thread_v1, |
805 | IRQF_SHARED, "brcmf_pcie_intr", | 806 | IRQF_SHARED, "brcmf_pcie_intr", |
806 | devinfo)) { | 807 | devinfo)) { |
808 | pci_disable_msi(pdev); | ||
807 | brcmf_err("Failed to request IRQ %d\n", pdev->irq); | 809 | brcmf_err("Failed to request IRQ %d\n", pdev->irq); |
808 | return -EIO; | 810 | return -EIO; |
809 | } | 811 | } |
@@ -813,6 +815,7 @@ static int brcmf_pcie_request_irq(struct brcmf_pciedev_info *devinfo) | |||
813 | brcmf_pcie_isr_thread_v2, | 815 | brcmf_pcie_isr_thread_v2, |
814 | IRQF_SHARED, "brcmf_pcie_intr", | 816 | IRQF_SHARED, "brcmf_pcie_intr", |
815 | devinfo)) { | 817 | devinfo)) { |
818 | pci_disable_msi(pdev); | ||
816 | brcmf_err("Failed to request IRQ %d\n", pdev->irq); | 819 | brcmf_err("Failed to request IRQ %d\n", pdev->irq); |
817 | return -EIO; | 820 | return -EIO; |
818 | } | 821 | } |
@@ -839,6 +842,7 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo) | |||
839 | return; | 842 | return; |
840 | devinfo->irq_requested = false; | 843 | devinfo->irq_requested = false; |
841 | free_irq(pdev->irq, devinfo); | 844 | free_irq(pdev->irq, devinfo); |
845 | pci_disable_msi(pdev); | ||
842 | 846 | ||
843 | msleep(50); | 847 | msleep(50); |
844 | count = 0; | 848 | count = 0; |
@@ -1857,6 +1861,8 @@ static struct pci_device_id brcmf_pcie_devid_table[] = { | |||
1857 | BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID), | 1861 | BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID), |
1858 | BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID), | 1862 | BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID), |
1859 | BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID), | 1863 | BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID), |
1864 | BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID), | ||
1865 | BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID), | ||
1860 | { /* end: all zeroes */ } | 1866 | { /* end: all zeroes */ } |
1861 | }; | 1867 | }; |
1862 | 1868 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 72e87b51f999..0b0d51a61060 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c | |||
@@ -670,7 +670,6 @@ static int brcmf_sdio_get_fwnames(struct brcmf_chip *ci, | |||
670 | struct brcmf_sdio_dev *sdiodev) | 670 | struct brcmf_sdio_dev *sdiodev) |
671 | { | 671 | { |
672 | int i; | 672 | int i; |
673 | uint fw_len, nv_len; | ||
674 | char end; | 673 | char end; |
675 | 674 | ||
676 | for (i = 0; i < ARRAY_SIZE(brcmf_fwname_data); i++) { | 675 | for (i = 0; i < ARRAY_SIZE(brcmf_fwname_data); i++) { |
@@ -684,25 +683,25 @@ static int brcmf_sdio_get_fwnames(struct brcmf_chip *ci, | |||
684 | return -ENODEV; | 683 | return -ENODEV; |
685 | } | 684 | } |
686 | 685 | ||
687 | fw_len = sizeof(sdiodev->fw_name) - 1; | ||
688 | nv_len = sizeof(sdiodev->nvram_name) - 1; | ||
689 | /* check if firmware path is provided by module parameter */ | 686 | /* check if firmware path is provided by module parameter */ |
690 | if (brcmf_firmware_path[0] != '\0') { | 687 | if (brcmf_firmware_path[0] != '\0') { |
691 | strncpy(sdiodev->fw_name, brcmf_firmware_path, fw_len); | 688 | strlcpy(sdiodev->fw_name, brcmf_firmware_path, |
692 | strncpy(sdiodev->nvram_name, brcmf_firmware_path, nv_len); | 689 | sizeof(sdiodev->fw_name)); |
693 | fw_len -= strlen(sdiodev->fw_name); | 690 | strlcpy(sdiodev->nvram_name, brcmf_firmware_path, |
694 | nv_len -= strlen(sdiodev->nvram_name); | 691 | sizeof(sdiodev->nvram_name)); |
695 | 692 | ||
696 | end = brcmf_firmware_path[strlen(brcmf_firmware_path) - 1]; | 693 | end = brcmf_firmware_path[strlen(brcmf_firmware_path) - 1]; |
697 | if (end != '/') { | 694 | if (end != '/') { |
698 | strncat(sdiodev->fw_name, "/", fw_len); | 695 | strlcat(sdiodev->fw_name, "/", |
699 | strncat(sdiodev->nvram_name, "/", nv_len); | 696 | sizeof(sdiodev->fw_name)); |
700 | fw_len--; | 697 | strlcat(sdiodev->nvram_name, "/", |
701 | nv_len--; | 698 | sizeof(sdiodev->nvram_name)); |
702 | } | 699 | } |
703 | } | 700 | } |
704 | strncat(sdiodev->fw_name, brcmf_fwname_data[i].bin, fw_len); | 701 | strlcat(sdiodev->fw_name, brcmf_fwname_data[i].bin, |
705 | strncat(sdiodev->nvram_name, brcmf_fwname_data[i].nv, nv_len); | 702 | sizeof(sdiodev->fw_name)); |
703 | strlcat(sdiodev->nvram_name, brcmf_fwname_data[i].nv, | ||
704 | sizeof(sdiodev->nvram_name)); | ||
706 | 705 | ||
707 | return 0; | 706 | return 0; |
708 | } | 707 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/vendor.c b/drivers/net/wireless/brcm80211/brcmfmac/vendor.c index 222f26a39642..50cdf7090198 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/vendor.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/vendor.c | |||
@@ -31,8 +31,8 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy, | |||
31 | struct wireless_dev *wdev, | 31 | struct wireless_dev *wdev, |
32 | const void *data, int len) | 32 | const void *data, int len) |
33 | { | 33 | { |
34 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | 34 | struct brcmf_cfg80211_vif *vif; |
35 | struct net_device *ndev = cfg_to_ndev(cfg); | 35 | struct brcmf_if *ifp; |
36 | const struct brcmf_vndr_dcmd_hdr *cmdhdr = data; | 36 | const struct brcmf_vndr_dcmd_hdr *cmdhdr = data; |
37 | struct sk_buff *reply; | 37 | struct sk_buff *reply; |
38 | int ret, payload, ret_len; | 38 | int ret, payload, ret_len; |
@@ -42,6 +42,9 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy, | |||
42 | brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set, | 42 | brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set, |
43 | cmdhdr->len); | 43 | cmdhdr->len); |
44 | 44 | ||
45 | vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); | ||
46 | ifp = vif->ifp; | ||
47 | |||
45 | len -= sizeof(struct brcmf_vndr_dcmd_hdr); | 48 | len -= sizeof(struct brcmf_vndr_dcmd_hdr); |
46 | ret_len = cmdhdr->len; | 49 | ret_len = cmdhdr->len; |
47 | if (ret_len > 0 || len > 0) { | 50 | if (ret_len > 0 || len > 0) { |
@@ -63,11 +66,11 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy, | |||
63 | } | 66 | } |
64 | 67 | ||
65 | if (cmdhdr->set) | 68 | if (cmdhdr->set) |
66 | ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), cmdhdr->cmd, | 69 | ret = brcmf_fil_cmd_data_set(ifp, cmdhdr->cmd, dcmd_buf, |
67 | dcmd_buf, ret_len); | 70 | ret_len); |
68 | else | 71 | else |
69 | ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), cmdhdr->cmd, | 72 | ret = brcmf_fil_cmd_data_get(ifp, cmdhdr->cmd, dcmd_buf, |
70 | dcmd_buf, ret_len); | 73 | ret_len); |
71 | if (ret != 0) | 74 | if (ret != 0) |
72 | goto exit; | 75 | goto exit; |
73 | 76 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c index 19740c1b1566..c9a8b9360ab1 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/debug.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "main.h" | 30 | #include "main.h" |
31 | #include "debug.h" | 31 | #include "debug.h" |
32 | #include "brcms_trace_events.h" | 32 | #include "brcms_trace_events.h" |
33 | #include "phy/phy_int.h" | ||
33 | 34 | ||
34 | static struct dentry *root_folder; | 35 | static struct dentry *root_folder; |
35 | 36 | ||
@@ -74,20 +75,33 @@ static | |||
74 | int brcms_debugfs_hardware_read(struct seq_file *s, void *data) | 75 | int brcms_debugfs_hardware_read(struct seq_file *s, void *data) |
75 | { | 76 | { |
76 | struct brcms_pub *drvr = s->private; | 77 | struct brcms_pub *drvr = s->private; |
78 | struct brcms_hardware *hw = drvr->wlc->hw; | ||
79 | struct bcma_device *core = hw->d11core; | ||
80 | struct bcma_bus *bus = core->bus; | ||
81 | char boardrev[10]; | ||
77 | 82 | ||
78 | seq_printf(s, "board vendor: %x\n" | 83 | seq_printf(s, "chipnum 0x%x\n" |
79 | "board type: %x\n" | 84 | "chiprev 0x%x\n" |
80 | "board revision: %x\n" | 85 | "chippackage 0x%x\n" |
81 | "board flags: %x\n" | 86 | "corerev 0x%x\n" |
82 | "board flags2: %x\n" | 87 | "boardid 0x%x\n" |
83 | "firmware revision: %x\n", | 88 | "boardvendor 0x%x\n" |
84 | drvr->wlc->hw->d11core->bus->boardinfo.vendor, | 89 | "boardrev %s\n" |
85 | drvr->wlc->hw->d11core->bus->boardinfo.type, | 90 | "boardflags 0x%x\n" |
86 | drvr->wlc->hw->boardrev, | 91 | "boardflags2 0x%x\n" |
87 | drvr->wlc->hw->boardflags, | 92 | "ucoderev 0x%x\n" |
88 | drvr->wlc->hw->boardflags2, | 93 | "radiorev 0x%x\n" |
89 | drvr->wlc->ucode_rev); | 94 | "phytype 0x%x\n" |
90 | 95 | "phyrev 0x%x\n" | |
96 | "anarev 0x%x\n" | ||
97 | "nvramrev %d\n", | ||
98 | bus->chipinfo.id, bus->chipinfo.rev, bus->chipinfo.pkg, | ||
99 | core->id.rev, bus->boardinfo.type, bus->boardinfo.vendor, | ||
100 | brcmu_boardrev_str(hw->boardrev, boardrev), | ||
101 | drvr->wlc->hw->boardflags, drvr->wlc->hw->boardflags2, | ||
102 | drvr->wlc->ucode_rev, hw->band->radiorev, | ||
103 | hw->band->phytype, hw->band->phyrev, hw->band->pi->ana_rev, | ||
104 | hw->sromrev); | ||
91 | return 0; | 105 | return 0; |
92 | } | 106 | } |
93 | 107 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 43c71bfaa474..f95b52442281 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | |||
@@ -764,7 +764,9 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw, | |||
764 | return; | 764 | return; |
765 | } | 765 | } |
766 | 766 | ||
767 | static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw) | 767 | static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw, |
768 | struct ieee80211_vif *vif, | ||
769 | const u8 *mac_addr) | ||
768 | { | 770 | { |
769 | struct brcms_info *wl = hw->priv; | 771 | struct brcms_info *wl = hw->priv; |
770 | spin_lock_bh(&wl->lock); | 772 | spin_lock_bh(&wl->lock); |
@@ -773,7 +775,8 @@ static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw) | |||
773 | return; | 775 | return; |
774 | } | 776 | } |
775 | 777 | ||
776 | static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw) | 778 | static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw, |
779 | struct ieee80211_vif *vif) | ||
777 | { | 780 | { |
778 | struct brcms_info *wl = hw->priv; | 781 | struct brcms_info *wl = hw->priv; |
779 | spin_lock_bh(&wl->lock); | 782 | spin_lock_bh(&wl->lock); |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index bc9be78faafa..a104d7ac3796 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c | |||
@@ -445,18 +445,18 @@ static void brcms_c_detach_mfree(struct brcms_c_info *wlc) | |||
445 | kfree(wlc->protection); | 445 | kfree(wlc->protection); |
446 | kfree(wlc->stf); | 446 | kfree(wlc->stf); |
447 | kfree(wlc->bandstate[0]); | 447 | kfree(wlc->bandstate[0]); |
448 | kfree(wlc->corestate->macstat_snapshot); | 448 | if (wlc->corestate) |
449 | kfree(wlc->corestate->macstat_snapshot); | ||
449 | kfree(wlc->corestate); | 450 | kfree(wlc->corestate); |
450 | kfree(wlc->hw->bandstate[0]); | 451 | if (wlc->hw) |
452 | kfree(wlc->hw->bandstate[0]); | ||
451 | kfree(wlc->hw); | 453 | kfree(wlc->hw); |
452 | if (wlc->beacon) | 454 | if (wlc->beacon) |
453 | dev_kfree_skb_any(wlc->beacon); | 455 | dev_kfree_skb_any(wlc->beacon); |
454 | if (wlc->probe_resp) | 456 | if (wlc->probe_resp) |
455 | dev_kfree_skb_any(wlc->probe_resp); | 457 | dev_kfree_skb_any(wlc->probe_resp); |
456 | 458 | ||
457 | /* free the wlc */ | ||
458 | kfree(wlc); | 459 | kfree(wlc); |
459 | wlc = NULL; | ||
460 | } | 460 | } |
461 | 461 | ||
462 | static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit) | 462 | static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit) |
@@ -1009,8 +1009,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) | |||
1009 | if (txh) | 1009 | if (txh) |
1010 | trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, | 1010 | trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, |
1011 | sizeof(*txh)); | 1011 | sizeof(*txh)); |
1012 | if (p) | 1012 | brcmu_pkt_buf_free_skb(p); |
1013 | brcmu_pkt_buf_free_skb(p); | ||
1014 | } | 1013 | } |
1015 | 1014 | ||
1016 | if (dma && queue < NFIFO) { | 1015 | if (dma && queue < NFIFO) { |
diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c index 0f7e1c7b6f58..906e89ddf319 100644 --- a/drivers/net/wireless/brcm80211/brcmutil/utils.c +++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c | |||
@@ -261,6 +261,21 @@ struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp, | |||
261 | } | 261 | } |
262 | EXPORT_SYMBOL(brcmu_pktq_mdeq); | 262 | EXPORT_SYMBOL(brcmu_pktq_mdeq); |
263 | 263 | ||
264 | /* Produce a human-readable string for boardrev */ | ||
265 | char *brcmu_boardrev_str(u32 brev, char *buf) | ||
266 | { | ||
267 | char c; | ||
268 | |||
269 | if (brev < 0x100) { | ||
270 | snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); | ||
271 | } else { | ||
272 | c = (brev & 0xf000) == 0x1000 ? 'P' : 'A'; | ||
273 | snprintf(buf, 8, "%c%03x", c, brev & 0xfff); | ||
274 | } | ||
275 | return buf; | ||
276 | } | ||
277 | EXPORT_SYMBOL(brcmu_boardrev_str); | ||
278 | |||
264 | #if defined(DEBUG) | 279 | #if defined(DEBUG) |
265 | /* pretty hex print a pkt buffer chain */ | 280 | /* pretty hex print a pkt buffer chain */ |
266 | void brcmu_prpkt(const char *msg, struct sk_buff *p0) | 281 | void brcmu_prpkt(const char *msg, struct sk_buff *p0) |
@@ -292,4 +307,5 @@ void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...) | |||
292 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data, size); | 307 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data, size); |
293 | } | 308 | } |
294 | EXPORT_SYMBOL(brcmu_dbg_hex_dump); | 309 | EXPORT_SYMBOL(brcmu_dbg_hex_dump); |
310 | |||
295 | #endif /* defined(DEBUG) */ | 311 | #endif /* defined(DEBUG) */ |
diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index af26e0de1e5c..6996fcc144cf 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h | |||
@@ -68,6 +68,8 @@ | |||
68 | #define BRCM_PCIE_43567_DEVICE_ID 0x43d3 | 68 | #define BRCM_PCIE_43567_DEVICE_ID 0x43d3 |
69 | #define BRCM_PCIE_43570_DEVICE_ID 0x43d9 | 69 | #define BRCM_PCIE_43570_DEVICE_ID 0x43d9 |
70 | #define BRCM_PCIE_43602_DEVICE_ID 0x43ba | 70 | #define BRCM_PCIE_43602_DEVICE_ID 0x43ba |
71 | #define BRCM_PCIE_43602_2G_DEVICE_ID 0x43bb | ||
72 | #define BRCM_PCIE_43602_5G_DEVICE_ID 0x43bc | ||
71 | 73 | ||
72 | /* brcmsmac IDs */ | 74 | /* brcmsmac IDs */ |
73 | #define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ | 75 | #define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ |
diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h index 8ba445b3fd72..a043e29f07e2 100644 --- a/drivers/net/wireless/brcm80211/include/brcmu_utils.h +++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h | |||
@@ -218,4 +218,6 @@ void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...) | |||
218 | } | 218 | } |
219 | #endif | 219 | #endif |
220 | 220 | ||
221 | char *brcmu_boardrev_str(u32 brev, char *buf); | ||
222 | |||
221 | #endif /* _BRCMU_UTILS_H_ */ | 223 | #endif /* _BRCMU_UTILS_H_ */ |
diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c index b2fb6c632092..f2e276faca70 100644 --- a/drivers/net/wireless/cw1200/scan.c +++ b/drivers/net/wireless/cw1200/scan.c | |||
@@ -78,7 +78,7 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, | |||
78 | if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS) | 78 | if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS) |
79 | return -EINVAL; | 79 | return -EINVAL; |
80 | 80 | ||
81 | frame.skb = ieee80211_probereq_get(hw, priv->vif, NULL, 0, | 81 | frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, |
82 | req->ie_len); | 82 | req->ie_len); |
83 | if (!frame.skb) | 83 | if (!frame.skb) |
84 | return -ENOMEM; | 84 | return -ENOMEM; |
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 26fec54dcd03..2748fde4b90c 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c | |||
@@ -6063,7 +6063,7 @@ il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
6063 | } | 6063 | } |
6064 | 6064 | ||
6065 | void | 6065 | void |
6066 | il4965_mac_channel_switch(struct ieee80211_hw *hw, | 6066 | il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
6067 | struct ieee80211_channel_switch *ch_switch) | 6067 | struct ieee80211_channel_switch *ch_switch) |
6068 | { | 6068 | { |
6069 | struct il_priv *il = hw->priv; | 6069 | struct il_priv *il = hw->priv; |
diff --git a/drivers/net/wireless/iwlegacy/4965.h b/drivers/net/wireless/iwlegacy/4965.h index 337dfcf3bbde..3a57f71b8ed5 100644 --- a/drivers/net/wireless/iwlegacy/4965.h +++ b/drivers/net/wireless/iwlegacy/4965.h | |||
@@ -187,8 +187,9 @@ int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
187 | u8 buf_size); | 187 | u8 buf_size); |
188 | int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 188 | int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
189 | struct ieee80211_sta *sta); | 189 | struct ieee80211_sta *sta); |
190 | void il4965_mac_channel_switch(struct ieee80211_hw *hw, | 190 | void |
191 | struct ieee80211_channel_switch *ch_switch); | 191 | il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
192 | struct ieee80211_channel_switch *ch_switch); | ||
192 | 193 | ||
193 | void il4965_led_enable(struct il_priv *il); | 194 | void il4965_led_enable(struct il_priv *il); |
194 | 195 | ||
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 139de90c2aaf..ab019b45551b 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
@@ -59,7 +59,7 @@ config IWLDVM | |||
59 | 59 | ||
60 | config IWLMVM | 60 | config IWLMVM |
61 | tristate "Intel Wireless WiFi MVM Firmware support" | 61 | tristate "Intel Wireless WiFi MVM Firmware support" |
62 | select BACKPORT_WANT_DEV_COREDUMP | 62 | select WANT_DEV_COREDUMP |
63 | help | 63 | help |
64 | This is the driver that supports the MVM firmware which is | 64 | This is the driver that supports the MVM firmware which is |
65 | currently only available for 7260 and 3160 devices. | 65 | currently only available for 7260 and 3160 devices. |
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 751ae1d10b7f..7a34e4d158d1 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h | |||
@@ -966,21 +966,21 @@ struct iwl_rem_sta_cmd { | |||
966 | 966 | ||
967 | 967 | ||
968 | /* WiFi queues mask */ | 968 | /* WiFi queues mask */ |
969 | #define IWL_SCD_BK_MSK cpu_to_le32(BIT(0)) | 969 | #define IWL_SCD_BK_MSK BIT(0) |
970 | #define IWL_SCD_BE_MSK cpu_to_le32(BIT(1)) | 970 | #define IWL_SCD_BE_MSK BIT(1) |
971 | #define IWL_SCD_VI_MSK cpu_to_le32(BIT(2)) | 971 | #define IWL_SCD_VI_MSK BIT(2) |
972 | #define IWL_SCD_VO_MSK cpu_to_le32(BIT(3)) | 972 | #define IWL_SCD_VO_MSK BIT(3) |
973 | #define IWL_SCD_MGMT_MSK cpu_to_le32(BIT(3)) | 973 | #define IWL_SCD_MGMT_MSK BIT(3) |
974 | 974 | ||
975 | /* PAN queues mask */ | 975 | /* PAN queues mask */ |
976 | #define IWL_PAN_SCD_BK_MSK cpu_to_le32(BIT(4)) | 976 | #define IWL_PAN_SCD_BK_MSK BIT(4) |
977 | #define IWL_PAN_SCD_BE_MSK cpu_to_le32(BIT(5)) | 977 | #define IWL_PAN_SCD_BE_MSK BIT(5) |
978 | #define IWL_PAN_SCD_VI_MSK cpu_to_le32(BIT(6)) | 978 | #define IWL_PAN_SCD_VI_MSK BIT(6) |
979 | #define IWL_PAN_SCD_VO_MSK cpu_to_le32(BIT(7)) | 979 | #define IWL_PAN_SCD_VO_MSK BIT(7) |
980 | #define IWL_PAN_SCD_MGMT_MSK cpu_to_le32(BIT(7)) | 980 | #define IWL_PAN_SCD_MGMT_MSK BIT(7) |
981 | #define IWL_PAN_SCD_MULTICAST_MSK cpu_to_le32(BIT(8)) | 981 | #define IWL_PAN_SCD_MULTICAST_MSK BIT(8) |
982 | 982 | ||
983 | #define IWL_AGG_TX_QUEUE_MSK cpu_to_le32(0xffc00) | 983 | #define IWL_AGG_TX_QUEUE_MSK 0xffc00 |
984 | 984 | ||
985 | #define IWL_DROP_ALL BIT(1) | 985 | #define IWL_DROP_ALL BIT(1) |
986 | 986 | ||
@@ -1005,12 +1005,17 @@ struct iwl_rem_sta_cmd { | |||
1005 | * 1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable. | 1005 | * 1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable. |
1006 | * 2: Dump all FIFO | 1006 | * 2: Dump all FIFO |
1007 | */ | 1007 | */ |
1008 | struct iwl_txfifo_flush_cmd { | 1008 | struct iwl_txfifo_flush_cmd_v3 { |
1009 | __le32 queue_control; | 1009 | __le32 queue_control; |
1010 | __le16 flush_control; | 1010 | __le16 flush_control; |
1011 | __le16 reserved; | 1011 | __le16 reserved; |
1012 | } __packed; | 1012 | } __packed; |
1013 | 1013 | ||
1014 | struct iwl_txfifo_flush_cmd_v2 { | ||
1015 | __le16 queue_control; | ||
1016 | __le16 flush_control; | ||
1017 | } __packed; | ||
1018 | |||
1014 | /* | 1019 | /* |
1015 | * REPLY_WEP_KEY = 0x20 | 1020 | * REPLY_WEP_KEY = 0x20 |
1016 | */ | 1021 | */ |
diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 02e4ede2b042..1d2223df5cb0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c | |||
@@ -137,37 +137,38 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, | |||
137 | */ | 137 | */ |
138 | int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk) | 138 | int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk) |
139 | { | 139 | { |
140 | struct iwl_txfifo_flush_cmd flush_cmd; | 140 | struct iwl_txfifo_flush_cmd_v3 flush_cmd_v3 = { |
141 | struct iwl_host_cmd cmd = { | 141 | .flush_control = cpu_to_le16(IWL_DROP_ALL), |
142 | .id = REPLY_TXFIFO_FLUSH, | 142 | }; |
143 | .len = { sizeof(struct iwl_txfifo_flush_cmd), }, | 143 | struct iwl_txfifo_flush_cmd_v2 flush_cmd_v2 = { |
144 | .data = { &flush_cmd, }, | 144 | .flush_control = cpu_to_le16(IWL_DROP_ALL), |
145 | }; | 145 | }; |
146 | 146 | ||
147 | memset(&flush_cmd, 0, sizeof(flush_cmd)); | 147 | u32 queue_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK | |
148 | IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | IWL_SCD_MGMT_MSK; | ||
148 | 149 | ||
149 | flush_cmd.queue_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK | | ||
150 | IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | | ||
151 | IWL_SCD_MGMT_MSK; | ||
152 | if ((priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) | 150 | if ((priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) |
153 | flush_cmd.queue_control |= IWL_PAN_SCD_VO_MSK | | 151 | queue_control |= IWL_PAN_SCD_VO_MSK | IWL_PAN_SCD_VI_MSK | |
154 | IWL_PAN_SCD_VI_MSK | | 152 | IWL_PAN_SCD_BE_MSK | IWL_PAN_SCD_BK_MSK | |
155 | IWL_PAN_SCD_BE_MSK | | 153 | IWL_PAN_SCD_MGMT_MSK | |
156 | IWL_PAN_SCD_BK_MSK | | 154 | IWL_PAN_SCD_MULTICAST_MSK; |
157 | IWL_PAN_SCD_MGMT_MSK | | ||
158 | IWL_PAN_SCD_MULTICAST_MSK; | ||
159 | 155 | ||
160 | if (priv->nvm_data->sku_cap_11n_enable) | 156 | if (priv->nvm_data->sku_cap_11n_enable) |
161 | flush_cmd.queue_control |= IWL_AGG_TX_QUEUE_MSK; | 157 | queue_control |= IWL_AGG_TX_QUEUE_MSK; |
162 | 158 | ||
163 | if (scd_q_msk) | 159 | if (scd_q_msk) |
164 | flush_cmd.queue_control = cpu_to_le32(scd_q_msk); | 160 | queue_control = scd_q_msk; |
165 | 161 | ||
166 | IWL_DEBUG_INFO(priv, "queue control: 0x%x\n", | 162 | IWL_DEBUG_INFO(priv, "queue control: 0x%x\n", queue_control); |
167 | flush_cmd.queue_control); | 163 | flush_cmd_v3.queue_control = cpu_to_le32(queue_control); |
168 | flush_cmd.flush_control = cpu_to_le16(IWL_DROP_ALL); | 164 | flush_cmd_v2.queue_control = cpu_to_le16((u16)queue_control); |
169 | 165 | ||
170 | return iwl_dvm_send_cmd(priv, &cmd); | 166 | if (IWL_UCODE_API(priv->fw->ucode_ver) > 2) |
167 | return iwl_dvm_send_cmd_pdu(priv, REPLY_TXFIFO_FLUSH, 0, | ||
168 | sizeof(flush_cmd_v3), | ||
169 | &flush_cmd_v3); | ||
170 | return iwl_dvm_send_cmd_pdu(priv, REPLY_TXFIFO_FLUSH, 0, | ||
171 | sizeof(flush_cmd_v2), &flush_cmd_v2); | ||
171 | } | 172 | } |
172 | 173 | ||
173 | void iwlagn_dev_txfifo_flush(struct iwl_priv *priv) | 174 | void iwlagn_dev_txfifo_flush(struct iwl_priv *priv) |
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index cae692ff1013..47e64e8b9517 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -941,6 +941,7 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw, | |||
941 | } | 941 | } |
942 | 942 | ||
943 | static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | 943 | static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, |
944 | struct ieee80211_vif *vif, | ||
944 | struct ieee80211_channel_switch *ch_switch) | 945 | struct ieee80211_channel_switch *ch_switch) |
945 | { | 946 | { |
946 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 947 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index b04b8858c690..e5be2d21868f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c | |||
@@ -73,12 +73,12 @@ | |||
73 | #define IWL3160_UCODE_API_MAX 10 | 73 | #define IWL3160_UCODE_API_MAX 10 |
74 | 74 | ||
75 | /* Oldest version we won't warn about */ | 75 | /* Oldest version we won't warn about */ |
76 | #define IWL7260_UCODE_API_OK 9 | 76 | #define IWL7260_UCODE_API_OK 10 |
77 | #define IWL3160_UCODE_API_OK 9 | 77 | #define IWL3160_UCODE_API_OK 10 |
78 | 78 | ||
79 | /* Lowest firmware API version supported */ | 79 | /* Lowest firmware API version supported */ |
80 | #define IWL7260_UCODE_API_MIN 8 | 80 | #define IWL7260_UCODE_API_MIN 9 |
81 | #define IWL3160_UCODE_API_MIN 8 | 81 | #define IWL3160_UCODE_API_MIN 9 |
82 | 82 | ||
83 | /* NVM versions */ | 83 | /* NVM versions */ |
84 | #define IWL7260_NVM_VERSION 0x0a1d | 84 | #define IWL7260_NVM_VERSION 0x0a1d |
@@ -89,6 +89,8 @@ | |||
89 | #define IWL3165_TX_POWER_VERSION 0xffff /* meaningless */ | 89 | #define IWL3165_TX_POWER_VERSION 0xffff /* meaningless */ |
90 | #define IWL7265_NVM_VERSION 0x0a1d | 90 | #define IWL7265_NVM_VERSION 0x0a1d |
91 | #define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ | 91 | #define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ |
92 | #define IWL7265D_NVM_VERSION 0x0c11 | ||
93 | #define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ | ||
92 | 94 | ||
93 | #define IWL7260_FW_PRE "iwlwifi-7260-" | 95 | #define IWL7260_FW_PRE "iwlwifi-7260-" |
94 | #define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" | 96 | #define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" |
@@ -102,6 +104,9 @@ | |||
102 | #define IWL7265_FW_PRE "iwlwifi-7265-" | 104 | #define IWL7265_FW_PRE "iwlwifi-7265-" |
103 | #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" | 105 | #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" |
104 | 106 | ||
107 | #define IWL7265D_FW_PRE "iwlwifi-7265D-" | ||
108 | #define IWL7265D_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" | ||
109 | |||
105 | #define NVM_HW_SECTION_NUM_FAMILY_7000 0 | 110 | #define NVM_HW_SECTION_NUM_FAMILY_7000 0 |
106 | 111 | ||
107 | static const struct iwl_base_params iwl7000_base_params = { | 112 | static const struct iwl_base_params iwl7000_base_params = { |
@@ -132,8 +137,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { | |||
132 | .base_params = &iwl7000_base_params, \ | 137 | .base_params = &iwl7000_base_params, \ |
133 | .led_mode = IWL_LED_RF_STATE, \ | 138 | .led_mode = IWL_LED_RF_STATE, \ |
134 | .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ | 139 | .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ |
135 | .non_shared_ant = ANT_A | 140 | .non_shared_ant = ANT_A, \ |
136 | 141 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | |
137 | 142 | ||
138 | const struct iwl_cfg iwl7260_2ac_cfg = { | 143 | const struct iwl_cfg iwl7260_2ac_cfg = { |
139 | .name = "Intel(R) Dual Band Wireless AC 7260", | 144 | .name = "Intel(R) Dual Band Wireless AC 7260", |
@@ -267,7 +272,38 @@ const struct iwl_cfg iwl7265_n_cfg = { | |||
267 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | 272 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, |
268 | }; | 273 | }; |
269 | 274 | ||
275 | const struct iwl_cfg iwl7265d_2ac_cfg = { | ||
276 | .name = "Intel(R) Dual Band Wireless AC 7265", | ||
277 | .fw_name_pre = IWL7265D_FW_PRE, | ||
278 | IWL_DEVICE_7000, | ||
279 | .ht_params = &iwl7265_ht_params, | ||
280 | .nvm_ver = IWL7265D_NVM_VERSION, | ||
281 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | ||
282 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | ||
283 | }; | ||
284 | |||
285 | const struct iwl_cfg iwl7265d_2n_cfg = { | ||
286 | .name = "Intel(R) Dual Band Wireless N 7265", | ||
287 | .fw_name_pre = IWL7265D_FW_PRE, | ||
288 | IWL_DEVICE_7000, | ||
289 | .ht_params = &iwl7265_ht_params, | ||
290 | .nvm_ver = IWL7265D_NVM_VERSION, | ||
291 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | ||
292 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | ||
293 | }; | ||
294 | |||
295 | const struct iwl_cfg iwl7265d_n_cfg = { | ||
296 | .name = "Intel(R) Wireless N 7265", | ||
297 | .fw_name_pre = IWL7265D_FW_PRE, | ||
298 | IWL_DEVICE_7000, | ||
299 | .ht_params = &iwl7265_ht_params, | ||
300 | .nvm_ver = IWL7265D_NVM_VERSION, | ||
301 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | ||
302 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | ||
303 | }; | ||
304 | |||
270 | MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); | 305 | MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); |
271 | MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); | 306 | MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); |
272 | MODULE_FIRMWARE(IWL3165_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); | 307 | MODULE_FIRMWARE(IWL3165_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); |
273 | MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); | 308 | MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); |
309 | MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 896ea906549c..bf0a95cb7153 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c | |||
@@ -72,10 +72,10 @@ | |||
72 | #define IWL8000_UCODE_API_MAX 10 | 72 | #define IWL8000_UCODE_API_MAX 10 |
73 | 73 | ||
74 | /* Oldest version we won't warn about */ | 74 | /* Oldest version we won't warn about */ |
75 | #define IWL8000_UCODE_API_OK 8 | 75 | #define IWL8000_UCODE_API_OK 10 |
76 | 76 | ||
77 | /* Lowest firmware API version supported */ | 77 | /* Lowest firmware API version supported */ |
78 | #define IWL8000_UCODE_API_MIN 8 | 78 | #define IWL8000_UCODE_API_MIN 9 |
79 | 79 | ||
80 | /* NVM versions */ | 80 | /* NVM versions */ |
81 | #define IWL8000_NVM_VERSION 0x0a1d | 81 | #define IWL8000_NVM_VERSION 0x0a1d |
@@ -91,6 +91,10 @@ | |||
91 | /* Max SDIO RX aggregation size of the ADDBA request/response */ | 91 | /* Max SDIO RX aggregation size of the ADDBA request/response */ |
92 | #define MAX_RX_AGG_SIZE_8260_SDIO 28 | 92 | #define MAX_RX_AGG_SIZE_8260_SDIO 28 |
93 | 93 | ||
94 | /* Max A-MPDU exponent for HT and VHT */ | ||
95 | #define MAX_HT_AMPDU_EXPONENT_8260_SDIO IEEE80211_HT_MAX_AMPDU_32K | ||
96 | #define MAX_VHT_AMPDU_EXPONENT_8260_SDIO IEEE80211_VHT_MAX_AMPDU_32K | ||
97 | |||
94 | static const struct iwl_base_params iwl8000_base_params = { | 98 | static const struct iwl_base_params iwl8000_base_params = { |
95 | .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, | 99 | .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, |
96 | .num_of_queues = IWLAGN_NUM_QUEUES, | 100 | .num_of_queues = IWLAGN_NUM_QUEUES, |
@@ -119,6 +123,7 @@ static const struct iwl_ht_params iwl8000_ht_params = { | |||
119 | .base_params = &iwl8000_base_params, \ | 123 | .base_params = &iwl8000_base_params, \ |
120 | .led_mode = IWL_LED_RF_STATE, \ | 124 | .led_mode = IWL_LED_RF_STATE, \ |
121 | .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ | 125 | .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ |
126 | .d0i3 = true, \ | ||
122 | .non_shared_ant = ANT_A | 127 | .non_shared_ant = ANT_A |
123 | 128 | ||
124 | const struct iwl_cfg iwl8260_2n_cfg = { | 129 | const struct iwl_cfg iwl8260_2n_cfg = { |
@@ -137,6 +142,7 @@ const struct iwl_cfg iwl8260_2ac_cfg = { | |||
137 | .ht_params = &iwl8000_ht_params, | 142 | .ht_params = &iwl8000_ht_params, |
138 | .nvm_ver = IWL8000_NVM_VERSION, | 143 | .nvm_ver = IWL8000_NVM_VERSION, |
139 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, | 144 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, |
145 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, | ||
140 | }; | 146 | }; |
141 | 147 | ||
142 | const struct iwl_cfg iwl8260_2ac_sdio_cfg = { | 148 | const struct iwl_cfg iwl8260_2ac_sdio_cfg = { |
@@ -149,6 +155,23 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { | |||
149 | .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, | 155 | .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, |
150 | .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, | 156 | .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, |
151 | .disable_dummy_notification = true, | 157 | .disable_dummy_notification = true, |
158 | .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, | ||
159 | .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, | ||
160 | }; | ||
161 | |||
162 | const struct iwl_cfg iwl4165_2ac_sdio_cfg = { | ||
163 | .name = "Intel(R) Dual Band Wireless-AC 4165", | ||
164 | .fw_name_pre = IWL8000_FW_PRE, | ||
165 | IWL_DEVICE_8000, | ||
166 | .ht_params = &iwl8000_ht_params, | ||
167 | .nvm_ver = IWL8000_NVM_VERSION, | ||
168 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, | ||
169 | .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, | ||
170 | .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, | ||
171 | .bt_shared_single_ant = true, | ||
172 | .disable_dummy_notification = true, | ||
173 | .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, | ||
174 | .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, | ||
152 | }; | 175 | }; |
153 | 176 | ||
154 | MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); | 177 | MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index f8aa9cf08279..3a4b9c7fc083 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h | |||
@@ -257,6 +257,10 @@ struct iwl_pwr_tx_backoff { | |||
257 | * @pwr_tx_backoffs: translation table between power limits and backoffs | 257 | * @pwr_tx_backoffs: translation table between power limits and backoffs |
258 | * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response | 258 | * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response |
259 | * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response | 259 | * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response |
260 | * @max_ht_ampdu_factor: the exponent of the max length of A-MPDU that the | ||
261 | * station can receive in HT | ||
262 | * @max_vht_ampdu_exponent: the exponent of the max length of A-MPDU that the | ||
263 | * station can receive in VHT | ||
260 | * | 264 | * |
261 | * We enable the driver to be backward compatible wrt. hardware features. | 265 | * We enable the driver to be backward compatible wrt. hardware features. |
262 | * API differences in uCode shouldn't be handled here but through TLVs | 266 | * API differences in uCode shouldn't be handled here but through TLVs |
@@ -297,6 +301,8 @@ struct iwl_cfg { | |||
297 | unsigned int max_rx_agg_size; | 301 | unsigned int max_rx_agg_size; |
298 | bool disable_dummy_notification; | 302 | bool disable_dummy_notification; |
299 | unsigned int max_tx_agg_size; | 303 | unsigned int max_tx_agg_size; |
304 | unsigned int max_ht_ampdu_exponent; | ||
305 | unsigned int max_vht_ampdu_exponent; | ||
300 | }; | 306 | }; |
301 | 307 | ||
302 | /* | 308 | /* |
@@ -358,9 +364,14 @@ extern const struct iwl_cfg iwl3165_2ac_cfg; | |||
358 | extern const struct iwl_cfg iwl7265_2ac_cfg; | 364 | extern const struct iwl_cfg iwl7265_2ac_cfg; |
359 | extern const struct iwl_cfg iwl7265_2n_cfg; | 365 | extern const struct iwl_cfg iwl7265_2n_cfg; |
360 | extern const struct iwl_cfg iwl7265_n_cfg; | 366 | extern const struct iwl_cfg iwl7265_n_cfg; |
367 | extern const struct iwl_cfg iwl7265d_2ac_cfg; | ||
368 | extern const struct iwl_cfg iwl7265d_2n_cfg; | ||
369 | extern const struct iwl_cfg iwl7265d_n_cfg; | ||
361 | extern const struct iwl_cfg iwl8260_2n_cfg; | 370 | extern const struct iwl_cfg iwl8260_2n_cfg; |
362 | extern const struct iwl_cfg iwl8260_2ac_cfg; | 371 | extern const struct iwl_cfg iwl8260_2ac_cfg; |
363 | extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; | 372 | extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; |
373 | extern const struct iwl_cfg iwl4265_2ac_sdio_cfg; | ||
374 | extern const struct iwl_cfg iwl4165_2ac_sdio_cfg; | ||
364 | #endif /* CONFIG_IWLMVM */ | 375 | #endif /* CONFIG_IWLMVM */ |
365 | 376 | ||
366 | #endif /* __IWL_CONFIG_H__ */ | 377 | #endif /* __IWL_CONFIG_H__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 3f6f015285e5..aff63c3f5bf8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
@@ -129,6 +129,8 @@ | |||
129 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) | 129 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) |
130 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) | 130 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) |
131 | 131 | ||
132 | #define CSR_MBOX_SET_REG (CSR_BASE + 0x88) | ||
133 | |||
132 | #define CSR_LED_REG (CSR_BASE+0x094) | 134 | #define CSR_LED_REG (CSR_BASE+0x094) |
133 | #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) | 135 | #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) |
134 | #define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE+0x0A8) /* 6000 and up */ | 136 | #define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE+0x0A8) /* 6000 and up */ |
@@ -184,6 +186,8 @@ | |||
184 | #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ | 186 | #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ |
185 | #define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ | 187 | #define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ |
186 | 188 | ||
189 | #define CSR_MBOX_SET_REG_OS_ALIVE BIT(5) | ||
190 | |||
187 | #define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ | 191 | #define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ |
188 | #define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ | 192 | #define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ |
189 | 193 | ||
@@ -305,23 +309,24 @@ enum { | |||
305 | }; | 309 | }; |
306 | 310 | ||
307 | 311 | ||
308 | #define CSR_HW_REV_TYPE_MSK (0x000FFF0) | 312 | #define CSR_HW_REV_TYPE_MSK (0x000FFF0) |
309 | #define CSR_HW_REV_TYPE_5300 (0x0000020) | 313 | #define CSR_HW_REV_TYPE_5300 (0x0000020) |
310 | #define CSR_HW_REV_TYPE_5350 (0x0000030) | 314 | #define CSR_HW_REV_TYPE_5350 (0x0000030) |
311 | #define CSR_HW_REV_TYPE_5100 (0x0000050) | 315 | #define CSR_HW_REV_TYPE_5100 (0x0000050) |
312 | #define CSR_HW_REV_TYPE_5150 (0x0000040) | 316 | #define CSR_HW_REV_TYPE_5150 (0x0000040) |
313 | #define CSR_HW_REV_TYPE_1000 (0x0000060) | 317 | #define CSR_HW_REV_TYPE_1000 (0x0000060) |
314 | #define CSR_HW_REV_TYPE_6x00 (0x0000070) | 318 | #define CSR_HW_REV_TYPE_6x00 (0x0000070) |
315 | #define CSR_HW_REV_TYPE_6x50 (0x0000080) | 319 | #define CSR_HW_REV_TYPE_6x50 (0x0000080) |
316 | #define CSR_HW_REV_TYPE_6150 (0x0000084) | 320 | #define CSR_HW_REV_TYPE_6150 (0x0000084) |
317 | #define CSR_HW_REV_TYPE_6x05 (0x00000B0) | 321 | #define CSR_HW_REV_TYPE_6x05 (0x00000B0) |
318 | #define CSR_HW_REV_TYPE_6x30 CSR_HW_REV_TYPE_6x05 | 322 | #define CSR_HW_REV_TYPE_6x30 CSR_HW_REV_TYPE_6x05 |
319 | #define CSR_HW_REV_TYPE_6x35 CSR_HW_REV_TYPE_6x05 | 323 | #define CSR_HW_REV_TYPE_6x35 CSR_HW_REV_TYPE_6x05 |
320 | #define CSR_HW_REV_TYPE_2x30 (0x00000C0) | 324 | #define CSR_HW_REV_TYPE_2x30 (0x00000C0) |
321 | #define CSR_HW_REV_TYPE_2x00 (0x0000100) | 325 | #define CSR_HW_REV_TYPE_2x00 (0x0000100) |
322 | #define CSR_HW_REV_TYPE_105 (0x0000110) | 326 | #define CSR_HW_REV_TYPE_105 (0x0000110) |
323 | #define CSR_HW_REV_TYPE_135 (0x0000120) | 327 | #define CSR_HW_REV_TYPE_135 (0x0000120) |
324 | #define CSR_HW_REV_TYPE_NONE (0x00001F0) | 328 | #define CSR_HW_REV_TYPE_7265D (0x0000210) |
329 | #define CSR_HW_REV_TYPE_NONE (0x00001F0) | ||
325 | 330 | ||
326 | /* EEPROM REG */ | 331 | /* EEPROM REG */ |
327 | #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) | 332 | #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 0a70bcd241f5..684254553558 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h | |||
@@ -143,7 +143,7 @@ do { \ | |||
143 | #define IWL_DL_INFO 0x00000001 | 143 | #define IWL_DL_INFO 0x00000001 |
144 | #define IWL_DL_MAC80211 0x00000002 | 144 | #define IWL_DL_MAC80211 0x00000002 |
145 | #define IWL_DL_HCMD 0x00000004 | 145 | #define IWL_DL_HCMD 0x00000004 |
146 | #define IWL_DL_STATE 0x00000008 | 146 | #define IWL_DL_TDLS 0x00000008 |
147 | /* 0x000000F0 - 0x00000010 */ | 147 | /* 0x000000F0 - 0x00000010 */ |
148 | #define IWL_DL_QUOTA 0x00000010 | 148 | #define IWL_DL_QUOTA 0x00000010 |
149 | #define IWL_DL_TE 0x00000020 | 149 | #define IWL_DL_TE 0x00000020 |
@@ -180,6 +180,7 @@ do { \ | |||
180 | #define IWL_DL_TX_QUEUES 0x80000000 | 180 | #define IWL_DL_TX_QUEUES 0x80000000 |
181 | 181 | ||
182 | #define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a) | 182 | #define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a) |
183 | #define IWL_DEBUG_TDLS(p, f, a...) IWL_DEBUG(p, IWL_DL_TDLS, f, ## a) | ||
183 | #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a) | 184 | #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a) |
184 | #define IWL_DEBUG_EXTERNAL(p, f, a...) IWL_DEBUG(p, IWL_DL_EXTERNAL, f, ## a) | 185 | #define IWL_DEBUG_EXTERNAL(p, f, a...) IWL_DEBUG(p, IWL_DL_EXTERNAL, f, ## a) |
185 | #define IWL_DEBUG_TEMP(p, f, a...) IWL_DEBUG(p, IWL_DL_TEMP, f, ## a) | 186 | #define IWL_DEBUG_TEMP(p, f, a...) IWL_DEBUG(p, IWL_DL_TEMP, f, ## a) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index d9fa8e034da2..38de1513e4de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -78,9 +78,6 @@ | |||
78 | #include "iwl-config.h" | 78 | #include "iwl-config.h" |
79 | #include "iwl-modparams.h" | 79 | #include "iwl-modparams.h" |
80 | 80 | ||
81 | /* private includes */ | ||
82 | #include "iwl-fw-file.h" | ||
83 | |||
84 | /****************************************************************************** | 81 | /****************************************************************************** |
85 | * | 82 | * |
86 | * module boiler plate | 83 | * module boiler plate |
@@ -187,6 +184,11 @@ static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img) | |||
187 | static void iwl_dealloc_ucode(struct iwl_drv *drv) | 184 | static void iwl_dealloc_ucode(struct iwl_drv *drv) |
188 | { | 185 | { |
189 | int i; | 186 | int i; |
187 | |||
188 | kfree(drv->fw.dbg_dest_tlv); | ||
189 | for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) | ||
190 | kfree(drv->fw.dbg_conf_tlv[i]); | ||
191 | |||
190 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) | 192 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) |
191 | iwl_free_fw_img(drv, drv->fw.img + i); | 193 | iwl_free_fw_img(drv, drv->fw.img + i); |
192 | } | 194 | } |
@@ -248,6 +250,9 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) | |||
248 | /* | 250 | /* |
249 | * Starting 8000B - FW name format has changed. This overwrites the | 251 | * Starting 8000B - FW name format has changed. This overwrites the |
250 | * previous name and uses the new format. | 252 | * previous name and uses the new format. |
253 | * | ||
254 | * TODO: | ||
255 | * Once there is only one supported step for 8000 family - delete this! | ||
251 | */ | 256 | */ |
252 | if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { | 257 | if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { |
253 | char rev_step[2] = { | 258 | char rev_step[2] = { |
@@ -258,6 +263,13 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) | |||
258 | if (CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP) | 263 | if (CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP) |
259 | rev_step[0] = 0; | 264 | rev_step[0] = 0; |
260 | 265 | ||
266 | /* | ||
267 | * If hw_rev wasn't set yet - default as B-step. If it IS A-step | ||
268 | * we'll reload that FW later instead. | ||
269 | */ | ||
270 | if (drv->trans->hw_rev == 0) | ||
271 | rev_step[0] = 'B'; | ||
272 | |||
261 | snprintf(drv->firmware_name, sizeof(drv->firmware_name), | 273 | snprintf(drv->firmware_name, sizeof(drv->firmware_name), |
262 | "%s%s-%s.ucode", name_pre, rev_step, tag); | 274 | "%s%s-%s.ucode", name_pre, rev_step, tag); |
263 | } | 275 | } |
@@ -301,6 +313,11 @@ struct iwl_firmware_pieces { | |||
301 | 313 | ||
302 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | 314 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; |
303 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | 315 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; |
316 | |||
317 | /* FW debug data parsed for driver usage */ | ||
318 | struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; | ||
319 | struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; | ||
320 | size_t dbg_conf_tlv_len[FW_DBG_MAX]; | ||
304 | }; | 321 | }; |
305 | 322 | ||
306 | /* | 323 | /* |
@@ -574,6 +591,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
574 | char buildstr[25]; | 591 | char buildstr[25]; |
575 | u32 build; | 592 | u32 build; |
576 | int num_of_cpus; | 593 | int num_of_cpus; |
594 | bool usniffer_images = false; | ||
595 | bool usniffer_req = false; | ||
577 | 596 | ||
578 | if (len < sizeof(*ucode)) { | 597 | if (len < sizeof(*ucode)) { |
579 | IWL_ERR(drv, "uCode has invalid length: %zd\n", len); | 598 | IWL_ERR(drv, "uCode has invalid length: %zd\n", len); |
@@ -846,12 +865,79 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
846 | capa->n_scan_channels = | 865 | capa->n_scan_channels = |
847 | le32_to_cpup((__le32 *)tlv_data); | 866 | le32_to_cpup((__le32 *)tlv_data); |
848 | break; | 867 | break; |
868 | case IWL_UCODE_TLV_FW_DBG_DEST: { | ||
869 | struct iwl_fw_dbg_dest_tlv *dest = (void *)tlv_data; | ||
870 | |||
871 | if (pieces->dbg_dest_tlv) { | ||
872 | IWL_ERR(drv, | ||
873 | "dbg destination ignored, already exists\n"); | ||
874 | break; | ||
875 | } | ||
876 | |||
877 | pieces->dbg_dest_tlv = dest; | ||
878 | IWL_INFO(drv, "Found debug destination: %s\n", | ||
879 | get_fw_dbg_mode_string(dest->monitor_mode)); | ||
880 | |||
881 | drv->fw.dbg_dest_reg_num = | ||
882 | tlv_len - offsetof(struct iwl_fw_dbg_dest_tlv, | ||
883 | reg_ops); | ||
884 | drv->fw.dbg_dest_reg_num /= | ||
885 | sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]); | ||
886 | |||
887 | break; | ||
888 | } | ||
889 | case IWL_UCODE_TLV_FW_DBG_CONF: { | ||
890 | struct iwl_fw_dbg_conf_tlv *conf = (void *)tlv_data; | ||
891 | |||
892 | if (!pieces->dbg_dest_tlv) { | ||
893 | IWL_ERR(drv, | ||
894 | "Ignore dbg config %d - no destination configured\n", | ||
895 | conf->id); | ||
896 | break; | ||
897 | } | ||
898 | |||
899 | if (conf->id >= ARRAY_SIZE(drv->fw.dbg_conf_tlv)) { | ||
900 | IWL_ERR(drv, | ||
901 | "Skip unknown configuration: %d\n", | ||
902 | conf->id); | ||
903 | break; | ||
904 | } | ||
905 | |||
906 | if (pieces->dbg_conf_tlv[conf->id]) { | ||
907 | IWL_ERR(drv, | ||
908 | "Ignore duplicate dbg config %d\n", | ||
909 | conf->id); | ||
910 | break; | ||
911 | } | ||
912 | |||
913 | if (conf->usniffer) | ||
914 | usniffer_req = true; | ||
915 | |||
916 | IWL_INFO(drv, "Found debug configuration: %d\n", | ||
917 | conf->id); | ||
918 | |||
919 | pieces->dbg_conf_tlv[conf->id] = conf; | ||
920 | pieces->dbg_conf_tlv_len[conf->id] = tlv_len; | ||
921 | break; | ||
922 | } | ||
923 | case IWL_UCODE_TLV_SEC_RT_USNIFFER: | ||
924 | usniffer_images = true; | ||
925 | iwl_store_ucode_sec(pieces, tlv_data, | ||
926 | IWL_UCODE_REGULAR_USNIFFER, | ||
927 | tlv_len); | ||
928 | break; | ||
849 | default: | 929 | default: |
850 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); | 930 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); |
851 | break; | 931 | break; |
852 | } | 932 | } |
853 | } | 933 | } |
854 | 934 | ||
935 | if (usniffer_req && !usniffer_images) { | ||
936 | IWL_ERR(drv, | ||
937 | "user selected to work with usniffer but usniffer image isn't available in ucode package\n"); | ||
938 | return -EINVAL; | ||
939 | } | ||
940 | |||
855 | if (len) { | 941 | if (len) { |
856 | IWL_ERR(drv, "invalid TLV after parsing: %zd\n", len); | 942 | IWL_ERR(drv, "invalid TLV after parsing: %zd\n", len); |
857 | iwl_print_hex_dump(drv, IWL_DL_FW, (u8 *)data, len); | 943 | iwl_print_hex_dump(drv, IWL_DL_FW, (u8 *)data, len); |
@@ -989,13 +1075,14 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
989 | struct iwl_ucode_header *ucode; | 1075 | struct iwl_ucode_header *ucode; |
990 | struct iwlwifi_opmode_table *op; | 1076 | struct iwlwifi_opmode_table *op; |
991 | int err; | 1077 | int err; |
992 | struct iwl_firmware_pieces pieces; | 1078 | struct iwl_firmware_pieces *pieces; |
993 | const unsigned int api_max = drv->cfg->ucode_api_max; | 1079 | const unsigned int api_max = drv->cfg->ucode_api_max; |
994 | unsigned int api_ok = drv->cfg->ucode_api_ok; | 1080 | unsigned int api_ok = drv->cfg->ucode_api_ok; |
995 | const unsigned int api_min = drv->cfg->ucode_api_min; | 1081 | const unsigned int api_min = drv->cfg->ucode_api_min; |
996 | u32 api_ver; | 1082 | u32 api_ver; |
997 | int i; | 1083 | int i; |
998 | bool load_module = false; | 1084 | bool load_module = false; |
1085 | u32 hw_rev = drv->trans->hw_rev; | ||
999 | 1086 | ||
1000 | fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; | 1087 | fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; |
1001 | fw->ucode_capa.standard_phy_calibration_size = | 1088 | fw->ucode_capa.standard_phy_calibration_size = |
@@ -1005,7 +1092,9 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1005 | if (!api_ok) | 1092 | if (!api_ok) |
1006 | api_ok = api_max; | 1093 | api_ok = api_max; |
1007 | 1094 | ||
1008 | memset(&pieces, 0, sizeof(pieces)); | 1095 | pieces = kzalloc(sizeof(*pieces), GFP_KERNEL); |
1096 | if (!pieces) | ||
1097 | return; | ||
1009 | 1098 | ||
1010 | if (!ucode_raw) { | 1099 | if (!ucode_raw) { |
1011 | if (drv->fw_index <= api_ok) | 1100 | if (drv->fw_index <= api_ok) |
@@ -1028,10 +1117,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1028 | ucode = (struct iwl_ucode_header *)ucode_raw->data; | 1117 | ucode = (struct iwl_ucode_header *)ucode_raw->data; |
1029 | 1118 | ||
1030 | if (ucode->ver) | 1119 | if (ucode->ver) |
1031 | err = iwl_parse_v1_v2_firmware(drv, ucode_raw, &pieces); | 1120 | err = iwl_parse_v1_v2_firmware(drv, ucode_raw, pieces); |
1032 | else | 1121 | else |
1033 | err = iwl_parse_tlv_firmware(drv, ucode_raw, &pieces, | 1122 | err = iwl_parse_tlv_firmware(drv, ucode_raw, pieces, |
1034 | &fw->ucode_capa); | 1123 | &fw->ucode_capa); |
1035 | 1124 | ||
1036 | if (err) | 1125 | if (err) |
1037 | goto try_again; | 1126 | goto try_again; |
@@ -1071,7 +1160,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1071 | * In mvm uCode there is no difference between data and instructions | 1160 | * In mvm uCode there is no difference between data and instructions |
1072 | * sections. | 1161 | * sections. |
1073 | */ | 1162 | */ |
1074 | if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, drv->cfg)) | 1163 | if (!fw->mvm_fw && validate_sec_sizes(drv, pieces, drv->cfg)) |
1075 | goto try_again; | 1164 | goto try_again; |
1076 | 1165 | ||
1077 | /* Allocate ucode buffers for card's bus-master loading ... */ | 1166 | /* Allocate ucode buffers for card's bus-master loading ... */ |
@@ -1080,9 +1169,33 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1080 | * 1) unmodified from disk | 1169 | * 1) unmodified from disk |
1081 | * 2) backup cache for save/restore during power-downs */ | 1170 | * 2) backup cache for save/restore during power-downs */ |
1082 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) | 1171 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) |
1083 | if (iwl_alloc_ucode(drv, &pieces, i)) | 1172 | if (iwl_alloc_ucode(drv, pieces, i)) |
1084 | goto out_free_fw; | 1173 | goto out_free_fw; |
1085 | 1174 | ||
1175 | if (pieces->dbg_dest_tlv) { | ||
1176 | drv->fw.dbg_dest_tlv = | ||
1177 | kmemdup(pieces->dbg_dest_tlv, | ||
1178 | sizeof(*pieces->dbg_dest_tlv) + | ||
1179 | sizeof(pieces->dbg_dest_tlv->reg_ops[0]) * | ||
1180 | drv->fw.dbg_dest_reg_num, GFP_KERNEL); | ||
1181 | |||
1182 | if (!drv->fw.dbg_dest_tlv) | ||
1183 | goto out_free_fw; | ||
1184 | } | ||
1185 | |||
1186 | for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) { | ||
1187 | if (pieces->dbg_conf_tlv[i]) { | ||
1188 | drv->fw.dbg_conf_tlv_len[i] = | ||
1189 | pieces->dbg_conf_tlv_len[i]; | ||
1190 | drv->fw.dbg_conf_tlv[i] = | ||
1191 | kmemdup(pieces->dbg_conf_tlv[i], | ||
1192 | drv->fw.dbg_conf_tlv_len[i], | ||
1193 | GFP_KERNEL); | ||
1194 | if (!drv->fw.dbg_conf_tlv[i]) | ||
1195 | goto out_free_fw; | ||
1196 | } | ||
1197 | } | ||
1198 | |||
1086 | /* Now that we can no longer fail, copy information */ | 1199 | /* Now that we can no longer fail, copy information */ |
1087 | 1200 | ||
1088 | /* | 1201 | /* |
@@ -1090,20 +1203,20 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1090 | * for each event, which is of mode 1 (including timestamp) for all | 1203 | * for each event, which is of mode 1 (including timestamp) for all |
1091 | * new microcodes that include this information. | 1204 | * new microcodes that include this information. |
1092 | */ | 1205 | */ |
1093 | fw->init_evtlog_ptr = pieces.init_evtlog_ptr; | 1206 | fw->init_evtlog_ptr = pieces->init_evtlog_ptr; |
1094 | if (pieces.init_evtlog_size) | 1207 | if (pieces->init_evtlog_size) |
1095 | fw->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; | 1208 | fw->init_evtlog_size = (pieces->init_evtlog_size - 16)/12; |
1096 | else | 1209 | else |
1097 | fw->init_evtlog_size = | 1210 | fw->init_evtlog_size = |
1098 | drv->cfg->base_params->max_event_log_size; | 1211 | drv->cfg->base_params->max_event_log_size; |
1099 | fw->init_errlog_ptr = pieces.init_errlog_ptr; | 1212 | fw->init_errlog_ptr = pieces->init_errlog_ptr; |
1100 | fw->inst_evtlog_ptr = pieces.inst_evtlog_ptr; | 1213 | fw->inst_evtlog_ptr = pieces->inst_evtlog_ptr; |
1101 | if (pieces.inst_evtlog_size) | 1214 | if (pieces->inst_evtlog_size) |
1102 | fw->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; | 1215 | fw->inst_evtlog_size = (pieces->inst_evtlog_size - 16)/12; |
1103 | else | 1216 | else |
1104 | fw->inst_evtlog_size = | 1217 | fw->inst_evtlog_size = |
1105 | drv->cfg->base_params->max_event_log_size; | 1218 | drv->cfg->base_params->max_event_log_size; |
1106 | fw->inst_errlog_ptr = pieces.inst_errlog_ptr; | 1219 | fw->inst_errlog_ptr = pieces->inst_errlog_ptr; |
1107 | 1220 | ||
1108 | /* | 1221 | /* |
1109 | * figure out the offset of chain noise reset and gain commands | 1222 | * figure out the offset of chain noise reset and gain commands |
@@ -1162,10 +1275,55 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1162 | op->name, err); | 1275 | op->name, err); |
1163 | #endif | 1276 | #endif |
1164 | } | 1277 | } |
1278 | |||
1279 | /* | ||
1280 | * We may have loaded the wrong FW file in 8000 HW family if it is an | ||
1281 | * A-step card, and if drv->trans->hw_rev wasn't properly read when | ||
1282 | * the FW file had been loaded. (This might happen in SDIO.) In such a | ||
1283 | * case - unload and reload the correct file. | ||
1284 | * | ||
1285 | * TODO: | ||
1286 | * Once there is only one supported step for 8000 family - delete this! | ||
1287 | */ | ||
1288 | if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && | ||
1289 | CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP && | ||
1290 | drv->trans->hw_rev != hw_rev) { | ||
1291 | char firmware_name[32]; | ||
1292 | |||
1293 | /* Free previous FW resources */ | ||
1294 | if (drv->op_mode) | ||
1295 | _iwl_op_mode_stop(drv); | ||
1296 | iwl_dealloc_ucode(drv); | ||
1297 | |||
1298 | /* Build name of correct-step FW */ | ||
1299 | snprintf(firmware_name, sizeof(firmware_name), | ||
1300 | strrchr(drv->firmware_name, '-')); | ||
1301 | snprintf(drv->firmware_name, sizeof(drv->firmware_name), | ||
1302 | "%s%s", drv->cfg->fw_name_pre, firmware_name); | ||
1303 | |||
1304 | /* Clear data before loading correct FW */ | ||
1305 | list_del(&drv->list); | ||
1306 | |||
1307 | /* Request correct FW file this time */ | ||
1308 | IWL_DEBUG_INFO(drv, "attempting to load A-step FW %s\n", | ||
1309 | drv->firmware_name); | ||
1310 | err = request_firmware(&ucode_raw, drv->firmware_name, | ||
1311 | drv->trans->dev); | ||
1312 | if (err) { | ||
1313 | IWL_ERR(drv, "Failed swapping FW!\n"); | ||
1314 | goto out_unbind; | ||
1315 | } | ||
1316 | |||
1317 | /* Redo callback function - this time with right FW */ | ||
1318 | iwl_req_fw_callback(ucode_raw, context); | ||
1319 | } | ||
1320 | |||
1321 | kfree(pieces); | ||
1165 | return; | 1322 | return; |
1166 | 1323 | ||
1167 | try_again: | 1324 | try_again: |
1168 | /* try next, if any */ | 1325 | /* try next, if any */ |
1326 | kfree(pieces); | ||
1169 | release_firmware(ucode_raw); | 1327 | release_firmware(ucode_raw); |
1170 | if (iwl_request_firmware(drv, false)) | 1328 | if (iwl_request_firmware(drv, false)) |
1171 | goto out_unbind; | 1329 | goto out_unbind; |
@@ -1176,6 +1334,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1176 | iwl_dealloc_ucode(drv); | 1334 | iwl_dealloc_ucode(drv); |
1177 | release_firmware(ucode_raw); | 1335 | release_firmware(ucode_raw); |
1178 | out_unbind: | 1336 | out_unbind: |
1337 | kfree(pieces); | ||
1179 | complete(&drv->request_firmware_complete); | 1338 | complete(&drv->request_firmware_complete); |
1180 | device_release_driver(drv->trans->dev); | 1339 | device_release_driver(drv->trans->dev); |
1181 | } | 1340 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 74b796dc4242..41ff85de7334 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c | |||
@@ -764,7 +764,7 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, | |||
764 | if (iwlwifi_mod_params.amsdu_size_8K) | 764 | if (iwlwifi_mod_params.amsdu_size_8K) |
765 | ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; | 765 | ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; |
766 | 766 | ||
767 | ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; | 767 | ht_info->ampdu_factor = cfg->max_ht_ampdu_exponent; |
768 | ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; | 768 | ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; |
769 | 769 | ||
770 | ht_info->mcs.rx_mask[0] = 0xFF; | 770 | ht_info->mcs.rx_mask[0] = 0xFF; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index e30a41d04c8b..20a8a64c9fe3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | |||
@@ -81,6 +81,7 @@ | |||
81 | * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor | 81 | * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor |
82 | * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several | 82 | * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several |
83 | * sections like this in a single file. | 83 | * sections like this in a single file. |
84 | * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers | ||
84 | */ | 85 | */ |
85 | enum iwl_fw_error_dump_type { | 86 | enum iwl_fw_error_dump_type { |
86 | IWL_FW_ERROR_DUMP_SRAM = 0, | 87 | IWL_FW_ERROR_DUMP_SRAM = 0, |
@@ -90,6 +91,8 @@ enum iwl_fw_error_dump_type { | |||
90 | IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, | 91 | IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, |
91 | IWL_FW_ERROR_DUMP_FW_MONITOR = 5, | 92 | IWL_FW_ERROR_DUMP_FW_MONITOR = 5, |
92 | IWL_FW_ERROR_DUMP_PRPH = 6, | 93 | IWL_FW_ERROR_DUMP_PRPH = 6, |
94 | IWL_FW_ERROR_DUMP_TXF = 7, | ||
95 | IWL_FW_ERROR_DUMP_FH_REGS = 8, | ||
93 | 96 | ||
94 | IWL_FW_ERROR_DUMP_MAX, | 97 | IWL_FW_ERROR_DUMP_MAX, |
95 | }; | 98 | }; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 401f7be36b93..f2a047f6bb3e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h | |||
@@ -131,6 +131,9 @@ enum iwl_ucode_tlv_type { | |||
131 | IWL_UCODE_TLV_API_CHANGES_SET = 29, | 131 | IWL_UCODE_TLV_API_CHANGES_SET = 29, |
132 | IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, | 132 | IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, |
133 | IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, | 133 | IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, |
134 | IWL_UCODE_TLV_SEC_RT_USNIFFER = 34, | ||
135 | IWL_UCODE_TLV_FW_DBG_DEST = 38, | ||
136 | IWL_UCODE_TLV_FW_DBG_CONF = 39, | ||
134 | }; | 137 | }; |
135 | 138 | ||
136 | struct iwl_ucode_tlv { | 139 | struct iwl_ucode_tlv { |
@@ -179,4 +182,309 @@ struct iwl_ucode_capa { | |||
179 | __le32 api_capa; | 182 | __le32 api_capa; |
180 | } __packed; | 183 | } __packed; |
181 | 184 | ||
185 | /** | ||
186 | * enum iwl_ucode_tlv_flag - ucode API flags | ||
187 | * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously | ||
188 | * was a separate TLV but moved here to save space. | ||
189 | * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, | ||
190 | * treats good CRC threshold as a boolean | ||
191 | * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). | ||
192 | * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. | ||
193 | * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS | ||
194 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: This uCode image supports uAPSD | ||
195 | * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan | ||
196 | * offload profile config command. | ||
197 | * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six | ||
198 | * (rather than two) IPv6 addresses | ||
199 | * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element | ||
200 | * from the probe request template. | ||
201 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) | ||
202 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) | ||
203 | * @IWL_UCODE_TLV_FLAGS_P2P_PM: P2P client supports PM as a stand alone MAC | ||
204 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and | ||
205 | * P2P client interfaces simultaneously if they are in different bindings. | ||
206 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_SCM: support power save on BSS station and | ||
207 | * P2P client interfaces simultaneously if they are in same bindings. | ||
208 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD | ||
209 | * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save | ||
210 | * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. | ||
211 | * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients | ||
212 | * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. | ||
213 | */ | ||
214 | enum iwl_ucode_tlv_flag { | ||
215 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), | ||
216 | IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), | ||
217 | IWL_UCODE_TLV_FLAGS_MFP = BIT(2), | ||
218 | IWL_UCODE_TLV_FLAGS_P2P = BIT(3), | ||
219 | IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), | ||
220 | IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7), | ||
221 | IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), | ||
222 | IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), | ||
223 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15), | ||
224 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16), | ||
225 | IWL_UCODE_TLV_FLAGS_P2P_PM = BIT(21), | ||
226 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22), | ||
227 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM = BIT(23), | ||
228 | IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), | ||
229 | IWL_UCODE_TLV_FLAGS_EBS_SUPPORT = BIT(25), | ||
230 | IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), | ||
231 | IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), | ||
232 | IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), | ||
233 | }; | ||
234 | |||
235 | /** | ||
236 | * enum iwl_ucode_tlv_api - ucode api | ||
237 | * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. | ||
238 | * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification | ||
239 | * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex | ||
240 | * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. | ||
241 | * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. | ||
242 | * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. | ||
243 | * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. | ||
244 | * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time | ||
245 | * longer than the passive one, which is essential for fragmented scan. | ||
246 | */ | ||
247 | enum iwl_ucode_tlv_api { | ||
248 | IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), | ||
249 | IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1), | ||
250 | IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), | ||
251 | IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), | ||
252 | IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), | ||
253 | IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), | ||
254 | IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), | ||
255 | IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), | ||
256 | }; | ||
257 | |||
258 | /** | ||
259 | * enum iwl_ucode_tlv_capa - ucode capabilities | ||
260 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 | ||
261 | * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory | ||
262 | * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. | ||
263 | * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality | ||
264 | * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current | ||
265 | * tx power value into TPC Report action frame and Link Measurement Report | ||
266 | * action frame | ||
267 | * @IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports updating current | ||
268 | * channel in DS parameter set element in probe requests. | ||
269 | * @IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in | ||
270 | * probe requests. | ||
271 | * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests | ||
272 | * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), | ||
273 | * which also implies support for the scheduler configuration command | ||
274 | * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching | ||
275 | * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command | ||
276 | */ | ||
277 | enum iwl_ucode_tlv_capa { | ||
278 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), | ||
279 | IWL_UCODE_TLV_CAPA_LAR_SUPPORT = BIT(1), | ||
280 | IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2), | ||
281 | IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = BIT(6), | ||
282 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8), | ||
283 | IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), | ||
284 | IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10), | ||
285 | IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11), | ||
286 | IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12), | ||
287 | IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = BIT(13), | ||
288 | IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18), | ||
289 | }; | ||
290 | |||
291 | /* The default calibrate table size if not specified by firmware file */ | ||
292 | #define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 | ||
293 | #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 | ||
294 | #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 | ||
295 | |||
296 | /* The default max probe length if not specified by the firmware file */ | ||
297 | #define IWL_DEFAULT_MAX_PROBE_LENGTH 200 | ||
298 | |||
299 | /* | ||
300 | * For 16.0 uCode and above, there is no differentiation between sections, | ||
301 | * just an offset to the HW address. | ||
302 | */ | ||
303 | #define IWL_UCODE_SECTION_MAX 12 | ||
304 | #define IWL_API_ARRAY_SIZE 1 | ||
305 | #define IWL_CAPABILITIES_ARRAY_SIZE 1 | ||
306 | #define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC | ||
307 | |||
308 | /* uCode version contains 4 values: Major/Minor/API/Serial */ | ||
309 | #define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) | ||
310 | #define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) | ||
311 | #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) | ||
312 | #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) | ||
313 | |||
314 | /* | ||
315 | * Calibration control struct. | ||
316 | * Sent as part of the phy configuration command. | ||
317 | * @flow_trigger: bitmap for which calibrations to perform according to | ||
318 | * flow triggers. | ||
319 | * @event_trigger: bitmap for which calibrations to perform according to | ||
320 | * event triggers. | ||
321 | */ | ||
322 | struct iwl_tlv_calib_ctrl { | ||
323 | __le32 flow_trigger; | ||
324 | __le32 event_trigger; | ||
325 | } __packed; | ||
326 | |||
327 | enum iwl_fw_phy_cfg { | ||
328 | FW_PHY_CFG_RADIO_TYPE_POS = 0, | ||
329 | FW_PHY_CFG_RADIO_TYPE = 0x3 << FW_PHY_CFG_RADIO_TYPE_POS, | ||
330 | FW_PHY_CFG_RADIO_STEP_POS = 2, | ||
331 | FW_PHY_CFG_RADIO_STEP = 0x3 << FW_PHY_CFG_RADIO_STEP_POS, | ||
332 | FW_PHY_CFG_RADIO_DASH_POS = 4, | ||
333 | FW_PHY_CFG_RADIO_DASH = 0x3 << FW_PHY_CFG_RADIO_DASH_POS, | ||
334 | FW_PHY_CFG_TX_CHAIN_POS = 16, | ||
335 | FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS, | ||
336 | FW_PHY_CFG_RX_CHAIN_POS = 20, | ||
337 | FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, | ||
338 | }; | ||
339 | |||
340 | #define IWL_UCODE_MAX_CS 1 | ||
341 | |||
342 | /** | ||
343 | * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW. | ||
344 | * @cipher: a cipher suite selector | ||
345 | * @flags: cipher scheme flags (currently reserved for a future use) | ||
346 | * @hdr_len: a size of MPDU security header | ||
347 | * @pn_len: a size of PN | ||
348 | * @pn_off: an offset of pn from the beginning of the security header | ||
349 | * @key_idx_off: an offset of key index byte in the security header | ||
350 | * @key_idx_mask: a bit mask of key_idx bits | ||
351 | * @key_idx_shift: bit shift needed to get key_idx | ||
352 | * @mic_len: mic length in bytes | ||
353 | * @hw_cipher: a HW cipher index used in host commands | ||
354 | */ | ||
355 | struct iwl_fw_cipher_scheme { | ||
356 | __le32 cipher; | ||
357 | u8 flags; | ||
358 | u8 hdr_len; | ||
359 | u8 pn_len; | ||
360 | u8 pn_off; | ||
361 | u8 key_idx_off; | ||
362 | u8 key_idx_mask; | ||
363 | u8 key_idx_shift; | ||
364 | u8 mic_len; | ||
365 | u8 hw_cipher; | ||
366 | } __packed; | ||
367 | |||
368 | enum iwl_fw_dbg_reg_operator { | ||
369 | CSR_ASSIGN, | ||
370 | CSR_SETBIT, | ||
371 | CSR_CLEARBIT, | ||
372 | |||
373 | PRPH_ASSIGN, | ||
374 | PRPH_SETBIT, | ||
375 | PRPH_CLEARBIT, | ||
376 | }; | ||
377 | |||
378 | /** | ||
379 | * struct iwl_fw_dbg_reg_op - an operation on a register | ||
380 | * | ||
381 | * @op: %enum iwl_fw_dbg_reg_operator | ||
382 | * @addr: offset of the register | ||
383 | * @val: value | ||
384 | */ | ||
385 | struct iwl_fw_dbg_reg_op { | ||
386 | u8 op; | ||
387 | u8 reserved[3]; | ||
388 | __le32 addr; | ||
389 | __le32 val; | ||
390 | } __packed; | ||
391 | |||
392 | /** | ||
393 | * enum iwl_fw_dbg_monitor_mode - available monitor recording modes | ||
394 | * | ||
395 | * @SMEM_MODE: monitor stores the data in SMEM | ||
396 | * @EXTERNAL_MODE: monitor stores the data in allocated DRAM | ||
397 | * @MARBH_MODE: monitor stores the data in MARBH buffer | ||
398 | */ | ||
399 | enum iwl_fw_dbg_monitor_mode { | ||
400 | SMEM_MODE = 0, | ||
401 | EXTERNAL_MODE = 1, | ||
402 | MARBH_MODE = 2, | ||
403 | }; | ||
404 | |||
405 | /** | ||
406 | * struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data | ||
407 | * | ||
408 | * @version: version of the TLV - currently 0 | ||
409 | * @monitor_mode: %enum iwl_fw_dbg_monitor_mode | ||
410 | * @base_reg: addr of the base addr register (PRPH) | ||
411 | * @end_reg: addr of the end addr register (PRPH) | ||
412 | * @write_ptr_reg: the addr of the reg of the write pointer | ||
413 | * @wrap_count: the addr of the reg of the wrap_count | ||
414 | * @base_shift: shift right of the base addr reg | ||
415 | * @end_shift: shift right of the end addr reg | ||
416 | * @reg_ops: array of registers operations | ||
417 | * | ||
418 | * This parses IWL_UCODE_TLV_FW_DBG_DEST | ||
419 | */ | ||
420 | struct iwl_fw_dbg_dest_tlv { | ||
421 | u8 version; | ||
422 | u8 monitor_mode; | ||
423 | u8 reserved[2]; | ||
424 | __le32 base_reg; | ||
425 | __le32 end_reg; | ||
426 | __le32 write_ptr_reg; | ||
427 | __le32 wrap_count; | ||
428 | u8 base_shift; | ||
429 | u8 end_shift; | ||
430 | struct iwl_fw_dbg_reg_op reg_ops[0]; | ||
431 | } __packed; | ||
432 | |||
433 | struct iwl_fw_dbg_conf_hcmd { | ||
434 | u8 id; | ||
435 | u8 reserved; | ||
436 | __le16 len; | ||
437 | u8 data[0]; | ||
438 | } __packed; | ||
439 | |||
440 | /** | ||
441 | * struct iwl_fw_dbg_trigger - a TLV that describes a debug configuration | ||
442 | * | ||
443 | * @enabled: is this trigger enabled | ||
444 | * @reserved: | ||
445 | * @len: length, in bytes, of the %trigger field | ||
446 | * @trigger: pointer to a trigger struct | ||
447 | */ | ||
448 | struct iwl_fw_dbg_trigger { | ||
449 | u8 enabled; | ||
450 | u8 reserved; | ||
451 | u8 len; | ||
452 | u8 trigger[0]; | ||
453 | } __packed; | ||
454 | |||
455 | /** | ||
456 | * enum iwl_fw_dbg_conf - configurations available | ||
457 | * | ||
458 | * @FW_DBG_CUSTOM: take this configuration from alive | ||
459 | * Note that the trigger is NO-OP for this configuration | ||
460 | */ | ||
461 | enum iwl_fw_dbg_conf { | ||
462 | FW_DBG_CUSTOM = 0, | ||
463 | |||
464 | /* must be last */ | ||
465 | FW_DBG_MAX, | ||
466 | FW_DBG_INVALID = 0xff, | ||
467 | }; | ||
468 | |||
469 | /** | ||
470 | * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration | ||
471 | * | ||
472 | * @id: %enum iwl_fw_dbg_conf | ||
473 | * @usniffer: should the uSniffer image be used | ||
474 | * @num_of_hcmds: how many HCMDs to send are present here | ||
475 | * @hcmd: a variable length host command to be sent to apply the configuration. | ||
476 | * If there is more than one HCMD to send, they will appear one after the | ||
477 | * other and be sent in the order that they appear in. | ||
478 | * This parses IWL_UCODE_TLV_FW_DBG_CONF | ||
479 | */ | ||
480 | struct iwl_fw_dbg_conf_tlv { | ||
481 | u8 id; | ||
482 | u8 usniffer; | ||
483 | u8 reserved; | ||
484 | u8 num_of_hcmds; | ||
485 | struct iwl_fw_dbg_conf_hcmd hcmd; | ||
486 | |||
487 | /* struct iwl_fw_dbg_trigger sits after all variable length hcmds */ | ||
488 | } __packed; | ||
489 | |||
182 | #endif /* __iwl_fw_file_h__ */ | 490 | #endif /* __iwl_fw_file_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 6f7ae5f7bdae..e6dc3b870949 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -70,110 +70,6 @@ | |||
70 | #include "iwl-fw-file.h" | 70 | #include "iwl-fw-file.h" |
71 | 71 | ||
72 | /** | 72 | /** |
73 | * enum iwl_ucode_tlv_flag - ucode API flags | ||
74 | * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously | ||
75 | * was a separate TLV but moved here to save space. | ||
76 | * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, | ||
77 | * treats good CRC threshold as a boolean | ||
78 | * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). | ||
79 | * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. | ||
80 | * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS | ||
81 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: This uCode image supports uAPSD | ||
82 | * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan | ||
83 | * offload profile config command. | ||
84 | * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six | ||
85 | * (rather than two) IPv6 addresses | ||
86 | * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element | ||
87 | * from the probe request template. | ||
88 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) | ||
89 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) | ||
90 | * @IWL_UCODE_TLV_FLAGS_P2P_PM: P2P client supports PM as a stand alone MAC | ||
91 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and | ||
92 | * P2P client interfaces simultaneously if they are in different bindings. | ||
93 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_SCM: support power save on BSS station and | ||
94 | * P2P client interfaces simultaneously if they are in same bindings. | ||
95 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD | ||
96 | * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save | ||
97 | * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. | ||
98 | * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients | ||
99 | * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. | ||
100 | */ | ||
101 | enum iwl_ucode_tlv_flag { | ||
102 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), | ||
103 | IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), | ||
104 | IWL_UCODE_TLV_FLAGS_MFP = BIT(2), | ||
105 | IWL_UCODE_TLV_FLAGS_P2P = BIT(3), | ||
106 | IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), | ||
107 | IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7), | ||
108 | IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), | ||
109 | IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), | ||
110 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15), | ||
111 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16), | ||
112 | IWL_UCODE_TLV_FLAGS_P2P_PM = BIT(21), | ||
113 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22), | ||
114 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM = BIT(23), | ||
115 | IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), | ||
116 | IWL_UCODE_TLV_FLAGS_EBS_SUPPORT = BIT(25), | ||
117 | IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), | ||
118 | IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), | ||
119 | IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), | ||
120 | }; | ||
121 | |||
122 | /** | ||
123 | * enum iwl_ucode_tlv_api - ucode api | ||
124 | * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. | ||
125 | * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification | ||
126 | * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex | ||
127 | * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. | ||
128 | * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. | ||
129 | * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. | ||
130 | * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. | ||
131 | * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time | ||
132 | * longer than the passive one, which is essential for fragmented scan. | ||
133 | */ | ||
134 | enum iwl_ucode_tlv_api { | ||
135 | IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), | ||
136 | IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1), | ||
137 | IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), | ||
138 | IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), | ||
139 | IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), | ||
140 | IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), | ||
141 | IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), | ||
142 | IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), | ||
143 | }; | ||
144 | |||
145 | /** | ||
146 | * enum iwl_ucode_tlv_capa - ucode capabilities | ||
147 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 | ||
148 | * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current | ||
149 | * tx power value into TPC Report action frame and Link Measurement Report | ||
150 | * action frame | ||
151 | * @IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports adding DS params | ||
152 | * element in probe requests. | ||
153 | * @IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in | ||
154 | * probe requests. | ||
155 | * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests | ||
156 | * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), | ||
157 | * which also implies support for the scheduler configuration command | ||
158 | */ | ||
159 | enum iwl_ucode_tlv_capa { | ||
160 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), | ||
161 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8), | ||
162 | IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), | ||
163 | IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10), | ||
164 | IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11), | ||
165 | IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12), | ||
166 | }; | ||
167 | |||
168 | /* The default calibrate table size if not specified by firmware file */ | ||
169 | #define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 | ||
170 | #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 | ||
171 | #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 | ||
172 | |||
173 | /* The default max probe length if not specified by the firmware file */ | ||
174 | #define IWL_DEFAULT_MAX_PROBE_LENGTH 200 | ||
175 | |||
176 | /** | ||
177 | * enum iwl_ucode_type | 73 | * enum iwl_ucode_type |
178 | * | 74 | * |
179 | * The type of ucode. | 75 | * The type of ucode. |
@@ -181,11 +77,13 @@ enum iwl_ucode_tlv_capa { | |||
181 | * @IWL_UCODE_REGULAR: Normal runtime ucode | 77 | * @IWL_UCODE_REGULAR: Normal runtime ucode |
182 | * @IWL_UCODE_INIT: Initial ucode | 78 | * @IWL_UCODE_INIT: Initial ucode |
183 | * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode | 79 | * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode |
80 | * @IWL_UCODE_REGULAR_USNIFFER: Normal runtime ucode when using usniffer image | ||
184 | */ | 81 | */ |
185 | enum iwl_ucode_type { | 82 | enum iwl_ucode_type { |
186 | IWL_UCODE_REGULAR, | 83 | IWL_UCODE_REGULAR, |
187 | IWL_UCODE_INIT, | 84 | IWL_UCODE_INIT, |
188 | IWL_UCODE_WOWLAN, | 85 | IWL_UCODE_WOWLAN, |
86 | IWL_UCODE_REGULAR_USNIFFER, | ||
189 | IWL_UCODE_TYPE_MAX, | 87 | IWL_UCODE_TYPE_MAX, |
190 | }; | 88 | }; |
191 | 89 | ||
@@ -200,14 +98,6 @@ enum iwl_ucode_sec { | |||
200 | IWL_UCODE_SECTION_DATA, | 98 | IWL_UCODE_SECTION_DATA, |
201 | IWL_UCODE_SECTION_INST, | 99 | IWL_UCODE_SECTION_INST, |
202 | }; | 100 | }; |
203 | /* | ||
204 | * For 16.0 uCode and above, there is no differentiation between sections, | ||
205 | * just an offset to the HW address. | ||
206 | */ | ||
207 | #define IWL_UCODE_SECTION_MAX 12 | ||
208 | #define IWL_API_ARRAY_SIZE 1 | ||
209 | #define IWL_CAPABILITIES_ARRAY_SIZE 1 | ||
210 | #define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC | ||
211 | 101 | ||
212 | struct iwl_ucode_capabilities { | 102 | struct iwl_ucode_capabilities { |
213 | u32 max_probe_length; | 103 | u32 max_probe_length; |
@@ -235,66 +125,6 @@ struct iwl_sf_region { | |||
235 | u32 size; | 125 | u32 size; |
236 | }; | 126 | }; |
237 | 127 | ||
238 | /* uCode version contains 4 values: Major/Minor/API/Serial */ | ||
239 | #define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) | ||
240 | #define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) | ||
241 | #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) | ||
242 | #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) | ||
243 | |||
244 | /* | ||
245 | * Calibration control struct. | ||
246 | * Sent as part of the phy configuration command. | ||
247 | * @flow_trigger: bitmap for which calibrations to perform according to | ||
248 | * flow triggers. | ||
249 | * @event_trigger: bitmap for which calibrations to perform according to | ||
250 | * event triggers. | ||
251 | */ | ||
252 | struct iwl_tlv_calib_ctrl { | ||
253 | __le32 flow_trigger; | ||
254 | __le32 event_trigger; | ||
255 | } __packed; | ||
256 | |||
257 | enum iwl_fw_phy_cfg { | ||
258 | FW_PHY_CFG_RADIO_TYPE_POS = 0, | ||
259 | FW_PHY_CFG_RADIO_TYPE = 0x3 << FW_PHY_CFG_RADIO_TYPE_POS, | ||
260 | FW_PHY_CFG_RADIO_STEP_POS = 2, | ||
261 | FW_PHY_CFG_RADIO_STEP = 0x3 << FW_PHY_CFG_RADIO_STEP_POS, | ||
262 | FW_PHY_CFG_RADIO_DASH_POS = 4, | ||
263 | FW_PHY_CFG_RADIO_DASH = 0x3 << FW_PHY_CFG_RADIO_DASH_POS, | ||
264 | FW_PHY_CFG_TX_CHAIN_POS = 16, | ||
265 | FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS, | ||
266 | FW_PHY_CFG_RX_CHAIN_POS = 20, | ||
267 | FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, | ||
268 | }; | ||
269 | |||
270 | #define IWL_UCODE_MAX_CS 1 | ||
271 | |||
272 | /** | ||
273 | * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW. | ||
274 | * @cipher: a cipher suite selector | ||
275 | * @flags: cipher scheme flags (currently reserved for a future use) | ||
276 | * @hdr_len: a size of MPDU security header | ||
277 | * @pn_len: a size of PN | ||
278 | * @pn_off: an offset of pn from the beginning of the security header | ||
279 | * @key_idx_off: an offset of key index byte in the security header | ||
280 | * @key_idx_mask: a bit mask of key_idx bits | ||
281 | * @key_idx_shift: bit shift needed to get key_idx | ||
282 | * @mic_len: mic length in bytes | ||
283 | * @hw_cipher: a HW cipher index used in host commands | ||
284 | */ | ||
285 | struct iwl_fw_cipher_scheme { | ||
286 | __le32 cipher; | ||
287 | u8 flags; | ||
288 | u8 hdr_len; | ||
289 | u8 pn_len; | ||
290 | u8 pn_off; | ||
291 | u8 key_idx_off; | ||
292 | u8 key_idx_mask; | ||
293 | u8 key_idx_shift; | ||
294 | u8 mic_len; | ||
295 | u8 hw_cipher; | ||
296 | } __packed; | ||
297 | |||
298 | /** | 128 | /** |
299 | * struct iwl_fw_cscheme_list - a cipher scheme list | 129 | * struct iwl_fw_cscheme_list - a cipher scheme list |
300 | * @size: a number of entries | 130 | * @size: a number of entries |
@@ -321,6 +151,11 @@ struct iwl_fw_cscheme_list { | |||
321 | * @inst_errlog_ptr: error log offfset for runtime ucode. | 151 | * @inst_errlog_ptr: error log offfset for runtime ucode. |
322 | * @mvm_fw: indicates this is MVM firmware | 152 | * @mvm_fw: indicates this is MVM firmware |
323 | * @cipher_scheme: optional external cipher scheme. | 153 | * @cipher_scheme: optional external cipher scheme. |
154 | * @human_readable: human readable version | ||
155 | * @dbg_dest_tlv: points to the destination TLV for debug | ||
156 | * @dbg_conf_tlv: array of pointers to configuration TLVs for debug | ||
157 | * @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries | ||
158 | * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv | ||
324 | */ | 159 | */ |
325 | struct iwl_fw { | 160 | struct iwl_fw { |
326 | u32 ucode_ver; | 161 | u32 ucode_ver; |
@@ -345,6 +180,68 @@ struct iwl_fw { | |||
345 | 180 | ||
346 | struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; | 181 | struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; |
347 | u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; | 182 | u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; |
183 | |||
184 | struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; | ||
185 | struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; | ||
186 | size_t dbg_conf_tlv_len[FW_DBG_MAX]; | ||
187 | |||
188 | u8 dbg_dest_reg_num; | ||
348 | }; | 189 | }; |
349 | 190 | ||
191 | static inline const char *get_fw_dbg_mode_string(int mode) | ||
192 | { | ||
193 | switch (mode) { | ||
194 | case SMEM_MODE: | ||
195 | return "SMEM"; | ||
196 | case EXTERNAL_MODE: | ||
197 | return "EXTERNAL_DRAM"; | ||
198 | case MARBH_MODE: | ||
199 | return "MARBH"; | ||
200 | default: | ||
201 | return "UNKNOWN"; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | static inline const struct iwl_fw_dbg_trigger * | ||
206 | iwl_fw_dbg_conf_get_trigger(const struct iwl_fw *fw, u8 id) | ||
207 | { | ||
208 | const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id]; | ||
209 | u8 *ptr; | ||
210 | int i; | ||
211 | |||
212 | if (!conf_tlv) | ||
213 | return NULL; | ||
214 | |||
215 | ptr = (void *)&conf_tlv->hcmd; | ||
216 | for (i = 0; i < conf_tlv->num_of_hcmds; i++) { | ||
217 | ptr += sizeof(conf_tlv->hcmd); | ||
218 | ptr += le16_to_cpu(conf_tlv->hcmd.len); | ||
219 | } | ||
220 | |||
221 | return (const struct iwl_fw_dbg_trigger *)ptr; | ||
222 | } | ||
223 | |||
224 | static inline bool | ||
225 | iwl_fw_dbg_conf_enabled(const struct iwl_fw *fw, u8 id) | ||
226 | { | ||
227 | const struct iwl_fw_dbg_trigger *trigger = | ||
228 | iwl_fw_dbg_conf_get_trigger(fw, id); | ||
229 | |||
230 | if (!trigger) | ||
231 | return false; | ||
232 | |||
233 | return trigger->enabled; | ||
234 | } | ||
235 | |||
236 | static inline bool | ||
237 | iwl_fw_dbg_conf_usniffer(const struct iwl_fw *fw, u8 id) | ||
238 | { | ||
239 | const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id]; | ||
240 | |||
241 | if (!conf_tlv) | ||
242 | return false; | ||
243 | |||
244 | return conf_tlv->usniffer; | ||
245 | } | ||
246 | |||
350 | #endif /* __iwl_fw_h__ */ | 247 | #endif /* __iwl_fw_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index c302e7468559..06e02fcd6f7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | |||
@@ -325,6 +325,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
325 | { | 325 | { |
326 | int num_rx_ants = num_of_ant(rx_chains); | 326 | int num_rx_ants = num_of_ant(rx_chains); |
327 | int num_tx_ants = num_of_ant(tx_chains); | 327 | int num_tx_ants = num_of_ant(tx_chains); |
328 | unsigned int max_ampdu_exponent = (cfg->max_vht_ampdu_exponent ?: | ||
329 | IEEE80211_VHT_MAX_AMPDU_1024K); | ||
328 | 330 | ||
329 | vht_cap->vht_supported = true; | 331 | vht_cap->vht_supported = true; |
330 | 332 | ||
@@ -332,7 +334,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
332 | IEEE80211_VHT_CAP_RXSTBC_1 | | 334 | IEEE80211_VHT_CAP_RXSTBC_1 | |
333 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | | 335 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | |
334 | 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | | 336 | 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | |
335 | 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | 337 | max_ampdu_exponent << |
338 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
336 | 339 | ||
337 | if (cfg->ht_params->ldpc) | 340 | if (cfg->ht_params->ldpc) |
338 | vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; | 341 | vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index b6d666ee8359..17de6d46222a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h | |||
@@ -138,7 +138,8 @@ struct iwl_cfg; | |||
138 | * @nic_config: configure NIC, called before firmware is started. | 138 | * @nic_config: configure NIC, called before firmware is started. |
139 | * May sleep | 139 | * May sleep |
140 | * @wimax_active: invoked when WiMax becomes active. May sleep | 140 | * @wimax_active: invoked when WiMax becomes active. May sleep |
141 | * @enter_d0i3: configure the fw to enter d0i3. May sleep. | 141 | * @enter_d0i3: configure the fw to enter d0i3. return 1 to indicate d0i3 |
142 | * entrance is aborted (e.g. due to held reference). May sleep. | ||
142 | * @exit_d0i3: configure the fw to exit d0i3. May sleep. | 143 | * @exit_d0i3: configure the fw to exit d0i3. May sleep. |
143 | */ | 144 | */ |
144 | struct iwl_op_mode_ops { | 145 | struct iwl_op_mode_ops { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 1560f4576c7d..2df51eab1348 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
@@ -322,6 +322,7 @@ enum secure_boot_config_reg { | |||
322 | LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, | 322 | LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, |
323 | }; | 323 | }; |
324 | 324 | ||
325 | #define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0 (0xA01E30) | ||
325 | #define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR (0x1E30) | 326 | #define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR (0x1E30) |
326 | #define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR (0x1E34) | 327 | #define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR (0x1E34) |
327 | enum secure_boot_status_reg { | 328 | enum secure_boot_status_reg { |
@@ -333,6 +334,7 @@ enum secure_boot_status_reg { | |||
333 | LMPM_SECURE_BOOT_STATUS_SUCCESS = 0x00000003, | 334 | LMPM_SECURE_BOOT_STATUS_SUCCESS = 0x00000003, |
334 | }; | 335 | }; |
335 | 336 | ||
337 | #define FH_UCODE_LOAD_STATUS (0x1AF0) | ||
336 | #define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70) | 338 | #define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70) |
337 | enum secure_load_status_reg { | 339 | enum secure_load_status_reg { |
338 | LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001, | 340 | LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001, |
@@ -352,7 +354,7 @@ enum secure_load_status_reg { | |||
352 | #define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000) | 354 | #define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000) |
353 | #define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400) | 355 | #define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400) |
354 | 356 | ||
355 | #define LMPM_SECURE_TIME_OUT (100) | 357 | #define LMPM_SECURE_TIME_OUT (100) /* 10 micro */ |
356 | 358 | ||
357 | /* Rx FIFO */ | 359 | /* Rx FIFO */ |
358 | #define RXF_SIZE_ADDR (0xa00c88) | 360 | #define RXF_SIZE_ADDR (0xa00c88) |
@@ -368,4 +370,10 @@ enum secure_load_status_reg { | |||
368 | #define MON_BUFF_WRPTR (0xa03c44) | 370 | #define MON_BUFF_WRPTR (0xa03c44) |
369 | #define MON_BUFF_CYCLE_CNT (0xa03c48) | 371 | #define MON_BUFF_CYCLE_CNT (0xa03c48) |
370 | 372 | ||
373 | /* FW chicken bits */ | ||
374 | #define LMPM_CHICK 0xA01FF8 | ||
375 | enum { | ||
376 | LMPM_CHICK_EXTENDED_ADDR_SPACE = BIT(0), | ||
377 | }; | ||
378 | |||
371 | #endif /* __iwl_prph_h__ */ | 379 | #endif /* __iwl_prph_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 0768f83e709d..028408a6ecba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -534,6 +534,8 @@ struct iwl_trans_ops { | |||
534 | u32 value); | 534 | u32 value); |
535 | void (*ref)(struct iwl_trans *trans); | 535 | void (*ref)(struct iwl_trans *trans); |
536 | void (*unref)(struct iwl_trans *trans); | 536 | void (*unref)(struct iwl_trans *trans); |
537 | void (*suspend)(struct iwl_trans *trans); | ||
538 | void (*resume)(struct iwl_trans *trans); | ||
537 | 539 | ||
538 | struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); | 540 | struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); |
539 | }; | 541 | }; |
@@ -572,6 +574,9 @@ enum iwl_trans_state { | |||
572 | * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the | 574 | * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the |
573 | * start of the 802.11 header in the @rx_mpdu_cmd | 575 | * start of the 802.11 header in the @rx_mpdu_cmd |
574 | * @dflt_pwr_limit: default power limit fetched from the platform (ACPI) | 576 | * @dflt_pwr_limit: default power limit fetched from the platform (ACPI) |
577 | * @dbg_dest_tlv: points to the destination TLV for debug | ||
578 | * @dbg_conf_tlv: array of pointers to configuration TLVs for debug | ||
579 | * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv | ||
575 | */ | 580 | */ |
576 | struct iwl_trans { | 581 | struct iwl_trans { |
577 | const struct iwl_trans_ops *ops; | 582 | const struct iwl_trans_ops *ops; |
@@ -603,6 +608,10 @@ struct iwl_trans { | |||
603 | 608 | ||
604 | u64 dflt_pwr_limit; | 609 | u64 dflt_pwr_limit; |
605 | 610 | ||
611 | const struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; | ||
612 | const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; | ||
613 | u8 dbg_dest_reg_num; | ||
614 | |||
606 | /* pointer to trans specific struct */ | 615 | /* pointer to trans specific struct */ |
607 | /*Ensure that this pointer will always be aligned to sizeof pointer */ | 616 | /*Ensure that this pointer will always be aligned to sizeof pointer */ |
608 | char trans_specific[0] __aligned(sizeof(void *)); | 617 | char trans_specific[0] __aligned(sizeof(void *)); |
@@ -702,6 +711,18 @@ static inline void iwl_trans_unref(struct iwl_trans *trans) | |||
702 | trans->ops->unref(trans); | 711 | trans->ops->unref(trans); |
703 | } | 712 | } |
704 | 713 | ||
714 | static inline void iwl_trans_suspend(struct iwl_trans *trans) | ||
715 | { | ||
716 | if (trans->ops->suspend) | ||
717 | trans->ops->suspend(trans); | ||
718 | } | ||
719 | |||
720 | static inline void iwl_trans_resume(struct iwl_trans *trans) | ||
721 | { | ||
722 | if (trans->ops->resume) | ||
723 | trans->ops->resume(trans); | ||
724 | } | ||
725 | |||
705 | static inline struct iwl_trans_dump_data * | 726 | static inline struct iwl_trans_dump_data * |
706 | iwl_trans_dump_data(struct iwl_trans *trans) | 727 | iwl_trans_dump_data(struct iwl_trans *trans) |
707 | { | 728 | { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 508c81359e41..a3bfda45d9e6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c | |||
@@ -1137,6 +1137,22 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | |||
1137 | return lut_type != BT_COEX_LOOSE_LUT; | 1137 | return lut_type != BT_COEX_LOOSE_LUT; |
1138 | } | 1138 | } |
1139 | 1139 | ||
1140 | bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant) | ||
1141 | { | ||
1142 | /* there is no other antenna, shared antenna is always available */ | ||
1143 | if (mvm->cfg->bt_shared_single_ant) | ||
1144 | return true; | ||
1145 | |||
1146 | if (ant & mvm->cfg->non_shared_ant) | ||
1147 | return true; | ||
1148 | |||
1149 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) | ||
1150 | return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm); | ||
1151 | |||
1152 | return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < | ||
1153 | BT_HIGH_TRAFFIC; | ||
1154 | } | ||
1155 | |||
1140 | bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) | 1156 | bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) |
1141 | { | 1157 | { |
1142 | /* there is no other antenna, shared antenna is always available */ | 1158 | /* there is no other antenna, shared antenna is always available */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index b571e1b0550c..b3210cfbecc8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | |||
@@ -612,7 +612,9 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) | |||
612 | BT_VALID_ANT_ISOLATION_THRS | | 612 | BT_VALID_ANT_ISOLATION_THRS | |
613 | BT_VALID_TXTX_DELTA_FREQ_THRS | | 613 | BT_VALID_TXTX_DELTA_FREQ_THRS | |
614 | BT_VALID_TXRX_MAX_FREQ_0 | | 614 | BT_VALID_TXRX_MAX_FREQ_0 | |
615 | BT_VALID_SYNC_TO_SCO); | 615 | BT_VALID_SYNC_TO_SCO | |
616 | BT_VALID_TTC | | ||
617 | BT_VALID_RRC); | ||
616 | 618 | ||
617 | if (IWL_MVM_BT_COEX_SYNC2SCO) | 619 | if (IWL_MVM_BT_COEX_SYNC2SCO) |
618 | bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); | 620 | bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); |
@@ -628,6 +630,12 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) | |||
628 | bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); | 630 | bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); |
629 | } | 631 | } |
630 | 632 | ||
633 | if (IWL_MVM_BT_COEX_TTC) | ||
634 | bt_cmd->flags |= cpu_to_le32(BT_COEX_TTC); | ||
635 | |||
636 | if (IWL_MVM_BT_COEX_RRC) | ||
637 | bt_cmd->flags |= cpu_to_le32(BT_COEX_RRC); | ||
638 | |||
631 | if (mvm->cfg->bt_shared_single_ant) | 639 | if (mvm->cfg->bt_shared_single_ant) |
632 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, | 640 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, |
633 | sizeof(iwl_single_shared_ant)); | 641 | sizeof(iwl_single_shared_ant)); |
@@ -824,6 +832,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
824 | if (!vif->bss_conf.assoc) | 832 | if (!vif->bss_conf.assoc) |
825 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 833 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
826 | 834 | ||
835 | if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id)) | ||
836 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
837 | |||
827 | IWL_DEBUG_COEX(data->mvm, | 838 | IWL_DEBUG_COEX(data->mvm, |
828 | "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", | 839 | "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", |
829 | mvmvif->id, data->notif->bt_status, bt_activity_grading, | 840 | mvmvif->id, data->notif->bt_status, bt_activity_grading, |
@@ -1156,6 +1167,12 @@ bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm, | |||
1156 | return lut_type != BT_COEX_LOOSE_LUT; | 1167 | return lut_type != BT_COEX_LOOSE_LUT; |
1157 | } | 1168 | } |
1158 | 1169 | ||
1170 | bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant) | ||
1171 | { | ||
1172 | u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); | ||
1173 | return ag < BT_HIGH_TRAFFIC; | ||
1174 | } | ||
1175 | |||
1159 | bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm) | 1176 | bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm) |
1160 | { | 1177 | { |
1161 | u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); | 1178 | u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 5c1ea80d5e3b..3bd93476ec1c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h | |||
@@ -92,8 +92,10 @@ | |||
92 | #define IWL_MVM_BT_COEX_SYNC2SCO 1 | 92 | #define IWL_MVM_BT_COEX_SYNC2SCO 1 |
93 | #define IWL_MVM_BT_COEX_CORUNNING 0 | 93 | #define IWL_MVM_BT_COEX_CORUNNING 0 |
94 | #define IWL_MVM_BT_COEX_MPLUT 1 | 94 | #define IWL_MVM_BT_COEX_MPLUT 1 |
95 | #define IWL_MVM_BT_COEX_MPLUT_REG0 0x2e402280 | 95 | #define IWL_MVM_BT_COEX_RRC 1 |
96 | #define IWL_MVM_BT_COEX_MPLUT_REG1 0x7711a751 | 96 | #define IWL_MVM_BT_COEX_TTC 1 |
97 | #define IWL_MVM_BT_COEX_MPLUT_REG0 0x28412201 | ||
98 | #define IWL_MVM_BT_COEX_MPLUT_REG1 0x11118451 | ||
97 | #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 | 99 | #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 |
98 | #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 | 100 | #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 |
99 | #define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 | 101 | #define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 3bbb511b0b38..744de262373e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -786,32 +786,18 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm) | |||
786 | } | 786 | } |
787 | 787 | ||
788 | static int | 788 | static int |
789 | iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm, | ||
790 | const struct iwl_wowlan_config_cmd_v3 *cmd) | ||
791 | { | ||
792 | /* start only with the v2 part of the command */ | ||
793 | u16 cmd_len = sizeof(cmd->common); | ||
794 | |||
795 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID) | ||
796 | cmd_len = sizeof(*cmd); | ||
797 | |||
798 | return iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, | ||
799 | cmd_len, cmd); | ||
800 | } | ||
801 | |||
802 | static int | ||
803 | iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, | 789 | iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, |
804 | struct cfg80211_wowlan *wowlan, | 790 | struct cfg80211_wowlan *wowlan, |
805 | struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd, | 791 | struct iwl_wowlan_config_cmd *wowlan_config_cmd, |
806 | struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, | 792 | struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, |
807 | struct ieee80211_sta *ap_sta) | 793 | struct ieee80211_sta *ap_sta) |
808 | { | 794 | { |
809 | int ret; | 795 | int ret; |
810 | struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; | 796 | struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; |
811 | 797 | ||
812 | /* TODO: wowlan_config_cmd->common.wowlan_ba_teardown_tids */ | 798 | /* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */ |
813 | 799 | ||
814 | wowlan_config_cmd->common.is_11n_connection = | 800 | wowlan_config_cmd->is_11n_connection = |
815 | ap_sta->ht_cap.ht_supported; | 801 | ap_sta->ht_cap.ht_supported; |
816 | 802 | ||
817 | /* Query the last used seqno and set it */ | 803 | /* Query the last used seqno and set it */ |
@@ -819,32 +805,32 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, | |||
819 | if (ret < 0) | 805 | if (ret < 0) |
820 | return ret; | 806 | return ret; |
821 | 807 | ||
822 | wowlan_config_cmd->common.non_qos_seq = cpu_to_le16(ret); | 808 | wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret); |
823 | 809 | ||
824 | iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd->common); | 810 | iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd); |
825 | 811 | ||
826 | if (wowlan->disconnect) | 812 | if (wowlan->disconnect) |
827 | wowlan_config_cmd->common.wakeup_filter |= | 813 | wowlan_config_cmd->wakeup_filter |= |
828 | cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | | 814 | cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | |
829 | IWL_WOWLAN_WAKEUP_LINK_CHANGE); | 815 | IWL_WOWLAN_WAKEUP_LINK_CHANGE); |
830 | if (wowlan->magic_pkt) | 816 | if (wowlan->magic_pkt) |
831 | wowlan_config_cmd->common.wakeup_filter |= | 817 | wowlan_config_cmd->wakeup_filter |= |
832 | cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); | 818 | cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); |
833 | if (wowlan->gtk_rekey_failure) | 819 | if (wowlan->gtk_rekey_failure) |
834 | wowlan_config_cmd->common.wakeup_filter |= | 820 | wowlan_config_cmd->wakeup_filter |= |
835 | cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); | 821 | cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); |
836 | if (wowlan->eap_identity_req) | 822 | if (wowlan->eap_identity_req) |
837 | wowlan_config_cmd->common.wakeup_filter |= | 823 | wowlan_config_cmd->wakeup_filter |= |
838 | cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); | 824 | cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); |
839 | if (wowlan->four_way_handshake) | 825 | if (wowlan->four_way_handshake) |
840 | wowlan_config_cmd->common.wakeup_filter |= | 826 | wowlan_config_cmd->wakeup_filter |= |
841 | cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); | 827 | cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); |
842 | if (wowlan->n_patterns) | 828 | if (wowlan->n_patterns) |
843 | wowlan_config_cmd->common.wakeup_filter |= | 829 | wowlan_config_cmd->wakeup_filter |= |
844 | cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); | 830 | cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); |
845 | 831 | ||
846 | if (wowlan->rfkill_release) | 832 | if (wowlan->rfkill_release) |
847 | wowlan_config_cmd->common.wakeup_filter |= | 833 | wowlan_config_cmd->wakeup_filter |= |
848 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); | 834 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); |
849 | 835 | ||
850 | if (wowlan->tcp) { | 836 | if (wowlan->tcp) { |
@@ -852,7 +838,7 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, | |||
852 | * Set the "link change" (really "link lost") flag as well | 838 | * Set the "link change" (really "link lost") flag as well |
853 | * since that implies losing the TCP connection. | 839 | * since that implies losing the TCP connection. |
854 | */ | 840 | */ |
855 | wowlan_config_cmd->common.wakeup_filter |= | 841 | wowlan_config_cmd->wakeup_filter |= |
856 | cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS | | 842 | cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS | |
857 | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE | | 843 | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE | |
858 | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET | | 844 | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET | |
@@ -865,7 +851,7 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, | |||
865 | static int | 851 | static int |
866 | iwl_mvm_wowlan_config(struct iwl_mvm *mvm, | 852 | iwl_mvm_wowlan_config(struct iwl_mvm *mvm, |
867 | struct cfg80211_wowlan *wowlan, | 853 | struct cfg80211_wowlan *wowlan, |
868 | struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd, | 854 | struct iwl_wowlan_config_cmd *wowlan_config_cmd, |
869 | struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, | 855 | struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, |
870 | struct ieee80211_sta *ap_sta) | 856 | struct ieee80211_sta *ap_sta) |
871 | { | 857 | { |
@@ -878,6 +864,10 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, | |||
878 | }; | 864 | }; |
879 | int ret; | 865 | int ret; |
880 | 866 | ||
867 | ret = iwl_mvm_switch_to_d3(mvm); | ||
868 | if (ret) | ||
869 | return ret; | ||
870 | |||
881 | ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); | 871 | ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); |
882 | if (ret) | 872 | if (ret) |
883 | return ret; | 873 | return ret; |
@@ -943,7 +933,9 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, | |||
943 | } | 933 | } |
944 | } | 934 | } |
945 | 935 | ||
946 | ret = iwl_mvm_send_wowlan_config_cmd(mvm, wowlan_config_cmd); | 936 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, |
937 | sizeof(*wowlan_config_cmd), | ||
938 | wowlan_config_cmd); | ||
947 | if (ret) | 939 | if (ret) |
948 | goto out; | 940 | goto out; |
949 | 941 | ||
@@ -962,6 +954,68 @@ out: | |||
962 | return ret; | 954 | return ret; |
963 | } | 955 | } |
964 | 956 | ||
957 | static int | ||
958 | iwl_mvm_netdetect_config(struct iwl_mvm *mvm, | ||
959 | struct cfg80211_wowlan *wowlan, | ||
960 | struct cfg80211_sched_scan_request *nd_config, | ||
961 | struct ieee80211_vif *vif) | ||
962 | { | ||
963 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; | ||
964 | int ret; | ||
965 | |||
966 | ret = iwl_mvm_switch_to_d3(mvm); | ||
967 | if (ret) | ||
968 | return ret; | ||
969 | |||
970 | /* rfkill release can be either for wowlan or netdetect */ | ||
971 | if (wowlan->rfkill_release) | ||
972 | wowlan_config_cmd.wakeup_filter |= | ||
973 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); | ||
974 | |||
975 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, | ||
976 | sizeof(wowlan_config_cmd), | ||
977 | &wowlan_config_cmd); | ||
978 | if (ret) | ||
979 | return ret; | ||
980 | |||
981 | ret = iwl_mvm_scan_offload_start(mvm, vif, nd_config, &mvm->nd_ies); | ||
982 | if (ret) | ||
983 | return ret; | ||
984 | |||
985 | if (WARN_ON(mvm->nd_match_sets || mvm->nd_channels)) | ||
986 | return -EBUSY; | ||
987 | |||
988 | /* save the sched scan matchsets... */ | ||
989 | if (nd_config->n_match_sets) { | ||
990 | mvm->nd_match_sets = kmemdup(nd_config->match_sets, | ||
991 | sizeof(*nd_config->match_sets) * | ||
992 | nd_config->n_match_sets, | ||
993 | GFP_KERNEL); | ||
994 | if (mvm->nd_match_sets) | ||
995 | mvm->n_nd_match_sets = nd_config->n_match_sets; | ||
996 | } | ||
997 | |||
998 | /* ...and the sched scan channels for later reporting */ | ||
999 | mvm->nd_channels = kmemdup(nd_config->channels, | ||
1000 | sizeof(*nd_config->channels) * | ||
1001 | nd_config->n_channels, | ||
1002 | GFP_KERNEL); | ||
1003 | if (mvm->nd_channels) | ||
1004 | mvm->n_nd_channels = nd_config->n_channels; | ||
1005 | |||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | static void iwl_mvm_free_nd(struct iwl_mvm *mvm) | ||
1010 | { | ||
1011 | kfree(mvm->nd_match_sets); | ||
1012 | mvm->nd_match_sets = NULL; | ||
1013 | mvm->n_nd_match_sets = 0; | ||
1014 | kfree(mvm->nd_channels); | ||
1015 | mvm->nd_channels = NULL; | ||
1016 | mvm->n_nd_channels = 0; | ||
1017 | } | ||
1018 | |||
965 | static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | 1019 | static int __iwl_mvm_suspend(struct ieee80211_hw *hw, |
966 | struct cfg80211_wowlan *wowlan, | 1020 | struct cfg80211_wowlan *wowlan, |
967 | bool test) | 1021 | bool test) |
@@ -970,7 +1024,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
970 | struct ieee80211_vif *vif = NULL; | 1024 | struct ieee80211_vif *vif = NULL; |
971 | struct iwl_mvm_vif *mvmvif = NULL; | 1025 | struct iwl_mvm_vif *mvmvif = NULL; |
972 | struct ieee80211_sta *ap_sta = NULL; | 1026 | struct ieee80211_sta *ap_sta = NULL; |
973 | struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {}; | ||
974 | struct iwl_d3_manager_config d3_cfg_cmd_data = { | 1027 | struct iwl_d3_manager_config d3_cfg_cmd_data = { |
975 | /* | 1028 | /* |
976 | * Program the minimum sleep time to 10 seconds, as many | 1029 | * Program the minimum sleep time to 10 seconds, as many |
@@ -1007,8 +1060,22 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1007 | 1060 | ||
1008 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1061 | mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1009 | 1062 | ||
1010 | /* if we're associated, this is wowlan */ | 1063 | if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) { |
1011 | if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 1064 | /* if we're not associated, this must be netdetect */ |
1065 | if (!wowlan->nd_config && !mvm->nd_config) { | ||
1066 | ret = 1; | ||
1067 | goto out_noreset; | ||
1068 | } | ||
1069 | |||
1070 | ret = iwl_mvm_netdetect_config( | ||
1071 | mvm, wowlan, wowlan->nd_config ?: mvm->nd_config, vif); | ||
1072 | if (ret) | ||
1073 | goto out; | ||
1074 | |||
1075 | mvm->net_detect = true; | ||
1076 | } else { | ||
1077 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; | ||
1078 | |||
1012 | ap_sta = rcu_dereference_protected( | 1079 | ap_sta = rcu_dereference_protected( |
1013 | mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], | 1080 | mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], |
1014 | lockdep_is_held(&mvm->mutex)); | 1081 | lockdep_is_held(&mvm->mutex)); |
@@ -1021,27 +1088,12 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1021 | vif, mvmvif, ap_sta); | 1088 | vif, mvmvif, ap_sta); |
1022 | if (ret) | 1089 | if (ret) |
1023 | goto out_noreset; | 1090 | goto out_noreset; |
1024 | |||
1025 | ret = iwl_mvm_switch_to_d3(mvm); | ||
1026 | if (ret) | ||
1027 | goto out; | ||
1028 | |||
1029 | ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, | 1091 | ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, |
1030 | vif, mvmvif, ap_sta); | 1092 | vif, mvmvif, ap_sta); |
1031 | if (ret) | 1093 | if (ret) |
1032 | goto out; | 1094 | goto out; |
1033 | } else if (mvm->nd_config) { | ||
1034 | ret = iwl_mvm_switch_to_d3(mvm); | ||
1035 | if (ret) | ||
1036 | goto out; | ||
1037 | 1095 | ||
1038 | ret = iwl_mvm_scan_offload_start(mvm, vif, mvm->nd_config, | 1096 | mvm->net_detect = false; |
1039 | mvm->nd_ies); | ||
1040 | if (ret) | ||
1041 | goto out; | ||
1042 | } else { | ||
1043 | ret = 1; | ||
1044 | goto out_noreset; | ||
1045 | } | 1097 | } |
1046 | 1098 | ||
1047 | ret = iwl_mvm_power_update_device(mvm); | 1099 | ret = iwl_mvm_power_update_device(mvm); |
@@ -1075,8 +1127,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1075 | 1127 | ||
1076 | iwl_trans_d3_suspend(mvm->trans, test); | 1128 | iwl_trans_d3_suspend(mvm->trans, test); |
1077 | out: | 1129 | out: |
1078 | if (ret < 0) | 1130 | if (ret < 0) { |
1079 | ieee80211_restart_hw(mvm->hw); | 1131 | ieee80211_restart_hw(mvm->hw); |
1132 | iwl_mvm_free_nd(mvm); | ||
1133 | } | ||
1080 | out_noreset: | 1134 | out_noreset: |
1081 | mutex_unlock(&mvm->mutex); | 1135 | mutex_unlock(&mvm->mutex); |
1082 | 1136 | ||
@@ -1087,6 +1141,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
1087 | { | 1141 | { |
1088 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1142 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1089 | 1143 | ||
1144 | iwl_trans_suspend(mvm->trans); | ||
1090 | if (iwl_mvm_is_d0i3_supported(mvm)) { | 1145 | if (iwl_mvm_is_d0i3_supported(mvm)) { |
1091 | mutex_lock(&mvm->d0i3_suspend_mutex); | 1146 | mutex_lock(&mvm->d0i3_suspend_mutex); |
1092 | __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); | 1147 | __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); |
@@ -1465,9 +1520,8 @@ out: | |||
1465 | return true; | 1520 | return true; |
1466 | } | 1521 | } |
1467 | 1522 | ||
1468 | /* releases the MVM mutex */ | 1523 | static struct iwl_wowlan_status * |
1469 | static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | 1524 | iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
1470 | struct ieee80211_vif *vif) | ||
1471 | { | 1525 | { |
1472 | u32 base = mvm->error_event_table; | 1526 | u32 base = mvm->error_event_table; |
1473 | struct error_table_start { | 1527 | struct error_table_start { |
@@ -1479,19 +1533,15 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1479 | .id = WOWLAN_GET_STATUSES, | 1533 | .id = WOWLAN_GET_STATUSES, |
1480 | .flags = CMD_WANT_SKB, | 1534 | .flags = CMD_WANT_SKB, |
1481 | }; | 1535 | }; |
1482 | struct iwl_wowlan_status_data status; | 1536 | struct iwl_wowlan_status *status, *fw_status; |
1483 | struct iwl_wowlan_status *fw_status; | 1537 | int ret, len, status_size; |
1484 | int ret, len, status_size, i; | ||
1485 | bool keep; | ||
1486 | struct ieee80211_sta *ap_sta; | ||
1487 | struct iwl_mvm_sta *mvm_ap_sta; | ||
1488 | 1538 | ||
1489 | iwl_trans_read_mem_bytes(mvm->trans, base, | 1539 | iwl_trans_read_mem_bytes(mvm->trans, base, |
1490 | &err_info, sizeof(err_info)); | 1540 | &err_info, sizeof(err_info)); |
1491 | 1541 | ||
1492 | if (err_info.valid) { | 1542 | if (err_info.valid) { |
1493 | IWL_INFO(mvm, "error table is valid (%d)\n", | 1543 | IWL_INFO(mvm, "error table is valid (%d) with error (%d)\n", |
1494 | err_info.valid); | 1544 | err_info.valid, err_info.error_id); |
1495 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { | 1545 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { |
1496 | struct cfg80211_wowlan_wakeup wakeup = { | 1546 | struct cfg80211_wowlan_wakeup wakeup = { |
1497 | .rfkill_release = true, | 1547 | .rfkill_release = true, |
@@ -1499,7 +1549,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1499 | ieee80211_report_wowlan_wakeup(vif, &wakeup, | 1549 | ieee80211_report_wowlan_wakeup(vif, &wakeup, |
1500 | GFP_KERNEL); | 1550 | GFP_KERNEL); |
1501 | } | 1551 | } |
1502 | goto out_unlock; | 1552 | return ERR_PTR(-EIO); |
1503 | } | 1553 | } |
1504 | 1554 | ||
1505 | /* only for tracing for now */ | 1555 | /* only for tracing for now */ |
@@ -1510,22 +1560,53 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1510 | ret = iwl_mvm_send_cmd(mvm, &cmd); | 1560 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
1511 | if (ret) { | 1561 | if (ret) { |
1512 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); | 1562 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); |
1513 | goto out_unlock; | 1563 | return ERR_PTR(ret); |
1514 | } | 1564 | } |
1515 | 1565 | ||
1516 | /* RF-kill already asserted again... */ | 1566 | /* RF-kill already asserted again... */ |
1517 | if (!cmd.resp_pkt) | 1567 | if (!cmd.resp_pkt) { |
1518 | goto out_unlock; | 1568 | ret = -ERFKILL; |
1569 | goto out_free_resp; | ||
1570 | } | ||
1519 | 1571 | ||
1520 | status_size = sizeof(*fw_status); | 1572 | status_size = sizeof(*fw_status); |
1521 | 1573 | ||
1522 | len = iwl_rx_packet_payload_len(cmd.resp_pkt); | 1574 | len = iwl_rx_packet_payload_len(cmd.resp_pkt); |
1523 | if (len < status_size) { | 1575 | if (len < status_size) { |
1524 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | 1576 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); |
1577 | ret = -EIO; | ||
1525 | goto out_free_resp; | 1578 | goto out_free_resp; |
1526 | } | 1579 | } |
1527 | 1580 | ||
1528 | fw_status = (void *)cmd.resp_pkt->data; | 1581 | status = (void *)cmd.resp_pkt->data; |
1582 | if (len != (status_size + | ||
1583 | ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4))) { | ||
1584 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
1585 | ret = -EIO; | ||
1586 | goto out_free_resp; | ||
1587 | } | ||
1588 | |||
1589 | fw_status = kmemdup(status, len, GFP_KERNEL); | ||
1590 | |||
1591 | out_free_resp: | ||
1592 | iwl_free_resp(&cmd); | ||
1593 | return ret ? ERR_PTR(ret) : fw_status; | ||
1594 | } | ||
1595 | |||
1596 | /* releases the MVM mutex */ | ||
1597 | static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | ||
1598 | struct ieee80211_vif *vif) | ||
1599 | { | ||
1600 | struct iwl_wowlan_status_data status; | ||
1601 | struct iwl_wowlan_status *fw_status; | ||
1602 | int i; | ||
1603 | bool keep; | ||
1604 | struct ieee80211_sta *ap_sta; | ||
1605 | struct iwl_mvm_sta *mvm_ap_sta; | ||
1606 | |||
1607 | fw_status = iwl_mvm_get_wakeup_status(mvm, vif); | ||
1608 | if (IS_ERR_OR_NULL(fw_status)) | ||
1609 | goto out_unlock; | ||
1529 | 1610 | ||
1530 | status.pattern_number = le16_to_cpu(fw_status->pattern_number); | 1611 | status.pattern_number = le16_to_cpu(fw_status->pattern_number); |
1531 | for (i = 0; i < 8; i++) | 1612 | for (i = 0; i < 8; i++) |
@@ -1538,17 +1619,12 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1538 | le32_to_cpu(fw_status->wake_packet_bufsize); | 1619 | le32_to_cpu(fw_status->wake_packet_bufsize); |
1539 | status.wake_packet = fw_status->wake_packet; | 1620 | status.wake_packet = fw_status->wake_packet; |
1540 | 1621 | ||
1541 | if (len != status_size + ALIGN(status.wake_packet_bufsize, 4)) { | ||
1542 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
1543 | goto out_free_resp; | ||
1544 | } | ||
1545 | |||
1546 | /* still at hard-coded place 0 for D3 image */ | 1622 | /* still at hard-coded place 0 for D3 image */ |
1547 | ap_sta = rcu_dereference_protected( | 1623 | ap_sta = rcu_dereference_protected( |
1548 | mvm->fw_id_to_mac_id[0], | 1624 | mvm->fw_id_to_mac_id[0], |
1549 | lockdep_is_held(&mvm->mutex)); | 1625 | lockdep_is_held(&mvm->mutex)); |
1550 | if (IS_ERR_OR_NULL(ap_sta)) | 1626 | if (IS_ERR_OR_NULL(ap_sta)) |
1551 | goto out_free_resp; | 1627 | goto out_free; |
1552 | 1628 | ||
1553 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; | 1629 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; |
1554 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { | 1630 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { |
@@ -1565,16 +1641,151 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1565 | 1641 | ||
1566 | keep = iwl_mvm_setup_connection_keep(mvm, vif, fw_status); | 1642 | keep = iwl_mvm_setup_connection_keep(mvm, vif, fw_status); |
1567 | 1643 | ||
1568 | iwl_free_resp(&cmd); | 1644 | kfree(fw_status); |
1569 | return keep; | 1645 | return keep; |
1570 | 1646 | ||
1571 | out_free_resp: | 1647 | out_free: |
1572 | iwl_free_resp(&cmd); | 1648 | kfree(fw_status); |
1573 | out_unlock: | 1649 | out_unlock: |
1574 | mutex_unlock(&mvm->mutex); | 1650 | mutex_unlock(&mvm->mutex); |
1575 | return false; | 1651 | return false; |
1576 | } | 1652 | } |
1577 | 1653 | ||
1654 | struct iwl_mvm_nd_query_results { | ||
1655 | u32 matched_profiles; | ||
1656 | struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES]; | ||
1657 | }; | ||
1658 | |||
1659 | static int | ||
1660 | iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, | ||
1661 | struct iwl_mvm_nd_query_results *results) | ||
1662 | { | ||
1663 | struct iwl_scan_offload_profiles_query *query; | ||
1664 | struct iwl_host_cmd cmd = { | ||
1665 | .id = SCAN_OFFLOAD_PROFILES_QUERY_CMD, | ||
1666 | .flags = CMD_WANT_SKB, | ||
1667 | }; | ||
1668 | int ret, len; | ||
1669 | |||
1670 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
1671 | if (ret) { | ||
1672 | IWL_ERR(mvm, "failed to query matched profiles (%d)\n", ret); | ||
1673 | return ret; | ||
1674 | } | ||
1675 | |||
1676 | /* RF-kill already asserted again... */ | ||
1677 | if (!cmd.resp_pkt) { | ||
1678 | ret = -ERFKILL; | ||
1679 | goto out_free_resp; | ||
1680 | } | ||
1681 | |||
1682 | len = iwl_rx_packet_payload_len(cmd.resp_pkt); | ||
1683 | if (len < sizeof(*query)) { | ||
1684 | IWL_ERR(mvm, "Invalid scan offload profiles query response!\n"); | ||
1685 | ret = -EIO; | ||
1686 | goto out_free_resp; | ||
1687 | } | ||
1688 | |||
1689 | query = (void *)cmd.resp_pkt->data; | ||
1690 | |||
1691 | results->matched_profiles = le32_to_cpu(query->matched_profiles); | ||
1692 | memcpy(results->matches, query->matches, sizeof(results->matches)); | ||
1693 | |||
1694 | out_free_resp: | ||
1695 | iwl_free_resp(&cmd); | ||
1696 | return ret; | ||
1697 | } | ||
1698 | |||
1699 | static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, | ||
1700 | struct ieee80211_vif *vif) | ||
1701 | { | ||
1702 | struct cfg80211_wowlan_nd_info *net_detect = NULL; | ||
1703 | struct cfg80211_wowlan_wakeup wakeup = { | ||
1704 | .pattern_idx = -1, | ||
1705 | }; | ||
1706 | struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; | ||
1707 | struct iwl_mvm_nd_query_results query; | ||
1708 | struct iwl_wowlan_status *fw_status; | ||
1709 | unsigned long matched_profiles; | ||
1710 | u32 reasons = 0; | ||
1711 | int i, j, n_matches, ret; | ||
1712 | |||
1713 | fw_status = iwl_mvm_get_wakeup_status(mvm, vif); | ||
1714 | if (!IS_ERR_OR_NULL(fw_status)) | ||
1715 | reasons = le32_to_cpu(fw_status->wakeup_reasons); | ||
1716 | |||
1717 | if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) | ||
1718 | wakeup.rfkill_release = true; | ||
1719 | |||
1720 | if (reasons != IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) | ||
1721 | goto out; | ||
1722 | |||
1723 | ret = iwl_mvm_netdetect_query_results(mvm, &query); | ||
1724 | if (ret || !query.matched_profiles) { | ||
1725 | wakeup_report = NULL; | ||
1726 | goto out; | ||
1727 | } | ||
1728 | |||
1729 | matched_profiles = query.matched_profiles; | ||
1730 | if (mvm->n_nd_match_sets) { | ||
1731 | n_matches = hweight_long(matched_profiles); | ||
1732 | } else { | ||
1733 | IWL_ERR(mvm, "no net detect match information available\n"); | ||
1734 | n_matches = 0; | ||
1735 | } | ||
1736 | |||
1737 | net_detect = kzalloc(sizeof(*net_detect) + | ||
1738 | (n_matches * sizeof(net_detect->matches[0])), | ||
1739 | GFP_KERNEL); | ||
1740 | if (!net_detect || !n_matches) | ||
1741 | goto out_report_nd; | ||
1742 | |||
1743 | for_each_set_bit(i, &matched_profiles, mvm->n_nd_match_sets) { | ||
1744 | struct iwl_scan_offload_profile_match *fw_match; | ||
1745 | struct cfg80211_wowlan_nd_match *match; | ||
1746 | int n_channels = 0; | ||
1747 | |||
1748 | fw_match = &query.matches[i]; | ||
1749 | |||
1750 | for (j = 0; j < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN; j++) | ||
1751 | n_channels += hweight8(fw_match->matching_channels[j]); | ||
1752 | |||
1753 | match = kzalloc(sizeof(*match) + | ||
1754 | (n_channels * sizeof(*match->channels)), | ||
1755 | GFP_KERNEL); | ||
1756 | if (!match) | ||
1757 | goto out_report_nd; | ||
1758 | |||
1759 | net_detect->matches[net_detect->n_matches++] = match; | ||
1760 | |||
1761 | match->ssid.ssid_len = mvm->nd_match_sets[i].ssid.ssid_len; | ||
1762 | memcpy(match->ssid.ssid, mvm->nd_match_sets[i].ssid.ssid, | ||
1763 | match->ssid.ssid_len); | ||
1764 | |||
1765 | if (mvm->n_nd_channels < n_channels) | ||
1766 | continue; | ||
1767 | |||
1768 | for (j = 0; j < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; j++) | ||
1769 | if (fw_match->matching_channels[j / 8] & (BIT(j % 8))) | ||
1770 | match->channels[match->n_channels++] = | ||
1771 | mvm->nd_channels[j]->center_freq; | ||
1772 | } | ||
1773 | |||
1774 | out_report_nd: | ||
1775 | wakeup.net_detect = net_detect; | ||
1776 | out: | ||
1777 | iwl_mvm_free_nd(mvm); | ||
1778 | |||
1779 | mutex_unlock(&mvm->mutex); | ||
1780 | ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); | ||
1781 | |||
1782 | if (net_detect) { | ||
1783 | for (i = 0; i < net_detect->n_matches; i++) | ||
1784 | kfree(net_detect->matches[i]); | ||
1785 | kfree(net_detect); | ||
1786 | } | ||
1787 | } | ||
1788 | |||
1578 | static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) | 1789 | static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) |
1579 | { | 1790 | { |
1580 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1791 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
@@ -1632,11 +1843,15 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
1632 | /* query SRAM first in case we want event logging */ | 1843 | /* query SRAM first in case we want event logging */ |
1633 | iwl_mvm_read_d3_sram(mvm); | 1844 | iwl_mvm_read_d3_sram(mvm); |
1634 | 1845 | ||
1635 | keep = iwl_mvm_query_wakeup_reasons(mvm, vif); | 1846 | if (mvm->net_detect) { |
1847 | iwl_mvm_query_netdetect_reasons(mvm, vif); | ||
1848 | } else { | ||
1849 | keep = iwl_mvm_query_wakeup_reasons(mvm, vif); | ||
1636 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1850 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
1637 | if (keep) | 1851 | if (keep) |
1638 | mvm->keep_vif = vif; | 1852 | mvm->keep_vif = vif; |
1639 | #endif | 1853 | #endif |
1854 | } | ||
1640 | /* has unlocked the mutex, so skip that */ | 1855 | /* has unlocked the mutex, so skip that */ |
1641 | goto out; | 1856 | goto out; |
1642 | 1857 | ||
@@ -1651,6 +1866,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
1651 | 1866 | ||
1652 | /* return 1 to reconfigure the device */ | 1867 | /* return 1 to reconfigure the device */ |
1653 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 1868 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
1869 | set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status); | ||
1654 | return 1; | 1870 | return 1; |
1655 | } | 1871 | } |
1656 | 1872 | ||
@@ -1658,18 +1874,10 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | |||
1658 | { | 1874 | { |
1659 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1875 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1660 | 1876 | ||
1661 | if (iwl_mvm_is_d0i3_supported(mvm)) { | 1877 | iwl_trans_resume(mvm->trans); |
1662 | bool exit_now; | ||
1663 | 1878 | ||
1664 | mutex_lock(&mvm->d0i3_suspend_mutex); | 1879 | if (iwl_mvm_is_d0i3_supported(mvm)) |
1665 | __clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); | ||
1666 | exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, | ||
1667 | &mvm->d0i3_suspend_flags); | ||
1668 | mutex_unlock(&mvm->d0i3_suspend_mutex); | ||
1669 | if (exit_now) | ||
1670 | _iwl_mvm_exit_d0i3(mvm); | ||
1671 | return 0; | 1880 | return 0; |
1672 | } | ||
1673 | 1881 | ||
1674 | return __iwl_mvm_resume(mvm, false); | 1882 | return __iwl_mvm_resume(mvm, false); |
1675 | } | 1883 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 51b7116965ed..33bf915cd7ea 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -936,7 +936,11 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, | |||
936 | if (scan_rx_ant & ~mvm->fw->valid_rx_ant) | 936 | if (scan_rx_ant & ~mvm->fw->valid_rx_ant) |
937 | return -EINVAL; | 937 | return -EINVAL; |
938 | 938 | ||
939 | mvm->scan_rx_ant = scan_rx_ant; | 939 | if (mvm->scan_rx_ant != scan_rx_ant) { |
940 | mvm->scan_rx_ant = scan_rx_ant; | ||
941 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
942 | iwl_mvm_config_scan(mvm); | ||
943 | } | ||
940 | 944 | ||
941 | return count; | 945 | return count; |
942 | } | 946 | } |
@@ -1194,14 +1198,8 @@ static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf, | |||
1194 | kfree(mvm->nd_config->match_sets); | 1198 | kfree(mvm->nd_config->match_sets); |
1195 | kfree(mvm->nd_config); | 1199 | kfree(mvm->nd_config); |
1196 | mvm->nd_config = NULL; | 1200 | mvm->nd_config = NULL; |
1197 | kfree(mvm->nd_ies); | ||
1198 | mvm->nd_ies = NULL; | ||
1199 | } | 1201 | } |
1200 | 1202 | ||
1201 | mvm->nd_ies = kzalloc(sizeof(*mvm->nd_ies), GFP_KERNEL); | ||
1202 | if (!mvm->nd_ies) | ||
1203 | return -ENOMEM; | ||
1204 | |||
1205 | mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) + | 1203 | mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) + |
1206 | (11 * sizeof(struct ieee80211_channel *)), | 1204 | (11 * sizeof(struct ieee80211_channel *)), |
1207 | GFP_KERNEL); | 1205 | GFP_KERNEL); |
@@ -1258,8 +1256,6 @@ out_free: | |||
1258 | kfree(mvm->nd_config->match_sets); | 1256 | kfree(mvm->nd_config->match_sets); |
1259 | kfree(mvm->nd_config); | 1257 | kfree(mvm->nd_config); |
1260 | mvm->nd_config = NULL; | 1258 | mvm->nd_config = NULL; |
1261 | kfree(mvm->nd_ies); | ||
1262 | mvm->nd_ies = NULL; | ||
1263 | out: | 1259 | out: |
1264 | return ret; | 1260 | return ret; |
1265 | } | 1261 | } |
@@ -1343,6 +1339,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, | |||
1343 | PRINT_MVM_REF(IWL_MVM_REF_NMI); | 1339 | PRINT_MVM_REF(IWL_MVM_REF_NMI); |
1344 | PRINT_MVM_REF(IWL_MVM_REF_TM_CMD); | 1340 | PRINT_MVM_REF(IWL_MVM_REF_TM_CMD); |
1345 | PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); | 1341 | PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); |
1342 | PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA); | ||
1346 | 1343 | ||
1347 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 1344 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
1348 | } | 1345 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index 816883f9ff94..f3b11897991e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | |||
@@ -84,6 +84,8 @@ | |||
84 | * @BT_COEX_SYNC2SCO: | 84 | * @BT_COEX_SYNC2SCO: |
85 | * @BT_COEX_CORUNNING: | 85 | * @BT_COEX_CORUNNING: |
86 | * @BT_COEX_MPLUT: | 86 | * @BT_COEX_MPLUT: |
87 | * @BT_COEX_TTC: | ||
88 | * @BT_COEX_RRC: | ||
87 | * | 89 | * |
88 | * The COEX_MODE must be set for each command. Even if it is not changed. | 90 | * The COEX_MODE must be set for each command. Even if it is not changed. |
89 | */ | 91 | */ |
@@ -100,6 +102,8 @@ enum iwl_bt_coex_flags { | |||
100 | BT_COEX_SYNC2SCO = BIT(7), | 102 | BT_COEX_SYNC2SCO = BIT(7), |
101 | BT_COEX_CORUNNING = BIT(8), | 103 | BT_COEX_CORUNNING = BIT(8), |
102 | BT_COEX_MPLUT = BIT(9), | 104 | BT_COEX_MPLUT = BIT(9), |
105 | BT_COEX_TTC = BIT(20), | ||
106 | BT_COEX_RRC = BIT(21), | ||
103 | }; | 107 | }; |
104 | 108 | ||
105 | /* | 109 | /* |
@@ -127,6 +131,8 @@ enum iwl_bt_coex_valid_bit_msk { | |||
127 | BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), | 131 | BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), |
128 | BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), | 132 | BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), |
129 | BT_VALID_SYNC_TO_SCO = BIT(18), | 133 | BT_VALID_SYNC_TO_SCO = BIT(18), |
134 | BT_VALID_TTC = BIT(20), | ||
135 | BT_VALID_RRC = BIT(21), | ||
130 | }; | 136 | }; |
131 | 137 | ||
132 | /** | 138 | /** |
@@ -506,7 +512,8 @@ struct iwl_bt_coex_profile_notif_old { | |||
506 | u8 bt_agg_traffic_load; | 512 | u8 bt_agg_traffic_load; |
507 | u8 bt_ci_compliance; | 513 | u8 bt_ci_compliance; |
508 | u8 ttc_enabled; | 514 | u8 ttc_enabled; |
509 | __le16 reserved; | 515 | u8 rrc_enabled; |
516 | u8 reserved; | ||
510 | 517 | ||
511 | __le32 primary_ch_lut; | 518 | __le32 primary_ch_lut; |
512 | __le32 secondary_ch_lut; | 519 | __le32 secondary_ch_lut; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index e74cdf2132f8..6d3bea5c59d1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | |||
@@ -241,16 +241,12 @@ enum iwl_wowlan_wakeup_filters { | |||
241 | IWL_WOWLAN_WAKEUP_BCN_FILTERING = BIT(16), | 241 | IWL_WOWLAN_WAKEUP_BCN_FILTERING = BIT(16), |
242 | }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ | 242 | }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ |
243 | 243 | ||
244 | struct iwl_wowlan_config_cmd_v2 { | 244 | struct iwl_wowlan_config_cmd { |
245 | __le32 wakeup_filter; | 245 | __le32 wakeup_filter; |
246 | __le16 non_qos_seq; | 246 | __le16 non_qos_seq; |
247 | __le16 qos_seq[8]; | 247 | __le16 qos_seq[8]; |
248 | u8 wowlan_ba_teardown_tids; | 248 | u8 wowlan_ba_teardown_tids; |
249 | u8 is_11n_connection; | 249 | u8 is_11n_connection; |
250 | } __packed; /* WOWLAN_CONFIG_API_S_VER_2 */ | ||
251 | |||
252 | struct iwl_wowlan_config_cmd_v3 { | ||
253 | struct iwl_wowlan_config_cmd_v2 common; | ||
254 | u8 offloading_tid; | 250 | u8 offloading_tid; |
255 | u8 reserved[3]; | 251 | u8 reserved[3]; |
256 | } __packed; /* WOWLAN_CONFIG_API_S_VER_3 */ | 252 | } __packed; /* WOWLAN_CONFIG_API_S_VER_3 */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 2fd8ad4633e0..430020047b77 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | |||
@@ -370,7 +370,7 @@ struct iwl_beacon_filter_cmd { | |||
370 | #define IWL_BF_DEBUG_FLAG_DEFAULT 0 | 370 | #define IWL_BF_DEBUG_FLAG_DEFAULT 0 |
371 | #define IWL_BF_DEBUG_FLAG_D0I3 0 | 371 | #define IWL_BF_DEBUG_FLAG_D0I3 0 |
372 | 372 | ||
373 | #define IWL_BF_ESCAPE_TIMER_DEFAULT 50 | 373 | #define IWL_BF_ESCAPE_TIMER_DEFAULT 0 |
374 | #define IWL_BF_ESCAPE_TIMER_D0I3 0 | 374 | #define IWL_BF_ESCAPE_TIMER_D0I3 0 |
375 | #define IWL_BF_ESCAPE_TIMER_MAX 1024 | 375 | #define IWL_BF_ESCAPE_TIMER_MAX 1024 |
376 | #define IWL_BF_ESCAPE_TIMER_MIN 0 | 376 | #define IWL_BF_ESCAPE_TIMER_MIN 0 |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 1354c68f6468..1f2acf47bfb2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | |||
@@ -794,4 +794,301 @@ struct iwl_periodic_scan_complete { | |||
794 | __le32 reserved; | 794 | __le32 reserved; |
795 | } __packed; | 795 | } __packed; |
796 | 796 | ||
797 | /* UMAC Scan API */ | ||
798 | |||
799 | /** | ||
800 | * struct iwl_mvm_umac_cmd_hdr - Command header for UMAC commands | ||
801 | * @size: size of the command (not including header) | ||
802 | * @reserved0: for future use and alignment | ||
803 | * @ver: API version number | ||
804 | */ | ||
805 | struct iwl_mvm_umac_cmd_hdr { | ||
806 | __le16 size; | ||
807 | u8 reserved0; | ||
808 | u8 ver; | ||
809 | } __packed; | ||
810 | |||
811 | #define IWL_MVM_MAX_SIMULTANEOUS_SCANS 8 | ||
812 | |||
813 | enum scan_config_flags { | ||
814 | SCAN_CONFIG_FLAG_ACTIVATE = BIT(0), | ||
815 | SCAN_CONFIG_FLAG_DEACTIVATE = BIT(1), | ||
816 | SCAN_CONFIG_FLAG_FORBID_CHUB_REQS = BIT(2), | ||
817 | SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS = BIT(3), | ||
818 | SCAN_CONFIG_FLAG_SET_TX_CHAINS = BIT(8), | ||
819 | SCAN_CONFIG_FLAG_SET_RX_CHAINS = BIT(9), | ||
820 | SCAN_CONFIG_FLAG_SET_AUX_STA_ID = BIT(10), | ||
821 | SCAN_CONFIG_FLAG_SET_ALL_TIMES = BIT(11), | ||
822 | SCAN_CONFIG_FLAG_SET_EFFECTIVE_TIMES = BIT(12), | ||
823 | SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS = BIT(13), | ||
824 | SCAN_CONFIG_FLAG_SET_LEGACY_RATES = BIT(14), | ||
825 | SCAN_CONFIG_FLAG_SET_MAC_ADDR = BIT(15), | ||
826 | SCAN_CONFIG_FLAG_SET_FRAGMENTED = BIT(16), | ||
827 | SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED = BIT(17), | ||
828 | SCAN_CONFIG_FLAG_SET_CAM_MODE = BIT(18), | ||
829 | SCAN_CONFIG_FLAG_CLEAR_CAM_MODE = BIT(19), | ||
830 | SCAN_CONFIG_FLAG_SET_PROMISC_MODE = BIT(20), | ||
831 | SCAN_CONFIG_FLAG_CLEAR_PROMISC_MODE = BIT(21), | ||
832 | |||
833 | /* Bits 26-31 are for num of channels in channel_array */ | ||
834 | #define SCAN_CONFIG_N_CHANNELS(n) ((n) << 26) | ||
835 | }; | ||
836 | |||
837 | enum scan_config_rates { | ||
838 | /* OFDM basic rates */ | ||
839 | SCAN_CONFIG_RATE_6M = BIT(0), | ||
840 | SCAN_CONFIG_RATE_9M = BIT(1), | ||
841 | SCAN_CONFIG_RATE_12M = BIT(2), | ||
842 | SCAN_CONFIG_RATE_18M = BIT(3), | ||
843 | SCAN_CONFIG_RATE_24M = BIT(4), | ||
844 | SCAN_CONFIG_RATE_36M = BIT(5), | ||
845 | SCAN_CONFIG_RATE_48M = BIT(6), | ||
846 | SCAN_CONFIG_RATE_54M = BIT(7), | ||
847 | /* CCK basic rates */ | ||
848 | SCAN_CONFIG_RATE_1M = BIT(8), | ||
849 | SCAN_CONFIG_RATE_2M = BIT(9), | ||
850 | SCAN_CONFIG_RATE_5M = BIT(10), | ||
851 | SCAN_CONFIG_RATE_11M = BIT(11), | ||
852 | |||
853 | /* Bits 16-27 are for supported rates */ | ||
854 | #define SCAN_CONFIG_SUPPORTED_RATE(rate) ((rate) << 16) | ||
855 | }; | ||
856 | |||
857 | enum iwl_channel_flags { | ||
858 | IWL_CHANNEL_FLAG_EBS = BIT(0), | ||
859 | IWL_CHANNEL_FLAG_ACCURATE_EBS = BIT(1), | ||
860 | IWL_CHANNEL_FLAG_EBS_ADD = BIT(2), | ||
861 | IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE = BIT(3), | ||
862 | }; | ||
863 | |||
864 | /** | ||
865 | * struct iwl_scan_config | ||
866 | * @hdr: umac command header | ||
867 | * @flags: enum scan_config_flags | ||
868 | * @tx_chains: valid_tx antenna - ANT_* definitions | ||
869 | * @rx_chains: valid_rx antenna - ANT_* definitions | ||
870 | * @legacy_rates: default legacy rates - enum scan_config_rates | ||
871 | * @out_of_channel_time: default max out of serving channel time | ||
872 | * @suspend_time: default max suspend time | ||
873 | * @dwell_active: default dwell time for active scan | ||
874 | * @dwell_passive: default dwell time for passive scan | ||
875 | * @dwell_fragmented: default dwell time for fragmented scan | ||
876 | * @reserved: for future use and alignment | ||
877 | * @mac_addr: default mac address to be used in probes | ||
878 | * @bcast_sta_id: the index of the station in the fw | ||
879 | * @channel_flags: default channel flags - enum iwl_channel_flags | ||
880 | * scan_config_channel_flag | ||
881 | * @channel_array: default supported channels | ||
882 | */ | ||
883 | struct iwl_scan_config { | ||
884 | struct iwl_mvm_umac_cmd_hdr hdr; | ||
885 | __le32 flags; | ||
886 | __le32 tx_chains; | ||
887 | __le32 rx_chains; | ||
888 | __le32 legacy_rates; | ||
889 | __le32 out_of_channel_time; | ||
890 | __le32 suspend_time; | ||
891 | u8 dwell_active; | ||
892 | u8 dwell_passive; | ||
893 | u8 dwell_fragmented; | ||
894 | u8 reserved; | ||
895 | u8 mac_addr[ETH_ALEN]; | ||
896 | u8 bcast_sta_id; | ||
897 | u8 channel_flags; | ||
898 | u8 channel_array[]; | ||
899 | } __packed; /* SCAN_CONFIG_DB_CMD_API_S */ | ||
900 | |||
901 | /** | ||
902 | * iwl_umac_scan_flags | ||
903 | *@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request | ||
904 | * can be preempted by other scan requests with higher priority. | ||
905 | * The low priority scan is aborted. | ||
906 | *@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver | ||
907 | * when scan starts. | ||
908 | */ | ||
909 | enum iwl_umac_scan_flags { | ||
910 | IWL_UMAC_SCAN_FLAG_PREEMPTIVE = BIT(0), | ||
911 | IWL_UMAC_SCAN_FLAG_START_NOTIF = BIT(1), | ||
912 | }; | ||
913 | |||
914 | enum iwl_umac_scan_uid_offsets { | ||
915 | IWL_UMAC_SCAN_UID_TYPE_OFFSET = 0, | ||
916 | IWL_UMAC_SCAN_UID_SEQ_OFFSET = 8, | ||
917 | }; | ||
918 | |||
919 | enum iwl_umac_scan_general_flags { | ||
920 | IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC = BIT(0), | ||
921 | IWL_UMAC_SCAN_GEN_FLAGS_OVER_BT = BIT(1), | ||
922 | IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL = BIT(2), | ||
923 | IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE = BIT(3), | ||
924 | IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT = BIT(4), | ||
925 | IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE = BIT(5), | ||
926 | IWL_UMAC_SCAN_GEN_FLAGS_MULTIPLE_SSID = BIT(6), | ||
927 | IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED = BIT(7), | ||
928 | IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED = BIT(8), | ||
929 | IWL_UMAC_SCAN_GEN_FLAGS_MATCH = BIT(9) | ||
930 | }; | ||
931 | |||
932 | /** | ||
933 | * struct iwl_scan_channel_cfg_umac | ||
934 | * @flags: bitmap - 0-19: directed scan to i'th ssid. | ||
935 | * @channel_num: channel number 1-13 etc. | ||
936 | * @iter_count: repetition count for the channel. | ||
937 | * @iter_interval: interval between two scan interations on one channel. | ||
938 | */ | ||
939 | struct iwl_scan_channel_cfg_umac { | ||
940 | __le32 flags; | ||
941 | u8 channel_num; | ||
942 | u8 iter_count; | ||
943 | __le16 iter_interval; | ||
944 | } __packed; /* SCAN_CHANNEL_CFG_S_VER2 */ | ||
945 | |||
946 | /** | ||
947 | * struct iwl_scan_umac_schedule | ||
948 | * @interval: interval in seconds between scan iterations | ||
949 | * @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop | ||
950 | * @reserved: for alignment and future use | ||
951 | */ | ||
952 | struct iwl_scan_umac_schedule { | ||
953 | __le16 interval; | ||
954 | u8 iter_count; | ||
955 | u8 reserved; | ||
956 | } __packed; /* SCAN_SCHED_PARAM_API_S_VER_1 */ | ||
957 | |||
958 | /** | ||
959 | * struct iwl_scan_req_umac_tail - the rest of the UMAC scan request command | ||
960 | * parameters following channels configuration array. | ||
961 | * @schedule: two scheduling plans. | ||
962 | * @delay: delay in TUs before starting the first scan iteration | ||
963 | * @reserved: for future use and alignment | ||
964 | * @preq: probe request with IEs blocks | ||
965 | * @direct_scan: list of SSIDs for directed active scan | ||
966 | */ | ||
967 | struct iwl_scan_req_umac_tail { | ||
968 | /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ | ||
969 | struct iwl_scan_umac_schedule schedule[2]; | ||
970 | __le16 delay; | ||
971 | __le16 reserved; | ||
972 | /* SCAN_PROBE_PARAMS_API_S_VER_1 */ | ||
973 | struct iwl_scan_probe_req preq; | ||
974 | struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; | ||
975 | } __packed; | ||
976 | |||
977 | /** | ||
978 | * struct iwl_scan_req_umac | ||
979 | * @hdr: umac command header | ||
980 | * @flags: &enum iwl_umac_scan_flags | ||
981 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | ||
982 | * @ooc_priority: out of channel priority - &enum iwl_scan_priority | ||
983 | * @general_flags: &enum iwl_umac_scan_general_flags | ||
984 | * @reserved1: for future use and alignment | ||
985 | * @active_dwell: dwell time for active scan | ||
986 | * @passive_dwell: dwell time for passive scan | ||
987 | * @fragmented_dwell: dwell time for fragmented passive scan | ||
988 | * @max_out_time: max out of serving channel time | ||
989 | * @suspend_time: max suspend time | ||
990 | * @scan_priority: scan internal prioritization &enum iwl_scan_priority | ||
991 | * @channel_flags: &enum iwl_scan_channel_flags | ||
992 | * @n_channels: num of channels in scan request | ||
993 | * @reserved2: for future use and alignment | ||
994 | * @data: &struct iwl_scan_channel_cfg_umac and | ||
995 | * &struct iwl_scan_req_umac_tail | ||
996 | */ | ||
997 | struct iwl_scan_req_umac { | ||
998 | struct iwl_mvm_umac_cmd_hdr hdr; | ||
999 | __le32 flags; | ||
1000 | __le32 uid; | ||
1001 | __le32 ooc_priority; | ||
1002 | /* SCAN_GENERAL_PARAMS_API_S_VER_1 */ | ||
1003 | __le32 general_flags; | ||
1004 | u8 reserved1; | ||
1005 | u8 active_dwell; | ||
1006 | u8 passive_dwell; | ||
1007 | u8 fragmented_dwell; | ||
1008 | __le32 max_out_time; | ||
1009 | __le32 suspend_time; | ||
1010 | __le32 scan_priority; | ||
1011 | /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ | ||
1012 | u8 channel_flags; | ||
1013 | u8 n_channels; | ||
1014 | __le16 reserved2; | ||
1015 | u8 data[]; | ||
1016 | } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ | ||
1017 | |||
1018 | /** | ||
1019 | * struct iwl_umac_scan_abort | ||
1020 | * @hdr: umac command header | ||
1021 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | ||
1022 | * @flags: reserved | ||
1023 | */ | ||
1024 | struct iwl_umac_scan_abort { | ||
1025 | struct iwl_mvm_umac_cmd_hdr hdr; | ||
1026 | __le32 uid; | ||
1027 | __le32 flags; | ||
1028 | } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */ | ||
1029 | |||
1030 | /** | ||
1031 | * struct iwl_umac_scan_complete | ||
1032 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | ||
1033 | * @last_schedule: last scheduling line | ||
1034 | * @last_iter: last scan iteration number | ||
1035 | * @scan status: &enum iwl_scan_offload_complete_status | ||
1036 | * @ebs_status: &enum iwl_scan_ebs_status | ||
1037 | * @time_from_last_iter: time elapsed from last iteration | ||
1038 | * @reserved: for future use | ||
1039 | */ | ||
1040 | struct iwl_umac_scan_complete { | ||
1041 | __le32 uid; | ||
1042 | u8 last_schedule; | ||
1043 | u8 last_iter; | ||
1044 | u8 status; | ||
1045 | u8 ebs_status; | ||
1046 | __le32 time_from_last_iter; | ||
1047 | __le32 reserved; | ||
1048 | } __packed; /* SCAN_COMPLETE_NTF_UMAC_API_S_VER_1 */ | ||
1049 | |||
1050 | #define SCAN_OFFLOAD_MATCHING_CHANNELS_LEN 5 | ||
1051 | /** | ||
1052 | * struct iwl_scan_offload_profile_match - match information | ||
1053 | * @bssid: matched bssid | ||
1054 | * @channel: channel where the match occurred | ||
1055 | * @energy: | ||
1056 | * @matching_feature: | ||
1057 | * @matching_channels: bitmap of channels that matched, referencing | ||
1058 | * the channels passed in tue scan offload request | ||
1059 | */ | ||
1060 | struct iwl_scan_offload_profile_match { | ||
1061 | u8 bssid[ETH_ALEN]; | ||
1062 | __le16 reserved; | ||
1063 | u8 channel; | ||
1064 | u8 energy; | ||
1065 | u8 matching_feature; | ||
1066 | u8 matching_channels[SCAN_OFFLOAD_MATCHING_CHANNELS_LEN]; | ||
1067 | } __packed; /* SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S_VER_1 */ | ||
1068 | |||
1069 | /** | ||
1070 | * struct iwl_scan_offload_profiles_query - match results query response | ||
1071 | * @matched_profiles: bitmap of matched profiles, referencing the | ||
1072 | * matches passed in the scan offload request | ||
1073 | * @last_scan_age: age of the last offloaded scan | ||
1074 | * @n_scans_done: number of offloaded scans done | ||
1075 | * @gp2_d0u: GP2 when D0U occurred | ||
1076 | * @gp2_invoked: GP2 when scan offload was invoked | ||
1077 | * @resume_while_scanning: not used | ||
1078 | * @self_recovery: obsolete | ||
1079 | * @reserved: reserved | ||
1080 | * @matches: array of match information, one for each match | ||
1081 | */ | ||
1082 | struct iwl_scan_offload_profiles_query { | ||
1083 | __le32 matched_profiles; | ||
1084 | __le32 last_scan_age; | ||
1085 | __le32 n_scans_done; | ||
1086 | __le32 gp2_d0u; | ||
1087 | __le32 gp2_invoked; | ||
1088 | u8 resume_while_scanning; | ||
1089 | u8 self_recovery; | ||
1090 | __le16 reserved; | ||
1091 | struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES]; | ||
1092 | } __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_2 */ | ||
1093 | |||
797 | #endif | 1094 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index c62575d86bcd..88af6dd2ceaa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -106,6 +106,12 @@ enum { | |||
106 | DBG_CFG = 0x9, | 106 | DBG_CFG = 0x9, |
107 | ANTENNA_COUPLING_NOTIFICATION = 0xa, | 107 | ANTENNA_COUPLING_NOTIFICATION = 0xa, |
108 | 108 | ||
109 | /* UMAC scan commands */ | ||
110 | SCAN_CFG_CMD = 0xc, | ||
111 | SCAN_REQ_UMAC = 0xd, | ||
112 | SCAN_ABORT_UMAC = 0xe, | ||
113 | SCAN_COMPLETE_UMAC = 0xf, | ||
114 | |||
109 | /* station table */ | 115 | /* station table */ |
110 | ADD_STA_KEY = 0x17, | 116 | ADD_STA_KEY = 0x17, |
111 | ADD_STA = 0x18, | 117 | ADD_STA = 0x18, |
@@ -122,6 +128,11 @@ enum { | |||
122 | /* global key */ | 128 | /* global key */ |
123 | WEP_KEY = 0x20, | 129 | WEP_KEY = 0x20, |
124 | 130 | ||
131 | /* TDLS */ | ||
132 | TDLS_CHANNEL_SWITCH_CMD = 0x27, | ||
133 | TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa, | ||
134 | TDLS_CONFIG_CMD = 0xa7, | ||
135 | |||
125 | /* MAC and Binding commands */ | 136 | /* MAC and Binding commands */ |
126 | MAC_CONTEXT_CMD = 0x28, | 137 | MAC_CONTEXT_CMD = 0x28, |
127 | TIME_EVENT_CMD = 0x29, /* both CMD and response */ | 138 | TIME_EVENT_CMD = 0x29, /* both CMD and response */ |
@@ -190,6 +201,8 @@ enum { | |||
190 | /* Power - new power table command */ | 201 | /* Power - new power table command */ |
191 | MAC_PM_POWER_TABLE = 0xa9, | 202 | MAC_PM_POWER_TABLE = 0xa9, |
192 | 203 | ||
204 | MFUART_LOAD_NOTIFICATION = 0xb1, | ||
205 | |||
193 | REPLY_RX_PHY_CMD = 0xc0, | 206 | REPLY_RX_PHY_CMD = 0xc0, |
194 | REPLY_RX_MPDU_CMD = 0xc1, | 207 | REPLY_RX_MPDU_CMD = 0xc1, |
195 | BA_NOTIF = 0xc5, | 208 | BA_NOTIF = 0xc5, |
@@ -236,11 +249,9 @@ enum { | |||
236 | WOWLAN_TX_POWER_PER_DB = 0xe6, | 249 | WOWLAN_TX_POWER_PER_DB = 0xe6, |
237 | 250 | ||
238 | /* and for NetDetect */ | 251 | /* and for NetDetect */ |
239 | NET_DETECT_CONFIG_CMD = 0x54, | 252 | SCAN_OFFLOAD_PROFILES_QUERY_CMD = 0x56, |
240 | NET_DETECT_PROFILES_QUERY_CMD = 0x56, | 253 | SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD = 0x58, |
241 | NET_DETECT_PROFILES_CMD = 0x57, | 254 | SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD = 0x59, |
242 | NET_DETECT_HOTSPOTS_CMD = 0x58, | ||
243 | NET_DETECT_HOTSPOTS_QUERY_CMD = 0x59, | ||
244 | 255 | ||
245 | REPLY_MAX = 0xff, | 256 | REPLY_MAX = 0xff, |
246 | }; | 257 | }; |
@@ -1201,6 +1212,21 @@ struct iwl_missed_beacons_notif { | |||
1201 | } __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */ | 1212 | } __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */ |
1202 | 1213 | ||
1203 | /** | 1214 | /** |
1215 | * struct iwl_mfuart_load_notif - mfuart image version & status | ||
1216 | * ( MFUART_LOAD_NOTIFICATION = 0xb1 ) | ||
1217 | * @installed_ver: installed image version | ||
1218 | * @external_ver: external image version | ||
1219 | * @status: MFUART loading status | ||
1220 | * @duration: MFUART loading time | ||
1221 | */ | ||
1222 | struct iwl_mfuart_load_notif { | ||
1223 | __le32 installed_ver; | ||
1224 | __le32 external_ver; | ||
1225 | __le32 status; | ||
1226 | __le32 duration; | ||
1227 | } __packed; /*MFU_LOADER_NTFY_API_S_VER_1*/ | ||
1228 | |||
1229 | /** | ||
1204 | * struct iwl_set_calib_default_cmd - set default value for calibration. | 1230 | * struct iwl_set_calib_default_cmd - set default value for calibration. |
1205 | * ( SET_CALIB_DEFAULT_CMD = 0x8e ) | 1231 | * ( SET_CALIB_DEFAULT_CMD = 0x8e ) |
1206 | * @calib_index: the calibration to set value for | 1232 | * @calib_index: the calibration to set value for |
@@ -1589,7 +1615,7 @@ enum iwl_sf_scenario { | |||
1589 | #define SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */ | 1615 | #define SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */ |
1590 | 1616 | ||
1591 | /* smart FIFO default values */ | 1617 | /* smart FIFO default values */ |
1592 | #define SF_W_MARK_SISO 4096 | 1618 | #define SF_W_MARK_SISO 6144 |
1593 | #define SF_W_MARK_MIMO2 8192 | 1619 | #define SF_W_MARK_MIMO2 8192 |
1594 | #define SF_W_MARK_MIMO3 6144 | 1620 | #define SF_W_MARK_MIMO3 6144 |
1595 | #define SF_W_MARK_LEGACY 4096 | 1621 | #define SF_W_MARK_LEGACY 4096 |
@@ -1711,4 +1737,145 @@ struct iwl_scd_txq_cfg_cmd { | |||
1711 | u8 flags; | 1737 | u8 flags; |
1712 | } __packed; | 1738 | } __packed; |
1713 | 1739 | ||
1740 | /*********************************** | ||
1741 | * TDLS API | ||
1742 | ***********************************/ | ||
1743 | |||
1744 | /* Type of TDLS request */ | ||
1745 | enum iwl_tdls_channel_switch_type { | ||
1746 | TDLS_SEND_CHAN_SW_REQ = 0, | ||
1747 | TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH, | ||
1748 | TDLS_MOVE_CH, | ||
1749 | }; /* TDLS_STA_CHANNEL_SWITCH_CMD_TYPE_API_E_VER_1 */ | ||
1750 | |||
1751 | /** | ||
1752 | * Switch timing sub-element in a TDLS channel-switch command | ||
1753 | * @frame_timestamp: GP2 timestamp of channel-switch request/response packet | ||
1754 | * received from peer | ||
1755 | * @max_offchan_duration: What amount of microseconds out of a DTIM is given | ||
1756 | * to the TDLS off-channel communication. For instance if the DTIM is | ||
1757 | * 200TU and the TDLS peer is to be given 25% of the time, the value | ||
1758 | * given will be 50TU, or 50 * 1024 if translated into microseconds. | ||
1759 | * @switch_time: switch time the peer sent in its channel switch timing IE | ||
1760 | * @switch_timout: switch timeout the peer sent in its channel switch timing IE | ||
1761 | */ | ||
1762 | struct iwl_tdls_channel_switch_timing { | ||
1763 | __le32 frame_timestamp; /* GP2 time of peer packet Rx */ | ||
1764 | __le32 max_offchan_duration; /* given in micro-seconds */ | ||
1765 | __le32 switch_time; /* given in micro-seconds */ | ||
1766 | __le32 switch_timeout; /* given in micro-seconds */ | ||
1767 | } __packed; /* TDLS_STA_CHANNEL_SWITCH_TIMING_DATA_API_S_VER_1 */ | ||
1768 | |||
1769 | #define IWL_TDLS_CH_SW_FRAME_MAX_SIZE 200 | ||
1770 | |||
1771 | /** | ||
1772 | * TDLS channel switch frame template | ||
1773 | * | ||
1774 | * A template representing a TDLS channel-switch request or response frame | ||
1775 | * | ||
1776 | * @switch_time_offset: offset to the channel switch timing IE in the template | ||
1777 | * @tx_cmd: Tx parameters for the frame | ||
1778 | * @data: frame data | ||
1779 | */ | ||
1780 | struct iwl_tdls_channel_switch_frame { | ||
1781 | __le32 switch_time_offset; | ||
1782 | struct iwl_tx_cmd tx_cmd; | ||
1783 | u8 data[IWL_TDLS_CH_SW_FRAME_MAX_SIZE]; | ||
1784 | } __packed; /* TDLS_STA_CHANNEL_SWITCH_FRAME_API_S_VER_1 */ | ||
1785 | |||
1786 | /** | ||
1787 | * TDLS channel switch command | ||
1788 | * | ||
1789 | * The command is sent to initiate a channel switch and also in response to | ||
1790 | * incoming TDLS channel-switch request/response packets from remote peers. | ||
1791 | * | ||
1792 | * @switch_type: see &enum iwl_tdls_channel_switch_type | ||
1793 | * @peer_sta_id: station id of TDLS peer | ||
1794 | * @ci: channel we switch to | ||
1795 | * @timing: timing related data for command | ||
1796 | * @frame: channel-switch request/response template, depending to switch_type | ||
1797 | */ | ||
1798 | struct iwl_tdls_channel_switch_cmd { | ||
1799 | u8 switch_type; | ||
1800 | __le32 peer_sta_id; | ||
1801 | struct iwl_fw_channel_info ci; | ||
1802 | struct iwl_tdls_channel_switch_timing timing; | ||
1803 | struct iwl_tdls_channel_switch_frame frame; | ||
1804 | } __packed; /* TDLS_STA_CHANNEL_SWITCH_CMD_API_S_VER_1 */ | ||
1805 | |||
1806 | /** | ||
1807 | * TDLS channel switch start notification | ||
1808 | * | ||
1809 | * @status: non-zero on success | ||
1810 | * @offchannel_duration: duration given in microseconds | ||
1811 | * @sta_id: peer currently performing the channel-switch with | ||
1812 | */ | ||
1813 | struct iwl_tdls_channel_switch_notif { | ||
1814 | __le32 status; | ||
1815 | __le32 offchannel_duration; | ||
1816 | __le32 sta_id; | ||
1817 | } __packed; /* TDLS_STA_CHANNEL_SWITCH_NTFY_API_S_VER_1 */ | ||
1818 | |||
1819 | /** | ||
1820 | * TDLS station info | ||
1821 | * | ||
1822 | * @sta_id: station id of the TDLS peer | ||
1823 | * @tx_to_peer_tid: TID reserved vs. the peer for FW based Tx | ||
1824 | * @tx_to_peer_ssn: initial SSN the FW should use for Tx on its TID vs the peer | ||
1825 | * @is_initiator: 1 if the peer is the TDLS link initiator, 0 otherwise | ||
1826 | */ | ||
1827 | struct iwl_tdls_sta_info { | ||
1828 | u8 sta_id; | ||
1829 | u8 tx_to_peer_tid; | ||
1830 | __le16 tx_to_peer_ssn; | ||
1831 | __le32 is_initiator; | ||
1832 | } __packed; /* TDLS_STA_INFO_VER_1 */ | ||
1833 | |||
1834 | /** | ||
1835 | * TDLS basic config command | ||
1836 | * | ||
1837 | * @id_and_color: MAC id and color being configured | ||
1838 | * @tdls_peer_count: amount of currently connected TDLS peers | ||
1839 | * @tx_to_ap_tid: TID reverved vs. the AP for FW based Tx | ||
1840 | * @tx_to_ap_ssn: initial SSN the FW should use for Tx on its TID vs. the AP | ||
1841 | * @sta_info: per-station info. Only the first tdls_peer_count entries are set | ||
1842 | * @pti_req_data_offset: offset of network-level data for the PTI template | ||
1843 | * @pti_req_tx_cmd: Tx parameters for PTI request template | ||
1844 | * @pti_req_template: PTI request template data | ||
1845 | */ | ||
1846 | struct iwl_tdls_config_cmd { | ||
1847 | __le32 id_and_color; /* mac id and color */ | ||
1848 | u8 tdls_peer_count; | ||
1849 | u8 tx_to_ap_tid; | ||
1850 | __le16 tx_to_ap_ssn; | ||
1851 | struct iwl_tdls_sta_info sta_info[IWL_MVM_TDLS_STA_COUNT]; | ||
1852 | |||
1853 | __le32 pti_req_data_offset; | ||
1854 | struct iwl_tx_cmd pti_req_tx_cmd; | ||
1855 | u8 pti_req_template[0]; | ||
1856 | } __packed; /* TDLS_CONFIG_CMD_API_S_VER_1 */ | ||
1857 | |||
1858 | /** | ||
1859 | * TDLS per-station config information from FW | ||
1860 | * | ||
1861 | * @sta_id: station id of the TDLS peer | ||
1862 | * @tx_to_peer_last_seq: last sequence number used by FW during FW-based Tx to | ||
1863 | * the peer | ||
1864 | */ | ||
1865 | struct iwl_tdls_config_sta_info_res { | ||
1866 | __le16 sta_id; | ||
1867 | __le16 tx_to_peer_last_seq; | ||
1868 | } __packed; /* TDLS_STA_INFO_RSP_VER_1 */ | ||
1869 | |||
1870 | /** | ||
1871 | * TDLS config information from FW | ||
1872 | * | ||
1873 | * @tx_to_ap_last_seq: last sequence number used by FW during FW-based Tx to AP | ||
1874 | * @sta_info: per-station TDLS config information | ||
1875 | */ | ||
1876 | struct iwl_tdls_config_res { | ||
1877 | __le32 tx_to_ap_last_seq; | ||
1878 | struct iwl_tdls_config_sta_info_res sta_info[IWL_MVM_TDLS_STA_COUNT]; | ||
1879 | } __packed; /* TDLS_CONFIG_RSP_API_S_VER_1 */ | ||
1880 | |||
1714 | #endif /* __fw_api_h__ */ | 1881 | #endif /* __fw_api_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index e0d9f19650b0..d0fa6e9ed590 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -186,7 +186,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | |||
186 | static const u8 alive_cmd[] = { MVM_ALIVE }; | 186 | static const u8 alive_cmd[] = { MVM_ALIVE }; |
187 | struct iwl_sf_region st_fwrd_space; | 187 | struct iwl_sf_region st_fwrd_space; |
188 | 188 | ||
189 | fw = iwl_get_ucode_image(mvm, ucode_type); | 189 | if (ucode_type == IWL_UCODE_REGULAR && |
190 | iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_CUSTOM) && | ||
191 | iwl_fw_dbg_conf_enabled(mvm->fw, FW_DBG_CUSTOM)) | ||
192 | fw = iwl_get_ucode_image(mvm, IWL_UCODE_REGULAR_USNIFFER); | ||
193 | else | ||
194 | fw = iwl_get_ucode_image(mvm, ucode_type); | ||
190 | if (WARN_ON(!fw)) | 195 | if (WARN_ON(!fw)) |
191 | return -EINVAL; | 196 | return -EINVAL; |
192 | mvm->cur_ucode = ucode_type; | 197 | mvm->cur_ucode = ucode_type; |
@@ -227,6 +232,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | |||
227 | st_fwrd_space.addr = mvm->sf_space.addr; | 232 | st_fwrd_space.addr = mvm->sf_space.addr; |
228 | st_fwrd_space.size = mvm->sf_space.size; | 233 | st_fwrd_space.size = mvm->sf_space.size; |
229 | ret = iwl_trans_update_sf(mvm->trans, &st_fwrd_space); | 234 | ret = iwl_trans_update_sf(mvm->trans, &st_fwrd_space); |
235 | if (ret) { | ||
236 | IWL_ERR(mvm, "Failed to update SF size. ret %d\n", ret); | ||
237 | return ret; | ||
238 | } | ||
230 | 239 | ||
231 | iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); | 240 | iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); |
232 | 241 | ||
@@ -284,7 +293,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
284 | 293 | ||
285 | lockdep_assert_held(&mvm->mutex); | 294 | lockdep_assert_held(&mvm->mutex); |
286 | 295 | ||
287 | if (WARN_ON_ONCE(mvm->init_ucode_complete)) | 296 | if (WARN_ON_ONCE(mvm->init_ucode_complete || mvm->calibrating)) |
288 | return 0; | 297 | return 0; |
289 | 298 | ||
290 | iwl_init_notification_wait(&mvm->notif_wait, | 299 | iwl_init_notification_wait(&mvm->notif_wait, |
@@ -334,6 +343,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
334 | goto out; | 343 | goto out; |
335 | } | 344 | } |
336 | 345 | ||
346 | mvm->calibrating = true; | ||
347 | |||
337 | /* Send TX valid antennas before triggering calibrations */ | 348 | /* Send TX valid antennas before triggering calibrations */ |
338 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); | 349 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); |
339 | if (ret) | 350 | if (ret) |
@@ -358,11 +369,17 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
358 | MVM_UCODE_CALIB_TIMEOUT); | 369 | MVM_UCODE_CALIB_TIMEOUT); |
359 | if (!ret) | 370 | if (!ret) |
360 | mvm->init_ucode_complete = true; | 371 | mvm->init_ucode_complete = true; |
372 | |||
373 | if (ret && iwl_mvm_is_radio_killed(mvm)) { | ||
374 | IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n"); | ||
375 | ret = 1; | ||
376 | } | ||
361 | goto out; | 377 | goto out; |
362 | 378 | ||
363 | error: | 379 | error: |
364 | iwl_remove_notification(&mvm->notif_wait, &calib_wait); | 380 | iwl_remove_notification(&mvm->notif_wait, &calib_wait); |
365 | out: | 381 | out: |
382 | mvm->calibrating = false; | ||
366 | if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { | 383 | if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { |
367 | /* we want to debug INIT and we have no NVM - fake */ | 384 | /* we want to debug INIT and we have no NVM - fake */ |
368 | mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + | 385 | mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + |
@@ -382,6 +399,42 @@ out: | |||
382 | return ret; | 399 | return ret; |
383 | } | 400 | } |
384 | 401 | ||
402 | static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, | ||
403 | enum iwl_fw_dbg_conf conf_id) | ||
404 | { | ||
405 | u8 *ptr; | ||
406 | int ret; | ||
407 | int i; | ||
408 | |||
409 | if (WARN_ONCE(conf_id >= ARRAY_SIZE(mvm->fw->dbg_conf_tlv), | ||
410 | "Invalid configuration %d\n", conf_id)) | ||
411 | return -EINVAL; | ||
412 | |||
413 | if (!mvm->fw->dbg_conf_tlv[conf_id]) | ||
414 | return -EINVAL; | ||
415 | |||
416 | if (mvm->fw_dbg_conf != FW_DBG_INVALID) | ||
417 | IWL_WARN(mvm, "FW already configured (%d) - re-configuring\n", | ||
418 | mvm->fw_dbg_conf); | ||
419 | |||
420 | /* Send all HCMDs for configuring the FW debug */ | ||
421 | ptr = (void *)&mvm->fw->dbg_conf_tlv[conf_id]->hcmd; | ||
422 | for (i = 0; i < mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) { | ||
423 | struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr; | ||
424 | |||
425 | ret = iwl_mvm_send_cmd_pdu(mvm, cmd->id, 0, | ||
426 | le16_to_cpu(cmd->len), cmd->data); | ||
427 | if (ret) | ||
428 | return ret; | ||
429 | |||
430 | ptr += sizeof(*cmd); | ||
431 | ptr += le16_to_cpu(cmd->len); | ||
432 | } | ||
433 | |||
434 | mvm->fw_dbg_conf = conf_id; | ||
435 | return ret; | ||
436 | } | ||
437 | |||
385 | int iwl_mvm_up(struct iwl_mvm *mvm) | 438 | int iwl_mvm_up(struct iwl_mvm *mvm) |
386 | { | 439 | { |
387 | int ret, i; | 440 | int ret, i; |
@@ -433,6 +486,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
433 | if (ret) | 486 | if (ret) |
434 | IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); | 487 | IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); |
435 | 488 | ||
489 | mvm->fw_dbg_conf = FW_DBG_INVALID; | ||
490 | iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_CUSTOM); | ||
491 | |||
436 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); | 492 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); |
437 | if (ret) | 493 | if (ret) |
438 | goto error; | 494 | goto error; |
@@ -454,6 +510,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
454 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) | 510 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) |
455 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); | 511 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); |
456 | 512 | ||
513 | mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT; | ||
514 | |||
457 | /* reset quota debouncing buffer - 0xff will yield invalid data */ | 515 | /* reset quota debouncing buffer - 0xff will yield invalid data */ |
458 | memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); | 516 | memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); |
459 | 517 | ||
@@ -493,6 +551,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
493 | if (ret) | 551 | if (ret) |
494 | goto error; | 552 | goto error; |
495 | 553 | ||
554 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { | ||
555 | ret = iwl_mvm_config_scan(mvm); | ||
556 | if (ret) | ||
557 | goto error; | ||
558 | } | ||
559 | |||
496 | /* allow FW/transport low power modes if not during restart */ | 560 | /* allow FW/transport low power modes if not during restart */ |
497 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | 561 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) |
498 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); | 562 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); |
@@ -579,3 +643,19 @@ int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
579 | le32_to_cpu(radio_version->radio_dash)); | 643 | le32_to_cpu(radio_version->radio_dash)); |
580 | return 0; | 644 | return 0; |
581 | } | 645 | } |
646 | |||
647 | int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, | ||
648 | struct iwl_rx_cmd_buffer *rxb, | ||
649 | struct iwl_device_cmd *cmd) | ||
650 | { | ||
651 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
652 | struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data; | ||
653 | |||
654 | IWL_DEBUG_INFO(mvm, | ||
655 | "MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x\n", | ||
656 | le32_to_cpu(mfuart_notif->installed_ver), | ||
657 | le32_to_cpu(mfuart_notif->external_ver), | ||
658 | le32_to_cpu(mfuart_notif->status), | ||
659 | le32_to_cpu(mfuart_notif->duration)); | ||
660 | return 0; | ||
661 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index b8ab4a108720..f6d86ccce6a8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -83,11 +83,15 @@ struct iwl_mvm_mac_iface_iterator_data { | |||
83 | struct ieee80211_vif *vif; | 83 | struct ieee80211_vif *vif; |
84 | unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)]; | 84 | unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)]; |
85 | unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)]; | 85 | unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)]; |
86 | u32 used_hw_queues; | ||
87 | enum iwl_tsf_id preferred_tsf; | 86 | enum iwl_tsf_id preferred_tsf; |
88 | bool found_vif; | 87 | bool found_vif; |
89 | }; | 88 | }; |
90 | 89 | ||
90 | struct iwl_mvm_hw_queues_iface_iterator_data { | ||
91 | struct ieee80211_vif *exclude_vif; | ||
92 | unsigned long used_hw_queues; | ||
93 | }; | ||
94 | |||
91 | static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, | 95 | static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, |
92 | struct ieee80211_vif *vif) | 96 | struct ieee80211_vif *vif) |
93 | { | 97 | { |
@@ -213,6 +217,54 @@ u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif) | |||
213 | return qmask; | 217 | return qmask; |
214 | } | 218 | } |
215 | 219 | ||
220 | static void iwl_mvm_iface_hw_queues_iter(void *_data, u8 *mac, | ||
221 | struct ieee80211_vif *vif) | ||
222 | { | ||
223 | struct iwl_mvm_hw_queues_iface_iterator_data *data = _data; | ||
224 | |||
225 | /* exclude the given vif */ | ||
226 | if (vif == data->exclude_vif) | ||
227 | return; | ||
228 | |||
229 | data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif); | ||
230 | } | ||
231 | |||
232 | static void iwl_mvm_mac_sta_hw_queues_iter(void *_data, | ||
233 | struct ieee80211_sta *sta) | ||
234 | { | ||
235 | struct iwl_mvm_hw_queues_iface_iterator_data *data = _data; | ||
236 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
237 | |||
238 | /* Mark the queues used by the sta */ | ||
239 | data->used_hw_queues |= mvmsta->tfd_queue_msk; | ||
240 | } | ||
241 | |||
242 | unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, | ||
243 | struct ieee80211_vif *exclude_vif) | ||
244 | { | ||
245 | struct iwl_mvm_hw_queues_iface_iterator_data data = { | ||
246 | .exclude_vif = exclude_vif, | ||
247 | .used_hw_queues = | ||
248 | BIT(IWL_MVM_OFFCHANNEL_QUEUE) | | ||
249 | BIT(mvm->aux_queue) | | ||
250 | BIT(IWL_MVM_CMD_QUEUE), | ||
251 | }; | ||
252 | |||
253 | lockdep_assert_held(&mvm->mutex); | ||
254 | |||
255 | /* mark all VIF used hw queues */ | ||
256 | ieee80211_iterate_active_interfaces_atomic( | ||
257 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | ||
258 | iwl_mvm_iface_hw_queues_iter, &data); | ||
259 | |||
260 | /* don't assign the same hw queues as TDLS stations */ | ||
261 | ieee80211_iterate_stations_atomic(mvm->hw, | ||
262 | iwl_mvm_mac_sta_hw_queues_iter, | ||
263 | &data); | ||
264 | |||
265 | return data.used_hw_queues; | ||
266 | } | ||
267 | |||
216 | static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | 268 | static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, |
217 | struct ieee80211_vif *vif) | 269 | struct ieee80211_vif *vif) |
218 | { | 270 | { |
@@ -225,9 +277,6 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | |||
225 | return; | 277 | return; |
226 | } | 278 | } |
227 | 279 | ||
228 | /* Mark the queues used by the vif */ | ||
229 | data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif); | ||
230 | |||
231 | /* Mark MAC IDs as used by clearing the available bit, and | 280 | /* Mark MAC IDs as used by clearing the available bit, and |
232 | * (below) mark TSFs as used if their existing use is not | 281 | * (below) mark TSFs as used if their existing use is not |
233 | * compatible with the new interface type. | 282 | * compatible with the new interface type. |
@@ -274,10 +323,6 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
274 | .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 }, | 323 | .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 }, |
275 | /* no preference yet */ | 324 | /* no preference yet */ |
276 | .preferred_tsf = NUM_TSF_IDS, | 325 | .preferred_tsf = NUM_TSF_IDS, |
277 | .used_hw_queues = | ||
278 | BIT(IWL_MVM_OFFCHANNEL_QUEUE) | | ||
279 | BIT(mvm->aux_queue) | | ||
280 | BIT(IWL_MVM_CMD_QUEUE), | ||
281 | .found_vif = false, | 326 | .found_vif = false, |
282 | }; | 327 | }; |
283 | u32 ac; | 328 | u32 ac; |
@@ -316,6 +361,8 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
316 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | 361 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
317 | iwl_mvm_mac_iface_iterator, &data); | 362 | iwl_mvm_mac_iface_iterator, &data); |
318 | 363 | ||
364 | used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, vif); | ||
365 | |||
319 | /* | 366 | /* |
320 | * In the case we're getting here during resume, it's similar to | 367 | * In the case we're getting here during resume, it's similar to |
321 | * firmware restart, and with RESUME_ALL the iterator will find | 368 | * firmware restart, and with RESUME_ALL the iterator will find |
@@ -365,8 +412,6 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
365 | return 0; | 412 | return 0; |
366 | } | 413 | } |
367 | 414 | ||
368 | used_hw_queues = data.used_hw_queues; | ||
369 | |||
370 | /* Find available queues, and allocate them to the ACs */ | 415 | /* Find available queues, and allocate them to the ACs */ |
371 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 416 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
372 | u8 queue = find_first_zero_bit(&used_hw_queues, | 417 | u8 queue = find_first_zero_bit(&used_hw_queues, |
@@ -1218,17 +1263,25 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
1218 | } | 1263 | } |
1219 | 1264 | ||
1220 | static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, | 1265 | static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, |
1221 | struct ieee80211_vif *csa_vif, u32 gp2) | 1266 | struct ieee80211_vif *csa_vif, u32 gp2, |
1267 | bool tx_success) | ||
1222 | { | 1268 | { |
1223 | struct iwl_mvm_vif *mvmvif = | 1269 | struct iwl_mvm_vif *mvmvif = |
1224 | iwl_mvm_vif_from_mac80211(csa_vif); | 1270 | iwl_mvm_vif_from_mac80211(csa_vif); |
1225 | 1271 | ||
1272 | /* Don't start to countdown from a failed beacon */ | ||
1273 | if (!tx_success && !mvmvif->csa_countdown) | ||
1274 | return; | ||
1275 | |||
1276 | mvmvif->csa_countdown = true; | ||
1277 | |||
1226 | if (!ieee80211_csa_is_complete(csa_vif)) { | 1278 | if (!ieee80211_csa_is_complete(csa_vif)) { |
1227 | int c = ieee80211_csa_update_counter(csa_vif); | 1279 | int c = ieee80211_csa_update_counter(csa_vif); |
1228 | 1280 | ||
1229 | iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); | 1281 | iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); |
1230 | if (csa_vif->p2p && | 1282 | if (csa_vif->p2p && |
1231 | !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) { | 1283 | !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2 && |
1284 | tx_success) { | ||
1232 | u32 rel_time = (c + 1) * | 1285 | u32 rel_time = (c + 1) * |
1233 | csa_vif->bss_conf.beacon_int - | 1286 | csa_vif->bss_conf.beacon_int - |
1234 | IWL_MVM_CHANNEL_SWITCH_TIME_GO; | 1287 | IWL_MVM_CHANNEL_SWITCH_TIME_GO; |
@@ -1251,38 +1304,30 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | |||
1251 | struct iwl_device_cmd *cmd) | 1304 | struct iwl_device_cmd *cmd) |
1252 | { | 1305 | { |
1253 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 1306 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
1307 | struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; | ||
1254 | struct iwl_mvm_tx_resp *beacon_notify_hdr; | 1308 | struct iwl_mvm_tx_resp *beacon_notify_hdr; |
1255 | struct ieee80211_vif *csa_vif; | 1309 | struct ieee80211_vif *csa_vif; |
1256 | struct ieee80211_vif *tx_blocked_vif; | 1310 | struct ieee80211_vif *tx_blocked_vif; |
1257 | u64 tsf; | 1311 | u16 status; |
1258 | 1312 | ||
1259 | lockdep_assert_held(&mvm->mutex); | 1313 | lockdep_assert_held(&mvm->mutex); |
1260 | 1314 | ||
1261 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_CAPA_EXTENDED_BEACON) { | 1315 | beacon_notify_hdr = &beacon->beacon_notify_hdr; |
1262 | struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; | 1316 | mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2); |
1263 | |||
1264 | beacon_notify_hdr = &beacon->beacon_notify_hdr; | ||
1265 | tsf = le64_to_cpu(beacon->tsf); | ||
1266 | mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2); | ||
1267 | } else { | ||
1268 | struct iwl_beacon_notif *beacon = (void *)pkt->data; | ||
1269 | |||
1270 | beacon_notify_hdr = &beacon->beacon_notify_hdr; | ||
1271 | tsf = le64_to_cpu(beacon->tsf); | ||
1272 | } | ||
1273 | 1317 | ||
1318 | status = le16_to_cpu(beacon_notify_hdr->status.status) & TX_STATUS_MSK; | ||
1274 | IWL_DEBUG_RX(mvm, | 1319 | IWL_DEBUG_RX(mvm, |
1275 | "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", | 1320 | "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", |
1276 | le16_to_cpu(beacon_notify_hdr->status.status) & | 1321 | status, beacon_notify_hdr->failure_frame, |
1277 | TX_STATUS_MSK, | 1322 | le64_to_cpu(beacon->tsf), |
1278 | beacon_notify_hdr->failure_frame, tsf, | ||
1279 | mvm->ap_last_beacon_gp2, | 1323 | mvm->ap_last_beacon_gp2, |
1280 | le32_to_cpu(beacon_notify_hdr->initial_rate)); | 1324 | le32_to_cpu(beacon_notify_hdr->initial_rate)); |
1281 | 1325 | ||
1282 | csa_vif = rcu_dereference_protected(mvm->csa_vif, | 1326 | csa_vif = rcu_dereference_protected(mvm->csa_vif, |
1283 | lockdep_is_held(&mvm->mutex)); | 1327 | lockdep_is_held(&mvm->mutex)); |
1284 | if (unlikely(csa_vif && csa_vif->csa_active)) | 1328 | if (unlikely(csa_vif && csa_vif->csa_active)) |
1285 | iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2); | 1329 | iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2, |
1330 | (status == TX_STATUS_SUCCESS)); | ||
1286 | 1331 | ||
1287 | tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif, | 1332 | tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif, |
1288 | lockdep_is_held(&mvm->mutex)); | 1333 | lockdep_is_held(&mvm->mutex)); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 3276b31898da..31a5b3f4266c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -254,6 +254,26 @@ static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm, | |||
254 | spin_unlock_bh(&mvm->refs_lock); | 254 | spin_unlock_bh(&mvm->refs_lock); |
255 | } | 255 | } |
256 | 256 | ||
257 | bool iwl_mvm_ref_taken(struct iwl_mvm *mvm) | ||
258 | { | ||
259 | int i; | ||
260 | bool taken = false; | ||
261 | |||
262 | if (!iwl_mvm_is_d0i3_supported(mvm)) | ||
263 | return true; | ||
264 | |||
265 | spin_lock_bh(&mvm->refs_lock); | ||
266 | for (i = 0; i < IWL_MVM_REF_COUNT; i++) { | ||
267 | if (mvm->refs[i]) { | ||
268 | taken = true; | ||
269 | break; | ||
270 | } | ||
271 | } | ||
272 | spin_unlock_bh(&mvm->refs_lock); | ||
273 | |||
274 | return taken; | ||
275 | } | ||
276 | |||
257 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | 277 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) |
258 | { | 278 | { |
259 | iwl_mvm_ref(mvm, ref_type); | 279 | iwl_mvm_ref(mvm, ref_type); |
@@ -303,7 +323,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
303 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; | 323 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; |
304 | hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | | 324 | hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | |
305 | IEEE80211_RADIOTAP_MCS_HAVE_STBC; | 325 | IEEE80211_RADIOTAP_MCS_HAVE_STBC; |
306 | hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC; | 326 | hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC | |
327 | IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED; | ||
307 | hw->rate_control_algorithm = "iwl-mvm-rs"; | 328 | hw->rate_control_algorithm = "iwl-mvm-rs"; |
308 | 329 | ||
309 | /* | 330 | /* |
@@ -316,15 +337,19 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
316 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | 337 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; |
317 | 338 | ||
318 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && | 339 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && |
319 | IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 && | ||
320 | !iwlwifi_mod_params.uapsd_disable) { | 340 | !iwlwifi_mod_params.uapsd_disable) { |
321 | hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; | 341 | hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; |
322 | hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; | 342 | hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; |
323 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; | 343 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; |
324 | } | 344 | } |
325 | 345 | ||
326 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 346 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN || |
347 | mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { | ||
327 | hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; | 348 | hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; |
349 | hw->wiphy->features |= | ||
350 | NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | | ||
351 | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; | ||
352 | } | ||
328 | 353 | ||
329 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); | 354 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); |
330 | hw->vif_data_size = sizeof(struct iwl_mvm_vif); | 355 | hw->vif_data_size = sizeof(struct iwl_mvm_vif); |
@@ -344,8 +369,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
344 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) | 369 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) |
345 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | 370 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; |
346 | 371 | ||
347 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_CSA_FLOW) | 372 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; |
348 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; | ||
349 | 373 | ||
350 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; | 374 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; |
351 | hw->wiphy->n_iface_combinations = | 375 | hw->wiphy->n_iface_combinations = |
@@ -403,7 +427,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
403 | NL80211_FEATURE_LOW_PRIORITY_SCAN | | 427 | NL80211_FEATURE_LOW_PRIORITY_SCAN | |
404 | NL80211_FEATURE_P2P_GO_OPPPS | | 428 | NL80211_FEATURE_P2P_GO_OPPPS | |
405 | NL80211_FEATURE_DYNAMIC_SMPS | | 429 | NL80211_FEATURE_DYNAMIC_SMPS | |
406 | NL80211_FEATURE_STATIC_SMPS; | 430 | NL80211_FEATURE_STATIC_SMPS | |
431 | NL80211_FEATURE_SUPPORTS_WMM_ADMISSION; | ||
407 | 432 | ||
408 | if (mvm->fw->ucode_capa.capa[0] & | 433 | if (mvm->fw->ucode_capa.capa[0] & |
409 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) | 434 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) |
@@ -441,7 +466,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
441 | mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | | 466 | mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | |
442 | WIPHY_WOWLAN_DISCONNECT | | 467 | WIPHY_WOWLAN_DISCONNECT | |
443 | WIPHY_WOWLAN_EAP_IDENTITY_REQ | | 468 | WIPHY_WOWLAN_EAP_IDENTITY_REQ | |
444 | WIPHY_WOWLAN_RFKILL_RELEASE; | 469 | WIPHY_WOWLAN_RFKILL_RELEASE | |
470 | WIPHY_WOWLAN_NET_DETECT; | ||
445 | if (!iwlwifi_mod_params.sw_crypto) | 471 | if (!iwlwifi_mod_params.sw_crypto) |
446 | mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | | 472 | mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | |
447 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | | 473 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | |
@@ -450,6 +476,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
450 | mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; | 476 | mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; |
451 | mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; | 477 | mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; |
452 | mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; | 478 | mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; |
479 | mvm->wowlan.max_nd_match_sets = IWL_SCAN_MAX_PROFILES; | ||
453 | mvm->wowlan.tcp = &iwl_mvm_wowlan_tcp_support; | 480 | mvm->wowlan.tcp = &iwl_mvm_wowlan_tcp_support; |
454 | hw->wiphy->wowlan = &mvm->wowlan; | 481 | hw->wiphy->wowlan = &mvm->wowlan; |
455 | } | 482 | } |
@@ -464,6 +491,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
464 | if (ret) | 491 | if (ret) |
465 | return ret; | 492 | return ret; |
466 | 493 | ||
494 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_TDLS_SUPPORT) { | ||
495 | IWL_DEBUG_TDLS(mvm, "TDLS supported\n"); | ||
496 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; | ||
497 | } | ||
498 | |||
499 | if (mvm->fw->ucode_capa.capa[0] & | ||
500 | IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH) { | ||
501 | IWL_DEBUG_TDLS(mvm, "TDLS channel switch supported\n"); | ||
502 | hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; | ||
503 | } | ||
504 | |||
467 | ret = ieee80211_register_hw(mvm->hw); | 505 | ret = ieee80211_register_hw(mvm->hw); |
468 | if (ret) | 506 | if (ret) |
469 | iwl_mvm_leds_exit(mvm); | 507 | iwl_mvm_leds_exit(mvm); |
@@ -819,12 +857,18 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | |||
819 | 857 | ||
820 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | 858 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) |
821 | { | 859 | { |
822 | iwl_mvm_fw_error_dump(mvm); | 860 | /* clear the D3 reconfig, we only need it to avoid dumping a |
861 | * firmware coredump on reconfiguration, we shouldn't do that | ||
862 | * on D3->D0 transition | ||
863 | */ | ||
864 | if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) | ||
865 | iwl_mvm_fw_error_dump(mvm); | ||
823 | 866 | ||
824 | iwl_trans_stop_device(mvm->trans); | 867 | iwl_trans_stop_device(mvm->trans); |
825 | 868 | ||
826 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 869 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
827 | mvm->ps_disabled = false; | 870 | mvm->ps_disabled = false; |
871 | mvm->calibrating = false; | ||
828 | 872 | ||
829 | /* just in case one was running */ | 873 | /* just in case one was running */ |
830 | ieee80211_remain_on_channel_expired(mvm->hw); | 874 | ieee80211_remain_on_channel_expired(mvm->hw); |
@@ -839,6 +883,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | |||
839 | iwl_mvm_reset_phy_ctxts(mvm); | 883 | iwl_mvm_reset_phy_ctxts(mvm); |
840 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | 884 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
841 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); | 885 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); |
886 | memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained)); | ||
842 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | 887 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); |
843 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); | 888 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); |
844 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); | 889 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); |
@@ -895,9 +940,8 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) | |||
895 | return ret; | 940 | return ret; |
896 | } | 941 | } |
897 | 942 | ||
898 | static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) | 943 | static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) |
899 | { | 944 | { |
900 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
901 | int ret; | 945 | int ret; |
902 | 946 | ||
903 | mutex_lock(&mvm->mutex); | 947 | mutex_lock(&mvm->mutex); |
@@ -912,9 +956,50 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) | |||
912 | /* allow transport/FW low power modes */ | 956 | /* allow transport/FW low power modes */ |
913 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); | 957 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); |
914 | 958 | ||
959 | /* | ||
960 | * If we have TDLS peers, remove them. We don't know the last seqno/PN | ||
961 | * of packets the FW sent out, so we must reconnect. | ||
962 | */ | ||
963 | iwl_mvm_teardown_tdls_peers(mvm); | ||
964 | |||
915 | mutex_unlock(&mvm->mutex); | 965 | mutex_unlock(&mvm->mutex); |
916 | } | 966 | } |
917 | 967 | ||
968 | static void iwl_mvm_resume_complete(struct iwl_mvm *mvm) | ||
969 | { | ||
970 | bool exit_now; | ||
971 | |||
972 | if (!iwl_mvm_is_d0i3_supported(mvm)) | ||
973 | return; | ||
974 | |||
975 | mutex_lock(&mvm->d0i3_suspend_mutex); | ||
976 | __clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); | ||
977 | exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, | ||
978 | &mvm->d0i3_suspend_flags); | ||
979 | mutex_unlock(&mvm->d0i3_suspend_mutex); | ||
980 | |||
981 | if (exit_now) { | ||
982 | IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n"); | ||
983 | _iwl_mvm_exit_d0i3(mvm); | ||
984 | } | ||
985 | } | ||
986 | |||
987 | static void | ||
988 | iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw, | ||
989 | enum ieee80211_reconfig_type reconfig_type) | ||
990 | { | ||
991 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
992 | |||
993 | switch (reconfig_type) { | ||
994 | case IEEE80211_RECONFIG_TYPE_RESTART: | ||
995 | iwl_mvm_restart_complete(mvm); | ||
996 | break; | ||
997 | case IEEE80211_RECONFIG_TYPE_SUSPEND: | ||
998 | iwl_mvm_resume_complete(mvm); | ||
999 | break; | ||
1000 | } | ||
1001 | } | ||
1002 | |||
918 | void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) | 1003 | void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) |
919 | { | 1004 | { |
920 | lockdep_assert_held(&mvm->mutex); | 1005 | lockdep_assert_held(&mvm->mutex); |
@@ -1874,9 +1959,11 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
1874 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) | 1959 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) |
1875 | return -EINVAL; | 1960 | return -EINVAL; |
1876 | 1961 | ||
1877 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED); | 1962 | if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { |
1878 | if (ret) | 1963 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED); |
1879 | return ret; | 1964 | if (ret) |
1965 | return ret; | ||
1966 | } | ||
1880 | 1967 | ||
1881 | mutex_lock(&mvm->mutex); | 1968 | mutex_lock(&mvm->mutex); |
1882 | 1969 | ||
@@ -1887,7 +1974,9 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
1887 | 1974 | ||
1888 | iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); | 1975 | iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); |
1889 | 1976 | ||
1890 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 1977 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) |
1978 | ret = iwl_mvm_scan_umac(mvm, vif, hw_req); | ||
1979 | else if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | ||
1891 | ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req); | 1980 | ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req); |
1892 | else | 1981 | else |
1893 | ret = iwl_mvm_scan_request(mvm, vif, req); | 1982 | ret = iwl_mvm_scan_request(mvm, vif, req); |
@@ -2104,6 +2193,15 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | |||
2104 | out_unlock: | 2193 | out_unlock: |
2105 | mutex_unlock(&mvm->mutex); | 2194 | mutex_unlock(&mvm->mutex); |
2106 | 2195 | ||
2196 | if (sta->tdls && ret == 0) { | ||
2197 | if (old_state == IEEE80211_STA_NOTEXIST && | ||
2198 | new_state == IEEE80211_STA_NONE) | ||
2199 | ieee80211_reserve_tid(sta, IWL_MVM_TDLS_FW_TID); | ||
2200 | else if (old_state == IEEE80211_STA_NONE && | ||
2201 | new_state == IEEE80211_STA_NOTEXIST) | ||
2202 | ieee80211_unreserve_tid(sta, IWL_MVM_TDLS_FW_TID); | ||
2203 | } | ||
2204 | |||
2107 | return ret; | 2205 | return ret; |
2108 | } | 2206 | } |
2109 | 2207 | ||
@@ -2186,9 +2284,11 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
2186 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2284 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2187 | int ret; | 2285 | int ret; |
2188 | 2286 | ||
2189 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS); | 2287 | if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { |
2190 | if (ret) | 2288 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS); |
2191 | return ret; | 2289 | if (ret) |
2290 | return ret; | ||
2291 | } | ||
2192 | 2292 | ||
2193 | mutex_lock(&mvm->mutex); | 2293 | mutex_lock(&mvm->mutex); |
2194 | 2294 | ||
@@ -2208,11 +2308,10 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
2208 | goto out; | 2308 | goto out; |
2209 | } | 2309 | } |
2210 | 2310 | ||
2211 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | ||
2212 | |||
2213 | ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies); | 2311 | ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies); |
2214 | if (ret) | 2312 | if (ret) |
2215 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 2313 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
2314 | |||
2216 | out: | 2315 | out: |
2217 | mutex_unlock(&mvm->mutex); | 2316 | mutex_unlock(&mvm->mutex); |
2218 | return ret; | 2317 | return ret; |
@@ -2230,6 +2329,7 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, | |||
2230 | iwl_mvm_wait_for_async_handlers(mvm); | 2329 | iwl_mvm_wait_for_async_handlers(mvm); |
2231 | 2330 | ||
2232 | return ret; | 2331 | return ret; |
2332 | |||
2233 | } | 2333 | } |
2234 | 2334 | ||
2235 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | 2335 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, |
@@ -2258,12 +2358,16 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | |||
2258 | break; | 2358 | break; |
2259 | case WLAN_CIPHER_SUITE_WEP40: | 2359 | case WLAN_CIPHER_SUITE_WEP40: |
2260 | case WLAN_CIPHER_SUITE_WEP104: | 2360 | case WLAN_CIPHER_SUITE_WEP104: |
2261 | /* | 2361 | /* For non-client mode, only use WEP keys for TX as we probably |
2262 | * Support for TX only, at least for now, so accept | 2362 | * don't have a station yet anyway and would then have to keep |
2263 | * the key and do nothing else. Then mac80211 will | 2363 | * track of the keys, linking them to each of the clients/peers |
2264 | * pass it for TX but we don't have to use it for RX. | 2364 | * as they appear. For now, don't do that, for performance WEP |
2365 | * offload doesn't really matter much, but we need it for some | ||
2366 | * other offload features in client mode. | ||
2265 | */ | 2367 | */ |
2266 | return 0; | 2368 | if (vif->type != NL80211_IFTYPE_STATION) |
2369 | return 0; | ||
2370 | break; | ||
2267 | default: | 2371 | default: |
2268 | /* currently FW supports only one optional cipher scheme */ | 2372 | /* currently FW supports only one optional cipher scheme */ |
2269 | if (hw->n_cipher_schemes && | 2373 | if (hw->n_cipher_schemes && |
@@ -2471,9 +2575,15 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, | |||
2471 | 2575 | ||
2472 | switch (vif->type) { | 2576 | switch (vif->type) { |
2473 | case NL80211_IFTYPE_STATION: | 2577 | case NL80211_IFTYPE_STATION: |
2474 | /* Use aux roc framework (HS20) */ | 2578 | if (mvm->fw->ucode_capa.capa[0] & |
2475 | ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, | 2579 | IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT) { |
2476 | vif, duration); | 2580 | /* Use aux roc framework (HS20) */ |
2581 | ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, | ||
2582 | vif, duration); | ||
2583 | goto out_unlock; | ||
2584 | } | ||
2585 | IWL_ERR(mvm, "hotspot not supported\n"); | ||
2586 | ret = -EINVAL; | ||
2477 | goto out_unlock; | 2587 | goto out_unlock; |
2478 | case NL80211_IFTYPE_P2P_DEVICE: | 2588 | case NL80211_IFTYPE_P2P_DEVICE: |
2479 | /* handle below */ | 2589 | /* handle below */ |
@@ -2580,7 +2690,7 @@ static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw) | |||
2580 | IWL_DEBUG_MAC80211(mvm, "enter\n"); | 2690 | IWL_DEBUG_MAC80211(mvm, "enter\n"); |
2581 | 2691 | ||
2582 | mutex_lock(&mvm->mutex); | 2692 | mutex_lock(&mvm->mutex); |
2583 | iwl_mvm_stop_p2p_roc(mvm); | 2693 | iwl_mvm_stop_roc(mvm); |
2584 | mutex_unlock(&mvm->mutex); | 2694 | mutex_unlock(&mvm->mutex); |
2585 | 2695 | ||
2586 | IWL_DEBUG_MAC80211(mvm, "leave\n"); | 2696 | IWL_DEBUG_MAC80211(mvm, "leave\n"); |
@@ -2693,8 +2803,8 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, | |||
2693 | 2803 | ||
2694 | switch (vif->type) { | 2804 | switch (vif->type) { |
2695 | case NL80211_IFTYPE_AP: | 2805 | case NL80211_IFTYPE_AP: |
2696 | /* Unless it's a CSA flow we have nothing to do here */ | 2806 | /* only needed if we're switching chanctx (i.e. during CSA) */ |
2697 | if (vif->csa_active) { | 2807 | if (switching_chanctx) { |
2698 | mvmvif->ap_ibss_active = true; | 2808 | mvmvif->ap_ibss_active = true; |
2699 | break; | 2809 | break; |
2700 | } | 2810 | } |
@@ -2738,23 +2848,32 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, | |||
2738 | } | 2848 | } |
2739 | 2849 | ||
2740 | /* Handle binding during CSA */ | 2850 | /* Handle binding during CSA */ |
2741 | if ((vif->type == NL80211_IFTYPE_AP) || | 2851 | if (vif->type == NL80211_IFTYPE_AP) { |
2742 | (switching_chanctx && (vif->type == NL80211_IFTYPE_STATION))) { | ||
2743 | iwl_mvm_update_quotas(mvm, NULL); | 2852 | iwl_mvm_update_quotas(mvm, NULL); |
2744 | iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); | 2853 | iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); |
2745 | } | 2854 | } |
2746 | 2855 | ||
2747 | if (vif->csa_active && vif->type == NL80211_IFTYPE_STATION) { | 2856 | if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) { |
2748 | struct iwl_mvm_sta *mvmsta; | 2857 | u32 duration = 2 * vif->bss_conf.beacon_int; |
2749 | 2858 | ||
2750 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, | 2859 | /* iwl_mvm_protect_session() reads directly from the |
2751 | mvmvif->ap_sta_id); | 2860 | * device (the system time), so make sure it is |
2861 | * available. | ||
2862 | */ | ||
2863 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_CSA); | ||
2864 | if (ret) | ||
2865 | goto out_remove_binding; | ||
2752 | 2866 | ||
2753 | if (WARN_ON(!mvmsta)) | 2867 | /* Protect the session to make sure we hear the first |
2754 | goto out; | 2868 | * beacon on the new channel. |
2869 | */ | ||
2870 | iwl_mvm_protect_session(mvm, vif, duration, duration, | ||
2871 | vif->bss_conf.beacon_int / 2, | ||
2872 | true); | ||
2755 | 2873 | ||
2756 | /* TODO: only re-enable after the first beacon */ | 2874 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA); |
2757 | iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false); | 2875 | |
2876 | iwl_mvm_update_quotas(mvm, NULL); | ||
2758 | } | 2877 | } |
2759 | 2878 | ||
2760 | goto out; | 2879 | goto out; |
@@ -2788,7 +2907,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | |||
2788 | { | 2907 | { |
2789 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 2908 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
2790 | struct ieee80211_vif *disabled_vif = NULL; | 2909 | struct ieee80211_vif *disabled_vif = NULL; |
2791 | struct iwl_mvm_sta *mvmsta; | ||
2792 | 2910 | ||
2793 | lockdep_assert_held(&mvm->mutex); | 2911 | lockdep_assert_held(&mvm->mutex); |
2794 | 2912 | ||
@@ -2803,9 +2921,11 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | |||
2803 | break; | 2921 | break; |
2804 | case NL80211_IFTYPE_AP: | 2922 | case NL80211_IFTYPE_AP: |
2805 | /* This part is triggered only during CSA */ | 2923 | /* This part is triggered only during CSA */ |
2806 | if (!vif->csa_active || !mvmvif->ap_ibss_active) | 2924 | if (!switching_chanctx || !mvmvif->ap_ibss_active) |
2807 | goto out; | 2925 | goto out; |
2808 | 2926 | ||
2927 | mvmvif->csa_countdown = false; | ||
2928 | |||
2809 | /* Set CS bit on all the stations */ | 2929 | /* Set CS bit on all the stations */ |
2810 | iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true); | 2930 | iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true); |
2811 | 2931 | ||
@@ -2820,12 +2940,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | |||
2820 | 2940 | ||
2821 | disabled_vif = vif; | 2941 | disabled_vif = vif; |
2822 | 2942 | ||
2823 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, | ||
2824 | mvmvif->ap_sta_id); | ||
2825 | |||
2826 | if (!WARN_ON(!mvmsta)) | ||
2827 | iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true); | ||
2828 | |||
2829 | iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL); | 2943 | iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL); |
2830 | break; | 2944 | break; |
2831 | default: | 2945 | default: |
@@ -2851,18 +2965,12 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, | |||
2851 | mutex_unlock(&mvm->mutex); | 2965 | mutex_unlock(&mvm->mutex); |
2852 | } | 2966 | } |
2853 | 2967 | ||
2854 | static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, | 2968 | static int |
2855 | struct ieee80211_vif_chanctx_switch *vifs, | 2969 | iwl_mvm_switch_vif_chanctx_swap(struct iwl_mvm *mvm, |
2856 | int n_vifs, | 2970 | struct ieee80211_vif_chanctx_switch *vifs) |
2857 | enum ieee80211_chanctx_switch_mode mode) | ||
2858 | { | 2971 | { |
2859 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
2860 | int ret; | 2972 | int ret; |
2861 | 2973 | ||
2862 | /* we only support SWAP_CONTEXTS and with a single-vif right now */ | ||
2863 | if (mode != CHANCTX_SWMODE_SWAP_CONTEXTS || n_vifs > 1) | ||
2864 | return -EOPNOTSUPP; | ||
2865 | |||
2866 | mutex_lock(&mvm->mutex); | 2974 | mutex_lock(&mvm->mutex); |
2867 | __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true); | 2975 | __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true); |
2868 | __iwl_mvm_remove_chanctx(mvm, vifs[0].old_ctx); | 2976 | __iwl_mvm_remove_chanctx(mvm, vifs[0].old_ctx); |
@@ -2891,15 +2999,51 @@ out_remove: | |||
2891 | __iwl_mvm_remove_chanctx(mvm, vifs[0].new_ctx); | 2999 | __iwl_mvm_remove_chanctx(mvm, vifs[0].new_ctx); |
2892 | 3000 | ||
2893 | out_reassign: | 3001 | out_reassign: |
2894 | ret = __iwl_mvm_add_chanctx(mvm, vifs[0].old_ctx); | 3002 | if (__iwl_mvm_add_chanctx(mvm, vifs[0].old_ctx)) { |
2895 | if (ret) { | ||
2896 | IWL_ERR(mvm, "failed to add old_ctx back after failure.\n"); | 3003 | IWL_ERR(mvm, "failed to add old_ctx back after failure.\n"); |
2897 | goto out_restart; | 3004 | goto out_restart; |
2898 | } | 3005 | } |
2899 | 3006 | ||
2900 | ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, | 3007 | if (__iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, |
3008 | true)) { | ||
3009 | IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n"); | ||
3010 | goto out_restart; | ||
3011 | } | ||
3012 | |||
3013 | goto out; | ||
3014 | |||
3015 | out_restart: | ||
3016 | /* things keep failing, better restart the hw */ | ||
3017 | iwl_mvm_nic_restart(mvm, false); | ||
3018 | |||
3019 | out: | ||
3020 | mutex_unlock(&mvm->mutex); | ||
3021 | |||
3022 | return ret; | ||
3023 | } | ||
3024 | |||
3025 | static int | ||
3026 | iwl_mvm_switch_vif_chanctx_reassign(struct iwl_mvm *mvm, | ||
3027 | struct ieee80211_vif_chanctx_switch *vifs) | ||
3028 | { | ||
3029 | int ret; | ||
3030 | |||
3031 | mutex_lock(&mvm->mutex); | ||
3032 | __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true); | ||
3033 | |||
3034 | ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].new_ctx, | ||
2901 | true); | 3035 | true); |
2902 | if (ret) { | 3036 | if (ret) { |
3037 | IWL_ERR(mvm, | ||
3038 | "failed to assign new_ctx during channel switch\n"); | ||
3039 | goto out_reassign; | ||
3040 | } | ||
3041 | |||
3042 | goto out; | ||
3043 | |||
3044 | out_reassign: | ||
3045 | if (__iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, | ||
3046 | true)) { | ||
2903 | IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n"); | 3047 | IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n"); |
2904 | goto out_restart; | 3048 | goto out_restart; |
2905 | } | 3049 | } |
@@ -2912,6 +3056,34 @@ out_restart: | |||
2912 | 3056 | ||
2913 | out: | 3057 | out: |
2914 | mutex_unlock(&mvm->mutex); | 3058 | mutex_unlock(&mvm->mutex); |
3059 | |||
3060 | return ret; | ||
3061 | } | ||
3062 | |||
3063 | static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, | ||
3064 | struct ieee80211_vif_chanctx_switch *vifs, | ||
3065 | int n_vifs, | ||
3066 | enum ieee80211_chanctx_switch_mode mode) | ||
3067 | { | ||
3068 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
3069 | int ret; | ||
3070 | |||
3071 | /* we only support a single-vif right now */ | ||
3072 | if (n_vifs > 1) | ||
3073 | return -EOPNOTSUPP; | ||
3074 | |||
3075 | switch (mode) { | ||
3076 | case CHANCTX_SWMODE_SWAP_CONTEXTS: | ||
3077 | ret = iwl_mvm_switch_vif_chanctx_swap(mvm, vifs); | ||
3078 | break; | ||
3079 | case CHANCTX_SWMODE_REASSIGN_VIF: | ||
3080 | ret = iwl_mvm_switch_vif_chanctx_reassign(mvm, vifs); | ||
3081 | break; | ||
3082 | default: | ||
3083 | ret = -EOPNOTSUPP; | ||
3084 | break; | ||
3085 | } | ||
3086 | |||
2915 | return ret; | 3087 | return ret; |
2916 | } | 3088 | } |
2917 | 3089 | ||
@@ -2997,27 +3169,134 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, | |||
2997 | } | 3169 | } |
2998 | #endif | 3170 | #endif |
2999 | 3171 | ||
3000 | static void iwl_mvm_channel_switch_beacon(struct ieee80211_hw *hw, | 3172 | static void iwl_mvm_channel_switch(struct ieee80211_hw *hw, |
3001 | struct ieee80211_vif *vif, | 3173 | struct ieee80211_vif *vif, |
3002 | struct cfg80211_chan_def *chandef) | 3174 | struct ieee80211_channel_switch *chsw) |
3175 | { | ||
3176 | /* By implementing this operation, we prevent mac80211 from | ||
3177 | * starting its own channel switch timer, so that we can call | ||
3178 | * ieee80211_chswitch_done() ourselves at the right time | ||
3179 | * (which is when the absence time event starts). | ||
3180 | */ | ||
3181 | |||
3182 | IWL_DEBUG_MAC80211(IWL_MAC80211_GET_MVM(hw), | ||
3183 | "dummy channel switch op\n"); | ||
3184 | } | ||
3185 | |||
3186 | static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, | ||
3187 | struct ieee80211_vif *vif, | ||
3188 | struct ieee80211_channel_switch *chsw) | ||
3003 | { | 3189 | { |
3004 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 3190 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
3005 | struct ieee80211_vif *csa_vif; | 3191 | struct ieee80211_vif *csa_vif; |
3192 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
3193 | u32 apply_time; | ||
3194 | int ret; | ||
3006 | 3195 | ||
3007 | mutex_lock(&mvm->mutex); | 3196 | mutex_lock(&mvm->mutex); |
3008 | 3197 | ||
3009 | csa_vif = rcu_dereference_protected(mvm->csa_vif, | 3198 | IWL_DEBUG_MAC80211(mvm, "pre CSA to freq %d\n", |
3010 | lockdep_is_held(&mvm->mutex)); | 3199 | chsw->chandef.center_freq1); |
3011 | if (WARN(csa_vif && csa_vif->csa_active, | 3200 | |
3012 | "Another CSA is already in progress")) | 3201 | switch (vif->type) { |
3202 | case NL80211_IFTYPE_AP: | ||
3203 | csa_vif = | ||
3204 | rcu_dereference_protected(mvm->csa_vif, | ||
3205 | lockdep_is_held(&mvm->mutex)); | ||
3206 | if (WARN_ONCE(csa_vif && csa_vif->csa_active, | ||
3207 | "Another CSA is already in progress")) { | ||
3208 | ret = -EBUSY; | ||
3209 | goto out_unlock; | ||
3210 | } | ||
3211 | |||
3212 | rcu_assign_pointer(mvm->csa_vif, vif); | ||
3213 | |||
3214 | if (WARN_ONCE(mvmvif->csa_countdown, | ||
3215 | "Previous CSA countdown didn't complete")) { | ||
3216 | ret = -EBUSY; | ||
3217 | goto out_unlock; | ||
3218 | } | ||
3219 | |||
3220 | break; | ||
3221 | case NL80211_IFTYPE_STATION: | ||
3222 | /* Schedule the time event to a bit before beacon 1, | ||
3223 | * to make sure we're in the new channel when the | ||
3224 | * GO/AP arrives. | ||
3225 | */ | ||
3226 | apply_time = chsw->device_timestamp + | ||
3227 | ((vif->bss_conf.beacon_int * (chsw->count - 1) - | ||
3228 | IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT) * 1024); | ||
3229 | |||
3230 | if (chsw->block_tx) | ||
3231 | iwl_mvm_csa_client_absent(mvm, vif); | ||
3232 | |||
3233 | iwl_mvm_schedule_csa_period(mvm, vif, vif->bss_conf.beacon_int, | ||
3234 | apply_time); | ||
3235 | if (mvmvif->bf_data.bf_enabled) { | ||
3236 | ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); | ||
3237 | if (ret) | ||
3238 | goto out_unlock; | ||
3239 | } | ||
3240 | |||
3241 | break; | ||
3242 | default: | ||
3243 | break; | ||
3244 | } | ||
3245 | |||
3246 | mvmvif->ps_disabled = true; | ||
3247 | |||
3248 | ret = iwl_mvm_power_update_ps(mvm); | ||
3249 | if (ret) | ||
3013 | goto out_unlock; | 3250 | goto out_unlock; |
3014 | 3251 | ||
3015 | IWL_DEBUG_MAC80211(mvm, "CSA started to freq %d\n", | 3252 | /* we won't be on this channel any longer */ |
3016 | chandef->center_freq1); | 3253 | iwl_mvm_teardown_tdls_peers(mvm); |
3017 | rcu_assign_pointer(mvm->csa_vif, vif); | 3254 | |
3255 | out_unlock: | ||
3256 | mutex_unlock(&mvm->mutex); | ||
3257 | |||
3258 | return ret; | ||
3259 | } | ||
3260 | |||
3261 | static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw, | ||
3262 | struct ieee80211_vif *vif) | ||
3263 | { | ||
3264 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
3265 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
3266 | int ret; | ||
3267 | |||
3268 | mutex_lock(&mvm->mutex); | ||
3269 | |||
3270 | if (vif->type == NL80211_IFTYPE_STATION) { | ||
3271 | struct iwl_mvm_sta *mvmsta; | ||
3272 | |||
3273 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, | ||
3274 | mvmvif->ap_sta_id); | ||
3275 | |||
3276 | if (WARN_ON(!mvmsta)) { | ||
3277 | ret = -EIO; | ||
3278 | goto out_unlock; | ||
3279 | } | ||
3280 | |||
3281 | iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false); | ||
3282 | |||
3283 | iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); | ||
3284 | |||
3285 | ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); | ||
3286 | if (ret) | ||
3287 | goto out_unlock; | ||
3288 | |||
3289 | iwl_mvm_stop_session_protection(mvm, vif); | ||
3290 | } | ||
3291 | |||
3292 | mvmvif->ps_disabled = false; | ||
3293 | |||
3294 | ret = iwl_mvm_power_update_ps(mvm); | ||
3018 | 3295 | ||
3019 | out_unlock: | 3296 | out_unlock: |
3020 | mutex_unlock(&mvm->mutex); | 3297 | mutex_unlock(&mvm->mutex); |
3298 | |||
3299 | return ret; | ||
3021 | } | 3300 | } |
3022 | 3301 | ||
3023 | static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, | 3302 | static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, |
@@ -3026,31 +3305,44 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, | |||
3026 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 3305 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
3027 | struct iwl_mvm_vif *mvmvif; | 3306 | struct iwl_mvm_vif *mvmvif; |
3028 | struct iwl_mvm_sta *mvmsta; | 3307 | struct iwl_mvm_sta *mvmsta; |
3308 | struct ieee80211_sta *sta; | ||
3309 | int i; | ||
3310 | u32 msk = 0; | ||
3029 | 3311 | ||
3030 | if (!vif || vif->type != NL80211_IFTYPE_STATION) | 3312 | if (!vif || vif->type != NL80211_IFTYPE_STATION) |
3031 | return; | 3313 | return; |
3032 | 3314 | ||
3033 | mutex_lock(&mvm->mutex); | 3315 | mutex_lock(&mvm->mutex); |
3034 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | 3316 | mvmvif = iwl_mvm_vif_from_mac80211(vif); |
3035 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); | ||
3036 | 3317 | ||
3037 | if (WARN_ON_ONCE(!mvmsta)) { | 3318 | /* flush the AP-station and all TDLS peers */ |
3038 | mutex_unlock(&mvm->mutex); | 3319 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { |
3039 | return; | 3320 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], |
3321 | lockdep_is_held(&mvm->mutex)); | ||
3322 | if (IS_ERR_OR_NULL(sta)) | ||
3323 | continue; | ||
3324 | |||
3325 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
3326 | if (mvmsta->vif != vif) | ||
3327 | continue; | ||
3328 | |||
3329 | /* make sure only TDLS peers or the AP are flushed */ | ||
3330 | WARN_ON(i != mvmvif->ap_sta_id && !sta->tdls); | ||
3331 | |||
3332 | msk |= mvmsta->tfd_queue_msk; | ||
3040 | } | 3333 | } |
3041 | 3334 | ||
3042 | if (drop) { | 3335 | if (drop) { |
3043 | if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true)) | 3336 | if (iwl_mvm_flush_tx_path(mvm, msk, true)) |
3044 | IWL_ERR(mvm, "flush request fail\n"); | 3337 | IWL_ERR(mvm, "flush request fail\n"); |
3045 | mutex_unlock(&mvm->mutex); | 3338 | mutex_unlock(&mvm->mutex); |
3046 | } else { | 3339 | } else { |
3047 | u32 tfd_queue_msk = mvmsta->tfd_queue_msk; | ||
3048 | mutex_unlock(&mvm->mutex); | 3340 | mutex_unlock(&mvm->mutex); |
3049 | 3341 | ||
3050 | /* this can take a while, and we may need/want other operations | 3342 | /* this can take a while, and we may need/want other operations |
3051 | * to succeed while doing this, so do it without the mutex held | 3343 | * to succeed while doing this, so do it without the mutex held |
3052 | */ | 3344 | */ |
3053 | iwl_trans_wait_tx_queue_empty(mvm->trans, tfd_queue_msk); | 3345 | iwl_trans_wait_tx_queue_empty(mvm->trans, msk); |
3054 | } | 3346 | } |
3055 | } | 3347 | } |
3056 | 3348 | ||
@@ -3058,7 +3350,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { | |||
3058 | .tx = iwl_mvm_mac_tx, | 3350 | .tx = iwl_mvm_mac_tx, |
3059 | .ampdu_action = iwl_mvm_mac_ampdu_action, | 3351 | .ampdu_action = iwl_mvm_mac_ampdu_action, |
3060 | .start = iwl_mvm_mac_start, | 3352 | .start = iwl_mvm_mac_start, |
3061 | .restart_complete = iwl_mvm_mac_restart_complete, | 3353 | .reconfig_complete = iwl_mvm_mac_reconfig_complete, |
3062 | .stop = iwl_mvm_mac_stop, | 3354 | .stop = iwl_mvm_mac_stop, |
3063 | .add_interface = iwl_mvm_mac_add_interface, | 3355 | .add_interface = iwl_mvm_mac_add_interface, |
3064 | .remove_interface = iwl_mvm_mac_remove_interface, | 3356 | .remove_interface = iwl_mvm_mac_remove_interface, |
@@ -3099,7 +3391,13 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { | |||
3099 | 3391 | ||
3100 | .set_tim = iwl_mvm_set_tim, | 3392 | .set_tim = iwl_mvm_set_tim, |
3101 | 3393 | ||
3102 | .channel_switch_beacon = iwl_mvm_channel_switch_beacon, | 3394 | .channel_switch = iwl_mvm_channel_switch, |
3395 | .pre_channel_switch = iwl_mvm_pre_channel_switch, | ||
3396 | .post_channel_switch = iwl_mvm_post_channel_switch, | ||
3397 | |||
3398 | .tdls_channel_switch = iwl_mvm_tdls_channel_switch, | ||
3399 | .tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch, | ||
3400 | .tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch, | ||
3103 | 3401 | ||
3104 | CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) | 3402 | CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) |
3105 | 3403 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 256765accbc6..d24660fb4ef2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -87,12 +87,18 @@ | |||
87 | /* A TimeUnit is 1024 microsecond */ | 87 | /* A TimeUnit is 1024 microsecond */ |
88 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) | 88 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) |
89 | 89 | ||
90 | /* This value represents the number of TUs before CSA "beacon 0" TBTT | 90 | /* For GO, this value represents the number of TUs before CSA "beacon |
91 | * when the CSA time-event needs to be scheduled to start. It must be | 91 | * 0" TBTT when the CSA time-event needs to be scheduled to start. It |
92 | * big enough to ensure that we switch in time. | 92 | * must be big enough to ensure that we switch in time. |
93 | */ | 93 | */ |
94 | #define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40 | 94 | #define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40 |
95 | 95 | ||
96 | /* For client, this value represents the number of TUs before CSA | ||
97 | * "beacon 1" TBTT, instead. This is because we don't know when the | ||
98 | * GO/AP will be in the new channel, so we switch early enough. | ||
99 | */ | ||
100 | #define IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT 10 | ||
101 | |||
96 | /* | 102 | /* |
97 | * This value (in TUs) is used to fine tune the CSA NoA end time which should | 103 | * This value (in TUs) is used to fine tune the CSA NoA end time which should |
98 | * be just before "beacon 0" TBTT. | 104 | * be just before "beacon 0" TBTT. |
@@ -269,6 +275,7 @@ enum iwl_mvm_ref_type { | |||
269 | IWL_MVM_REF_NMI, | 275 | IWL_MVM_REF_NMI, |
270 | IWL_MVM_REF_TM_CMD, | 276 | IWL_MVM_REF_TM_CMD, |
271 | IWL_MVM_REF_EXIT_WORK, | 277 | IWL_MVM_REF_EXIT_WORK, |
278 | IWL_MVM_REF_PROTECT_CSA, | ||
272 | 279 | ||
273 | /* update debugfs.c when changing this */ | 280 | /* update debugfs.c when changing this */ |
274 | 281 | ||
@@ -288,7 +295,6 @@ enum iwl_bt_force_ant_mode { | |||
288 | * struct iwl_mvm_vif_bf_data - beacon filtering related data | 295 | * struct iwl_mvm_vif_bf_data - beacon filtering related data |
289 | * @bf_enabled: indicates if beacon filtering is enabled | 296 | * @bf_enabled: indicates if beacon filtering is enabled |
290 | * @ba_enabled: indicated if beacon abort is enabled | 297 | * @ba_enabled: indicated if beacon abort is enabled |
291 | * @last_beacon_signal: last beacon rssi signal in dbm | ||
292 | * @ave_beacon_signal: average beacon signal | 298 | * @ave_beacon_signal: average beacon signal |
293 | * @last_cqm_event: rssi of the last cqm event | 299 | * @last_cqm_event: rssi of the last cqm event |
294 | * @bt_coex_min_thold: minimum threshold for BT coex | 300 | * @bt_coex_min_thold: minimum threshold for BT coex |
@@ -399,6 +405,9 @@ struct iwl_mvm_vif { | |||
399 | 405 | ||
400 | /* FW identified misbehaving AP */ | 406 | /* FW identified misbehaving AP */ |
401 | u8 uapsd_misbehaving_bssid[ETH_ALEN]; | 407 | u8 uapsd_misbehaving_bssid[ETH_ALEN]; |
408 | |||
409 | /* Indicates that CSA countdown may be started */ | ||
410 | bool csa_countdown; | ||
402 | }; | 411 | }; |
403 | 412 | ||
404 | static inline struct iwl_mvm_vif * | 413 | static inline struct iwl_mvm_vif * |
@@ -519,6 +528,13 @@ enum { | |||
519 | #define IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -100 | 528 | #define IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -100 |
520 | #define IWL_MVM_DEBUG_SET_TEMPERATURE_MAX 200 | 529 | #define IWL_MVM_DEBUG_SET_TEMPERATURE_MAX 200 |
521 | 530 | ||
531 | enum iwl_mvm_tdls_cs_state { | ||
532 | IWL_MVM_TDLS_SW_IDLE = 0, | ||
533 | IWL_MVM_TDLS_SW_REQ_SENT, | ||
534 | IWL_MVM_TDLS_SW_REQ_RCVD, | ||
535 | IWL_MVM_TDLS_SW_ACTIVE, | ||
536 | }; | ||
537 | |||
522 | struct iwl_mvm { | 538 | struct iwl_mvm { |
523 | /* for logger access */ | 539 | /* for logger access */ |
524 | struct device *dev; | 540 | struct device *dev; |
@@ -548,6 +564,7 @@ struct iwl_mvm { | |||
548 | enum iwl_ucode_type cur_ucode; | 564 | enum iwl_ucode_type cur_ucode; |
549 | bool ucode_loaded; | 565 | bool ucode_loaded; |
550 | bool init_ucode_complete; | 566 | bool init_ucode_complete; |
567 | bool calibrating; | ||
551 | u32 error_event_table; | 568 | u32 error_event_table; |
552 | u32 log_event_table; | 569 | u32 log_event_table; |
553 | u32 umac_error_event_table; | 570 | u32 umac_error_event_table; |
@@ -577,6 +594,7 @@ struct iwl_mvm { | |||
577 | struct work_struct sta_drained_wk; | 594 | struct work_struct sta_drained_wk; |
578 | unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; | 595 | unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; |
579 | atomic_t pending_frames[IWL_MVM_STATION_COUNT]; | 596 | atomic_t pending_frames[IWL_MVM_STATION_COUNT]; |
597 | u32 tfd_drained[IWL_MVM_STATION_COUNT]; | ||
580 | u8 rx_ba_sessions; | 598 | u8 rx_ba_sessions; |
581 | 599 | ||
582 | /* configured by mac80211 */ | 600 | /* configured by mac80211 */ |
@@ -587,6 +605,10 @@ struct iwl_mvm { | |||
587 | void *scan_cmd; | 605 | void *scan_cmd; |
588 | struct iwl_mcast_filter_cmd *mcast_filter_cmd; | 606 | struct iwl_mcast_filter_cmd *mcast_filter_cmd; |
589 | 607 | ||
608 | /* UMAC scan tracking */ | ||
609 | u32 scan_uid[IWL_MVM_MAX_SIMULTANEOUS_SCANS]; | ||
610 | u8 scan_seq_num, sched_scan_seq_num; | ||
611 | |||
590 | /* rx chain antennas set through debugfs for the scan command */ | 612 | /* rx chain antennas set through debugfs for the scan command */ |
591 | u8 scan_rx_ant; | 613 | u8 scan_rx_ant; |
592 | 614 | ||
@@ -648,6 +670,7 @@ struct iwl_mvm { | |||
648 | /* -1 for always, 0 for never, >0 for that many times */ | 670 | /* -1 for always, 0 for never, >0 for that many times */ |
649 | s8 restart_fw; | 671 | s8 restart_fw; |
650 | struct work_struct fw_error_dump_wk; | 672 | struct work_struct fw_error_dump_wk; |
673 | enum iwl_fw_dbg_conf fw_dbg_conf; | ||
651 | 674 | ||
652 | #ifdef CONFIG_IWLWIFI_LEDS | 675 | #ifdef CONFIG_IWLWIFI_LEDS |
653 | struct led_classdev led; | 676 | struct led_classdev led; |
@@ -661,7 +684,12 @@ struct iwl_mvm { | |||
661 | 684 | ||
662 | /* sched scan settings for net detect */ | 685 | /* sched scan settings for net detect */ |
663 | struct cfg80211_sched_scan_request *nd_config; | 686 | struct cfg80211_sched_scan_request *nd_config; |
664 | struct ieee80211_scan_ies *nd_ies; | 687 | struct ieee80211_scan_ies nd_ies; |
688 | struct cfg80211_match_set *nd_match_sets; | ||
689 | int n_nd_match_sets; | ||
690 | struct ieee80211_channel **nd_channels; | ||
691 | int n_nd_channels; | ||
692 | bool net_detect; | ||
665 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 693 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
666 | u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */ | 694 | u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */ |
667 | bool d3_test_active; | 695 | bool d3_test_active; |
@@ -734,6 +762,28 @@ struct iwl_mvm { | |||
734 | u32 ap_last_beacon_gp2; | 762 | u32 ap_last_beacon_gp2; |
735 | 763 | ||
736 | u8 low_latency_agg_frame_limit; | 764 | u8 low_latency_agg_frame_limit; |
765 | |||
766 | /* TDLS channel switch data */ | ||
767 | struct { | ||
768 | struct delayed_work dwork; | ||
769 | enum iwl_mvm_tdls_cs_state state; | ||
770 | |||
771 | /* | ||
772 | * Current cs sta - might be different from periodic cs peer | ||
773 | * station. Value is meaningless when the cs-state is idle. | ||
774 | */ | ||
775 | u8 cur_sta_id; | ||
776 | |||
777 | /* TDLS periodic channel-switch peer */ | ||
778 | struct { | ||
779 | u8 sta_id; | ||
780 | u8 op_class; | ||
781 | bool initiator; /* are we the link initiator */ | ||
782 | struct cfg80211_chan_def chandef; | ||
783 | struct sk_buff *skb; /* ch sw template */ | ||
784 | u32 ch_sw_tm_ie; | ||
785 | } peer; | ||
786 | } tdls_cs; | ||
737 | }; | 787 | }; |
738 | 788 | ||
739 | /* Extract MVM priv from op_mode and _hw */ | 789 | /* Extract MVM priv from op_mode and _hw */ |
@@ -750,6 +800,7 @@ enum iwl_mvm_status { | |||
750 | IWL_MVM_STATUS_IN_HW_RESTART, | 800 | IWL_MVM_STATUS_IN_HW_RESTART, |
751 | IWL_MVM_STATUS_IN_D0I3, | 801 | IWL_MVM_STATUS_IN_D0I3, |
752 | IWL_MVM_STATUS_ROC_AUX_RUNNING, | 802 | IWL_MVM_STATUS_ROC_AUX_RUNNING, |
803 | IWL_MVM_STATUS_D3_RECONFIG, | ||
753 | }; | 804 | }; |
754 | 805 | ||
755 | static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) | 806 | static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) |
@@ -758,6 +809,26 @@ static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) | |||
758 | test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); | 809 | test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); |
759 | } | 810 | } |
760 | 811 | ||
812 | /* Must be called with rcu_read_lock() held and it can only be | ||
813 | * released when mvmsta is not needed anymore. | ||
814 | */ | ||
815 | static inline struct iwl_mvm_sta * | ||
816 | iwl_mvm_sta_from_staid_rcu(struct iwl_mvm *mvm, u8 sta_id) | ||
817 | { | ||
818 | struct ieee80211_sta *sta; | ||
819 | |||
820 | if (sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)) | ||
821 | return NULL; | ||
822 | |||
823 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
824 | |||
825 | /* This can happen if the station has been removed right now */ | ||
826 | if (IS_ERR_OR_NULL(sta)) | ||
827 | return NULL; | ||
828 | |||
829 | return iwl_mvm_sta_from_mac80211(sta); | ||
830 | } | ||
831 | |||
761 | static inline struct iwl_mvm_sta * | 832 | static inline struct iwl_mvm_sta * |
762 | iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) | 833 | iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) |
763 | { | 834 | { |
@@ -831,6 +902,16 @@ int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, | |||
831 | int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | 902 | int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, |
832 | struct ieee80211_sta *sta); | 903 | struct ieee80211_sta *sta); |
833 | int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb); | 904 | int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb); |
905 | void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | ||
906 | struct iwl_tx_cmd *tx_cmd, | ||
907 | struct ieee80211_tx_info *info, u8 sta_id); | ||
908 | void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, | ||
909 | struct ieee80211_tx_info *info, | ||
910 | struct iwl_tx_cmd *tx_cmd, | ||
911 | struct sk_buff *skb_frag); | ||
912 | void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, | ||
913 | struct ieee80211_tx_info *info, | ||
914 | struct ieee80211_sta *sta, __le16 fc); | ||
834 | #ifdef CONFIG_IWLWIFI_DEBUG | 915 | #ifdef CONFIG_IWLWIFI_DEBUG |
835 | const char *iwl_mvm_get_tx_fail_reason(u32 status); | 916 | const char *iwl_mvm_get_tx_fail_reason(u32 status); |
836 | #else | 917 | #else |
@@ -887,6 +968,8 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, | |||
887 | struct iwl_device_cmd *cmd); | 968 | struct iwl_device_cmd *cmd); |
888 | int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | 969 | int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, |
889 | struct iwl_device_cmd *cmd); | 970 | struct iwl_device_cmd *cmd); |
971 | int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
972 | struct iwl_device_cmd *cmd); | ||
890 | 973 | ||
891 | /* MVM PHY */ | 974 | /* MVM PHY */ |
892 | int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | 975 | int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, |
@@ -900,6 +983,8 @@ void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, | |||
900 | void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, | 983 | void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, |
901 | struct iwl_mvm_phy_ctxt *ctxt); | 984 | struct iwl_mvm_phy_ctxt *ctxt); |
902 | int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm); | 985 | int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm); |
986 | u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef); | ||
987 | u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef); | ||
903 | 988 | ||
904 | /* MAC (virtual interface) programming */ | 989 | /* MAC (virtual interface) programming */ |
905 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 990 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
@@ -919,6 +1004,8 @@ int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, | |||
919 | struct iwl_device_cmd *cmd); | 1004 | struct iwl_device_cmd *cmd); |
920 | void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, | 1005 | void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, |
921 | struct ieee80211_vif *vif); | 1006 | struct ieee80211_vif *vif); |
1007 | unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, | ||
1008 | struct ieee80211_vif *exclude_vif); | ||
922 | 1009 | ||
923 | /* Bindings */ | 1010 | /* Bindings */ |
924 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 1011 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
@@ -929,6 +1016,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | |||
929 | struct ieee80211_vif *disabled_vif); | 1016 | struct ieee80211_vif *disabled_vif); |
930 | 1017 | ||
931 | /* Scanning */ | 1018 | /* Scanning */ |
1019 | int iwl_mvm_scan_size(struct iwl_mvm *mvm); | ||
932 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, | 1020 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, |
933 | struct ieee80211_vif *vif, | 1021 | struct ieee80211_vif *vif, |
934 | struct cfg80211_scan_request *req); | 1022 | struct cfg80211_scan_request *req); |
@@ -969,6 +1057,17 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
969 | struct cfg80211_sched_scan_request *req, | 1057 | struct cfg80211_sched_scan_request *req, |
970 | struct ieee80211_scan_ies *ies); | 1058 | struct ieee80211_scan_ies *ies); |
971 | 1059 | ||
1060 | /* UMAC scan */ | ||
1061 | int iwl_mvm_config_scan(struct iwl_mvm *mvm); | ||
1062 | int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
1063 | struct ieee80211_scan_request *req); | ||
1064 | int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
1065 | struct cfg80211_sched_scan_request *req, | ||
1066 | struct ieee80211_scan_ies *ies); | ||
1067 | int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, | ||
1068 | struct iwl_rx_cmd_buffer *rxb, | ||
1069 | struct iwl_device_cmd *cmd); | ||
1070 | |||
972 | /* MVM debugfs */ | 1071 | /* MVM debugfs */ |
973 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1072 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
974 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); | 1073 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); |
@@ -1048,7 +1147,7 @@ iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
1048 | } | 1147 | } |
1049 | #endif | 1148 | #endif |
1050 | void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, | 1149 | void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, |
1051 | struct iwl_wowlan_config_cmd_v2 *cmd); | 1150 | struct iwl_wowlan_config_cmd *cmd); |
1052 | int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | 1151 | int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, |
1053 | struct ieee80211_vif *vif, | 1152 | struct ieee80211_vif *vif, |
1054 | bool disable_offloading, | 1153 | bool disable_offloading, |
@@ -1058,6 +1157,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | |||
1058 | void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | 1157 | void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); |
1059 | void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | 1158 | void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); |
1060 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | 1159 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); |
1160 | bool iwl_mvm_ref_taken(struct iwl_mvm *mvm); | ||
1061 | void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); | 1161 | void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); |
1062 | int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); | 1162 | int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); |
1063 | 1163 | ||
@@ -1073,12 +1173,14 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, | |||
1073 | struct ieee80211_sta *sta); | 1173 | struct ieee80211_sta *sta); |
1074 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | 1174 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, |
1075 | struct ieee80211_sta *sta); | 1175 | struct ieee80211_sta *sta); |
1176 | bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant); | ||
1076 | bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm); | 1177 | bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm); |
1077 | bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, | 1178 | bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, |
1078 | enum ieee80211_band band); | 1179 | enum ieee80211_band band); |
1079 | u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, | 1180 | u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, |
1080 | struct ieee80211_tx_info *info, u8 ac); | 1181 | struct ieee80211_tx_info *info, u8 ac); |
1081 | 1182 | ||
1183 | bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant); | ||
1082 | bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm); | 1184 | bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm); |
1083 | void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm); | 1185 | void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm); |
1084 | int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm); | 1186 | int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm); |
@@ -1194,6 +1296,10 @@ bool iwl_mvm_is_idle(struct iwl_mvm *mvm); | |||
1194 | 1296 | ||
1195 | /* Thermal management and CT-kill */ | 1297 | /* Thermal management and CT-kill */ |
1196 | void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); | 1298 | void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); |
1299 | void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp); | ||
1300 | int iwl_mvm_temp_notif(struct iwl_mvm *mvm, | ||
1301 | struct iwl_rx_cmd_buffer *rxb, | ||
1302 | struct iwl_device_cmd *cmd); | ||
1197 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm); | 1303 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm); |
1198 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff); | 1304 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff); |
1199 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm); | 1305 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm); |
@@ -1205,12 +1311,33 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
1205 | bool added_vif); | 1311 | bool added_vif); |
1206 | 1312 | ||
1207 | /* TDLS */ | 1313 | /* TDLS */ |
1314 | |||
1315 | /* | ||
1316 | * We use TID 4 (VI) as a FW-used-only TID when TDLS connections are present. | ||
1317 | * This TID is marked as used vs the AP and all connected TDLS peers. | ||
1318 | */ | ||
1319 | #define IWL_MVM_TDLS_FW_TID 4 | ||
1320 | |||
1208 | int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 1321 | int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
1209 | void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm); | 1322 | void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm); |
1210 | void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1323 | void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
1211 | bool sta_added); | 1324 | bool sta_added); |
1212 | void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, | 1325 | void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, |
1213 | struct ieee80211_vif *vif); | 1326 | struct ieee80211_vif *vif); |
1327 | int iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw, | ||
1328 | struct ieee80211_vif *vif, | ||
1329 | struct ieee80211_sta *sta, u8 oper_class, | ||
1330 | struct cfg80211_chan_def *chandef, | ||
1331 | struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie); | ||
1332 | void iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, | ||
1333 | struct ieee80211_vif *vif, | ||
1334 | struct ieee80211_tdls_ch_sw_params *params); | ||
1335 | void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, | ||
1336 | struct ieee80211_vif *vif, | ||
1337 | struct ieee80211_sta *sta); | ||
1338 | int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
1339 | struct iwl_device_cmd *cmd); | ||
1340 | void iwl_mvm_tdls_ch_switch_work(struct work_struct *work); | ||
1214 | 1341 | ||
1215 | struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); | 1342 | struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); |
1216 | 1343 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index af074563e770..d55fd8e3654c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
@@ -339,11 +339,15 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) | |||
339 | } *file_sec; | 339 | } *file_sec; |
340 | const u8 *eof, *temp; | 340 | const u8 *eof, *temp; |
341 | int max_section_size; | 341 | int max_section_size; |
342 | const __le32 *dword_buff; | ||
342 | 343 | ||
343 | #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) | 344 | #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) |
344 | #define NVM_WORD2_ID(x) (x >> 12) | 345 | #define NVM_WORD2_ID(x) (x >> 12) |
345 | #define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8)) | 346 | #define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8)) |
346 | #define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4) | 347 | #define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4) |
348 | #define NVM_HEADER_0 (0x2A504C54) | ||
349 | #define NVM_HEADER_1 (0x4E564D2A) | ||
350 | #define NVM_HEADER_SIZE (4 * sizeof(u32)) | ||
347 | 351 | ||
348 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); | 352 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); |
349 | 353 | ||
@@ -372,12 +376,6 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) | |||
372 | IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n", | 376 | IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n", |
373 | mvm->nvm_file_name, fw_entry->size); | 377 | mvm->nvm_file_name, fw_entry->size); |
374 | 378 | ||
375 | if (fw_entry->size < sizeof(*file_sec)) { | ||
376 | IWL_ERR(mvm, "NVM file too small\n"); | ||
377 | ret = -EINVAL; | ||
378 | goto out; | ||
379 | } | ||
380 | |||
381 | if (fw_entry->size > MAX_NVM_FILE_LEN) { | 379 | if (fw_entry->size > MAX_NVM_FILE_LEN) { |
382 | IWL_ERR(mvm, "NVM file too large\n"); | 380 | IWL_ERR(mvm, "NVM file too large\n"); |
383 | ret = -EINVAL; | 381 | ret = -EINVAL; |
@@ -385,8 +383,25 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) | |||
385 | } | 383 | } |
386 | 384 | ||
387 | eof = fw_entry->data + fw_entry->size; | 385 | eof = fw_entry->data + fw_entry->size; |
388 | 386 | dword_buff = (__le32 *)fw_entry->data; | |
389 | file_sec = (void *)fw_entry->data; | 387 | |
388 | /* some NVM file will contain a header. | ||
389 | * The header is identified by 2 dwords header as follow: | ||
390 | * dword[0] = 0x2A504C54 | ||
391 | * dword[1] = 0x4E564D2A | ||
392 | * | ||
393 | * This header must be skipped when providing the NVM data to the FW. | ||
394 | */ | ||
395 | if (fw_entry->size > NVM_HEADER_SIZE && | ||
396 | dword_buff[0] == cpu_to_le32(NVM_HEADER_0) && | ||
397 | dword_buff[1] == cpu_to_le32(NVM_HEADER_1)) { | ||
398 | file_sec = (void *)(fw_entry->data + NVM_HEADER_SIZE); | ||
399 | IWL_INFO(mvm, "NVM Version %08X\n", le32_to_cpu(dword_buff[2])); | ||
400 | IWL_INFO(mvm, "NVM Manufacturing date %08X\n", | ||
401 | le32_to_cpu(dword_buff[3])); | ||
402 | } else { | ||
403 | file_sec = (void *)fw_entry->data; | ||
404 | } | ||
390 | 405 | ||
391 | while (true) { | 406 | while (true) { |
392 | if (file_sec->data > eof) { | 407 | if (file_sec->data > eof) { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/offloading.c b/drivers/net/wireless/iwlwifi/mvm/offloading.c index adcbf4c8edd8..68b0169c8892 100644 --- a/drivers/net/wireless/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/iwlwifi/mvm/offloading.c | |||
@@ -67,7 +67,7 @@ | |||
67 | #include "mvm.h" | 67 | #include "mvm.h" |
68 | 68 | ||
69 | void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, | 69 | void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, |
70 | struct iwl_wowlan_config_cmd_v2 *cmd) | 70 | struct iwl_wowlan_config_cmd *cmd) |
71 | { | 71 | { |
72 | int i; | 72 | int i; |
73 | 73 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index bd52ecfabedb..97dfba50c682 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -244,6 +244,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
244 | iwl_mvm_rx_scan_offload_complete_notif, true), | 244 | iwl_mvm_rx_scan_offload_complete_notif, true), |
245 | RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results, | 245 | RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results, |
246 | false), | 246 | false), |
247 | RX_HANDLER(SCAN_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_complete_notif, | ||
248 | true), | ||
247 | 249 | ||
248 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), | 250 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), |
249 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), | 251 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), |
@@ -254,6 +256,12 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
254 | RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), | 256 | RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), |
255 | RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION, | 257 | RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION, |
256 | iwl_mvm_power_uapsd_misbehaving_ap_notif, false), | 258 | iwl_mvm_power_uapsd_misbehaving_ap_notif, false), |
259 | RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true), | ||
260 | |||
261 | RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif, | ||
262 | true), | ||
263 | RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false), | ||
264 | |||
257 | }; | 265 | }; |
258 | #undef RX_HANDLER | 266 | #undef RX_HANDLER |
259 | #define CMD(x) [x] = #x | 267 | #define CMD(x) [x] = #x |
@@ -317,11 +325,9 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
317 | CMD(WOWLAN_KEK_KCK_MATERIAL), | 325 | CMD(WOWLAN_KEK_KCK_MATERIAL), |
318 | CMD(WOWLAN_GET_STATUSES), | 326 | CMD(WOWLAN_GET_STATUSES), |
319 | CMD(WOWLAN_TX_POWER_PER_DB), | 327 | CMD(WOWLAN_TX_POWER_PER_DB), |
320 | CMD(NET_DETECT_CONFIG_CMD), | 328 | CMD(SCAN_OFFLOAD_PROFILES_QUERY_CMD), |
321 | CMD(NET_DETECT_PROFILES_QUERY_CMD), | 329 | CMD(SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD), |
322 | CMD(NET_DETECT_PROFILES_CMD), | 330 | CMD(SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD), |
323 | CMD(NET_DETECT_HOTSPOTS_CMD), | ||
324 | CMD(NET_DETECT_HOTSPOTS_QUERY_CMD), | ||
325 | CMD(CARD_STATE_NOTIFICATION), | 331 | CMD(CARD_STATE_NOTIFICATION), |
326 | CMD(MISSED_BEACONS_NOTIFICATION), | 332 | CMD(MISSED_BEACONS_NOTIFICATION), |
327 | CMD(BT_COEX_PRIO_TABLE), | 333 | CMD(BT_COEX_PRIO_TABLE), |
@@ -344,6 +350,13 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
344 | CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), | 350 | CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), |
345 | CMD(ANTENNA_COUPLING_NOTIFICATION), | 351 | CMD(ANTENNA_COUPLING_NOTIFICATION), |
346 | CMD(SCD_QUEUE_CFG), | 352 | CMD(SCD_QUEUE_CFG), |
353 | CMD(SCAN_CFG_CMD), | ||
354 | CMD(SCAN_REQ_UMAC), | ||
355 | CMD(SCAN_ABORT_UMAC), | ||
356 | CMD(SCAN_COMPLETE_UMAC), | ||
357 | CMD(TDLS_CHANNEL_SWITCH_CMD), | ||
358 | CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION), | ||
359 | CMD(TDLS_CONFIG_CMD), | ||
347 | }; | 360 | }; |
348 | #undef CMD | 361 | #undef CMD |
349 | 362 | ||
@@ -427,6 +440,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
427 | } | 440 | } |
428 | mvm->sf_state = SF_UNINIT; | 441 | mvm->sf_state = SF_UNINIT; |
429 | mvm->low_latency_agg_frame_limit = 6; | 442 | mvm->low_latency_agg_frame_limit = 6; |
443 | mvm->cur_ucode = IWL_UCODE_INIT; | ||
430 | 444 | ||
431 | mutex_init(&mvm->mutex); | 445 | mutex_init(&mvm->mutex); |
432 | mutex_init(&mvm->d0i3_suspend_mutex); | 446 | mutex_init(&mvm->d0i3_suspend_mutex); |
@@ -441,6 +455,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
441 | INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); | 455 | INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); |
442 | INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); | 456 | INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); |
443 | INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk); | 457 | INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk); |
458 | INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work); | ||
444 | 459 | ||
445 | spin_lock_init(&mvm->d0i3_tx_lock); | 460 | spin_lock_init(&mvm->d0i3_tx_lock); |
446 | spin_lock_init(&mvm->refs_lock); | 461 | spin_lock_init(&mvm->refs_lock); |
@@ -481,6 +496,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
481 | 496 | ||
482 | trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; | 497 | trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; |
483 | trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); | 498 | trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); |
499 | trans->dbg_dest_tlv = mvm->fw->dbg_dest_tlv; | ||
500 | trans->dbg_dest_reg_num = mvm->fw->dbg_dest_reg_num; | ||
501 | memcpy(trans->dbg_conf_tlv, mvm->fw->dbg_conf_tlv, | ||
502 | sizeof(trans->dbg_conf_tlv)); | ||
484 | 503 | ||
485 | /* set up notification wait support */ | 504 | /* set up notification wait support */ |
486 | iwl_notification_wait_init(&mvm->notif_wait); | 505 | iwl_notification_wait_init(&mvm->notif_wait); |
@@ -524,7 +543,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
524 | 543 | ||
525 | mutex_lock(&mvm->mutex); | 544 | mutex_lock(&mvm->mutex); |
526 | err = iwl_run_init_mvm_ucode(mvm, true); | 545 | err = iwl_run_init_mvm_ucode(mvm, true); |
527 | iwl_trans_stop_device(trans); | 546 | if (!err || !iwlmvm_mod_params.init_dbg) |
547 | iwl_trans_stop_device(trans); | ||
528 | mutex_unlock(&mvm->mutex); | 548 | mutex_unlock(&mvm->mutex); |
529 | /* returns 0 if successful, 1 if success but in rfkill */ | 549 | /* returns 0 if successful, 1 if success but in rfkill */ |
530 | if (err < 0 && !iwlmvm_mod_params.init_dbg) { | 550 | if (err < 0 && !iwlmvm_mod_params.init_dbg) { |
@@ -533,16 +553,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
533 | } | 553 | } |
534 | } | 554 | } |
535 | 555 | ||
536 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 556 | scan_size = iwl_mvm_scan_size(mvm); |
537 | scan_size = sizeof(struct iwl_scan_req_unified_lmac) + | ||
538 | sizeof(struct iwl_scan_channel_cfg_lmac) * | ||
539 | mvm->fw->ucode_capa.n_scan_channels + | ||
540 | sizeof(struct iwl_scan_probe_req); | ||
541 | else | ||
542 | scan_size = sizeof(struct iwl_scan_cmd) + | ||
543 | mvm->fw->ucode_capa.max_probe_length + | ||
544 | mvm->fw->ucode_capa.n_scan_channels * | ||
545 | sizeof(struct iwl_scan_channel); | ||
546 | 557 | ||
547 | mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); | 558 | mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); |
548 | if (!mvm->scan_cmd) | 559 | if (!mvm->scan_cmd) |
@@ -596,8 +607,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) | |||
596 | kfree(mvm->nd_config->match_sets); | 607 | kfree(mvm->nd_config->match_sets); |
597 | kfree(mvm->nd_config); | 608 | kfree(mvm->nd_config); |
598 | mvm->nd_config = NULL; | 609 | mvm->nd_config = NULL; |
599 | kfree(mvm->nd_ies); | ||
600 | mvm->nd_ies = NULL; | ||
601 | } | 610 | } |
602 | #endif | 611 | #endif |
603 | 612 | ||
@@ -757,6 +766,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) | |||
757 | static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | 766 | static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) |
758 | { | 767 | { |
759 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 768 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
769 | bool calibrating = ACCESS_ONCE(mvm->calibrating); | ||
760 | 770 | ||
761 | if (state) | 771 | if (state) |
762 | set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); | 772 | set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); |
@@ -765,7 +775,15 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | |||
765 | 775 | ||
766 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); | 776 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); |
767 | 777 | ||
768 | return state && mvm->cur_ucode != IWL_UCODE_INIT; | 778 | /* iwl_run_init_mvm_ucode is waiting for results, abort it */ |
779 | if (calibrating) | ||
780 | iwl_abort_notification_waits(&mvm->notif_wait); | ||
781 | |||
782 | /* | ||
783 | * Stop the device if we run OPERATIONAL firmware or if we are in the | ||
784 | * middle of the calibrations. | ||
785 | */ | ||
786 | return state && (mvm->cur_ucode != IWL_UCODE_INIT || calibrating); | ||
769 | } | 787 | } |
770 | 788 | ||
771 | static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | 789 | static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) |
@@ -986,7 +1004,7 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, | |||
986 | } | 1004 | } |
987 | 1005 | ||
988 | static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, | 1006 | static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, |
989 | struct iwl_wowlan_config_cmd_v3 *cmd, | 1007 | struct iwl_wowlan_config_cmd *cmd, |
990 | struct iwl_d0i3_iter_data *iter_data) | 1008 | struct iwl_d0i3_iter_data *iter_data) |
991 | { | 1009 | { |
992 | struct ieee80211_sta *ap_sta; | 1010 | struct ieee80211_sta *ap_sta; |
@@ -1002,14 +1020,14 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, | |||
1002 | goto out; | 1020 | goto out; |
1003 | 1021 | ||
1004 | mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); | 1022 | mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); |
1005 | cmd->common.is_11n_connection = ap_sta->ht_cap.ht_supported; | 1023 | cmd->is_11n_connection = ap_sta->ht_cap.ht_supported; |
1006 | cmd->offloading_tid = iter_data->offloading_tid; | 1024 | cmd->offloading_tid = iter_data->offloading_tid; |
1007 | 1025 | ||
1008 | /* | 1026 | /* |
1009 | * The d0i3 uCode takes care of the nonqos counters, | 1027 | * The d0i3 uCode takes care of the nonqos counters, |
1010 | * so configure only the qos seq ones. | 1028 | * so configure only the qos seq ones. |
1011 | */ | 1029 | */ |
1012 | iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &cmd->common); | 1030 | iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, cmd); |
1013 | out: | 1031 | out: |
1014 | rcu_read_unlock(); | 1032 | rcu_read_unlock(); |
1015 | } | 1033 | } |
@@ -1021,14 +1039,11 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) | |||
1021 | struct iwl_d0i3_iter_data d0i3_iter_data = { | 1039 | struct iwl_d0i3_iter_data d0i3_iter_data = { |
1022 | .mvm = mvm, | 1040 | .mvm = mvm, |
1023 | }; | 1041 | }; |
1024 | struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = { | 1042 | struct iwl_wowlan_config_cmd wowlan_config_cmd = { |
1025 | .common = { | 1043 | .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | |
1026 | .wakeup_filter = | 1044 | IWL_WOWLAN_WAKEUP_BEACON_MISS | |
1027 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | | 1045 | IWL_WOWLAN_WAKEUP_LINK_CHANGE | |
1028 | IWL_WOWLAN_WAKEUP_BEACON_MISS | | 1046 | IWL_WOWLAN_WAKEUP_BCN_FILTERING), |
1029 | IWL_WOWLAN_WAKEUP_LINK_CHANGE | | ||
1030 | IWL_WOWLAN_WAKEUP_BCN_FILTERING), | ||
1031 | }, | ||
1032 | }; | 1047 | }; |
1033 | struct iwl_d3_manager_config d3_cfg_cmd = { | 1048 | struct iwl_d3_manager_config d3_cfg_cmd = { |
1034 | .min_sleep_time = cpu_to_le32(1000), | 1049 | .min_sleep_time = cpu_to_le32(1000), |
@@ -1040,6 +1055,19 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) | |||
1040 | set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); | 1055 | set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); |
1041 | synchronize_net(); | 1056 | synchronize_net(); |
1042 | 1057 | ||
1058 | /* | ||
1059 | * iwl_mvm_ref_sync takes a reference before checking the flag. | ||
1060 | * so by checking there is no held reference we prevent a state | ||
1061 | * in which iwl_mvm_ref_sync continues successfully while we | ||
1062 | * configure the firmware to enter d0i3 | ||
1063 | */ | ||
1064 | if (iwl_mvm_ref_taken(mvm)) { | ||
1065 | IWL_DEBUG_RPM(mvm->trans, "abort d0i3 due to taken ref\n"); | ||
1066 | clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); | ||
1067 | wake_up(&mvm->d0i3_exit_waitq); | ||
1068 | return 1; | ||
1069 | } | ||
1070 | |||
1043 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | 1071 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, |
1044 | IEEE80211_IFACE_ITER_NORMAL, | 1072 | IEEE80211_IFACE_ITER_NORMAL, |
1045 | iwl_mvm_enter_d0i3_iterator, | 1073 | iwl_mvm_enter_d0i3_iterator, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 12283b55ee84..1c0d4a45c1a8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | |||
@@ -68,7 +68,7 @@ | |||
68 | #include "mvm.h" | 68 | #include "mvm.h" |
69 | 69 | ||
70 | /* Maps the driver specific channel width definition to the the fw values */ | 70 | /* Maps the driver specific channel width definition to the the fw values */ |
71 | static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) | 71 | u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) |
72 | { | 72 | { |
73 | switch (chandef->width) { | 73 | switch (chandef->width) { |
74 | case NL80211_CHAN_WIDTH_20_NOHT: | 74 | case NL80211_CHAN_WIDTH_20_NOHT: |
@@ -90,7 +90,7 @@ static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) | |||
90 | * Maps the driver specific control channel position (relative to the center | 90 | * Maps the driver specific control channel position (relative to the center |
91 | * freq) definitions to the the fw values | 91 | * freq) definitions to the the fw values |
92 | */ | 92 | */ |
93 | static inline u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) | 93 | u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) |
94 | { | 94 | { |
95 | switch (chandef->chan->center_freq - chandef->center_freq1) { | 95 | switch (chandef->chan->center_freq - chandef->center_freq1) { |
96 | case -70: | 96 | case -70: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 5b85b0cc7a2a..2620dd0c45f9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -286,6 +286,27 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, | |||
286 | return true; | 286 | return true; |
287 | } | 287 | } |
288 | 288 | ||
289 | static int iwl_mvm_power_get_skip_over_dtim(int dtimper, int bi) | ||
290 | { | ||
291 | int numerator; | ||
292 | int dtim_interval = dtimper * bi; | ||
293 | |||
294 | if (WARN_ON(!dtim_interval)) | ||
295 | return 0; | ||
296 | |||
297 | if (dtimper == 1) { | ||
298 | if (bi > 100) | ||
299 | numerator = 408; | ||
300 | else | ||
301 | numerator = 510; | ||
302 | } else if (dtimper < 10) { | ||
303 | numerator = 612; | ||
304 | } else { | ||
305 | return 0; | ||
306 | } | ||
307 | return max(1, (numerator / dtim_interval)); | ||
308 | } | ||
309 | |||
289 | static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) | 310 | static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) |
290 | { | 311 | { |
291 | struct ieee80211_chanctx_conf *chanctx_conf; | 312 | struct ieee80211_chanctx_conf *chanctx_conf; |
@@ -308,7 +329,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
308 | struct ieee80211_vif *vif, | 329 | struct ieee80211_vif *vif, |
309 | struct iwl_mac_power_cmd *cmd) | 330 | struct iwl_mac_power_cmd *cmd) |
310 | { | 331 | { |
311 | int dtimper, dtimper_msec; | 332 | int dtimper, bi; |
312 | int keep_alive; | 333 | int keep_alive; |
313 | bool radar_detect = false; | 334 | bool radar_detect = false; |
314 | struct iwl_mvm_vif *mvmvif __maybe_unused = | 335 | struct iwl_mvm_vif *mvmvif __maybe_unused = |
@@ -317,6 +338,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
317 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | 338 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, |
318 | mvmvif->color)); | 339 | mvmvif->color)); |
319 | dtimper = vif->bss_conf.dtim_period; | 340 | dtimper = vif->bss_conf.dtim_period; |
341 | bi = vif->bss_conf.beacon_int; | ||
320 | 342 | ||
321 | /* | 343 | /* |
322 | * Regardless of power management state the driver must set | 344 | * Regardless of power management state the driver must set |
@@ -324,10 +346,9 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
324 | * immediately after association. Check that keep alive period | 346 | * immediately after association. Check that keep alive period |
325 | * is at least 3 * DTIM | 347 | * is at least 3 * DTIM |
326 | */ | 348 | */ |
327 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | 349 | keep_alive = DIV_ROUND_UP(ieee80211_tu_to_usec(3 * dtimper * bi), |
328 | keep_alive = max_t(int, 3 * dtimper_msec, | 350 | USEC_PER_SEC); |
329 | MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); | 351 | keep_alive = max(keep_alive, POWER_KEEP_ALIVE_PERIOD_SEC); |
330 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | ||
331 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); | 352 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); |
332 | 353 | ||
333 | if (mvm->ps_disabled) | 354 | if (mvm->ps_disabled) |
@@ -352,11 +373,14 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
352 | radar_detect = iwl_mvm_power_is_radar(vif); | 373 | radar_detect = iwl_mvm_power_is_radar(vif); |
353 | 374 | ||
354 | /* Check skip over DTIM conditions */ | 375 | /* Check skip over DTIM conditions */ |
355 | if (!radar_detect && (dtimper <= 10) && | 376 | if (!radar_detect && (dtimper < 10) && |
356 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || | 377 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || |
357 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { | 378 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { |
358 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | 379 | cmd->skip_dtim_periods = |
359 | cmd->skip_dtim_periods = 3; | 380 | iwl_mvm_power_get_skip_over_dtim(dtimper, bi); |
381 | if (cmd->skip_dtim_periods) | ||
382 | cmd->flags |= | ||
383 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
360 | } | 384 | } |
361 | 385 | ||
362 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { | 386 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index ce884847cc8a..30ceb67ed7a7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -158,6 +158,12 @@ struct rs_tx_column { | |||
158 | allow_column_func_t checks[MAX_COLUMN_CHECKS]; | 158 | allow_column_func_t checks[MAX_COLUMN_CHECKS]; |
159 | }; | 159 | }; |
160 | 160 | ||
161 | static bool rs_ant_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
162 | struct iwl_scale_tbl_info *tbl) | ||
163 | { | ||
164 | return iwl_mvm_bt_coex_is_ant_avail(mvm, tbl->rate.ant); | ||
165 | } | ||
166 | |||
161 | static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | 167 | static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
162 | struct iwl_scale_tbl_info *tbl) | 168 | struct iwl_scale_tbl_info *tbl) |
163 | { | 169 | { |
@@ -218,6 +224,9 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
218 | RS_COLUMN_INVALID, | 224 | RS_COLUMN_INVALID, |
219 | RS_COLUMN_INVALID, | 225 | RS_COLUMN_INVALID, |
220 | }, | 226 | }, |
227 | .checks = { | ||
228 | rs_ant_allow, | ||
229 | }, | ||
221 | }, | 230 | }, |
222 | [RS_COLUMN_LEGACY_ANT_B] = { | 231 | [RS_COLUMN_LEGACY_ANT_B] = { |
223 | .mode = RS_LEGACY, | 232 | .mode = RS_LEGACY, |
@@ -231,6 +240,9 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
231 | RS_COLUMN_INVALID, | 240 | RS_COLUMN_INVALID, |
232 | RS_COLUMN_INVALID, | 241 | RS_COLUMN_INVALID, |
233 | }, | 242 | }, |
243 | .checks = { | ||
244 | rs_ant_allow, | ||
245 | }, | ||
234 | }, | 246 | }, |
235 | [RS_COLUMN_SISO_ANT_A] = { | 247 | [RS_COLUMN_SISO_ANT_A] = { |
236 | .mode = RS_SISO, | 248 | .mode = RS_SISO, |
@@ -246,6 +258,7 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
246 | }, | 258 | }, |
247 | .checks = { | 259 | .checks = { |
248 | rs_siso_allow, | 260 | rs_siso_allow, |
261 | rs_ant_allow, | ||
249 | }, | 262 | }, |
250 | }, | 263 | }, |
251 | [RS_COLUMN_SISO_ANT_B] = { | 264 | [RS_COLUMN_SISO_ANT_B] = { |
@@ -262,6 +275,7 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
262 | }, | 275 | }, |
263 | .checks = { | 276 | .checks = { |
264 | rs_siso_allow, | 277 | rs_siso_allow, |
278 | rs_ant_allow, | ||
265 | }, | 279 | }, |
266 | }, | 280 | }, |
267 | [RS_COLUMN_SISO_ANT_A_SGI] = { | 281 | [RS_COLUMN_SISO_ANT_A_SGI] = { |
@@ -279,6 +293,7 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
279 | }, | 293 | }, |
280 | .checks = { | 294 | .checks = { |
281 | rs_siso_allow, | 295 | rs_siso_allow, |
296 | rs_ant_allow, | ||
282 | rs_sgi_allow, | 297 | rs_sgi_allow, |
283 | }, | 298 | }, |
284 | }, | 299 | }, |
@@ -297,6 +312,7 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
297 | }, | 312 | }, |
298 | .checks = { | 313 | .checks = { |
299 | rs_siso_allow, | 314 | rs_siso_allow, |
315 | rs_ant_allow, | ||
300 | rs_sgi_allow, | 316 | rs_sgi_allow, |
301 | }, | 317 | }, |
302 | }, | 318 | }, |
@@ -506,7 +522,7 @@ static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, | |||
506 | const char *prefix) | 522 | const char *prefix) |
507 | { | 523 | { |
508 | IWL_DEBUG_RATE(mvm, | 524 | IWL_DEBUG_RATE(mvm, |
509 | "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC %d\n", | 525 | "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC: %d\n", |
510 | prefix, rs_pretty_lq_type(rate->type), | 526 | prefix, rs_pretty_lq_type(rate->type), |
511 | rate->index, rs_pretty_ant(rate->ant), | 527 | rate->index, rs_pretty_ant(rate->ant), |
512 | rate->bw, rate->sgi, rate->ldpc, rate->stbc); | 528 | rate->bw, rate->sgi, rate->ldpc, rate->stbc); |
@@ -816,7 +832,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, | |||
816 | 832 | ||
817 | if (nss == 1) { | 833 | if (nss == 1) { |
818 | rate->type = LQ_VHT_SISO; | 834 | rate->type = LQ_VHT_SISO; |
819 | WARN_ON_ONCE(num_of_ant != 1); | 835 | WARN_ON_ONCE(!rate->stbc && num_of_ant != 1); |
820 | } else if (nss == 2) { | 836 | } else if (nss == 2) { |
821 | rate->type = LQ_VHT_MIMO2; | 837 | rate->type = LQ_VHT_MIMO2; |
822 | WARN_ON_ONCE(num_of_ant != 2); | 838 | WARN_ON_ONCE(num_of_ant != 2); |
@@ -1110,10 +1126,11 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
1110 | 1126 | ||
1111 | if (time_after(jiffies, | 1127 | if (time_after(jiffies, |
1112 | (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) { | 1128 | (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) { |
1113 | int tid; | 1129 | int t; |
1130 | |||
1114 | IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); | 1131 | IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); |
1115 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) | 1132 | for (t = 0; t < IWL_MAX_TID_COUNT; t++) |
1116 | ieee80211_stop_tx_ba_session(sta, tid); | 1133 | ieee80211_stop_tx_ba_session(sta, t); |
1117 | 1134 | ||
1118 | iwl_mvm_rs_rate_init(mvm, sta, info->band, false); | 1135 | iwl_mvm_rs_rate_init(mvm, sta, info->band, false); |
1119 | return; | 1136 | return; |
@@ -1154,16 +1171,15 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
1154 | /* Rate did match, so reset the missed_rate_counter */ | 1171 | /* Rate did match, so reset the missed_rate_counter */ |
1155 | lq_sta->missed_rate_counter = 0; | 1172 | lq_sta->missed_rate_counter = 0; |
1156 | 1173 | ||
1157 | /* Figure out if rate scale algorithm is in active or search table */ | 1174 | if (!lq_sta->search_better_tbl) { |
1158 | if (rs_rate_match(&rate, | ||
1159 | &(lq_sta->lq_info[lq_sta->active_tbl].rate))) { | ||
1160 | curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1175 | curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
1161 | other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | 1176 | other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); |
1162 | } else if (rs_rate_match(&rate, | 1177 | } else { |
1163 | &lq_sta->lq_info[1 - lq_sta->active_tbl].rate)) { | ||
1164 | curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | 1178 | curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); |
1165 | other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1179 | other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
1166 | } else { | 1180 | } |
1181 | |||
1182 | if (WARN_ON_ONCE(!rs_rate_match(&rate, &curr_tbl->rate))) { | ||
1167 | IWL_DEBUG_RATE(mvm, | 1183 | IWL_DEBUG_RATE(mvm, |
1168 | "Neither active nor search matches tx rate\n"); | 1184 | "Neither active nor search matches tx rate\n"); |
1169 | tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1185 | tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
@@ -1188,6 +1204,13 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
1188 | * first index into rate scale table. | 1204 | * first index into rate scale table. |
1189 | */ | 1205 | */ |
1190 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { | 1206 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { |
1207 | /* ampdu_ack_len = 0 marks no BA was received. In this case | ||
1208 | * treat it as a single frame loss as we don't want the success | ||
1209 | * ratio to dip too quickly because a BA wasn't received | ||
1210 | */ | ||
1211 | if (info->status.ampdu_ack_len == 0) | ||
1212 | info->status.ampdu_len = 1; | ||
1213 | |||
1191 | ucode_rate = le32_to_cpu(table->rs_table[0]); | 1214 | ucode_rate = le32_to_cpu(table->rs_table[0]); |
1192 | rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); | 1215 | rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); |
1193 | rs_collect_tx_data(lq_sta, curr_tbl, rate.index, | 1216 | rs_collect_tx_data(lq_sta, curr_tbl, rate.index, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 3cf40f3f58ec..94b6e7297a1e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -96,27 +96,27 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
96 | * Adds the rxb to a new skb and give it to mac80211 | 96 | * Adds the rxb to a new skb and give it to mac80211 |
97 | */ | 97 | */ |
98 | static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | 98 | static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, |
99 | struct sk_buff *skb, | ||
99 | struct ieee80211_hdr *hdr, u16 len, | 100 | struct ieee80211_hdr *hdr, u16 len, |
100 | u32 ampdu_status, | 101 | u32 ampdu_status, u8 crypt_len, |
101 | struct iwl_rx_cmd_buffer *rxb, | 102 | struct iwl_rx_cmd_buffer *rxb) |
102 | struct ieee80211_rx_status *stats) | ||
103 | { | 103 | { |
104 | struct sk_buff *skb; | ||
105 | unsigned int hdrlen, fraglen; | 104 | unsigned int hdrlen, fraglen; |
106 | 105 | ||
107 | /* Dont use dev_alloc_skb(), we'll have enough headroom once | ||
108 | * ieee80211_hdr pulled. | ||
109 | */ | ||
110 | skb = alloc_skb(128, GFP_ATOMIC); | ||
111 | if (!skb) { | ||
112 | IWL_ERR(mvm, "alloc_skb failed\n"); | ||
113 | return; | ||
114 | } | ||
115 | /* If frame is small enough to fit in skb->head, pull it completely. | 106 | /* If frame is small enough to fit in skb->head, pull it completely. |
116 | * If not, only pull ieee80211_hdr so that splice() or TCP coalesce | 107 | * If not, only pull ieee80211_hdr (including crypto if present, and |
117 | * are more efficient. | 108 | * an additional 8 bytes for SNAP/ethertype, see below) so that |
109 | * splice() or TCP coalesce are more efficient. | ||
110 | * | ||
111 | * Since, in addition, ieee80211_data_to_8023() always pull in at | ||
112 | * least 8 bytes (possibly more for mesh) we can do the same here | ||
113 | * to save the cost of doing it later. That still doesn't pull in | ||
114 | * the actual IP header since the typical case has a SNAP header. | ||
115 | * If the latter changes (there are efforts in the standards group | ||
116 | * to do so) we should revisit this and ieee80211_data_to_8023(). | ||
118 | */ | 117 | */ |
119 | hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr); | 118 | hdrlen = (len <= skb_tailroom(skb)) ? len : |
119 | sizeof(*hdr) + crypt_len + 8; | ||
120 | 120 | ||
121 | memcpy(skb_put(skb, hdrlen), hdr, hdrlen); | 121 | memcpy(skb_put(skb, hdrlen), hdr, hdrlen); |
122 | fraglen = len - hdrlen; | 122 | fraglen = len - hdrlen; |
@@ -129,8 +129,6 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | |||
129 | fraglen, rxb->truesize); | 129 | fraglen, rxb->truesize); |
130 | } | 130 | } |
131 | 131 | ||
132 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | ||
133 | |||
134 | ieee80211_rx(mvm->hw, skb); | 132 | ieee80211_rx(mvm->hw, skb); |
135 | } | 133 | } |
136 | 134 | ||
@@ -185,7 +183,8 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, | |||
185 | static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, | 183 | static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, |
186 | struct ieee80211_hdr *hdr, | 184 | struct ieee80211_hdr *hdr, |
187 | struct ieee80211_rx_status *stats, | 185 | struct ieee80211_rx_status *stats, |
188 | u32 rx_pkt_status) | 186 | u32 rx_pkt_status, |
187 | u8 *crypt_len) | ||
189 | { | 188 | { |
190 | if (!ieee80211_has_protected(hdr->frame_control) || | 189 | if (!ieee80211_has_protected(hdr->frame_control) || |
191 | (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == | 190 | (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == |
@@ -205,12 +204,14 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, | |||
205 | 204 | ||
206 | stats->flag |= RX_FLAG_DECRYPTED; | 205 | stats->flag |= RX_FLAG_DECRYPTED; |
207 | IWL_DEBUG_WEP(mvm, "hw decrypted CCMP successfully\n"); | 206 | IWL_DEBUG_WEP(mvm, "hw decrypted CCMP successfully\n"); |
207 | *crypt_len = IEEE80211_CCMP_HDR_LEN; | ||
208 | return 0; | 208 | return 0; |
209 | 209 | ||
210 | case RX_MPDU_RES_STATUS_SEC_TKIP_ENC: | 210 | case RX_MPDU_RES_STATUS_SEC_TKIP_ENC: |
211 | /* Don't drop the frame and decrypt it in SW */ | 211 | /* Don't drop the frame and decrypt it in SW */ |
212 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK)) | 212 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK)) |
213 | return 0; | 213 | return 0; |
214 | *crypt_len = IEEE80211_TKIP_IV_LEN; | ||
214 | /* fall through if TTAK OK */ | 215 | /* fall through if TTAK OK */ |
215 | 216 | ||
216 | case RX_MPDU_RES_STATUS_SEC_WEP_ENC: | 217 | case RX_MPDU_RES_STATUS_SEC_WEP_ENC: |
@@ -218,6 +219,9 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, | |||
218 | return -1; | 219 | return -1; |
219 | 220 | ||
220 | stats->flag |= RX_FLAG_DECRYPTED; | 221 | stats->flag |= RX_FLAG_DECRYPTED; |
222 | if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == | ||
223 | RX_MPDU_RES_STATUS_SEC_WEP_ENC) | ||
224 | *crypt_len = IEEE80211_WEP_IV_LEN; | ||
221 | return 0; | 225 | return 0; |
222 | 226 | ||
223 | case RX_MPDU_RES_STATUS_SEC_EXT_ENC: | 227 | case RX_MPDU_RES_STATUS_SEC_EXT_ENC: |
@@ -242,15 +246,17 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
242 | struct iwl_device_cmd *cmd) | 246 | struct iwl_device_cmd *cmd) |
243 | { | 247 | { |
244 | struct ieee80211_hdr *hdr; | 248 | struct ieee80211_hdr *hdr; |
245 | struct ieee80211_rx_status rx_status = {}; | 249 | struct ieee80211_rx_status *rx_status; |
246 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 250 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
247 | struct iwl_rx_phy_info *phy_info; | 251 | struct iwl_rx_phy_info *phy_info; |
248 | struct iwl_rx_mpdu_res_start *rx_res; | 252 | struct iwl_rx_mpdu_res_start *rx_res; |
249 | struct ieee80211_sta *sta; | 253 | struct ieee80211_sta *sta; |
254 | struct sk_buff *skb; | ||
250 | u32 len; | 255 | u32 len; |
251 | u32 ampdu_status; | 256 | u32 ampdu_status; |
252 | u32 rate_n_flags; | 257 | u32 rate_n_flags; |
253 | u32 rx_pkt_status; | 258 | u32 rx_pkt_status; |
259 | u8 crypt_len = 0; | ||
254 | 260 | ||
255 | phy_info = &mvm->last_phy_info; | 261 | phy_info = &mvm->last_phy_info; |
256 | rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data; | 262 | rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data; |
@@ -259,20 +265,32 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
259 | rx_pkt_status = le32_to_cpup((__le32 *) | 265 | rx_pkt_status = le32_to_cpup((__le32 *) |
260 | (pkt->data + sizeof(*rx_res) + len)); | 266 | (pkt->data + sizeof(*rx_res) + len)); |
261 | 267 | ||
262 | memset(&rx_status, 0, sizeof(rx_status)); | 268 | /* Dont use dev_alloc_skb(), we'll have enough headroom once |
269 | * ieee80211_hdr pulled. | ||
270 | */ | ||
271 | skb = alloc_skb(128, GFP_ATOMIC); | ||
272 | if (!skb) { | ||
273 | IWL_ERR(mvm, "alloc_skb failed\n"); | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | rx_status = IEEE80211_SKB_RXCB(skb); | ||
263 | 278 | ||
264 | /* | 279 | /* |
265 | * drop the packet if it has failed being decrypted by HW | 280 | * drop the packet if it has failed being decrypted by HW |
266 | */ | 281 | */ |
267 | if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, &rx_status, rx_pkt_status)) { | 282 | if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, rx_status, rx_pkt_status, |
283 | &crypt_len)) { | ||
268 | IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n", | 284 | IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n", |
269 | rx_pkt_status); | 285 | rx_pkt_status); |
286 | kfree_skb(skb); | ||
270 | return 0; | 287 | return 0; |
271 | } | 288 | } |
272 | 289 | ||
273 | if ((unlikely(phy_info->cfg_phy_cnt > 20))) { | 290 | if ((unlikely(phy_info->cfg_phy_cnt > 20))) { |
274 | IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n", | 291 | IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n", |
275 | phy_info->cfg_phy_cnt); | 292 | phy_info->cfg_phy_cnt); |
293 | kfree_skb(skb); | ||
276 | return 0; | 294 | return 0; |
277 | } | 295 | } |
278 | 296 | ||
@@ -283,31 +301,31 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
283 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) || | 301 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) || |
284 | !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) { | 302 | !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) { |
285 | IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); | 303 | IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); |
286 | rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; | 304 | rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; |
287 | } | 305 | } |
288 | 306 | ||
289 | /* This will be used in several places later */ | 307 | /* This will be used in several places later */ |
290 | rate_n_flags = le32_to_cpu(phy_info->rate_n_flags); | 308 | rate_n_flags = le32_to_cpu(phy_info->rate_n_flags); |
291 | 309 | ||
292 | /* rx_status carries information about the packet to mac80211 */ | 310 | /* rx_status carries information about the packet to mac80211 */ |
293 | rx_status.mactime = le64_to_cpu(phy_info->timestamp); | 311 | rx_status->mactime = le64_to_cpu(phy_info->timestamp); |
294 | rx_status.device_timestamp = le32_to_cpu(phy_info->system_timestamp); | 312 | rx_status->device_timestamp = le32_to_cpu(phy_info->system_timestamp); |
295 | rx_status.band = | 313 | rx_status->band = |
296 | (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ? | 314 | (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ? |
297 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | 315 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; |
298 | rx_status.freq = | 316 | rx_status->freq = |
299 | ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel), | 317 | ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel), |
300 | rx_status.band); | 318 | rx_status->band); |
301 | /* | 319 | /* |
302 | * TSF as indicated by the fw is at INA time, but mac80211 expects the | 320 | * TSF as indicated by the fw is at INA time, but mac80211 expects the |
303 | * TSF at the beginning of the MPDU. | 321 | * TSF at the beginning of the MPDU. |
304 | */ | 322 | */ |
305 | /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ | 323 | /*rx_status->flag |= RX_FLAG_MACTIME_MPDU;*/ |
306 | 324 | ||
307 | iwl_mvm_get_signal_strength(mvm, phy_info, &rx_status); | 325 | iwl_mvm_get_signal_strength(mvm, phy_info, rx_status); |
308 | 326 | ||
309 | IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal, | 327 | IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status->signal, |
310 | (unsigned long long)rx_status.mactime); | 328 | (unsigned long long)rx_status->mactime); |
311 | 329 | ||
312 | rcu_read_lock(); | 330 | rcu_read_lock(); |
313 | /* | 331 | /* |
@@ -326,15 +344,14 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
326 | if (sta) { | 344 | if (sta) { |
327 | struct iwl_mvm_sta *mvmsta; | 345 | struct iwl_mvm_sta *mvmsta; |
328 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | 346 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
329 | rs_update_last_rssi(mvm, &mvmsta->lq_sta, | 347 | rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status); |
330 | &rx_status); | ||
331 | } | 348 | } |
332 | 349 | ||
333 | rcu_read_unlock(); | 350 | rcu_read_unlock(); |
334 | 351 | ||
335 | /* set the preamble flag if appropriate */ | 352 | /* set the preamble flag if appropriate */ |
336 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) | 353 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) |
337 | rx_status.flag |= RX_FLAG_SHORTPRE; | 354 | rx_status->flag |= RX_FLAG_SHORTPRE; |
338 | 355 | ||
339 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { | 356 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { |
340 | /* | 357 | /* |
@@ -342,8 +359,8 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
342 | * together since we get a single PHY response | 359 | * together since we get a single PHY response |
343 | * from the firmware for all of them | 360 | * from the firmware for all of them |
344 | */ | 361 | */ |
345 | rx_status.flag |= RX_FLAG_AMPDU_DETAILS; | 362 | rx_status->flag |= RX_FLAG_AMPDU_DETAILS; |
346 | rx_status.ampdu_reference = mvm->ampdu_ref; | 363 | rx_status->ampdu_reference = mvm->ampdu_ref; |
347 | } | 364 | } |
348 | 365 | ||
349 | /* Set up the HT phy flags */ | 366 | /* Set up the HT phy flags */ |
@@ -351,50 +368,50 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
351 | case RATE_MCS_CHAN_WIDTH_20: | 368 | case RATE_MCS_CHAN_WIDTH_20: |
352 | break; | 369 | break; |
353 | case RATE_MCS_CHAN_WIDTH_40: | 370 | case RATE_MCS_CHAN_WIDTH_40: |
354 | rx_status.flag |= RX_FLAG_40MHZ; | 371 | rx_status->flag |= RX_FLAG_40MHZ; |
355 | break; | 372 | break; |
356 | case RATE_MCS_CHAN_WIDTH_80: | 373 | case RATE_MCS_CHAN_WIDTH_80: |
357 | rx_status.vht_flag |= RX_VHT_FLAG_80MHZ; | 374 | rx_status->vht_flag |= RX_VHT_FLAG_80MHZ; |
358 | break; | 375 | break; |
359 | case RATE_MCS_CHAN_WIDTH_160: | 376 | case RATE_MCS_CHAN_WIDTH_160: |
360 | rx_status.vht_flag |= RX_VHT_FLAG_160MHZ; | 377 | rx_status->vht_flag |= RX_VHT_FLAG_160MHZ; |
361 | break; | 378 | break; |
362 | } | 379 | } |
363 | if (rate_n_flags & RATE_MCS_SGI_MSK) | 380 | if (rate_n_flags & RATE_MCS_SGI_MSK) |
364 | rx_status.flag |= RX_FLAG_SHORT_GI; | 381 | rx_status->flag |= RX_FLAG_SHORT_GI; |
365 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) | 382 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) |
366 | rx_status.flag |= RX_FLAG_HT_GF; | 383 | rx_status->flag |= RX_FLAG_HT_GF; |
367 | if (rate_n_flags & RATE_MCS_LDPC_MSK) | 384 | if (rate_n_flags & RATE_MCS_LDPC_MSK) |
368 | rx_status.flag |= RX_FLAG_LDPC; | 385 | rx_status->flag |= RX_FLAG_LDPC; |
369 | if (rate_n_flags & RATE_MCS_HT_MSK) { | 386 | if (rate_n_flags & RATE_MCS_HT_MSK) { |
370 | u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> | 387 | u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> |
371 | RATE_MCS_STBC_POS; | 388 | RATE_MCS_STBC_POS; |
372 | rx_status.flag |= RX_FLAG_HT; | 389 | rx_status->flag |= RX_FLAG_HT; |
373 | rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; | 390 | rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; |
374 | rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT; | 391 | rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT; |
375 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { | 392 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { |
376 | u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >> | 393 | u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >> |
377 | RATE_MCS_STBC_POS; | 394 | RATE_MCS_STBC_POS; |
378 | rx_status.vht_nss = | 395 | rx_status->vht_nss = |
379 | ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> | 396 | ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> |
380 | RATE_VHT_MCS_NSS_POS) + 1; | 397 | RATE_VHT_MCS_NSS_POS) + 1; |
381 | rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; | 398 | rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; |
382 | rx_status.flag |= RX_FLAG_VHT; | 399 | rx_status->flag |= RX_FLAG_VHT; |
383 | rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT; | 400 | rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT; |
384 | if (rate_n_flags & RATE_MCS_BF_MSK) | 401 | if (rate_n_flags & RATE_MCS_BF_MSK) |
385 | rx_status.vht_flag |= RX_VHT_FLAG_BF; | 402 | rx_status->vht_flag |= RX_VHT_FLAG_BF; |
386 | } else { | 403 | } else { |
387 | rx_status.rate_idx = | 404 | rx_status->rate_idx = |
388 | iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, | 405 | iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, |
389 | rx_status.band); | 406 | rx_status->band); |
390 | } | 407 | } |
391 | 408 | ||
392 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 409 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
393 | iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags, | 410 | iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags, |
394 | rx_status.flag & RX_FLAG_AMPDU_DETAILS); | 411 | rx_status->flag & RX_FLAG_AMPDU_DETAILS); |
395 | #endif | 412 | #endif |
396 | iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status, | 413 | iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status, |
397 | rxb, &rx_status); | 414 | crypt_len, rxb); |
398 | return 0; | 415 | return 0; |
399 | } | 416 | } |
400 | 417 | ||
@@ -500,29 +517,8 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, | |||
500 | .mvm = mvm, | 517 | .mvm = mvm, |
501 | }; | 518 | }; |
502 | 519 | ||
503 | /* | 520 | iwl_mvm_tt_temp_changed(mvm, le32_to_cpu(common->temperature)); |
504 | * set temperature debug enabled - ignore FW temperature updates | ||
505 | * and use the user set temperature. | ||
506 | */ | ||
507 | if (mvm->temperature_test) { | ||
508 | if (mvm->temperature < le32_to_cpu(common->temperature)) | ||
509 | IWL_DEBUG_TEMP(mvm, | ||
510 | "Ignoring FW temperature update that is greater than the debug set temperature (debug temp = %d, fw temp = %d)\n", | ||
511 | mvm->temperature, | ||
512 | le32_to_cpu(common->temperature)); | ||
513 | /* | ||
514 | * skip iwl_mvm_tt_handler since we are in | ||
515 | * temperature debug mode and we are ignoring | ||
516 | * the new temperature value | ||
517 | */ | ||
518 | goto update; | ||
519 | } | ||
520 | 521 | ||
521 | if (mvm->temperature != le32_to_cpu(common->temperature)) { | ||
522 | mvm->temperature = le32_to_cpu(common->temperature); | ||
523 | iwl_mvm_tt_handler(mvm); | ||
524 | } | ||
525 | update: | ||
526 | iwl_mvm_update_rx_statistics(mvm, stats); | 522 | iwl_mvm_update_rx_statistics(mvm, stats); |
527 | 523 | ||
528 | ieee80211_iterate_active_interfaces(mvm->hw, | 524 | ieee80211_iterate_active_interfaces(mvm->hw, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 5cd59a43e1da..e5294d01181e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -83,15 +83,29 @@ struct iwl_mvm_scan_params { | |||
83 | } dwell[IEEE80211_NUM_BANDS]; | 83 | } dwell[IEEE80211_NUM_BANDS]; |
84 | }; | 84 | }; |
85 | 85 | ||
86 | enum iwl_umac_scan_uid_type { | ||
87 | IWL_UMAC_SCAN_UID_REG_SCAN = BIT(0), | ||
88 | IWL_UMAC_SCAN_UID_SCHED_SCAN = BIT(1), | ||
89 | IWL_UMAC_SCAN_UID_ALL = IWL_UMAC_SCAN_UID_REG_SCAN | | ||
90 | IWL_UMAC_SCAN_UID_SCHED_SCAN, | ||
91 | }; | ||
92 | |||
93 | static int iwl_umac_scan_stop(struct iwl_mvm *mvm, | ||
94 | enum iwl_umac_scan_uid_type type, bool notify); | ||
95 | |||
96 | static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) | ||
97 | { | ||
98 | if (mvm->scan_rx_ant != ANT_NONE) | ||
99 | return mvm->scan_rx_ant; | ||
100 | return mvm->fw->valid_rx_ant; | ||
101 | } | ||
102 | |||
86 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) | 103 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) |
87 | { | 104 | { |
88 | u16 rx_chain; | 105 | u16 rx_chain; |
89 | u8 rx_ant; | 106 | u8 rx_ant; |
90 | 107 | ||
91 | if (mvm->scan_rx_ant != ANT_NONE) | 108 | rx_ant = iwl_mvm_scan_rx_ant(mvm); |
92 | rx_ant = mvm->scan_rx_ant; | ||
93 | else | ||
94 | rx_ant = mvm->fw->valid_rx_ant; | ||
95 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; | 109 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; |
96 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; | 110 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; |
97 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; | 111 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; |
@@ -366,6 +380,10 @@ static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm, | |||
366 | !is_sched_scan) | 380 | !is_sched_scan) |
367 | max_probe_len -= 32; | 381 | max_probe_len -= 32; |
368 | 382 | ||
383 | /* DS parameter set element is added on 2.4GHZ band if required */ | ||
384 | if (iwl_mvm_rrm_scan_needed(mvm)) | ||
385 | max_probe_len -= 3; | ||
386 | |||
369 | return max_probe_len; | 387 | return max_probe_len; |
370 | } | 388 | } |
371 | 389 | ||
@@ -537,23 +555,17 @@ int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm, | |||
537 | struct iwl_device_cmd *cmd) | 555 | struct iwl_device_cmd *cmd) |
538 | { | 556 | { |
539 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 557 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
540 | u8 client_bitmap = 0; | ||
541 | 558 | ||
542 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | 559 | if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) && |
560 | !(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | ||
543 | struct iwl_sched_scan_results *notif = (void *)pkt->data; | 561 | struct iwl_sched_scan_results *notif = (void *)pkt->data; |
544 | 562 | ||
545 | client_bitmap = notif->client_bitmap; | 563 | if (!(notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN)) |
564 | return 0; | ||
546 | } | 565 | } |
547 | 566 | ||
548 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN || | 567 | IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); |
549 | client_bitmap & SCAN_CLIENT_SCHED_SCAN) { | 568 | ieee80211_sched_scan_results(mvm->hw); |
550 | if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { | ||
551 | IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); | ||
552 | ieee80211_sched_scan_results(mvm->hw); | ||
553 | } else { | ||
554 | IWL_DEBUG_SCAN(mvm, "Scan results\n"); | ||
555 | } | ||
556 | } | ||
557 | 569 | ||
558 | return 0; | 570 | return 0; |
559 | } | 571 | } |
@@ -603,16 +615,6 @@ static int iwl_mvm_cancel_regular_scan(struct iwl_mvm *mvm) | |||
603 | SCAN_COMPLETE_NOTIFICATION }; | 615 | SCAN_COMPLETE_NOTIFICATION }; |
604 | int ret; | 616 | int ret; |
605 | 617 | ||
606 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) | ||
607 | return 0; | ||
608 | |||
609 | if (iwl_mvm_is_radio_killed(mvm)) { | ||
610 | ieee80211_scan_completed(mvm->hw, true); | ||
611 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
612 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort, | 618 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort, |
617 | scan_abort_notif, | 619 | scan_abort_notif, |
618 | ARRAY_SIZE(scan_abort_notif), | 620 | ARRAY_SIZE(scan_abort_notif), |
@@ -975,6 +977,20 @@ free_blacklist: | |||
975 | return ret; | 977 | return ret; |
976 | } | 978 | } |
977 | 979 | ||
980 | static bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm, | ||
981 | struct cfg80211_sched_scan_request *req) | ||
982 | { | ||
983 | if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { | ||
984 | IWL_DEBUG_SCAN(mvm, | ||
985 | "Sending scheduled scan with filtering, n_match_sets %d\n", | ||
986 | req->n_match_sets); | ||
987 | return false; | ||
988 | } | ||
989 | |||
990 | IWL_DEBUG_SCAN(mvm, "Sending Scheduled scan without filtering\n"); | ||
991 | return true; | ||
992 | } | ||
993 | |||
978 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | 994 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, |
979 | struct cfg80211_sched_scan_request *req) | 995 | struct cfg80211_sched_scan_request *req) |
980 | { | 996 | { |
@@ -990,15 +1006,8 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | |||
990 | .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER, | 1006 | .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER, |
991 | }; | 1007 | }; |
992 | 1008 | ||
993 | if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { | 1009 | if (iwl_mvm_scan_pass_all(mvm, req)) |
994 | IWL_DEBUG_SCAN(mvm, | ||
995 | "Sending scheduled scan with filtering, filter len %d\n", | ||
996 | req->n_match_sets); | ||
997 | } else { | ||
998 | IWL_DEBUG_SCAN(mvm, | ||
999 | "Sending Scheduled scan without filtering\n"); | ||
1000 | scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL); | 1010 | scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL); |
1001 | } | ||
1002 | 1011 | ||
1003 | if (mvm->last_ebs_successful && | 1012 | if (mvm->last_ebs_successful && |
1004 | mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) | 1013 | mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) |
@@ -1016,12 +1025,19 @@ int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm, | |||
1016 | { | 1025 | { |
1017 | int ret; | 1026 | int ret; |
1018 | 1027 | ||
1019 | if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | 1028 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { |
1029 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); | ||
1030 | if (ret) | ||
1031 | return ret; | ||
1032 | ret = iwl_mvm_sched_scan_umac(mvm, vif, req, ies); | ||
1033 | } else if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | ||
1034 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | ||
1020 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); | 1035 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); |
1021 | if (ret) | 1036 | if (ret) |
1022 | return ret; | 1037 | return ret; |
1023 | ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); | 1038 | ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); |
1024 | } else { | 1039 | } else { |
1040 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | ||
1025 | ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); | 1041 | ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); |
1026 | if (ret) | 1042 | if (ret) |
1027 | return ret; | 1043 | return ret; |
@@ -1078,6 +1094,10 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) | |||
1078 | 1094 | ||
1079 | lockdep_assert_held(&mvm->mutex); | 1095 | lockdep_assert_held(&mvm->mutex); |
1080 | 1096 | ||
1097 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
1098 | return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN, | ||
1099 | notify); | ||
1100 | |||
1081 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED && | 1101 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED && |
1082 | (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) || | 1102 | (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) || |
1083 | mvm->scan_status != IWL_MVM_SCAN_OS)) { | 1103 | mvm->scan_status != IWL_MVM_SCAN_OS)) { |
@@ -1165,20 +1185,64 @@ iwl_mvm_lmac_scan_cfg_channels(struct iwl_mvm *mvm, | |||
1165 | } | 1185 | } |
1166 | } | 1186 | } |
1167 | 1187 | ||
1188 | static u8 *iwl_mvm_copy_and_insert_ds_elem(struct iwl_mvm *mvm, const u8 *ies, | ||
1189 | size_t len, u8 *const pos) | ||
1190 | { | ||
1191 | static const u8 before_ds_params[] = { | ||
1192 | WLAN_EID_SSID, | ||
1193 | WLAN_EID_SUPP_RATES, | ||
1194 | WLAN_EID_REQUEST, | ||
1195 | WLAN_EID_EXT_SUPP_RATES, | ||
1196 | }; | ||
1197 | size_t offs; | ||
1198 | u8 *newpos = pos; | ||
1199 | |||
1200 | if (!iwl_mvm_rrm_scan_needed(mvm)) { | ||
1201 | memcpy(newpos, ies, len); | ||
1202 | return newpos + len; | ||
1203 | } | ||
1204 | |||
1205 | offs = ieee80211_ie_split(ies, len, | ||
1206 | before_ds_params, | ||
1207 | ARRAY_SIZE(before_ds_params), | ||
1208 | 0); | ||
1209 | |||
1210 | memcpy(newpos, ies, offs); | ||
1211 | newpos += offs; | ||
1212 | |||
1213 | /* Add a placeholder for DS Parameter Set element */ | ||
1214 | *newpos++ = WLAN_EID_DS_PARAMS; | ||
1215 | *newpos++ = 1; | ||
1216 | *newpos++ = 0; | ||
1217 | |||
1218 | memcpy(newpos, ies + offs, len - offs); | ||
1219 | newpos += len - offs; | ||
1220 | |||
1221 | return newpos; | ||
1222 | } | ||
1223 | |||
1168 | static void | 1224 | static void |
1169 | iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1225 | iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
1170 | struct ieee80211_scan_ies *ies, | 1226 | struct ieee80211_scan_ies *ies, |
1171 | struct iwl_scan_req_unified_lmac *cmd) | 1227 | struct iwl_scan_probe_req *preq, |
1228 | const u8 *mac_addr, const u8 *mac_addr_mask) | ||
1172 | { | 1229 | { |
1173 | struct iwl_scan_probe_req *preq = (void *)(cmd->data + | ||
1174 | sizeof(struct iwl_scan_channel_cfg_lmac) * | ||
1175 | mvm->fw->ucode_capa.n_scan_channels); | ||
1176 | struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf; | 1230 | struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf; |
1177 | u8 *pos; | 1231 | u8 *pos, *newpos; |
1232 | |||
1233 | /* | ||
1234 | * Unfortunately, right now the offload scan doesn't support randomising | ||
1235 | * within the firmware, so until the firmware API is ready we implement | ||
1236 | * it in the driver. This means that the scan iterations won't really be | ||
1237 | * random, only when it's restarted, but at least that helps a bit. | ||
1238 | */ | ||
1239 | if (mac_addr) | ||
1240 | get_random_mask_addr(frame->sa, mac_addr, mac_addr_mask); | ||
1241 | else | ||
1242 | memcpy(frame->sa, vif->addr, ETH_ALEN); | ||
1178 | 1243 | ||
1179 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | 1244 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); |
1180 | eth_broadcast_addr(frame->da); | 1245 | eth_broadcast_addr(frame->da); |
1181 | memcpy(frame->sa, vif->addr, ETH_ALEN); | ||
1182 | eth_broadcast_addr(frame->bssid); | 1246 | eth_broadcast_addr(frame->bssid); |
1183 | frame->seq_ctrl = 0; | 1247 | frame->seq_ctrl = 0; |
1184 | 1248 | ||
@@ -1189,11 +1253,14 @@ iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
1189 | preq->mac_header.offset = 0; | 1253 | preq->mac_header.offset = 0; |
1190 | preq->mac_header.len = cpu_to_le16(24 + 2); | 1254 | preq->mac_header.len = cpu_to_le16(24 + 2); |
1191 | 1255 | ||
1192 | memcpy(pos, ies->ies[IEEE80211_BAND_2GHZ], | 1256 | /* Insert ds parameter set element on 2.4 GHz band */ |
1193 | ies->len[IEEE80211_BAND_2GHZ]); | 1257 | newpos = iwl_mvm_copy_and_insert_ds_elem(mvm, |
1258 | ies->ies[IEEE80211_BAND_2GHZ], | ||
1259 | ies->len[IEEE80211_BAND_2GHZ], | ||
1260 | pos); | ||
1194 | preq->band_data[0].offset = cpu_to_le16(pos - preq->buf); | 1261 | preq->band_data[0].offset = cpu_to_le16(pos - preq->buf); |
1195 | preq->band_data[0].len = cpu_to_le16(ies->len[IEEE80211_BAND_2GHZ]); | 1262 | preq->band_data[0].len = cpu_to_le16(newpos - pos); |
1196 | pos += ies->len[IEEE80211_BAND_2GHZ]; | 1263 | pos = newpos; |
1197 | 1264 | ||
1198 | memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ], | 1265 | memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ], |
1199 | ies->len[IEEE80211_BAND_5GHZ]); | 1266 | ies->len[IEEE80211_BAND_5GHZ]); |
@@ -1254,9 +1321,10 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, | |||
1254 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | 1321 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
1255 | }; | 1322 | }; |
1256 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; | 1323 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; |
1324 | struct iwl_scan_probe_req *preq; | ||
1257 | struct iwl_mvm_scan_params params = {}; | 1325 | struct iwl_mvm_scan_params params = {}; |
1258 | u32 flags; | 1326 | u32 flags; |
1259 | int ssid_bitmap = 0; | 1327 | u32 ssid_bitmap = 0; |
1260 | int ret, i; | 1328 | int ret, i; |
1261 | 1329 | ||
1262 | lockdep_assert_held(&mvm->mutex); | 1330 | lockdep_assert_held(&mvm->mutex); |
@@ -1315,7 +1383,13 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, | |||
1315 | req->req.n_channels, ssid_bitmap, | 1383 | req->req.n_channels, ssid_bitmap, |
1316 | cmd); | 1384 | cmd); |
1317 | 1385 | ||
1318 | iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, cmd); | 1386 | preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) * |
1387 | mvm->fw->ucode_capa.n_scan_channels); | ||
1388 | |||
1389 | iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, preq, | ||
1390 | req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ? | ||
1391 | req->req.mac_addr : NULL, | ||
1392 | req->req.mac_addr_mask); | ||
1319 | 1393 | ||
1320 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | 1394 | ret = iwl_mvm_send_cmd(mvm, &hcmd); |
1321 | if (!ret) { | 1395 | if (!ret) { |
@@ -1348,6 +1422,7 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
1348 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | 1422 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
1349 | }; | 1423 | }; |
1350 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; | 1424 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; |
1425 | struct iwl_scan_probe_req *preq; | ||
1351 | struct iwl_mvm_scan_params params = {}; | 1426 | struct iwl_mvm_scan_params params = {}; |
1352 | int ret; | 1427 | int ret; |
1353 | u32 flags = 0, ssid_bitmap = 0; | 1428 | u32 flags = 0, ssid_bitmap = 0; |
@@ -1371,15 +1446,8 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
1371 | 1446 | ||
1372 | cmd->n_channels = (u8)req->n_channels; | 1447 | cmd->n_channels = (u8)req->n_channels; |
1373 | 1448 | ||
1374 | if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { | 1449 | if (iwl_mvm_scan_pass_all(mvm, req)) |
1375 | IWL_DEBUG_SCAN(mvm, | ||
1376 | "Sending scheduled scan with filtering, n_match_sets %d\n", | ||
1377 | req->n_match_sets); | ||
1378 | } else { | ||
1379 | IWL_DEBUG_SCAN(mvm, | ||
1380 | "Sending Scheduled scan without filtering\n"); | ||
1381 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; | 1450 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; |
1382 | } | ||
1383 | 1451 | ||
1384 | if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0) | 1452 | if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0) |
1385 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; | 1453 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; |
@@ -1409,7 +1477,13 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
1409 | iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels, | 1477 | iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels, |
1410 | ssid_bitmap, cmd); | 1478 | ssid_bitmap, cmd); |
1411 | 1479 | ||
1412 | iwl_mvm_build_unified_scan_probe(mvm, vif, ies, cmd); | 1480 | preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) * |
1481 | mvm->fw->ucode_capa.n_scan_channels); | ||
1482 | |||
1483 | iwl_mvm_build_unified_scan_probe(mvm, vif, ies, preq, | ||
1484 | req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ? | ||
1485 | req->mac_addr : NULL, | ||
1486 | req->mac_addr_mask); | ||
1413 | 1487 | ||
1414 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | 1488 | ret = iwl_mvm_send_cmd(mvm, &hcmd); |
1415 | if (!ret) { | 1489 | if (!ret) { |
@@ -1431,7 +1505,594 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
1431 | 1505 | ||
1432 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) | 1506 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) |
1433 | { | 1507 | { |
1508 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
1509 | return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_REG_SCAN, | ||
1510 | true); | ||
1511 | |||
1512 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) | ||
1513 | return 0; | ||
1514 | |||
1515 | if (iwl_mvm_is_radio_killed(mvm)) { | ||
1516 | ieee80211_scan_completed(mvm->hw, true); | ||
1517 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
1518 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
1519 | return 0; | ||
1520 | } | ||
1521 | |||
1434 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 1522 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) |
1435 | return iwl_mvm_scan_offload_stop(mvm, true); | 1523 | return iwl_mvm_scan_offload_stop(mvm, true); |
1436 | return iwl_mvm_cancel_regular_scan(mvm); | 1524 | return iwl_mvm_cancel_regular_scan(mvm); |
1437 | } | 1525 | } |
1526 | |||
1527 | /* UMAC scan API */ | ||
1528 | |||
1529 | struct iwl_umac_scan_done { | ||
1530 | struct iwl_mvm *mvm; | ||
1531 | enum iwl_umac_scan_uid_type type; | ||
1532 | }; | ||
1533 | |||
1534 | static int rate_to_scan_rate_flag(unsigned int rate) | ||
1535 | { | ||
1536 | static const int rate_to_scan_rate[IWL_RATE_COUNT] = { | ||
1537 | [IWL_RATE_1M_INDEX] = SCAN_CONFIG_RATE_1M, | ||
1538 | [IWL_RATE_2M_INDEX] = SCAN_CONFIG_RATE_2M, | ||
1539 | [IWL_RATE_5M_INDEX] = SCAN_CONFIG_RATE_5M, | ||
1540 | [IWL_RATE_11M_INDEX] = SCAN_CONFIG_RATE_11M, | ||
1541 | [IWL_RATE_6M_INDEX] = SCAN_CONFIG_RATE_6M, | ||
1542 | [IWL_RATE_9M_INDEX] = SCAN_CONFIG_RATE_9M, | ||
1543 | [IWL_RATE_12M_INDEX] = SCAN_CONFIG_RATE_12M, | ||
1544 | [IWL_RATE_18M_INDEX] = SCAN_CONFIG_RATE_18M, | ||
1545 | [IWL_RATE_24M_INDEX] = SCAN_CONFIG_RATE_24M, | ||
1546 | [IWL_RATE_36M_INDEX] = SCAN_CONFIG_RATE_36M, | ||
1547 | [IWL_RATE_48M_INDEX] = SCAN_CONFIG_RATE_48M, | ||
1548 | [IWL_RATE_54M_INDEX] = SCAN_CONFIG_RATE_54M, | ||
1549 | }; | ||
1550 | |||
1551 | return rate_to_scan_rate[rate]; | ||
1552 | } | ||
1553 | |||
1554 | static __le32 iwl_mvm_scan_config_rates(struct iwl_mvm *mvm) | ||
1555 | { | ||
1556 | struct ieee80211_supported_band *band; | ||
1557 | unsigned int rates = 0; | ||
1558 | int i; | ||
1559 | |||
1560 | band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; | ||
1561 | for (i = 0; i < band->n_bitrates; i++) | ||
1562 | rates |= rate_to_scan_rate_flag(band->bitrates[i].hw_value); | ||
1563 | band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | ||
1564 | for (i = 0; i < band->n_bitrates; i++) | ||
1565 | rates |= rate_to_scan_rate_flag(band->bitrates[i].hw_value); | ||
1566 | |||
1567 | /* Set both basic rates and supported rates */ | ||
1568 | rates |= SCAN_CONFIG_SUPPORTED_RATE(rates); | ||
1569 | |||
1570 | return cpu_to_le32(rates); | ||
1571 | } | ||
1572 | |||
1573 | int iwl_mvm_config_scan(struct iwl_mvm *mvm) | ||
1574 | { | ||
1575 | |||
1576 | struct iwl_scan_config *scan_config; | ||
1577 | struct ieee80211_supported_band *band; | ||
1578 | int num_channels = | ||
1579 | mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + | ||
1580 | mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; | ||
1581 | int ret, i, j = 0, cmd_size, data_size; | ||
1582 | struct iwl_host_cmd cmd = { | ||
1583 | .id = SCAN_CFG_CMD, | ||
1584 | }; | ||
1585 | |||
1586 | if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) | ||
1587 | return -ENOBUFS; | ||
1588 | |||
1589 | cmd_size = sizeof(*scan_config) + mvm->fw->ucode_capa.n_scan_channels; | ||
1590 | |||
1591 | scan_config = kzalloc(cmd_size, GFP_KERNEL); | ||
1592 | if (!scan_config) | ||
1593 | return -ENOMEM; | ||
1594 | |||
1595 | data_size = cmd_size - sizeof(struct iwl_mvm_umac_cmd_hdr); | ||
1596 | scan_config->hdr.size = cpu_to_le16(data_size); | ||
1597 | scan_config->flags = cpu_to_le32(SCAN_CONFIG_FLAG_ACTIVATE | | ||
1598 | SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | | ||
1599 | SCAN_CONFIG_FLAG_SET_TX_CHAINS | | ||
1600 | SCAN_CONFIG_FLAG_SET_RX_CHAINS | | ||
1601 | SCAN_CONFIG_FLAG_SET_ALL_TIMES | | ||
1602 | SCAN_CONFIG_FLAG_SET_LEGACY_RATES | | ||
1603 | SCAN_CONFIG_FLAG_SET_MAC_ADDR | | ||
1604 | SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| | ||
1605 | SCAN_CONFIG_N_CHANNELS(num_channels)); | ||
1606 | scan_config->tx_chains = cpu_to_le32(mvm->fw->valid_tx_ant); | ||
1607 | scan_config->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm)); | ||
1608 | scan_config->legacy_rates = iwl_mvm_scan_config_rates(mvm); | ||
1609 | scan_config->out_of_channel_time = cpu_to_le32(170); | ||
1610 | scan_config->suspend_time = cpu_to_le32(30); | ||
1611 | scan_config->dwell_active = 20; | ||
1612 | scan_config->dwell_passive = 110; | ||
1613 | scan_config->dwell_fragmented = 20; | ||
1614 | |||
1615 | memcpy(&scan_config->mac_addr, &mvm->addresses[0].addr, ETH_ALEN); | ||
1616 | |||
1617 | scan_config->bcast_sta_id = mvm->aux_sta.sta_id; | ||
1618 | scan_config->channel_flags = IWL_CHANNEL_FLAG_EBS | | ||
1619 | IWL_CHANNEL_FLAG_ACCURATE_EBS | | ||
1620 | IWL_CHANNEL_FLAG_EBS_ADD | | ||
1621 | IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE; | ||
1622 | |||
1623 | band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; | ||
1624 | for (i = 0; i < band->n_channels; i++, j++) | ||
1625 | scan_config->channel_array[j] = band->channels[i].center_freq; | ||
1626 | band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | ||
1627 | for (i = 0; i < band->n_channels; i++, j++) | ||
1628 | scan_config->channel_array[j] = band->channels[i].center_freq; | ||
1629 | |||
1630 | cmd.data[0] = scan_config; | ||
1631 | cmd.len[0] = cmd_size; | ||
1632 | cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; | ||
1633 | |||
1634 | IWL_DEBUG_SCAN(mvm, "Sending UMAC scan config\n"); | ||
1635 | |||
1636 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
1637 | |||
1638 | kfree(scan_config); | ||
1639 | return ret; | ||
1640 | } | ||
1641 | |||
1642 | static int iwl_mvm_find_scan_uid(struct iwl_mvm *mvm, u32 uid) | ||
1643 | { | ||
1644 | int i; | ||
1645 | |||
1646 | for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) | ||
1647 | if (mvm->scan_uid[i] == uid) | ||
1648 | return i; | ||
1649 | |||
1650 | return i; | ||
1651 | } | ||
1652 | |||
1653 | static int iwl_mvm_find_free_scan_uid(struct iwl_mvm *mvm) | ||
1654 | { | ||
1655 | return iwl_mvm_find_scan_uid(mvm, 0); | ||
1656 | } | ||
1657 | |||
1658 | static bool iwl_mvm_find_scan_type(struct iwl_mvm *mvm, | ||
1659 | enum iwl_umac_scan_uid_type type) | ||
1660 | { | ||
1661 | int i; | ||
1662 | |||
1663 | for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) | ||
1664 | if (mvm->scan_uid[i] & type) | ||
1665 | return true; | ||
1666 | |||
1667 | return false; | ||
1668 | } | ||
1669 | |||
1670 | static u32 iwl_generate_scan_uid(struct iwl_mvm *mvm, | ||
1671 | enum iwl_umac_scan_uid_type type) | ||
1672 | { | ||
1673 | u32 uid; | ||
1674 | |||
1675 | /* make sure exactly one bit is on in scan type */ | ||
1676 | WARN_ON(hweight8(type) != 1); | ||
1677 | |||
1678 | /* | ||
1679 | * Make sure scan uids are unique. If one scan lasts long time while | ||
1680 | * others are completing frequently, the seq number will wrap up and | ||
1681 | * we may have more than one scan with the same uid. | ||
1682 | */ | ||
1683 | do { | ||
1684 | uid = type | (mvm->scan_seq_num << | ||
1685 | IWL_UMAC_SCAN_UID_SEQ_OFFSET); | ||
1686 | mvm->scan_seq_num++; | ||
1687 | } while (iwl_mvm_find_scan_uid(mvm, uid) < | ||
1688 | IWL_MVM_MAX_SIMULTANEOUS_SCANS); | ||
1689 | |||
1690 | IWL_DEBUG_SCAN(mvm, "Generated scan UID %u\n", uid); | ||
1691 | |||
1692 | return uid; | ||
1693 | } | ||
1694 | |||
1695 | static void | ||
1696 | iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm, | ||
1697 | struct iwl_scan_req_umac *cmd, | ||
1698 | struct iwl_mvm_scan_params *params) | ||
1699 | { | ||
1700 | memset(cmd, 0, ksize(cmd)); | ||
1701 | cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) - | ||
1702 | sizeof(struct iwl_mvm_umac_cmd_hdr)); | ||
1703 | cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; | ||
1704 | cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; | ||
1705 | if (params->passive_fragmented) | ||
1706 | cmd->fragmented_dwell = | ||
1707 | params->dwell[IEEE80211_BAND_2GHZ].passive; | ||
1708 | cmd->max_out_time = cpu_to_le32(params->max_out_time); | ||
1709 | cmd->suspend_time = cpu_to_le32(params->suspend_time); | ||
1710 | cmd->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH); | ||
1711 | } | ||
1712 | |||
1713 | static void | ||
1714 | iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, | ||
1715 | struct ieee80211_channel **channels, | ||
1716 | int n_channels, u32 ssid_bitmap, | ||
1717 | struct iwl_scan_req_umac *cmd) | ||
1718 | { | ||
1719 | struct iwl_scan_channel_cfg_umac *channel_cfg = (void *)&cmd->data; | ||
1720 | int i; | ||
1721 | |||
1722 | for (i = 0; i < n_channels; i++) { | ||
1723 | channel_cfg[i].flags = cpu_to_le32(ssid_bitmap); | ||
1724 | channel_cfg[i].channel_num = channels[i]->hw_value; | ||
1725 | channel_cfg[i].iter_count = 1; | ||
1726 | channel_cfg[i].iter_interval = 0; | ||
1727 | } | ||
1728 | } | ||
1729 | |||
1730 | static u32 iwl_mvm_scan_umac_common_flags(struct iwl_mvm *mvm, int n_ssids, | ||
1731 | struct cfg80211_ssid *ssids, | ||
1732 | int fragmented) | ||
1733 | { | ||
1734 | int flags = 0; | ||
1735 | |||
1736 | if (n_ssids == 0) | ||
1737 | flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE; | ||
1738 | |||
1739 | if (n_ssids == 1 && ssids[0].ssid_len != 0) | ||
1740 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT; | ||
1741 | |||
1742 | if (fragmented) | ||
1743 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED; | ||
1744 | |||
1745 | if (iwl_mvm_rrm_scan_needed(mvm)) | ||
1746 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED; | ||
1747 | |||
1748 | return flags; | ||
1749 | } | ||
1750 | |||
1751 | int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
1752 | struct ieee80211_scan_request *req) | ||
1753 | { | ||
1754 | struct iwl_host_cmd hcmd = { | ||
1755 | .id = SCAN_REQ_UMAC, | ||
1756 | .len = { iwl_mvm_scan_size(mvm), }, | ||
1757 | .data = { mvm->scan_cmd, }, | ||
1758 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
1759 | }; | ||
1760 | struct iwl_scan_req_umac *cmd = mvm->scan_cmd; | ||
1761 | struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data + | ||
1762 | sizeof(struct iwl_scan_channel_cfg_umac) * | ||
1763 | mvm->fw->ucode_capa.n_scan_channels; | ||
1764 | struct iwl_mvm_scan_params params = {}; | ||
1765 | u32 uid, flags; | ||
1766 | u32 ssid_bitmap = 0; | ||
1767 | int ret, i, uid_idx; | ||
1768 | |||
1769 | lockdep_assert_held(&mvm->mutex); | ||
1770 | |||
1771 | uid_idx = iwl_mvm_find_free_scan_uid(mvm); | ||
1772 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
1773 | return -EBUSY; | ||
1774 | |||
1775 | /* we should have failed registration if scan_cmd was NULL */ | ||
1776 | if (WARN_ON(mvm->scan_cmd == NULL)) | ||
1777 | return -ENOMEM; | ||
1778 | |||
1779 | if (WARN_ON(req->req.n_ssids > PROBE_OPTION_MAX || | ||
1780 | req->ies.common_ie_len + | ||
1781 | req->ies.len[NL80211_BAND_2GHZ] + | ||
1782 | req->ies.len[NL80211_BAND_5GHZ] + 24 + 2 > | ||
1783 | SCAN_OFFLOAD_PROBE_REQ_SIZE || req->req.n_channels > | ||
1784 | mvm->fw->ucode_capa.n_scan_channels)) | ||
1785 | return -ENOBUFS; | ||
1786 | |||
1787 | iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags, | ||
1788 | ¶ms); | ||
1789 | |||
1790 | iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, ¶ms); | ||
1791 | |||
1792 | uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_REG_SCAN); | ||
1793 | mvm->scan_uid[uid_idx] = uid; | ||
1794 | cmd->uid = cpu_to_le32(uid); | ||
1795 | |||
1796 | cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH); | ||
1797 | |||
1798 | flags = iwl_mvm_scan_umac_common_flags(mvm, req->req.n_ssids, | ||
1799 | req->req.ssids, | ||
1800 | params.passive_fragmented); | ||
1801 | |||
1802 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; | ||
1803 | |||
1804 | cmd->general_flags = cpu_to_le32(flags); | ||
1805 | cmd->n_channels = req->req.n_channels; | ||
1806 | |||
1807 | for (i = 0; i < req->req.n_ssids; i++) | ||
1808 | ssid_bitmap |= BIT(i); | ||
1809 | |||
1810 | iwl_mvm_umac_scan_cfg_channels(mvm, req->req.channels, | ||
1811 | req->req.n_channels, ssid_bitmap, cmd); | ||
1812 | |||
1813 | sec_part->schedule[0].iter_count = 1; | ||
1814 | sec_part->delay = 0; | ||
1815 | |||
1816 | iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, &sec_part->preq, | ||
1817 | req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ? | ||
1818 | req->req.mac_addr : NULL, | ||
1819 | req->req.mac_addr_mask); | ||
1820 | |||
1821 | iwl_mvm_scan_fill_ssids(sec_part->direct_scan, req->req.ssids, | ||
1822 | req->req.n_ssids, 0); | ||
1823 | |||
1824 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | ||
1825 | if (!ret) { | ||
1826 | IWL_DEBUG_SCAN(mvm, | ||
1827 | "Scan request was sent successfully\n"); | ||
1828 | } else { | ||
1829 | /* | ||
1830 | * If the scan failed, it usually means that the FW was unable | ||
1831 | * to allocate the time events. Warn on it, but maybe we | ||
1832 | * should try to send the command again with different params. | ||
1833 | */ | ||
1834 | IWL_ERR(mvm, "Scan failed! ret %d\n", ret); | ||
1835 | } | ||
1836 | return ret; | ||
1837 | } | ||
1838 | |||
1839 | int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
1840 | struct cfg80211_sched_scan_request *req, | ||
1841 | struct ieee80211_scan_ies *ies) | ||
1842 | { | ||
1843 | |||
1844 | struct iwl_host_cmd hcmd = { | ||
1845 | .id = SCAN_REQ_UMAC, | ||
1846 | .len = { iwl_mvm_scan_size(mvm), }, | ||
1847 | .data = { mvm->scan_cmd, }, | ||
1848 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
1849 | }; | ||
1850 | struct iwl_scan_req_umac *cmd = mvm->scan_cmd; | ||
1851 | struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data + | ||
1852 | sizeof(struct iwl_scan_channel_cfg_umac) * | ||
1853 | mvm->fw->ucode_capa.n_scan_channels; | ||
1854 | struct iwl_mvm_scan_params params = {}; | ||
1855 | u32 uid, flags; | ||
1856 | u32 ssid_bitmap = 0; | ||
1857 | int ret, uid_idx; | ||
1858 | |||
1859 | lockdep_assert_held(&mvm->mutex); | ||
1860 | |||
1861 | uid_idx = iwl_mvm_find_free_scan_uid(mvm); | ||
1862 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
1863 | return -EBUSY; | ||
1864 | |||
1865 | /* we should have failed registration if scan_cmd was NULL */ | ||
1866 | if (WARN_ON(mvm->scan_cmd == NULL)) | ||
1867 | return -ENOMEM; | ||
1868 | |||
1869 | if (WARN_ON(req->n_ssids > PROBE_OPTION_MAX || | ||
1870 | ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] + | ||
1871 | ies->len[NL80211_BAND_5GHZ] + 24 + 2 > | ||
1872 | SCAN_OFFLOAD_PROBE_REQ_SIZE || req->n_channels > | ||
1873 | mvm->fw->ucode_capa.n_scan_channels)) | ||
1874 | return -ENOBUFS; | ||
1875 | |||
1876 | iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags, | ||
1877 | ¶ms); | ||
1878 | |||
1879 | iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, ¶ms); | ||
1880 | |||
1881 | cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE); | ||
1882 | |||
1883 | uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN); | ||
1884 | mvm->scan_uid[uid_idx] = uid; | ||
1885 | cmd->uid = cpu_to_le32(uid); | ||
1886 | |||
1887 | cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_LOW); | ||
1888 | |||
1889 | flags = iwl_mvm_scan_umac_common_flags(mvm, req->n_ssids, req->ssids, | ||
1890 | params.passive_fragmented); | ||
1891 | |||
1892 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC; | ||
1893 | |||
1894 | if (iwl_mvm_scan_pass_all(mvm, req)) | ||
1895 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; | ||
1896 | else | ||
1897 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH; | ||
1898 | |||
1899 | cmd->general_flags = cpu_to_le32(flags); | ||
1900 | |||
1901 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT && | ||
1902 | mvm->last_ebs_successful) | ||
1903 | cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS | | ||
1904 | IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | | ||
1905 | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; | ||
1906 | |||
1907 | cmd->n_channels = req->n_channels; | ||
1908 | |||
1909 | iwl_scan_offload_build_ssid(req, sec_part->direct_scan, &ssid_bitmap, | ||
1910 | false); | ||
1911 | |||
1912 | /* This API uses bits 0-19 instead of 1-20. */ | ||
1913 | ssid_bitmap = ssid_bitmap >> 1; | ||
1914 | |||
1915 | iwl_mvm_umac_scan_cfg_channels(mvm, req->channels, req->n_channels, | ||
1916 | ssid_bitmap, cmd); | ||
1917 | |||
1918 | sec_part->schedule[0].interval = | ||
1919 | cpu_to_le16(req->interval / MSEC_PER_SEC); | ||
1920 | sec_part->schedule[0].iter_count = 0xff; | ||
1921 | |||
1922 | sec_part->delay = 0; | ||
1923 | |||
1924 | iwl_mvm_build_unified_scan_probe(mvm, vif, ies, &sec_part->preq, | ||
1925 | req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ? | ||
1926 | req->mac_addr : NULL, | ||
1927 | req->mac_addr_mask); | ||
1928 | |||
1929 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | ||
1930 | if (!ret) { | ||
1931 | IWL_DEBUG_SCAN(mvm, | ||
1932 | "Sched scan request was sent successfully\n"); | ||
1933 | } else { | ||
1934 | /* | ||
1935 | * If the scan failed, it usually means that the FW was unable | ||
1936 | * to allocate the time events. Warn on it, but maybe we | ||
1937 | * should try to send the command again with different params. | ||
1938 | */ | ||
1939 | IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret); | ||
1940 | } | ||
1941 | return ret; | ||
1942 | } | ||
1943 | |||
1944 | int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, | ||
1945 | struct iwl_rx_cmd_buffer *rxb, | ||
1946 | struct iwl_device_cmd *cmd) | ||
1947 | { | ||
1948 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1949 | struct iwl_umac_scan_complete *notif = (void *)pkt->data; | ||
1950 | u32 uid = __le32_to_cpu(notif->uid); | ||
1951 | bool sched = !!(uid & IWL_UMAC_SCAN_UID_SCHED_SCAN); | ||
1952 | int uid_idx = iwl_mvm_find_scan_uid(mvm, uid); | ||
1953 | |||
1954 | /* | ||
1955 | * Scan uid may be set to zero in case of scan abort request from above. | ||
1956 | */ | ||
1957 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
1958 | return 0; | ||
1959 | |||
1960 | IWL_DEBUG_SCAN(mvm, | ||
1961 | "Scan completed, uid %u type %s, status %s, EBS status %s\n", | ||
1962 | uid, sched ? "sched" : "regular", | ||
1963 | notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? | ||
1964 | "completed" : "aborted", | ||
1965 | notif->ebs_status == IWL_SCAN_EBS_SUCCESS ? | ||
1966 | "success" : "failed"); | ||
1967 | |||
1968 | mvm->last_ebs_successful = !notif->ebs_status; | ||
1969 | mvm->scan_uid[uid_idx] = 0; | ||
1970 | |||
1971 | if (!sched) { | ||
1972 | ieee80211_scan_completed(mvm->hw, | ||
1973 | notif->status == | ||
1974 | IWL_SCAN_OFFLOAD_ABORTED); | ||
1975 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
1976 | } else if (!iwl_mvm_find_scan_type(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN)) { | ||
1977 | ieee80211_sched_scan_stopped(mvm->hw); | ||
1978 | } else { | ||
1979 | IWL_DEBUG_SCAN(mvm, "Another sched scan is running\n"); | ||
1980 | } | ||
1981 | |||
1982 | return 0; | ||
1983 | } | ||
1984 | |||
1985 | static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait, | ||
1986 | struct iwl_rx_packet *pkt, void *data) | ||
1987 | { | ||
1988 | struct iwl_umac_scan_done *scan_done = data; | ||
1989 | struct iwl_umac_scan_complete *notif = (void *)pkt->data; | ||
1990 | u32 uid = __le32_to_cpu(notif->uid); | ||
1991 | int uid_idx = iwl_mvm_find_scan_uid(scan_done->mvm, uid); | ||
1992 | |||
1993 | if (WARN_ON(pkt->hdr.cmd != SCAN_COMPLETE_UMAC)) | ||
1994 | return false; | ||
1995 | |||
1996 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
1997 | return false; | ||
1998 | |||
1999 | /* | ||
2000 | * Clear scan uid of scans that was aborted from above and completed | ||
2001 | * in FW so the RX handler does nothing. | ||
2002 | */ | ||
2003 | scan_done->mvm->scan_uid[uid_idx] = 0; | ||
2004 | |||
2005 | return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type); | ||
2006 | } | ||
2007 | |||
2008 | static int iwl_umac_scan_abort_one(struct iwl_mvm *mvm, u32 uid) | ||
2009 | { | ||
2010 | struct iwl_umac_scan_abort cmd = { | ||
2011 | .hdr.size = cpu_to_le16(sizeof(struct iwl_umac_scan_abort) - | ||
2012 | sizeof(struct iwl_mvm_umac_cmd_hdr)), | ||
2013 | .uid = cpu_to_le32(uid), | ||
2014 | }; | ||
2015 | |||
2016 | lockdep_assert_held(&mvm->mutex); | ||
2017 | |||
2018 | IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid); | ||
2019 | |||
2020 | return iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd); | ||
2021 | } | ||
2022 | |||
2023 | static int iwl_umac_scan_stop(struct iwl_mvm *mvm, | ||
2024 | enum iwl_umac_scan_uid_type type, bool notify) | ||
2025 | { | ||
2026 | struct iwl_notification_wait wait_scan_done; | ||
2027 | static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC, }; | ||
2028 | struct iwl_umac_scan_done scan_done = { | ||
2029 | .mvm = mvm, | ||
2030 | .type = type, | ||
2031 | }; | ||
2032 | int i, ret = -EIO; | ||
2033 | |||
2034 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, | ||
2035 | scan_done_notif, | ||
2036 | ARRAY_SIZE(scan_done_notif), | ||
2037 | iwl_scan_umac_done_check, &scan_done); | ||
2038 | |||
2039 | IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type); | ||
2040 | |||
2041 | for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) { | ||
2042 | if (mvm->scan_uid[i] & type) { | ||
2043 | int err; | ||
2044 | |||
2045 | if (iwl_mvm_is_radio_killed(mvm) && | ||
2046 | (type & IWL_UMAC_SCAN_UID_REG_SCAN)) { | ||
2047 | ieee80211_scan_completed(mvm->hw, true); | ||
2048 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
2049 | break; | ||
2050 | } | ||
2051 | |||
2052 | err = iwl_umac_scan_abort_one(mvm, mvm->scan_uid[i]); | ||
2053 | if (!err) | ||
2054 | ret = 0; | ||
2055 | } | ||
2056 | } | ||
2057 | |||
2058 | if (ret) { | ||
2059 | IWL_DEBUG_SCAN(mvm, "Couldn't stop scan\n"); | ||
2060 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); | ||
2061 | return ret; | ||
2062 | } | ||
2063 | |||
2064 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); | ||
2065 | if (ret) | ||
2066 | return ret; | ||
2067 | |||
2068 | if (notify) { | ||
2069 | if (type & IWL_UMAC_SCAN_UID_SCHED_SCAN) | ||
2070 | ieee80211_sched_scan_stopped(mvm->hw); | ||
2071 | if (type & IWL_UMAC_SCAN_UID_REG_SCAN) { | ||
2072 | ieee80211_scan_completed(mvm->hw, true); | ||
2073 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
2074 | } | ||
2075 | } | ||
2076 | |||
2077 | return ret; | ||
2078 | } | ||
2079 | |||
2080 | int iwl_mvm_scan_size(struct iwl_mvm *mvm) | ||
2081 | { | ||
2082 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
2083 | return sizeof(struct iwl_scan_req_umac) + | ||
2084 | sizeof(struct iwl_scan_channel_cfg_umac) * | ||
2085 | mvm->fw->ucode_capa.n_scan_channels + | ||
2086 | sizeof(struct iwl_scan_req_umac_tail); | ||
2087 | |||
2088 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | ||
2089 | return sizeof(struct iwl_scan_req_unified_lmac) + | ||
2090 | sizeof(struct iwl_scan_channel_cfg_lmac) * | ||
2091 | mvm->fw->ucode_capa.n_scan_channels + | ||
2092 | sizeof(struct iwl_scan_probe_req); | ||
2093 | |||
2094 | return sizeof(struct iwl_scan_cmd) + | ||
2095 | mvm->fw->ucode_capa.max_probe_length + | ||
2096 | mvm->fw->ucode_capa.n_scan_channels * | ||
2097 | sizeof(struct iwl_scan_channel); | ||
2098 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index dd0dc5bf8583..d86fe432e51f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -204,6 +204,56 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
204 | return ret; | 204 | return ret; |
205 | } | 205 | } |
206 | 206 | ||
207 | static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm, | ||
208 | struct ieee80211_sta *sta) | ||
209 | { | ||
210 | unsigned long used_hw_queues; | ||
211 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
212 | u32 ac; | ||
213 | |||
214 | lockdep_assert_held(&mvm->mutex); | ||
215 | |||
216 | used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, NULL); | ||
217 | |||
218 | /* Find available queues, and allocate them to the ACs */ | ||
219 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
220 | u8 queue = find_first_zero_bit(&used_hw_queues, | ||
221 | mvm->first_agg_queue); | ||
222 | |||
223 | if (queue >= mvm->first_agg_queue) { | ||
224 | IWL_ERR(mvm, "Failed to allocate STA queue\n"); | ||
225 | return -EBUSY; | ||
226 | } | ||
227 | |||
228 | __set_bit(queue, &used_hw_queues); | ||
229 | mvmsta->hw_queue[ac] = queue; | ||
230 | } | ||
231 | |||
232 | /* Found a place for all queues - enable them */ | ||
233 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
234 | iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac], | ||
235 | iwl_mvm_ac_to_tx_fifo[ac]); | ||
236 | mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]); | ||
237 | } | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm, | ||
243 | struct ieee80211_sta *sta) | ||
244 | { | ||
245 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
246 | unsigned long sta_msk; | ||
247 | int i; | ||
248 | |||
249 | lockdep_assert_held(&mvm->mutex); | ||
250 | |||
251 | /* disable the TDLS STA-specific queues */ | ||
252 | sta_msk = mvmsta->tfd_queue_msk; | ||
253 | for_each_set_bit(i, &sta_msk, sizeof(sta_msk)) | ||
254 | iwl_mvm_disable_txq(mvm, i); | ||
255 | } | ||
256 | |||
207 | int iwl_mvm_add_sta(struct iwl_mvm *mvm, | 257 | int iwl_mvm_add_sta(struct iwl_mvm *mvm, |
208 | struct ieee80211_vif *vif, | 258 | struct ieee80211_vif *vif, |
209 | struct ieee80211_sta *sta) | 259 | struct ieee80211_sta *sta) |
@@ -237,9 +287,17 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
237 | atomic_set(&mvm->pending_frames[sta_id], 0); | 287 | atomic_set(&mvm->pending_frames[sta_id], 0); |
238 | mvm_sta->tid_disable_agg = 0; | 288 | mvm_sta->tid_disable_agg = 0; |
239 | mvm_sta->tfd_queue_msk = 0; | 289 | mvm_sta->tfd_queue_msk = 0; |
240 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | 290 | |
241 | if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) | 291 | /* allocate new queues for a TDLS station */ |
242 | mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); | 292 | if (sta->tdls) { |
293 | ret = iwl_mvm_tdls_sta_init(mvm, sta); | ||
294 | if (ret) | ||
295 | return ret; | ||
296 | } else { | ||
297 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | ||
298 | if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) | ||
299 | mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); | ||
300 | } | ||
243 | 301 | ||
244 | /* for HW restart - reset everything but the sequence number */ | 302 | /* for HW restart - reset everything but the sequence number */ |
245 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { | 303 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { |
@@ -251,7 +309,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
251 | 309 | ||
252 | ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); | 310 | ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); |
253 | if (ret) | 311 | if (ret) |
254 | return ret; | 312 | goto err; |
255 | 313 | ||
256 | if (vif->type == NL80211_IFTYPE_STATION) { | 314 | if (vif->type == NL80211_IFTYPE_STATION) { |
257 | if (!sta->tdls) { | 315 | if (!sta->tdls) { |
@@ -265,6 +323,10 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
265 | rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta); | 323 | rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta); |
266 | 324 | ||
267 | return 0; | 325 | return 0; |
326 | |||
327 | err: | ||
328 | iwl_mvm_tdls_sta_deinit(mvm, sta); | ||
329 | return ret; | ||
268 | } | 330 | } |
269 | 331 | ||
270 | int iwl_mvm_update_sta(struct iwl_mvm *mvm, | 332 | int iwl_mvm_update_sta(struct iwl_mvm *mvm, |
@@ -398,6 +460,17 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk) | |||
398 | } | 460 | } |
399 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); | 461 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); |
400 | clear_bit(sta_id, mvm->sta_drained); | 462 | clear_bit(sta_id, mvm->sta_drained); |
463 | |||
464 | if (mvm->tfd_drained[sta_id]) { | ||
465 | unsigned long i, msk = mvm->tfd_drained[sta_id]; | ||
466 | |||
467 | for_each_set_bit(i, &msk, sizeof(msk)) | ||
468 | iwl_mvm_disable_txq(mvm, i); | ||
469 | |||
470 | mvm->tfd_drained[sta_id] = 0; | ||
471 | IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n", | ||
472 | sta_id, msk); | ||
473 | } | ||
401 | } | 474 | } |
402 | 475 | ||
403 | mutex_unlock(&mvm->mutex); | 476 | mutex_unlock(&mvm->mutex); |
@@ -431,6 +504,15 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | |||
431 | } | 504 | } |
432 | 505 | ||
433 | /* | 506 | /* |
507 | * This shouldn't happen - the TDLS channel switch should be canceled | ||
508 | * before the STA is removed. | ||
509 | */ | ||
510 | if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == mvm_sta->sta_id)) { | ||
511 | mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT; | ||
512 | cancel_delayed_work(&mvm->tdls_cs.dwork); | ||
513 | } | ||
514 | |||
515 | /* | ||
434 | * Make sure that the tx response code sees the station as -EBUSY and | 516 | * Make sure that the tx response code sees the station as -EBUSY and |
435 | * calls the drain worker. | 517 | * calls the drain worker. |
436 | */ | 518 | */ |
@@ -443,9 +525,22 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | |||
443 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], | 525 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], |
444 | ERR_PTR(-EBUSY)); | 526 | ERR_PTR(-EBUSY)); |
445 | spin_unlock_bh(&mvm_sta->lock); | 527 | spin_unlock_bh(&mvm_sta->lock); |
528 | |||
529 | /* disable TDLS sta queues on drain complete */ | ||
530 | if (sta->tdls) { | ||
531 | mvm->tfd_drained[mvm_sta->sta_id] = | ||
532 | mvm_sta->tfd_queue_msk; | ||
533 | IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n", | ||
534 | mvm_sta->sta_id); | ||
535 | } | ||
536 | |||
446 | ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); | 537 | ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); |
447 | } else { | 538 | } else { |
448 | spin_unlock_bh(&mvm_sta->lock); | 539 | spin_unlock_bh(&mvm_sta->lock); |
540 | |||
541 | if (sta->tdls) | ||
542 | iwl_mvm_tdls_sta_deinit(mvm, sta); | ||
543 | |||
449 | ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); | 544 | ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); |
450 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); | 545 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); |
451 | } | 546 | } |
@@ -1071,15 +1166,16 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, | |||
1071 | 1166 | ||
1072 | static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | 1167 | static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, |
1073 | struct iwl_mvm_sta *mvm_sta, | 1168 | struct iwl_mvm_sta *mvm_sta, |
1074 | struct ieee80211_key_conf *keyconf, | 1169 | struct ieee80211_key_conf *keyconf, bool mcast, |
1075 | u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k, | 1170 | u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags) |
1076 | u32 cmd_flags) | ||
1077 | { | 1171 | { |
1078 | struct iwl_mvm_add_sta_key_cmd cmd = {}; | 1172 | struct iwl_mvm_add_sta_key_cmd cmd = {}; |
1079 | __le16 key_flags; | 1173 | __le16 key_flags; |
1080 | int ret, status; | 1174 | int ret; |
1175 | u32 status; | ||
1081 | u16 keyidx; | 1176 | u16 keyidx; |
1082 | int i; | 1177 | int i; |
1178 | u8 sta_id = mvm_sta->sta_id; | ||
1083 | 1179 | ||
1084 | keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & | 1180 | keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & |
1085 | STA_KEY_FLG_KEYID_MSK; | 1181 | STA_KEY_FLG_KEYID_MSK; |
@@ -1098,12 +1194,18 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | |||
1098 | key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); | 1194 | key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); |
1099 | memcpy(cmd.key, keyconf->key, keyconf->keylen); | 1195 | memcpy(cmd.key, keyconf->key, keyconf->keylen); |
1100 | break; | 1196 | break; |
1197 | case WLAN_CIPHER_SUITE_WEP104: | ||
1198 | key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_13BYTES); | ||
1199 | case WLAN_CIPHER_SUITE_WEP40: | ||
1200 | key_flags |= cpu_to_le16(STA_KEY_FLG_WEP); | ||
1201 | memcpy(cmd.key + 3, keyconf->key, keyconf->keylen); | ||
1202 | break; | ||
1101 | default: | 1203 | default: |
1102 | key_flags |= cpu_to_le16(STA_KEY_FLG_EXT); | 1204 | key_flags |= cpu_to_le16(STA_KEY_FLG_EXT); |
1103 | memcpy(cmd.key, keyconf->key, keyconf->keylen); | 1205 | memcpy(cmd.key, keyconf->key, keyconf->keylen); |
1104 | } | 1206 | } |
1105 | 1207 | ||
1106 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | 1208 | if (mcast) |
1107 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | 1209 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); |
1108 | 1210 | ||
1109 | cmd.key_offset = keyconf->hw_key_idx; | 1211 | cmd.key_offset = keyconf->hw_key_idx; |
@@ -1195,17 +1297,88 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, | |||
1195 | return NULL; | 1297 | return NULL; |
1196 | } | 1298 | } |
1197 | 1299 | ||
1300 | static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | ||
1301 | struct ieee80211_vif *vif, | ||
1302 | struct ieee80211_sta *sta, | ||
1303 | struct ieee80211_key_conf *keyconf, | ||
1304 | bool mcast) | ||
1305 | { | ||
1306 | struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); | ||
1307 | int ret; | ||
1308 | const u8 *addr; | ||
1309 | struct ieee80211_key_seq seq; | ||
1310 | u16 p1k[5]; | ||
1311 | |||
1312 | switch (keyconf->cipher) { | ||
1313 | case WLAN_CIPHER_SUITE_TKIP: | ||
1314 | addr = iwl_mvm_get_mac_addr(mvm, vif, sta); | ||
1315 | /* get phase 1 key from mac80211 */ | ||
1316 | ieee80211_get_key_rx_seq(keyconf, 0, &seq); | ||
1317 | ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); | ||
1318 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, | ||
1319 | seq.tkip.iv32, p1k, 0); | ||
1320 | break; | ||
1321 | case WLAN_CIPHER_SUITE_CCMP: | ||
1322 | case WLAN_CIPHER_SUITE_WEP40: | ||
1323 | case WLAN_CIPHER_SUITE_WEP104: | ||
1324 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, | ||
1325 | 0, NULL, 0); | ||
1326 | break; | ||
1327 | default: | ||
1328 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, | ||
1329 | 0, NULL, 0); | ||
1330 | } | ||
1331 | |||
1332 | return ret; | ||
1333 | } | ||
1334 | |||
1335 | static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, | ||
1336 | struct ieee80211_key_conf *keyconf, | ||
1337 | bool mcast) | ||
1338 | { | ||
1339 | struct iwl_mvm_add_sta_key_cmd cmd = {}; | ||
1340 | __le16 key_flags; | ||
1341 | int ret; | ||
1342 | u32 status; | ||
1343 | |||
1344 | key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & | ||
1345 | STA_KEY_FLG_KEYID_MSK); | ||
1346 | key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); | ||
1347 | key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); | ||
1348 | |||
1349 | if (mcast) | ||
1350 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | ||
1351 | |||
1352 | cmd.key_flags = key_flags; | ||
1353 | cmd.key_offset = keyconf->hw_key_idx; | ||
1354 | cmd.sta_id = sta_id; | ||
1355 | |||
1356 | status = ADD_STA_SUCCESS; | ||
1357 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd), | ||
1358 | &cmd, &status); | ||
1359 | |||
1360 | switch (status) { | ||
1361 | case ADD_STA_SUCCESS: | ||
1362 | IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n"); | ||
1363 | break; | ||
1364 | default: | ||
1365 | ret = -EIO; | ||
1366 | IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n"); | ||
1367 | break; | ||
1368 | } | ||
1369 | |||
1370 | return ret; | ||
1371 | } | ||
1372 | |||
1198 | int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | 1373 | int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, |
1199 | struct ieee80211_vif *vif, | 1374 | struct ieee80211_vif *vif, |
1200 | struct ieee80211_sta *sta, | 1375 | struct ieee80211_sta *sta, |
1201 | struct ieee80211_key_conf *keyconf, | 1376 | struct ieee80211_key_conf *keyconf, |
1202 | bool have_key_offset) | 1377 | bool have_key_offset) |
1203 | { | 1378 | { |
1204 | struct iwl_mvm_sta *mvm_sta; | 1379 | bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); |
1380 | u8 sta_id; | ||
1205 | int ret; | 1381 | int ret; |
1206 | u8 *addr, sta_id; | ||
1207 | struct ieee80211_key_seq seq; | ||
1208 | u16 p1k[5]; | ||
1209 | 1382 | ||
1210 | lockdep_assert_held(&mvm->mutex); | 1383 | lockdep_assert_held(&mvm->mutex); |
1211 | 1384 | ||
@@ -1234,8 +1407,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
1234 | } | 1407 | } |
1235 | } | 1408 | } |
1236 | 1409 | ||
1237 | mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv; | 1410 | if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) |
1238 | if (WARN_ON_ONCE(mvm_sta->vif != vif)) | ||
1239 | return -EINVAL; | 1411 | return -EINVAL; |
1240 | 1412 | ||
1241 | if (!have_key_offset) { | 1413 | if (!have_key_offset) { |
@@ -1249,26 +1421,26 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
1249 | return -ENOSPC; | 1421 | return -ENOSPC; |
1250 | } | 1422 | } |
1251 | 1423 | ||
1252 | switch (keyconf->cipher) { | 1424 | ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, mcast); |
1253 | case WLAN_CIPHER_SUITE_TKIP: | 1425 | if (ret) { |
1254 | addr = iwl_mvm_get_mac_addr(mvm, vif, sta); | 1426 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); |
1255 | /* get phase 1 key from mac80211 */ | 1427 | goto end; |
1256 | ieee80211_get_key_rx_seq(keyconf, 0, &seq); | ||
1257 | ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); | ||
1258 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | ||
1259 | seq.tkip.iv32, p1k, 0); | ||
1260 | break; | ||
1261 | case WLAN_CIPHER_SUITE_CCMP: | ||
1262 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | ||
1263 | 0, NULL, 0); | ||
1264 | break; | ||
1265 | default: | ||
1266 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, | ||
1267 | sta_id, 0, NULL, 0); | ||
1268 | } | 1428 | } |
1269 | 1429 | ||
1270 | if (ret) | 1430 | /* |
1271 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); | 1431 | * For WEP, the same key is used for multicast and unicast. Upload it |
1432 | * again, using the same key offset, and now pointing the other one | ||
1433 | * to the same key slot (offset). | ||
1434 | * If this fails, remove the original as well. | ||
1435 | */ | ||
1436 | if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || | ||
1437 | keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { | ||
1438 | ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, !mcast); | ||
1439 | if (ret) { | ||
1440 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); | ||
1441 | __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); | ||
1442 | } | ||
1443 | } | ||
1272 | 1444 | ||
1273 | end: | 1445 | end: |
1274 | IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", | 1446 | IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", |
@@ -1282,11 +1454,9 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
1282 | struct ieee80211_sta *sta, | 1454 | struct ieee80211_sta *sta, |
1283 | struct ieee80211_key_conf *keyconf) | 1455 | struct ieee80211_key_conf *keyconf) |
1284 | { | 1456 | { |
1285 | struct iwl_mvm_sta *mvm_sta; | 1457 | bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); |
1286 | struct iwl_mvm_add_sta_key_cmd cmd = {}; | ||
1287 | __le16 key_flags; | ||
1288 | int ret, status; | ||
1289 | u8 sta_id; | 1458 | u8 sta_id; |
1459 | int ret; | ||
1290 | 1460 | ||
1291 | lockdep_assert_held(&mvm->mutex); | 1461 | lockdep_assert_held(&mvm->mutex); |
1292 | 1462 | ||
@@ -1299,8 +1469,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
1299 | if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) | 1469 | if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
1300 | return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true); | 1470 | return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true); |
1301 | 1471 | ||
1302 | ret = __test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); | 1472 | if (!__test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table)) { |
1303 | if (!ret) { | ||
1304 | IWL_ERR(mvm, "offset %d not used in fw key table.\n", | 1473 | IWL_ERR(mvm, "offset %d not used in fw key table.\n", |
1305 | keyconf->hw_key_idx); | 1474 | keyconf->hw_key_idx); |
1306 | return -ENOENT; | 1475 | return -ENOENT; |
@@ -1326,35 +1495,17 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
1326 | } | 1495 | } |
1327 | } | 1496 | } |
1328 | 1497 | ||
1329 | mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv; | 1498 | if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) |
1330 | if (WARN_ON_ONCE(mvm_sta->vif != vif)) | ||
1331 | return -EINVAL; | 1499 | return -EINVAL; |
1332 | 1500 | ||
1333 | key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & | 1501 | ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); |
1334 | STA_KEY_FLG_KEYID_MSK); | 1502 | if (ret) |
1335 | key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); | 1503 | return ret; |
1336 | key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); | ||
1337 | |||
1338 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | ||
1339 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | ||
1340 | |||
1341 | cmd.key_flags = key_flags; | ||
1342 | cmd.key_offset = keyconf->hw_key_idx; | ||
1343 | cmd.sta_id = sta_id; | ||
1344 | |||
1345 | status = ADD_STA_SUCCESS; | ||
1346 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd), | ||
1347 | &cmd, &status); | ||
1348 | 1504 | ||
1349 | switch (status) { | 1505 | /* delete WEP key twice to get rid of (now useless) offset */ |
1350 | case ADD_STA_SUCCESS: | 1506 | if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || |
1351 | IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n"); | 1507 | keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) |
1352 | break; | 1508 | ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, !mcast); |
1353 | default: | ||
1354 | ret = -EIO; | ||
1355 | IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n"); | ||
1356 | break; | ||
1357 | } | ||
1358 | 1509 | ||
1359 | return ret; | 1510 | return ret; |
1360 | } | 1511 | } |
@@ -1367,6 +1518,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
1367 | { | 1518 | { |
1368 | struct iwl_mvm_sta *mvm_sta; | 1519 | struct iwl_mvm_sta *mvm_sta; |
1369 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); | 1520 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); |
1521 | bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); | ||
1370 | 1522 | ||
1371 | if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) | 1523 | if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) |
1372 | return; | 1524 | return; |
@@ -1381,8 +1533,8 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
1381 | } | 1533 | } |
1382 | } | 1534 | } |
1383 | 1535 | ||
1384 | mvm_sta = (void *)sta->drv_priv; | 1536 | mvm_sta = iwl_mvm_sta_from_mac80211(sta); |
1385 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | 1537 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, |
1386 | iv32, phase1key, CMD_ASYNC); | 1538 | iv32, phase1key, CMD_ASYNC); |
1387 | rcu_read_unlock(); | 1539 | rcu_read_unlock(); |
1388 | } | 1540 | } |
@@ -1580,3 +1732,18 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, | |||
1580 | iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, disable); | 1732 | iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, disable); |
1581 | } | 1733 | } |
1582 | } | 1734 | } |
1735 | |||
1736 | void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
1737 | { | ||
1738 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1739 | struct iwl_mvm_sta *mvmsta; | ||
1740 | |||
1741 | rcu_read_lock(); | ||
1742 | |||
1743 | mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, mvmvif->ap_sta_id); | ||
1744 | |||
1745 | if (!WARN_ON(!mvmsta)) | ||
1746 | iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true); | ||
1747 | |||
1748 | rcu_read_unlock(); | ||
1749 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index d9c0d7b0e9d4..d8f48975ad08 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -264,6 +264,7 @@ enum iwl_mvm_agg_state { | |||
264 | * the first packet to be sent in legacy HW queue in Tx AGG stop flow. | 264 | * the first packet to be sent in legacy HW queue in Tx AGG stop flow. |
265 | * Basically when next_reclaimed reaches ssn, we can tell mac80211 that | 265 | * Basically when next_reclaimed reaches ssn, we can tell mac80211 that |
266 | * we are ready to finish the Tx AGG stop / start flow. | 266 | * we are ready to finish the Tx AGG stop / start flow. |
267 | * @tx_time: medium time consumed by this A-MPDU | ||
267 | */ | 268 | */ |
268 | struct iwl_mvm_tid_data { | 269 | struct iwl_mvm_tid_data { |
269 | u16 seq_number; | 270 | u16 seq_number; |
@@ -274,6 +275,7 @@ struct iwl_mvm_tid_data { | |||
274 | enum iwl_mvm_agg_state state; | 275 | enum iwl_mvm_agg_state state; |
275 | u16 txq_id; | 276 | u16 txq_id; |
276 | u16 ssn; | 277 | u16 ssn; |
278 | u16 tx_time; | ||
277 | }; | 279 | }; |
278 | 280 | ||
279 | static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) | 281 | static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) |
@@ -286,6 +288,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) | |||
286 | * struct iwl_mvm_sta - representation of a station in the driver | 288 | * struct iwl_mvm_sta - representation of a station in the driver |
287 | * @sta_id: the index of the station in the fw (will be replaced by id_n_color) | 289 | * @sta_id: the index of the station in the fw (will be replaced by id_n_color) |
288 | * @tfd_queue_msk: the tfd queues used by the station | 290 | * @tfd_queue_msk: the tfd queues used by the station |
291 | * @hw_queue: per-AC mapping of the TFD queues used by station | ||
289 | * @mac_id_n_color: the MAC context this station is linked to | 292 | * @mac_id_n_color: the MAC context this station is linked to |
290 | * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for | 293 | * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for |
291 | * tid. | 294 | * tid. |
@@ -309,6 +312,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) | |||
309 | struct iwl_mvm_sta { | 312 | struct iwl_mvm_sta { |
310 | u32 sta_id; | 313 | u32 sta_id; |
311 | u32 tfd_queue_msk; | 314 | u32 tfd_queue_msk; |
315 | u8 hw_queue[IEEE80211_NUM_ACS]; | ||
312 | u32 mac_id_n_color; | 316 | u32 mac_id_n_color; |
313 | u16 tid_disable_agg; | 317 | u16 tid_disable_agg; |
314 | u8 max_agg_bufsize; | 318 | u8 max_agg_bufsize; |
@@ -418,5 +422,6 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, | |||
418 | void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, | 422 | void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, |
419 | struct iwl_mvm_vif *mvmvif, | 423 | struct iwl_mvm_vif *mvmvif, |
420 | bool disable); | 424 | bool disable); |
425 | void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
421 | 426 | ||
422 | #endif /* __sta_h__ */ | 427 | #endif /* __sta_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index 66c82df2d0a1..c0e00bae5bd0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c | |||
@@ -61,9 +61,13 @@ | |||
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | 63 | ||
64 | #include <linux/etherdevice.h> | ||
64 | #include "mvm.h" | 65 | #include "mvm.h" |
65 | #include "time-event.h" | 66 | #include "time-event.h" |
66 | 67 | ||
68 | #define TU_TO_US(x) (x * 1024) | ||
69 | #define TU_TO_MS(x) (TU_TO_US(x) / 1000) | ||
70 | |||
67 | void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) | 71 | void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) |
68 | { | 72 | { |
69 | struct ieee80211_sta *sta; | 73 | struct ieee80211_sta *sta; |
@@ -113,17 +117,85 @@ int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
113 | return count; | 117 | return count; |
114 | } | 118 | } |
115 | 119 | ||
120 | static void iwl_mvm_tdls_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
121 | { | ||
122 | struct iwl_rx_packet *pkt; | ||
123 | struct iwl_tdls_config_res *resp; | ||
124 | struct iwl_tdls_config_cmd tdls_cfg_cmd = {}; | ||
125 | struct iwl_host_cmd cmd = { | ||
126 | .id = TDLS_CONFIG_CMD, | ||
127 | .flags = CMD_WANT_SKB, | ||
128 | .data = { &tdls_cfg_cmd, }, | ||
129 | .len = { sizeof(struct iwl_tdls_config_cmd), }, | ||
130 | }; | ||
131 | struct ieee80211_sta *sta; | ||
132 | int ret, i, cnt; | ||
133 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
134 | |||
135 | lockdep_assert_held(&mvm->mutex); | ||
136 | |||
137 | tdls_cfg_cmd.id_and_color = | ||
138 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | ||
139 | tdls_cfg_cmd.tx_to_ap_tid = IWL_MVM_TDLS_FW_TID; | ||
140 | tdls_cfg_cmd.tx_to_ap_ssn = cpu_to_le16(0); /* not used for now */ | ||
141 | |||
142 | /* for now the Tx cmd is empty and unused */ | ||
143 | |||
144 | /* populate TDLS peer data */ | ||
145 | cnt = 0; | ||
146 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
147 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
148 | lockdep_is_held(&mvm->mutex)); | ||
149 | if (IS_ERR_OR_NULL(sta) || !sta->tdls) | ||
150 | continue; | ||
151 | |||
152 | tdls_cfg_cmd.sta_info[cnt].sta_id = i; | ||
153 | tdls_cfg_cmd.sta_info[cnt].tx_to_peer_tid = | ||
154 | IWL_MVM_TDLS_FW_TID; | ||
155 | tdls_cfg_cmd.sta_info[cnt].tx_to_peer_ssn = cpu_to_le16(0); | ||
156 | tdls_cfg_cmd.sta_info[cnt].is_initiator = | ||
157 | cpu_to_le32(sta->tdls_initiator ? 1 : 0); | ||
158 | |||
159 | cnt++; | ||
160 | } | ||
161 | |||
162 | tdls_cfg_cmd.tdls_peer_count = cnt; | ||
163 | IWL_DEBUG_TDLS(mvm, "send TDLS config to FW for %d peers\n", cnt); | ||
164 | |||
165 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
166 | if (WARN_ON_ONCE(ret)) | ||
167 | return; | ||
168 | |||
169 | pkt = cmd.resp_pkt; | ||
170 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
171 | IWL_ERR(mvm, "Bad return from TDLS_CONFIG_COMMAND (0x%08X)\n", | ||
172 | pkt->hdr.flags); | ||
173 | goto exit; | ||
174 | } | ||
175 | |||
176 | if (WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp))) | ||
177 | goto exit; | ||
178 | |||
179 | /* we don't really care about the response at this point */ | ||
180 | |||
181 | exit: | ||
182 | iwl_free_resp(&cmd); | ||
183 | } | ||
184 | |||
116 | void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 185 | void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
117 | bool sta_added) | 186 | bool sta_added) |
118 | { | 187 | { |
119 | int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); | 188 | int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); |
120 | 189 | ||
121 | /* | 190 | /* when the first peer joins, send a power update first */ |
122 | * Disable ps when the first TDLS sta is added and re-enable it | 191 | if (tdls_sta_cnt == 1 && sta_added) |
123 | * when the last TDLS sta is removed | 192 | iwl_mvm_power_update_mac(mvm); |
124 | */ | 193 | |
125 | if ((tdls_sta_cnt == 1 && sta_added) || | 194 | /* configure the FW with TDLS peer info */ |
126 | (tdls_sta_cnt == 0 && !sta_added)) | 195 | iwl_mvm_tdls_config(mvm, vif); |
196 | |||
197 | /* when the last peer leaves, send a power update last */ | ||
198 | if (tdls_sta_cnt == 0 && !sta_added) | ||
127 | iwl_mvm_power_update_mac(mvm); | 199 | iwl_mvm_power_update_mac(mvm); |
128 | } | 200 | } |
129 | 201 | ||
@@ -147,3 +219,488 @@ void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, | |||
147 | 219 | ||
148 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); | 220 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); |
149 | } | 221 | } |
222 | |||
223 | static const char * | ||
224 | iwl_mvm_tdls_cs_state_str(enum iwl_mvm_tdls_cs_state state) | ||
225 | { | ||
226 | switch (state) { | ||
227 | case IWL_MVM_TDLS_SW_IDLE: | ||
228 | return "IDLE"; | ||
229 | case IWL_MVM_TDLS_SW_REQ_SENT: | ||
230 | return "REQ SENT"; | ||
231 | case IWL_MVM_TDLS_SW_REQ_RCVD: | ||
232 | return "REQ RECEIVED"; | ||
233 | case IWL_MVM_TDLS_SW_ACTIVE: | ||
234 | return "ACTIVE"; | ||
235 | } | ||
236 | |||
237 | return NULL; | ||
238 | } | ||
239 | |||
240 | static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, | ||
241 | enum iwl_mvm_tdls_cs_state state) | ||
242 | { | ||
243 | if (mvm->tdls_cs.state == state) | ||
244 | return; | ||
245 | |||
246 | IWL_DEBUG_TDLS(mvm, "TDLS channel switch state: %s -> %s\n", | ||
247 | iwl_mvm_tdls_cs_state_str(mvm->tdls_cs.state), | ||
248 | iwl_mvm_tdls_cs_state_str(state)); | ||
249 | mvm->tdls_cs.state = state; | ||
250 | |||
251 | if (state == IWL_MVM_TDLS_SW_IDLE) | ||
252 | mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT; | ||
253 | } | ||
254 | |||
255 | int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
256 | struct iwl_device_cmd *cmd) | ||
257 | { | ||
258 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
259 | struct iwl_tdls_channel_switch_notif *notif = (void *)pkt->data; | ||
260 | struct ieee80211_sta *sta; | ||
261 | unsigned int delay; | ||
262 | struct iwl_mvm_sta *mvmsta; | ||
263 | struct ieee80211_vif *vif; | ||
264 | u32 sta_id = le32_to_cpu(notif->sta_id); | ||
265 | |||
266 | lockdep_assert_held(&mvm->mutex); | ||
267 | |||
268 | /* can fail sometimes */ | ||
269 | if (!le32_to_cpu(notif->status)) { | ||
270 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); | ||
271 | goto out; | ||
272 | } | ||
273 | |||
274 | if (WARN_ON(sta_id >= IWL_MVM_STATION_COUNT)) | ||
275 | goto out; | ||
276 | |||
277 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
278 | lockdep_is_held(&mvm->mutex)); | ||
279 | /* the station may not be here, but if it is, it must be a TDLS peer */ | ||
280 | if (IS_ERR_OR_NULL(sta) || WARN_ON(!sta->tdls)) | ||
281 | goto out; | ||
282 | |||
283 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
284 | vif = mvmsta->vif; | ||
285 | |||
286 | /* | ||
287 | * Update state and possibly switch again after this is over (DTIM). | ||
288 | * Also convert TU to msec. | ||
289 | */ | ||
290 | delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int); | ||
291 | mod_delayed_work(system_wq, &mvm->tdls_cs.dwork, | ||
292 | msecs_to_jiffies(delay)); | ||
293 | |||
294 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_ACTIVE); | ||
295 | |||
296 | out: | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int | ||
301 | iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, | ||
302 | enum iwl_tdls_channel_switch_type type, | ||
303 | const u8 *peer, bool peer_initiator) | ||
304 | { | ||
305 | bool same_peer = false; | ||
306 | int ret = 0; | ||
307 | |||
308 | /* get the existing peer if it's there */ | ||
309 | if (mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE && | ||
310 | mvm->tdls_cs.cur_sta_id != IWL_MVM_STATION_COUNT) { | ||
311 | struct ieee80211_sta *sta = rcu_dereference_protected( | ||
312 | mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id], | ||
313 | lockdep_is_held(&mvm->mutex)); | ||
314 | if (!IS_ERR_OR_NULL(sta)) | ||
315 | same_peer = ether_addr_equal(peer, sta->addr); | ||
316 | } | ||
317 | |||
318 | switch (mvm->tdls_cs.state) { | ||
319 | case IWL_MVM_TDLS_SW_IDLE: | ||
320 | /* | ||
321 | * might be spurious packet from the peer after the switch is | ||
322 | * already done | ||
323 | */ | ||
324 | if (type == TDLS_MOVE_CH) | ||
325 | ret = -EINVAL; | ||
326 | break; | ||
327 | case IWL_MVM_TDLS_SW_REQ_SENT: | ||
328 | /* | ||
329 | * We received a ch-switch request while an outgoing one is | ||
330 | * pending. Allow it to proceed if the other peer is the same | ||
331 | * one we sent to, and we are not the link initiator. | ||
332 | */ | ||
333 | if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH) { | ||
334 | if (!same_peer) | ||
335 | ret = -EBUSY; | ||
336 | else if (!peer_initiator) /* we are the initiator */ | ||
337 | ret = -EBUSY; | ||
338 | } | ||
339 | break; | ||
340 | case IWL_MVM_TDLS_SW_REQ_RCVD: | ||
341 | /* as above, allow the link initiator to proceed */ | ||
342 | if (type == TDLS_SEND_CHAN_SW_REQ) { | ||
343 | if (!same_peer) | ||
344 | ret = -EBUSY; | ||
345 | else if (peer_initiator) /* they are the initiator */ | ||
346 | ret = -EBUSY; | ||
347 | } else if (type == TDLS_MOVE_CH) { | ||
348 | ret = -EINVAL; | ||
349 | } | ||
350 | break; | ||
351 | case IWL_MVM_TDLS_SW_ACTIVE: | ||
352 | /* we don't allow initiations during active channel switch */ | ||
353 | if (type == TDLS_SEND_CHAN_SW_REQ) | ||
354 | ret = -EINVAL; | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | if (ret) | ||
359 | IWL_DEBUG_TDLS(mvm, | ||
360 | "Invalid TDLS action %d state %d peer %pM same_peer %d initiator %d\n", | ||
361 | type, mvm->tdls_cs.state, peer, same_peer, | ||
362 | peer_initiator); | ||
363 | |||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | static int | ||
368 | iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, | ||
369 | struct ieee80211_vif *vif, | ||
370 | enum iwl_tdls_channel_switch_type type, | ||
371 | const u8 *peer, bool peer_initiator, | ||
372 | u8 oper_class, | ||
373 | struct cfg80211_chan_def *chandef, | ||
374 | u32 timestamp, u16 switch_time, | ||
375 | u16 switch_timeout, struct sk_buff *skb, | ||
376 | u32 ch_sw_tm_ie) | ||
377 | { | ||
378 | struct ieee80211_sta *sta; | ||
379 | struct iwl_mvm_sta *mvmsta; | ||
380 | struct ieee80211_tx_info *info; | ||
381 | struct ieee80211_hdr *hdr; | ||
382 | struct iwl_tdls_channel_switch_cmd cmd = {0}; | ||
383 | int ret; | ||
384 | |||
385 | lockdep_assert_held(&mvm->mutex); | ||
386 | |||
387 | ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator); | ||
388 | if (ret) | ||
389 | return ret; | ||
390 | |||
391 | if (!skb || WARN_ON(skb->len > IWL_TDLS_CH_SW_FRAME_MAX_SIZE)) { | ||
392 | ret = -EINVAL; | ||
393 | goto out; | ||
394 | } | ||
395 | |||
396 | cmd.switch_type = type; | ||
397 | cmd.timing.frame_timestamp = cpu_to_le32(timestamp); | ||
398 | cmd.timing.switch_time = cpu_to_le32(switch_time); | ||
399 | cmd.timing.switch_timeout = cpu_to_le32(switch_timeout); | ||
400 | |||
401 | rcu_read_lock(); | ||
402 | sta = ieee80211_find_sta(vif, peer); | ||
403 | if (!sta) { | ||
404 | rcu_read_unlock(); | ||
405 | ret = -ENOENT; | ||
406 | goto out; | ||
407 | } | ||
408 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
409 | cmd.peer_sta_id = cpu_to_le32(mvmsta->sta_id); | ||
410 | |||
411 | if (!chandef) { | ||
412 | if (mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT && | ||
413 | mvm->tdls_cs.peer.chandef.chan) { | ||
414 | /* actually moving to the channel */ | ||
415 | chandef = &mvm->tdls_cs.peer.chandef; | ||
416 | } else if (mvm->tdls_cs.state == IWL_MVM_TDLS_SW_ACTIVE && | ||
417 | type == TDLS_MOVE_CH) { | ||
418 | /* we need to return to base channel */ | ||
419 | struct ieee80211_chanctx_conf *chanctx = | ||
420 | rcu_dereference(vif->chanctx_conf); | ||
421 | |||
422 | if (WARN_ON_ONCE(!chanctx)) { | ||
423 | rcu_read_unlock(); | ||
424 | goto out; | ||
425 | } | ||
426 | |||
427 | chandef = &chanctx->def; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | if (chandef) { | ||
432 | cmd.ci.band = (chandef->chan->band == IEEE80211_BAND_2GHZ ? | ||
433 | PHY_BAND_24 : PHY_BAND_5); | ||
434 | cmd.ci.channel = chandef->chan->hw_value; | ||
435 | cmd.ci.width = iwl_mvm_get_channel_width(chandef); | ||
436 | cmd.ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef); | ||
437 | } | ||
438 | |||
439 | /* keep quota calculation simple for now - 50% of DTIM for TDLS */ | ||
440 | cmd.timing.max_offchan_duration = | ||
441 | cpu_to_le32(TU_TO_US(vif->bss_conf.dtim_period * | ||
442 | vif->bss_conf.beacon_int) / 2); | ||
443 | |||
444 | /* Switch time is the first element in the switch-timing IE. */ | ||
445 | cmd.frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2); | ||
446 | |||
447 | info = IEEE80211_SKB_CB(skb); | ||
448 | if (info->control.hw_key) | ||
449 | iwl_mvm_set_tx_cmd_crypto(mvm, info, &cmd.frame.tx_cmd, skb); | ||
450 | |||
451 | iwl_mvm_set_tx_cmd(mvm, skb, &cmd.frame.tx_cmd, info, | ||
452 | mvmsta->sta_id); | ||
453 | |||
454 | hdr = (void *)skb->data; | ||
455 | iwl_mvm_set_tx_cmd_rate(mvm, &cmd.frame.tx_cmd, info, sta, | ||
456 | hdr->frame_control); | ||
457 | rcu_read_unlock(); | ||
458 | |||
459 | memcpy(cmd.frame.data, skb->data, skb->len); | ||
460 | |||
461 | ret = iwl_mvm_send_cmd_pdu(mvm, TDLS_CHANNEL_SWITCH_CMD, 0, | ||
462 | sizeof(cmd), &cmd); | ||
463 | if (ret) { | ||
464 | IWL_ERR(mvm, "Failed to send TDLS_CHANNEL_SWITCH cmd: %d\n", | ||
465 | ret); | ||
466 | goto out; | ||
467 | } | ||
468 | |||
469 | /* channel switch has started, update state */ | ||
470 | if (type != TDLS_MOVE_CH) { | ||
471 | mvm->tdls_cs.cur_sta_id = mvmsta->sta_id; | ||
472 | iwl_mvm_tdls_update_cs_state(mvm, | ||
473 | type == TDLS_SEND_CHAN_SW_REQ ? | ||
474 | IWL_MVM_TDLS_SW_REQ_SENT : | ||
475 | IWL_MVM_TDLS_SW_REQ_RCVD); | ||
476 | } | ||
477 | |||
478 | out: | ||
479 | |||
480 | /* channel switch failed - we are idle */ | ||
481 | if (ret) | ||
482 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); | ||
483 | |||
484 | return ret; | ||
485 | } | ||
486 | |||
487 | void iwl_mvm_tdls_ch_switch_work(struct work_struct *work) | ||
488 | { | ||
489 | struct iwl_mvm *mvm; | ||
490 | struct ieee80211_sta *sta; | ||
491 | struct iwl_mvm_sta *mvmsta; | ||
492 | struct ieee80211_vif *vif; | ||
493 | unsigned int delay; | ||
494 | int ret; | ||
495 | |||
496 | mvm = container_of(work, struct iwl_mvm, tdls_cs.dwork.work); | ||
497 | mutex_lock(&mvm->mutex); | ||
498 | |||
499 | /* called after an active channel switch has finished or timed-out */ | ||
500 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); | ||
501 | |||
502 | /* station might be gone, in that case do nothing */ | ||
503 | if (mvm->tdls_cs.peer.sta_id == IWL_MVM_STATION_COUNT) | ||
504 | goto out; | ||
505 | |||
506 | sta = rcu_dereference_protected( | ||
507 | mvm->fw_id_to_mac_id[mvm->tdls_cs.peer.sta_id], | ||
508 | lockdep_is_held(&mvm->mutex)); | ||
509 | /* the station may not be here, but if it is, it must be a TDLS peer */ | ||
510 | if (!sta || IS_ERR(sta) || WARN_ON(!sta->tdls)) | ||
511 | goto out; | ||
512 | |||
513 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
514 | vif = mvmsta->vif; | ||
515 | ret = iwl_mvm_tdls_config_channel_switch(mvm, vif, | ||
516 | TDLS_SEND_CHAN_SW_REQ, | ||
517 | sta->addr, | ||
518 | mvm->tdls_cs.peer.initiator, | ||
519 | mvm->tdls_cs.peer.op_class, | ||
520 | &mvm->tdls_cs.peer.chandef, | ||
521 | 0, 0, 0, | ||
522 | mvm->tdls_cs.peer.skb, | ||
523 | mvm->tdls_cs.peer.ch_sw_tm_ie); | ||
524 | if (ret) | ||
525 | IWL_ERR(mvm, "Not sending TDLS channel switch: %d\n", ret); | ||
526 | |||
527 | /* retry after a DTIM if we failed sending now */ | ||
528 | delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int); | ||
529 | queue_delayed_work(system_wq, &mvm->tdls_cs.dwork, | ||
530 | msecs_to_jiffies(delay)); | ||
531 | out: | ||
532 | mutex_unlock(&mvm->mutex); | ||
533 | } | ||
534 | |||
535 | int | ||
536 | iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw, | ||
537 | struct ieee80211_vif *vif, | ||
538 | struct ieee80211_sta *sta, u8 oper_class, | ||
539 | struct cfg80211_chan_def *chandef, | ||
540 | struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie) | ||
541 | { | ||
542 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
543 | struct iwl_mvm_sta *mvmsta; | ||
544 | unsigned int delay; | ||
545 | int ret; | ||
546 | |||
547 | mutex_lock(&mvm->mutex); | ||
548 | |||
549 | IWL_DEBUG_TDLS(mvm, "TDLS channel switch with %pM ch %d width %d\n", | ||
550 | sta->addr, chandef->chan->center_freq, chandef->width); | ||
551 | |||
552 | /* we only support a single peer for channel switching */ | ||
553 | if (mvm->tdls_cs.peer.sta_id != IWL_MVM_STATION_COUNT) { | ||
554 | IWL_DEBUG_TDLS(mvm, | ||
555 | "Existing peer. Can't start switch with %pM\n", | ||
556 | sta->addr); | ||
557 | ret = -EBUSY; | ||
558 | goto out; | ||
559 | } | ||
560 | |||
561 | ret = iwl_mvm_tdls_config_channel_switch(mvm, vif, | ||
562 | TDLS_SEND_CHAN_SW_REQ, | ||
563 | sta->addr, sta->tdls_initiator, | ||
564 | oper_class, chandef, 0, 0, 0, | ||
565 | tmpl_skb, ch_sw_tm_ie); | ||
566 | if (ret) | ||
567 | goto out; | ||
568 | |||
569 | /* | ||
570 | * Mark the peer as "in tdls switch" for this vif. We only allow a | ||
571 | * single such peer per vif. | ||
572 | */ | ||
573 | mvm->tdls_cs.peer.skb = skb_copy(tmpl_skb, GFP_KERNEL); | ||
574 | if (!mvm->tdls_cs.peer.skb) { | ||
575 | ret = -ENOMEM; | ||
576 | goto out; | ||
577 | } | ||
578 | |||
579 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
580 | mvm->tdls_cs.peer.sta_id = mvmsta->sta_id; | ||
581 | mvm->tdls_cs.peer.chandef = *chandef; | ||
582 | mvm->tdls_cs.peer.initiator = sta->tdls_initiator; | ||
583 | mvm->tdls_cs.peer.op_class = oper_class; | ||
584 | mvm->tdls_cs.peer.ch_sw_tm_ie = ch_sw_tm_ie; | ||
585 | |||
586 | /* | ||
587 | * Wait for 2 DTIM periods before attempting the next switch. The next | ||
588 | * switch will be made sooner if the current one completes before that. | ||
589 | */ | ||
590 | delay = 2 * TU_TO_MS(vif->bss_conf.dtim_period * | ||
591 | vif->bss_conf.beacon_int); | ||
592 | mod_delayed_work(system_wq, &mvm->tdls_cs.dwork, | ||
593 | msecs_to_jiffies(delay)); | ||
594 | |||
595 | out: | ||
596 | mutex_unlock(&mvm->mutex); | ||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, | ||
601 | struct ieee80211_vif *vif, | ||
602 | struct ieee80211_sta *sta) | ||
603 | { | ||
604 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
605 | struct ieee80211_sta *cur_sta; | ||
606 | bool wait_for_phy = false; | ||
607 | |||
608 | mutex_lock(&mvm->mutex); | ||
609 | |||
610 | IWL_DEBUG_TDLS(mvm, "TDLS cancel channel switch with %pM\n", sta->addr); | ||
611 | |||
612 | /* we only support a single peer for channel switching */ | ||
613 | if (mvm->tdls_cs.peer.sta_id == IWL_MVM_STATION_COUNT) { | ||
614 | IWL_DEBUG_TDLS(mvm, "No ch switch peer - %pM\n", sta->addr); | ||
615 | goto out; | ||
616 | } | ||
617 | |||
618 | cur_sta = rcu_dereference_protected( | ||
619 | mvm->fw_id_to_mac_id[mvm->tdls_cs.peer.sta_id], | ||
620 | lockdep_is_held(&mvm->mutex)); | ||
621 | /* make sure it's the same peer */ | ||
622 | if (cur_sta != sta) | ||
623 | goto out; | ||
624 | |||
625 | /* | ||
626 | * If we're currently in a switch because of the now canceled peer, | ||
627 | * wait a DTIM here to make sure the phy is back on the base channel. | ||
628 | * We can't otherwise force it. | ||
629 | */ | ||
630 | if (mvm->tdls_cs.cur_sta_id == mvm->tdls_cs.peer.sta_id && | ||
631 | mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE) | ||
632 | wait_for_phy = true; | ||
633 | |||
634 | mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT; | ||
635 | dev_kfree_skb(mvm->tdls_cs.peer.skb); | ||
636 | mvm->tdls_cs.peer.skb = NULL; | ||
637 | |||
638 | out: | ||
639 | mutex_unlock(&mvm->mutex); | ||
640 | |||
641 | /* make sure the phy is on the base channel */ | ||
642 | if (wait_for_phy) | ||
643 | msleep(TU_TO_MS(vif->bss_conf.dtim_period * | ||
644 | vif->bss_conf.beacon_int)); | ||
645 | |||
646 | /* flush the channel switch state */ | ||
647 | flush_delayed_work(&mvm->tdls_cs.dwork); | ||
648 | |||
649 | IWL_DEBUG_TDLS(mvm, "TDLS ending channel switch with %pM\n", sta->addr); | ||
650 | } | ||
651 | |||
652 | void | ||
653 | iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, | ||
654 | struct ieee80211_vif *vif, | ||
655 | struct ieee80211_tdls_ch_sw_params *params) | ||
656 | { | ||
657 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
658 | enum iwl_tdls_channel_switch_type type; | ||
659 | unsigned int delay; | ||
660 | |||
661 | mutex_lock(&mvm->mutex); | ||
662 | |||
663 | IWL_DEBUG_TDLS(mvm, | ||
664 | "Received TDLS ch switch action %d from %pM status %d\n", | ||
665 | params->action_code, params->sta->addr, params->status); | ||
666 | |||
667 | /* | ||
668 | * we got a non-zero status from a peer we were switching to - move to | ||
669 | * the idle state and retry again later | ||
670 | */ | ||
671 | if (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE && | ||
672 | params->status != 0 && | ||
673 | mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT && | ||
674 | mvm->tdls_cs.cur_sta_id != IWL_MVM_STATION_COUNT) { | ||
675 | struct ieee80211_sta *cur_sta; | ||
676 | |||
677 | /* make sure it's the same peer */ | ||
678 | cur_sta = rcu_dereference_protected( | ||
679 | mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id], | ||
680 | lockdep_is_held(&mvm->mutex)); | ||
681 | if (cur_sta == params->sta) { | ||
682 | iwl_mvm_tdls_update_cs_state(mvm, | ||
683 | IWL_MVM_TDLS_SW_IDLE); | ||
684 | goto retry; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | type = (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST) ? | ||
689 | TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH : TDLS_MOVE_CH; | ||
690 | |||
691 | iwl_mvm_tdls_config_channel_switch(mvm, vif, type, params->sta->addr, | ||
692 | params->sta->tdls_initiator, 0, | ||
693 | params->chandef, params->timestamp, | ||
694 | params->switch_time, | ||
695 | params->switch_timeout, | ||
696 | params->tmpl_skb, | ||
697 | params->ch_sw_tm_ie); | ||
698 | |||
699 | retry: | ||
700 | /* register a timeout in case we don't succeed in switching */ | ||
701 | delay = vif->bss_conf.dtim_period * vif->bss_conf.beacon_int * | ||
702 | 1024 / 1000; | ||
703 | mod_delayed_work(system_wq, &mvm->tdls_cs.dwork, | ||
704 | msecs_to_jiffies(delay)); | ||
705 | mutex_unlock(&mvm->mutex); | ||
706 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 6dfad230be5e..54fafbf9a711 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -191,6 +191,35 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, | |||
191 | return true; | 191 | return true; |
192 | } | 192 | } |
193 | 193 | ||
194 | static void | ||
195 | iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm, | ||
196 | struct iwl_mvm_time_event_data *te_data, | ||
197 | struct iwl_time_event_notif *notif) | ||
198 | { | ||
199 | if (!le32_to_cpu(notif->status)) { | ||
200 | IWL_DEBUG_TE(mvm, "CSA time event failed to start\n"); | ||
201 | iwl_mvm_te_clear_data(mvm, te_data); | ||
202 | return; | ||
203 | } | ||
204 | |||
205 | switch (te_data->vif->type) { | ||
206 | case NL80211_IFTYPE_AP: | ||
207 | iwl_mvm_csa_noa_start(mvm); | ||
208 | break; | ||
209 | case NL80211_IFTYPE_STATION: | ||
210 | iwl_mvm_csa_client_absent(mvm, te_data->vif); | ||
211 | ieee80211_chswitch_done(te_data->vif, true); | ||
212 | break; | ||
213 | default: | ||
214 | /* should never happen */ | ||
215 | WARN_ON_ONCE(1); | ||
216 | break; | ||
217 | } | ||
218 | |||
219 | /* we don't need it anymore */ | ||
220 | iwl_mvm_te_clear_data(mvm, te_data); | ||
221 | } | ||
222 | |||
194 | /* | 223 | /* |
195 | * Handles a FW notification for an event that is known to the driver. | 224 | * Handles a FW notification for an event that is known to the driver. |
196 | * | 225 | * |
@@ -252,14 +281,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
252 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | 281 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); |
253 | iwl_mvm_ref(mvm, IWL_MVM_REF_ROC); | 282 | iwl_mvm_ref(mvm, IWL_MVM_REF_ROC); |
254 | ieee80211_ready_on_channel(mvm->hw); | 283 | ieee80211_ready_on_channel(mvm->hw); |
255 | } else if (te_data->vif->type == NL80211_IFTYPE_AP) { | 284 | } else if (te_data->id == TE_CHANNEL_SWITCH_PERIOD) { |
256 | if (le32_to_cpu(notif->status)) | 285 | iwl_mvm_te_handle_notify_csa(mvm, te_data, notif); |
257 | iwl_mvm_csa_noa_start(mvm); | ||
258 | else | ||
259 | IWL_DEBUG_TE(mvm, "CSA NOA failed to start\n"); | ||
260 | |||
261 | /* we don't need it anymore */ | ||
262 | iwl_mvm_te_clear_data(mvm, te_data); | ||
263 | } | 286 | } |
264 | } else { | 287 | } else { |
265 | IWL_WARN(mvm, "Got TE with unknown action\n"); | 288 | IWL_WARN(mvm, "Got TE with unknown action\n"); |
@@ -549,18 +572,11 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
549 | } | 572 | } |
550 | } | 573 | } |
551 | 574 | ||
552 | /* | 575 | static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, |
553 | * Explicit request to remove a time event. The removal of a time event needs to | 576 | struct iwl_mvm_time_event_data *te_data, |
554 | * be synchronized with the flow of a time event's end notification, which also | 577 | u32 *uid) |
555 | * removes the time event from the op mode data structures. | ||
556 | */ | ||
557 | void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | ||
558 | struct iwl_mvm_vif *mvmvif, | ||
559 | struct iwl_mvm_time_event_data *te_data) | ||
560 | { | 578 | { |
561 | struct iwl_time_event_cmd time_cmd = {}; | 579 | u32 id; |
562 | u32 id, uid; | ||
563 | int ret; | ||
564 | 580 | ||
565 | /* | 581 | /* |
566 | * It is possible that by the time we got to this point the time | 582 | * It is possible that by the time we got to this point the time |
@@ -569,7 +585,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | |||
569 | spin_lock_bh(&mvm->time_event_lock); | 585 | spin_lock_bh(&mvm->time_event_lock); |
570 | 586 | ||
571 | /* Save time event uid before clearing its data */ | 587 | /* Save time event uid before clearing its data */ |
572 | uid = te_data->uid; | 588 | *uid = te_data->uid; |
573 | id = te_data->id; | 589 | id = te_data->id; |
574 | 590 | ||
575 | /* | 591 | /* |
@@ -584,10 +600,59 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | |||
584 | * send a removal command. | 600 | * send a removal command. |
585 | */ | 601 | */ |
586 | if (id == TE_MAX) { | 602 | if (id == TE_MAX) { |
587 | IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", uid); | 603 | IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid); |
588 | return; | 604 | return false; |
589 | } | 605 | } |
590 | 606 | ||
607 | return true; | ||
608 | } | ||
609 | |||
610 | /* | ||
611 | * Explicit request to remove a aux roc time event. The removal of a time | ||
612 | * event needs to be synchronized with the flow of a time event's end | ||
613 | * notification, which also removes the time event from the op mode | ||
614 | * data structures. | ||
615 | */ | ||
616 | static void iwl_mvm_remove_aux_roc_te(struct iwl_mvm *mvm, | ||
617 | struct iwl_mvm_vif *mvmvif, | ||
618 | struct iwl_mvm_time_event_data *te_data) | ||
619 | { | ||
620 | struct iwl_hs20_roc_req aux_cmd = {}; | ||
621 | u32 uid; | ||
622 | int ret; | ||
623 | |||
624 | if (!__iwl_mvm_remove_time_event(mvm, te_data, &uid)) | ||
625 | return; | ||
626 | |||
627 | aux_cmd.event_unique_id = cpu_to_le32(uid); | ||
628 | aux_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE); | ||
629 | aux_cmd.id_and_color = | ||
630 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | ||
631 | IWL_DEBUG_TE(mvm, "Removing BSS AUX ROC TE 0x%x\n", | ||
632 | le32_to_cpu(aux_cmd.event_unique_id)); | ||
633 | ret = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, | ||
634 | sizeof(aux_cmd), &aux_cmd); | ||
635 | |||
636 | if (WARN_ON(ret)) | ||
637 | return; | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * Explicit request to remove a time event. The removal of a time event needs to | ||
642 | * be synchronized with the flow of a time event's end notification, which also | ||
643 | * removes the time event from the op mode data structures. | ||
644 | */ | ||
645 | void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | ||
646 | struct iwl_mvm_vif *mvmvif, | ||
647 | struct iwl_mvm_time_event_data *te_data) | ||
648 | { | ||
649 | struct iwl_time_event_cmd time_cmd = {}; | ||
650 | u32 uid; | ||
651 | int ret; | ||
652 | |||
653 | if (!__iwl_mvm_remove_time_event(mvm, te_data, &uid)) | ||
654 | return; | ||
655 | |||
591 | /* When we remove a TE, the UID is to be set in the id field */ | 656 | /* When we remove a TE, the UID is to be set in the id field */ |
592 | time_cmd.id = cpu_to_le32(uid); | 657 | time_cmd.id = cpu_to_le32(uid); |
593 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE); | 658 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE); |
@@ -666,13 +731,17 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
666 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 731 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
667 | } | 732 | } |
668 | 733 | ||
669 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) | 734 | void iwl_mvm_stop_roc(struct iwl_mvm *mvm) |
670 | { | 735 | { |
671 | struct iwl_mvm_vif *mvmvif; | 736 | struct iwl_mvm_vif *mvmvif; |
672 | struct iwl_mvm_time_event_data *te_data; | 737 | struct iwl_mvm_time_event_data *te_data; |
738 | bool is_p2p = false; | ||
673 | 739 | ||
674 | lockdep_assert_held(&mvm->mutex); | 740 | lockdep_assert_held(&mvm->mutex); |
675 | 741 | ||
742 | mvmvif = NULL; | ||
743 | spin_lock_bh(&mvm->time_event_lock); | ||
744 | |||
676 | /* | 745 | /* |
677 | * Iterate over the list of time events and find the time event that is | 746 | * Iterate over the list of time events and find the time event that is |
678 | * associated with a P2P_DEVICE interface. | 747 | * associated with a P2P_DEVICE interface. |
@@ -680,22 +749,41 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) | |||
680 | * event at any given time and this time event coresponds to a ROC | 749 | * event at any given time and this time event coresponds to a ROC |
681 | * request | 750 | * request |
682 | */ | 751 | */ |
683 | mvmvif = NULL; | ||
684 | spin_lock_bh(&mvm->time_event_lock); | ||
685 | list_for_each_entry(te_data, &mvm->time_event_list, list) { | 752 | list_for_each_entry(te_data, &mvm->time_event_list, list) { |
686 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 753 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE && |
754 | te_data->running) { | ||
687 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); | 755 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); |
688 | break; | 756 | is_p2p = true; |
757 | goto remove_te; | ||
689 | } | 758 | } |
690 | } | 759 | } |
760 | |||
761 | /* | ||
762 | * Iterate over the list of aux roc time events and find the time | ||
763 | * event that is associated with a BSS interface. | ||
764 | * This assumes that a BSS interface can have only a single time | ||
765 | * event at any given time and this time event coresponds to a ROC | ||
766 | * request | ||
767 | */ | ||
768 | list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) { | ||
769 | if (te_data->running) { | ||
770 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); | ||
771 | goto remove_te; | ||
772 | } | ||
773 | } | ||
774 | |||
775 | remove_te: | ||
691 | spin_unlock_bh(&mvm->time_event_lock); | 776 | spin_unlock_bh(&mvm->time_event_lock); |
692 | 777 | ||
693 | if (!mvmvif) { | 778 | if (!mvmvif) { |
694 | IWL_WARN(mvm, "P2P_DEVICE no remain on channel event\n"); | 779 | IWL_WARN(mvm, "No remain on channel event\n"); |
695 | return; | 780 | return; |
696 | } | 781 | } |
697 | 782 | ||
698 | iwl_mvm_remove_time_event(mvm, mvmvif, te_data); | 783 | if (is_p2p) |
784 | iwl_mvm_remove_time_event(mvm, mvmvif, te_data); | ||
785 | else | ||
786 | iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data); | ||
699 | 787 | ||
700 | iwl_mvm_roc_finished(mvm); | 788 | iwl_mvm_roc_finished(mvm); |
701 | } | 789 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index b350e47e19da..6f6b35db3ab8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h | |||
@@ -182,14 +182,14 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
182 | int duration, enum ieee80211_roc_type type); | 182 | int duration, enum ieee80211_roc_type type); |
183 | 183 | ||
184 | /** | 184 | /** |
185 | * iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity | 185 | * iwl_mvm_stop_roc - stop remain on channel functionality |
186 | * @mvm: the mvm component | 186 | * @mvm: the mvm component |
187 | * | 187 | * |
188 | * This function can be used to cancel an ongoing ROC session. | 188 | * This function can be used to cancel an ongoing ROC session. |
189 | * The function is async, it will instruct the FW to stop serving the ROC | 189 | * The function is async, it will instruct the FW to stop serving the ROC |
190 | * session, but will not wait for the actual stopping of the session. | 190 | * session, but will not wait for the actual stopping of the session. |
191 | */ | 191 | */ |
192 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm); | 192 | void iwl_mvm_stop_roc(struct iwl_mvm *mvm); |
193 | 193 | ||
194 | /** | 194 | /** |
195 | * iwl_mvm_remove_time_event - general function to clean up of time event | 195 | * iwl_mvm_remove_time_event - general function to clean up of time event |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index d4f2c29025c7..2b1e61fac34a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c | |||
@@ -95,32 +95,81 @@ static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) | |||
95 | iwl_mvm_set_hw_ctkill_state(mvm, false); | 95 | iwl_mvm_set_hw_ctkill_state(mvm, false); |
96 | } | 96 | } |
97 | 97 | ||
98 | static bool iwl_mvm_temp_notif(struct iwl_notif_wait_data *notif_wait, | 98 | void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp) |
99 | struct iwl_rx_packet *pkt, void *data) | 99 | { |
100 | /* ignore the notification if we are in test mode */ | ||
101 | if (mvm->temperature_test) | ||
102 | return; | ||
103 | |||
104 | if (mvm->temperature == temp) | ||
105 | return; | ||
106 | |||
107 | mvm->temperature = temp; | ||
108 | iwl_mvm_tt_handler(mvm); | ||
109 | } | ||
110 | |||
111 | static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm, | ||
112 | struct iwl_rx_packet *pkt) | ||
100 | { | 113 | { |
101 | struct iwl_mvm *mvm = | ||
102 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
103 | int *temp = data; | ||
104 | struct iwl_dts_measurement_notif *notif; | 114 | struct iwl_dts_measurement_notif *notif; |
105 | int len = iwl_rx_packet_payload_len(pkt); | 115 | int len = iwl_rx_packet_payload_len(pkt); |
116 | int temp; | ||
106 | 117 | ||
107 | if (WARN_ON_ONCE(len != sizeof(*notif))) { | 118 | if (WARN_ON_ONCE(len != sizeof(*notif))) { |
108 | IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); | 119 | IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); |
109 | return true; | 120 | return -EINVAL; |
110 | } | 121 | } |
111 | 122 | ||
112 | notif = (void *)pkt->data; | 123 | notif = (void *)pkt->data; |
113 | 124 | ||
114 | *temp = le32_to_cpu(notif->temp); | 125 | temp = le32_to_cpu(notif->temp); |
115 | 126 | ||
116 | /* shouldn't be negative, but since it's s32, make sure it isn't */ | 127 | /* shouldn't be negative, but since it's s32, make sure it isn't */ |
117 | if (WARN_ON_ONCE(*temp < 0)) | 128 | if (WARN_ON_ONCE(temp < 0)) |
118 | *temp = 0; | 129 | temp = 0; |
130 | |||
131 | IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", temp); | ||
132 | |||
133 | return temp; | ||
134 | } | ||
135 | |||
136 | static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait, | ||
137 | struct iwl_rx_packet *pkt, void *data) | ||
138 | { | ||
139 | struct iwl_mvm *mvm = | ||
140 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
141 | int *temp = data; | ||
142 | int ret; | ||
143 | |||
144 | ret = iwl_mvm_temp_notif_parse(mvm, pkt); | ||
145 | if (ret < 0) | ||
146 | return true; | ||
147 | |||
148 | *temp = ret; | ||
119 | 149 | ||
120 | IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", *temp); | ||
121 | return true; | 150 | return true; |
122 | } | 151 | } |
123 | 152 | ||
153 | int iwl_mvm_temp_notif(struct iwl_mvm *mvm, | ||
154 | struct iwl_rx_cmd_buffer *rxb, | ||
155 | struct iwl_device_cmd *cmd) | ||
156 | { | ||
157 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
158 | int temp; | ||
159 | |||
160 | /* the notification is handled synchronously in ctkill, so skip here */ | ||
161 | if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) | ||
162 | return 0; | ||
163 | |||
164 | temp = iwl_mvm_temp_notif_parse(mvm, pkt); | ||
165 | if (temp < 0) | ||
166 | return 0; | ||
167 | |||
168 | iwl_mvm_tt_temp_changed(mvm, temp); | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
124 | static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) | 173 | static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) |
125 | { | 174 | { |
126 | struct iwl_dts_measurement_cmd cmd = { | 175 | struct iwl_dts_measurement_cmd cmd = { |
@@ -141,7 +190,7 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm) | |||
141 | 190 | ||
142 | iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, | 191 | iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, |
143 | temp_notif, ARRAY_SIZE(temp_notif), | 192 | temp_notif, ARRAY_SIZE(temp_notif), |
144 | iwl_mvm_temp_notif, &temp); | 193 | iwl_mvm_temp_notif_wait, &temp); |
145 | 194 | ||
146 | ret = iwl_mvm_get_temp_cmd(mvm); | 195 | ret = iwl_mvm_get_temp_cmd(mvm); |
147 | if (ret) { | 196 | if (ret) { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 8d848735cdb8..4f15d9decc81 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -73,9 +73,9 @@ | |||
73 | /* | 73 | /* |
74 | * Sets most of the Tx cmd's fields | 74 | * Sets most of the Tx cmd's fields |
75 | */ | 75 | */ |
76 | static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | 76 | void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, |
77 | struct iwl_tx_cmd *tx_cmd, | 77 | struct iwl_tx_cmd *tx_cmd, |
78 | struct ieee80211_tx_info *info, u8 sta_id) | 78 | struct ieee80211_tx_info *info, u8 sta_id) |
79 | { | 79 | { |
80 | struct ieee80211_hdr *hdr = (void *)skb->data; | 80 | struct ieee80211_hdr *hdr = (void *)skb->data; |
81 | __le16 fc = hdr->frame_control; | 81 | __le16 fc = hdr->frame_control; |
@@ -149,11 +149,9 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
149 | /* | 149 | /* |
150 | * Sets the fields in the Tx cmd that are rate related | 150 | * Sets the fields in the Tx cmd that are rate related |
151 | */ | 151 | */ |
152 | static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | 152 | void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, |
153 | struct iwl_tx_cmd *tx_cmd, | 153 | struct ieee80211_tx_info *info, |
154 | struct ieee80211_tx_info *info, | 154 | struct ieee80211_sta *sta, __le16 fc) |
155 | struct ieee80211_sta *sta, | ||
156 | __le16 fc) | ||
157 | { | 155 | { |
158 | u32 rate_flags; | 156 | u32 rate_flags; |
159 | int rate_idx; | 157 | int rate_idx; |
@@ -232,10 +230,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | |||
232 | /* | 230 | /* |
233 | * Sets the fields in the Tx cmd that are crypto related | 231 | * Sets the fields in the Tx cmd that are crypto related |
234 | */ | 232 | */ |
235 | static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, | 233 | void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, |
236 | struct ieee80211_tx_info *info, | 234 | struct ieee80211_tx_info *info, |
237 | struct iwl_tx_cmd *tx_cmd, | 235 | struct iwl_tx_cmd *tx_cmd, |
238 | struct sk_buff *skb_frag) | 236 | struct sk_buff *skb_frag) |
239 | { | 237 | { |
240 | struct ieee80211_key_conf *keyconf = info->control.hw_key; | 238 | struct ieee80211_key_conf *keyconf = info->control.hw_key; |
241 | 239 | ||
@@ -426,6 +424,13 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
426 | 424 | ||
427 | WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); | 425 | WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); |
428 | 426 | ||
427 | if (sta->tdls) { | ||
428 | /* default to TID 0 for non-QoS packets */ | ||
429 | u8 tdls_tid = tid == IWL_MAX_TID_COUNT ? 0 : tid; | ||
430 | |||
431 | txq_id = mvmsta->hw_queue[tid_to_mac80211_ac[tdls_tid]]; | ||
432 | } | ||
433 | |||
429 | if (is_ampdu) { | 434 | if (is_ampdu) { |
430 | if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON)) | 435 | if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON)) |
431 | goto drop_unlock_sta; | 436 | goto drop_unlock_sta; |
@@ -660,6 +665,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
660 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); | 665 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); |
661 | } | 666 | } |
662 | 667 | ||
668 | /* | ||
669 | * TODO: this is not accurate if we are freeing more than one | ||
670 | * packet. | ||
671 | */ | ||
672 | info->status.tx_time = | ||
673 | le16_to_cpu(tx_resp->wireless_media_time); | ||
663 | BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); | 674 | BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); |
664 | info->status.status_driver_data[0] = | 675 | info->status.status_driver_data[0] = |
665 | (void *)(uintptr_t)tx_resp->reduced_tpc; | 676 | (void *)(uintptr_t)tx_resp->reduced_tpc; |
@@ -852,6 +863,8 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, | |||
852 | mvmsta->tid_data[tid].rate_n_flags = | 863 | mvmsta->tid_data[tid].rate_n_flags = |
853 | le32_to_cpu(tx_resp->initial_rate); | 864 | le32_to_cpu(tx_resp->initial_rate); |
854 | mvmsta->tid_data[tid].reduced_tpc = tx_resp->reduced_tpc; | 865 | mvmsta->tid_data[tid].reduced_tpc = tx_resp->reduced_tpc; |
866 | mvmsta->tid_data[tid].tx_time = | ||
867 | le16_to_cpu(tx_resp->wireless_media_time); | ||
855 | } | 868 | } |
856 | 869 | ||
857 | rcu_read_unlock(); | 870 | rcu_read_unlock(); |
@@ -880,6 +893,8 @@ static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info, | |||
880 | info->status.ampdu_len = ba_notif->txed; | 893 | info->status.ampdu_len = ba_notif->txed; |
881 | iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags, | 894 | iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags, |
882 | info); | 895 | info); |
896 | /* TODO: not accounted if the whole A-MPDU failed */ | ||
897 | info->status.tx_time = tid_data->tx_time; | ||
883 | info->status.status_driver_data[0] = | 898 | info->status.status_driver_data[0] = |
884 | (void *)(uintptr_t)tid_data->reduced_tpc; | 899 | (void *)(uintptr_t)tid_data->reduced_tpc; |
885 | } | 900 | } |
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 6ced8549eb3a..3ee8e3848876 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c | |||
@@ -499,6 +499,7 @@ static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) {} | |||
499 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 499 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
500 | { | 500 | { |
501 | const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); | 501 | const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); |
502 | const struct iwl_cfg *cfg_7265d __maybe_unused = NULL; | ||
502 | struct iwl_trans *iwl_trans; | 503 | struct iwl_trans *iwl_trans; |
503 | struct iwl_trans_pcie *trans_pcie; | 504 | struct iwl_trans_pcie *trans_pcie; |
504 | int ret; | 505 | int ret; |
@@ -507,6 +508,25 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
507 | if (IS_ERR(iwl_trans)) | 508 | if (IS_ERR(iwl_trans)) |
508 | return PTR_ERR(iwl_trans); | 509 | return PTR_ERR(iwl_trans); |
509 | 510 | ||
511 | #if IS_ENABLED(CONFIG_IWLMVM) | ||
512 | /* | ||
513 | * special-case 7265D, it has the same PCI IDs. | ||
514 | * | ||
515 | * Note that because we already pass the cfg to the transport above, | ||
516 | * all the parameters that the transport uses must, until that is | ||
517 | * changed, be identical to the ones in the 7265D configuration. | ||
518 | */ | ||
519 | if (cfg == &iwl7265_2ac_cfg) | ||
520 | cfg_7265d = &iwl7265d_2ac_cfg; | ||
521 | else if (cfg == &iwl7265_2n_cfg) | ||
522 | cfg_7265d = &iwl7265d_2n_cfg; | ||
523 | else if (cfg == &iwl7265_n_cfg) | ||
524 | cfg_7265d = &iwl7265d_n_cfg; | ||
525 | if (cfg_7265d && | ||
526 | (iwl_trans->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) | ||
527 | cfg = cfg_7265d; | ||
528 | #endif | ||
529 | |||
510 | pci_set_drvdata(pdev, iwl_trans); | 530 | pci_set_drvdata(pdev, iwl_trans); |
511 | 531 | ||
512 | trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); | 532 | trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 40a290603ead..5d79a1f44b8e 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -78,6 +78,11 @@ | |||
78 | #include "iwl-agn-hw.h" | 78 | #include "iwl-agn-hw.h" |
79 | #include "iwl-fw-error-dump.h" | 79 | #include "iwl-fw-error-dump.h" |
80 | #include "internal.h" | 80 | #include "internal.h" |
81 | #include "iwl-fh.h" | ||
82 | |||
83 | /* extended range in FW SRAM */ | ||
84 | #define IWL_FW_MEM_EXTENDED_START 0x40000 | ||
85 | #define IWL_FW_MEM_EXTENDED_END 0x57FFF | ||
81 | 86 | ||
82 | static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) | 87 | static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) |
83 | { | 88 | { |
@@ -512,6 +517,9 @@ static int iwl_pcie_set_hw_ready(struct iwl_trans *trans) | |||
512 | CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, | 517 | CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, |
513 | HW_READY_TIMEOUT); | 518 | HW_READY_TIMEOUT); |
514 | 519 | ||
520 | if (ret >= 0) | ||
521 | iwl_set_bit(trans, CSR_MBOX_SET_REG, CSR_MBOX_SET_REG_OS_ALIVE); | ||
522 | |||
515 | IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : ""); | 523 | IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : ""); |
516 | return ret; | 524 | return ret; |
517 | } | 525 | } |
@@ -624,14 +632,28 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, | |||
624 | } | 632 | } |
625 | 633 | ||
626 | for (offset = 0; offset < section->len; offset += chunk_sz) { | 634 | for (offset = 0; offset < section->len; offset += chunk_sz) { |
627 | u32 copy_size; | 635 | u32 copy_size, dst_addr; |
636 | bool extended_addr = false; | ||
628 | 637 | ||
629 | copy_size = min_t(u32, chunk_sz, section->len - offset); | 638 | copy_size = min_t(u32, chunk_sz, section->len - offset); |
639 | dst_addr = section->offset + offset; | ||
640 | |||
641 | if (dst_addr >= IWL_FW_MEM_EXTENDED_START && | ||
642 | dst_addr <= IWL_FW_MEM_EXTENDED_END) | ||
643 | extended_addr = true; | ||
644 | |||
645 | if (extended_addr) | ||
646 | iwl_set_bits_prph(trans, LMPM_CHICK, | ||
647 | LMPM_CHICK_EXTENDED_ADDR_SPACE); | ||
630 | 648 | ||
631 | memcpy(v_addr, (u8 *)section->data + offset, copy_size); | 649 | memcpy(v_addr, (u8 *)section->data + offset, copy_size); |
632 | ret = iwl_pcie_load_firmware_chunk(trans, | 650 | ret = iwl_pcie_load_firmware_chunk(trans, dst_addr, p_addr, |
633 | section->offset + offset, | 651 | copy_size); |
634 | p_addr, copy_size); | 652 | |
653 | if (extended_addr) | ||
654 | iwl_clear_bits_prph(trans, LMPM_CHICK, | ||
655 | LMPM_CHICK_EXTENDED_ADDR_SPACE); | ||
656 | |||
635 | if (ret) { | 657 | if (ret) { |
636 | IWL_ERR(trans, | 658 | IWL_ERR(trans, |
637 | "Could not load the [%d] uCode section\n", | 659 | "Could not load the [%d] uCode section\n", |
@@ -644,14 +666,14 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, | |||
644 | return ret; | 666 | return ret; |
645 | } | 667 | } |
646 | 668 | ||
647 | static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans, | 669 | static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans, |
648 | const struct fw_img *image, | 670 | const struct fw_img *image, |
649 | int cpu, | 671 | int cpu, |
650 | int *first_ucode_section) | 672 | int *first_ucode_section) |
651 | { | 673 | { |
652 | int shift_param; | 674 | int shift_param; |
653 | int i, ret = 0; | 675 | int i, ret = 0, sec_num = 0x1; |
654 | u32 last_read_idx = 0; | 676 | u32 val, last_read_idx = 0; |
655 | 677 | ||
656 | if (cpu == 1) { | 678 | if (cpu == 1) { |
657 | shift_param = 0; | 679 | shift_param = 0; |
@@ -672,21 +694,16 @@ static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans, | |||
672 | break; | 694 | break; |
673 | } | 695 | } |
674 | 696 | ||
675 | if (i == (*first_ucode_section) + 1) | ||
676 | /* set CPU to started */ | ||
677 | iwl_set_bits_prph(trans, | ||
678 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
679 | LMPM_CPU_HDRS_LOADING_COMPLETED | ||
680 | << shift_param); | ||
681 | |||
682 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); | 697 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); |
683 | if (ret) | 698 | if (ret) |
684 | return ret; | 699 | return ret; |
700 | |||
701 | /* Notify the ucode of the loaded section number and status */ | ||
702 | val = iwl_read_direct32(trans, FH_UCODE_LOAD_STATUS); | ||
703 | val = val | (sec_num << shift_param); | ||
704 | iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, val); | ||
705 | sec_num = (sec_num << 1) | 0x1; | ||
685 | } | 706 | } |
686 | /* image loading complete */ | ||
687 | iwl_set_bits_prph(trans, | ||
688 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
689 | LMPM_CPU_UCODE_LOADING_COMPLETED << shift_param); | ||
690 | 707 | ||
691 | *first_ucode_section = last_read_idx; | 708 | *first_ucode_section = last_read_idx; |
692 | 709 | ||
@@ -739,46 +756,78 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, | |||
739 | return 0; | 756 | return 0; |
740 | } | 757 | } |
741 | 758 | ||
742 | static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | 759 | static void iwl_pcie_apply_destination(struct iwl_trans *trans) |
743 | const struct fw_img *image) | ||
744 | { | 760 | { |
745 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 761 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
746 | int ret = 0; | 762 | const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv; |
747 | int first_ucode_section; | 763 | int i; |
748 | 764 | ||
749 | IWL_DEBUG_FW(trans, | 765 | if (dest->version) |
750 | "working with %s CPU\n", | 766 | IWL_ERR(trans, |
751 | image->is_dual_cpus ? "Dual" : "Single"); | 767 | "DBG DEST version is %d - expect issues\n", |
768 | dest->version); | ||
752 | 769 | ||
753 | /* configure the ucode to be ready to get the secured image */ | 770 | IWL_INFO(trans, "Applying debug destination %s\n", |
754 | if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) { | 771 | get_fw_dbg_mode_string(dest->monitor_mode)); |
755 | /* set secure boot inspector addresses */ | ||
756 | iwl_write_prph(trans, | ||
757 | LMPM_SECURE_INSPECTOR_CODE_ADDR, | ||
758 | LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE); | ||
759 | 772 | ||
760 | iwl_write_prph(trans, | 773 | if (dest->monitor_mode == EXTERNAL_MODE) |
761 | LMPM_SECURE_INSPECTOR_DATA_ADDR, | 774 | iwl_pcie_alloc_fw_monitor(trans); |
762 | LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE); | 775 | else |
776 | IWL_WARN(trans, "PCI should have external buffer debug\n"); | ||
763 | 777 | ||
764 | /* set CPU1 header address */ | 778 | for (i = 0; i < trans->dbg_dest_reg_num; i++) { |
765 | iwl_write_prph(trans, | 779 | u32 addr = le32_to_cpu(dest->reg_ops[i].addr); |
766 | LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR, | 780 | u32 val = le32_to_cpu(dest->reg_ops[i].val); |
767 | LMPM_SECURE_CPU1_HDR_MEM_SPACE); | ||
768 | 781 | ||
769 | /* load to FW the binary Secured sections of CPU1 */ | 782 | switch (dest->reg_ops[i].op) { |
770 | ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1, | 783 | case CSR_ASSIGN: |
771 | &first_ucode_section); | 784 | iwl_write32(trans, addr, val); |
772 | if (ret) | 785 | break; |
773 | return ret; | 786 | case CSR_SETBIT: |
787 | iwl_set_bit(trans, addr, BIT(val)); | ||
788 | break; | ||
789 | case CSR_CLEARBIT: | ||
790 | iwl_clear_bit(trans, addr, BIT(val)); | ||
791 | break; | ||
792 | case PRPH_ASSIGN: | ||
793 | iwl_write_prph(trans, addr, val); | ||
794 | break; | ||
795 | case PRPH_SETBIT: | ||
796 | iwl_set_bits_prph(trans, addr, BIT(val)); | ||
797 | break; | ||
798 | case PRPH_CLEARBIT: | ||
799 | iwl_clear_bits_prph(trans, addr, BIT(val)); | ||
800 | break; | ||
801 | default: | ||
802 | IWL_ERR(trans, "FW debug - unknown OP %d\n", | ||
803 | dest->reg_ops[i].op); | ||
804 | break; | ||
805 | } | ||
806 | } | ||
774 | 807 | ||
775 | } else { | 808 | if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) { |
776 | /* load to FW the binary Non secured sections of CPU1 */ | 809 | iwl_write_prph(trans, le32_to_cpu(dest->base_reg), |
777 | ret = iwl_pcie_load_cpu_sections(trans, image, 1, | 810 | trans_pcie->fw_mon_phys >> dest->base_shift); |
778 | &first_ucode_section); | 811 | iwl_write_prph(trans, le32_to_cpu(dest->end_reg), |
779 | if (ret) | 812 | (trans_pcie->fw_mon_phys + |
780 | return ret; | 813 | trans_pcie->fw_mon_size) >> dest->end_shift); |
781 | } | 814 | } |
815 | } | ||
816 | |||
817 | static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | ||
818 | const struct fw_img *image) | ||
819 | { | ||
820 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
821 | int ret = 0; | ||
822 | int first_ucode_section; | ||
823 | |||
824 | IWL_DEBUG_FW(trans, "working with %s CPU\n", | ||
825 | image->is_dual_cpus ? "Dual" : "Single"); | ||
826 | |||
827 | /* load to FW the binary non secured sections of CPU1 */ | ||
828 | ret = iwl_pcie_load_cpu_sections(trans, image, 1, &first_ucode_section); | ||
829 | if (ret) | ||
830 | return ret; | ||
782 | 831 | ||
783 | if (image->is_dual_cpus) { | 832 | if (image->is_dual_cpus) { |
784 | /* set CPU2 header address */ | 833 | /* set CPU2 header address */ |
@@ -787,14 +836,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | |||
787 | LMPM_SECURE_CPU2_HDR_MEM_SPACE); | 836 | LMPM_SECURE_CPU2_HDR_MEM_SPACE); |
788 | 837 | ||
789 | /* load to FW the binary sections of CPU2 */ | 838 | /* load to FW the binary sections of CPU2 */ |
790 | if (iwl_has_secure_boot(trans->hw_rev, | 839 | ret = iwl_pcie_load_cpu_sections(trans, image, 2, |
791 | trans->cfg->device_family)) | 840 | &first_ucode_section); |
792 | ret = iwl_pcie_load_cpu_secured_sections( | ||
793 | trans, image, 2, | ||
794 | &first_ucode_section); | ||
795 | else | ||
796 | ret = iwl_pcie_load_cpu_sections(trans, image, 2, | ||
797 | &first_ucode_section); | ||
798 | if (ret) | 841 | if (ret) |
799 | return ret; | 842 | return ret; |
800 | } | 843 | } |
@@ -811,6 +854,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | |||
811 | (trans_pcie->fw_mon_phys + | 854 | (trans_pcie->fw_mon_phys + |
812 | trans_pcie->fw_mon_size) >> 4); | 855 | trans_pcie->fw_mon_size) >> 4); |
813 | } | 856 | } |
857 | } else if (trans->dbg_dest_tlv) { | ||
858 | iwl_pcie_apply_destination(trans); | ||
814 | } | 859 | } |
815 | 860 | ||
816 | /* release CPU reset */ | 861 | /* release CPU reset */ |
@@ -819,18 +864,50 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | |||
819 | else | 864 | else |
820 | iwl_write32(trans, CSR_RESET, 0); | 865 | iwl_write32(trans, CSR_RESET, 0); |
821 | 866 | ||
822 | if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) { | 867 | return 0; |
823 | /* wait for image verification to complete */ | 868 | } |
824 | ret = iwl_poll_prph_bit(trans, | ||
825 | LMPM_SECURE_BOOT_CPU1_STATUS_ADDR, | ||
826 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
827 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
828 | LMPM_SECURE_TIME_OUT); | ||
829 | 869 | ||
830 | if (ret < 0) { | 870 | static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, |
831 | IWL_ERR(trans, "Time out on secure boot process\n"); | 871 | const struct fw_img *image) |
832 | return ret; | 872 | { |
833 | } | 873 | int ret = 0; |
874 | int first_ucode_section; | ||
875 | u32 reg; | ||
876 | |||
877 | IWL_DEBUG_FW(trans, "working with %s CPU\n", | ||
878 | image->is_dual_cpus ? "Dual" : "Single"); | ||
879 | |||
880 | /* configure the ucode to be ready to get the secured image */ | ||
881 | /* release CPU reset */ | ||
882 | iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); | ||
883 | |||
884 | /* load to FW the binary Secured sections of CPU1 */ | ||
885 | ret = iwl_pcie_load_cpu_sections_8000b(trans, image, 1, | ||
886 | &first_ucode_section); | ||
887 | if (ret) | ||
888 | return ret; | ||
889 | |||
890 | /* load to FW the binary sections of CPU2 */ | ||
891 | ret = iwl_pcie_load_cpu_sections_8000b(trans, image, 2, | ||
892 | &first_ucode_section); | ||
893 | if (ret) | ||
894 | return ret; | ||
895 | |||
896 | /* Notify FW loading is done */ | ||
897 | iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF); | ||
898 | |||
899 | /* wait for image verification to complete */ | ||
900 | ret = iwl_poll_prph_bit(trans, LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0, | ||
901 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
902 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
903 | LMPM_SECURE_TIME_OUT); | ||
904 | if (ret < 0) { | ||
905 | reg = iwl_read_prph(trans, | ||
906 | LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0); | ||
907 | |||
908 | IWL_ERR(trans, "Timeout on secure boot process, reg = %x\n", | ||
909 | reg); | ||
910 | return ret; | ||
834 | } | 911 | } |
835 | 912 | ||
836 | return 0; | 913 | return 0; |
@@ -882,7 +959,11 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, | |||
882 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | 959 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); |
883 | 960 | ||
884 | /* Load the given image to the HW */ | 961 | /* Load the given image to the HW */ |
885 | return iwl_pcie_load_given_ucode(trans, fw); | 962 | if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) && |
963 | (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP)) | ||
964 | return iwl_pcie_load_given_ucode_8000b(trans, fw); | ||
965 | else | ||
966 | return iwl_pcie_load_given_ucode(trans, fw); | ||
886 | } | 967 | } |
887 | 968 | ||
888 | static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) | 969 | static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) |
@@ -913,7 +994,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
913 | * restart. So don't process again if the device is | 994 | * restart. So don't process again if the device is |
914 | * already dead. | 995 | * already dead. |
915 | */ | 996 | */ |
916 | if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) { | 997 | if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) { |
998 | IWL_DEBUG_INFO(trans, "DEVICE_ENABLED bit was set and is now cleared\n"); | ||
917 | iwl_pcie_tx_stop(trans); | 999 | iwl_pcie_tx_stop(trans); |
918 | iwl_pcie_rx_stop(trans); | 1000 | iwl_pcie_rx_stop(trans); |
919 | 1001 | ||
@@ -938,12 +1020,12 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
938 | spin_unlock(&trans_pcie->irq_lock); | 1020 | spin_unlock(&trans_pcie->irq_lock); |
939 | 1021 | ||
940 | /* stop and reset the on-board processor */ | 1022 | /* stop and reset the on-board processor */ |
941 | iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); | 1023 | iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); |
1024 | udelay(20); | ||
942 | 1025 | ||
943 | /* clear all status bits */ | 1026 | /* clear all status bits */ |
944 | clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); | 1027 | clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); |
945 | clear_bit(STATUS_INT_ENABLED, &trans->status); | 1028 | clear_bit(STATUS_INT_ENABLED, &trans->status); |
946 | clear_bit(STATUS_DEVICE_ENABLED, &trans->status); | ||
947 | clear_bit(STATUS_TPOWER_PMI, &trans->status); | 1029 | clear_bit(STATUS_TPOWER_PMI, &trans->status); |
948 | clear_bit(STATUS_RFKILL, &trans->status); | 1030 | clear_bit(STATUS_RFKILL, &trans->status); |
949 | 1031 | ||
@@ -972,6 +1054,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
972 | clear_bit(STATUS_RFKILL, &trans->status); | 1054 | clear_bit(STATUS_RFKILL, &trans->status); |
973 | if (hw_rfkill != was_hw_rfkill) | 1055 | if (hw_rfkill != was_hw_rfkill) |
974 | iwl_trans_pcie_rf_kill(trans, hw_rfkill); | 1056 | iwl_trans_pcie_rf_kill(trans, hw_rfkill); |
1057 | |||
1058 | /* re-take ownership to prevent other users from stealing the deivce */ | ||
1059 | iwl_pcie_prepare_card_hw(trans); | ||
975 | } | 1060 | } |
976 | 1061 | ||
977 | void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) | 1062 | void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) |
@@ -1031,6 +1116,9 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, | |||
1031 | iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 1116 | iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
1032 | iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | 1117 | iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); |
1033 | 1118 | ||
1119 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
1120 | udelay(2); | ||
1121 | |||
1034 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | 1122 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, |
1035 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | 1123 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, |
1036 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | 1124 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, |
@@ -1233,6 +1321,8 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, | |||
1233 | /* this bit wakes up the NIC */ | 1321 | /* this bit wakes up the NIC */ |
1234 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, | 1322 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, |
1235 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 1323 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
1324 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
1325 | udelay(2); | ||
1236 | 1326 | ||
1237 | /* | 1327 | /* |
1238 | * These bits say the device is running, and should keep running for | 1328 | * These bits say the device is running, and should keep running for |
@@ -1898,8 +1988,7 @@ static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans, | |||
1898 | int reg; | 1988 | int reg; |
1899 | __le32 *val; | 1989 | __le32 *val; |
1900 | 1990 | ||
1901 | prph_len += sizeof(*data) + sizeof(*prph) + | 1991 | prph_len += sizeof(**data) + sizeof(*prph) + num_bytes_in_chunk; |
1902 | num_bytes_in_chunk; | ||
1903 | 1992 | ||
1904 | (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH); | 1993 | (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH); |
1905 | (*data)->len = cpu_to_le32(sizeof(*prph) + | 1994 | (*data)->len = cpu_to_le32(sizeof(*prph) + |
@@ -1942,6 +2031,31 @@ static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans, | |||
1942 | return csr_len; | 2031 | return csr_len; |
1943 | } | 2032 | } |
1944 | 2033 | ||
2034 | static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans, | ||
2035 | struct iwl_fw_error_dump_data **data) | ||
2036 | { | ||
2037 | u32 fh_regs_len = FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND; | ||
2038 | unsigned long flags; | ||
2039 | __le32 *val; | ||
2040 | int i; | ||
2041 | |||
2042 | if (!iwl_trans_grab_nic_access(trans, false, &flags)) | ||
2043 | return 0; | ||
2044 | |||
2045 | (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FH_REGS); | ||
2046 | (*data)->len = cpu_to_le32(fh_regs_len); | ||
2047 | val = (void *)(*data)->data; | ||
2048 | |||
2049 | for (i = FH_MEM_LOWER_BOUND; i < FH_MEM_UPPER_BOUND; i += sizeof(u32)) | ||
2050 | *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i)); | ||
2051 | |||
2052 | iwl_trans_release_nic_access(trans, &flags); | ||
2053 | |||
2054 | *data = iwl_fw_error_next_data(*data); | ||
2055 | |||
2056 | return sizeof(**data) + fh_regs_len; | ||
2057 | } | ||
2058 | |||
1945 | static | 2059 | static |
1946 | struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) | 2060 | struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) |
1947 | { | 2061 | { |
@@ -1951,6 +2065,7 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) | |||
1951 | struct iwl_fw_error_dump_txcmd *txcmd; | 2065 | struct iwl_fw_error_dump_txcmd *txcmd; |
1952 | struct iwl_trans_dump_data *dump_data; | 2066 | struct iwl_trans_dump_data *dump_data; |
1953 | u32 len; | 2067 | u32 len; |
2068 | u32 monitor_len; | ||
1954 | int i, ptr; | 2069 | int i, ptr; |
1955 | 2070 | ||
1956 | /* transport dump header */ | 2071 | /* transport dump header */ |
@@ -1973,10 +2088,34 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) | |||
1973 | num_bytes_in_chunk; | 2088 | num_bytes_in_chunk; |
1974 | } | 2089 | } |
1975 | 2090 | ||
2091 | /* FH registers */ | ||
2092 | len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); | ||
2093 | |||
1976 | /* FW monitor */ | 2094 | /* FW monitor */ |
1977 | if (trans_pcie->fw_mon_page) | 2095 | if (trans_pcie->fw_mon_page) { |
1978 | len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + | 2096 | len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + |
1979 | trans_pcie->fw_mon_size; | 2097 | trans_pcie->fw_mon_size; |
2098 | monitor_len = trans_pcie->fw_mon_size; | ||
2099 | } else if (trans->dbg_dest_tlv) { | ||
2100 | u32 base, end; | ||
2101 | |||
2102 | base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); | ||
2103 | end = le32_to_cpu(trans->dbg_dest_tlv->end_reg); | ||
2104 | |||
2105 | base = iwl_read_prph(trans, base) << | ||
2106 | trans->dbg_dest_tlv->base_shift; | ||
2107 | end = iwl_read_prph(trans, end) << | ||
2108 | trans->dbg_dest_tlv->end_shift; | ||
2109 | |||
2110 | /* Make "end" point to the actual end */ | ||
2111 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
2112 | end += (1 << trans->dbg_dest_tlv->end_shift); | ||
2113 | monitor_len = end - base; | ||
2114 | len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + | ||
2115 | monitor_len; | ||
2116 | } else { | ||
2117 | monitor_len = 0; | ||
2118 | } | ||
1980 | 2119 | ||
1981 | dump_data = vzalloc(len); | 2120 | dump_data = vzalloc(len); |
1982 | if (!dump_data) | 2121 | if (!dump_data) |
@@ -2013,36 +2152,71 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) | |||
2013 | 2152 | ||
2014 | len += iwl_trans_pcie_dump_prph(trans, &data); | 2153 | len += iwl_trans_pcie_dump_prph(trans, &data); |
2015 | len += iwl_trans_pcie_dump_csr(trans, &data); | 2154 | len += iwl_trans_pcie_dump_csr(trans, &data); |
2155 | len += iwl_trans_pcie_fh_regs_dump(trans, &data); | ||
2016 | /* data is already pointing to the next section */ | 2156 | /* data is already pointing to the next section */ |
2017 | 2157 | ||
2018 | if (trans_pcie->fw_mon_page) { | 2158 | if ((trans_pcie->fw_mon_page && |
2159 | trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || | ||
2160 | trans->dbg_dest_tlv) { | ||
2019 | struct iwl_fw_error_dump_fw_mon *fw_mon_data; | 2161 | struct iwl_fw_error_dump_fw_mon *fw_mon_data; |
2162 | u32 base, write_ptr, wrap_cnt; | ||
2163 | |||
2164 | /* If there was a dest TLV - use the values from there */ | ||
2165 | if (trans->dbg_dest_tlv) { | ||
2166 | write_ptr = | ||
2167 | le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); | ||
2168 | wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); | ||
2169 | base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); | ||
2170 | } else { | ||
2171 | base = MON_BUFF_BASE_ADDR; | ||
2172 | write_ptr = MON_BUFF_WRPTR; | ||
2173 | wrap_cnt = MON_BUFF_CYCLE_CNT; | ||
2174 | } | ||
2020 | 2175 | ||
2021 | data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); | 2176 | data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); |
2022 | data->len = cpu_to_le32(trans_pcie->fw_mon_size + | ||
2023 | sizeof(*fw_mon_data)); | ||
2024 | fw_mon_data = (void *)data->data; | 2177 | fw_mon_data = (void *)data->data; |
2025 | fw_mon_data->fw_mon_wr_ptr = | 2178 | fw_mon_data->fw_mon_wr_ptr = |
2026 | cpu_to_le32(iwl_read_prph(trans, MON_BUFF_WRPTR)); | 2179 | cpu_to_le32(iwl_read_prph(trans, write_ptr)); |
2027 | fw_mon_data->fw_mon_cycle_cnt = | 2180 | fw_mon_data->fw_mon_cycle_cnt = |
2028 | cpu_to_le32(iwl_read_prph(trans, MON_BUFF_CYCLE_CNT)); | 2181 | cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); |
2029 | fw_mon_data->fw_mon_base_ptr = | 2182 | fw_mon_data->fw_mon_base_ptr = |
2030 | cpu_to_le32(iwl_read_prph(trans, MON_BUFF_BASE_ADDR)); | 2183 | cpu_to_le32(iwl_read_prph(trans, base)); |
2031 | 2184 | ||
2032 | /* | 2185 | len += sizeof(*data) + sizeof(*fw_mon_data); |
2033 | * The firmware is now asserted, it won't write anything to | 2186 | if (trans_pcie->fw_mon_page) { |
2034 | * the buffer. CPU can take ownership to fetch the data. | 2187 | data->len = cpu_to_le32(trans_pcie->fw_mon_size + |
2035 | * The buffer will be handed back to the device before the | 2188 | sizeof(*fw_mon_data)); |
2036 | * firmware will be restarted. | 2189 | |
2037 | */ | 2190 | /* |
2038 | dma_sync_single_for_cpu(trans->dev, trans_pcie->fw_mon_phys, | 2191 | * The firmware is now asserted, it won't write anything |
2039 | trans_pcie->fw_mon_size, | 2192 | * to the buffer. CPU can take ownership to fetch the |
2040 | DMA_FROM_DEVICE); | 2193 | * data. The buffer will be handed back to the device |
2041 | memcpy(fw_mon_data->data, page_address(trans_pcie->fw_mon_page), | 2194 | * before the firmware will be restarted. |
2042 | trans_pcie->fw_mon_size); | 2195 | */ |
2043 | 2196 | dma_sync_single_for_cpu(trans->dev, | |
2044 | len += sizeof(*data) + sizeof(*fw_mon_data) + | 2197 | trans_pcie->fw_mon_phys, |
2045 | trans_pcie->fw_mon_size; | 2198 | trans_pcie->fw_mon_size, |
2199 | DMA_FROM_DEVICE); | ||
2200 | memcpy(fw_mon_data->data, | ||
2201 | page_address(trans_pcie->fw_mon_page), | ||
2202 | trans_pcie->fw_mon_size); | ||
2203 | |||
2204 | len += trans_pcie->fw_mon_size; | ||
2205 | } else { | ||
2206 | /* If we are here then the buffer is internal */ | ||
2207 | |||
2208 | /* | ||
2209 | * Update pointers to reflect actual values after | ||
2210 | * shifting | ||
2211 | */ | ||
2212 | base = iwl_read_prph(trans, base) << | ||
2213 | trans->dbg_dest_tlv->base_shift; | ||
2214 | iwl_trans_read_mem(trans, base, fw_mon_data->data, | ||
2215 | monitor_len / sizeof(u32)); | ||
2216 | data->len = cpu_to_le32(sizeof(*fw_mon_data) + | ||
2217 | monitor_len); | ||
2218 | len += monitor_len; | ||
2219 | } | ||
2046 | } | 2220 | } |
2047 | 2221 | ||
2048 | dump_data->len = len; | 2222 | dump_data->len = len; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index eb8e2984c5e9..8a6c7a084aa1 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -989,6 +989,65 @@ out: | |||
989 | spin_unlock_bh(&txq->lock); | 989 | spin_unlock_bh(&txq->lock); |
990 | } | 990 | } |
991 | 991 | ||
992 | static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans) | ||
993 | { | ||
994 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
995 | int ret; | ||
996 | |||
997 | lockdep_assert_held(&trans_pcie->reg_lock); | ||
998 | |||
999 | if (trans_pcie->cmd_in_flight) | ||
1000 | return 0; | ||
1001 | |||
1002 | trans_pcie->cmd_in_flight = true; | ||
1003 | |||
1004 | /* | ||
1005 | * wake up the NIC to make sure that the firmware will see the host | ||
1006 | * command - we will let the NIC sleep once all the host commands | ||
1007 | * returned. This needs to be done only on NICs that have | ||
1008 | * apmg_wake_up_wa set. | ||
1009 | */ | ||
1010 | if (trans->cfg->base_params->apmg_wake_up_wa) { | ||
1011 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, | ||
1012 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
1013 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
1014 | udelay(2); | ||
1015 | |||
1016 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | ||
1017 | CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, | ||
1018 | (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | | ||
1019 | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), | ||
1020 | 15000); | ||
1021 | if (ret < 0) { | ||
1022 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, | ||
1023 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
1024 | trans_pcie->cmd_in_flight = false; | ||
1025 | IWL_ERR(trans, "Failed to wake NIC for hcmd\n"); | ||
1026 | return -EIO; | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1033 | static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) | ||
1034 | { | ||
1035 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
1036 | |||
1037 | lockdep_assert_held(&trans_pcie->reg_lock); | ||
1038 | |||
1039 | if (WARN_ON(!trans_pcie->cmd_in_flight)) | ||
1040 | return 0; | ||
1041 | |||
1042 | trans_pcie->cmd_in_flight = false; | ||
1043 | |||
1044 | if (trans->cfg->base_params->apmg_wake_up_wa) | ||
1045 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, | ||
1046 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
1047 | |||
1048 | return 0; | ||
1049 | } | ||
1050 | |||
992 | /* | 1051 | /* |
993 | * iwl_pcie_cmdq_reclaim - Reclaim TX command queue entries already Tx'd | 1052 | * iwl_pcie_cmdq_reclaim - Reclaim TX command queue entries already Tx'd |
994 | * | 1053 | * |
@@ -1024,14 +1083,9 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) | |||
1024 | } | 1083 | } |
1025 | } | 1084 | } |
1026 | 1085 | ||
1027 | if (trans->cfg->base_params->apmg_wake_up_wa && | 1086 | if (q->read_ptr == q->write_ptr) { |
1028 | q->read_ptr == q->write_ptr) { | ||
1029 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); | 1087 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); |
1030 | WARN_ON(!trans_pcie->cmd_in_flight); | 1088 | iwl_pcie_clear_cmd_in_flight(trans); |
1031 | trans_pcie->cmd_in_flight = false; | ||
1032 | __iwl_trans_pcie_clear_bit(trans, | ||
1033 | CSR_GP_CNTRL, | ||
1034 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
1035 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); | 1089 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); |
1036 | } | 1090 | } |
1037 | 1091 | ||
@@ -1419,32 +1473,11 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
1419 | mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); | 1473 | mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); |
1420 | 1474 | ||
1421 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); | 1475 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); |
1422 | 1476 | ret = iwl_pcie_set_cmd_in_flight(trans); | |
1423 | /* | 1477 | if (ret < 0) { |
1424 | * wake up the NIC to make sure that the firmware will see the host | 1478 | idx = ret; |
1425 | * command - we will let the NIC sleep once all the host commands | 1479 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); |
1426 | * returned. This needs to be done only on NICs that have | 1480 | goto out; |
1427 | * apmg_wake_up_wa set. | ||
1428 | */ | ||
1429 | if (trans->cfg->base_params->apmg_wake_up_wa && | ||
1430 | !trans_pcie->cmd_in_flight) { | ||
1431 | trans_pcie->cmd_in_flight = true; | ||
1432 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, | ||
1433 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
1434 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | ||
1435 | CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, | ||
1436 | (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | | ||
1437 | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), | ||
1438 | 15000); | ||
1439 | if (ret < 0) { | ||
1440 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, | ||
1441 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
1442 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); | ||
1443 | trans_pcie->cmd_in_flight = false; | ||
1444 | IWL_ERR(trans, "Failed to wake NIC for hcmd\n"); | ||
1445 | idx = -EIO; | ||
1446 | goto out; | ||
1447 | } | ||
1448 | } | 1481 | } |
1449 | 1482 | ||
1450 | /* Increment and update queue's write index */ | 1483 | /* Increment and update queue's write index */ |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index babbdc1ce741..a71b9d5e353d 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -412,6 +412,11 @@ struct mac80211_hwsim_data { | |||
412 | struct mac_address addresses[2]; | 412 | struct mac_address addresses[2]; |
413 | int channels, idx; | 413 | int channels, idx; |
414 | bool use_chanctx; | 414 | bool use_chanctx; |
415 | bool destroy_on_close; | ||
416 | struct work_struct destroy_work; | ||
417 | u32 portid; | ||
418 | char alpha2[2]; | ||
419 | const struct ieee80211_regdomain *regd; | ||
415 | 420 | ||
416 | struct ieee80211_channel *tmp_chan; | 421 | struct ieee80211_channel *tmp_chan; |
417 | struct delayed_work roc_done; | 422 | struct delayed_work roc_done; |
@@ -419,6 +424,7 @@ struct mac80211_hwsim_data { | |||
419 | struct cfg80211_scan_request *hw_scan_request; | 424 | struct cfg80211_scan_request *hw_scan_request; |
420 | struct ieee80211_vif *hw_scan_vif; | 425 | struct ieee80211_vif *hw_scan_vif; |
421 | int scan_chan_idx; | 426 | int scan_chan_idx; |
427 | u8 scan_addr[ETH_ALEN]; | ||
422 | 428 | ||
423 | struct ieee80211_channel *channel; | 429 | struct ieee80211_channel *channel; |
424 | u64 beacon_int /* beacon interval in us */; | 430 | u64 beacon_int /* beacon interval in us */; |
@@ -436,7 +442,7 @@ struct mac80211_hwsim_data { | |||
436 | /* | 442 | /* |
437 | * Only radios in the same group can communicate together (the | 443 | * Only radios in the same group can communicate together (the |
438 | * channel has to match too). Each bit represents a group. A | 444 | * channel has to match too). Each bit represents a group. A |
439 | * radio can be in more then one group. | 445 | * radio can be in more than one group. |
440 | */ | 446 | */ |
441 | u64 group; | 447 | u64 group; |
442 | 448 | ||
@@ -447,6 +453,14 @@ struct mac80211_hwsim_data { | |||
447 | s64 bcn_delta; | 453 | s64 bcn_delta; |
448 | /* absolute beacon transmission time. Used to cover up "tx" delay. */ | 454 | /* absolute beacon transmission time. Used to cover up "tx" delay. */ |
449 | u64 abs_bcn_ts; | 455 | u64 abs_bcn_ts; |
456 | |||
457 | /* Stats */ | ||
458 | u64 tx_pkts; | ||
459 | u64 rx_pkts; | ||
460 | u64 tx_bytes; | ||
461 | u64 rx_bytes; | ||
462 | u64 tx_dropped; | ||
463 | u64 tx_failed; | ||
450 | }; | 464 | }; |
451 | 465 | ||
452 | 466 | ||
@@ -476,6 +490,14 @@ static struct genl_family hwsim_genl_family = { | |||
476 | .maxattr = HWSIM_ATTR_MAX, | 490 | .maxattr = HWSIM_ATTR_MAX, |
477 | }; | 491 | }; |
478 | 492 | ||
493 | enum hwsim_multicast_groups { | ||
494 | HWSIM_MCGRP_CONFIG, | ||
495 | }; | ||
496 | |||
497 | static const struct genl_multicast_group hwsim_mcgrps[] = { | ||
498 | [HWSIM_MCGRP_CONFIG] = { .name = "config", }, | ||
499 | }; | ||
500 | |||
479 | /* MAC80211_HWSIM netlink policy */ | 501 | /* MAC80211_HWSIM netlink policy */ |
480 | 502 | ||
481 | static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { | 503 | static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { |
@@ -496,6 +518,10 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { | |||
496 | [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 }, | 518 | [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 }, |
497 | [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG }, | 519 | [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG }, |
498 | [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG }, | 520 | [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG }, |
521 | [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG }, | ||
522 | [HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING }, | ||
523 | [HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG }, | ||
524 | [HWSIM_ATTR_FREQ] = { .type = NLA_U32 }, | ||
499 | }; | 525 | }; |
500 | 526 | ||
501 | static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | 527 | static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, |
@@ -807,6 +833,9 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, | |||
807 | .ret = false, | 833 | .ret = false, |
808 | }; | 834 | }; |
809 | 835 | ||
836 | if (data->scanning && memcmp(addr, data->scan_addr, ETH_ALEN) == 0) | ||
837 | return true; | ||
838 | |||
810 | memcpy(md.addr, addr, ETH_ALEN); | 839 | memcpy(md.addr, addr, ETH_ALEN); |
811 | 840 | ||
812 | ieee80211_iterate_active_interfaces_atomic(data->hw, | 841 | ieee80211_iterate_active_interfaces_atomic(data->hw, |
@@ -861,8 +890,10 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, | |||
861 | /* If the queue contains MAX_QUEUE skb's drop some */ | 890 | /* If the queue contains MAX_QUEUE skb's drop some */ |
862 | if (skb_queue_len(&data->pending) >= MAX_QUEUE) { | 891 | if (skb_queue_len(&data->pending) >= MAX_QUEUE) { |
863 | /* Droping until WARN_QUEUE level */ | 892 | /* Droping until WARN_QUEUE level */ |
864 | while (skb_queue_len(&data->pending) >= WARN_QUEUE) | 893 | while (skb_queue_len(&data->pending) >= WARN_QUEUE) { |
865 | skb_dequeue(&data->pending); | 894 | ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); |
895 | data->tx_dropped++; | ||
896 | } | ||
866 | } | 897 | } |
867 | 898 | ||
868 | skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); | 899 | skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); |
@@ -896,6 +927,9 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, | |||
896 | if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags)) | 927 | if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags)) |
897 | goto nla_put_failure; | 928 | goto nla_put_failure; |
898 | 929 | ||
930 | if (nla_put_u32(skb, HWSIM_ATTR_FREQ, data->channel->center_freq)) | ||
931 | goto nla_put_failure; | ||
932 | |||
899 | /* We get the tx control (rate and retries) info*/ | 933 | /* We get the tx control (rate and retries) info*/ |
900 | 934 | ||
901 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 935 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
@@ -917,10 +951,14 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, | |||
917 | 951 | ||
918 | /* Enqueue the packet */ | 952 | /* Enqueue the packet */ |
919 | skb_queue_tail(&data->pending, my_skb); | 953 | skb_queue_tail(&data->pending, my_skb); |
954 | data->tx_pkts++; | ||
955 | data->tx_bytes += my_skb->len; | ||
920 | return; | 956 | return; |
921 | 957 | ||
922 | nla_put_failure: | 958 | nla_put_failure: |
923 | printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); | 959 | printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); |
960 | ieee80211_free_txskb(hw, my_skb); | ||
961 | data->tx_failed++; | ||
924 | } | 962 | } |
925 | 963 | ||
926 | static bool hwsim_chans_compat(struct ieee80211_channel *c1, | 964 | static bool hwsim_chans_compat(struct ieee80211_channel *c1, |
@@ -952,6 +990,53 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, | |||
952 | data->receive = true; | 990 | data->receive = true; |
953 | } | 991 | } |
954 | 992 | ||
993 | static void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb) | ||
994 | { | ||
995 | /* | ||
996 | * To enable this code, #define the HWSIM_RADIOTAP_OUI, | ||
997 | * e.g. like this: | ||
998 | * #define HWSIM_RADIOTAP_OUI "\x02\x00\x00" | ||
999 | * (but you should use a valid OUI, not that) | ||
1000 | * | ||
1001 | * If anyone wants to 'donate' a radiotap OUI/subns code | ||
1002 | * please send a patch removing this #ifdef and changing | ||
1003 | * the values accordingly. | ||
1004 | */ | ||
1005 | #ifdef HWSIM_RADIOTAP_OUI | ||
1006 | struct ieee80211_vendor_radiotap *rtap; | ||
1007 | |||
1008 | /* | ||
1009 | * Note that this code requires the headroom in the SKB | ||
1010 | * that was allocated earlier. | ||
1011 | */ | ||
1012 | rtap = (void *)skb_push(skb, sizeof(*rtap) + 8 + 4); | ||
1013 | rtap->oui[0] = HWSIM_RADIOTAP_OUI[0]; | ||
1014 | rtap->oui[1] = HWSIM_RADIOTAP_OUI[1]; | ||
1015 | rtap->oui[2] = HWSIM_RADIOTAP_OUI[2]; | ||
1016 | rtap->subns = 127; | ||
1017 | |||
1018 | /* | ||
1019 | * Radiotap vendor namespaces can (and should) also be | ||
1020 | * split into fields by using the standard radiotap | ||
1021 | * presence bitmap mechanism. Use just BIT(0) here for | ||
1022 | * the presence bitmap. | ||
1023 | */ | ||
1024 | rtap->present = BIT(0); | ||
1025 | /* We have 8 bytes of (dummy) data */ | ||
1026 | rtap->len = 8; | ||
1027 | /* For testing, also require it to be aligned */ | ||
1028 | rtap->align = 8; | ||
1029 | /* And also test that padding works, 4 bytes */ | ||
1030 | rtap->pad = 4; | ||
1031 | /* push the data */ | ||
1032 | memcpy(rtap->data, "ABCDEFGH", 8); | ||
1033 | /* make sure to clear padding, mac80211 doesn't */ | ||
1034 | memset(rtap->data + 8, 0, 4); | ||
1035 | |||
1036 | IEEE80211_SKB_RXCB(skb)->flag |= RX_FLAG_RADIOTAP_VENDOR_DATA; | ||
1037 | #endif | ||
1038 | } | ||
1039 | |||
955 | static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | 1040 | static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, |
956 | struct sk_buff *skb, | 1041 | struct sk_buff *skb, |
957 | struct ieee80211_channel *chan) | 1042 | struct ieee80211_channel *chan) |
@@ -1066,6 +1151,11 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
1066 | rx_status.mactime = now + data2->tsf_offset; | 1151 | rx_status.mactime = now + data2->tsf_offset; |
1067 | 1152 | ||
1068 | memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); | 1153 | memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); |
1154 | |||
1155 | mac80211_hwsim_add_vendor_rtap(nskb); | ||
1156 | |||
1157 | data2->rx_pkts++; | ||
1158 | data2->rx_bytes += nskb->len; | ||
1069 | ieee80211_rx_irqsafe(data2->hw, nskb); | 1159 | ieee80211_rx_irqsafe(data2->hw, nskb); |
1070 | } | 1160 | } |
1071 | spin_unlock(&hwsim_radio_lock); | 1161 | spin_unlock(&hwsim_radio_lock); |
@@ -1133,6 +1223,8 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, | |||
1133 | return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); | 1223 | return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); |
1134 | 1224 | ||
1135 | /* NO wmediumd detected, perfect medium simulation */ | 1225 | /* NO wmediumd detected, perfect medium simulation */ |
1226 | data->tx_pkts++; | ||
1227 | data->tx_bytes += skb->len; | ||
1136 | ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel); | 1228 | ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel); |
1137 | 1229 | ||
1138 | if (ack && skb->len >= 16) { | 1230 | if (ack && skb->len >= 16) { |
@@ -1716,7 +1808,7 @@ static void hw_scan_work(struct work_struct *work) | |||
1716 | struct sk_buff *probe; | 1808 | struct sk_buff *probe; |
1717 | 1809 | ||
1718 | probe = ieee80211_probereq_get(hwsim->hw, | 1810 | probe = ieee80211_probereq_get(hwsim->hw, |
1719 | hwsim->hw_scan_vif, | 1811 | hwsim->scan_addr, |
1720 | req->ssids[i].ssid, | 1812 | req->ssids[i].ssid, |
1721 | req->ssids[i].ssid_len, | 1813 | req->ssids[i].ssid_len, |
1722 | req->ie_len); | 1814 | req->ie_len); |
@@ -1754,6 +1846,12 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, | |||
1754 | hwsim->hw_scan_request = req; | 1846 | hwsim->hw_scan_request = req; |
1755 | hwsim->hw_scan_vif = vif; | 1847 | hwsim->hw_scan_vif = vif; |
1756 | hwsim->scan_chan_idx = 0; | 1848 | hwsim->scan_chan_idx = 0; |
1849 | if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) | ||
1850 | get_random_mask_addr(hwsim->scan_addr, | ||
1851 | hw_req->req.mac_addr, | ||
1852 | hw_req->req.mac_addr_mask); | ||
1853 | else | ||
1854 | memcpy(hwsim->scan_addr, vif->addr, ETH_ALEN); | ||
1757 | mutex_unlock(&hwsim->mutex); | 1855 | mutex_unlock(&hwsim->mutex); |
1758 | 1856 | ||
1759 | wiphy_debug(hw->wiphy, "hwsim hw_scan request\n"); | 1857 | wiphy_debug(hw->wiphy, "hwsim hw_scan request\n"); |
@@ -1780,7 +1878,9 @@ static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, | |||
1780 | mutex_unlock(&hwsim->mutex); | 1878 | mutex_unlock(&hwsim->mutex); |
1781 | } | 1879 | } |
1782 | 1880 | ||
1783 | static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw) | 1881 | static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw, |
1882 | struct ieee80211_vif *vif, | ||
1883 | const u8 *mac_addr) | ||
1784 | { | 1884 | { |
1785 | struct mac80211_hwsim_data *hwsim = hw->priv; | 1885 | struct mac80211_hwsim_data *hwsim = hw->priv; |
1786 | 1886 | ||
@@ -1792,13 +1892,16 @@ static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw) | |||
1792 | } | 1892 | } |
1793 | 1893 | ||
1794 | printk(KERN_DEBUG "hwsim sw_scan request, prepping stuff\n"); | 1894 | printk(KERN_DEBUG "hwsim sw_scan request, prepping stuff\n"); |
1895 | |||
1896 | memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN); | ||
1795 | hwsim->scanning = true; | 1897 | hwsim->scanning = true; |
1796 | 1898 | ||
1797 | out: | 1899 | out: |
1798 | mutex_unlock(&hwsim->mutex); | 1900 | mutex_unlock(&hwsim->mutex); |
1799 | } | 1901 | } |
1800 | 1902 | ||
1801 | static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw) | 1903 | static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw, |
1904 | struct ieee80211_vif *vif) | ||
1802 | { | 1905 | { |
1803 | struct mac80211_hwsim_data *hwsim = hw->priv; | 1906 | struct mac80211_hwsim_data *hwsim = hw->priv; |
1804 | 1907 | ||
@@ -1806,6 +1909,7 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw) | |||
1806 | 1909 | ||
1807 | printk(KERN_DEBUG "hwsim sw_scan_complete\n"); | 1910 | printk(KERN_DEBUG "hwsim sw_scan_complete\n"); |
1808 | hwsim->scanning = false; | 1911 | hwsim->scanning = false; |
1912 | memset(hwsim->scan_addr, 0, ETH_ALEN); | ||
1809 | 1913 | ||
1810 | mutex_unlock(&hwsim->mutex); | 1914 | mutex_unlock(&hwsim->mutex); |
1811 | } | 1915 | } |
@@ -1916,6 +2020,57 @@ static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, | |||
1916 | hwsim_check_chanctx_magic(ctx); | 2020 | hwsim_check_chanctx_magic(ctx); |
1917 | } | 2021 | } |
1918 | 2022 | ||
2023 | static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = { | ||
2024 | "tx_pkts_nic", | ||
2025 | "tx_bytes_nic", | ||
2026 | "rx_pkts_nic", | ||
2027 | "rx_bytes_nic", | ||
2028 | "d_tx_dropped", | ||
2029 | "d_tx_failed", | ||
2030 | "d_ps_mode", | ||
2031 | "d_group", | ||
2032 | "d_tx_power", | ||
2033 | }; | ||
2034 | |||
2035 | #define MAC80211_HWSIM_SSTATS_LEN ARRAY_SIZE(mac80211_hwsim_gstrings_stats) | ||
2036 | |||
2037 | static void mac80211_hwsim_get_et_strings(struct ieee80211_hw *hw, | ||
2038 | struct ieee80211_vif *vif, | ||
2039 | u32 sset, u8 *data) | ||
2040 | { | ||
2041 | if (sset == ETH_SS_STATS) | ||
2042 | memcpy(data, *mac80211_hwsim_gstrings_stats, | ||
2043 | sizeof(mac80211_hwsim_gstrings_stats)); | ||
2044 | } | ||
2045 | |||
2046 | static int mac80211_hwsim_get_et_sset_count(struct ieee80211_hw *hw, | ||
2047 | struct ieee80211_vif *vif, int sset) | ||
2048 | { | ||
2049 | if (sset == ETH_SS_STATS) | ||
2050 | return MAC80211_HWSIM_SSTATS_LEN; | ||
2051 | return 0; | ||
2052 | } | ||
2053 | |||
2054 | static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw, | ||
2055 | struct ieee80211_vif *vif, | ||
2056 | struct ethtool_stats *stats, u64 *data) | ||
2057 | { | ||
2058 | struct mac80211_hwsim_data *ar = hw->priv; | ||
2059 | int i = 0; | ||
2060 | |||
2061 | data[i++] = ar->tx_pkts; | ||
2062 | data[i++] = ar->tx_bytes; | ||
2063 | data[i++] = ar->rx_pkts; | ||
2064 | data[i++] = ar->rx_bytes; | ||
2065 | data[i++] = ar->tx_dropped; | ||
2066 | data[i++] = ar->tx_failed; | ||
2067 | data[i++] = ar->ps; | ||
2068 | data[i++] = ar->group; | ||
2069 | data[i++] = ar->power_level; | ||
2070 | |||
2071 | WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN); | ||
2072 | } | ||
2073 | |||
1919 | static const struct ieee80211_ops mac80211_hwsim_ops = { | 2074 | static const struct ieee80211_ops mac80211_hwsim_ops = { |
1920 | .tx = mac80211_hwsim_tx, | 2075 | .tx = mac80211_hwsim_tx, |
1921 | .start = mac80211_hwsim_start, | 2076 | .start = mac80211_hwsim_start, |
@@ -1939,14 +2094,131 @@ static const struct ieee80211_ops mac80211_hwsim_ops = { | |||
1939 | .flush = mac80211_hwsim_flush, | 2094 | .flush = mac80211_hwsim_flush, |
1940 | .get_tsf = mac80211_hwsim_get_tsf, | 2095 | .get_tsf = mac80211_hwsim_get_tsf, |
1941 | .set_tsf = mac80211_hwsim_set_tsf, | 2096 | .set_tsf = mac80211_hwsim_set_tsf, |
2097 | .get_et_sset_count = mac80211_hwsim_get_et_sset_count, | ||
2098 | .get_et_stats = mac80211_hwsim_get_et_stats, | ||
2099 | .get_et_strings = mac80211_hwsim_get_et_strings, | ||
1942 | }; | 2100 | }; |
1943 | 2101 | ||
1944 | static struct ieee80211_ops mac80211_hwsim_mchan_ops; | 2102 | static struct ieee80211_ops mac80211_hwsim_mchan_ops; |
1945 | 2103 | ||
1946 | static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | 2104 | struct hwsim_new_radio_params { |
1947 | const struct ieee80211_regdomain *regd, | 2105 | unsigned int channels; |
1948 | bool reg_strict, bool p2p_device, | 2106 | const char *reg_alpha2; |
1949 | bool use_chanctx) | 2107 | const struct ieee80211_regdomain *regd; |
2108 | bool reg_strict; | ||
2109 | bool p2p_device; | ||
2110 | bool use_chanctx; | ||
2111 | bool destroy_on_close; | ||
2112 | const char *hwname; | ||
2113 | bool no_vif; | ||
2114 | }; | ||
2115 | |||
2116 | static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, | ||
2117 | struct genl_info *info) | ||
2118 | { | ||
2119 | if (info) | ||
2120 | genl_notify(&hwsim_genl_family, mcast_skb, | ||
2121 | genl_info_net(info), info->snd_portid, | ||
2122 | HWSIM_MCGRP_CONFIG, info->nlhdr, GFP_KERNEL); | ||
2123 | else | ||
2124 | genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0, | ||
2125 | HWSIM_MCGRP_CONFIG, GFP_KERNEL); | ||
2126 | } | ||
2127 | |||
2128 | static int append_radio_msg(struct sk_buff *skb, int id, | ||
2129 | struct hwsim_new_radio_params *param) | ||
2130 | { | ||
2131 | int ret; | ||
2132 | |||
2133 | ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); | ||
2134 | if (ret < 0) | ||
2135 | return ret; | ||
2136 | |||
2137 | if (param->channels) { | ||
2138 | ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels); | ||
2139 | if (ret < 0) | ||
2140 | return ret; | ||
2141 | } | ||
2142 | |||
2143 | if (param->reg_alpha2) { | ||
2144 | ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2, | ||
2145 | param->reg_alpha2); | ||
2146 | if (ret < 0) | ||
2147 | return ret; | ||
2148 | } | ||
2149 | |||
2150 | if (param->regd) { | ||
2151 | int i; | ||
2152 | |||
2153 | for (i = 0; hwsim_world_regdom_custom[i] != param->regd && | ||
2154 | i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) | ||
2155 | ; | ||
2156 | |||
2157 | if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) { | ||
2158 | ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i); | ||
2159 | if (ret < 0) | ||
2160 | return ret; | ||
2161 | } | ||
2162 | } | ||
2163 | |||
2164 | if (param->reg_strict) { | ||
2165 | ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG); | ||
2166 | if (ret < 0) | ||
2167 | return ret; | ||
2168 | } | ||
2169 | |||
2170 | if (param->p2p_device) { | ||
2171 | ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE); | ||
2172 | if (ret < 0) | ||
2173 | return ret; | ||
2174 | } | ||
2175 | |||
2176 | if (param->use_chanctx) { | ||
2177 | ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX); | ||
2178 | if (ret < 0) | ||
2179 | return ret; | ||
2180 | } | ||
2181 | |||
2182 | if (param->hwname) { | ||
2183 | ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, | ||
2184 | strlen(param->hwname), param->hwname); | ||
2185 | if (ret < 0) | ||
2186 | return ret; | ||
2187 | } | ||
2188 | |||
2189 | return 0; | ||
2190 | } | ||
2191 | |||
2192 | static void hwsim_mcast_new_radio(int id, struct genl_info *info, | ||
2193 | struct hwsim_new_radio_params *param) | ||
2194 | { | ||
2195 | struct sk_buff *mcast_skb; | ||
2196 | void *data; | ||
2197 | |||
2198 | mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2199 | if (!mcast_skb) | ||
2200 | return; | ||
2201 | |||
2202 | data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0, | ||
2203 | HWSIM_CMD_NEW_RADIO); | ||
2204 | if (!data) | ||
2205 | goto out_err; | ||
2206 | |||
2207 | if (append_radio_msg(mcast_skb, id, param) < 0) | ||
2208 | goto out_err; | ||
2209 | |||
2210 | genlmsg_end(mcast_skb, data); | ||
2211 | |||
2212 | hwsim_mcast_config_msg(mcast_skb, info); | ||
2213 | return; | ||
2214 | |||
2215 | out_err: | ||
2216 | genlmsg_cancel(mcast_skb, data); | ||
2217 | nlmsg_free(mcast_skb); | ||
2218 | } | ||
2219 | |||
2220 | static int mac80211_hwsim_new_radio(struct genl_info *info, | ||
2221 | struct hwsim_new_radio_params *param) | ||
1950 | { | 2222 | { |
1951 | int err; | 2223 | int err; |
1952 | u8 addr[ETH_ALEN]; | 2224 | u8 addr[ETH_ALEN]; |
@@ -1956,16 +2228,16 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
1956 | const struct ieee80211_ops *ops = &mac80211_hwsim_ops; | 2228 | const struct ieee80211_ops *ops = &mac80211_hwsim_ops; |
1957 | int idx; | 2229 | int idx; |
1958 | 2230 | ||
1959 | if (WARN_ON(channels > 1 && !use_chanctx)) | 2231 | if (WARN_ON(param->channels > 1 && !param->use_chanctx)) |
1960 | return -EINVAL; | 2232 | return -EINVAL; |
1961 | 2233 | ||
1962 | spin_lock_bh(&hwsim_radio_lock); | 2234 | spin_lock_bh(&hwsim_radio_lock); |
1963 | idx = hwsim_radio_idx++; | 2235 | idx = hwsim_radio_idx++; |
1964 | spin_unlock_bh(&hwsim_radio_lock); | 2236 | spin_unlock_bh(&hwsim_radio_lock); |
1965 | 2237 | ||
1966 | if (use_chanctx) | 2238 | if (param->use_chanctx) |
1967 | ops = &mac80211_hwsim_mchan_ops; | 2239 | ops = &mac80211_hwsim_mchan_ops; |
1968 | hw = ieee80211_alloc_hw(sizeof(*data), ops); | 2240 | hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname); |
1969 | if (!hw) { | 2241 | if (!hw) { |
1970 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n"); | 2242 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n"); |
1971 | err = -ENOMEM; | 2243 | err = -ENOMEM; |
@@ -1987,7 +2259,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
1987 | if (err != 0) { | 2259 | if (err != 0) { |
1988 | printk(KERN_DEBUG "mac80211_hwsim: device_bind_driver failed (%d)\n", | 2260 | printk(KERN_DEBUG "mac80211_hwsim: device_bind_driver failed (%d)\n", |
1989 | err); | 2261 | err); |
1990 | goto failed_hw; | 2262 | goto failed_bind; |
1991 | } | 2263 | } |
1992 | 2264 | ||
1993 | skb_queue_head_init(&data->pending); | 2265 | skb_queue_head_init(&data->pending); |
@@ -2003,9 +2275,12 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
2003 | hw->wiphy->n_addresses = 2; | 2275 | hw->wiphy->n_addresses = 2; |
2004 | hw->wiphy->addresses = data->addresses; | 2276 | hw->wiphy->addresses = data->addresses; |
2005 | 2277 | ||
2006 | data->channels = channels; | 2278 | data->channels = param->channels; |
2007 | data->use_chanctx = use_chanctx; | 2279 | data->use_chanctx = param->use_chanctx; |
2008 | data->idx = idx; | 2280 | data->idx = idx; |
2281 | data->destroy_on_close = param->destroy_on_close; | ||
2282 | if (info) | ||
2283 | data->portid = info->snd_portid; | ||
2009 | 2284 | ||
2010 | if (data->use_chanctx) { | 2285 | if (data->use_chanctx) { |
2011 | hw->wiphy->max_scan_ssids = 255; | 2286 | hw->wiphy->max_scan_ssids = 255; |
@@ -2014,12 +2289,12 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
2014 | /* For channels > 1 DFS is not allowed */ | 2289 | /* For channels > 1 DFS is not allowed */ |
2015 | hw->wiphy->n_iface_combinations = 1; | 2290 | hw->wiphy->n_iface_combinations = 1; |
2016 | hw->wiphy->iface_combinations = &data->if_combination; | 2291 | hw->wiphy->iface_combinations = &data->if_combination; |
2017 | if (p2p_device) | 2292 | if (param->p2p_device) |
2018 | data->if_combination = hwsim_if_comb_p2p_dev[0]; | 2293 | data->if_combination = hwsim_if_comb_p2p_dev[0]; |
2019 | else | 2294 | else |
2020 | data->if_combination = hwsim_if_comb[0]; | 2295 | data->if_combination = hwsim_if_comb[0]; |
2021 | data->if_combination.num_different_channels = data->channels; | 2296 | data->if_combination.num_different_channels = data->channels; |
2022 | } else if (p2p_device) { | 2297 | } else if (param->p2p_device) { |
2023 | hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev; | 2298 | hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev; |
2024 | hw->wiphy->n_iface_combinations = | 2299 | hw->wiphy->n_iface_combinations = |
2025 | ARRAY_SIZE(hwsim_if_comb_p2p_dev); | 2300 | ARRAY_SIZE(hwsim_if_comb_p2p_dev); |
@@ -2040,7 +2315,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
2040 | BIT(NL80211_IFTYPE_ADHOC) | | 2315 | BIT(NL80211_IFTYPE_ADHOC) | |
2041 | BIT(NL80211_IFTYPE_MESH_POINT); | 2316 | BIT(NL80211_IFTYPE_MESH_POINT); |
2042 | 2317 | ||
2043 | if (p2p_device) | 2318 | if (param->p2p_device) |
2044 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE); | 2319 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE); |
2045 | 2320 | ||
2046 | hw->flags = IEEE80211_HW_MFP_CAPABLE | | 2321 | hw->flags = IEEE80211_HW_MFP_CAPABLE | |
@@ -2060,7 +2335,8 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
2060 | hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | | 2335 | hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | |
2061 | NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | | 2336 | NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | |
2062 | NL80211_FEATURE_STATIC_SMPS | | 2337 | NL80211_FEATURE_STATIC_SMPS | |
2063 | NL80211_FEATURE_DYNAMIC_SMPS; | 2338 | NL80211_FEATURE_DYNAMIC_SMPS | |
2339 | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; | ||
2064 | 2340 | ||
2065 | /* ask mac80211 to reserve space for magic */ | 2341 | /* ask mac80211 to reserve space for magic */ |
2066 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); | 2342 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); |
@@ -2095,6 +2371,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
2095 | sband->ht_cap.ht_supported = true; | 2371 | sband->ht_cap.ht_supported = true; |
2096 | sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 2372 | sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
2097 | IEEE80211_HT_CAP_GRN_FLD | | 2373 | IEEE80211_HT_CAP_GRN_FLD | |
2374 | IEEE80211_HT_CAP_SGI_20 | | ||
2098 | IEEE80211_HT_CAP_SGI_40 | | 2375 | IEEE80211_HT_CAP_SGI_40 | |
2099 | IEEE80211_HT_CAP_DSSSCCK40; | 2376 | IEEE80211_HT_CAP_DSSSCCK40; |
2100 | sband->ht_cap.ampdu_factor = 0x3; | 2377 | sband->ht_cap.ampdu_factor = 0x3; |
@@ -2111,7 +2388,6 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
2111 | sband->vht_cap.cap = | 2388 | sband->vht_cap.cap = |
2112 | IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | | 2389 | IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | |
2113 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | | 2390 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | |
2114 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | | ||
2115 | IEEE80211_VHT_CAP_RXLDPC | | 2391 | IEEE80211_VHT_CAP_RXLDPC | |
2116 | IEEE80211_VHT_CAP_SHORT_GI_80 | | 2392 | IEEE80211_VHT_CAP_SHORT_GI_80 | |
2117 | IEEE80211_VHT_CAP_SHORT_GI_160 | | 2393 | IEEE80211_VHT_CAP_SHORT_GI_160 | |
@@ -2142,15 +2418,19 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
2142 | hw->max_rates = 4; | 2418 | hw->max_rates = 4; |
2143 | hw->max_rate_tries = 11; | 2419 | hw->max_rate_tries = 11; |
2144 | 2420 | ||
2145 | if (reg_strict) | 2421 | if (param->reg_strict) |
2146 | hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; | 2422 | hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; |
2147 | if (regd) { | 2423 | if (param->regd) { |
2424 | data->regd = param->regd; | ||
2148 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; | 2425 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; |
2149 | wiphy_apply_custom_regulatory(hw->wiphy, regd); | 2426 | wiphy_apply_custom_regulatory(hw->wiphy, param->regd); |
2150 | /* give the regulatory workqueue a chance to run */ | 2427 | /* give the regulatory workqueue a chance to run */ |
2151 | schedule_timeout_interruptible(1); | 2428 | schedule_timeout_interruptible(1); |
2152 | } | 2429 | } |
2153 | 2430 | ||
2431 | if (param->no_vif) | ||
2432 | hw->flags |= IEEE80211_HW_NO_AUTO_VIF; | ||
2433 | |||
2154 | err = ieee80211_register_hw(hw); | 2434 | err = ieee80211_register_hw(hw); |
2155 | if (err < 0) { | 2435 | if (err < 0) { |
2156 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", | 2436 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", |
@@ -2160,8 +2440,11 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
2160 | 2440 | ||
2161 | wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); | 2441 | wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); |
2162 | 2442 | ||
2163 | if (reg_alpha2) | 2443 | if (param->reg_alpha2) { |
2164 | regulatory_hint(hw->wiphy, reg_alpha2); | 2444 | data->alpha2[0] = param->reg_alpha2[0]; |
2445 | data->alpha2[1] = param->reg_alpha2[1]; | ||
2446 | regulatory_hint(hw->wiphy, param->reg_alpha2); | ||
2447 | } | ||
2165 | 2448 | ||
2166 | data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); | 2449 | data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); |
2167 | debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); | 2450 | debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); |
@@ -2180,9 +2463,14 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, | |||
2180 | list_add_tail(&data->list, &hwsim_radios); | 2463 | list_add_tail(&data->list, &hwsim_radios); |
2181 | spin_unlock_bh(&hwsim_radio_lock); | 2464 | spin_unlock_bh(&hwsim_radio_lock); |
2182 | 2465 | ||
2466 | if (idx > 0) | ||
2467 | hwsim_mcast_new_radio(idx, info, param); | ||
2468 | |||
2183 | return idx; | 2469 | return idx; |
2184 | 2470 | ||
2185 | failed_hw: | 2471 | failed_hw: |
2472 | device_release_driver(data->dev); | ||
2473 | failed_bind: | ||
2186 | device_unregister(data->dev); | 2474 | device_unregister(data->dev); |
2187 | failed_drvdata: | 2475 | failed_drvdata: |
2188 | ieee80211_free_hw(hw); | 2476 | ieee80211_free_hw(hw); |
@@ -2190,8 +2478,46 @@ failed: | |||
2190 | return err; | 2478 | return err; |
2191 | } | 2479 | } |
2192 | 2480 | ||
2193 | static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data) | 2481 | static void hwsim_mcast_del_radio(int id, const char *hwname, |
2482 | struct genl_info *info) | ||
2194 | { | 2483 | { |
2484 | struct sk_buff *skb; | ||
2485 | void *data; | ||
2486 | int ret; | ||
2487 | |||
2488 | skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2489 | if (!skb) | ||
2490 | return; | ||
2491 | |||
2492 | data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, | ||
2493 | HWSIM_CMD_DEL_RADIO); | ||
2494 | if (!data) | ||
2495 | goto error; | ||
2496 | |||
2497 | ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); | ||
2498 | if (ret < 0) | ||
2499 | goto error; | ||
2500 | |||
2501 | ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname), | ||
2502 | hwname); | ||
2503 | if (ret < 0) | ||
2504 | goto error; | ||
2505 | |||
2506 | genlmsg_end(skb, data); | ||
2507 | |||
2508 | hwsim_mcast_config_msg(skb, info); | ||
2509 | |||
2510 | return; | ||
2511 | |||
2512 | error: | ||
2513 | nlmsg_free(skb); | ||
2514 | } | ||
2515 | |||
2516 | static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data, | ||
2517 | const char *hwname, | ||
2518 | struct genl_info *info) | ||
2519 | { | ||
2520 | hwsim_mcast_del_radio(data->idx, hwname, info); | ||
2195 | debugfs_remove_recursive(data->debugfs); | 2521 | debugfs_remove_recursive(data->debugfs); |
2196 | ieee80211_unregister_hw(data->hw); | 2522 | ieee80211_unregister_hw(data->hw); |
2197 | device_release_driver(data->dev); | 2523 | device_release_driver(data->dev); |
@@ -2199,6 +2525,46 @@ static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data) | |||
2199 | ieee80211_free_hw(data->hw); | 2525 | ieee80211_free_hw(data->hw); |
2200 | } | 2526 | } |
2201 | 2527 | ||
2528 | static int mac80211_hwsim_get_radio(struct sk_buff *skb, | ||
2529 | struct mac80211_hwsim_data *data, | ||
2530 | u32 portid, u32 seq, | ||
2531 | struct netlink_callback *cb, int flags) | ||
2532 | { | ||
2533 | void *hdr; | ||
2534 | struct hwsim_new_radio_params param = { }; | ||
2535 | int res = -EMSGSIZE; | ||
2536 | |||
2537 | hdr = genlmsg_put(skb, portid, seq, &hwsim_genl_family, flags, | ||
2538 | HWSIM_CMD_GET_RADIO); | ||
2539 | if (!hdr) | ||
2540 | return -EMSGSIZE; | ||
2541 | |||
2542 | if (cb) | ||
2543 | genl_dump_check_consistent(cb, hdr, &hwsim_genl_family); | ||
2544 | |||
2545 | if (data->alpha2[0] && data->alpha2[1]) | ||
2546 | param.reg_alpha2 = data->alpha2; | ||
2547 | |||
2548 | param.reg_strict = !!(data->hw->wiphy->regulatory_flags & | ||
2549 | REGULATORY_STRICT_REG); | ||
2550 | param.p2p_device = !!(data->hw->wiphy->interface_modes & | ||
2551 | BIT(NL80211_IFTYPE_P2P_DEVICE)); | ||
2552 | param.use_chanctx = data->use_chanctx; | ||
2553 | param.regd = data->regd; | ||
2554 | param.channels = data->channels; | ||
2555 | param.hwname = wiphy_name(data->hw->wiphy); | ||
2556 | |||
2557 | res = append_radio_msg(skb, data->idx, ¶m); | ||
2558 | if (res < 0) | ||
2559 | goto out_err; | ||
2560 | |||
2561 | return genlmsg_end(skb, hdr); | ||
2562 | |||
2563 | out_err: | ||
2564 | genlmsg_cancel(skb, hdr); | ||
2565 | return res; | ||
2566 | } | ||
2567 | |||
2202 | static void mac80211_hwsim_free(void) | 2568 | static void mac80211_hwsim_free(void) |
2203 | { | 2569 | { |
2204 | struct mac80211_hwsim_data *data; | 2570 | struct mac80211_hwsim_data *data; |
@@ -2209,7 +2575,8 @@ static void mac80211_hwsim_free(void) | |||
2209 | list))) { | 2575 | list))) { |
2210 | list_del(&data->list); | 2576 | list_del(&data->list); |
2211 | spin_unlock_bh(&hwsim_radio_lock); | 2577 | spin_unlock_bh(&hwsim_radio_lock); |
2212 | mac80211_hwsim_destroy_radio(data); | 2578 | mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), |
2579 | NULL); | ||
2213 | spin_lock_bh(&hwsim_radio_lock); | 2580 | spin_lock_bh(&hwsim_radio_lock); |
2214 | } | 2581 | } |
2215 | spin_unlock_bh(&hwsim_radio_lock); | 2582 | spin_unlock_bh(&hwsim_radio_lock); |
@@ -2337,7 +2704,6 @@ out: | |||
2337 | static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, | 2704 | static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, |
2338 | struct genl_info *info) | 2705 | struct genl_info *info) |
2339 | { | 2706 | { |
2340 | |||
2341 | struct mac80211_hwsim_data *data2; | 2707 | struct mac80211_hwsim_data *data2; |
2342 | struct ieee80211_rx_status rx_status; | 2708 | struct ieee80211_rx_status rx_status; |
2343 | const u8 *dst; | 2709 | const u8 *dst; |
@@ -2380,18 +2746,22 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, | |||
2380 | 2746 | ||
2381 | /* A frame is received from user space */ | 2747 | /* A frame is received from user space */ |
2382 | memset(&rx_status, 0, sizeof(rx_status)); | 2748 | memset(&rx_status, 0, sizeof(rx_status)); |
2749 | /* TODO: Check ATTR_FREQ if it exists, and maybe throw away off-channel | ||
2750 | * packets? | ||
2751 | */ | ||
2383 | rx_status.freq = data2->channel->center_freq; | 2752 | rx_status.freq = data2->channel->center_freq; |
2384 | rx_status.band = data2->channel->band; | 2753 | rx_status.band = data2->channel->band; |
2385 | rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); | 2754 | rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); |
2386 | rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); | 2755 | rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); |
2387 | 2756 | ||
2388 | memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); | 2757 | memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); |
2758 | data2->rx_pkts++; | ||
2759 | data2->rx_bytes += skb->len; | ||
2389 | ieee80211_rx_irqsafe(data2->hw, skb); | 2760 | ieee80211_rx_irqsafe(data2->hw, skb); |
2390 | 2761 | ||
2391 | return 0; | 2762 | return 0; |
2392 | err: | 2763 | err: |
2393 | printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); | 2764 | printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); |
2394 | goto out; | ||
2395 | out: | 2765 | out: |
2396 | dev_kfree_skb(skb); | 2766 | dev_kfree_skb(skb); |
2397 | return -EINVAL; | 2767 | return -EINVAL; |
@@ -2427,54 +2797,72 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2, | |||
2427 | return 0; | 2797 | return 0; |
2428 | } | 2798 | } |
2429 | 2799 | ||
2430 | static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info) | 2800 | static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) |
2431 | { | 2801 | { |
2432 | unsigned int chans = channels; | 2802 | struct hwsim_new_radio_params param = { 0 }; |
2433 | const char *alpha2 = NULL; | 2803 | |
2434 | const struct ieee80211_regdomain *regd = NULL; | 2804 | param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; |
2435 | bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; | 2805 | param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; |
2436 | bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; | 2806 | param.channels = channels; |
2437 | bool use_chanctx; | 2807 | param.destroy_on_close = |
2808 | info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE]; | ||
2438 | 2809 | ||
2439 | if (info->attrs[HWSIM_ATTR_CHANNELS]) | 2810 | if (info->attrs[HWSIM_ATTR_CHANNELS]) |
2440 | chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); | 2811 | param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); |
2812 | |||
2813 | if (info->attrs[HWSIM_ATTR_NO_VIF]) | ||
2814 | param.no_vif = true; | ||
2815 | |||
2816 | if (info->attrs[HWSIM_ATTR_RADIO_NAME]) | ||
2817 | param.hwname = nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]); | ||
2441 | 2818 | ||
2442 | if (info->attrs[HWSIM_ATTR_USE_CHANCTX]) | 2819 | if (info->attrs[HWSIM_ATTR_USE_CHANCTX]) |
2443 | use_chanctx = true; | 2820 | param.use_chanctx = true; |
2444 | else | 2821 | else |
2445 | use_chanctx = (chans > 1); | 2822 | param.use_chanctx = (param.channels > 1); |
2446 | 2823 | ||
2447 | if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) | 2824 | if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) |
2448 | alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); | 2825 | param.reg_alpha2 = |
2826 | nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); | ||
2449 | 2827 | ||
2450 | if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { | 2828 | if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { |
2451 | u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); | 2829 | u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); |
2452 | 2830 | ||
2453 | if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) | 2831 | if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) |
2454 | return -EINVAL; | 2832 | return -EINVAL; |
2455 | regd = hwsim_world_regdom_custom[idx]; | 2833 | param.regd = hwsim_world_regdom_custom[idx]; |
2456 | } | 2834 | } |
2457 | 2835 | ||
2458 | return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict, | 2836 | return mac80211_hwsim_new_radio(info, ¶m); |
2459 | p2p_device, use_chanctx); | ||
2460 | } | 2837 | } |
2461 | 2838 | ||
2462 | static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info) | 2839 | static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) |
2463 | { | 2840 | { |
2464 | struct mac80211_hwsim_data *data; | 2841 | struct mac80211_hwsim_data *data; |
2465 | int idx; | 2842 | s64 idx = -1; |
2843 | const char *hwname = NULL; | ||
2466 | 2844 | ||
2467 | if (!info->attrs[HWSIM_ATTR_RADIO_ID]) | 2845 | if (info->attrs[HWSIM_ATTR_RADIO_ID]) |
2846 | idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); | ||
2847 | else if (info->attrs[HWSIM_ATTR_RADIO_NAME]) | ||
2848 | hwname = (void *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]); | ||
2849 | else | ||
2468 | return -EINVAL; | 2850 | return -EINVAL; |
2469 | idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); | ||
2470 | 2851 | ||
2471 | spin_lock_bh(&hwsim_radio_lock); | 2852 | spin_lock_bh(&hwsim_radio_lock); |
2472 | list_for_each_entry(data, &hwsim_radios, list) { | 2853 | list_for_each_entry(data, &hwsim_radios, list) { |
2473 | if (data->idx != idx) | 2854 | if (idx >= 0) { |
2474 | continue; | 2855 | if (data->idx != idx) |
2856 | continue; | ||
2857 | } else { | ||
2858 | if (strcmp(hwname, wiphy_name(data->hw->wiphy))) | ||
2859 | continue; | ||
2860 | } | ||
2861 | |||
2475 | list_del(&data->list); | 2862 | list_del(&data->list); |
2476 | spin_unlock_bh(&hwsim_radio_lock); | 2863 | spin_unlock_bh(&hwsim_radio_lock); |
2477 | mac80211_hwsim_destroy_radio(data); | 2864 | mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), |
2865 | info); | ||
2478 | return 0; | 2866 | return 0; |
2479 | } | 2867 | } |
2480 | spin_unlock_bh(&hwsim_radio_lock); | 2868 | spin_unlock_bh(&hwsim_radio_lock); |
@@ -2482,6 +2870,77 @@ static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info) | |||
2482 | return -ENODEV; | 2870 | return -ENODEV; |
2483 | } | 2871 | } |
2484 | 2872 | ||
2873 | static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info) | ||
2874 | { | ||
2875 | struct mac80211_hwsim_data *data; | ||
2876 | struct sk_buff *skb; | ||
2877 | int idx, res = -ENODEV; | ||
2878 | |||
2879 | if (!info->attrs[HWSIM_ATTR_RADIO_ID]) | ||
2880 | return -EINVAL; | ||
2881 | idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); | ||
2882 | |||
2883 | spin_lock_bh(&hwsim_radio_lock); | ||
2884 | list_for_each_entry(data, &hwsim_radios, list) { | ||
2885 | if (data->idx != idx) | ||
2886 | continue; | ||
2887 | |||
2888 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2889 | if (!skb) { | ||
2890 | res = -ENOMEM; | ||
2891 | goto out_err; | ||
2892 | } | ||
2893 | |||
2894 | res = mac80211_hwsim_get_radio(skb, data, info->snd_portid, | ||
2895 | info->snd_seq, NULL, 0); | ||
2896 | if (res < 0) { | ||
2897 | nlmsg_free(skb); | ||
2898 | goto out_err; | ||
2899 | } | ||
2900 | |||
2901 | genlmsg_reply(skb, info); | ||
2902 | break; | ||
2903 | } | ||
2904 | |||
2905 | out_err: | ||
2906 | spin_unlock_bh(&hwsim_radio_lock); | ||
2907 | |||
2908 | return res; | ||
2909 | } | ||
2910 | |||
2911 | static int hwsim_dump_radio_nl(struct sk_buff *skb, | ||
2912 | struct netlink_callback *cb) | ||
2913 | { | ||
2914 | int idx = cb->args[0]; | ||
2915 | struct mac80211_hwsim_data *data = NULL; | ||
2916 | int res; | ||
2917 | |||
2918 | spin_lock_bh(&hwsim_radio_lock); | ||
2919 | |||
2920 | if (idx == hwsim_radio_idx) | ||
2921 | goto done; | ||
2922 | |||
2923 | list_for_each_entry(data, &hwsim_radios, list) { | ||
2924 | if (data->idx < idx) | ||
2925 | continue; | ||
2926 | |||
2927 | res = mac80211_hwsim_get_radio(skb, data, | ||
2928 | NETLINK_CB(cb->skb).portid, | ||
2929 | cb->nlh->nlmsg_seq, cb, | ||
2930 | NLM_F_MULTI); | ||
2931 | if (res < 0) | ||
2932 | break; | ||
2933 | |||
2934 | idx = data->idx + 1; | ||
2935 | } | ||
2936 | |||
2937 | cb->args[0] = idx; | ||
2938 | |||
2939 | done: | ||
2940 | spin_unlock_bh(&hwsim_radio_lock); | ||
2941 | return skb->len; | ||
2942 | } | ||
2943 | |||
2485 | /* Generic Netlink operations array */ | 2944 | /* Generic Netlink operations array */ |
2486 | static const struct genl_ops hwsim_ops[] = { | 2945 | static const struct genl_ops hwsim_ops[] = { |
2487 | { | 2946 | { |
@@ -2501,19 +2960,48 @@ static const struct genl_ops hwsim_ops[] = { | |||
2501 | .doit = hwsim_tx_info_frame_received_nl, | 2960 | .doit = hwsim_tx_info_frame_received_nl, |
2502 | }, | 2961 | }, |
2503 | { | 2962 | { |
2504 | .cmd = HWSIM_CMD_CREATE_RADIO, | 2963 | .cmd = HWSIM_CMD_NEW_RADIO, |
2505 | .policy = hwsim_genl_policy, | 2964 | .policy = hwsim_genl_policy, |
2506 | .doit = hwsim_create_radio_nl, | 2965 | .doit = hwsim_new_radio_nl, |
2507 | .flags = GENL_ADMIN_PERM, | 2966 | .flags = GENL_ADMIN_PERM, |
2508 | }, | 2967 | }, |
2509 | { | 2968 | { |
2510 | .cmd = HWSIM_CMD_DESTROY_RADIO, | 2969 | .cmd = HWSIM_CMD_DEL_RADIO, |
2511 | .policy = hwsim_genl_policy, | 2970 | .policy = hwsim_genl_policy, |
2512 | .doit = hwsim_destroy_radio_nl, | 2971 | .doit = hwsim_del_radio_nl, |
2513 | .flags = GENL_ADMIN_PERM, | 2972 | .flags = GENL_ADMIN_PERM, |
2514 | }, | 2973 | }, |
2974 | { | ||
2975 | .cmd = HWSIM_CMD_GET_RADIO, | ||
2976 | .policy = hwsim_genl_policy, | ||
2977 | .doit = hwsim_get_radio_nl, | ||
2978 | .dumpit = hwsim_dump_radio_nl, | ||
2979 | }, | ||
2515 | }; | 2980 | }; |
2516 | 2981 | ||
2982 | static void destroy_radio(struct work_struct *work) | ||
2983 | { | ||
2984 | struct mac80211_hwsim_data *data = | ||
2985 | container_of(work, struct mac80211_hwsim_data, destroy_work); | ||
2986 | |||
2987 | mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), NULL); | ||
2988 | } | ||
2989 | |||
2990 | static void remove_user_radios(u32 portid) | ||
2991 | { | ||
2992 | struct mac80211_hwsim_data *entry, *tmp; | ||
2993 | |||
2994 | spin_lock_bh(&hwsim_radio_lock); | ||
2995 | list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) { | ||
2996 | if (entry->destroy_on_close && entry->portid == portid) { | ||
2997 | list_del(&entry->list); | ||
2998 | INIT_WORK(&entry->destroy_work, destroy_radio); | ||
2999 | schedule_work(&entry->destroy_work); | ||
3000 | } | ||
3001 | } | ||
3002 | spin_unlock_bh(&hwsim_radio_lock); | ||
3003 | } | ||
3004 | |||
2517 | static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, | 3005 | static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, |
2518 | unsigned long state, | 3006 | unsigned long state, |
2519 | void *_notify) | 3007 | void *_notify) |
@@ -2523,6 +3011,8 @@ static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, | |||
2523 | if (state != NETLINK_URELEASE) | 3011 | if (state != NETLINK_URELEASE) |
2524 | return NOTIFY_DONE; | 3012 | return NOTIFY_DONE; |
2525 | 3013 | ||
3014 | remove_user_radios(notify->portid); | ||
3015 | |||
2526 | if (notify->portid == wmediumd_portid) { | 3016 | if (notify->portid == wmediumd_portid) { |
2527 | printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" | 3017 | printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" |
2528 | " socket, switching to perfect channel medium\n"); | 3018 | " socket, switching to perfect channel medium\n"); |
@@ -2542,7 +3032,9 @@ static int hwsim_init_netlink(void) | |||
2542 | 3032 | ||
2543 | printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); | 3033 | printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); |
2544 | 3034 | ||
2545 | rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops); | 3035 | rc = genl_register_family_with_ops_groups(&hwsim_genl_family, |
3036 | hwsim_ops, | ||
3037 | hwsim_mcgrps); | ||
2546 | if (rc) | 3038 | if (rc) |
2547 | goto failure; | 3039 | goto failure; |
2548 | 3040 | ||
@@ -2603,69 +3095,73 @@ static int __init init_mac80211_hwsim(void) | |||
2603 | goto out_unregister_driver; | 3095 | goto out_unregister_driver; |
2604 | } | 3096 | } |
2605 | 3097 | ||
3098 | err = hwsim_init_netlink(); | ||
3099 | if (err < 0) | ||
3100 | goto out_unregister_driver; | ||
3101 | |||
2606 | for (i = 0; i < radios; i++) { | 3102 | for (i = 0; i < radios; i++) { |
2607 | const char *reg_alpha2 = NULL; | 3103 | struct hwsim_new_radio_params param = { 0 }; |
2608 | const struct ieee80211_regdomain *regd = NULL; | 3104 | |
2609 | bool reg_strict = false; | 3105 | param.channels = channels; |
2610 | 3106 | ||
2611 | switch (regtest) { | 3107 | switch (regtest) { |
2612 | case HWSIM_REGTEST_DIFF_COUNTRY: | 3108 | case HWSIM_REGTEST_DIFF_COUNTRY: |
2613 | if (i < ARRAY_SIZE(hwsim_alpha2s)) | 3109 | if (i < ARRAY_SIZE(hwsim_alpha2s)) |
2614 | reg_alpha2 = hwsim_alpha2s[i]; | 3110 | param.reg_alpha2 = hwsim_alpha2s[i]; |
2615 | break; | 3111 | break; |
2616 | case HWSIM_REGTEST_DRIVER_REG_FOLLOW: | 3112 | case HWSIM_REGTEST_DRIVER_REG_FOLLOW: |
2617 | if (!i) | 3113 | if (!i) |
2618 | reg_alpha2 = hwsim_alpha2s[0]; | 3114 | param.reg_alpha2 = hwsim_alpha2s[0]; |
2619 | break; | 3115 | break; |
2620 | case HWSIM_REGTEST_STRICT_ALL: | 3116 | case HWSIM_REGTEST_STRICT_ALL: |
2621 | reg_strict = true; | 3117 | param.reg_strict = true; |
2622 | case HWSIM_REGTEST_DRIVER_REG_ALL: | 3118 | case HWSIM_REGTEST_DRIVER_REG_ALL: |
2623 | reg_alpha2 = hwsim_alpha2s[0]; | 3119 | param.reg_alpha2 = hwsim_alpha2s[0]; |
2624 | break; | 3120 | break; |
2625 | case HWSIM_REGTEST_WORLD_ROAM: | 3121 | case HWSIM_REGTEST_WORLD_ROAM: |
2626 | if (i == 0) | 3122 | if (i == 0) |
2627 | regd = &hwsim_world_regdom_custom_01; | 3123 | param.regd = &hwsim_world_regdom_custom_01; |
2628 | break; | 3124 | break; |
2629 | case HWSIM_REGTEST_CUSTOM_WORLD: | 3125 | case HWSIM_REGTEST_CUSTOM_WORLD: |
2630 | regd = &hwsim_world_regdom_custom_01; | 3126 | param.regd = &hwsim_world_regdom_custom_01; |
2631 | break; | 3127 | break; |
2632 | case HWSIM_REGTEST_CUSTOM_WORLD_2: | 3128 | case HWSIM_REGTEST_CUSTOM_WORLD_2: |
2633 | if (i == 0) | 3129 | if (i == 0) |
2634 | regd = &hwsim_world_regdom_custom_01; | 3130 | param.regd = &hwsim_world_regdom_custom_01; |
2635 | else if (i == 1) | 3131 | else if (i == 1) |
2636 | regd = &hwsim_world_regdom_custom_02; | 3132 | param.regd = &hwsim_world_regdom_custom_02; |
2637 | break; | 3133 | break; |
2638 | case HWSIM_REGTEST_STRICT_FOLLOW: | 3134 | case HWSIM_REGTEST_STRICT_FOLLOW: |
2639 | if (i == 0) { | 3135 | if (i == 0) { |
2640 | reg_strict = true; | 3136 | param.reg_strict = true; |
2641 | reg_alpha2 = hwsim_alpha2s[0]; | 3137 | param.reg_alpha2 = hwsim_alpha2s[0]; |
2642 | } | 3138 | } |
2643 | break; | 3139 | break; |
2644 | case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: | 3140 | case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: |
2645 | if (i == 0) { | 3141 | if (i == 0) { |
2646 | reg_strict = true; | 3142 | param.reg_strict = true; |
2647 | reg_alpha2 = hwsim_alpha2s[0]; | 3143 | param.reg_alpha2 = hwsim_alpha2s[0]; |
2648 | } else if (i == 1) { | 3144 | } else if (i == 1) { |
2649 | reg_alpha2 = hwsim_alpha2s[1]; | 3145 | param.reg_alpha2 = hwsim_alpha2s[1]; |
2650 | } | 3146 | } |
2651 | break; | 3147 | break; |
2652 | case HWSIM_REGTEST_ALL: | 3148 | case HWSIM_REGTEST_ALL: |
2653 | switch (i) { | 3149 | switch (i) { |
2654 | case 0: | 3150 | case 0: |
2655 | regd = &hwsim_world_regdom_custom_01; | 3151 | param.regd = &hwsim_world_regdom_custom_01; |
2656 | break; | 3152 | break; |
2657 | case 1: | 3153 | case 1: |
2658 | regd = &hwsim_world_regdom_custom_02; | 3154 | param.regd = &hwsim_world_regdom_custom_02; |
2659 | break; | 3155 | break; |
2660 | case 2: | 3156 | case 2: |
2661 | reg_alpha2 = hwsim_alpha2s[0]; | 3157 | param.reg_alpha2 = hwsim_alpha2s[0]; |
2662 | break; | 3158 | break; |
2663 | case 3: | 3159 | case 3: |
2664 | reg_alpha2 = hwsim_alpha2s[1]; | 3160 | param.reg_alpha2 = hwsim_alpha2s[1]; |
2665 | break; | 3161 | break; |
2666 | case 4: | 3162 | case 4: |
2667 | reg_strict = true; | 3163 | param.reg_strict = true; |
2668 | reg_alpha2 = hwsim_alpha2s[2]; | 3164 | param.reg_alpha2 = hwsim_alpha2s[2]; |
2669 | break; | 3165 | break; |
2670 | } | 3166 | } |
2671 | break; | 3167 | break; |
@@ -2673,10 +3169,10 @@ static int __init init_mac80211_hwsim(void) | |||
2673 | break; | 3169 | break; |
2674 | } | 3170 | } |
2675 | 3171 | ||
2676 | err = mac80211_hwsim_create_radio(channels, reg_alpha2, | 3172 | param.p2p_device = support_p2p_device; |
2677 | regd, reg_strict, | 3173 | param.use_chanctx = channels > 1; |
2678 | support_p2p_device, | 3174 | |
2679 | channels > 1); | 3175 | err = mac80211_hwsim_new_radio(NULL, ¶m); |
2680 | if (err < 0) | 3176 | if (err < 0) |
2681 | goto out_free_radios; | 3177 | goto out_free_radios; |
2682 | } | 3178 | } |
@@ -2702,10 +3198,6 @@ static int __init init_mac80211_hwsim(void) | |||
2702 | } | 3198 | } |
2703 | rtnl_unlock(); | 3199 | rtnl_unlock(); |
2704 | 3200 | ||
2705 | err = hwsim_init_netlink(); | ||
2706 | if (err < 0) | ||
2707 | goto out_free_mon; | ||
2708 | |||
2709 | return 0; | 3201 | return 0; |
2710 | 3202 | ||
2711 | out_free_mon: | 3203 | out_free_mon: |
diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index c9d0315575ba..66e1c73bd507 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h | |||
@@ -60,14 +60,17 @@ enum hwsim_tx_control_flags { | |||
60 | * space, uses: | 60 | * space, uses: |
61 | * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER, | 61 | * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER, |
62 | * %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE, | 62 | * %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE, |
63 | * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE | 63 | * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE, %HWSIM_ATTR_FREQ (optional) |
64 | * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to | 64 | * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to |
65 | * kernel, uses: | 65 | * kernel, uses: |
66 | * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS, | 66 | * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS, |
67 | * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE | 67 | * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE |
68 | * @HWSIM_CMD_CREATE_RADIO: create a new radio with the given parameters, | 68 | * @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters, |
69 | * returns the radio ID (>= 0) or negative on errors | 69 | * returns the radio ID (>= 0) or negative on errors, if successful |
70 | * @HWSIM_CMD_DESTROY_RADIO: destroy a radio | 70 | * then multicast the result |
71 | * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted | ||
72 | * @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses: | ||
73 | * %HWSIM_ATTR_RADIO_ID | ||
71 | * @__HWSIM_CMD_MAX: enum limit | 74 | * @__HWSIM_CMD_MAX: enum limit |
72 | */ | 75 | */ |
73 | enum { | 76 | enum { |
@@ -75,12 +78,16 @@ enum { | |||
75 | HWSIM_CMD_REGISTER, | 78 | HWSIM_CMD_REGISTER, |
76 | HWSIM_CMD_FRAME, | 79 | HWSIM_CMD_FRAME, |
77 | HWSIM_CMD_TX_INFO_FRAME, | 80 | HWSIM_CMD_TX_INFO_FRAME, |
78 | HWSIM_CMD_CREATE_RADIO, | 81 | HWSIM_CMD_NEW_RADIO, |
79 | HWSIM_CMD_DESTROY_RADIO, | 82 | HWSIM_CMD_DEL_RADIO, |
83 | HWSIM_CMD_GET_RADIO, | ||
80 | __HWSIM_CMD_MAX, | 84 | __HWSIM_CMD_MAX, |
81 | }; | 85 | }; |
82 | #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) | 86 | #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) |
83 | 87 | ||
88 | #define HWSIM_CMD_CREATE_RADIO HWSIM_CMD_NEW_RADIO | ||
89 | #define HWSIM_CMD_DESTROY_RADIO HWSIM_CMD_DEL_RADIO | ||
90 | |||
84 | /** | 91 | /** |
85 | * enum hwsim_attrs - hwsim netlink attributes | 92 | * enum hwsim_attrs - hwsim netlink attributes |
86 | * | 93 | * |
@@ -111,6 +118,11 @@ enum { | |||
111 | * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO | 118 | * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO |
112 | * command to force use of channel contexts even when only a | 119 | * command to force use of channel contexts even when only a |
113 | * single channel is supported | 120 | * single channel is supported |
121 | * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_CREATE_RADIO | ||
122 | * command to force radio removal when process that created the radio dies | ||
123 | * @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666 | ||
124 | * @HWSIM_ATTR_NO_VIF: Do not create vif (wlanX) when creating radio. | ||
125 | * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received. | ||
114 | * @__HWSIM_ATTR_MAX: enum limit | 126 | * @__HWSIM_ATTR_MAX: enum limit |
115 | */ | 127 | */ |
116 | 128 | ||
@@ -132,6 +144,10 @@ enum { | |||
132 | HWSIM_ATTR_REG_STRICT_REG, | 144 | HWSIM_ATTR_REG_STRICT_REG, |
133 | HWSIM_ATTR_SUPPORT_P2P_DEVICE, | 145 | HWSIM_ATTR_SUPPORT_P2P_DEVICE, |
134 | HWSIM_ATTR_USE_CHANCTX, | 146 | HWSIM_ATTR_USE_CHANCTX, |
147 | HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE, | ||
148 | HWSIM_ATTR_RADIO_NAME, | ||
149 | HWSIM_ATTR_NO_VIF, | ||
150 | HWSIM_ATTR_FREQ, | ||
135 | __HWSIM_ATTR_MAX, | 151 | __HWSIM_ATTR_MAX, |
136 | }; | 152 | }; |
137 | #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) | 153 | #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) |
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 2ee268b632be..f275675cdbd3 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h | |||
@@ -84,6 +84,8 @@ mwifiex_is_amsdu_in_ampdu_allowed(struct mwifiex_private *priv, | |||
84 | { | 84 | { |
85 | struct mwifiex_tx_ba_stream_tbl *tx_tbl; | 85 | struct mwifiex_tx_ba_stream_tbl *tx_tbl; |
86 | 86 | ||
87 | if (is_broadcast_ether_addr(ptr->ra)) | ||
88 | return false; | ||
87 | tx_tbl = mwifiex_get_ba_tbl(priv, tid, ptr->ra); | 89 | tx_tbl = mwifiex_get_ba_tbl(priv, tid, ptr->ra); |
88 | if (tx_tbl) | 90 | if (tx_tbl) |
89 | return tx_tbl->amsdu; | 91 | return tx_tbl->amsdu; |
@@ -96,6 +98,8 @@ static inline u8 | |||
96 | mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, | 98 | mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, |
97 | struct mwifiex_ra_list_tbl *ptr, int tid) | 99 | struct mwifiex_ra_list_tbl *ptr, int tid) |
98 | { | 100 | { |
101 | if (is_broadcast_ether_addr(ptr->ra)) | ||
102 | return false; | ||
99 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { | 103 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { |
100 | return mwifiex_is_station_ampdu_allowed(priv, ptr, tid); | 104 | return mwifiex_is_station_ampdu_allowed(priv, ptr, tid); |
101 | } else { | 105 | } else { |
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 40057079ffb9..5ef5a0eeba50 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c | |||
@@ -196,6 +196,7 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv, | |||
196 | mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win); | 196 | mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win); |
197 | 197 | ||
198 | del_timer_sync(&tbl->timer_context.timer); | 198 | del_timer_sync(&tbl->timer_context.timer); |
199 | tbl->timer_context.timer_is_set = false; | ||
199 | 200 | ||
200 | spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); | 201 | spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); |
201 | list_del(&tbl->list); | 202 | list_del(&tbl->list); |
@@ -297,6 +298,7 @@ mwifiex_flush_data(unsigned long context) | |||
297 | (struct reorder_tmr_cnxt *) context; | 298 | (struct reorder_tmr_cnxt *) context; |
298 | int start_win, seq_num; | 299 | int start_win, seq_num; |
299 | 300 | ||
301 | ctx->timer_is_set = false; | ||
300 | seq_num = mwifiex_11n_find_last_seq_num(ctx); | 302 | seq_num = mwifiex_11n_find_last_seq_num(ctx); |
301 | 303 | ||
302 | if (seq_num < 0) | 304 | if (seq_num < 0) |
@@ -385,6 +387,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, | |||
385 | 387 | ||
386 | new_node->timer_context.ptr = new_node; | 388 | new_node->timer_context.ptr = new_node; |
387 | new_node->timer_context.priv = priv; | 389 | new_node->timer_context.priv = priv; |
390 | new_node->timer_context.timer_is_set = false; | ||
388 | 391 | ||
389 | init_timer(&new_node->timer_context.timer); | 392 | init_timer(&new_node->timer_context.timer); |
390 | new_node->timer_context.timer.function = mwifiex_flush_data; | 393 | new_node->timer_context.timer.function = mwifiex_flush_data; |
@@ -399,6 +402,22 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, | |||
399 | spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); | 402 | spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); |
400 | } | 403 | } |
401 | 404 | ||
405 | static void | ||
406 | mwifiex_11n_rxreorder_timer_restart(struct mwifiex_rx_reorder_tbl *tbl) | ||
407 | { | ||
408 | u32 min_flush_time; | ||
409 | |||
410 | if (tbl->win_size >= MWIFIEX_BA_WIN_SIZE_32) | ||
411 | min_flush_time = MIN_FLUSH_TIMER_15_MS; | ||
412 | else | ||
413 | min_flush_time = MIN_FLUSH_TIMER_MS; | ||
414 | |||
415 | mod_timer(&tbl->timer_context.timer, | ||
416 | jiffies + msecs_to_jiffies(min_flush_time * tbl->win_size)); | ||
417 | |||
418 | tbl->timer_context.timer_is_set = true; | ||
419 | } | ||
420 | |||
402 | /* | 421 | /* |
403 | * This function prepares command for adding a BA request. | 422 | * This function prepares command for adding a BA request. |
404 | * | 423 | * |
@@ -523,31 +542,31 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, | |||
523 | u8 *ta, u8 pkt_type, void *payload) | 542 | u8 *ta, u8 pkt_type, void *payload) |
524 | { | 543 | { |
525 | struct mwifiex_rx_reorder_tbl *tbl; | 544 | struct mwifiex_rx_reorder_tbl *tbl; |
526 | int start_win, end_win, win_size; | 545 | int prev_start_win, start_win, end_win, win_size; |
527 | u16 pkt_index; | 546 | u16 pkt_index; |
528 | bool init_window_shift = false; | 547 | bool init_window_shift = false; |
548 | int ret = 0; | ||
529 | 549 | ||
530 | tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); | 550 | tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); |
531 | if (!tbl) { | 551 | if (!tbl) { |
532 | if (pkt_type != PKT_TYPE_BAR) | 552 | if (pkt_type != PKT_TYPE_BAR) |
533 | mwifiex_11n_dispatch_pkt(priv, payload); | 553 | mwifiex_11n_dispatch_pkt(priv, payload); |
534 | return 0; | 554 | return ret; |
535 | } | 555 | } |
536 | 556 | ||
537 | if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) { | 557 | if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) { |
538 | mwifiex_11n_dispatch_pkt(priv, payload); | 558 | mwifiex_11n_dispatch_pkt(priv, payload); |
539 | return 0; | 559 | return ret; |
540 | } | 560 | } |
541 | 561 | ||
542 | start_win = tbl->start_win; | 562 | start_win = tbl->start_win; |
563 | prev_start_win = start_win; | ||
543 | win_size = tbl->win_size; | 564 | win_size = tbl->win_size; |
544 | end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); | 565 | end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); |
545 | if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) { | 566 | if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) { |
546 | init_window_shift = true; | 567 | init_window_shift = true; |
547 | tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT; | 568 | tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT; |
548 | } | 569 | } |
549 | mod_timer(&tbl->timer_context.timer, | ||
550 | jiffies + msecs_to_jiffies(MIN_FLUSH_TIMER_MS * win_size)); | ||
551 | 570 | ||
552 | if (tbl->flags & RXREOR_FORCE_NO_DROP) { | 571 | if (tbl->flags & RXREOR_FORCE_NO_DROP) { |
553 | dev_dbg(priv->adapter->dev, | 572 | dev_dbg(priv->adapter->dev, |
@@ -568,11 +587,14 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, | |||
568 | if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) { | 587 | if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) { |
569 | if (seq_num >= ((start_win + TWOPOW11) & | 588 | if (seq_num >= ((start_win + TWOPOW11) & |
570 | (MAX_TID_VALUE - 1)) && | 589 | (MAX_TID_VALUE - 1)) && |
571 | seq_num < start_win) | 590 | seq_num < start_win) { |
572 | return -1; | 591 | ret = -1; |
592 | goto done; | ||
593 | } | ||
573 | } else if ((seq_num < start_win) || | 594 | } else if ((seq_num < start_win) || |
574 | (seq_num > (start_win + TWOPOW11))) { | 595 | (seq_num >= (start_win + TWOPOW11))) { |
575 | return -1; | 596 | ret = -1; |
597 | goto done; | ||
576 | } | 598 | } |
577 | } | 599 | } |
578 | 600 | ||
@@ -601,8 +623,10 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, | |||
601 | else | 623 | else |
602 | pkt_index = (seq_num+MAX_TID_VALUE) - start_win; | 624 | pkt_index = (seq_num+MAX_TID_VALUE) - start_win; |
603 | 625 | ||
604 | if (tbl->rx_reorder_ptr[pkt_index]) | 626 | if (tbl->rx_reorder_ptr[pkt_index]) { |
605 | return -1; | 627 | ret = -1; |
628 | goto done; | ||
629 | } | ||
606 | 630 | ||
607 | tbl->rx_reorder_ptr[pkt_index] = payload; | 631 | tbl->rx_reorder_ptr[pkt_index] = payload; |
608 | } | 632 | } |
@@ -613,7 +637,11 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, | |||
613 | */ | 637 | */ |
614 | mwifiex_11n_scan_and_dispatch(priv, tbl); | 638 | mwifiex_11n_scan_and_dispatch(priv, tbl); |
615 | 639 | ||
616 | return 0; | 640 | done: |
641 | if (!tbl->timer_context.timer_is_set || | ||
642 | prev_start_win != tbl->start_win) | ||
643 | mwifiex_11n_rxreorder_timer_restart(tbl); | ||
644 | return ret; | ||
617 | } | 645 | } |
618 | 646 | ||
619 | /* | 647 | /* |
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h index 3a87bb0e3a62..63ecea89b4ab 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.h +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h | |||
@@ -21,6 +21,8 @@ | |||
21 | #define _MWIFIEX_11N_RXREORDER_H_ | 21 | #define _MWIFIEX_11N_RXREORDER_H_ |
22 | 22 | ||
23 | #define MIN_FLUSH_TIMER_MS 50 | 23 | #define MIN_FLUSH_TIMER_MS 50 |
24 | #define MIN_FLUSH_TIMER_15_MS 15 | ||
25 | #define MWIFIEX_BA_WIN_SIZE_32 32 | ||
24 | 26 | ||
25 | #define PKT_TYPE_BAR 0xE7 | 27 | #define PKT_TYPE_BAR 0xE7 |
26 | #define MAX_TID_VALUE (2 << 11) | 28 | #define MAX_TID_VALUE (2 << 11) |
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig index e70d0df9b0da..aa01c9bc77f9 100644 --- a/drivers/net/wireless/mwifiex/Kconfig +++ b/drivers/net/wireless/mwifiex/Kconfig | |||
@@ -31,7 +31,7 @@ config MWIFIEX_PCIE | |||
31 | mwifiex_pcie. | 31 | mwifiex_pcie. |
32 | 32 | ||
33 | config MWIFIEX_USB | 33 | config MWIFIEX_USB |
34 | tristate "Marvell WiFi-Ex Driver for USB8797/8897" | 34 | tristate "Marvell WiFi-Ex Driver for USB8766/8797/8897" |
35 | depends on MWIFIEX && USB | 35 | depends on MWIFIEX && USB |
36 | select FW_LOADER | 36 | select FW_LOADER |
37 | ---help--- | 37 | ---help--- |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b3c763525cc0..f881044e450d 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -194,10 +194,17 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
194 | tx_info->pkt_len = pkt_len; | 194 | tx_info->pkt_len = pkt_len; |
195 | 195 | ||
196 | mwifiex_form_mgmt_frame(skb, buf, len); | 196 | mwifiex_form_mgmt_frame(skb, buf, len); |
197 | mwifiex_queue_tx_pkt(priv, skb); | ||
198 | |||
199 | *cookie = prandom_u32() | 1; | 197 | *cookie = prandom_u32() | 1; |
200 | cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, GFP_ATOMIC); | 198 | |
199 | if (ieee80211_is_action(mgmt->frame_control)) | ||
200 | skb = mwifiex_clone_skb_for_tx_status(priv, | ||
201 | skb, | ||
202 | MWIFIEX_BUF_FLAG_ACTION_TX_STATUS, cookie); | ||
203 | else | ||
204 | cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, | ||
205 | GFP_ATOMIC); | ||
206 | |||
207 | mwifiex_queue_tx_pkt(priv, skb); | ||
201 | 208 | ||
202 | wiphy_dbg(wiphy, "info: management frame transmitted\n"); | 209 | wiphy_dbg(wiphy, "info: management frame transmitted\n"); |
203 | return 0; | 210 | return 0; |
@@ -1285,7 +1292,7 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy, | |||
1285 | */ | 1292 | */ |
1286 | static int | 1293 | static int |
1287 | mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, | 1294 | mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, |
1288 | const u8 *mac) | 1295 | struct station_del_parameters *params) |
1289 | { | 1296 | { |
1290 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | 1297 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
1291 | struct mwifiex_sta_node *sta_node; | 1298 | struct mwifiex_sta_node *sta_node; |
@@ -1294,7 +1301,7 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
1294 | if (list_empty(&priv->sta_list) || !priv->bss_started) | 1301 | if (list_empty(&priv->sta_list) || !priv->bss_started) |
1295 | return 0; | 1302 | return 0; |
1296 | 1303 | ||
1297 | if (!mac || is_broadcast_ether_addr(mac)) { | 1304 | if (!params->mac || is_broadcast_ether_addr(params->mac)) { |
1298 | wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__); | 1305 | wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__); |
1299 | list_for_each_entry(sta_node, &priv->sta_list, list) { | 1306 | list_for_each_entry(sta_node, &priv->sta_list, list) { |
1300 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH, | 1307 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH, |
@@ -1304,9 +1311,10 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
1304 | mwifiex_uap_del_sta_data(priv, sta_node); | 1311 | mwifiex_uap_del_sta_data(priv, sta_node); |
1305 | } | 1312 | } |
1306 | } else { | 1313 | } else { |
1307 | wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, mac); | 1314 | wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, |
1315 | params->mac); | ||
1308 | spin_lock_irqsave(&priv->sta_list_spinlock, flags); | 1316 | spin_lock_irqsave(&priv->sta_list_spinlock, flags); |
1309 | sta_node = mwifiex_get_sta_entry(priv, mac); | 1317 | sta_node = mwifiex_get_sta_entry(priv, params->mac); |
1310 | spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); | 1318 | spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); |
1311 | if (sta_node) { | 1319 | if (sta_node) { |
1312 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH, | 1320 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH, |
@@ -1805,6 +1813,10 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
1805 | dev_dbg(priv->adapter->dev, | 1813 | dev_dbg(priv->adapter->dev, |
1806 | "info: associated to bssid %pM successfully\n", | 1814 | "info: associated to bssid %pM successfully\n", |
1807 | priv->cfg_bssid); | 1815 | priv->cfg_bssid); |
1816 | if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && | ||
1817 | priv->adapter->auto_tdls && | ||
1818 | priv->bss_type == MWIFIEX_BSS_TYPE_STA) | ||
1819 | mwifiex_setup_auto_tdls_timer(priv); | ||
1808 | } else { | 1820 | } else { |
1809 | dev_dbg(priv->adapter->dev, | 1821 | dev_dbg(priv->adapter->dev, |
1810 | "info: association to bssid %pM failed\n", | 1822 | "info: association to bssid %pM failed\n", |
@@ -2676,11 +2688,13 @@ mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
2676 | dev_dbg(priv->adapter->dev, | 2688 | dev_dbg(priv->adapter->dev, |
2677 | "Send TDLS Setup Request to %pM status_code=%d\n", peer, | 2689 | "Send TDLS Setup Request to %pM status_code=%d\n", peer, |
2678 | status_code); | 2690 | status_code); |
2691 | mwifiex_add_auto_tdls_peer(priv, peer); | ||
2679 | ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, | 2692 | ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, |
2680 | dialog_token, status_code, | 2693 | dialog_token, status_code, |
2681 | extra_ies, extra_ies_len); | 2694 | extra_ies, extra_ies_len); |
2682 | break; | 2695 | break; |
2683 | case WLAN_TDLS_SETUP_RESPONSE: | 2696 | case WLAN_TDLS_SETUP_RESPONSE: |
2697 | mwifiex_add_auto_tdls_peer(priv, peer); | ||
2684 | dev_dbg(priv->adapter->dev, | 2698 | dev_dbg(priv->adapter->dev, |
2685 | "Send TDLS Setup Response to %pM status_code=%d\n", | 2699 | "Send TDLS Setup Response to %pM status_code=%d\n", |
2686 | peer, status_code); | 2700 | peer, status_code); |
@@ -2981,6 +2995,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) | |||
2981 | NL80211_FEATURE_INACTIVITY_TIMER | | 2995 | NL80211_FEATURE_INACTIVITY_TIMER | |
2982 | NL80211_FEATURE_NEED_OBSS_SCAN; | 2996 | NL80211_FEATURE_NEED_OBSS_SCAN; |
2983 | 2997 | ||
2998 | if (adapter->fw_api_ver == MWIFIEX_FW_V15) | ||
2999 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; | ||
3000 | |||
2984 | /* Reserve space for mwifiex specific private data for BSS */ | 3001 | /* Reserve space for mwifiex specific private data for BSS */ |
2985 | wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); | 3002 | wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); |
2986 | 3003 | ||
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index f53e5b50d3d8..2269acf41ad8 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h | |||
@@ -76,6 +76,8 @@ | |||
76 | #define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) | 76 | #define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) |
77 | #define MWIFIEX_BUF_FLAG_BRIDGED_PKT BIT(1) | 77 | #define MWIFIEX_BUF_FLAG_BRIDGED_PKT BIT(1) |
78 | #define MWIFIEX_BUF_FLAG_TDLS_PKT BIT(2) | 78 | #define MWIFIEX_BUF_FLAG_TDLS_PKT BIT(2) |
79 | #define MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS BIT(3) | ||
80 | #define MWIFIEX_BUF_FLAG_ACTION_TX_STATUS BIT(4) | ||
79 | 81 | ||
80 | #define MWIFIEX_BRIDGED_PKTS_THR_HIGH 1024 | 82 | #define MWIFIEX_BRIDGED_PKTS_THR_HIGH 1024 |
81 | #define MWIFIEX_BRIDGED_PKTS_THR_LOW 128 | 83 | #define MWIFIEX_BRIDGED_PKTS_THR_LOW 128 |
@@ -85,6 +87,11 @@ | |||
85 | #define MWIFIEX_TDLS_CREATE_LINK 0x02 | 87 | #define MWIFIEX_TDLS_CREATE_LINK 0x02 |
86 | #define MWIFIEX_TDLS_CONFIG_LINK 0x03 | 88 | #define MWIFIEX_TDLS_CONFIG_LINK 0x03 |
87 | 89 | ||
90 | #define MWIFIEX_TDLS_RSSI_HIGH 50 | ||
91 | #define MWIFIEX_TDLS_RSSI_LOW 55 | ||
92 | #define MWIFIEX_TDLS_MAX_FAIL_COUNT 4 | ||
93 | #define MWIFIEX_AUTO_TDLS_IDLE_TIME 10 | ||
94 | |||
88 | enum mwifiex_bss_type { | 95 | enum mwifiex_bss_type { |
89 | MWIFIEX_BSS_TYPE_STA = 0, | 96 | MWIFIEX_BSS_TYPE_STA = 0, |
90 | MWIFIEX_BSS_TYPE_UAP = 1, | 97 | MWIFIEX_BSS_TYPE_UAP = 1, |
@@ -154,6 +161,8 @@ struct mwifiex_txinfo { | |||
154 | u8 bss_num; | 161 | u8 bss_num; |
155 | u8 bss_type; | 162 | u8 bss_type; |
156 | u32 pkt_len; | 163 | u32 pkt_len; |
164 | u8 ack_frame_id; | ||
165 | u64 cookie; | ||
157 | }; | 166 | }; |
158 | 167 | ||
159 | enum mwifiex_wmm_ac_e { | 168 | enum mwifiex_wmm_ac_e { |
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 7f922a882c13..fb5936eb82e3 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h | |||
@@ -494,6 +494,7 @@ enum P2P_MODES { | |||
494 | #define EVENT_TDLS_GENERIC_EVENT 0x00000052 | 494 | #define EVENT_TDLS_GENERIC_EVENT 0x00000052 |
495 | #define EVENT_EXT_SCAN_REPORT 0x00000058 | 495 | #define EVENT_EXT_SCAN_REPORT 0x00000058 |
496 | #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f | 496 | #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f |
497 | #define EVENT_TX_STATUS_REPORT 0x00000074 | ||
497 | 498 | ||
498 | #define EVENT_ID_MASK 0xffff | 499 | #define EVENT_ID_MASK 0xffff |
499 | #define BSS_NUM_MASK 0xf | 500 | #define BSS_NUM_MASK 0xf |
@@ -542,6 +543,7 @@ struct mwifiex_ie_types_data { | |||
542 | #define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08 | 543 | #define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08 |
543 | #define MWIFIEX_TXPD_FLAGS_TDLS_PACKET 0x10 | 544 | #define MWIFIEX_TXPD_FLAGS_TDLS_PACKET 0x10 |
544 | #define MWIFIEX_RXPD_FLAGS_TDLS_PACKET 0x01 | 545 | #define MWIFIEX_RXPD_FLAGS_TDLS_PACKET 0x01 |
546 | #define MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS 0x20 | ||
545 | 547 | ||
546 | struct txpd { | 548 | struct txpd { |
547 | u8 bss_type; | 549 | u8 bss_type; |
@@ -553,7 +555,9 @@ struct txpd { | |||
553 | u8 priority; | 555 | u8 priority; |
554 | u8 flags; | 556 | u8 flags; |
555 | u8 pkt_delay_2ms; | 557 | u8 pkt_delay_2ms; |
556 | u8 reserved1; | 558 | u8 reserved1[2]; |
559 | u8 tx_token_id; | ||
560 | u8 reserved[2]; | ||
557 | } __packed; | 561 | } __packed; |
558 | 562 | ||
559 | struct rxpd { | 563 | struct rxpd { |
@@ -584,6 +588,7 @@ struct rxpd { | |||
584 | * [Bit 7] Reserved | 588 | * [Bit 7] Reserved |
585 | */ | 589 | */ |
586 | u8 ht_info; | 590 | u8 ht_info; |
591 | u8 reserved[3]; | ||
587 | u8 flags; | 592 | u8 flags; |
588 | } __packed; | 593 | } __packed; |
589 | 594 | ||
@@ -597,8 +602,9 @@ struct uap_txpd { | |||
597 | u8 priority; | 602 | u8 priority; |
598 | u8 flags; | 603 | u8 flags; |
599 | u8 pkt_delay_2ms; | 604 | u8 pkt_delay_2ms; |
600 | u8 reserved1; | 605 | u8 reserved1[2]; |
601 | __le32 reserved2; | 606 | u8 tx_token_id; |
607 | u8 reserved[2]; | ||
602 | }; | 608 | }; |
603 | 609 | ||
604 | struct uap_rxpd { | 610 | struct uap_rxpd { |
@@ -1223,6 +1229,12 @@ struct mwifiex_event_scan_result { | |||
1223 | u8 num_of_set; | 1229 | u8 num_of_set; |
1224 | } __packed; | 1230 | } __packed; |
1225 | 1231 | ||
1232 | struct tx_status_event { | ||
1233 | u8 packet_type; | ||
1234 | u8 tx_token_id; | ||
1235 | u8 status; | ||
1236 | } __packed; | ||
1237 | |||
1226 | #define MWIFIEX_USER_SCAN_CHAN_MAX 50 | 1238 | #define MWIFIEX_USER_SCAN_CHAN_MAX 50 |
1227 | 1239 | ||
1228 | #define MWIFIEX_MAX_SSID_LIST_LENGTH 10 | 1240 | #define MWIFIEX_MAX_SSID_LIST_LENGTH 10 |
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 580aa45ec4bc..520ad4a3018b 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c | |||
@@ -137,6 +137,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv) | |||
137 | priv->csa_expire_time = 0; | 137 | priv->csa_expire_time = 0; |
138 | priv->del_list_idx = 0; | 138 | priv->del_list_idx = 0; |
139 | priv->hs2_enabled = false; | 139 | priv->hs2_enabled = false; |
140 | priv->check_tdls_tx = false; | ||
140 | memcpy(priv->tos_to_tid_inv, tos_to_tid_inv, MAX_NUM_TID); | 141 | memcpy(priv->tos_to_tid_inv, tos_to_tid_inv, MAX_NUM_TID); |
141 | 142 | ||
142 | return mwifiex_add_bss_prio_tbl(priv); | 143 | return mwifiex_add_bss_prio_tbl(priv); |
@@ -366,6 +367,7 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) | |||
366 | list_del(&priv->tx_ba_stream_tbl_ptr); | 367 | list_del(&priv->tx_ba_stream_tbl_ptr); |
367 | list_del(&priv->rx_reorder_tbl_ptr); | 368 | list_del(&priv->rx_reorder_tbl_ptr); |
368 | list_del(&priv->sta_list); | 369 | list_del(&priv->sta_list); |
370 | list_del(&priv->auto_tdls_list); | ||
369 | } | 371 | } |
370 | } | 372 | } |
371 | } | 373 | } |
@@ -434,6 +436,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) | |||
434 | spin_lock_init(&priv->wmm.ra_list_spinlock); | 436 | spin_lock_init(&priv->wmm.ra_list_spinlock); |
435 | spin_lock_init(&priv->curr_bcn_buf_lock); | 437 | spin_lock_init(&priv->curr_bcn_buf_lock); |
436 | spin_lock_init(&priv->sta_list_spinlock); | 438 | spin_lock_init(&priv->sta_list_spinlock); |
439 | spin_lock_init(&priv->auto_tdls_lock); | ||
437 | } | 440 | } |
438 | } | 441 | } |
439 | 442 | ||
@@ -449,7 +452,6 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) | |||
449 | spin_lock_init(&adapter->scan_pending_q_lock); | 452 | spin_lock_init(&adapter->scan_pending_q_lock); |
450 | spin_lock_init(&adapter->rx_proc_lock); | 453 | spin_lock_init(&adapter->rx_proc_lock); |
451 | 454 | ||
452 | skb_queue_head_init(&adapter->usb_rx_data_q); | ||
453 | skb_queue_head_init(&adapter->rx_data_q); | 455 | skb_queue_head_init(&adapter->rx_data_q); |
454 | 456 | ||
455 | for (i = 0; i < adapter->priv_num; ++i) { | 457 | for (i = 0; i < adapter->priv_num; ++i) { |
@@ -466,10 +468,14 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) | |||
466 | INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); | 468 | INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); |
467 | INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); | 469 | INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); |
468 | INIT_LIST_HEAD(&priv->sta_list); | 470 | INIT_LIST_HEAD(&priv->sta_list); |
471 | INIT_LIST_HEAD(&priv->auto_tdls_list); | ||
469 | skb_queue_head_init(&priv->tdls_txq); | 472 | skb_queue_head_init(&priv->tdls_txq); |
470 | 473 | ||
471 | spin_lock_init(&priv->tx_ba_stream_tbl_lock); | 474 | spin_lock_init(&priv->tx_ba_stream_tbl_lock); |
472 | spin_lock_init(&priv->rx_reorder_tbl_lock); | 475 | spin_lock_init(&priv->rx_reorder_tbl_lock); |
476 | |||
477 | spin_lock_init(&priv->ack_status_lock); | ||
478 | idr_init(&priv->ack_status_frames); | ||
473 | } | 479 | } |
474 | 480 | ||
475 | return 0; | 481 | return 0; |
@@ -646,6 +652,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) | |||
646 | if (adapter->priv[i]) { | 652 | if (adapter->priv[i]) { |
647 | priv = adapter->priv[i]; | 653 | priv = adapter->priv[i]; |
648 | 654 | ||
655 | mwifiex_clean_auto_tdls(priv); | ||
649 | mwifiex_clean_txrx(priv); | 656 | mwifiex_clean_txrx(priv); |
650 | mwifiex_delete_bss_prio_tbl(priv); | 657 | mwifiex_delete_bss_prio_tbl(priv); |
651 | } | 658 | } |
@@ -668,19 +675,6 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) | |||
668 | 675 | ||
669 | spin_lock(&adapter->mwifiex_lock); | 676 | spin_lock(&adapter->mwifiex_lock); |
670 | 677 | ||
671 | if (adapter->if_ops.data_complete) { | ||
672 | while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) { | ||
673 | struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); | ||
674 | |||
675 | priv = adapter->priv[rx_info->bss_num]; | ||
676 | if (priv) | ||
677 | priv->stats.rx_dropped++; | ||
678 | |||
679 | dev_kfree_skb_any(skb); | ||
680 | adapter->if_ops.data_complete(adapter); | ||
681 | } | ||
682 | } | ||
683 | |||
684 | mwifiex_adapter_cleanup(adapter); | 678 | mwifiex_adapter_cleanup(adapter); |
685 | 679 | ||
686 | spin_unlock(&adapter->mwifiex_lock); | 680 | spin_unlock(&adapter->mwifiex_lock); |
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 8d6c25908b6d..411a6c2f4aca 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c | |||
@@ -880,9 +880,7 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, | |||
880 | 880 | ||
881 | /* Set Capability info */ | 881 | /* Set Capability info */ |
882 | bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; | 882 | bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; |
883 | tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap); | 883 | tmp_cap = WLAN_CAPABILITY_IBSS; |
884 | tmp_cap &= ~WLAN_CAPABILITY_ESS; | ||
885 | tmp_cap |= WLAN_CAPABILITY_IBSS; | ||
886 | 884 | ||
887 | /* Set up privacy in bss_desc */ | 885 | /* Set up privacy in bss_desc */ |
888 | if (priv->sec_info.encryption_mode) { | 886 | if (priv->sec_info.encryption_mode) { |
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index f26420dbab6f..d4d2223d1f31 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c | |||
@@ -28,6 +28,11 @@ const char driver_version[] = "mwifiex " VERSION " (%s) "; | |||
28 | static char *cal_data_cfg; | 28 | static char *cal_data_cfg; |
29 | module_param(cal_data_cfg, charp, 0); | 29 | module_param(cal_data_cfg, charp, 0); |
30 | 30 | ||
31 | static unsigned short driver_mode; | ||
32 | module_param(driver_mode, ushort, 0); | ||
33 | MODULE_PARM_DESC(driver_mode, | ||
34 | "station=0x1(default), ap-sta=0x3, station-p2p=0x5, ap-sta-p2p=0x7"); | ||
35 | |||
31 | /* | 36 | /* |
32 | * This function registers the device and performs all the necessary | 37 | * This function registers the device and performs all the necessary |
33 | * initializations. | 38 | * initializations. |
@@ -144,8 +149,11 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter) | |||
144 | /* Check for Rx data */ | 149 | /* Check for Rx data */ |
145 | while ((skb = skb_dequeue(&adapter->rx_data_q))) { | 150 | while ((skb = skb_dequeue(&adapter->rx_data_q))) { |
146 | atomic_dec(&adapter->rx_pending); | 151 | atomic_dec(&adapter->rx_pending); |
147 | if (adapter->delay_main_work && | 152 | if ((adapter->delay_main_work || |
153 | adapter->iface_type == MWIFIEX_USB) && | ||
148 | (atomic_read(&adapter->rx_pending) < LOW_RX_PENDING)) { | 154 | (atomic_read(&adapter->rx_pending) < LOW_RX_PENDING)) { |
155 | if (adapter->if_ops.submit_rem_rx_urbs) | ||
156 | adapter->if_ops.submit_rem_rx_urbs(adapter); | ||
149 | adapter->delay_main_work = false; | 157 | adapter->delay_main_work = false; |
150 | queue_work(adapter->workqueue, &adapter->main_work); | 158 | queue_work(adapter->workqueue, &adapter->main_work); |
151 | } | 159 | } |
@@ -178,7 +186,6 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) | |||
178 | { | 186 | { |
179 | int ret = 0; | 187 | int ret = 0; |
180 | unsigned long flags; | 188 | unsigned long flags; |
181 | struct sk_buff *skb; | ||
182 | 189 | ||
183 | spin_lock_irqsave(&adapter->main_proc_lock, flags); | 190 | spin_lock_irqsave(&adapter->main_proc_lock, flags); |
184 | 191 | ||
@@ -196,12 +203,15 @@ process_start: | |||
196 | (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) | 203 | (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) |
197 | break; | 204 | break; |
198 | 205 | ||
199 | /* If we process interrupts first, it would increase RX pending | 206 | /* For non-USB interfaces, If we process interrupts first, it |
200 | * even further. Avoid this by checking if rx_pending has | 207 | * would increase RX pending even further. Avoid this by |
201 | * crossed high threshold and schedule rx work queue | 208 | * checking if rx_pending has crossed high threshold and |
202 | * and then process interrupts | 209 | * schedule rx work queue and then process interrupts. |
210 | * For USB interface, there are no interrupts. We already have | ||
211 | * HIGH_RX_PENDING check in usb.c | ||
203 | */ | 212 | */ |
204 | if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING) { | 213 | if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING && |
214 | adapter->iface_type != MWIFIEX_USB) { | ||
205 | adapter->delay_main_work = true; | 215 | adapter->delay_main_work = true; |
206 | if (!adapter->rx_processing) | 216 | if (!adapter->rx_processing) |
207 | queue_work(adapter->rx_workqueue, | 217 | queue_work(adapter->rx_workqueue, |
@@ -253,11 +263,6 @@ process_start: | |||
253 | } | 263 | } |
254 | } | 264 | } |
255 | 265 | ||
256 | /* Check Rx data for USB */ | ||
257 | if (adapter->iface_type == MWIFIEX_USB) | ||
258 | while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) | ||
259 | mwifiex_handle_rx_packet(adapter, skb); | ||
260 | |||
261 | /* Check for event */ | 266 | /* Check for event */ |
262 | if (adapter->event_received) { | 267 | if (adapter->event_received) { |
263 | adapter->event_received = false; | 268 | adapter->event_received = false; |
@@ -453,6 +458,11 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) | |||
453 | goto err_init_fw; | 458 | goto err_init_fw; |
454 | } | 459 | } |
455 | 460 | ||
461 | if (driver_mode) { | ||
462 | driver_mode &= MWIFIEX_DRIVER_MODE_BITMASK; | ||
463 | driver_mode |= MWIFIEX_DRIVER_MODE_STA; | ||
464 | } | ||
465 | |||
456 | rtnl_lock(); | 466 | rtnl_lock(); |
457 | /* Create station interface by default */ | 467 | /* Create station interface by default */ |
458 | wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", | 468 | wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", |
@@ -462,6 +472,28 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) | |||
462 | rtnl_unlock(); | 472 | rtnl_unlock(); |
463 | goto err_add_intf; | 473 | goto err_add_intf; |
464 | } | 474 | } |
475 | |||
476 | if (driver_mode & MWIFIEX_DRIVER_MODE_UAP) { | ||
477 | wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", | ||
478 | NL80211_IFTYPE_AP, NULL, NULL); | ||
479 | if (IS_ERR(wdev)) { | ||
480 | dev_err(adapter->dev, "cannot create AP interface\n"); | ||
481 | rtnl_unlock(); | ||
482 | goto err_add_intf; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | if (driver_mode & MWIFIEX_DRIVER_MODE_P2P) { | ||
487 | wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", | ||
488 | NL80211_IFTYPE_P2P_CLIENT, NULL, | ||
489 | NULL); | ||
490 | if (IS_ERR(wdev)) { | ||
491 | dev_err(adapter->dev, | ||
492 | "cannot create p2p client interface\n"); | ||
493 | rtnl_unlock(); | ||
494 | goto err_add_intf; | ||
495 | } | ||
496 | } | ||
465 | rtnl_unlock(); | 497 | rtnl_unlock(); |
466 | 498 | ||
467 | mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); | 499 | mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); |
@@ -576,6 +608,48 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) | |||
576 | return 0; | 608 | return 0; |
577 | } | 609 | } |
578 | 610 | ||
611 | struct sk_buff * | ||
612 | mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, | ||
613 | struct sk_buff *skb, u8 flag, u64 *cookie) | ||
614 | { | ||
615 | struct sk_buff *orig_skb = skb; | ||
616 | struct mwifiex_txinfo *tx_info, *orig_tx_info; | ||
617 | |||
618 | skb = skb_clone(skb, GFP_ATOMIC); | ||
619 | if (skb) { | ||
620 | unsigned long flags; | ||
621 | int id; | ||
622 | |||
623 | spin_lock_irqsave(&priv->ack_status_lock, flags); | ||
624 | id = idr_alloc(&priv->ack_status_frames, orig_skb, | ||
625 | 1, 0xff, GFP_ATOMIC); | ||
626 | spin_unlock_irqrestore(&priv->ack_status_lock, flags); | ||
627 | |||
628 | if (id >= 0) { | ||
629 | tx_info = MWIFIEX_SKB_TXCB(skb); | ||
630 | tx_info->ack_frame_id = id; | ||
631 | tx_info->flags |= flag; | ||
632 | orig_tx_info = MWIFIEX_SKB_TXCB(orig_skb); | ||
633 | orig_tx_info->ack_frame_id = id; | ||
634 | orig_tx_info->flags |= flag; | ||
635 | |||
636 | if (flag == MWIFIEX_BUF_FLAG_ACTION_TX_STATUS && cookie) | ||
637 | orig_tx_info->cookie = *cookie; | ||
638 | |||
639 | } else if (skb_shared(skb)) { | ||
640 | kfree_skb(orig_skb); | ||
641 | } else { | ||
642 | kfree_skb(skb); | ||
643 | skb = orig_skb; | ||
644 | } | ||
645 | } else { | ||
646 | /* couldn't clone -- lose tx status ... */ | ||
647 | skb = orig_skb; | ||
648 | } | ||
649 | |||
650 | return skb; | ||
651 | } | ||
652 | |||
579 | /* | 653 | /* |
580 | * CFG802.11 network device handler for data transmission. | 654 | * CFG802.11 network device handler for data transmission. |
581 | */ | 655 | */ |
@@ -585,6 +659,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
585 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | 659 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
586 | struct sk_buff *new_skb; | 660 | struct sk_buff *new_skb; |
587 | struct mwifiex_txinfo *tx_info; | 661 | struct mwifiex_txinfo *tx_info; |
662 | bool multicast; | ||
588 | 663 | ||
589 | dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n", | 664 | dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n", |
590 | jiffies, priv->bss_type, priv->bss_num); | 665 | jiffies, priv->bss_type, priv->bss_num); |
@@ -625,6 +700,15 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
625 | tx_info->bss_type = priv->bss_type; | 700 | tx_info->bss_type = priv->bss_type; |
626 | tx_info->pkt_len = skb->len; | 701 | tx_info->pkt_len = skb->len; |
627 | 702 | ||
703 | multicast = is_multicast_ether_addr(skb->data); | ||
704 | |||
705 | if (unlikely(!multicast && skb->sk && | ||
706 | skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS && | ||
707 | priv->adapter->fw_api_ver == MWIFIEX_FW_V15)) | ||
708 | skb = mwifiex_clone_skb_for_tx_status(priv, | ||
709 | skb, | ||
710 | MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS, NULL); | ||
711 | |||
628 | /* Record the current time the packet was queued; used to | 712 | /* Record the current time the packet was queued; used to |
629 | * determine the amount of time the packet was queued in | 713 | * determine the amount of time the packet was queued in |
630 | * the driver before it was sent to the firmware. | 714 | * the driver before it was sent to the firmware. |
@@ -634,6 +718,13 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
634 | */ | 718 | */ |
635 | __net_timestamp(skb); | 719 | __net_timestamp(skb); |
636 | 720 | ||
721 | if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && | ||
722 | priv->bss_type == MWIFIEX_BSS_TYPE_STA && | ||
723 | !ether_addr_equal_unaligned(priv->cfg_bssid, skb->data)) { | ||
724 | if (priv->adapter->auto_tdls && priv->check_tdls_tx) | ||
725 | mwifiex_tdls_check_tx(priv, skb); | ||
726 | } | ||
727 | |||
637 | mwifiex_queue_tx_pkt(priv, skb); | 728 | mwifiex_queue_tx_pkt(priv, skb); |
638 | 729 | ||
639 | return 0; | 730 | return 0; |
@@ -864,7 +955,7 @@ mwifiex_add_card(void *card, struct semaphore *sem, | |||
864 | adapter->cmd_wait_q.status = 0; | 955 | adapter->cmd_wait_q.status = 0; |
865 | adapter->scan_wait_q_woken = false; | 956 | adapter->scan_wait_q_woken = false; |
866 | 957 | ||
867 | if (num_possible_cpus() > 1) { | 958 | if ((num_possible_cpus() > 1) || adapter->iface_type == MWIFIEX_USB) { |
868 | adapter->rx_work_enabled = true; | 959 | adapter->rx_work_enabled = true; |
869 | pr_notice("rx work enabled, cpus %d\n", num_possible_cpus()); | 960 | pr_notice("rx work enabled, cpus %d\n", num_possible_cpus()); |
870 | } | 961 | } |
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index fb47731d45a6..bdba37b7015d 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/firmware.h> | 34 | #include <linux/firmware.h> |
35 | #include <linux/ctype.h> | 35 | #include <linux/ctype.h> |
36 | #include <linux/of.h> | 36 | #include <linux/of.h> |
37 | #include <linux/idr.h> | ||
37 | 38 | ||
38 | #include "decl.h" | 39 | #include "decl.h" |
39 | #include "ioctl.h" | 40 | #include "ioctl.h" |
@@ -48,6 +49,11 @@ enum { | |||
48 | MWIFIEX_SYNC_CMD | 49 | MWIFIEX_SYNC_CMD |
49 | }; | 50 | }; |
50 | 51 | ||
52 | #define MWIFIEX_DRIVER_MODE_STA BIT(0) | ||
53 | #define MWIFIEX_DRIVER_MODE_UAP BIT(1) | ||
54 | #define MWIFIEX_DRIVER_MODE_P2P BIT(2) | ||
55 | #define MWIFIEX_DRIVER_MODE_BITMASK (BIT(0) | BIT(1) | BIT(2)) | ||
56 | |||
51 | #define MWIFIEX_MAX_AP 64 | 57 | #define MWIFIEX_MAX_AP 64 |
52 | 58 | ||
53 | #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) | 59 | #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) |
@@ -106,10 +112,7 @@ enum { | |||
106 | */ | 112 | */ |
107 | #define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \ | 113 | #define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \ |
108 | adapter->event_received || \ | 114 | adapter->event_received || \ |
109 | ((adapter->iface_type != MWIFIEX_USB) && \ | 115 | adapter->data_received) |
110 | adapter->data_received) || \ | ||
111 | ((adapter->iface_type == MWIFIEX_USB) && \ | ||
112 | !skb_queue_empty(&adapter->usb_rx_data_q))) | ||
113 | 116 | ||
114 | #define MWIFIEX_TYPE_CMD 1 | 117 | #define MWIFIEX_TYPE_CMD 1 |
115 | #define MWIFIEX_TYPE_DATA 0 | 118 | #define MWIFIEX_TYPE_DATA 0 |
@@ -504,8 +507,11 @@ struct mwifiex_private { | |||
504 | struct mwifiex_wmm_desc wmm; | 507 | struct mwifiex_wmm_desc wmm; |
505 | atomic_t wmm_tx_pending[IEEE80211_NUM_ACS]; | 508 | atomic_t wmm_tx_pending[IEEE80211_NUM_ACS]; |
506 | struct list_head sta_list; | 509 | struct list_head sta_list; |
507 | /* spin lock for associated station list */ | 510 | /* spin lock for associated station/TDLS peers list */ |
508 | spinlock_t sta_list_spinlock; | 511 | spinlock_t sta_list_spinlock; |
512 | struct list_head auto_tdls_list; | ||
513 | /* spin lock for auto TDLS peer list */ | ||
514 | spinlock_t auto_tdls_lock; | ||
509 | struct list_head tx_ba_stream_tbl_ptr; | 515 | struct list_head tx_ba_stream_tbl_ptr; |
510 | /* spin lock for tx_ba_stream_tbl_ptr queue */ | 516 | /* spin lock for tx_ba_stream_tbl_ptr queue */ |
511 | spinlock_t tx_ba_stream_tbl_lock; | 517 | spinlock_t tx_ba_stream_tbl_lock; |
@@ -570,6 +576,12 @@ struct mwifiex_private { | |||
570 | bool hs2_enabled; | 576 | bool hs2_enabled; |
571 | struct station_parameters *sta_params; | 577 | struct station_parameters *sta_params; |
572 | struct sk_buff_head tdls_txq; | 578 | struct sk_buff_head tdls_txq; |
579 | u8 check_tdls_tx; | ||
580 | struct timer_list auto_tdls_timer; | ||
581 | bool auto_tdls_timer_active; | ||
582 | struct idr ack_status_frames; | ||
583 | /* spin lock for ack status */ | ||
584 | spinlock_t ack_status_lock; | ||
573 | }; | 585 | }; |
574 | 586 | ||
575 | enum mwifiex_ba_status { | 587 | enum mwifiex_ba_status { |
@@ -592,6 +604,7 @@ struct reorder_tmr_cnxt { | |||
592 | struct timer_list timer; | 604 | struct timer_list timer; |
593 | struct mwifiex_rx_reorder_tbl *ptr; | 605 | struct mwifiex_rx_reorder_tbl *ptr; |
594 | struct mwifiex_private *priv; | 606 | struct mwifiex_private *priv; |
607 | u8 timer_is_set; | ||
595 | }; | 608 | }; |
596 | 609 | ||
597 | struct mwifiex_rx_reorder_tbl { | 610 | struct mwifiex_rx_reorder_tbl { |
@@ -669,6 +682,17 @@ struct mwifiex_sta_node { | |||
669 | struct mwifiex_tdls_capab tdls_cap; | 682 | struct mwifiex_tdls_capab tdls_cap; |
670 | }; | 683 | }; |
671 | 684 | ||
685 | struct mwifiex_auto_tdls_peer { | ||
686 | struct list_head list; | ||
687 | u8 mac_addr[ETH_ALEN]; | ||
688 | u8 tdls_status; | ||
689 | int rssi; | ||
690 | long rssi_jiffies; | ||
691 | u8 failure_count; | ||
692 | u8 do_discover; | ||
693 | u8 do_setup; | ||
694 | }; | ||
695 | |||
672 | struct mwifiex_if_ops { | 696 | struct mwifiex_if_ops { |
673 | int (*init_if) (struct mwifiex_adapter *); | 697 | int (*init_if) (struct mwifiex_adapter *); |
674 | void (*cleanup_if) (struct mwifiex_adapter *); | 698 | void (*cleanup_if) (struct mwifiex_adapter *); |
@@ -689,13 +713,13 @@ struct mwifiex_if_ops { | |||
689 | void (*cleanup_mpa_buf) (struct mwifiex_adapter *); | 713 | void (*cleanup_mpa_buf) (struct mwifiex_adapter *); |
690 | int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); | 714 | int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); |
691 | int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); | 715 | int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); |
692 | int (*data_complete) (struct mwifiex_adapter *); | ||
693 | int (*init_fw_port) (struct mwifiex_adapter *); | 716 | int (*init_fw_port) (struct mwifiex_adapter *); |
694 | int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); | 717 | int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); |
695 | void (*card_reset) (struct mwifiex_adapter *); | 718 | void (*card_reset) (struct mwifiex_adapter *); |
696 | void (*fw_dump)(struct mwifiex_adapter *); | 719 | void (*fw_dump)(struct mwifiex_adapter *); |
697 | int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); | 720 | int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); |
698 | void (*iface_work)(struct work_struct *work); | 721 | void (*iface_work)(struct work_struct *work); |
722 | void (*submit_rem_rx_urbs)(struct mwifiex_adapter *adapter); | ||
699 | }; | 723 | }; |
700 | 724 | ||
701 | struct mwifiex_adapter { | 725 | struct mwifiex_adapter { |
@@ -766,7 +790,6 @@ struct mwifiex_adapter { | |||
766 | spinlock_t scan_pending_q_lock; | 790 | spinlock_t scan_pending_q_lock; |
767 | /* spin lock for RX processing routine */ | 791 | /* spin lock for RX processing routine */ |
768 | spinlock_t rx_proc_lock; | 792 | spinlock_t rx_proc_lock; |
769 | struct sk_buff_head usb_rx_data_q; | ||
770 | u32 scan_processing; | 793 | u32 scan_processing; |
771 | u16 region_code; | 794 | u16 region_code; |
772 | struct mwifiex_802_11d_domain_reg domain_reg; | 795 | struct mwifiex_802_11d_domain_reg domain_reg; |
@@ -847,6 +870,7 @@ struct mwifiex_adapter { | |||
847 | struct mwifiex_chan_stats *chan_stats; | 870 | struct mwifiex_chan_stats *chan_stats; |
848 | u32 num_in_chan_stats; | 871 | u32 num_in_chan_stats; |
849 | int survey_idx; | 872 | int survey_idx; |
873 | bool auto_tdls; | ||
850 | }; | 874 | }; |
851 | 875 | ||
852 | int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); | 876 | int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); |
@@ -1304,6 +1328,24 @@ u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band, | |||
1304 | u32 pri_chan, u8 chan_bw); | 1328 | u32 pri_chan, u8 chan_bw); |
1305 | int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter); | 1329 | int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter); |
1306 | 1330 | ||
1331 | int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb); | ||
1332 | void mwifiex_flush_auto_tdls_list(struct mwifiex_private *priv); | ||
1333 | void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv, | ||
1334 | const u8 *mac, u8 link_status); | ||
1335 | void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv, | ||
1336 | u8 *mac, s8 snr, s8 nflr); | ||
1337 | void mwifiex_check_auto_tdls(unsigned long context); | ||
1338 | void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac); | ||
1339 | void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv); | ||
1340 | void mwifiex_clean_auto_tdls(struct mwifiex_private *priv); | ||
1341 | |||
1342 | void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, | ||
1343 | void *event_body); | ||
1344 | |||
1345 | struct sk_buff * | ||
1346 | mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, | ||
1347 | struct sk_buff *skb, u8 flag, u64 *cookie); | ||
1348 | |||
1307 | #ifdef CONFIG_DEBUG_FS | 1349 | #ifdef CONFIG_DEBUG_FS |
1308 | void mwifiex_debugfs_init(void); | 1350 | void mwifiex_debugfs_init(void); |
1309 | void mwifiex_debugfs_remove(void); | 1351 | void mwifiex_debugfs_remove(void); |
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 3a17821157d7..984a7a4fa93b 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c | |||
@@ -1623,7 +1623,7 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, | |||
1623 | 1623 | ||
1624 | if (*bytes_left >= sizeof(beacon_size)) { | 1624 | if (*bytes_left >= sizeof(beacon_size)) { |
1625 | /* Extract & convert beacon size from command buffer */ | 1625 | /* Extract & convert beacon size from command buffer */ |
1626 | memcpy(&beacon_size, *bss_info, sizeof(beacon_size)); | 1626 | beacon_size = le16_to_cpu(*(__le16 *)(*bss_info)); |
1627 | *bytes_left -= sizeof(beacon_size); | 1627 | *bytes_left -= sizeof(beacon_size); |
1628 | *bss_info += sizeof(beacon_size); | 1628 | *bss_info += sizeof(beacon_size); |
1629 | } | 1629 | } |
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index b25766b43b9f..933dae137850 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c | |||
@@ -106,6 +106,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) | |||
106 | card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; | 106 | card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; |
107 | card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; | 107 | card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; |
108 | card->supports_fw_dump = data->supports_fw_dump; | 108 | card->supports_fw_dump = data->supports_fw_dump; |
109 | card->auto_tdls = data->auto_tdls; | ||
109 | } | 110 | } |
110 | 111 | ||
111 | sdio_claim_host(func); | 112 | sdio_claim_host(func); |
@@ -1880,6 +1881,7 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) | |||
1880 | return -1; | 1881 | return -1; |
1881 | } | 1882 | } |
1882 | 1883 | ||
1884 | adapter->auto_tdls = card->auto_tdls; | ||
1883 | return ret; | 1885 | return ret; |
1884 | } | 1886 | } |
1885 | 1887 | ||
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 20cd9adc98d3..54c07156dd78 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h | |||
@@ -246,6 +246,7 @@ struct sdio_mmc_card { | |||
246 | u8 curr_wr_port; | 246 | u8 curr_wr_port; |
247 | 247 | ||
248 | u8 *mp_regs; | 248 | u8 *mp_regs; |
249 | u8 auto_tdls; | ||
249 | 250 | ||
250 | struct mwifiex_sdio_mpa_tx mpa_tx; | 251 | struct mwifiex_sdio_mpa_tx mpa_tx; |
251 | struct mwifiex_sdio_mpa_rx mpa_rx; | 252 | struct mwifiex_sdio_mpa_rx mpa_rx; |
@@ -262,6 +263,7 @@ struct mwifiex_sdio_device { | |||
262 | u16 tx_buf_size; | 263 | u16 tx_buf_size; |
263 | u32 mp_tx_agg_buf_size; | 264 | u32 mp_tx_agg_buf_size; |
264 | u32 mp_rx_agg_buf_size; | 265 | u32 mp_rx_agg_buf_size; |
266 | u8 auto_tdls; | ||
265 | }; | 267 | }; |
266 | 268 | ||
267 | static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = { | 269 | static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = { |
@@ -387,6 +389,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { | |||
387 | .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, | 389 | .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, |
388 | .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, | 390 | .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, |
389 | .supports_fw_dump = false, | 391 | .supports_fw_dump = false, |
392 | .auto_tdls = false, | ||
390 | }; | 393 | }; |
391 | 394 | ||
392 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { | 395 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { |
@@ -400,6 +403,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { | |||
400 | .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, | 403 | .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, |
401 | .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, | 404 | .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, |
402 | .supports_fw_dump = false, | 405 | .supports_fw_dump = false, |
406 | .auto_tdls = false, | ||
403 | }; | 407 | }; |
404 | 408 | ||
405 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { | 409 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { |
@@ -413,6 +417,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { | |||
413 | .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, | 417 | .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, |
414 | .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, | 418 | .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, |
415 | .supports_fw_dump = false, | 419 | .supports_fw_dump = false, |
420 | .auto_tdls = false, | ||
416 | }; | 421 | }; |
417 | 422 | ||
418 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { | 423 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { |
@@ -426,6 +431,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { | |||
426 | .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, | 431 | .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, |
427 | .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, | 432 | .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, |
428 | .supports_fw_dump = true, | 433 | .supports_fw_dump = true, |
434 | .auto_tdls = false, | ||
429 | }; | 435 | }; |
430 | 436 | ||
431 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { | 437 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { |
@@ -439,6 +445,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { | |||
439 | .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, | 445 | .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, |
440 | .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, | 446 | .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, |
441 | .supports_fw_dump = false, | 447 | .supports_fw_dump = false, |
448 | .auto_tdls = true, | ||
442 | }; | 449 | }; |
443 | 450 | ||
444 | /* | 451 | /* |
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index f1c240eca0cd..b8c171df6223 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c | |||
@@ -55,9 +55,13 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) | |||
55 | priv->scan_block = false; | 55 | priv->scan_block = false; |
56 | 56 | ||
57 | if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && | 57 | if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && |
58 | ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) | 58 | ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) { |
59 | mwifiex_disable_all_tdls_links(priv); | 59 | mwifiex_disable_all_tdls_links(priv); |
60 | 60 | ||
61 | if (priv->adapter->auto_tdls) | ||
62 | mwifiex_clean_auto_tdls(priv); | ||
63 | } | ||
64 | |||
61 | /* Free Tx and Rx packets, report disconnect to upper layer */ | 65 | /* Free Tx and Rx packets, report disconnect to upper layer */ |
62 | mwifiex_clean_txrx(priv); | 66 | mwifiex_clean_txrx(priv); |
63 | 67 | ||
@@ -163,9 +167,6 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, | |||
163 | NL80211_TDLS_TEARDOWN, | 167 | NL80211_TDLS_TEARDOWN, |
164 | le16_to_cpu(tdls_evt->u.reason_code), | 168 | le16_to_cpu(tdls_evt->u.reason_code), |
165 | GFP_KERNEL); | 169 | GFP_KERNEL); |
166 | ret = mwifiex_tdls_oper(priv, tdls_evt->peer_mac, | ||
167 | MWIFIEX_TDLS_DISABLE_LINK); | ||
168 | queue_work(adapter->workqueue, &adapter->main_work); | ||
169 | break; | 170 | break; |
170 | default: | 171 | default: |
171 | break; | 172 | break; |
@@ -503,6 +504,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) | |||
503 | ret = mwifiex_parse_tdls_event(priv, adapter->event_skb); | 504 | ret = mwifiex_parse_tdls_event(priv, adapter->event_skb); |
504 | break; | 505 | break; |
505 | 506 | ||
507 | case EVENT_TX_STATUS_REPORT: | ||
508 | dev_dbg(adapter->dev, "event: TX_STATUS Report\n"); | ||
509 | mwifiex_parse_tx_status_event(priv, adapter->event_body); | ||
510 | break; | ||
511 | |||
506 | default: | 512 | default: |
507 | dev_dbg(adapter->dev, "event: unknown event id: %#x\n", | 513 | dev_dbg(adapter->dev, "event: unknown event id: %#x\n", |
508 | eventcause); | 514 | eventcause); |
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 92f3eb839866..1626868a4b5c 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c | |||
@@ -1026,12 +1026,12 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, | |||
1026 | int max_len) | 1026 | int max_len) |
1027 | { | 1027 | { |
1028 | union { | 1028 | union { |
1029 | u32 l; | 1029 | __le32 l; |
1030 | u8 c[4]; | 1030 | u8 c[4]; |
1031 | } ver; | 1031 | } ver; |
1032 | char fw_ver[32]; | 1032 | char fw_ver[32]; |
1033 | 1033 | ||
1034 | ver.l = adapter->fw_release_number; | 1034 | ver.l = cpu_to_le32(adapter->fw_release_number); |
1035 | sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]); | 1035 | sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]); |
1036 | 1036 | ||
1037 | snprintf(version, max_len, driver_version, fw_ver); | 1037 | snprintf(version, max_len, driver_version, fw_ver); |
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index 9ceb1dbe34c5..c2ad3b63ae70 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c | |||
@@ -232,6 +232,9 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv, | |||
232 | if (sta_ptr) | 232 | if (sta_ptr) |
233 | sta_ptr->rx_seq[local_rx_pd->priority] = | 233 | sta_ptr->rx_seq[local_rx_pd->priority] = |
234 | le16_to_cpu(local_rx_pd->seq_num); | 234 | le16_to_cpu(local_rx_pd->seq_num); |
235 | mwifiex_auto_tdls_update_peer_signal(priv, ta, | ||
236 | local_rx_pd->snr, | ||
237 | local_rx_pd->nf); | ||
235 | } | 238 | } |
236 | } else { | 239 | } else { |
237 | if (rx_pkt_type != PKT_TYPE_BAR) | 240 | if (rx_pkt_type != PKT_TYPE_BAR) |
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index dab7b33c54be..b896d7375b52 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c | |||
@@ -77,6 +77,12 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, | |||
77 | local_tx_pd->pkt_delay_2ms = | 77 | local_tx_pd->pkt_delay_2ms = |
78 | mwifiex_wmm_compute_drv_pkt_delay(priv, skb); | 78 | mwifiex_wmm_compute_drv_pkt_delay(priv, skb); |
79 | 79 | ||
80 | if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS || | ||
81 | tx_info->flags & MWIFIEX_BUF_FLAG_ACTION_TX_STATUS) { | ||
82 | local_tx_pd->tx_token_id = tx_info->ack_frame_id; | ||
83 | local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS; | ||
84 | } | ||
85 | |||
80 | if (local_tx_pd->priority < | 86 | if (local_tx_pd->priority < |
81 | ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) | 87 | ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) |
82 | /* | 88 | /* |
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index e2949077f5b5..22884b429be7 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #define TDLS_REQ_FIX_LEN 6 | 24 | #define TDLS_REQ_FIX_LEN 6 |
25 | #define TDLS_RESP_FIX_LEN 8 | 25 | #define TDLS_RESP_FIX_LEN 8 |
26 | #define TDLS_CONFIRM_FIX_LEN 6 | 26 | #define TDLS_CONFIRM_FIX_LEN 6 |
27 | #define MWIFIEX_TDLS_WMM_INFO_SIZE 7 | ||
27 | 28 | ||
28 | static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv, | 29 | static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv, |
29 | const u8 *mac, u8 status) | 30 | const u8 *mac, u8 status) |
@@ -367,6 +368,55 @@ static void mwifiex_tdls_add_qos_capab(struct sk_buff *skb) | |||
367 | *pos++ = MWIFIEX_TDLS_DEF_QOS_CAPAB; | 368 | *pos++ = MWIFIEX_TDLS_DEF_QOS_CAPAB; |
368 | } | 369 | } |
369 | 370 | ||
371 | static void | ||
372 | mwifiex_tdls_add_wmm_param_ie(struct mwifiex_private *priv, struct sk_buff *skb) | ||
373 | { | ||
374 | struct ieee80211_wmm_param_ie *wmm; | ||
375 | u8 ac_vi[] = {0x42, 0x43, 0x5e, 0x00}; | ||
376 | u8 ac_vo[] = {0x62, 0x32, 0x2f, 0x00}; | ||
377 | u8 ac_be[] = {0x03, 0xa4, 0x00, 0x00}; | ||
378 | u8 ac_bk[] = {0x27, 0xa4, 0x00, 0x00}; | ||
379 | |||
380 | wmm = (void *)skb_put(skb, sizeof(*wmm)); | ||
381 | memset(wmm, 0, sizeof(*wmm)); | ||
382 | |||
383 | wmm->element_id = WLAN_EID_VENDOR_SPECIFIC; | ||
384 | wmm->len = sizeof(*wmm) - 2; | ||
385 | wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
386 | wmm->oui[1] = 0x50; | ||
387 | wmm->oui[2] = 0xf2; | ||
388 | wmm->oui_type = 2; /* WME */ | ||
389 | wmm->oui_subtype = 1; /* WME param */ | ||
390 | wmm->version = 1; /* WME ver */ | ||
391 | wmm->qos_info = 0; /* U-APSD not in use */ | ||
392 | |||
393 | /* use default WMM AC parameters for TDLS link*/ | ||
394 | memcpy(&wmm->ac[0], ac_be, sizeof(ac_be)); | ||
395 | memcpy(&wmm->ac[1], ac_bk, sizeof(ac_bk)); | ||
396 | memcpy(&wmm->ac[2], ac_vi, sizeof(ac_vi)); | ||
397 | memcpy(&wmm->ac[3], ac_vo, sizeof(ac_vo)); | ||
398 | } | ||
399 | |||
400 | static void | ||
401 | mwifiex_add_wmm_info_ie(struct mwifiex_private *priv, struct sk_buff *skb, | ||
402 | u8 qosinfo) | ||
403 | { | ||
404 | u8 *buf; | ||
405 | |||
406 | buf = (void *)skb_put(skb, MWIFIEX_TDLS_WMM_INFO_SIZE + | ||
407 | sizeof(struct ieee_types_header)); | ||
408 | |||
409 | *buf++ = WLAN_EID_VENDOR_SPECIFIC; | ||
410 | *buf++ = 7; /* len */ | ||
411 | *buf++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
412 | *buf++ = 0x50; | ||
413 | *buf++ = 0xf2; | ||
414 | *buf++ = 2; /* WME */ | ||
415 | *buf++ = 0; /* WME info */ | ||
416 | *buf++ = 1; /* WME ver */ | ||
417 | *buf++ = qosinfo; /* U-APSD no in use */ | ||
418 | } | ||
419 | |||
370 | static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, | 420 | static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, |
371 | const u8 *peer, u8 action_code, | 421 | const u8 *peer, u8 action_code, |
372 | u8 dialog_token, | 422 | u8 dialog_token, |
@@ -421,6 +471,7 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, | |||
421 | 471 | ||
422 | mwifiex_tdls_add_ext_capab(priv, skb); | 472 | mwifiex_tdls_add_ext_capab(priv, skb); |
423 | mwifiex_tdls_add_qos_capab(skb); | 473 | mwifiex_tdls_add_qos_capab(skb); |
474 | mwifiex_add_wmm_info_ie(priv, skb, 0); | ||
424 | break; | 475 | break; |
425 | 476 | ||
426 | case WLAN_TDLS_SETUP_RESPONSE: | 477 | case WLAN_TDLS_SETUP_RESPONSE: |
@@ -458,6 +509,7 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, | |||
458 | 509 | ||
459 | mwifiex_tdls_add_ext_capab(priv, skb); | 510 | mwifiex_tdls_add_ext_capab(priv, skb); |
460 | mwifiex_tdls_add_qos_capab(skb); | 511 | mwifiex_tdls_add_qos_capab(skb); |
512 | mwifiex_add_wmm_info_ie(priv, skb, 0); | ||
461 | break; | 513 | break; |
462 | 514 | ||
463 | case WLAN_TDLS_SETUP_CONFIRM: | 515 | case WLAN_TDLS_SETUP_CONFIRM: |
@@ -466,6 +518,8 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, | |||
466 | skb_put(skb, sizeof(tf->u.setup_cfm)); | 518 | skb_put(skb, sizeof(tf->u.setup_cfm)); |
467 | tf->u.setup_cfm.status_code = cpu_to_le16(status_code); | 519 | tf->u.setup_cfm.status_code = cpu_to_le16(status_code); |
468 | tf->u.setup_cfm.dialog_token = dialog_token; | 520 | tf->u.setup_cfm.dialog_token = dialog_token; |
521 | |||
522 | mwifiex_tdls_add_wmm_param_ie(priv, skb); | ||
469 | if (priv->adapter->is_hw_11ac_capable) { | 523 | if (priv->adapter->is_hw_11ac_capable) { |
470 | ret = mwifiex_tdls_add_vht_oper(priv, peer, skb); | 524 | ret = mwifiex_tdls_add_vht_oper(priv, peer, skb); |
471 | if (ret) { | 525 | if (ret) { |
@@ -544,6 +598,7 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, | |||
544 | sizeof(struct ieee_types_bss_co_2040) + | 598 | sizeof(struct ieee_types_bss_co_2040) + |
545 | sizeof(struct ieee80211_ht_operation) + | 599 | sizeof(struct ieee80211_ht_operation) + |
546 | sizeof(struct ieee80211_tdls_lnkie) + | 600 | sizeof(struct ieee80211_tdls_lnkie) + |
601 | sizeof(struct ieee80211_wmm_param_ie) + | ||
547 | extra_ies_len; | 602 | extra_ies_len; |
548 | 603 | ||
549 | if (priv->adapter->is_hw_11ac_capable) | 604 | if (priv->adapter->is_hw_11ac_capable) |
@@ -973,6 +1028,7 @@ mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, const u8 *peer) | |||
973 | } | 1028 | } |
974 | 1029 | ||
975 | mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN); | 1030 | mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN); |
1031 | mwifiex_auto_tdls_update_peer_status(priv, peer, TDLS_NOT_SETUP); | ||
976 | memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN); | 1032 | memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN); |
977 | tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK; | 1033 | tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK; |
978 | return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, | 1034 | return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, |
@@ -1017,6 +1073,8 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer) | |||
1017 | 1073 | ||
1018 | memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq)); | 1074 | memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq)); |
1019 | mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE); | 1075 | mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE); |
1076 | mwifiex_auto_tdls_update_peer_status(priv, peer, | ||
1077 | TDLS_SETUP_COMPLETE); | ||
1020 | } else { | 1078 | } else { |
1021 | dev_dbg(priv->adapter->dev, | 1079 | dev_dbg(priv->adapter->dev, |
1022 | "tdls: enable link %pM failed\n", peer); | 1080 | "tdls: enable link %pM failed\n", peer); |
@@ -1030,6 +1088,8 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer) | |||
1030 | mwifiex_del_sta_entry(priv, peer); | 1088 | mwifiex_del_sta_entry(priv, peer); |
1031 | } | 1089 | } |
1032 | mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN); | 1090 | mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN); |
1091 | mwifiex_auto_tdls_update_peer_status(priv, peer, | ||
1092 | TDLS_NOT_SETUP); | ||
1033 | 1093 | ||
1034 | return -1; | 1094 | return -1; |
1035 | } | 1095 | } |
@@ -1097,3 +1157,231 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv) | |||
1097 | 1157 | ||
1098 | mwifiex_del_all_sta_list(priv); | 1158 | mwifiex_del_all_sta_list(priv); |
1099 | } | 1159 | } |
1160 | |||
1161 | int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb) | ||
1162 | { | ||
1163 | struct mwifiex_auto_tdls_peer *peer; | ||
1164 | unsigned long flags; | ||
1165 | u8 mac[ETH_ALEN]; | ||
1166 | |||
1167 | ether_addr_copy(mac, skb->data); | ||
1168 | |||
1169 | spin_lock_irqsave(&priv->auto_tdls_lock, flags); | ||
1170 | list_for_each_entry(peer, &priv->auto_tdls_list, list) { | ||
1171 | if (!memcmp(mac, peer->mac_addr, ETH_ALEN)) { | ||
1172 | if (peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH && | ||
1173 | peer->tdls_status == TDLS_NOT_SETUP && | ||
1174 | (peer->failure_count < | ||
1175 | MWIFIEX_TDLS_MAX_FAIL_COUNT)) { | ||
1176 | peer->tdls_status = TDLS_SETUP_INPROGRESS; | ||
1177 | dev_dbg(priv->adapter->dev, | ||
1178 | "setup TDLS link, peer=%pM rssi=%d\n", | ||
1179 | peer->mac_addr, peer->rssi); | ||
1180 | |||
1181 | cfg80211_tdls_oper_request(priv->netdev, | ||
1182 | peer->mac_addr, | ||
1183 | NL80211_TDLS_SETUP, | ||
1184 | 0, GFP_ATOMIC); | ||
1185 | peer->do_setup = false; | ||
1186 | priv->check_tdls_tx = false; | ||
1187 | } else if (peer->failure_count < | ||
1188 | MWIFIEX_TDLS_MAX_FAIL_COUNT && | ||
1189 | peer->do_discover) { | ||
1190 | mwifiex_send_tdls_data_frame(priv, | ||
1191 | peer->mac_addr, | ||
1192 | WLAN_TDLS_DISCOVERY_REQUEST, | ||
1193 | 1, 0, NULL, 0); | ||
1194 | peer->do_discover = false; | ||
1195 | } | ||
1196 | } | ||
1197 | } | ||
1198 | spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); | ||
1199 | |||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | void mwifiex_flush_auto_tdls_list(struct mwifiex_private *priv) | ||
1204 | { | ||
1205 | struct mwifiex_auto_tdls_peer *peer, *tmp_node; | ||
1206 | unsigned long flags; | ||
1207 | |||
1208 | spin_lock_irqsave(&priv->auto_tdls_lock, flags); | ||
1209 | list_for_each_entry_safe(peer, tmp_node, &priv->auto_tdls_list, list) { | ||
1210 | list_del(&peer->list); | ||
1211 | kfree(peer); | ||
1212 | } | ||
1213 | |||
1214 | INIT_LIST_HEAD(&priv->auto_tdls_list); | ||
1215 | spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); | ||
1216 | priv->check_tdls_tx = false; | ||
1217 | } | ||
1218 | |||
1219 | void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac) | ||
1220 | { | ||
1221 | struct mwifiex_auto_tdls_peer *tdls_peer; | ||
1222 | unsigned long flags; | ||
1223 | |||
1224 | if (!priv->adapter->auto_tdls) | ||
1225 | return; | ||
1226 | |||
1227 | spin_lock_irqsave(&priv->auto_tdls_lock, flags); | ||
1228 | list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) { | ||
1229 | if (!memcmp(tdls_peer->mac_addr, mac, ETH_ALEN)) { | ||
1230 | tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS; | ||
1231 | tdls_peer->rssi_jiffies = jiffies; | ||
1232 | spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); | ||
1233 | return; | ||
1234 | } | ||
1235 | } | ||
1236 | |||
1237 | /* create new TDLS peer */ | ||
1238 | tdls_peer = kzalloc(sizeof(*tdls_peer), GFP_ATOMIC); | ||
1239 | if (tdls_peer) { | ||
1240 | ether_addr_copy(tdls_peer->mac_addr, mac); | ||
1241 | tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS; | ||
1242 | tdls_peer->rssi_jiffies = jiffies; | ||
1243 | INIT_LIST_HEAD(&tdls_peer->list); | ||
1244 | list_add_tail(&tdls_peer->list, &priv->auto_tdls_list); | ||
1245 | dev_dbg(priv->adapter->dev, "Add auto TDLS peer= %pM to list\n", | ||
1246 | mac); | ||
1247 | } | ||
1248 | |||
1249 | spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); | ||
1250 | } | ||
1251 | |||
1252 | void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv, | ||
1253 | const u8 *mac, u8 link_status) | ||
1254 | { | ||
1255 | struct mwifiex_auto_tdls_peer *peer; | ||
1256 | unsigned long flags; | ||
1257 | |||
1258 | if (!priv->adapter->auto_tdls) | ||
1259 | return; | ||
1260 | |||
1261 | spin_lock_irqsave(&priv->auto_tdls_lock, flags); | ||
1262 | list_for_each_entry(peer, &priv->auto_tdls_list, list) { | ||
1263 | if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) { | ||
1264 | if ((link_status == TDLS_NOT_SETUP) && | ||
1265 | (peer->tdls_status == TDLS_SETUP_INPROGRESS)) | ||
1266 | peer->failure_count++; | ||
1267 | else if (link_status == TDLS_SETUP_COMPLETE) | ||
1268 | peer->failure_count = 0; | ||
1269 | |||
1270 | peer->tdls_status = link_status; | ||
1271 | break; | ||
1272 | } | ||
1273 | } | ||
1274 | spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); | ||
1275 | } | ||
1276 | |||
1277 | void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv, | ||
1278 | u8 *mac, s8 snr, s8 nflr) | ||
1279 | { | ||
1280 | struct mwifiex_auto_tdls_peer *peer; | ||
1281 | unsigned long flags; | ||
1282 | |||
1283 | if (!priv->adapter->auto_tdls) | ||
1284 | return; | ||
1285 | |||
1286 | spin_lock_irqsave(&priv->auto_tdls_lock, flags); | ||
1287 | list_for_each_entry(peer, &priv->auto_tdls_list, list) { | ||
1288 | if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) { | ||
1289 | peer->rssi = nflr - snr; | ||
1290 | peer->rssi_jiffies = jiffies; | ||
1291 | break; | ||
1292 | } | ||
1293 | } | ||
1294 | spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); | ||
1295 | } | ||
1296 | |||
1297 | void mwifiex_check_auto_tdls(unsigned long context) | ||
1298 | { | ||
1299 | struct mwifiex_private *priv = (struct mwifiex_private *)context; | ||
1300 | struct mwifiex_auto_tdls_peer *tdls_peer; | ||
1301 | unsigned long flags; | ||
1302 | u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED; | ||
1303 | |||
1304 | if (WARN_ON_ONCE(!priv || !priv->adapter)) { | ||
1305 | pr_err("mwifiex: %s: adapter or private structure is NULL\n", | ||
1306 | __func__); | ||
1307 | return; | ||
1308 | } | ||
1309 | |||
1310 | if (unlikely(!priv->adapter->auto_tdls)) | ||
1311 | return; | ||
1312 | |||
1313 | if (!priv->auto_tdls_timer_active) { | ||
1314 | dev_dbg(priv->adapter->dev, | ||
1315 | "auto TDLS timer inactive; return"); | ||
1316 | return; | ||
1317 | } | ||
1318 | |||
1319 | priv->check_tdls_tx = false; | ||
1320 | |||
1321 | if (list_empty(&priv->auto_tdls_list)) { | ||
1322 | mod_timer(&priv->auto_tdls_timer, | ||
1323 | jiffies + | ||
1324 | msecs_to_jiffies(MWIFIEX_TIMER_10S)); | ||
1325 | return; | ||
1326 | } | ||
1327 | |||
1328 | spin_lock_irqsave(&priv->auto_tdls_lock, flags); | ||
1329 | list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) { | ||
1330 | if ((jiffies - tdls_peer->rssi_jiffies) > | ||
1331 | (MWIFIEX_AUTO_TDLS_IDLE_TIME * HZ)) { | ||
1332 | tdls_peer->rssi = 0; | ||
1333 | tdls_peer->do_discover = true; | ||
1334 | priv->check_tdls_tx = true; | ||
1335 | } | ||
1336 | |||
1337 | if (((tdls_peer->rssi >= MWIFIEX_TDLS_RSSI_LOW) || | ||
1338 | !tdls_peer->rssi) && | ||
1339 | tdls_peer->tdls_status == TDLS_SETUP_COMPLETE) { | ||
1340 | tdls_peer->tdls_status = TDLS_LINK_TEARDOWN; | ||
1341 | dev_dbg(priv->adapter->dev, | ||
1342 | "teardown TDLS link,peer=%pM rssi=%d\n", | ||
1343 | tdls_peer->mac_addr, -tdls_peer->rssi); | ||
1344 | tdls_peer->do_discover = true; | ||
1345 | priv->check_tdls_tx = true; | ||
1346 | cfg80211_tdls_oper_request(priv->netdev, | ||
1347 | tdls_peer->mac_addr, | ||
1348 | NL80211_TDLS_TEARDOWN, | ||
1349 | reason, GFP_ATOMIC); | ||
1350 | } else if (tdls_peer->rssi && | ||
1351 | tdls_peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH && | ||
1352 | tdls_peer->tdls_status == TDLS_NOT_SETUP && | ||
1353 | tdls_peer->failure_count < | ||
1354 | MWIFIEX_TDLS_MAX_FAIL_COUNT) { | ||
1355 | priv->check_tdls_tx = true; | ||
1356 | tdls_peer->do_setup = true; | ||
1357 | dev_dbg(priv->adapter->dev, | ||
1358 | "check TDLS with peer=%pM rssi=%d\n", | ||
1359 | tdls_peer->mac_addr, -tdls_peer->rssi); | ||
1360 | } | ||
1361 | } | ||
1362 | spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); | ||
1363 | |||
1364 | mod_timer(&priv->auto_tdls_timer, | ||
1365 | jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S)); | ||
1366 | } | ||
1367 | |||
1368 | void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv) | ||
1369 | { | ||
1370 | init_timer(&priv->auto_tdls_timer); | ||
1371 | priv->auto_tdls_timer.function = mwifiex_check_auto_tdls; | ||
1372 | priv->auto_tdls_timer.data = (unsigned long)priv; | ||
1373 | priv->auto_tdls_timer_active = true; | ||
1374 | mod_timer(&priv->auto_tdls_timer, | ||
1375 | jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S)); | ||
1376 | } | ||
1377 | |||
1378 | void mwifiex_clean_auto_tdls(struct mwifiex_private *priv) | ||
1379 | { | ||
1380 | if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && | ||
1381 | priv->adapter->auto_tdls && | ||
1382 | priv->bss_type == MWIFIEX_BSS_TYPE_STA) { | ||
1383 | priv->auto_tdls_timer_active = false; | ||
1384 | del_timer(&priv->auto_tdls_timer); | ||
1385 | mwifiex_flush_auto_tdls_list(priv); | ||
1386 | } | ||
1387 | } | ||
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 96a2126cc44b..6ae133333363 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c | |||
@@ -64,10 +64,6 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, | |||
64 | else | 64 | else |
65 | ret = mwifiex_process_sta_rx_packet(priv, skb); | 65 | ret = mwifiex_process_sta_rx_packet(priv, skb); |
66 | 66 | ||
67 | /* Decrement RX pending counter for each packet */ | ||
68 | if (adapter->if_ops.data_complete) | ||
69 | adapter->if_ops.data_complete(adapter); | ||
70 | |||
71 | return ret; | 67 | return ret; |
72 | } | 68 | } |
73 | EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); | 69 | EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); |
@@ -207,3 +203,34 @@ done: | |||
207 | } | 203 | } |
208 | EXPORT_SYMBOL_GPL(mwifiex_write_data_complete); | 204 | EXPORT_SYMBOL_GPL(mwifiex_write_data_complete); |
209 | 205 | ||
206 | void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, | ||
207 | void *event_body) | ||
208 | { | ||
209 | struct tx_status_event *tx_status = (void *)priv->adapter->event_body; | ||
210 | struct sk_buff *ack_skb; | ||
211 | unsigned long flags; | ||
212 | struct mwifiex_txinfo *tx_info; | ||
213 | |||
214 | if (!tx_status->tx_token_id) | ||
215 | return; | ||
216 | |||
217 | spin_lock_irqsave(&priv->ack_status_lock, flags); | ||
218 | ack_skb = idr_find(&priv->ack_status_frames, tx_status->tx_token_id); | ||
219 | if (ack_skb) | ||
220 | idr_remove(&priv->ack_status_frames, tx_status->tx_token_id); | ||
221 | spin_unlock_irqrestore(&priv->ack_status_lock, flags); | ||
222 | |||
223 | if (ack_skb) { | ||
224 | tx_info = MWIFIEX_SKB_TXCB(ack_skb); | ||
225 | |||
226 | if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS) { | ||
227 | /* consumes ack_skb */ | ||
228 | skb_complete_wifi_ack(ack_skb, !tx_status->status); | ||
229 | } else { | ||
230 | cfg80211_mgmt_tx_status(priv->wdev, tx_info->cookie, | ||
231 | ack_skb->data, ack_skb->len, | ||
232 | !tx_status->status, GFP_ATOMIC); | ||
233 | dev_kfree_skb_any(ack_skb); | ||
234 | } | ||
235 | } | ||
236 | } | ||
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index 300bab438011..0f347fdefa0a 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c | |||
@@ -167,7 +167,7 @@ mwifiex_set_ht_params(struct mwifiex_private *priv, | |||
167 | ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail, | 167 | ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail, |
168 | params->beacon.tail_len); | 168 | params->beacon.tail_len); |
169 | if (ht_ie) { | 169 | if (ht_ie) { |
170 | memcpy(&bss_cfg->ht_cap, ht_ie + 2, | 170 | memcpy(&bss_cfg->ht_cap, ht_ie, |
171 | sizeof(struct ieee80211_ht_cap)); | 171 | sizeof(struct ieee80211_ht_cap)); |
172 | cap_info = le16_to_cpu(bss_cfg->ht_cap.cap_info); | 172 | cap_info = le16_to_cpu(bss_cfg->ht_cap.cap_info); |
173 | memset(&bss_cfg->ht_cap.mcs, 0, | 173 | memset(&bss_cfg->ht_cap.mcs, 0, |
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 7c2b97660a03..38390cb85a90 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c | |||
@@ -172,6 +172,10 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) | |||
172 | return mwifiex_handle_event_ext_scan_report(priv, | 172 | return mwifiex_handle_event_ext_scan_report(priv, |
173 | adapter->event_skb->data); | 173 | adapter->event_skb->data); |
174 | break; | 174 | break; |
175 | case EVENT_TX_STATUS_REPORT: | ||
176 | dev_dbg(adapter->dev, "event: TX_STATUS Report\n"); | ||
177 | mwifiex_parse_tx_status_event(priv, adapter->event_body); | ||
178 | break; | ||
175 | default: | 179 | default: |
176 | dev_dbg(adapter->dev, "event: unknown event id: %#x\n", | 180 | dev_dbg(adapter->dev, "event: unknown event id: %#x\n", |
177 | eventcause); | 181 | eventcause); |
diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index ec7309d096ab..e7d326f5b96e 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c | |||
@@ -370,10 +370,16 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, | |||
370 | txpd->bss_num = priv->bss_num; | 370 | txpd->bss_num = priv->bss_num; |
371 | txpd->bss_type = priv->bss_type; | 371 | txpd->bss_type = priv->bss_type; |
372 | txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - len)); | 372 | txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - len)); |
373 | |||
374 | txpd->priority = (u8)skb->priority; | 373 | txpd->priority = (u8)skb->priority; |
374 | |||
375 | txpd->pkt_delay_2ms = mwifiex_wmm_compute_drv_pkt_delay(priv, skb); | 375 | txpd->pkt_delay_2ms = mwifiex_wmm_compute_drv_pkt_delay(priv, skb); |
376 | 376 | ||
377 | if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS || | ||
378 | tx_info->flags & MWIFIEX_BUF_FLAG_ACTION_TX_STATUS) { | ||
379 | txpd->tx_token_id = tx_info->ack_frame_id; | ||
380 | txpd->flags |= MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS; | ||
381 | } | ||
382 | |||
377 | if (txpd->priority < ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) | 383 | if (txpd->priority < ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) |
378 | /* | 384 | /* |
379 | * Set the priority specific tx_control field, setting of 0 will | 385 | * Set the priority specific tx_control field, setting of 0 will |
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 4371e12b36f3..1b56495ec872 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c | |||
@@ -27,6 +27,11 @@ static struct mwifiex_if_ops usb_ops; | |||
27 | static struct semaphore add_remove_card_sem; | 27 | static struct semaphore add_remove_card_sem; |
28 | 28 | ||
29 | static struct usb_device_id mwifiex_usb_table[] = { | 29 | static struct usb_device_id mwifiex_usb_table[] = { |
30 | /* 8766 */ | ||
31 | {USB_DEVICE(USB8XXX_VID, USB8766_PID_1)}, | ||
32 | {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8766_PID_2, | ||
33 | USB_CLASS_VENDOR_SPEC, | ||
34 | USB_SUBCLASS_VENDOR_SPEC, 0xff)}, | ||
30 | /* 8797 */ | 35 | /* 8797 */ |
31 | {USB_DEVICE(USB8XXX_VID, USB8797_PID_1)}, | 36 | {USB_DEVICE(USB8XXX_VID, USB8797_PID_1)}, |
32 | {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8797_PID_2, | 37 | {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8797_PID_2, |
@@ -125,8 +130,10 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter, | |||
125 | dev_err(dev, "DATA: skb->len too large\n"); | 130 | dev_err(dev, "DATA: skb->len too large\n"); |
126 | return -1; | 131 | return -1; |
127 | } | 132 | } |
128 | skb_queue_tail(&adapter->usb_rx_data_q, skb); | 133 | |
134 | skb_queue_tail(&adapter->rx_data_q, skb); | ||
129 | adapter->data_received = true; | 135 | adapter->data_received = true; |
136 | atomic_inc(&adapter->rx_pending); | ||
130 | break; | 137 | break; |
131 | default: | 138 | default: |
132 | dev_err(dev, "%s: unknown endport %#x\n", __func__, ep); | 139 | dev_err(dev, "%s: unknown endport %#x\n", __func__, ep); |
@@ -176,7 +183,6 @@ static void mwifiex_usb_rx_complete(struct urb *urb) | |||
176 | else | 183 | else |
177 | skb_put(skb, recv_length - skb->len); | 184 | skb_put(skb, recv_length - skb->len); |
178 | 185 | ||
179 | atomic_inc(&adapter->rx_pending); | ||
180 | status = mwifiex_usb_recv(adapter, skb, context->ep); | 186 | status = mwifiex_usb_recv(adapter, skb, context->ep); |
181 | 187 | ||
182 | dev_dbg(adapter->dev, "info: recv_length=%d, status=%d\n", | 188 | dev_dbg(adapter->dev, "info: recv_length=%d, status=%d\n", |
@@ -191,7 +197,6 @@ static void mwifiex_usb_rx_complete(struct urb *urb) | |||
191 | if (card->rx_cmd_ep == context->ep) | 197 | if (card->rx_cmd_ep == context->ep) |
192 | return; | 198 | return; |
193 | } else { | 199 | } else { |
194 | atomic_dec(&adapter->rx_pending); | ||
195 | if (status == -1) | 200 | if (status == -1) |
196 | dev_err(adapter->dev, | 201 | dev_err(adapter->dev, |
197 | "received data processing failed!\n"); | 202 | "received data processing failed!\n"); |
@@ -222,7 +227,13 @@ setup_for_next: | |||
222 | else | 227 | else |
223 | size = MWIFIEX_RX_DATA_BUF_SIZE; | 228 | size = MWIFIEX_RX_DATA_BUF_SIZE; |
224 | 229 | ||
225 | mwifiex_usb_submit_rx_urb(context, size); | 230 | if (card->rx_cmd_ep == context->ep) { |
231 | mwifiex_usb_submit_rx_urb(context, size); | ||
232 | } else { | ||
233 | context->skb = NULL; | ||
234 | if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING) | ||
235 | mwifiex_usb_submit_rx_urb(context, size); | ||
236 | } | ||
226 | 237 | ||
227 | return; | 238 | return; |
228 | } | 239 | } |
@@ -348,10 +359,12 @@ static int mwifiex_usb_probe(struct usb_interface *intf, | |||
348 | 359 | ||
349 | /* PID_1 is used for firmware downloading only */ | 360 | /* PID_1 is used for firmware downloading only */ |
350 | switch (id_product) { | 361 | switch (id_product) { |
362 | case USB8766_PID_1: | ||
351 | case USB8797_PID_1: | 363 | case USB8797_PID_1: |
352 | case USB8897_PID_1: | 364 | case USB8897_PID_1: |
353 | card->usb_boot_state = USB8XXX_FW_DNLD; | 365 | card->usb_boot_state = USB8XXX_FW_DNLD; |
354 | break; | 366 | break; |
367 | case USB8766_PID_2: | ||
355 | case USB8797_PID_2: | 368 | case USB8797_PID_2: |
356 | case USB8897_PID_2: | 369 | case USB8897_PID_2: |
357 | card->usb_boot_state = USB8XXX_FW_READY; | 370 | card->usb_boot_state = USB8XXX_FW_READY; |
@@ -780,6 +793,11 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) | |||
780 | adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; | 793 | adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; |
781 | strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME); | 794 | strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME); |
782 | break; | 795 | break; |
796 | case USB8766_PID_1: | ||
797 | case USB8766_PID_2: | ||
798 | adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; | ||
799 | strcpy(adapter->fw_name, USB8766_DEFAULT_FW_NAME); | ||
800 | break; | ||
783 | case USB8797_PID_1: | 801 | case USB8797_PID_1: |
784 | case USB8797_PID_2: | 802 | case USB8797_PID_2: |
785 | default: | 803 | default: |
@@ -962,19 +980,11 @@ static void mwifiex_submit_rx_urb(struct mwifiex_adapter *adapter, u8 ep) | |||
962 | static int mwifiex_usb_cmd_event_complete(struct mwifiex_adapter *adapter, | 980 | static int mwifiex_usb_cmd_event_complete(struct mwifiex_adapter *adapter, |
963 | struct sk_buff *skb) | 981 | struct sk_buff *skb) |
964 | { | 982 | { |
965 | atomic_dec(&adapter->rx_pending); | ||
966 | mwifiex_submit_rx_urb(adapter, MWIFIEX_USB_EP_CMD_EVENT); | 983 | mwifiex_submit_rx_urb(adapter, MWIFIEX_USB_EP_CMD_EVENT); |
967 | 984 | ||
968 | return 0; | 985 | return 0; |
969 | } | 986 | } |
970 | 987 | ||
971 | static int mwifiex_usb_data_complete(struct mwifiex_adapter *adapter) | ||
972 | { | ||
973 | atomic_dec(&adapter->rx_pending); | ||
974 | |||
975 | return 0; | ||
976 | } | ||
977 | |||
978 | /* This function wakes up the card. */ | 988 | /* This function wakes up the card. */ |
979 | static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) | 989 | static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) |
980 | { | 990 | { |
@@ -986,6 +996,20 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) | |||
986 | return 0; | 996 | return 0; |
987 | } | 997 | } |
988 | 998 | ||
999 | static void mwifiex_usb_submit_rem_rx_urbs(struct mwifiex_adapter *adapter) | ||
1000 | { | ||
1001 | struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; | ||
1002 | int i; | ||
1003 | struct urb_context *ctx; | ||
1004 | |||
1005 | for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { | ||
1006 | if (card->rx_data_list[i].skb) | ||
1007 | continue; | ||
1008 | ctx = &card->rx_data_list[i]; | ||
1009 | mwifiex_usb_submit_rx_urb(ctx, MWIFIEX_RX_DATA_BUF_SIZE); | ||
1010 | } | ||
1011 | } | ||
1012 | |||
989 | static struct mwifiex_if_ops usb_ops = { | 1013 | static struct mwifiex_if_ops usb_ops = { |
990 | .register_dev = mwifiex_register_dev, | 1014 | .register_dev = mwifiex_register_dev, |
991 | .unregister_dev = mwifiex_unregister_dev, | 1015 | .unregister_dev = mwifiex_unregister_dev, |
@@ -996,8 +1020,8 @@ static struct mwifiex_if_ops usb_ops = { | |||
996 | .dnld_fw = mwifiex_usb_dnld_fw, | 1020 | .dnld_fw = mwifiex_usb_dnld_fw, |
997 | .cmdrsp_complete = mwifiex_usb_cmd_event_complete, | 1021 | .cmdrsp_complete = mwifiex_usb_cmd_event_complete, |
998 | .event_complete = mwifiex_usb_cmd_event_complete, | 1022 | .event_complete = mwifiex_usb_cmd_event_complete, |
999 | .data_complete = mwifiex_usb_data_complete, | ||
1000 | .host_to_card = mwifiex_usb_host_to_card, | 1023 | .host_to_card = mwifiex_usb_host_to_card, |
1024 | .submit_rem_rx_urbs = mwifiex_usb_submit_rem_rx_urbs, | ||
1001 | }; | 1025 | }; |
1002 | 1026 | ||
1003 | /* This function initializes the USB driver module. | 1027 | /* This function initializes the USB driver module. |
@@ -1048,5 +1072,6 @@ MODULE_AUTHOR("Marvell International Ltd."); | |||
1048 | MODULE_DESCRIPTION("Marvell WiFi-Ex USB Driver version" USB_VERSION); | 1072 | MODULE_DESCRIPTION("Marvell WiFi-Ex USB Driver version" USB_VERSION); |
1049 | MODULE_VERSION(USB_VERSION); | 1073 | MODULE_VERSION(USB_VERSION); |
1050 | MODULE_LICENSE("GPL v2"); | 1074 | MODULE_LICENSE("GPL v2"); |
1075 | MODULE_FIRMWARE(USB8766_DEFAULT_FW_NAME); | ||
1051 | MODULE_FIRMWARE(USB8797_DEFAULT_FW_NAME); | 1076 | MODULE_FIRMWARE(USB8797_DEFAULT_FW_NAME); |
1052 | MODULE_FIRMWARE(USB8897_DEFAULT_FW_NAME); | 1077 | MODULE_FIRMWARE(USB8897_DEFAULT_FW_NAME); |
diff --git a/drivers/net/wireless/mwifiex/usb.h b/drivers/net/wireless/mwifiex/usb.h index 4c41c2a193c5..a7cbba1355af 100644 --- a/drivers/net/wireless/mwifiex/usb.h +++ b/drivers/net/wireless/mwifiex/usb.h | |||
@@ -24,6 +24,8 @@ | |||
24 | 24 | ||
25 | #define USB8XXX_VID 0x1286 | 25 | #define USB8XXX_VID 0x1286 |
26 | 26 | ||
27 | #define USB8766_PID_1 0x2041 | ||
28 | #define USB8766_PID_2 0x2042 | ||
27 | #define USB8797_PID_1 0x2043 | 29 | #define USB8797_PID_1 0x2043 |
28 | #define USB8797_PID_2 0x2044 | 30 | #define USB8797_PID_2 0x2044 |
29 | #define USB8897_PID_1 0x2045 | 31 | #define USB8897_PID_1 0x2045 |
@@ -37,6 +39,7 @@ | |||
37 | #define MWIFIEX_RX_DATA_URB 6 | 39 | #define MWIFIEX_RX_DATA_URB 6 |
38 | #define MWIFIEX_USB_TIMEOUT 100 | 40 | #define MWIFIEX_USB_TIMEOUT 100 |
39 | 41 | ||
42 | #define USB8766_DEFAULT_FW_NAME "mrvl/usb8766_uapsta.bin" | ||
40 | #define USB8797_DEFAULT_FW_NAME "mrvl/usb8797_uapsta.bin" | 43 | #define USB8797_DEFAULT_FW_NAME "mrvl/usb8797_uapsta.bin" |
41 | #define USB8897_DEFAULT_FW_NAME "mrvl/usb8897_uapsta.bin" | 44 | #define USB8897_DEFAULT_FW_NAME "mrvl/usb8897_uapsta.bin" |
42 | 45 | ||
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index ec79c49de097..b1768fbf98f2 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c | |||
@@ -141,6 +141,38 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, | |||
141 | return 0; | 141 | return 0; |
142 | } | 142 | } |
143 | 143 | ||
144 | static int | ||
145 | mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len, | ||
146 | struct rxpd *rx_pd) | ||
147 | { | ||
148 | u16 stype; | ||
149 | u8 category, action_code; | ||
150 | struct ieee80211_hdr *ieee_hdr = (void *)payload; | ||
151 | |||
152 | stype = (le16_to_cpu(ieee_hdr->frame_control) & IEEE80211_FCTL_STYPE); | ||
153 | |||
154 | switch (stype) { | ||
155 | case IEEE80211_STYPE_ACTION: | ||
156 | category = *(payload + sizeof(struct ieee80211_hdr)); | ||
157 | action_code = *(payload + sizeof(struct ieee80211_hdr) + 1); | ||
158 | if (category == WLAN_CATEGORY_PUBLIC && | ||
159 | action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { | ||
160 | dev_dbg(priv->adapter->dev, | ||
161 | "TDLS discovery response %pM nf=%d, snr=%d\n", | ||
162 | ieee_hdr->addr2, rx_pd->nf, rx_pd->snr); | ||
163 | mwifiex_auto_tdls_update_peer_signal(priv, | ||
164 | ieee_hdr->addr2, | ||
165 | rx_pd->snr, | ||
166 | rx_pd->nf); | ||
167 | } | ||
168 | break; | ||
169 | default: | ||
170 | dev_dbg(priv->adapter->dev, | ||
171 | "unknown mgmt frame subytpe %#x\n", stype); | ||
172 | } | ||
173 | |||
174 | return 0; | ||
175 | } | ||
144 | /* | 176 | /* |
145 | * This function processes the received management packet and send it | 177 | * This function processes the received management packet and send it |
146 | * to the kernel. | 178 | * to the kernel. |
@@ -151,6 +183,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, | |||
151 | { | 183 | { |
152 | struct rxpd *rx_pd; | 184 | struct rxpd *rx_pd; |
153 | u16 pkt_len; | 185 | u16 pkt_len; |
186 | struct ieee80211_hdr *ieee_hdr; | ||
154 | 187 | ||
155 | if (!skb) | 188 | if (!skb) |
156 | return -1; | 189 | return -1; |
@@ -162,6 +195,11 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, | |||
162 | 195 | ||
163 | pkt_len = le16_to_cpu(rx_pd->rx_pkt_length); | 196 | pkt_len = le16_to_cpu(rx_pd->rx_pkt_length); |
164 | 197 | ||
198 | ieee_hdr = (void *)skb->data; | ||
199 | if (ieee80211_is_mgmt(ieee_hdr->frame_control)) { | ||
200 | mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr, | ||
201 | pkt_len, rx_pd); | ||
202 | } | ||
165 | /* Remove address4 */ | 203 | /* Remove address4 */ |
166 | memmove(skb->data + sizeof(struct ieee80211_hdr_3addr), | 204 | memmove(skb->data + sizeof(struct ieee80211_hdr_3addr), |
167 | skb->data + sizeof(struct ieee80211_hdr), | 205 | skb->data + sizeof(struct ieee80211_hdr), |
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 94c98a86ebbe..dc1f2adfafc2 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c | |||
@@ -523,6 +523,13 @@ static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv) | |||
523 | } | 523 | } |
524 | } | 524 | } |
525 | 525 | ||
526 | static int mwifiex_free_ack_frame(int id, void *p, void *data) | ||
527 | { | ||
528 | pr_warn("Have pending ack frames!\n"); | ||
529 | kfree_skb(p); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
526 | /* | 533 | /* |
527 | * This function cleans up the Tx and Rx queues. | 534 | * This function cleans up the Tx and Rx queues. |
528 | * | 535 | * |
@@ -558,6 +565,9 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) | |||
558 | 565 | ||
559 | skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) | 566 | skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) |
560 | mwifiex_write_data_complete(priv->adapter, skb, 0, -1); | 567 | mwifiex_write_data_complete(priv->adapter, skb, 0, -1); |
568 | |||
569 | idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL); | ||
570 | idr_destroy(&priv->ack_status_frames); | ||
561 | } | 571 | } |
562 | 572 | ||
563 | /* | 573 | /* |
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ef1104476bd8..b8d1e04aa9b9 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -5548,7 +5548,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
5548 | return rc; | 5548 | return rc; |
5549 | } | 5549 | } |
5550 | 5550 | ||
5551 | static void mwl8k_sw_scan_start(struct ieee80211_hw *hw) | 5551 | static void mwl8k_sw_scan_start(struct ieee80211_hw *hw, |
5552 | struct ieee80211_vif *vif, | ||
5553 | const u8 *mac_addr) | ||
5552 | { | 5554 | { |
5553 | struct mwl8k_priv *priv = hw->priv; | 5555 | struct mwl8k_priv *priv = hw->priv; |
5554 | u8 tmp; | 5556 | u8 tmp; |
@@ -5565,7 +5567,8 @@ static void mwl8k_sw_scan_start(struct ieee80211_hw *hw) | |||
5565 | priv->sw_scan_start = true; | 5567 | priv->sw_scan_start = true; |
5566 | } | 5568 | } |
5567 | 5569 | ||
5568 | static void mwl8k_sw_scan_complete(struct ieee80211_hw *hw) | 5570 | static void mwl8k_sw_scan_complete(struct ieee80211_hw *hw, |
5571 | struct ieee80211_vif *vif) | ||
5569 | { | 5572 | { |
5570 | struct mwl8k_priv *priv = hw->priv; | 5573 | struct mwl8k_priv *priv = hw->priv; |
5571 | u8 tmp; | 5574 | u8 tmp; |
diff --git a/drivers/net/wireless/p54/net2280.h b/drivers/net/wireless/p54/net2280.h deleted file mode 100644 index aedfaf24f386..000000000000 --- a/drivers/net/wireless/p54/net2280.h +++ /dev/null | |||
@@ -1,451 +0,0 @@ | |||
1 | #ifndef NET2280_H | ||
2 | #define NET2280_H | ||
3 | /* | ||
4 | * NetChip 2280 high/full speed USB device controller. | ||
5 | * Unlike many such controllers, this one talks PCI. | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) | ||
10 | * Copyright (C) 2003 David Brownell | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
24 | */ | ||
25 | |||
26 | /*-------------------------------------------------------------------------*/ | ||
27 | |||
28 | /* NET2280 MEMORY MAPPED REGISTERS | ||
29 | * | ||
30 | * The register layout came from the chip documentation, and the bit | ||
31 | * number definitions were extracted from chip specification. | ||
32 | * | ||
33 | * Use the shift operator ('<<') to build bit masks, with readl/writel | ||
34 | * to access the registers through PCI. | ||
35 | */ | ||
36 | |||
37 | /* main registers, BAR0 + 0x0000 */ | ||
38 | struct net2280_regs { | ||
39 | /* offset 0x0000 */ | ||
40 | __le32 devinit; | ||
41 | #define LOCAL_CLOCK_FREQUENCY 8 | ||
42 | #define FORCE_PCI_RESET 7 | ||
43 | #define PCI_ID 6 | ||
44 | #define PCI_ENABLE 5 | ||
45 | #define FIFO_SOFT_RESET 4 | ||
46 | #define CFG_SOFT_RESET 3 | ||
47 | #define PCI_SOFT_RESET 2 | ||
48 | #define USB_SOFT_RESET 1 | ||
49 | #define M8051_RESET 0 | ||
50 | __le32 eectl; | ||
51 | #define EEPROM_ADDRESS_WIDTH 23 | ||
52 | #define EEPROM_CHIP_SELECT_ACTIVE 22 | ||
53 | #define EEPROM_PRESENT 21 | ||
54 | #define EEPROM_VALID 20 | ||
55 | #define EEPROM_BUSY 19 | ||
56 | #define EEPROM_CHIP_SELECT_ENABLE 18 | ||
57 | #define EEPROM_BYTE_READ_START 17 | ||
58 | #define EEPROM_BYTE_WRITE_START 16 | ||
59 | #define EEPROM_READ_DATA 8 | ||
60 | #define EEPROM_WRITE_DATA 0 | ||
61 | __le32 eeclkfreq; | ||
62 | u32 _unused0; | ||
63 | /* offset 0x0010 */ | ||
64 | |||
65 | __le32 pciirqenb0; /* interrupt PCI master ... */ | ||
66 | #define SETUP_PACKET_INTERRUPT_ENABLE 7 | ||
67 | #define ENDPOINT_F_INTERRUPT_ENABLE 6 | ||
68 | #define ENDPOINT_E_INTERRUPT_ENABLE 5 | ||
69 | #define ENDPOINT_D_INTERRUPT_ENABLE 4 | ||
70 | #define ENDPOINT_C_INTERRUPT_ENABLE 3 | ||
71 | #define ENDPOINT_B_INTERRUPT_ENABLE 2 | ||
72 | #define ENDPOINT_A_INTERRUPT_ENABLE 1 | ||
73 | #define ENDPOINT_0_INTERRUPT_ENABLE 0 | ||
74 | __le32 pciirqenb1; | ||
75 | #define PCI_INTERRUPT_ENABLE 31 | ||
76 | #define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 | ||
77 | #define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 | ||
78 | #define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 | ||
79 | #define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 | ||
80 | #define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 | ||
81 | #define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18 | ||
82 | #define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 | ||
83 | #define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 | ||
84 | #define GPIO_INTERRUPT_ENABLE 13 | ||
85 | #define DMA_D_INTERRUPT_ENABLE 12 | ||
86 | #define DMA_C_INTERRUPT_ENABLE 11 | ||
87 | #define DMA_B_INTERRUPT_ENABLE 10 | ||
88 | #define DMA_A_INTERRUPT_ENABLE 9 | ||
89 | #define EEPROM_DONE_INTERRUPT_ENABLE 8 | ||
90 | #define VBUS_INTERRUPT_ENABLE 7 | ||
91 | #define CONTROL_STATUS_INTERRUPT_ENABLE 6 | ||
92 | #define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 | ||
93 | #define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 | ||
94 | #define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 | ||
95 | #define RESUME_INTERRUPT_ENABLE 1 | ||
96 | #define SOF_INTERRUPT_ENABLE 0 | ||
97 | __le32 cpu_irqenb0; /* ... or onboard 8051 */ | ||
98 | #define SETUP_PACKET_INTERRUPT_ENABLE 7 | ||
99 | #define ENDPOINT_F_INTERRUPT_ENABLE 6 | ||
100 | #define ENDPOINT_E_INTERRUPT_ENABLE 5 | ||
101 | #define ENDPOINT_D_INTERRUPT_ENABLE 4 | ||
102 | #define ENDPOINT_C_INTERRUPT_ENABLE 3 | ||
103 | #define ENDPOINT_B_INTERRUPT_ENABLE 2 | ||
104 | #define ENDPOINT_A_INTERRUPT_ENABLE 1 | ||
105 | #define ENDPOINT_0_INTERRUPT_ENABLE 0 | ||
106 | __le32 cpu_irqenb1; | ||
107 | #define CPU_INTERRUPT_ENABLE 31 | ||
108 | #define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 | ||
109 | #define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 | ||
110 | #define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 | ||
111 | #define PCI_INTA_INTERRUPT_ENABLE 24 | ||
112 | #define PCI_PME_INTERRUPT_ENABLE 23 | ||
113 | #define PCI_SERR_INTERRUPT_ENABLE 22 | ||
114 | #define PCI_PERR_INTERRUPT_ENABLE 21 | ||
115 | #define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 | ||
116 | #define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 | ||
117 | #define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 | ||
118 | #define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 | ||
119 | #define GPIO_INTERRUPT_ENABLE 13 | ||
120 | #define DMA_D_INTERRUPT_ENABLE 12 | ||
121 | #define DMA_C_INTERRUPT_ENABLE 11 | ||
122 | #define DMA_B_INTERRUPT_ENABLE 10 | ||
123 | #define DMA_A_INTERRUPT_ENABLE 9 | ||
124 | #define EEPROM_DONE_INTERRUPT_ENABLE 8 | ||
125 | #define VBUS_INTERRUPT_ENABLE 7 | ||
126 | #define CONTROL_STATUS_INTERRUPT_ENABLE 6 | ||
127 | #define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 | ||
128 | #define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 | ||
129 | #define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 | ||
130 | #define RESUME_INTERRUPT_ENABLE 1 | ||
131 | #define SOF_INTERRUPT_ENABLE 0 | ||
132 | |||
133 | /* offset 0x0020 */ | ||
134 | u32 _unused1; | ||
135 | __le32 usbirqenb1; | ||
136 | #define USB_INTERRUPT_ENABLE 31 | ||
137 | #define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 | ||
138 | #define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 | ||
139 | #define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 | ||
140 | #define PCI_INTA_INTERRUPT_ENABLE 24 | ||
141 | #define PCI_PME_INTERRUPT_ENABLE 23 | ||
142 | #define PCI_SERR_INTERRUPT_ENABLE 22 | ||
143 | #define PCI_PERR_INTERRUPT_ENABLE 21 | ||
144 | #define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 | ||
145 | #define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 | ||
146 | #define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 | ||
147 | #define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 | ||
148 | #define GPIO_INTERRUPT_ENABLE 13 | ||
149 | #define DMA_D_INTERRUPT_ENABLE 12 | ||
150 | #define DMA_C_INTERRUPT_ENABLE 11 | ||
151 | #define DMA_B_INTERRUPT_ENABLE 10 | ||
152 | #define DMA_A_INTERRUPT_ENABLE 9 | ||
153 | #define EEPROM_DONE_INTERRUPT_ENABLE 8 | ||
154 | #define VBUS_INTERRUPT_ENABLE 7 | ||
155 | #define CONTROL_STATUS_INTERRUPT_ENABLE 6 | ||
156 | #define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 | ||
157 | #define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 | ||
158 | #define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 | ||
159 | #define RESUME_INTERRUPT_ENABLE 1 | ||
160 | #define SOF_INTERRUPT_ENABLE 0 | ||
161 | __le32 irqstat0; | ||
162 | #define INTA_ASSERTED 12 | ||
163 | #define SETUP_PACKET_INTERRUPT 7 | ||
164 | #define ENDPOINT_F_INTERRUPT 6 | ||
165 | #define ENDPOINT_E_INTERRUPT 5 | ||
166 | #define ENDPOINT_D_INTERRUPT 4 | ||
167 | #define ENDPOINT_C_INTERRUPT 3 | ||
168 | #define ENDPOINT_B_INTERRUPT 2 | ||
169 | #define ENDPOINT_A_INTERRUPT 1 | ||
170 | #define ENDPOINT_0_INTERRUPT 0 | ||
171 | __le32 irqstat1; | ||
172 | #define POWER_STATE_CHANGE_INTERRUPT 27 | ||
173 | #define PCI_ARBITER_TIMEOUT_INTERRUPT 26 | ||
174 | #define PCI_PARITY_ERROR_INTERRUPT 25 | ||
175 | #define PCI_INTA_INTERRUPT 24 | ||
176 | #define PCI_PME_INTERRUPT 23 | ||
177 | #define PCI_SERR_INTERRUPT 22 | ||
178 | #define PCI_PERR_INTERRUPT 21 | ||
179 | #define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20 | ||
180 | #define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 | ||
181 | #define PCI_RETRY_ABORT_INTERRUPT 17 | ||
182 | #define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 | ||
183 | #define GPIO_INTERRUPT 13 | ||
184 | #define DMA_D_INTERRUPT 12 | ||
185 | #define DMA_C_INTERRUPT 11 | ||
186 | #define DMA_B_INTERRUPT 10 | ||
187 | #define DMA_A_INTERRUPT 9 | ||
188 | #define EEPROM_DONE_INTERRUPT 8 | ||
189 | #define VBUS_INTERRUPT 7 | ||
190 | #define CONTROL_STATUS_INTERRUPT 6 | ||
191 | #define ROOT_PORT_RESET_INTERRUPT 4 | ||
192 | #define SUSPEND_REQUEST_INTERRUPT 3 | ||
193 | #define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 | ||
194 | #define RESUME_INTERRUPT 1 | ||
195 | #define SOF_INTERRUPT 0 | ||
196 | /* offset 0x0030 */ | ||
197 | __le32 idxaddr; | ||
198 | __le32 idxdata; | ||
199 | __le32 fifoctl; | ||
200 | #define PCI_BASE2_RANGE 16 | ||
201 | #define IGNORE_FIFO_AVAILABILITY 3 | ||
202 | #define PCI_BASE2_SELECT 2 | ||
203 | #define FIFO_CONFIGURATION_SELECT 0 | ||
204 | u32 _unused2; | ||
205 | /* offset 0x0040 */ | ||
206 | __le32 memaddr; | ||
207 | #define START 28 | ||
208 | #define DIRECTION 27 | ||
209 | #define FIFO_DIAGNOSTIC_SELECT 24 | ||
210 | #define MEMORY_ADDRESS 0 | ||
211 | __le32 memdata0; | ||
212 | __le32 memdata1; | ||
213 | u32 _unused3; | ||
214 | /* offset 0x0050 */ | ||
215 | __le32 gpioctl; | ||
216 | #define GPIO3_LED_SELECT 12 | ||
217 | #define GPIO3_INTERRUPT_ENABLE 11 | ||
218 | #define GPIO2_INTERRUPT_ENABLE 10 | ||
219 | #define GPIO1_INTERRUPT_ENABLE 9 | ||
220 | #define GPIO0_INTERRUPT_ENABLE 8 | ||
221 | #define GPIO3_OUTPUT_ENABLE 7 | ||
222 | #define GPIO2_OUTPUT_ENABLE 6 | ||
223 | #define GPIO1_OUTPUT_ENABLE 5 | ||
224 | #define GPIO0_OUTPUT_ENABLE 4 | ||
225 | #define GPIO3_DATA 3 | ||
226 | #define GPIO2_DATA 2 | ||
227 | #define GPIO1_DATA 1 | ||
228 | #define GPIO0_DATA 0 | ||
229 | __le32 gpiostat; | ||
230 | #define GPIO3_INTERRUPT 3 | ||
231 | #define GPIO2_INTERRUPT 2 | ||
232 | #define GPIO1_INTERRUPT 1 | ||
233 | #define GPIO0_INTERRUPT 0 | ||
234 | } __packed; | ||
235 | |||
236 | /* usb control, BAR0 + 0x0080 */ | ||
237 | struct net2280_usb_regs { | ||
238 | /* offset 0x0080 */ | ||
239 | __le32 stdrsp; | ||
240 | #define STALL_UNSUPPORTED_REQUESTS 31 | ||
241 | #define SET_TEST_MODE 16 | ||
242 | #define GET_OTHER_SPEED_CONFIGURATION 15 | ||
243 | #define GET_DEVICE_QUALIFIER 14 | ||
244 | #define SET_ADDRESS 13 | ||
245 | #define ENDPOINT_SET_CLEAR_HALT 12 | ||
246 | #define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11 | ||
247 | #define GET_STRING_DESCRIPTOR_2 10 | ||
248 | #define GET_STRING_DESCRIPTOR_1 9 | ||
249 | #define GET_STRING_DESCRIPTOR_0 8 | ||
250 | #define GET_SET_INTERFACE 6 | ||
251 | #define GET_SET_CONFIGURATION 5 | ||
252 | #define GET_CONFIGURATION_DESCRIPTOR 4 | ||
253 | #define GET_DEVICE_DESCRIPTOR 3 | ||
254 | #define GET_ENDPOINT_STATUS 2 | ||
255 | #define GET_INTERFACE_STATUS 1 | ||
256 | #define GET_DEVICE_STATUS 0 | ||
257 | __le32 prodvendid; | ||
258 | #define PRODUCT_ID 16 | ||
259 | #define VENDOR_ID 0 | ||
260 | __le32 relnum; | ||
261 | __le32 usbctl; | ||
262 | #define SERIAL_NUMBER_INDEX 16 | ||
263 | #define PRODUCT_ID_STRING_ENABLE 13 | ||
264 | #define VENDOR_ID_STRING_ENABLE 12 | ||
265 | #define USB_ROOT_PORT_WAKEUP_ENABLE 11 | ||
266 | #define VBUS_PIN 10 | ||
267 | #define TIMED_DISCONNECT 9 | ||
268 | #define SUSPEND_IMMEDIATELY 7 | ||
269 | #define SELF_POWERED_USB_DEVICE 6 | ||
270 | #define REMOTE_WAKEUP_SUPPORT 5 | ||
271 | #define PME_POLARITY 4 | ||
272 | #define USB_DETECT_ENABLE 3 | ||
273 | #define PME_WAKEUP_ENABLE 2 | ||
274 | #define DEVICE_REMOTE_WAKEUP_ENABLE 1 | ||
275 | #define SELF_POWERED_STATUS 0 | ||
276 | /* offset 0x0090 */ | ||
277 | __le32 usbstat; | ||
278 | #define HIGH_SPEED 7 | ||
279 | #define FULL_SPEED 6 | ||
280 | #define GENERATE_RESUME 5 | ||
281 | #define GENERATE_DEVICE_REMOTE_WAKEUP 4 | ||
282 | __le32 xcvrdiag; | ||
283 | #define FORCE_HIGH_SPEED_MODE 31 | ||
284 | #define FORCE_FULL_SPEED_MODE 30 | ||
285 | #define USB_TEST_MODE 24 | ||
286 | #define LINE_STATE 16 | ||
287 | #define TRANSCEIVER_OPERATION_MODE 2 | ||
288 | #define TRANSCEIVER_SELECT 1 | ||
289 | #define TERMINATION_SELECT 0 | ||
290 | __le32 setup0123; | ||
291 | __le32 setup4567; | ||
292 | /* offset 0x0090 */ | ||
293 | u32 _unused0; | ||
294 | __le32 ouraddr; | ||
295 | #define FORCE_IMMEDIATE 7 | ||
296 | #define OUR_USB_ADDRESS 0 | ||
297 | __le32 ourconfig; | ||
298 | } __packed; | ||
299 | |||
300 | /* pci control, BAR0 + 0x0100 */ | ||
301 | struct net2280_pci_regs { | ||
302 | /* offset 0x0100 */ | ||
303 | __le32 pcimstctl; | ||
304 | #define PCI_ARBITER_PARK_SELECT 13 | ||
305 | #define PCI_MULTI LEVEL_ARBITER 12 | ||
306 | #define PCI_RETRY_ABORT_ENABLE 11 | ||
307 | #define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10 | ||
308 | #define DMA_READ_MULTIPLE_ENABLE 9 | ||
309 | #define DMA_READ_LINE_ENABLE 8 | ||
310 | #define PCI_MASTER_COMMAND_SELECT 6 | ||
311 | #define MEM_READ_OR_WRITE 0 | ||
312 | #define IO_READ_OR_WRITE 1 | ||
313 | #define CFG_READ_OR_WRITE 2 | ||
314 | #define PCI_MASTER_START 5 | ||
315 | #define PCI_MASTER_READ_WRITE 4 | ||
316 | #define PCI_MASTER_WRITE 0 | ||
317 | #define PCI_MASTER_READ 1 | ||
318 | #define PCI_MASTER_BYTE_WRITE_ENABLES 0 | ||
319 | __le32 pcimstaddr; | ||
320 | __le32 pcimstdata; | ||
321 | __le32 pcimststat; | ||
322 | #define PCI_ARBITER_CLEAR 2 | ||
323 | #define PCI_EXTERNAL_ARBITER 1 | ||
324 | #define PCI_HOST_MODE 0 | ||
325 | } __packed; | ||
326 | |||
327 | /* dma control, BAR0 + 0x0180 ... array of four structs like this, | ||
328 | * for channels 0..3. see also struct net2280_dma: descriptor | ||
329 | * that can be loaded into some of these registers. | ||
330 | */ | ||
331 | struct net2280_dma_regs { /* [11.7] */ | ||
332 | /* offset 0x0180, 0x01a0, 0x01c0, 0x01e0, */ | ||
333 | __le32 dmactl; | ||
334 | #define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 | ||
335 | #define DMA_CLEAR_COUNT_ENABLE 21 | ||
336 | #define DESCRIPTOR_POLLING_RATE 19 | ||
337 | #define POLL_CONTINUOUS 0 | ||
338 | #define POLL_1_USEC 1 | ||
339 | #define POLL_100_USEC 2 | ||
340 | #define POLL_1_MSEC 3 | ||
341 | #define DMA_VALID_BIT_POLLING_ENABLE 18 | ||
342 | #define DMA_VALID_BIT_ENABLE 17 | ||
343 | #define DMA_SCATTER_GATHER_ENABLE 16 | ||
344 | #define DMA_OUT_AUTO_START_ENABLE 4 | ||
345 | #define DMA_PREEMPT_ENABLE 3 | ||
346 | #define DMA_FIFO_VALIDATE 2 | ||
347 | #define DMA_ENABLE 1 | ||
348 | #define DMA_ADDRESS_HOLD 0 | ||
349 | __le32 dmastat; | ||
350 | #define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 | ||
351 | #define DMA_TRANSACTION_DONE_INTERRUPT 24 | ||
352 | #define DMA_ABORT 1 | ||
353 | #define DMA_START 0 | ||
354 | u32 _unused0[2]; | ||
355 | /* offset 0x0190, 0x01b0, 0x01d0, 0x01f0, */ | ||
356 | __le32 dmacount; | ||
357 | #define VALID_BIT 31 | ||
358 | #define DMA_DIRECTION 30 | ||
359 | #define DMA_DONE_INTERRUPT_ENABLE 29 | ||
360 | #define END_OF_CHAIN 28 | ||
361 | #define DMA_BYTE_COUNT_MASK ((1<<24)-1) | ||
362 | #define DMA_BYTE_COUNT 0 | ||
363 | __le32 dmaaddr; | ||
364 | __le32 dmadesc; | ||
365 | u32 _unused1; | ||
366 | } __packed; | ||
367 | |||
368 | /* dedicated endpoint registers, BAR0 + 0x0200 */ | ||
369 | |||
370 | struct net2280_dep_regs { /* [11.8] */ | ||
371 | /* offset 0x0200, 0x0210, 0x220, 0x230, 0x240 */ | ||
372 | __le32 dep_cfg; | ||
373 | /* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */ | ||
374 | __le32 dep_rsp; | ||
375 | u32 _unused[2]; | ||
376 | } __packed; | ||
377 | |||
378 | /* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs | ||
379 | * like this, for ep0 then the configurable endpoints A..F | ||
380 | * ep0 reserved for control; E and F have only 64 bytes of fifo | ||
381 | */ | ||
382 | struct net2280_ep_regs { /* [11.9] */ | ||
383 | /* offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 */ | ||
384 | __le32 ep_cfg; | ||
385 | #define ENDPOINT_BYTE_COUNT 16 | ||
386 | #define ENDPOINT_ENABLE 10 | ||
387 | #define ENDPOINT_TYPE 8 | ||
388 | #define ENDPOINT_DIRECTION 7 | ||
389 | #define ENDPOINT_NUMBER 0 | ||
390 | __le32 ep_rsp; | ||
391 | #define SET_NAK_OUT_PACKETS 15 | ||
392 | #define SET_EP_HIDE_STATUS_PHASE 14 | ||
393 | #define SET_EP_FORCE_CRC_ERROR 13 | ||
394 | #define SET_INTERRUPT_MODE 12 | ||
395 | #define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 | ||
396 | #define SET_NAK_OUT_PACKETS_MODE 10 | ||
397 | #define SET_ENDPOINT_TOGGLE 9 | ||
398 | #define SET_ENDPOINT_HALT 8 | ||
399 | #define CLEAR_NAK_OUT_PACKETS 7 | ||
400 | #define CLEAR_EP_HIDE_STATUS_PHASE 6 | ||
401 | #define CLEAR_EP_FORCE_CRC_ERROR 5 | ||
402 | #define CLEAR_INTERRUPT_MODE 4 | ||
403 | #define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 | ||
404 | #define CLEAR_NAK_OUT_PACKETS_MODE 2 | ||
405 | #define CLEAR_ENDPOINT_TOGGLE 1 | ||
406 | #define CLEAR_ENDPOINT_HALT 0 | ||
407 | __le32 ep_irqenb; | ||
408 | #define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6 | ||
409 | #define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5 | ||
410 | #define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 | ||
411 | #define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 | ||
412 | #define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1 | ||
413 | #define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 | ||
414 | __le32 ep_stat; | ||
415 | #define FIFO_VALID_COUNT 24 | ||
416 | #define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22 | ||
417 | #define TIMEOUT 21 | ||
418 | #define USB_STALL_SENT 20 | ||
419 | #define USB_IN_NAK_SENT 19 | ||
420 | #define USB_IN_ACK_RCVD 18 | ||
421 | #define USB_OUT_PING_NAK_SENT 17 | ||
422 | #define USB_OUT_ACK_SENT 16 | ||
423 | #define FIFO_OVERFLOW 13 | ||
424 | #define FIFO_UNDERFLOW 12 | ||
425 | #define FIFO_FULL 11 | ||
426 | #define FIFO_EMPTY 10 | ||
427 | #define FIFO_FLUSH 9 | ||
428 | #define SHORT_PACKET_OUT_DONE_INTERRUPT 6 | ||
429 | #define SHORT_PACKET_TRANSFERRED_INTERRUPT 5 | ||
430 | #define NAK_OUT_PACKETS 4 | ||
431 | #define DATA_PACKET_RECEIVED_INTERRUPT 3 | ||
432 | #define DATA_PACKET_TRANSMITTED_INTERRUPT 2 | ||
433 | #define DATA_OUT_PING_TOKEN_INTERRUPT 1 | ||
434 | #define DATA_IN_TOKEN_INTERRUPT 0 | ||
435 | /* offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 */ | ||
436 | __le32 ep_avail; | ||
437 | __le32 ep_data; | ||
438 | u32 _unused0[2]; | ||
439 | } __packed; | ||
440 | |||
441 | struct net2280_reg_write { | ||
442 | __le16 port; | ||
443 | __le32 addr; | ||
444 | __le32 val; | ||
445 | } __packed; | ||
446 | |||
447 | struct net2280_reg_read { | ||
448 | __le16 port; | ||
449 | __le32 addr; | ||
450 | } __packed; | ||
451 | #endif /* NET2280_H */ | ||
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index d273be7272b9..a5f5f0fea3bd 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h | |||
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | /* for isl3886 register definitions used on ver 1 devices */ | 17 | /* for isl3886 register definitions used on ver 1 devices */ |
18 | #include "p54pci.h" | 18 | #include "p54pci.h" |
19 | #include "net2280.h" | 19 | #include <linux/usb/net2280.h> |
20 | 20 | ||
21 | /* pci */ | 21 | /* pci */ |
22 | #define NET2280_BASE 0x10000000 | 22 | #define NET2280_BASE 0x10000000 |
@@ -93,6 +93,17 @@ enum net2280_op_type { | |||
93 | NET2280_DEV_CFG_U16 = 0x0883 | 93 | NET2280_DEV_CFG_U16 = 0x0883 |
94 | }; | 94 | }; |
95 | 95 | ||
96 | struct net2280_reg_write { | ||
97 | __le16 port; | ||
98 | __le32 addr; | ||
99 | __le32 val; | ||
100 | } __packed; | ||
101 | |||
102 | struct net2280_reg_read { | ||
103 | __le16 port; | ||
104 | __le32 addr; | ||
105 | } __packed; | ||
106 | |||
96 | #define P54U_FW_BLOCK 2048 | 107 | #define P54U_FW_BLOCK 2048 |
97 | 108 | ||
98 | #define X2_SIGNATURE "x2 " | 109 | #define X2_SIGNATURE "x2 " |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index c878e3f3993c..05c64597838d 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -47,7 +47,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | |||
47 | * BBP and RF register require indirect register access, | 47 | * BBP and RF register require indirect register access, |
48 | * and use the CSR registers BBPCSR and RFCSR to achieve this. | 48 | * and use the CSR registers BBPCSR and RFCSR to achieve this. |
49 | * These indirect registers work with busy bits, | 49 | * These indirect registers work with busy bits, |
50 | * and we will try maximal REGISTER_BUSY_COUNT times to access | 50 | * and we will try maximal REGISTER_USB_BUSY_COUNT times to access |
51 | * the register while taking a REGISTER_BUSY_DELAY us delay | 51 | * the register while taking a REGISTER_BUSY_DELAY us delay |
52 | * between each attampt. When the busy bit is still set at that time, | 52 | * between each attampt. When the busy bit is still set at that time, |
53 | * the access attempt is considered to have failed, | 53 | * the access attempt is considered to have failed, |
@@ -122,7 +122,7 @@ static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev, | |||
122 | { | 122 | { |
123 | unsigned int i; | 123 | unsigned int i; |
124 | 124 | ||
125 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | 125 | for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { |
126 | rt2500usb_register_read_lock(rt2x00dev, offset, reg); | 126 | rt2500usb_register_read_lock(rt2x00dev, offset, reg); |
127 | if (!rt2x00_get_field16(*reg, field)) | 127 | if (!rt2x00_get_field16(*reg, field)) |
128 | return 1; | 128 | return 1; |
@@ -904,7 +904,7 @@ static int rt2500usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) | |||
904 | unsigned int i; | 904 | unsigned int i; |
905 | u8 value; | 905 | u8 value; |
906 | 906 | ||
907 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | 907 | for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { |
908 | rt2500usb_bbp_read(rt2x00dev, 0, &value); | 908 | rt2500usb_bbp_read(rt2x00dev, 0, &value); |
909 | if ((value != 0xff) && (value != 0x00)) | 909 | if ((value != 0xff) && (value != 0x00)) |
910 | return 0; | 910 | return 0; |
@@ -1023,7 +1023,7 @@ static int rt2500usb_set_state(struct rt2x00_dev *rt2x00dev, | |||
1023 | * We must wait until the register indicates that the | 1023 | * We must wait until the register indicates that the |
1024 | * device has entered the correct state. | 1024 | * device has entered the correct state. |
1025 | */ | 1025 | */ |
1026 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | 1026 | for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { |
1027 | rt2500usb_register_read(rt2x00dev, MAC_CSR17, ®2); | 1027 | rt2500usb_register_read(rt2x00dev, MAC_CSR17, ®2); |
1028 | bbp_state = rt2x00_get_field16(reg2, MAC_CSR17_BBP_CURR_STATE); | 1028 | bbp_state = rt2x00_get_field16(reg2, MAC_CSR17_BBP_CURR_STATE); |
1029 | rf_state = rt2x00_get_field16(reg2, MAC_CSR17_RF_CURR_STATE); | 1029 | rf_state = rt2x00_get_field16(reg2, MAC_CSR17_RF_CURR_STATE); |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 9f57a2db791c..81ee481487cf 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -4119,7 +4119,20 @@ static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev, | |||
4119 | * expected. We adjust it, based on TSSI reference and boundaries values | 4119 | * expected. We adjust it, based on TSSI reference and boundaries values |
4120 | * provided in EEPROM. | 4120 | * provided in EEPROM. |
4121 | */ | 4121 | */ |
4122 | delta += rt2800_get_gain_calibration_delta(rt2x00dev); | 4122 | switch (rt2x00dev->chip.rt) { |
4123 | case RT2860: | ||
4124 | case RT2872: | ||
4125 | case RT2883: | ||
4126 | case RT3070: | ||
4127 | case RT3071: | ||
4128 | case RT3090: | ||
4129 | case RT3572: | ||
4130 | delta += rt2800_get_gain_calibration_delta(rt2x00dev); | ||
4131 | break; | ||
4132 | default: | ||
4133 | /* TODO: temperature compensation code for other chips. */ | ||
4134 | break; | ||
4135 | } | ||
4123 | 4136 | ||
4124 | /* | 4137 | /* |
4125 | * Decrease power according to user settings, on devices with unknown | 4138 | * Decrease power according to user settings, on devices with unknown |
@@ -4136,25 +4149,19 @@ static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev, | |||
4136 | * TODO: we do not use +6 dBm option to do not increase power beyond | 4149 | * TODO: we do not use +6 dBm option to do not increase power beyond |
4137 | * regulatory limit, however this could be utilized for devices with | 4150 | * regulatory limit, however this could be utilized for devices with |
4138 | * CAPABILITY_POWER_LIMIT. | 4151 | * CAPABILITY_POWER_LIMIT. |
4139 | * | 4152 | */ |
4140 | * TODO: add different temperature compensation code for RT3290 & RT5390 | 4153 | if (delta <= -12) { |
4141 | * to allow to use BBP_R1 for those chips. | 4154 | power_ctrl = 2; |
4142 | */ | 4155 | delta += 12; |
4143 | if (!rt2x00_rt(rt2x00dev, RT3290) && | 4156 | } else if (delta <= -6) { |
4144 | !rt2x00_rt(rt2x00dev, RT5390)) { | 4157 | power_ctrl = 1; |
4145 | rt2800_bbp_read(rt2x00dev, 1, &r1); | 4158 | delta += 6; |
4146 | if (delta <= -12) { | 4159 | } else { |
4147 | power_ctrl = 2; | 4160 | power_ctrl = 0; |
4148 | delta += 12; | ||
4149 | } else if (delta <= -6) { | ||
4150 | power_ctrl = 1; | ||
4151 | delta += 6; | ||
4152 | } else { | ||
4153 | power_ctrl = 0; | ||
4154 | } | ||
4155 | rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, power_ctrl); | ||
4156 | rt2800_bbp_write(rt2x00dev, 1, r1); | ||
4157 | } | 4161 | } |
4162 | rt2800_bbp_read(rt2x00dev, 1, &r1); | ||
4163 | rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, power_ctrl); | ||
4164 | rt2800_bbp_write(rt2x00dev, 1, r1); | ||
4158 | 4165 | ||
4159 | offset = TX_PWR_CFG_0; | 4166 | offset = TX_PWR_CFG_0; |
4160 | 4167 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 573897b8e878..8444313eabe2 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -1111,6 +1111,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1111 | /* Ovislink */ | 1111 | /* Ovislink */ |
1112 | { USB_DEVICE(0x1b75, 0x3071) }, | 1112 | { USB_DEVICE(0x1b75, 0x3071) }, |
1113 | { USB_DEVICE(0x1b75, 0x3072) }, | 1113 | { USB_DEVICE(0x1b75, 0x3072) }, |
1114 | { USB_DEVICE(0x1b75, 0xa200) }, | ||
1114 | /* Para */ | 1115 | /* Para */ |
1115 | { USB_DEVICE(0x20b8, 0x8888) }, | 1116 | { USB_DEVICE(0x20b8, 0x8888) }, |
1116 | /* Pegatron */ | 1117 | /* Pegatron */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index d13f25cd70d5..9bb398bed9bb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -1019,9 +1019,12 @@ struct rt2x00_bar_list_entry { | |||
1019 | * Register defines. | 1019 | * Register defines. |
1020 | * Some registers require multiple attempts before success, | 1020 | * Some registers require multiple attempts before success, |
1021 | * in those cases REGISTER_BUSY_COUNT attempts should be | 1021 | * in those cases REGISTER_BUSY_COUNT attempts should be |
1022 | * taken with a REGISTER_BUSY_DELAY interval. | 1022 | * taken with a REGISTER_BUSY_DELAY interval. Due to USB |
1023 | * bus delays, we do not have to loop so many times to wait | ||
1024 | * for valid register value on that bus. | ||
1023 | */ | 1025 | */ |
1024 | #define REGISTER_BUSY_COUNT 100 | 1026 | #define REGISTER_BUSY_COUNT 100 |
1027 | #define REGISTER_USB_BUSY_COUNT 20 | ||
1025 | #define REGISTER_BUSY_DELAY 100 | 1028 | #define REGISTER_BUSY_DELAY 100 |
1026 | 1029 | ||
1027 | /* | 1030 | /* |
@@ -1437,8 +1440,11 @@ int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
1437 | struct ieee80211_sta *sta); | 1440 | struct ieee80211_sta *sta); |
1438 | int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1441 | int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
1439 | struct ieee80211_sta *sta); | 1442 | struct ieee80211_sta *sta); |
1440 | void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw); | 1443 | void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw, |
1441 | void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw); | 1444 | struct ieee80211_vif *vif, |
1445 | const u8 *mac_addr); | ||
1446 | void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw, | ||
1447 | struct ieee80211_vif *vif); | ||
1442 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, | 1448 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, |
1443 | struct ieee80211_low_level_stats *stats); | 1449 | struct ieee80211_low_level_stats *stats); |
1444 | void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, | 1450 | void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index ad6e5a8d1e10..cb40245a0695 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -568,7 +568,9 @@ int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
568 | } | 568 | } |
569 | EXPORT_SYMBOL_GPL(rt2x00mac_sta_remove); | 569 | EXPORT_SYMBOL_GPL(rt2x00mac_sta_remove); |
570 | 570 | ||
571 | void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw) | 571 | void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw, |
572 | struct ieee80211_vif *vif, | ||
573 | const u8 *mac_addr) | ||
572 | { | 574 | { |
573 | struct rt2x00_dev *rt2x00dev = hw->priv; | 575 | struct rt2x00_dev *rt2x00dev = hw->priv; |
574 | set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); | 576 | set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); |
@@ -576,7 +578,8 @@ void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw) | |||
576 | } | 578 | } |
577 | EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start); | 579 | EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start); |
578 | 580 | ||
579 | void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw) | 581 | void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw, |
582 | struct ieee80211_vif *vif) | ||
580 | { | 583 | { |
581 | struct rt2x00_dev *rt2x00dev = hw->priv; | 584 | struct rt2x00_dev *rt2x00dev = hw->priv; |
582 | clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); | 585 | clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 8e68f87ab13c..66ff36447b94 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -158,55 +158,29 @@ void rt2x00queue_align_frame(struct sk_buff *skb) | |||
158 | skb_trim(skb, frame_length); | 158 | skb_trim(skb, frame_length); |
159 | } | 159 | } |
160 | 160 | ||
161 | void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) | 161 | /* |
162 | * H/W needs L2 padding between the header and the paylod if header size | ||
163 | * is not 4 bytes aligned. | ||
164 | */ | ||
165 | void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int hdr_len) | ||
162 | { | 166 | { |
163 | unsigned int payload_length = skb->len - header_length; | 167 | unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0; |
164 | unsigned int header_align = ALIGN_SIZE(skb, 0); | ||
165 | unsigned int payload_align = ALIGN_SIZE(skb, header_length); | ||
166 | unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0; | ||
167 | 168 | ||
168 | /* | 169 | if (!l2pad) |
169 | * Adjust the header alignment if the payload needs to be moved more | ||
170 | * than the header. | ||
171 | */ | ||
172 | if (payload_align > header_align) | ||
173 | header_align += 4; | ||
174 | |||
175 | /* There is nothing to do if no alignment is needed */ | ||
176 | if (!header_align) | ||
177 | return; | 170 | return; |
178 | 171 | ||
179 | /* Reserve the amount of space needed in front of the frame */ | 172 | skb_push(skb, l2pad); |
180 | skb_push(skb, header_align); | 173 | memmove(skb->data, skb->data + l2pad, hdr_len); |
181 | |||
182 | /* | ||
183 | * Move the header. | ||
184 | */ | ||
185 | memmove(skb->data, skb->data + header_align, header_length); | ||
186 | |||
187 | /* Move the payload, if present and if required */ | ||
188 | if (payload_length && payload_align) | ||
189 | memmove(skb->data + header_length + l2pad, | ||
190 | skb->data + header_length + l2pad + payload_align, | ||
191 | payload_length); | ||
192 | |||
193 | /* Trim the skb to the correct size */ | ||
194 | skb_trim(skb, header_length + l2pad + payload_length); | ||
195 | } | 174 | } |
196 | 175 | ||
197 | void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) | 176 | void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int hdr_len) |
198 | { | 177 | { |
199 | /* | 178 | unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0; |
200 | * L2 padding is only present if the skb contains more than just the | ||
201 | * IEEE 802.11 header. | ||
202 | */ | ||
203 | unsigned int l2pad = (skb->len > header_length) ? | ||
204 | L2PAD_SIZE(header_length) : 0; | ||
205 | 179 | ||
206 | if (!l2pad) | 180 | if (!l2pad) |
207 | return; | 181 | return; |
208 | 182 | ||
209 | memmove(skb->data + l2pad, skb->data, header_length); | 183 | memmove(skb->data + l2pad, skb->data, hdr_len); |
210 | skb_pull(skb, l2pad); | 184 | skb_pull(skb, l2pad); |
211 | } | 185 | } |
212 | 186 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index dc85d3e0ffe5..892270dd3e7b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c | |||
@@ -42,37 +42,27 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev, | |||
42 | { | 42 | { |
43 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); | 43 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); |
44 | int status; | 44 | int status; |
45 | unsigned int i; | ||
46 | unsigned int pipe = | 45 | unsigned int pipe = |
47 | (requesttype == USB_VENDOR_REQUEST_IN) ? | 46 | (requesttype == USB_VENDOR_REQUEST_IN) ? |
48 | usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0); | 47 | usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0); |
48 | unsigned long expire = jiffies + msecs_to_jiffies(timeout); | ||
49 | 49 | ||
50 | if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) | 50 | if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) |
51 | return -ENODEV; | 51 | return -ENODEV; |
52 | 52 | ||
53 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | 53 | do { |
54 | status = usb_control_msg(usb_dev, pipe, request, requesttype, | 54 | status = usb_control_msg(usb_dev, pipe, request, requesttype, |
55 | value, offset, buffer, buffer_length, | 55 | value, offset, buffer, buffer_length, |
56 | timeout); | 56 | timeout / 2); |
57 | if (status >= 0) | 57 | if (status >= 0) |
58 | return 0; | 58 | return 0; |
59 | 59 | ||
60 | /* | 60 | if (status == -ENODEV) { |
61 | * Check for errors | 61 | /* Device has disappeared. */ |
62 | * -ENODEV: Device has disappeared, no point continuing. | ||
63 | * All other errors: Try again. | ||
64 | */ | ||
65 | else if (status == -ENODEV) { | ||
66 | clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); | 62 | clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); |
67 | break; | 63 | break; |
68 | } | 64 | } |
69 | } | 65 | } while (time_before(jiffies, expire)); |
70 | |||
71 | /* If the port is powered down, we get a -EPROTO error, and this | ||
72 | * leads to a endless loop. So just say that the device is gone. | ||
73 | */ | ||
74 | if (status == -EPROTO) | ||
75 | clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); | ||
76 | 66 | ||
77 | rt2x00_err(rt2x00dev, | 67 | rt2x00_err(rt2x00dev, |
78 | "Vendor Request 0x%02x failed for offset 0x%04x with error %d\n", | 68 | "Vendor Request 0x%02x failed for offset 0x%04x with error %d\n", |
@@ -154,7 +144,7 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, | |||
154 | if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) | 144 | if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) |
155 | return -ENODEV; | 145 | return -ENODEV; |
156 | 146 | ||
157 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | 147 | for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { |
158 | rt2x00usb_register_read_lock(rt2x00dev, offset, reg); | 148 | rt2x00usb_register_read_lock(rt2x00dev, offset, reg); |
159 | if (!rt2x00_get_field32(*reg, field)) | 149 | if (!rt2x00_get_field32(*reg, field)) |
160 | return 1; | 150 | return 1; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 819690e978c0..8f85fbd5f237 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h | |||
@@ -38,7 +38,7 @@ | |||
38 | * a higher value is required. In that case we use the REGISTER_TIMEOUT_FIRMWARE | 38 | * a higher value is required. In that case we use the REGISTER_TIMEOUT_FIRMWARE |
39 | * and EEPROM_TIMEOUT. | 39 | * and EEPROM_TIMEOUT. |
40 | */ | 40 | */ |
41 | #define REGISTER_TIMEOUT 500 | 41 | #define REGISTER_TIMEOUT 100 |
42 | #define REGISTER_TIMEOUT_FIRMWARE 1000 | 42 | #define REGISTER_TIMEOUT_FIRMWARE 1000 |
43 | #define EEPROM_TIMEOUT 2000 | 43 | #define EEPROM_TIMEOUT 2000 |
44 | 44 | ||
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 95724ff9c726..a5458cf01fb2 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -1295,7 +1295,7 @@ static int rt73usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) | |||
1295 | unsigned int i; | 1295 | unsigned int i; |
1296 | u8 value; | 1296 | u8 value; |
1297 | 1297 | ||
1298 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | 1298 | for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { |
1299 | rt73usb_bbp_read(rt2x00dev, 0, &value); | 1299 | rt73usb_bbp_read(rt2x00dev, 0, &value); |
1300 | if ((value != 0xff) && (value != 0x00)) | 1300 | if ((value != 0xff) && (value != 0x00)) |
1301 | return 0; | 1301 | return 0; |
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 58ba71830886..40b6d1d006d7 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c | |||
@@ -467,7 +467,7 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw) | |||
467 | rtl_easy_concurrent_retrytimer_callback, (unsigned long)hw); | 467 | rtl_easy_concurrent_retrytimer_callback, (unsigned long)hw); |
468 | /* <2> work queue */ | 468 | /* <2> work queue */ |
469 | rtlpriv->works.hw = hw; | 469 | rtlpriv->works.hw = hw; |
470 | rtlpriv->works.rtl_wq = alloc_workqueue(rtlpriv->cfg->name, 0, 0); | 470 | rtlpriv->works.rtl_wq = alloc_workqueue("%s", 0, 0, rtlpriv->cfg->name); |
471 | INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq, | 471 | INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq, |
472 | (void *)rtl_watchdog_wq_callback); | 472 | (void *)rtl_watchdog_wq_callback); |
473 | INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, | 473 | INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, |
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index f6179bc06086..5fc6f52641bd 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c | |||
@@ -786,6 +786,7 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, | |||
786 | unsigned int changed_flags, | 786 | unsigned int changed_flags, |
787 | unsigned int *new_flags, u64 multicast) | 787 | unsigned int *new_flags, u64 multicast) |
788 | { | 788 | { |
789 | bool update_rcr = false; | ||
789 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 790 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
790 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | 791 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); |
791 | 792 | ||
@@ -806,6 +807,7 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, | |||
806 | RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, | 807 | RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, |
807 | "Disable receive multicast frame\n"); | 808 | "Disable receive multicast frame\n"); |
808 | } | 809 | } |
810 | update_rcr = true; | ||
809 | } | 811 | } |
810 | 812 | ||
811 | if (changed_flags & FIF_FCSFAIL) { | 813 | if (changed_flags & FIF_FCSFAIL) { |
@@ -818,6 +820,8 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, | |||
818 | RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, | 820 | RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, |
819 | "Disable receive FCS error frame\n"); | 821 | "Disable receive FCS error frame\n"); |
820 | } | 822 | } |
823 | if (!update_rcr) | ||
824 | update_rcr = true; | ||
821 | } | 825 | } |
822 | 826 | ||
823 | /* if ssid not set to hw don't check bssid | 827 | /* if ssid not set to hw don't check bssid |
@@ -832,6 +836,8 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, | |||
832 | rtlpriv->cfg->ops->set_chk_bssid(hw, false); | 836 | rtlpriv->cfg->ops->set_chk_bssid(hw, false); |
833 | else | 837 | else |
834 | rtlpriv->cfg->ops->set_chk_bssid(hw, true); | 838 | rtlpriv->cfg->ops->set_chk_bssid(hw, true); |
839 | if (update_rcr) | ||
840 | update_rcr = false; | ||
835 | } | 841 | } |
836 | } | 842 | } |
837 | 843 | ||
@@ -846,6 +852,8 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, | |||
846 | RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, | 852 | RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, |
847 | "Disable receive control frame.\n"); | 853 | "Disable receive control frame.\n"); |
848 | } | 854 | } |
855 | if (!update_rcr) | ||
856 | update_rcr = true; | ||
849 | } | 857 | } |
850 | 858 | ||
851 | if (changed_flags & FIF_OTHER_BSS) { | 859 | if (changed_flags & FIF_OTHER_BSS) { |
@@ -858,7 +866,13 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, | |||
858 | RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, | 866 | RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, |
859 | "Disable receive other BSS's frame.\n"); | 867 | "Disable receive other BSS's frame.\n"); |
860 | } | 868 | } |
869 | if (!update_rcr) | ||
870 | update_rcr = true; | ||
861 | } | 871 | } |
872 | |||
873 | if (update_rcr) | ||
874 | rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, | ||
875 | (u8 *)(&mac->rx_conf)); | ||
862 | } | 876 | } |
863 | static int rtl_op_sta_add(struct ieee80211_hw *hw, | 877 | static int rtl_op_sta_add(struct ieee80211_hw *hw, |
864 | struct ieee80211_vif *vif, | 878 | struct ieee80211_vif *vif, |
@@ -1361,7 +1375,9 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw, | |||
1361 | return 0; | 1375 | return 0; |
1362 | } | 1376 | } |
1363 | 1377 | ||
1364 | static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) | 1378 | static void rtl_op_sw_scan_start(struct ieee80211_hw *hw, |
1379 | struct ieee80211_vif *vif, | ||
1380 | const u8 *mac_addr) | ||
1365 | { | 1381 | { |
1366 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 1382 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1367 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | 1383 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); |
@@ -1396,7 +1412,8 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) | |||
1396 | rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP_BAND0); | 1412 | rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP_BAND0); |
1397 | } | 1413 | } |
1398 | 1414 | ||
1399 | static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw) | 1415 | static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw, |
1416 | struct ieee80211_vif *vif) | ||
1400 | { | 1417 | { |
1401 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 1418 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1402 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | 1419 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); |
@@ -1828,3 +1845,9 @@ const struct ieee80211_ops rtl_ops = { | |||
1828 | .flush = rtl_op_flush, | 1845 | .flush = rtl_op_flush, |
1829 | }; | 1846 | }; |
1830 | EXPORT_SYMBOL_GPL(rtl_ops); | 1847 | EXPORT_SYMBOL_GPL(rtl_ops); |
1848 | |||
1849 | bool rtl_btc_status_false(void) | ||
1850 | { | ||
1851 | return false; | ||
1852 | } | ||
1853 | EXPORT_SYMBOL_GPL(rtl_btc_status_false); | ||
diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index 59cd3b9dca25..624e1dc16d31 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h | |||
@@ -42,5 +42,6 @@ void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, | |||
42 | u32 mask, u32 data); | 42 | u32 mask, u32 data); |
43 | void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data); | 43 | void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data); |
44 | bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); | 44 | bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); |
45 | bool rtl_btc_status_false(void); | ||
45 | 46 | ||
46 | #endif | 47 | #endif |
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 667aba81246c..61f5d36eca6a 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c | |||
@@ -842,7 +842,8 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) | |||
842 | break; | 842 | break; |
843 | } | 843 | } |
844 | /* handle command packet here */ | 844 | /* handle command packet here */ |
845 | if (rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) { | 845 | if (rtlpriv->cfg->ops->rx_command_packet && |
846 | rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) { | ||
846 | dev_kfree_skb_any(skb); | 847 | dev_kfree_skb_any(skb); |
847 | goto end; | 848 | goto end; |
848 | } | 849 | } |
@@ -1127,9 +1128,14 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) | |||
1127 | 1128 | ||
1128 | __skb_queue_tail(&ring->queue, pskb); | 1129 | __skb_queue_tail(&ring->queue, pskb); |
1129 | 1130 | ||
1130 | rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN, | 1131 | if (rtlpriv->use_new_trx_flow) { |
1131 | &temp_one); | 1132 | temp_one = 4; |
1132 | 1133 | rtlpriv->cfg->ops->set_desc(hw, (u8 *)pbuffer_desc, true, | |
1134 | HW_DESC_OWN, (u8 *)&temp_one); | ||
1135 | } else { | ||
1136 | rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN, | ||
1137 | &temp_one); | ||
1138 | } | ||
1133 | return; | 1139 | return; |
1134 | } | 1140 | } |
1135 | 1141 | ||
@@ -1370,9 +1376,9 @@ static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw, | |||
1370 | ring->desc = NULL; | 1376 | ring->desc = NULL; |
1371 | if (rtlpriv->use_new_trx_flow) { | 1377 | if (rtlpriv->use_new_trx_flow) { |
1372 | pci_free_consistent(rtlpci->pdev, | 1378 | pci_free_consistent(rtlpci->pdev, |
1373 | sizeof(*ring->desc) * ring->entries, | 1379 | sizeof(*ring->buffer_desc) * ring->entries, |
1374 | ring->buffer_desc, ring->buffer_desc_dma); | 1380 | ring->buffer_desc, ring->buffer_desc_dma); |
1375 | ring->desc = NULL; | 1381 | ring->buffer_desc = NULL; |
1376 | } | 1382 | } |
1377 | } | 1383 | } |
1378 | 1384 | ||
@@ -1543,7 +1549,6 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) | |||
1543 | true, | 1549 | true, |
1544 | HW_DESC_TXBUFF_ADDR), | 1550 | HW_DESC_TXBUFF_ADDR), |
1545 | skb->len, PCI_DMA_TODEVICE); | 1551 | skb->len, PCI_DMA_TODEVICE); |
1546 | ring->idx = (ring->idx + 1) % ring->entries; | ||
1547 | kfree_skb(skb); | 1552 | kfree_skb(skb); |
1548 | ring->idx = (ring->idx + 1) % ring->entries; | 1553 | ring->idx = (ring->idx + 1) % ring->entries; |
1549 | } | 1554 | } |
@@ -1796,7 +1801,8 @@ static int rtl_pci_start(struct ieee80211_hw *hw) | |||
1796 | rtl_pci_reset_trx_ring(hw); | 1801 | rtl_pci_reset_trx_ring(hw); |
1797 | 1802 | ||
1798 | rtlpci->driver_is_goingto_unload = false; | 1803 | rtlpci->driver_is_goingto_unload = false; |
1799 | if (rtlpriv->cfg->ops->get_btc_status()) { | 1804 | if (rtlpriv->cfg->ops->get_btc_status && |
1805 | rtlpriv->cfg->ops->get_btc_status()) { | ||
1800 | rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv); | 1806 | rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv); |
1801 | rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv); | 1807 | rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv); |
1802 | } | 1808 | } |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index a00861b26ece..29983bc96a89 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c | |||
@@ -656,7 +656,8 @@ static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { | |||
656 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 656 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
657 | }; | 657 | }; |
658 | 658 | ||
659 | void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) | 659 | void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, |
660 | bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *)) | ||
660 | { | 661 | { |
661 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 662 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
662 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | 663 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); |
@@ -722,7 +723,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) | |||
722 | memcpy((u8 *)skb_put(skb, totalpacketlen), | 723 | memcpy((u8 *)skb_put(skb, totalpacketlen), |
723 | &reserved_page_packet, totalpacketlen); | 724 | &reserved_page_packet, totalpacketlen); |
724 | 725 | ||
725 | rtstatus = rtl_cmd_send_packet(hw, skb); | 726 | if (cmd_send_packet) |
727 | rtstatus = cmd_send_packet(hw, skb); | ||
728 | else | ||
729 | rtstatus = rtl_cmd_send_packet(hw, skb); | ||
726 | 730 | ||
727 | if (rtstatus) | 731 | if (rtstatus) |
728 | b_dlok = true; | 732 | b_dlok = true; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h index a815bd6273da..b64ae45dc674 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h | |||
@@ -109,7 +109,9 @@ void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, | |||
109 | u32 cmd_len, u8 *p_cmdbuffer); | 109 | u32 cmd_len, u8 *p_cmdbuffer); |
110 | void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); | 110 | void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); |
111 | void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); | 111 | void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); |
112 | void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); | 112 | void rtl92c_set_fw_rsvdpagepkt |
113 | (struct ieee80211_hw *hw, | ||
114 | bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *)); | ||
113 | void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); | 115 | void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); |
114 | void usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, void *data, u16 len); | 116 | void usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, void *data, u16 len); |
115 | void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); | 117 | void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h index 831df101d7b7..9b660df6fd71 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h | |||
@@ -114,6 +114,8 @@ | |||
114 | LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4) | 114 | LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4) |
115 | #define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \ | 115 | #define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \ |
116 | LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12) | 116 | LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12) |
117 | #define GET_RX_STATUS_DESC_BUFF_ADDR(__pdesc) \ | ||
118 | SHIFT_AND_MASK_LE(__pdesc + 24, 0, 32) | ||
117 | 119 | ||
118 | #define CHIP_VER_B BIT(4) | 120 | #define CHIP_VER_B BIT(4) |
119 | #define CHIP_BONDING_IDENTIFIER(_value) (((_value) >> 22) & 0x3) | 121 | #define CHIP_BONDING_IDENTIFIER(_value) (((_value) >> 22) & 0x3) |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 8ec0f031f48a..55357d69397a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | |||
@@ -459,7 +459,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) | |||
459 | rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, | 459 | rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, |
460 | tmp_reg422 & (~BIT(6))); | 460 | tmp_reg422 & (~BIT(6))); |
461 | 461 | ||
462 | rtl92c_set_fw_rsvdpagepkt(hw, 0); | 462 | rtl92c_set_fw_rsvdpagepkt(hw, NULL); |
463 | 463 | ||
464 | _rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0); | 464 | _rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0); |
465 | _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4)); | 465 | _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4)); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index d86b5b566444..46ea07605eb4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c | |||
@@ -244,6 +244,7 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { | |||
244 | .phy_lc_calibrate = _rtl92ce_phy_lc_calibrate, | 244 | .phy_lc_calibrate = _rtl92ce_phy_lc_calibrate, |
245 | .phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback, | 245 | .phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback, |
246 | .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower, | 246 | .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower, |
247 | .get_btc_status = rtl_btc_status_false, | ||
247 | }; | 248 | }; |
248 | 249 | ||
249 | static struct rtl_mod_params rtl92ce_mod_params = { | 250 | static struct rtl_mod_params rtl92ce_mod_params = { |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 2fb9c7acb76a..dc3d20b17a26 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | |||
@@ -728,6 +728,9 @@ u32 rtl92ce_get_desc(u8 *p_desc, bool istx, u8 desc_name) | |||
728 | case HW_DESC_RXPKT_LEN: | 728 | case HW_DESC_RXPKT_LEN: |
729 | ret = GET_RX_DESC_PKT_LEN(pdesc); | 729 | ret = GET_RX_DESC_PKT_LEN(pdesc); |
730 | break; | 730 | break; |
731 | case HW_DESC_RXBUFF_ADDR: | ||
732 | ret = GET_RX_STATUS_DESC_BUFF_ADDR(pdesc); | ||
733 | break; | ||
731 | default: | 734 | default: |
732 | RT_ASSERT(false, "ERR rxdesc :%d not process\n", | 735 | RT_ASSERT(false, "ERR rxdesc :%d not process\n", |
733 | desc_name); | 736 | desc_name); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 04aa0b5f5b3d..873363acbacf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | |||
@@ -1592,6 +1592,20 @@ void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) | |||
1592 | } | 1592 | } |
1593 | } | 1593 | } |
1594 | 1594 | ||
1595 | bool usb_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
1596 | { | ||
1597 | /* Currently nothing happens here. | ||
1598 | * Traffic stops after some seconds in WPA2 802.11n mode. | ||
1599 | * Maybe because rtl8192cu chip should be set from here? | ||
1600 | * If I understand correctly, the realtek vendor driver sends some urbs | ||
1601 | * if its "here". | ||
1602 | * | ||
1603 | * This is maybe necessary: | ||
1604 | * rtlpriv->cfg->ops->fill_tx_cmddesc(hw, buffer, 1, 1, skb); | ||
1605 | */ | ||
1606 | return true; | ||
1607 | } | ||
1608 | |||
1595 | void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) | 1609 | void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) |
1596 | { | 1610 | { |
1597 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 1611 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
@@ -1939,7 +1953,8 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) | |||
1939 | recover = true; | 1953 | recover = true; |
1940 | rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, | 1954 | rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, |
1941 | tmp_reg422 & (~BIT(6))); | 1955 | tmp_reg422 & (~BIT(6))); |
1942 | rtl92c_set_fw_rsvdpagepkt(hw, 0); | 1956 | rtl92c_set_fw_rsvdpagepkt(hw, |
1957 | &usb_cmd_send_packet); | ||
1943 | _rtl92cu_set_bcn_ctrl_reg(hw, BIT(3), 0); | 1958 | _rtl92cu_set_bcn_ctrl_reg(hw, BIT(3), 0); |
1944 | _rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(4)); | 1959 | _rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(4)); |
1945 | if (recover) | 1960 | if (recover) |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h index 0f7812e0c8aa..c1e33b0228c0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h | |||
@@ -104,7 +104,6 @@ bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid); | |||
104 | void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); | 104 | void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); |
105 | int rtl92c_download_fw(struct ieee80211_hw *hw); | 105 | int rtl92c_download_fw(struct ieee80211_hw *hw); |
106 | void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); | 106 | void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); |
107 | void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished); | ||
108 | void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); | 107 | void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); |
109 | void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, | 108 | void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, |
110 | u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); | 109 | u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 7c5fbaf5fee0..e06bafee37f9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | |||
@@ -101,6 +101,12 @@ static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw) | |||
101 | } | 101 | } |
102 | } | 102 | } |
103 | 103 | ||
104 | /* get bt coexist status */ | ||
105 | static bool rtl92cu_get_btc_status(void) | ||
106 | { | ||
107 | return false; | ||
108 | } | ||
109 | |||
104 | static struct rtl_hal_ops rtl8192cu_hal_ops = { | 110 | static struct rtl_hal_ops rtl8192cu_hal_ops = { |
105 | .init_sw_vars = rtl92cu_init_sw_vars, | 111 | .init_sw_vars = rtl92cu_init_sw_vars, |
106 | .deinit_sw_vars = rtl92cu_deinit_sw_vars, | 112 | .deinit_sw_vars = rtl92cu_deinit_sw_vars, |
@@ -148,6 +154,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = { | |||
148 | .phy_set_bw_mode_callback = rtl92cu_phy_set_bw_mode_callback, | 154 | .phy_set_bw_mode_callback = rtl92cu_phy_set_bw_mode_callback, |
149 | .dm_dynamic_txpower = rtl92cu_dm_dynamic_txpower, | 155 | .dm_dynamic_txpower = rtl92cu_dm_dynamic_txpower, |
150 | .fill_h2c_cmd = rtl92c_fill_h2c_cmd, | 156 | .fill_h2c_cmd = rtl92c_fill_h2c_cmd, |
157 | .get_btc_status = rtl92cu_get_btc_status, | ||
151 | }; | 158 | }; |
152 | 159 | ||
153 | static struct rtl_mod_params rtl92cu_mod_params = { | 160 | static struct rtl_mod_params rtl92cu_mod_params = { |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c index edab5a5351b5..a0aba088259a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c | |||
@@ -251,6 +251,7 @@ static struct rtl_hal_ops rtl8192de_hal_ops = { | |||
251 | .get_rfreg = rtl92d_phy_query_rf_reg, | 251 | .get_rfreg = rtl92d_phy_query_rf_reg, |
252 | .set_rfreg = rtl92d_phy_set_rf_reg, | 252 | .set_rfreg = rtl92d_phy_set_rf_reg, |
253 | .linked_set_reg = rtl92d_linked_set_reg, | 253 | .linked_set_reg = rtl92d_linked_set_reg, |
254 | .get_btc_status = rtl_btc_status_false, | ||
254 | }; | 255 | }; |
255 | 256 | ||
256 | static struct rtl_mod_params rtl92de_mod_params = { | 257 | static struct rtl_mod_params rtl92de_mod_params = { |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/Makefile b/drivers/net/wireless/rtlwifi/rtl8192ee/Makefile index 11952b99daf8..0315eeda9b60 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/Makefile | |||
@@ -1,6 +1,3 @@ | |||
1 | obj-m := rtl8192ee.o | ||
2 | |||
3 | |||
4 | rtl8192ee-objs := \ | 1 | rtl8192ee-objs := \ |
5 | dm.o \ | 2 | dm.o \ |
6 | fw.o \ | 3 | fw.o \ |
@@ -14,6 +11,6 @@ rtl8192ee-objs := \ | |||
14 | trx.o \ | 11 | trx.o \ |
15 | 12 | ||
16 | 13 | ||
17 | obj-$(CONFIG_RTL8821AE) += rtl8192ee.o | 14 | obj-$(CONFIG_RTL8192EE) += rtl8192ee.o |
18 | 15 | ||
19 | ccflags-y += -D__CHECK_ENDIAN__ | 16 | ccflags-y += -D__CHECK_ENDIAN__ |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c index dfdc9b20e4ad..1a87edca2c3f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c | |||
@@ -362,7 +362,7 @@ void rtl92ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) | |||
362 | } | 362 | } |
363 | break; | 363 | break; |
364 | default: | 364 | default: |
365 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 365 | RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, |
366 | "switch case not process %x\n", variable); | 366 | "switch case not process %x\n", variable); |
367 | break; | 367 | break; |
368 | } | 368 | } |
@@ -591,7 +591,7 @@ void rtl92ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) | |||
591 | acm_ctrl &= (~ACMHW_BEQEN); | 591 | acm_ctrl &= (~ACMHW_BEQEN); |
592 | break; | 592 | break; |
593 | default: | 593 | default: |
594 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 594 | RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, |
595 | "switch case not process\n"); | 595 | "switch case not process\n"); |
596 | break; | 596 | break; |
597 | } | 597 | } |
@@ -710,7 +710,7 @@ void rtl92ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) | |||
710 | } | 710 | } |
711 | break; | 711 | break; |
712 | default: | 712 | default: |
713 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 713 | RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, |
714 | "switch case not process %x\n", variable); | 714 | "switch case not process %x\n", variable); |
715 | break; | 715 | break; |
716 | } | 716 | } |
@@ -2424,7 +2424,7 @@ void rtl92ee_set_key(struct ieee80211_hw *hw, u32 key_index, | |||
2424 | enc_algo = CAM_AES; | 2424 | enc_algo = CAM_AES; |
2425 | break; | 2425 | break; |
2426 | default: | 2426 | default: |
2427 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 2427 | RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, |
2428 | "switch case not process\n"); | 2428 | "switch case not process\n"); |
2429 | enc_algo = CAM_TKIP; | 2429 | enc_algo = CAM_TKIP; |
2430 | break; | 2430 | break; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h index 83c98674bfd3..6e7a70b43949 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h | |||
@@ -446,6 +446,8 @@ | |||
446 | /* DWORD 6 */ | 446 | /* DWORD 6 */ |
447 | #define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \ | 447 | #define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \ |
448 | SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val) | 448 | SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val) |
449 | #define GET_RX_STATUS_DESC_BUFF_ADDR(__pdesc) \ | ||
450 | SHIFT_AND_MASK_LE(__pdesc + 24, 0, 32) | ||
449 | 451 | ||
450 | #define SE_RX_HAL_IS_CCK_RATE(_pdesc)\ | 452 | #define SE_RX_HAL_IS_CCK_RATE(_pdesc)\ |
451 | (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M || \ | 453 | (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M || \ |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 00e067044c08..5761d5b49e39 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c | |||
@@ -1201,6 +1201,9 @@ static int _rtl92se_set_media_status(struct ieee80211_hw *hw, | |||
1201 | 1201 | ||
1202 | } | 1202 | } |
1203 | 1203 | ||
1204 | if (type != NL80211_IFTYPE_AP && | ||
1205 | rtlpriv->mac80211.link_state < MAC80211_LINKED) | ||
1206 | bt_msr = rtl_read_byte(rtlpriv, MSR) & ~MSR_LINK_MASK; | ||
1204 | rtl_write_byte(rtlpriv, (MSR), bt_msr); | 1207 | rtl_write_byte(rtlpriv, (MSR), bt_msr); |
1205 | 1208 | ||
1206 | temp = rtl_read_dword(rtlpriv, TCR); | 1209 | temp = rtl_read_dword(rtlpriv, TCR); |
@@ -1262,6 +1265,7 @@ void rtl92se_enable_interrupt(struct ieee80211_hw *hw) | |||
1262 | rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]); | 1265 | rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]); |
1263 | /* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */ | 1266 | /* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */ |
1264 | rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F); | 1267 | rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F); |
1268 | rtlpci->irq_enabled = true; | ||
1265 | } | 1269 | } |
1266 | 1270 | ||
1267 | void rtl92se_disable_interrupt(struct ieee80211_hw *hw) | 1271 | void rtl92se_disable_interrupt(struct ieee80211_hw *hw) |
@@ -1276,8 +1280,7 @@ void rtl92se_disable_interrupt(struct ieee80211_hw *hw) | |||
1276 | rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | 1280 | rtlpci = rtl_pcidev(rtl_pcipriv(hw)); |
1277 | rtl_write_dword(rtlpriv, INTA_MASK, 0); | 1281 | rtl_write_dword(rtlpriv, INTA_MASK, 0); |
1278 | rtl_write_dword(rtlpriv, INTA_MASK + 4, 0); | 1282 | rtl_write_dword(rtlpriv, INTA_MASK + 4, 0); |
1279 | 1283 | rtlpci->irq_enabled = false; | |
1280 | synchronize_irq(rtlpci->pdev->irq); | ||
1281 | } | 1284 | } |
1282 | 1285 | ||
1283 | static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data) | 1286 | static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data) |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index 77c5b5f35244..4b4612fe2fdb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c | |||
@@ -399,6 +399,8 @@ static bool _rtl92s_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, | |||
399 | case 2: | 399 | case 2: |
400 | currentcmd = &postcommoncmd[*step]; | 400 | currentcmd = &postcommoncmd[*step]; |
401 | break; | 401 | break; |
402 | default: | ||
403 | return true; | ||
402 | } | 404 | } |
403 | 405 | ||
404 | if (currentcmd->cmdid == CMDID_END) { | 406 | if (currentcmd->cmdid == CMDID_END) { |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index 1bff2a0f7600..fb003868bdef 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c | |||
@@ -87,11 +87,8 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) | |||
87 | static void rtl92se_fw_cb(const struct firmware *firmware, void *context) | 87 | static void rtl92se_fw_cb(const struct firmware *firmware, void *context) |
88 | { | 88 | { |
89 | struct ieee80211_hw *hw = context; | 89 | struct ieee80211_hw *hw = context; |
90 | struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); | ||
91 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 90 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
92 | struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); | ||
93 | struct rt_firmware *pfirmware = NULL; | 91 | struct rt_firmware *pfirmware = NULL; |
94 | int err; | ||
95 | 92 | ||
96 | RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, | 93 | RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, |
97 | "Firmware callback routine entered!\n"); | 94 | "Firmware callback routine entered!\n"); |
@@ -112,20 +109,6 @@ static void rtl92se_fw_cb(const struct firmware *firmware, void *context) | |||
112 | memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size); | 109 | memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size); |
113 | pfirmware->sz_fw_tmpbufferlen = firmware->size; | 110 | pfirmware->sz_fw_tmpbufferlen = firmware->size; |
114 | release_firmware(firmware); | 111 | release_firmware(firmware); |
115 | |||
116 | err = ieee80211_register_hw(hw); | ||
117 | if (err) { | ||
118 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | ||
119 | "Can't register mac80211 hw\n"); | ||
120 | return; | ||
121 | } else { | ||
122 | rtlpriv->mac80211.mac80211_registered = 1; | ||
123 | } | ||
124 | rtlpci->irq_alloc = 1; | ||
125 | set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); | ||
126 | |||
127 | /*init rfkill */ | ||
128 | rtl_init_rfkill(hw); | ||
129 | } | 112 | } |
130 | 113 | ||
131 | static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) | 114 | static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) |
@@ -226,8 +209,8 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) | |||
226 | if (!rtlpriv->rtlhal.pfirmware) | 209 | if (!rtlpriv->rtlhal.pfirmware) |
227 | return 1; | 210 | return 1; |
228 | 211 | ||
229 | rtlpriv->max_fw_size = RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE; | 212 | rtlpriv->max_fw_size = RTL8190_MAX_FIRMWARE_CODE_SIZE*2 + |
230 | 213 | sizeof(struct fw_hdr); | |
231 | pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n" | 214 | pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n" |
232 | "Loading firmware %s\n", rtlpriv->cfg->fw_name); | 215 | "Loading firmware %s\n", rtlpriv->cfg->fw_name); |
233 | /* request fw */ | 216 | /* request fw */ |
@@ -253,6 +236,19 @@ static void rtl92s_deinit_sw_vars(struct ieee80211_hw *hw) | |||
253 | } | 236 | } |
254 | } | 237 | } |
255 | 238 | ||
239 | static bool rtl92se_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, | ||
240 | u16 index) | ||
241 | { | ||
242 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | ||
243 | struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; | ||
244 | u8 *entry = (u8 *)(&ring->desc[ring->idx]); | ||
245 | u8 own = (u8)rtl92se_get_desc(entry, true, HW_DESC_OWN); | ||
246 | |||
247 | if (own) | ||
248 | return false; | ||
249 | return true; | ||
250 | } | ||
251 | |||
256 | static struct rtl_hal_ops rtl8192se_hal_ops = { | 252 | static struct rtl_hal_ops rtl8192se_hal_ops = { |
257 | .init_sw_vars = rtl92s_init_sw_vars, | 253 | .init_sw_vars = rtl92s_init_sw_vars, |
258 | .deinit_sw_vars = rtl92s_deinit_sw_vars, | 254 | .deinit_sw_vars = rtl92s_deinit_sw_vars, |
@@ -286,6 +282,7 @@ static struct rtl_hal_ops rtl8192se_hal_ops = { | |||
286 | .led_control = rtl92se_led_control, | 282 | .led_control = rtl92se_led_control, |
287 | .set_desc = rtl92se_set_desc, | 283 | .set_desc = rtl92se_set_desc, |
288 | .get_desc = rtl92se_get_desc, | 284 | .get_desc = rtl92se_get_desc, |
285 | .is_tx_desc_closed = rtl92se_is_tx_desc_closed, | ||
289 | .tx_polling = rtl92se_tx_polling, | 286 | .tx_polling = rtl92se_tx_polling, |
290 | .enable_hw_sec = rtl92se_enable_hw_security_config, | 287 | .enable_hw_sec = rtl92se_enable_hw_security_config, |
291 | .set_key = rtl92se_set_key, | 288 | .set_key = rtl92se_set_key, |
@@ -294,6 +291,7 @@ static struct rtl_hal_ops rtl8192se_hal_ops = { | |||
294 | .set_bbreg = rtl92s_phy_set_bb_reg, | 291 | .set_bbreg = rtl92s_phy_set_bb_reg, |
295 | .get_rfreg = rtl92s_phy_query_rf_reg, | 292 | .get_rfreg = rtl92s_phy_query_rf_reg, |
296 | .set_rfreg = rtl92s_phy_set_rf_reg, | 293 | .set_rfreg = rtl92s_phy_set_rf_reg, |
294 | .get_btc_status = rtl_btc_status_false, | ||
297 | }; | 295 | }; |
298 | 296 | ||
299 | static struct rtl_mod_params rtl92se_mod_params = { | 297 | static struct rtl_mod_params rtl92se_mod_params = { |
@@ -322,6 +320,8 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = { | |||
322 | .maps[MAC_RCR_ACRC32] = RCR_ACRC32, | 320 | .maps[MAC_RCR_ACRC32] = RCR_ACRC32, |
323 | .maps[MAC_RCR_ACF] = RCR_ACF, | 321 | .maps[MAC_RCR_ACF] = RCR_ACF, |
324 | .maps[MAC_RCR_AAP] = RCR_AAP, | 322 | .maps[MAC_RCR_AAP] = RCR_AAP, |
323 | .maps[MAC_HIMR] = INTA_MASK, | ||
324 | .maps[MAC_HIMRE] = INTA_MASK + 4, | ||
325 | 325 | ||
326 | .maps[EFUSE_TEST] = REG_EFUSE_TEST, | 326 | .maps[EFUSE_TEST] = REG_EFUSE_TEST, |
327 | .maps[EFUSE_CTRL] = REG_EFUSE_CTRL, | 327 | .maps[EFUSE_CTRL] = REG_EFUSE_CTRL, |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index b358ebce8942..672fd3b02835 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c | |||
@@ -640,6 +640,9 @@ u32 rtl92se_get_desc(u8 *desc, bool istx, u8 desc_name) | |||
640 | case HW_DESC_RXPKT_LEN: | 640 | case HW_DESC_RXPKT_LEN: |
641 | ret = GET_RX_STATUS_DESC_PKT_LEN(desc); | 641 | ret = GET_RX_STATUS_DESC_PKT_LEN(desc); |
642 | break; | 642 | break; |
643 | case HW_DESC_RXBUFF_ADDR: | ||
644 | ret = GET_RX_STATUS_DESC_BUFF_ADDR(desc); | ||
645 | break; | ||
643 | default: | 646 | default: |
644 | RT_ASSERT(false, "ERR rxdesc :%d not process\n", | 647 | RT_ASSERT(false, "ERR rxdesc :%d not process\n", |
645 | desc_name); | 648 | desc_name); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile index 9c34a85fdb89..6220672a96f4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile | |||
@@ -1,6 +1,3 @@ | |||
1 | obj-m := rtl8723ae.o | ||
2 | |||
3 | |||
4 | rtl8723ae-objs := \ | 1 | rtl8723ae-objs := \ |
5 | dm.o \ | 2 | dm.o \ |
6 | fw.o \ | 3 | fw.o \ |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/Makefile b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile index 59e416abd93a..a77c34102792 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile | |||
@@ -1,6 +1,3 @@ | |||
1 | obj-m := rtl8723be.o | ||
2 | |||
3 | |||
4 | rtl8723be-objs := \ | 1 | rtl8723be-objs := \ |
5 | dm.o \ | 2 | dm.o \ |
6 | fw.o \ | 3 | fw.o \ |
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/Makefile b/drivers/net/wireless/rtlwifi/rtl8821ae/Makefile index 87ad604a1eb3..f7a26f71197e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/Makefile | |||
@@ -1,6 +1,3 @@ | |||
1 | obj-m := rtl8821ae.o | ||
2 | |||
3 | |||
4 | rtl8821ae-objs := \ | 1 | rtl8821ae-objs := \ |
5 | dm.o \ | 2 | dm.o \ |
6 | fw.o \ | 3 | fw.o \ |
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8821ae/phy.c index 4be278f7df51..9b4d8a637915 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/phy.c | |||
@@ -1889,15 +1889,18 @@ static void _rtl8821ae_store_tx_power_by_rate(struct ieee80211_hw *hw, | |||
1889 | struct rtl_phy *rtlphy = &rtlpriv->phy; | 1889 | struct rtl_phy *rtlphy = &rtlpriv->phy; |
1890 | u8 rate_section = _rtl8821ae_get_rate_section_index(regaddr); | 1890 | u8 rate_section = _rtl8821ae_get_rate_section_index(regaddr); |
1891 | 1891 | ||
1892 | if (band != BAND_ON_2_4G && band != BAND_ON_5G) | 1892 | if (band != BAND_ON_2_4G && band != BAND_ON_5G) { |
1893 | RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid Band %d\n", band); | 1893 | RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid Band %d\n", band); |
1894 | 1894 | band = BAND_ON_2_4G; | |
1895 | if (rfpath >= MAX_RF_PATH) | 1895 | } |
1896 | if (rfpath >= MAX_RF_PATH) { | ||
1896 | RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid RfPath %d\n", rfpath); | 1897 | RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid RfPath %d\n", rfpath); |
1897 | 1898 | rfpath = MAX_RF_PATH - 1; | |
1898 | if (txnum >= MAX_RF_PATH) | 1899 | } |
1900 | if (txnum >= MAX_RF_PATH) { | ||
1899 | RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid TxNum %d\n", txnum); | 1901 | RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid TxNum %d\n", txnum); |
1900 | 1902 | txnum = MAX_RF_PATH - 1; | |
1903 | } | ||
1901 | rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] = data; | 1904 | rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] = data; |
1902 | RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, | 1905 | RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, |
1903 | "TxPwrByRateOffset[Band %d][RfPath %d][TxNum %d][RateSection %d] = 0x%x\n", | 1906 | "TxPwrByRateOffset[Band %d][RfPath %d][TxNum %d][RateSection %d] = 0x%x\n", |
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 10cf69c4bc42..46ee956d0235 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c | |||
@@ -1117,7 +1117,18 @@ int rtl_usb_probe(struct usb_interface *intf, | |||
1117 | } | 1117 | } |
1118 | rtlpriv->cfg->ops->init_sw_leds(hw); | 1118 | rtlpriv->cfg->ops->init_sw_leds(hw); |
1119 | 1119 | ||
1120 | err = ieee80211_register_hw(hw); | ||
1121 | if (err) { | ||
1122 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | ||
1123 | "Can't register mac80211 hw.\n"); | ||
1124 | err = -ENODEV; | ||
1125 | goto error_out; | ||
1126 | } | ||
1127 | rtlpriv->mac80211.mac80211_registered = 1; | ||
1128 | |||
1129 | set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); | ||
1120 | return 0; | 1130 | return 0; |
1131 | |||
1121 | error_out: | 1132 | error_out: |
1122 | rtl_deinit_core(hw); | 1133 | rtl_deinit_core(hw); |
1123 | _rtl_usb_io_handler_release(hw); | 1134 | _rtl_usb_io_handler_release(hw); |
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 38234851457e..0b30a7b4d663 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c | |||
@@ -1029,7 +1029,7 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | |||
1029 | goto out_sleep; | 1029 | goto out_sleep; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, | 1032 | skb = ieee80211_probereq_get(wl->hw, wl->vif->addr, ssid, ssid_len, |
1033 | req->ie_len); | 1033 | req->ie_len); |
1034 | if (!skb) { | 1034 | if (!skb) { |
1035 | ret = -ENOMEM; | 1035 | ret = -ENOMEM; |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 05604ee31224..b82661962d33 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c | |||
@@ -64,6 +64,9 @@ static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf, | |||
64 | id != CMD_STOP_FWLOGGER)) | 64 | id != CMD_STOP_FWLOGGER)) |
65 | return -EIO; | 65 | return -EIO; |
66 | 66 | ||
67 | if (WARN_ON_ONCE(len < sizeof(*cmd))) | ||
68 | return -EIO; | ||
69 | |||
67 | cmd = buf; | 70 | cmd = buf; |
68 | cmd->id = cpu_to_le16(id); | 71 | cmd->id = cpu_to_le16(id); |
69 | cmd->status = 0; | 72 | cmd->status = 0; |
@@ -128,8 +131,9 @@ static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf, | |||
128 | * send command to fw and return cmd status on success | 131 | * send command to fw and return cmd status on success |
129 | * valid_rets contains a bitmap of allowed error codes | 132 | * valid_rets contains a bitmap of allowed error codes |
130 | */ | 133 | */ |
131 | int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len, | 134 | static int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, |
132 | size_t res_len, unsigned long valid_rets) | 135 | size_t len, size_t res_len, |
136 | unsigned long valid_rets) | ||
133 | { | 137 | { |
134 | int ret = __wlcore_cmd_send(wl, id, buf, len, res_len); | 138 | int ret = __wlcore_cmd_send(wl, id, buf, len, res_len); |
135 | 139 | ||
@@ -150,7 +154,6 @@ fail: | |||
150 | wl12xx_queue_recovery_work(wl); | 154 | wl12xx_queue_recovery_work(wl); |
151 | return ret; | 155 | return ret; |
152 | } | 156 | } |
153 | EXPORT_SYMBOL_GPL(wl1271_cmd_send); | ||
154 | 157 | ||
155 | /* | 158 | /* |
156 | * wrapper for wlcore_cmd_send that accept only CMD_STATUS_SUCCESS | 159 | * wrapper for wlcore_cmd_send that accept only CMD_STATUS_SUCCESS |
@@ -165,6 +168,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | |||
165 | return ret; | 168 | return ret; |
166 | return 0; | 169 | return 0; |
167 | } | 170 | } |
171 | EXPORT_SYMBOL_GPL(wl1271_cmd_send); | ||
168 | 172 | ||
169 | /* | 173 | /* |
170 | * Poll the mailbox event field until any of the bits in the mask is set or a | 174 | * Poll the mailbox event field until any of the bits in the mask is set or a |
@@ -891,6 +895,9 @@ int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf, | |||
891 | 895 | ||
892 | wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id); | 896 | wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id); |
893 | 897 | ||
898 | if (WARN_ON_ONCE(len < sizeof(*acx))) | ||
899 | return -EIO; | ||
900 | |||
894 | acx->id = cpu_to_le16(id); | 901 | acx->id = cpu_to_le16(id); |
895 | 902 | ||
896 | /* payload length, does not include any headers */ | 903 | /* payload length, does not include any headers */ |
@@ -1138,7 +1145,7 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1138 | 1145 | ||
1139 | wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); | 1146 | wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); |
1140 | 1147 | ||
1141 | skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, | 1148 | skb = ieee80211_probereq_get(wl->hw, vif->addr, ssid, ssid_len, |
1142 | ie0_len + ie1_len); | 1149 | ie0_len + ie1_len); |
1143 | if (!skb) { | 1150 | if (!skb) { |
1144 | ret = -ENOMEM; | 1151 | ret = -ENOMEM; |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index ca6a28b03f8f..453684a71d30 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h | |||
@@ -31,8 +31,6 @@ struct acx_header; | |||
31 | 31 | ||
32 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | 32 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, |
33 | size_t res_len); | 33 | size_t res_len); |
34 | int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len, | ||
35 | size_t res_len, unsigned long valid_rets); | ||
36 | int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, | 34 | int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, |
37 | u8 *role_id); | 35 | u8 *role_id); |
38 | int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); | 36 | int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); |
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 16d10281798d..5153640f4532 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c | |||
@@ -259,10 +259,7 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap) | |||
259 | &wlvif->connection_loss_work, | 259 | &wlvif->connection_loss_work, |
260 | msecs_to_jiffies(delay)); | 260 | msecs_to_jiffies(delay)); |
261 | 261 | ||
262 | ieee80211_cqm_rssi_notify( | 262 | ieee80211_cqm_beacon_loss_notify(vif, GFP_KERNEL); |
263 | vif, | ||
264 | NL80211_CQM_RSSI_BEACON_LOSS_EVENT, | ||
265 | GFP_KERNEL); | ||
266 | } | 263 | } |
267 | } | 264 | } |
268 | EXPORT_SYMBOL_GPL(wlcore_event_beacon_loss); | 265 | EXPORT_SYMBOL_GPL(wlcore_event_beacon_loss); |
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 575c8f6d4009..6ad3fcedab9b 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c | |||
@@ -5177,10 +5177,11 @@ out: | |||
5177 | } | 5177 | } |
5178 | 5178 | ||
5179 | static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, | 5179 | static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, |
5180 | struct ieee80211_vif *vif, | ||
5180 | struct ieee80211_channel_switch *ch_switch) | 5181 | struct ieee80211_channel_switch *ch_switch) |
5181 | { | 5182 | { |
5182 | struct wl1271 *wl = hw->priv; | 5183 | struct wl1271 *wl = hw->priv; |
5183 | struct wl12xx_vif *wlvif; | 5184 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); |
5184 | int ret; | 5185 | int ret; |
5185 | 5186 | ||
5186 | wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch"); | 5187 | wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch"); |
@@ -5190,14 +5191,8 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, | |||
5190 | mutex_lock(&wl->mutex); | 5191 | mutex_lock(&wl->mutex); |
5191 | 5192 | ||
5192 | if (unlikely(wl->state == WLCORE_STATE_OFF)) { | 5193 | if (unlikely(wl->state == WLCORE_STATE_OFF)) { |
5193 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | 5194 | if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) |
5194 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
5195 | |||
5196 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
5197 | continue; | ||
5198 | |||
5199 | ieee80211_chswitch_done(vif, false); | 5195 | ieee80211_chswitch_done(vif, false); |
5200 | } | ||
5201 | goto out; | 5196 | goto out; |
5202 | } else if (unlikely(wl->state != WLCORE_STATE_ON)) { | 5197 | } else if (unlikely(wl->state != WLCORE_STATE_ON)) { |
5203 | goto out; | 5198 | goto out; |
@@ -5208,11 +5203,9 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, | |||
5208 | goto out; | 5203 | goto out; |
5209 | 5204 | ||
5210 | /* TODO: change mac80211 to pass vif as param */ | 5205 | /* TODO: change mac80211 to pass vif as param */ |
5211 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
5212 | unsigned long delay_usec; | ||
5213 | 5206 | ||
5214 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | 5207 | if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { |
5215 | continue; | 5208 | unsigned long delay_usec; |
5216 | 5209 | ||
5217 | ret = wl->ops->channel_switch(wl, wlvif, ch_switch); | 5210 | ret = wl->ops->channel_switch(wl, wlvif, ch_switch); |
5218 | if (ret) | 5211 | if (ret) |
@@ -5222,10 +5215,10 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, | |||
5222 | 5215 | ||
5223 | /* indicate failure 5 seconds after channel switch time */ | 5216 | /* indicate failure 5 seconds after channel switch time */ |
5224 | delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) * | 5217 | delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) * |
5225 | ch_switch->count; | 5218 | ch_switch->count; |
5226 | ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work, | 5219 | ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work, |
5227 | usecs_to_jiffies(delay_usec) + | 5220 | usecs_to_jiffies(delay_usec) + |
5228 | msecs_to_jiffies(5000)); | 5221 | msecs_to_jiffies(5000)); |
5229 | } | 5222 | } |
5230 | 5223 | ||
5231 | out_sleep: | 5224 | out_sleep: |
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index 440291ab7263..fc02e8d6a193 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c | |||
@@ -29,8 +29,8 @@ | |||
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/nfc.h> | 30 | #include <linux/nfc.h> |
31 | #include <linux/firmware.h> | 31 | #include <linux/firmware.h> |
32 | #include <linux/unaligned/access_ok.h> | ||
33 | #include <linux/platform_data/pn544.h> | 32 | #include <linux/platform_data/pn544.h> |
33 | #include <asm/unaligned.h> | ||
34 | 34 | ||
35 | #include <net/nfc/hci.h> | 35 | #include <net/nfc/hci.h> |
36 | #include <net/nfc/llc.h> | 36 | #include <net/nfc/llc.h> |
diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 0ea756b77519..05722085a59f 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c | |||
@@ -28,8 +28,8 @@ | |||
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/nfc.h> | 29 | #include <linux/nfc.h> |
30 | #include <linux/firmware.h> | 30 | #include <linux/firmware.h> |
31 | #include <linux/unaligned/access_ok.h> | ||
32 | #include <linux/platform_data/st21nfca.h> | 31 | #include <linux/platform_data/st21nfca.h> |
32 | #include <asm/unaligned.h> | ||
33 | 33 | ||
34 | #include <net/nfc/hci.h> | 34 | #include <net/nfc/hci.h> |
35 | #include <net/nfc/llc.h> | 35 | #include <net/nfc/llc.h> |
@@ -72,7 +72,6 @@ struct st21nfca_i2c_phy { | |||
72 | struct nfc_hci_dev *hdev; | 72 | struct nfc_hci_dev *hdev; |
73 | 73 | ||
74 | unsigned int gpio_ena; | 74 | unsigned int gpio_ena; |
75 | unsigned int gpio_irq; | ||
76 | unsigned int irq_polarity; | 75 | unsigned int irq_polarity; |
77 | 76 | ||
78 | struct sk_buff *pending_skb; | 77 | struct sk_buff *pending_skb; |
@@ -531,20 +530,12 @@ static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client) | |||
531 | "clf_enable"); | 530 | "clf_enable"); |
532 | if (r) { | 531 | if (r) { |
533 | nfc_err(&client->dev, "Failed to request enable pin\n"); | 532 | nfc_err(&client->dev, "Failed to request enable pin\n"); |
534 | return -ENODEV; | 533 | return r; |
535 | } | 534 | } |
536 | 535 | ||
537 | phy->gpio_ena = gpio; | 536 | phy->gpio_ena = gpio; |
538 | 537 | ||
539 | /* IRQ */ | 538 | phy->irq_polarity = irq_get_trigger_type(client->irq); |
540 | r = irq_of_parse_and_map(pp, 0); | ||
541 | if (r < 0) { | ||
542 | nfc_err(&client->dev, "Unable to get irq, error: %d\n", r); | ||
543 | return r; | ||
544 | } | ||
545 | |||
546 | phy->irq_polarity = irq_get_trigger_type(r); | ||
547 | client->irq = r; | ||
548 | 539 | ||
549 | return 0; | 540 | return 0; |
550 | } | 541 | } |
@@ -560,7 +551,6 @@ static int st21nfca_hci_i2c_request_resources(struct i2c_client *client) | |||
560 | struct st21nfca_nfc_platform_data *pdata; | 551 | struct st21nfca_nfc_platform_data *pdata; |
561 | struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client); | 552 | struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client); |
562 | int r; | 553 | int r; |
563 | int irq; | ||
564 | 554 | ||
565 | pdata = client->dev.platform_data; | 555 | pdata = client->dev.platform_data; |
566 | if (pdata == NULL) { | 556 | if (pdata == NULL) { |
@@ -569,36 +559,18 @@ static int st21nfca_hci_i2c_request_resources(struct i2c_client *client) | |||
569 | } | 559 | } |
570 | 560 | ||
571 | /* store for later use */ | 561 | /* store for later use */ |
572 | phy->gpio_irq = pdata->gpio_irq; | ||
573 | phy->gpio_ena = pdata->gpio_ena; | 562 | phy->gpio_ena = pdata->gpio_ena; |
574 | phy->irq_polarity = pdata->irq_polarity; | 563 | phy->irq_polarity = pdata->irq_polarity; |
575 | 564 | ||
576 | r = devm_gpio_request_one(&client->dev, phy->gpio_irq, GPIOF_IN, | ||
577 | "wake_up"); | ||
578 | if (r) { | ||
579 | pr_err("%s : gpio_request failed\n", __FILE__); | ||
580 | return -ENODEV; | ||
581 | } | ||
582 | |||
583 | if (phy->gpio_ena > 0) { | 565 | if (phy->gpio_ena > 0) { |
584 | r = devm_gpio_request_one(&client->dev, phy->gpio_ena, | 566 | r = devm_gpio_request_one(&client->dev, phy->gpio_ena, |
585 | GPIOF_OUT_INIT_HIGH, "clf_enable"); | 567 | GPIOF_OUT_INIT_HIGH, "clf_enable"); |
586 | if (r) { | 568 | if (r) { |
587 | pr_err("%s : ena gpio_request failed\n", __FILE__); | 569 | pr_err("%s : ena gpio_request failed\n", __FILE__); |
588 | return -ENODEV; | 570 | return r; |
589 | } | 571 | } |
590 | } | 572 | } |
591 | 573 | ||
592 | /* IRQ */ | ||
593 | irq = gpio_to_irq(phy->gpio_irq); | ||
594 | if (irq < 0) { | ||
595 | nfc_err(&client->dev, | ||
596 | "Unable to get irq number for GPIO %d error %d\n", | ||
597 | phy->gpio_irq, r); | ||
598 | return -ENODEV; | ||
599 | } | ||
600 | client->irq = irq; | ||
601 | |||
602 | return 0; | 574 | return 0; |
603 | } | 575 | } |
604 | 576 | ||
@@ -656,7 +628,7 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client, | |||
656 | r = st21nfca_hci_platform_init(phy); | 628 | r = st21nfca_hci_platform_init(phy); |
657 | if (r < 0) { | 629 | if (r < 0) { |
658 | nfc_err(&client->dev, "Unable to reboot st21nfca\n"); | 630 | nfc_err(&client->dev, "Unable to reboot st21nfca\n"); |
659 | return -ENODEV; | 631 | return r; |
660 | } | 632 | } |
661 | 633 | ||
662 | r = devm_request_threaded_irq(&client->dev, client->irq, NULL, | 634 | r = devm_request_threaded_irq(&client->dev, client->irq, NULL, |
@@ -687,10 +659,13 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client) | |||
687 | return 0; | 659 | return 0; |
688 | } | 660 | } |
689 | 661 | ||
662 | #ifdef CONFIG_OF | ||
690 | static const struct of_device_id of_st21nfca_i2c_match[] = { | 663 | static const struct of_device_id of_st21nfca_i2c_match[] = { |
691 | { .compatible = "st,st21nfca_i2c", }, | 664 | { .compatible = "st,st21nfca_i2c", }, |
692 | {} | 665 | {} |
693 | }; | 666 | }; |
667 | MODULE_DEVICE_TABLE(of, of_st21nfca_i2c_match); | ||
668 | #endif | ||
694 | 669 | ||
695 | static struct i2c_driver st21nfca_hci_i2c_driver = { | 670 | static struct i2c_driver st21nfca_hci_i2c_driver = { |
696 | .driver = { | 671 | .driver = { |
diff --git a/drivers/nfc/st21nfca/st21nfca.c b/drivers/nfc/st21nfca/st21nfca.c index a89e56c2c749..f2596c8d68b0 100644 --- a/drivers/nfc/st21nfca/st21nfca.c +++ b/drivers/nfc/st21nfca/st21nfca.c | |||
@@ -77,10 +77,6 @@ | |||
77 | ((p & 0x0f) == (ST21NFCA_DM_PIPE_CREATED | ST21NFCA_DM_PIPE_OPEN)) | 77 | ((p & 0x0f) == (ST21NFCA_DM_PIPE_CREATED | ST21NFCA_DM_PIPE_OPEN)) |
78 | 78 | ||
79 | #define ST21NFCA_NFC_MODE 0x03 /* NFC_MODE parameter*/ | 79 | #define ST21NFCA_NFC_MODE 0x03 /* NFC_MODE parameter*/ |
80 | #define ST21NFCA_EVT_FIELD_ON 0x11 | ||
81 | #define ST21NFCA_EVT_CARD_DEACTIVATED 0x12 | ||
82 | #define ST21NFCA_EVT_CARD_ACTIVATED 0x13 | ||
83 | #define ST21NFCA_EVT_FIELD_OFF 0x14 | ||
84 | 80 | ||
85 | static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES); | 81 | static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES); |
86 | 82 | ||
@@ -841,31 +837,11 @@ static int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev, | |||
841 | static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, | 837 | static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, |
842 | u8 event, struct sk_buff *skb) | 838 | u8 event, struct sk_buff *skb) |
843 | { | 839 | { |
844 | int r; | 840 | pr_debug("hci event: %d gate: %x\n", event, gate); |
845 | struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); | ||
846 | |||
847 | pr_debug("hci event: %d\n", event); | ||
848 | 841 | ||
849 | switch (event) { | 842 | switch (gate) { |
850 | case ST21NFCA_EVT_CARD_ACTIVATED: | 843 | case ST21NFCA_RF_CARD_F_GATE: |
851 | if (gate == ST21NFCA_RF_CARD_F_GATE) | 844 | return st21nfca_dep_event_received(hdev, event, skb); |
852 | info->dep_info.curr_nfc_dep_pni = 0; | ||
853 | break; | ||
854 | case ST21NFCA_EVT_CARD_DEACTIVATED: | ||
855 | break; | ||
856 | case ST21NFCA_EVT_FIELD_ON: | ||
857 | break; | ||
858 | case ST21NFCA_EVT_FIELD_OFF: | ||
859 | break; | ||
860 | case ST21NFCA_EVT_SEND_DATA: | ||
861 | if (gate == ST21NFCA_RF_CARD_F_GATE) { | ||
862 | r = st21nfca_tm_event_send_data(hdev, skb, gate); | ||
863 | if (r < 0) | ||
864 | return r; | ||
865 | return 0; | ||
866 | } | ||
867 | info->dep_info.curr_nfc_dep_pni = 0; | ||
868 | return 1; | ||
869 | default: | 845 | default: |
870 | return 1; | 846 | return 1; |
871 | } | 847 | } |
diff --git a/drivers/nfc/st21nfca/st21nfca.h b/drivers/nfc/st21nfca/st21nfca.h index a0b77f1ba6d9..7c2a85292230 100644 --- a/drivers/nfc/st21nfca/st21nfca.h +++ b/drivers/nfc/st21nfca/st21nfca.h | |||
@@ -85,6 +85,4 @@ struct st21nfca_hci_info { | |||
85 | 85 | ||
86 | #define ST21NFCA_RF_CARD_F_GATE 0x24 | 86 | #define ST21NFCA_RF_CARD_F_GATE 0x24 |
87 | 87 | ||
88 | #define ST21NFCA_EVT_SEND_DATA 0x10 | ||
89 | |||
90 | #endif /* __LOCAL_ST21NFCA_H_ */ | 88 | #endif /* __LOCAL_ST21NFCA_H_ */ |
diff --git a/drivers/nfc/st21nfca/st21nfca_dep.c b/drivers/nfc/st21nfca/st21nfca_dep.c index bfb6df56c505..8882181d65de 100644 --- a/drivers/nfc/st21nfca/st21nfca_dep.c +++ b/drivers/nfc/st21nfca/st21nfca_dep.c | |||
@@ -49,6 +49,12 @@ | |||
49 | #define ST21NFCA_LR_BITS_PAYLOAD_SIZE_254B 0x30 | 49 | #define ST21NFCA_LR_BITS_PAYLOAD_SIZE_254B 0x30 |
50 | #define ST21NFCA_GB_BIT 0x02 | 50 | #define ST21NFCA_GB_BIT 0x02 |
51 | 51 | ||
52 | #define ST21NFCA_EVT_SEND_DATA 0x10 | ||
53 | #define ST21NFCA_EVT_FIELD_ON 0x11 | ||
54 | #define ST21NFCA_EVT_CARD_DEACTIVATED 0x12 | ||
55 | #define ST21NFCA_EVT_CARD_ACTIVATED 0x13 | ||
56 | #define ST21NFCA_EVT_FIELD_OFF 0x14 | ||
57 | |||
52 | #define ST21NFCA_EVT_CARD_F_BITRATE 0x16 | 58 | #define ST21NFCA_EVT_CARD_F_BITRATE 0x16 |
53 | #define ST21NFCA_EVT_READER_F_BITRATE 0x13 | 59 | #define ST21NFCA_EVT_READER_F_BITRATE 0x13 |
54 | #define ST21NFCA_PSL_REQ_SEND_SPEED(brs) (brs & 0x38) | 60 | #define ST21NFCA_PSL_REQ_SEND_SPEED(brs) (brs & 0x38) |
@@ -372,8 +378,8 @@ exit: | |||
372 | return r; | 378 | return r; |
373 | } | 379 | } |
374 | 380 | ||
375 | int st21nfca_tm_event_send_data(struct nfc_hci_dev *hdev, struct sk_buff *skb, | 381 | static int st21nfca_tm_event_send_data(struct nfc_hci_dev *hdev, |
376 | u8 gate) | 382 | struct sk_buff *skb) |
377 | { | 383 | { |
378 | u8 cmd0, cmd1; | 384 | u8 cmd0, cmd1; |
379 | int r; | 385 | int r; |
@@ -400,7 +406,42 @@ int st21nfca_tm_event_send_data(struct nfc_hci_dev *hdev, struct sk_buff *skb, | |||
400 | } | 406 | } |
401 | return r; | 407 | return r; |
402 | } | 408 | } |
403 | EXPORT_SYMBOL(st21nfca_tm_event_send_data); | 409 | |
410 | /* | ||
411 | * Returns: | ||
412 | * <= 0: driver handled the event, skb consumed | ||
413 | * 1: driver does not handle the event, please do standard processing | ||
414 | */ | ||
415 | int st21nfca_dep_event_received(struct nfc_hci_dev *hdev, | ||
416 | u8 event, struct sk_buff *skb) | ||
417 | { | ||
418 | int r = 0; | ||
419 | struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); | ||
420 | |||
421 | pr_debug("dep event: %d\n", event); | ||
422 | |||
423 | switch (event) { | ||
424 | case ST21NFCA_EVT_CARD_ACTIVATED: | ||
425 | info->dep_info.curr_nfc_dep_pni = 0; | ||
426 | break; | ||
427 | case ST21NFCA_EVT_CARD_DEACTIVATED: | ||
428 | break; | ||
429 | case ST21NFCA_EVT_FIELD_ON: | ||
430 | break; | ||
431 | case ST21NFCA_EVT_FIELD_OFF: | ||
432 | break; | ||
433 | case ST21NFCA_EVT_SEND_DATA: | ||
434 | r = st21nfca_tm_event_send_data(hdev, skb); | ||
435 | if (r < 0) | ||
436 | return r; | ||
437 | return 0; | ||
438 | default: | ||
439 | return 1; | ||
440 | } | ||
441 | kfree_skb(skb); | ||
442 | return r; | ||
443 | } | ||
444 | EXPORT_SYMBOL(st21nfca_dep_event_received); | ||
404 | 445 | ||
405 | static void st21nfca_im_send_psl_req(struct nfc_hci_dev *hdev, u8 did, u8 bsi, | 446 | static void st21nfca_im_send_psl_req(struct nfc_hci_dev *hdev, u8 did, u8 bsi, |
406 | u8 bri, u8 lri) | 447 | u8 bri, u8 lri) |
diff --git a/drivers/nfc/st21nfca/st21nfca_dep.h b/drivers/nfc/st21nfca/st21nfca_dep.h index ca213dee9c6e..baf4664b4fc4 100644 --- a/drivers/nfc/st21nfca/st21nfca_dep.h +++ b/drivers/nfc/st21nfca/st21nfca_dep.h | |||
@@ -32,8 +32,8 @@ struct st21nfca_dep_info { | |||
32 | u8 lri; | 32 | u8 lri; |
33 | } __packed; | 33 | } __packed; |
34 | 34 | ||
35 | int st21nfca_tm_event_send_data(struct nfc_hci_dev *hdev, struct sk_buff *skb, | 35 | int st21nfca_dep_event_received(struct nfc_hci_dev *hdev, |
36 | u8 gate); | 36 | u8 event, struct sk_buff *skb); |
37 | int st21nfca_tm_send_dep_res(struct nfc_hci_dev *hdev, struct sk_buff *skb); | 37 | int st21nfca_tm_send_dep_res(struct nfc_hci_dev *hdev, struct sk_buff *skb); |
38 | 38 | ||
39 | int st21nfca_im_send_atr_req(struct nfc_hci_dev *hdev, u8 *gb, size_t gb_len); | 39 | int st21nfca_im_send_atr_req(struct nfc_hci_dev *hdev, u8 *gb, size_t gb_len); |
diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st21nfcb/i2c.c index c5d2427a3db2..01ba865863ee 100644 --- a/drivers/nfc/st21nfcb/i2c.c +++ b/drivers/nfc/st21nfcb/i2c.c | |||
@@ -50,7 +50,6 @@ struct st21nfcb_i2c_phy { | |||
50 | struct i2c_client *i2c_dev; | 50 | struct i2c_client *i2c_dev; |
51 | struct llt_ndlc *ndlc; | 51 | struct llt_ndlc *ndlc; |
52 | 52 | ||
53 | unsigned int gpio_irq; | ||
54 | unsigned int gpio_reset; | 53 | unsigned int gpio_reset; |
55 | unsigned int irq_polarity; | 54 | unsigned int irq_polarity; |
56 | 55 | ||
@@ -81,8 +80,6 @@ static void st21nfcb_nci_i2c_disable(void *phy_id) | |||
81 | { | 80 | { |
82 | struct st21nfcb_i2c_phy *phy = phy_id; | 81 | struct st21nfcb_i2c_phy *phy = phy_id; |
83 | 82 | ||
84 | pr_info("\n"); | ||
85 | |||
86 | phy->powered = 0; | 83 | phy->powered = 0; |
87 | /* reset chip in order to flush clf */ | 84 | /* reset chip in order to flush clf */ |
88 | gpio_set_value(phy->gpio_reset, 0); | 85 | gpio_set_value(phy->gpio_reset, 0); |
@@ -258,19 +255,11 @@ static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client) | |||
258 | GPIOF_OUT_INIT_HIGH, "clf_reset"); | 255 | GPIOF_OUT_INIT_HIGH, "clf_reset"); |
259 | if (r) { | 256 | if (r) { |
260 | nfc_err(&client->dev, "Failed to request reset pin\n"); | 257 | nfc_err(&client->dev, "Failed to request reset pin\n"); |
261 | return -ENODEV; | ||
262 | } | ||
263 | phy->gpio_reset = gpio; | ||
264 | |||
265 | /* IRQ */ | ||
266 | r = irq_of_parse_and_map(pp, 0); | ||
267 | if (r < 0) { | ||
268 | nfc_err(&client->dev, "Unable to get irq, error: %d\n", r); | ||
269 | return r; | 258 | return r; |
270 | } | 259 | } |
260 | phy->gpio_reset = gpio; | ||
271 | 261 | ||
272 | phy->irq_polarity = irq_get_trigger_type(r); | 262 | phy->irq_polarity = irq_get_trigger_type(client->irq); |
273 | client->irq = r; | ||
274 | 263 | ||
275 | return 0; | 264 | return 0; |
276 | } | 265 | } |
@@ -286,7 +275,6 @@ static int st21nfcb_nci_i2c_request_resources(struct i2c_client *client) | |||
286 | struct st21nfcb_nfc_platform_data *pdata; | 275 | struct st21nfcb_nfc_platform_data *pdata; |
287 | struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client); | 276 | struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client); |
288 | int r; | 277 | int r; |
289 | int irq; | ||
290 | 278 | ||
291 | pdata = client->dev.platform_data; | 279 | pdata = client->dev.platform_data; |
292 | if (pdata == NULL) { | 280 | if (pdata == NULL) { |
@@ -295,33 +283,15 @@ static int st21nfcb_nci_i2c_request_resources(struct i2c_client *client) | |||
295 | } | 283 | } |
296 | 284 | ||
297 | /* store for later use */ | 285 | /* store for later use */ |
298 | phy->gpio_irq = pdata->gpio_irq; | ||
299 | phy->gpio_reset = pdata->gpio_reset; | 286 | phy->gpio_reset = pdata->gpio_reset; |
300 | phy->irq_polarity = pdata->irq_polarity; | 287 | phy->irq_polarity = pdata->irq_polarity; |
301 | 288 | ||
302 | r = devm_gpio_request_one(&client->dev, phy->gpio_irq, | ||
303 | GPIOF_IN, "clf_irq"); | ||
304 | if (r) { | ||
305 | pr_err("%s : gpio_request failed\n", __FILE__); | ||
306 | return -ENODEV; | ||
307 | } | ||
308 | |||
309 | r = devm_gpio_request_one(&client->dev, | 289 | r = devm_gpio_request_one(&client->dev, |
310 | phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset"); | 290 | phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset"); |
311 | if (r) { | 291 | if (r) { |
312 | pr_err("%s : reset gpio_request failed\n", __FILE__); | 292 | pr_err("%s : reset gpio_request failed\n", __FILE__); |
313 | return -ENODEV; | 293 | return r; |
314 | } | ||
315 | |||
316 | /* IRQ */ | ||
317 | irq = gpio_to_irq(phy->gpio_irq); | ||
318 | if (irq < 0) { | ||
319 | nfc_err(&client->dev, | ||
320 | "Unable to get irq number for GPIO %d error %d\n", | ||
321 | phy->gpio_irq, r); | ||
322 | return -ENODEV; | ||
323 | } | 294 | } |
324 | client->irq = irq; | ||
325 | 295 | ||
326 | return 0; | 296 | return 0; |
327 | } | 297 | } |
@@ -401,10 +371,13 @@ static int st21nfcb_nci_i2c_remove(struct i2c_client *client) | |||
401 | return 0; | 371 | return 0; |
402 | } | 372 | } |
403 | 373 | ||
374 | #ifdef CONFIG_OF | ||
404 | static const struct of_device_id of_st21nfcb_i2c_match[] = { | 375 | static const struct of_device_id of_st21nfcb_i2c_match[] = { |
405 | { .compatible = "st,st21nfcb_i2c", }, | 376 | { .compatible = "st,st21nfcb_i2c", }, |
406 | {} | 377 | {} |
407 | }; | 378 | }; |
379 | MODULE_DEVICE_TABLE(of, of_st21nfcb_i2c_match); | ||
380 | #endif | ||
408 | 381 | ||
409 | static struct i2c_driver st21nfcb_nci_i2c_driver = { | 382 | static struct i2c_driver st21nfcb_nci_i2c_driver = { |
410 | .driver = { | 383 | .driver = { |
diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st21nfcb/ndlc.c index e7bff8921d11..bac50e805f1d 100644 --- a/drivers/nfc/st21nfcb/ndlc.c +++ b/drivers/nfc/st21nfcb/ndlc.c | |||
@@ -266,7 +266,7 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, | |||
266 | 266 | ||
267 | *ndlc_id = ndlc; | 267 | *ndlc_id = ndlc; |
268 | 268 | ||
269 | /* start timers */ | 269 | /* initialize timers */ |
270 | init_timer(&ndlc->t1_timer); | 270 | init_timer(&ndlc->t1_timer); |
271 | ndlc->t1_timer.data = (unsigned long)ndlc; | 271 | ndlc->t1_timer.data = (unsigned long)ndlc; |
272 | ndlc->t1_timer.function = ndlc_t1_timeout; | 272 | ndlc->t1_timer.function = ndlc_t1_timeout; |
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c index 69161bbc4d0b..410215c16920 100644 --- a/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c | |||
@@ -11,15 +11,17 @@ | |||
11 | * Licensed under the GNU/GPL. See COPYING for details. | 11 | * Licensed under the GNU/GPL. See COPYING for details. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/pm.h> | ||
14 | #include <linux/pci.h> | 15 | #include <linux/pci.h> |
15 | #include <linux/export.h> | 16 | #include <linux/export.h> |
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
17 | #include <linux/ssb/ssb.h> | 18 | #include <linux/ssb/ssb.h> |
18 | 19 | ||
19 | 20 | ||
20 | #ifdef CONFIG_PM | 21 | #ifdef CONFIG_PM_SLEEP |
21 | static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) | 22 | static int ssb_pcihost_suspend(struct device *d) |
22 | { | 23 | { |
24 | struct pci_dev *dev = to_pci_dev(d); | ||
23 | struct ssb_bus *ssb = pci_get_drvdata(dev); | 25 | struct ssb_bus *ssb = pci_get_drvdata(dev); |
24 | int err; | 26 | int err; |
25 | 27 | ||
@@ -28,17 +30,23 @@ static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) | |||
28 | return err; | 30 | return err; |
29 | pci_save_state(dev); | 31 | pci_save_state(dev); |
30 | pci_disable_device(dev); | 32 | pci_disable_device(dev); |
31 | pci_set_power_state(dev, pci_choose_state(dev, state)); | 33 | |
34 | /* if there is a wakeup enabled child device on ssb bus, | ||
35 | enable pci wakeup posibility. */ | ||
36 | device_set_wakeup_enable(d, d->power.wakeup_path); | ||
37 | |||
38 | pci_prepare_to_sleep(dev); | ||
32 | 39 | ||
33 | return 0; | 40 | return 0; |
34 | } | 41 | } |
35 | 42 | ||
36 | static int ssb_pcihost_resume(struct pci_dev *dev) | 43 | static int ssb_pcihost_resume(struct device *d) |
37 | { | 44 | { |
45 | struct pci_dev *dev = to_pci_dev(d); | ||
38 | struct ssb_bus *ssb = pci_get_drvdata(dev); | 46 | struct ssb_bus *ssb = pci_get_drvdata(dev); |
39 | int err; | 47 | int err; |
40 | 48 | ||
41 | pci_set_power_state(dev, PCI_D0); | 49 | pci_back_from_sleep(dev); |
42 | err = pci_enable_device(dev); | 50 | err = pci_enable_device(dev); |
43 | if (err) | 51 | if (err) |
44 | return err; | 52 | return err; |
@@ -49,10 +57,12 @@ static int ssb_pcihost_resume(struct pci_dev *dev) | |||
49 | 57 | ||
50 | return 0; | 58 | return 0; |
51 | } | 59 | } |
52 | #else /* CONFIG_PM */ | 60 | |
53 | # define ssb_pcihost_suspend NULL | 61 | static const struct dev_pm_ops ssb_pcihost_pm_ops = { |
54 | # define ssb_pcihost_resume NULL | 62 | SET_SYSTEM_SLEEP_PM_OPS(ssb_pcihost_suspend, ssb_pcihost_resume) |
55 | #endif /* CONFIG_PM */ | 63 | }; |
64 | |||
65 | #endif /* CONFIG_PM_SLEEP */ | ||
56 | 66 | ||
57 | static int ssb_pcihost_probe(struct pci_dev *dev, | 67 | static int ssb_pcihost_probe(struct pci_dev *dev, |
58 | const struct pci_device_id *id) | 68 | const struct pci_device_id *id) |
@@ -115,8 +125,9 @@ int ssb_pcihost_register(struct pci_driver *driver) | |||
115 | { | 125 | { |
116 | driver->probe = ssb_pcihost_probe; | 126 | driver->probe = ssb_pcihost_probe; |
117 | driver->remove = ssb_pcihost_remove; | 127 | driver->remove = ssb_pcihost_remove; |
118 | driver->suspend = ssb_pcihost_suspend; | 128 | #ifdef CONFIG_PM_SLEEP |
119 | driver->resume = ssb_pcihost_resume; | 129 | driver->driver.pm = &ssb_pcihost_pm_ops; |
130 | #endif | ||
120 | 131 | ||
121 | return pci_register_driver(driver); | 132 | return pci_register_driver(driver); |
122 | } | 133 | } |
diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c index bd6953af0a03..3d26955da724 100644 --- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c | |||
@@ -2856,8 +2856,10 @@ static int cfg80211_rtw_add_station(struct wiphy *wiphy, | |||
2856 | } | 2856 | } |
2857 | 2857 | ||
2858 | static int cfg80211_rtw_del_station(struct wiphy *wiphy, | 2858 | static int cfg80211_rtw_del_station(struct wiphy *wiphy, |
2859 | struct net_device *ndev, const u8 *mac) | 2859 | struct net_device *ndev, |
2860 | struct station_del_parameters *params) | ||
2860 | { | 2861 | { |
2862 | const u8 *mac = params->mac; | ||
2861 | int ret = 0; | 2863 | int ret = 0; |
2862 | struct list_head *phead, *plist, *ptmp; | 2864 | struct list_head *phead, *plist, *ptmp; |
2863 | u8 updated = 0; | 2865 | u8 updated = 0; |
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 2fbff907ce8a..dbc311c3dc37 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c | |||
@@ -856,7 +856,9 @@ static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
856 | return 0; | 856 | return 0; |
857 | } | 857 | } |
858 | 858 | ||
859 | static void vnt_sw_scan_start(struct ieee80211_hw *hw) | 859 | static void vnt_sw_scan_start(struct ieee80211_hw *hw, |
860 | struct ieee80211_vif *vif, | ||
861 | const u8 *addr) | ||
860 | { | 862 | { |
861 | struct vnt_private *priv = hw->priv; | 863 | struct vnt_private *priv = hw->priv; |
862 | 864 | ||
@@ -865,7 +867,8 @@ static void vnt_sw_scan_start(struct ieee80211_hw *hw) | |||
865 | vnt_update_pre_ed_threshold(priv, true); | 867 | vnt_update_pre_ed_threshold(priv, true); |
866 | } | 868 | } |
867 | 869 | ||
868 | static void vnt_sw_scan_complete(struct ieee80211_hw *hw) | 870 | static void vnt_sw_scan_complete(struct ieee80211_hw *hw, |
871 | struct ieee80211_vif *vif) | ||
869 | { | 872 | { |
870 | struct vnt_private *priv = hw->priv; | 873 | struct vnt_private *priv = hw->priv; |
871 | 874 | ||
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 729f48e6b20b..eb1c6a47b67f 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h | |||
@@ -447,4 +447,6 @@ extern u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset); | |||
447 | #define BCMA_DMA_TRANSLATION_DMA64_CMT 0x80000000 /* Client Mode Translation for 64-bit DMA */ | 447 | #define BCMA_DMA_TRANSLATION_DMA64_CMT 0x80000000 /* Client Mode Translation for 64-bit DMA */ |
448 | extern u32 bcma_core_dma_translation(struct bcma_device *core); | 448 | extern u32 bcma_core_dma_translation(struct bcma_device *core); |
449 | 449 | ||
450 | extern unsigned int bcma_core_irq(struct bcma_device *core, int num); | ||
451 | |||
450 | #endif /* LINUX_BCMA_H_ */ | 452 | #endif /* LINUX_BCMA_H_ */ |
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h index fb61f3fb4ddb..0b3b32aeeb8a 100644 --- a/include/linux/bcma/bcma_driver_mips.h +++ b/include/linux/bcma/bcma_driver_mips.h | |||
@@ -43,12 +43,12 @@ struct bcma_drv_mips { | |||
43 | extern void bcma_core_mips_init(struct bcma_drv_mips *mcore); | 43 | extern void bcma_core_mips_init(struct bcma_drv_mips *mcore); |
44 | extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore); | 44 | extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore); |
45 | 45 | ||
46 | extern unsigned int bcma_core_irq(struct bcma_device *core); | 46 | extern unsigned int bcma_core_mips_irq(struct bcma_device *dev); |
47 | #else | 47 | #else |
48 | static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { } | 48 | static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { } |
49 | static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { } | 49 | static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { } |
50 | 50 | ||
51 | static inline unsigned int bcma_core_irq(struct bcma_device *core) | 51 | static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev) |
52 | { | 52 | { |
53 | return 0; | 53 | return 0; |
54 | } | 54 | } |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index b1be39c76931..4f4eea8a6288 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/types.h> | 19 | #include <linux/types.h> |
20 | #include <linux/if_ether.h> | 20 | #include <linux/if_ether.h> |
21 | #include <asm/byteorder.h> | 21 | #include <asm/byteorder.h> |
22 | #include <asm/unaligned.h> | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * DS bit usage | 25 | * DS bit usage |
@@ -1066,6 +1067,12 @@ struct ieee80211_pspoll { | |||
1066 | 1067 | ||
1067 | /* TDLS */ | 1068 | /* TDLS */ |
1068 | 1069 | ||
1070 | /* Channel switch timing */ | ||
1071 | struct ieee80211_ch_switch_timing { | ||
1072 | __le16 switch_time; | ||
1073 | __le16 switch_timeout; | ||
1074 | } __packed; | ||
1075 | |||
1069 | /* Link-id information element */ | 1076 | /* Link-id information element */ |
1070 | struct ieee80211_tdls_lnkie { | 1077 | struct ieee80211_tdls_lnkie { |
1071 | u8 ie_type; /* Link Identifier IE */ | 1078 | u8 ie_type; /* Link Identifier IE */ |
@@ -1107,6 +1114,15 @@ struct ieee80211_tdls_data { | |||
1107 | u8 dialog_token; | 1114 | u8 dialog_token; |
1108 | u8 variable[0]; | 1115 | u8 variable[0]; |
1109 | } __packed discover_req; | 1116 | } __packed discover_req; |
1117 | struct { | ||
1118 | u8 target_channel; | ||
1119 | u8 oper_class; | ||
1120 | u8 variable[0]; | ||
1121 | } __packed chan_switch_req; | ||
1122 | struct { | ||
1123 | __le16 status_code; | ||
1124 | u8 variable[0]; | ||
1125 | } __packed chan_switch_resp; | ||
1110 | } u; | 1126 | } u; |
1111 | } __packed; | 1127 | } __packed; |
1112 | 1128 | ||
@@ -1274,7 +1290,7 @@ struct ieee80211_ht_cap { | |||
1274 | #define IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT 2 | 1290 | #define IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT 2 |
1275 | 1291 | ||
1276 | /* | 1292 | /* |
1277 | * Maximum length of AMPDU that the STA can receive. | 1293 | * Maximum length of AMPDU that the STA can receive in high-throughput (HT). |
1278 | * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) | 1294 | * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) |
1279 | */ | 1295 | */ |
1280 | enum ieee80211_max_ampdu_length_exp { | 1296 | enum ieee80211_max_ampdu_length_exp { |
@@ -1284,6 +1300,21 @@ enum ieee80211_max_ampdu_length_exp { | |||
1284 | IEEE80211_HT_MAX_AMPDU_64K = 3 | 1300 | IEEE80211_HT_MAX_AMPDU_64K = 3 |
1285 | }; | 1301 | }; |
1286 | 1302 | ||
1303 | /* | ||
1304 | * Maximum length of AMPDU that the STA can receive in VHT. | ||
1305 | * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) | ||
1306 | */ | ||
1307 | enum ieee80211_vht_max_ampdu_length_exp { | ||
1308 | IEEE80211_VHT_MAX_AMPDU_8K = 0, | ||
1309 | IEEE80211_VHT_MAX_AMPDU_16K = 1, | ||
1310 | IEEE80211_VHT_MAX_AMPDU_32K = 2, | ||
1311 | IEEE80211_VHT_MAX_AMPDU_64K = 3, | ||
1312 | IEEE80211_VHT_MAX_AMPDU_128K = 4, | ||
1313 | IEEE80211_VHT_MAX_AMPDU_256K = 5, | ||
1314 | IEEE80211_VHT_MAX_AMPDU_512K = 6, | ||
1315 | IEEE80211_VHT_MAX_AMPDU_1024K = 7 | ||
1316 | }; | ||
1317 | |||
1287 | #define IEEE80211_HT_MAX_AMPDU_FACTOR 13 | 1318 | #define IEEE80211_HT_MAX_AMPDU_FACTOR 13 |
1288 | 1319 | ||
1289 | /* Minimum MPDU start spacing */ | 1320 | /* Minimum MPDU start spacing */ |
@@ -1998,6 +2029,16 @@ enum ieee80211_tdls_actioncode { | |||
1998 | WLAN_TDLS_DISCOVERY_REQUEST = 10, | 2029 | WLAN_TDLS_DISCOVERY_REQUEST = 10, |
1999 | }; | 2030 | }; |
2000 | 2031 | ||
2032 | /* Extended Channel Switching capability to be set in the 1st byte of | ||
2033 | * the @WLAN_EID_EXT_CAPABILITY information element | ||
2034 | */ | ||
2035 | #define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2) | ||
2036 | |||
2037 | /* TDLS capabilities in the the 4th byte of @WLAN_EID_EXT_CAPABILITY */ | ||
2038 | #define WLAN_EXT_CAPA4_TDLS_BUFFER_STA BIT(4) | ||
2039 | #define WLAN_EXT_CAPA4_TDLS_PEER_PSM BIT(5) | ||
2040 | #define WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH BIT(6) | ||
2041 | |||
2001 | /* Interworking capabilities are set in 7th bit of 4th byte of the | 2042 | /* Interworking capabilities are set in 7th bit of 4th byte of the |
2002 | * @WLAN_EID_EXT_CAPABILITY information element | 2043 | * @WLAN_EID_EXT_CAPABILITY information element |
2003 | */ | 2044 | */ |
@@ -2009,6 +2050,7 @@ enum ieee80211_tdls_actioncode { | |||
2009 | */ | 2050 | */ |
2010 | #define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) | 2051 | #define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) |
2011 | #define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) | 2052 | #define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) |
2053 | #define WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED BIT(7) | ||
2012 | 2054 | ||
2013 | #define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6) | 2055 | #define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6) |
2014 | #define WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED BIT(7) | 2056 | #define WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED BIT(7) |
@@ -2016,6 +2058,9 @@ enum ieee80211_tdls_actioncode { | |||
2016 | /* TDLS specific payload type in the LLC/SNAP header */ | 2058 | /* TDLS specific payload type in the LLC/SNAP header */ |
2017 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 | 2059 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 |
2018 | 2060 | ||
2061 | /* BSS Coex IE information field bits */ | ||
2062 | #define WLAN_BSS_COEX_INFORMATION_REQUEST BIT(0) | ||
2063 | |||
2019 | /** | 2064 | /** |
2020 | * enum - mesh synchronization method identifier | 2065 | * enum - mesh synchronization method identifier |
2021 | * | 2066 | * |
@@ -2398,6 +2443,30 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim, | |||
2398 | return !!(tim->virtual_map[index] & mask); | 2443 | return !!(tim->virtual_map[index] & mask); |
2399 | } | 2444 | } |
2400 | 2445 | ||
2446 | /** | ||
2447 | * ieee80211_get_tdls_action - get tdls packet action (or -1, if not tdls packet) | ||
2448 | * @skb: the skb containing the frame, length will not be checked | ||
2449 | * @hdr_size: the size of the ieee80211_hdr that starts at skb->data | ||
2450 | * | ||
2451 | * This function assumes the frame is a data frame, and that the network header | ||
2452 | * is in the correct place. | ||
2453 | */ | ||
2454 | static inline int ieee80211_get_tdls_action(struct sk_buff *skb, u32 hdr_size) | ||
2455 | { | ||
2456 | if (!skb_is_nonlinear(skb) && | ||
2457 | skb->len > (skb_network_offset(skb) + 2)) { | ||
2458 | /* Point to where the indication of TDLS should start */ | ||
2459 | const u8 *tdls_data = skb_network_header(skb) - 2; | ||
2460 | |||
2461 | if (get_unaligned_be16(tdls_data) == ETH_P_TDLS && | ||
2462 | tdls_data[2] == WLAN_TDLS_SNAP_RFTYPE && | ||
2463 | tdls_data[3] == WLAN_CATEGORY_TDLS) | ||
2464 | return tdls_data[4]; | ||
2465 | } | ||
2466 | |||
2467 | return -1; | ||
2468 | } | ||
2469 | |||
2401 | /* convert time units */ | 2470 | /* convert time units */ |
2402 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) | 2471 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) |
2403 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) | 2472 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) |
diff --git a/include/linux/platform_data/st21nfca.h b/include/linux/platform_data/st21nfca.h index 1730312398ff..5087fff96d86 100644 --- a/include/linux/platform_data/st21nfca.h +++ b/include/linux/platform_data/st21nfca.h | |||
@@ -24,7 +24,6 @@ | |||
24 | #define ST21NFCA_HCI_DRIVER_NAME "st21nfca_hci" | 24 | #define ST21NFCA_HCI_DRIVER_NAME "st21nfca_hci" |
25 | 25 | ||
26 | struct st21nfca_nfc_platform_data { | 26 | struct st21nfca_nfc_platform_data { |
27 | unsigned int gpio_irq; | ||
28 | unsigned int gpio_ena; | 27 | unsigned int gpio_ena; |
29 | unsigned int irq_polarity; | 28 | unsigned int irq_polarity; |
30 | }; | 29 | }; |
diff --git a/include/linux/platform_data/st21nfcb.h b/include/linux/platform_data/st21nfcb.h index 2d11f1f5efab..c3b432f5b63e 100644 --- a/include/linux/platform_data/st21nfcb.h +++ b/include/linux/platform_data/st21nfcb.h | |||
@@ -24,7 +24,6 @@ | |||
24 | #define ST21NFCB_NCI_DRIVER_NAME "st21nfcb_nci" | 24 | #define ST21NFCB_NCI_DRIVER_NAME "st21nfcb_nci" |
25 | 25 | ||
26 | struct st21nfcb_nfc_platform_data { | 26 | struct st21nfcb_nfc_platform_data { |
27 | unsigned int gpio_irq; | ||
28 | unsigned int gpio_reset; | 27 | unsigned int gpio_reset; |
29 | unsigned int irq_polarity; | 28 | unsigned int irq_polarity; |
30 | }; | 29 | }; |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a2ddcf2398fd..4ebb816241fa 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -319,9 +319,12 @@ struct ieee80211_supported_band { | |||
319 | /** | 319 | /** |
320 | * struct vif_params - describes virtual interface parameters | 320 | * struct vif_params - describes virtual interface parameters |
321 | * @use_4addr: use 4-address frames | 321 | * @use_4addr: use 4-address frames |
322 | * @macaddr: address to use for this virtual interface. This will only | 322 | * @macaddr: address to use for this virtual interface. |
323 | * be used for non-netdevice interfaces. If this parameter is set | 323 | * If this parameter is set to zero address the driver may |
324 | * to zero address the driver may determine the address as needed. | 324 | * determine the address as needed. |
325 | * This feature is only fully supported by drivers that enable the | ||
326 | * %NL80211_FEATURE_MAC_ON_CREATE flag. Others may support creating | ||
327 | ** only p2p devices with specified MAC. | ||
325 | */ | 328 | */ |
326 | struct vif_params { | 329 | struct vif_params { |
327 | int use_4addr; | 330 | int use_4addr; |
@@ -799,6 +802,22 @@ struct station_parameters { | |||
799 | }; | 802 | }; |
800 | 803 | ||
801 | /** | 804 | /** |
805 | * struct station_del_parameters - station deletion parameters | ||
806 | * | ||
807 | * Used to delete a station entry (or all stations). | ||
808 | * | ||
809 | * @mac: MAC address of the station to remove or NULL to remove all stations | ||
810 | * @subtype: Management frame subtype to use for indicating removal | ||
811 | * (10 = Disassociation, 12 = Deauthentication) | ||
812 | * @reason_code: Reason code for the Disassociation/Deauthentication frame | ||
813 | */ | ||
814 | struct station_del_parameters { | ||
815 | const u8 *mac; | ||
816 | u8 subtype; | ||
817 | u16 reason_code; | ||
818 | }; | ||
819 | |||
820 | /** | ||
802 | * enum cfg80211_station_type - the type of station being modified | 821 | * enum cfg80211_station_type - the type of station being modified |
803 | * @CFG80211_STA_AP_CLIENT: client of an AP interface | 822 | * @CFG80211_STA_AP_CLIENT: client of an AP interface |
804 | * @CFG80211_STA_AP_MLME_CLIENT: client of an AP interface that has | 823 | * @CFG80211_STA_AP_MLME_CLIENT: client of an AP interface that has |
@@ -1340,6 +1359,16 @@ struct mesh_setup { | |||
1340 | }; | 1359 | }; |
1341 | 1360 | ||
1342 | /** | 1361 | /** |
1362 | * struct ocb_setup - 802.11p OCB mode setup configuration | ||
1363 | * @chandef: defines the channel to use | ||
1364 | * | ||
1365 | * These parameters are fixed when connecting to the network | ||
1366 | */ | ||
1367 | struct ocb_setup { | ||
1368 | struct cfg80211_chan_def chandef; | ||
1369 | }; | ||
1370 | |||
1371 | /** | ||
1343 | * struct ieee80211_txq_params - TX queue parameters | 1372 | * struct ieee80211_txq_params - TX queue parameters |
1344 | * @ac: AC identifier | 1373 | * @ac: AC identifier |
1345 | * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled | 1374 | * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled |
@@ -1408,6 +1437,10 @@ struct cfg80211_ssid { | |||
1408 | * @aborted: (internal) scan request was notified as aborted | 1437 | * @aborted: (internal) scan request was notified as aborted |
1409 | * @notified: (internal) scan request was notified as done or aborted | 1438 | * @notified: (internal) scan request was notified as done or aborted |
1410 | * @no_cck: used to send probe requests at non CCK rate in 2GHz band | 1439 | * @no_cck: used to send probe requests at non CCK rate in 2GHz band |
1440 | * @mac_addr: MAC address used with randomisation | ||
1441 | * @mac_addr_mask: MAC address mask used with randomisation, bits that | ||
1442 | * are 0 in the mask should be randomised, bits that are 1 should | ||
1443 | * be taken from the @mac_addr | ||
1411 | */ | 1444 | */ |
1412 | struct cfg80211_scan_request { | 1445 | struct cfg80211_scan_request { |
1413 | struct cfg80211_ssid *ssids; | 1446 | struct cfg80211_ssid *ssids; |
@@ -1422,6 +1455,9 @@ struct cfg80211_scan_request { | |||
1422 | 1455 | ||
1423 | struct wireless_dev *wdev; | 1456 | struct wireless_dev *wdev; |
1424 | 1457 | ||
1458 | u8 mac_addr[ETH_ALEN] __aligned(2); | ||
1459 | u8 mac_addr_mask[ETH_ALEN] __aligned(2); | ||
1460 | |||
1425 | /* internal */ | 1461 | /* internal */ |
1426 | struct wiphy *wiphy; | 1462 | struct wiphy *wiphy; |
1427 | unsigned long scan_start; | 1463 | unsigned long scan_start; |
@@ -1432,6 +1468,17 @@ struct cfg80211_scan_request { | |||
1432 | struct ieee80211_channel *channels[0]; | 1468 | struct ieee80211_channel *channels[0]; |
1433 | }; | 1469 | }; |
1434 | 1470 | ||
1471 | static inline void get_random_mask_addr(u8 *buf, const u8 *addr, const u8 *mask) | ||
1472 | { | ||
1473 | int i; | ||
1474 | |||
1475 | get_random_bytes(buf, ETH_ALEN); | ||
1476 | for (i = 0; i < ETH_ALEN; i++) { | ||
1477 | buf[i] &= ~mask[i]; | ||
1478 | buf[i] |= addr[i] & mask[i]; | ||
1479 | } | ||
1480 | } | ||
1481 | |||
1435 | /** | 1482 | /** |
1436 | * struct cfg80211_match_set - sets of attributes to match | 1483 | * struct cfg80211_match_set - sets of attributes to match |
1437 | * | 1484 | * |
@@ -1465,6 +1512,10 @@ struct cfg80211_match_set { | |||
1465 | * @channels: channels to scan | 1512 | * @channels: channels to scan |
1466 | * @min_rssi_thold: for drivers only supporting a single threshold, this | 1513 | * @min_rssi_thold: for drivers only supporting a single threshold, this |
1467 | * contains the minimum over all matchsets | 1514 | * contains the minimum over all matchsets |
1515 | * @mac_addr: MAC address used with randomisation | ||
1516 | * @mac_addr_mask: MAC address mask used with randomisation, bits that | ||
1517 | * are 0 in the mask should be randomised, bits that are 1 should | ||
1518 | * be taken from the @mac_addr | ||
1468 | */ | 1519 | */ |
1469 | struct cfg80211_sched_scan_request { | 1520 | struct cfg80211_sched_scan_request { |
1470 | struct cfg80211_ssid *ssids; | 1521 | struct cfg80211_ssid *ssids; |
@@ -1479,6 +1530,9 @@ struct cfg80211_sched_scan_request { | |||
1479 | int n_match_sets; | 1530 | int n_match_sets; |
1480 | s32 min_rssi_thold; | 1531 | s32 min_rssi_thold; |
1481 | 1532 | ||
1533 | u8 mac_addr[ETH_ALEN] __aligned(2); | ||
1534 | u8 mac_addr_mask[ETH_ALEN] __aligned(2); | ||
1535 | |||
1482 | /* internal */ | 1536 | /* internal */ |
1483 | struct wiphy *wiphy; | 1537 | struct wiphy *wiphy; |
1484 | struct net_device *dev; | 1538 | struct net_device *dev; |
@@ -1911,6 +1965,7 @@ struct cfg80211_wowlan_tcp { | |||
1911 | * @rfkill_release: wake up when rfkill is released | 1965 | * @rfkill_release: wake up when rfkill is released |
1912 | * @tcp: TCP connection establishment/wakeup parameters, see nl80211.h. | 1966 | * @tcp: TCP connection establishment/wakeup parameters, see nl80211.h. |
1913 | * NULL if not configured. | 1967 | * NULL if not configured. |
1968 | * @nd_config: configuration for the scan to be used for net detect wake. | ||
1914 | */ | 1969 | */ |
1915 | struct cfg80211_wowlan { | 1970 | struct cfg80211_wowlan { |
1916 | bool any, disconnect, magic_pkt, gtk_rekey_failure, | 1971 | bool any, disconnect, magic_pkt, gtk_rekey_failure, |
@@ -1919,6 +1974,7 @@ struct cfg80211_wowlan { | |||
1919 | struct cfg80211_pkt_pattern *patterns; | 1974 | struct cfg80211_pkt_pattern *patterns; |
1920 | struct cfg80211_wowlan_tcp *tcp; | 1975 | struct cfg80211_wowlan_tcp *tcp; |
1921 | int n_patterns; | 1976 | int n_patterns; |
1977 | struct cfg80211_sched_scan_request *nd_config; | ||
1922 | }; | 1978 | }; |
1923 | 1979 | ||
1924 | /** | 1980 | /** |
@@ -1951,6 +2007,35 @@ struct cfg80211_coalesce { | |||
1951 | }; | 2007 | }; |
1952 | 2008 | ||
1953 | /** | 2009 | /** |
2010 | * struct cfg80211_wowlan_nd_match - information about the match | ||
2011 | * | ||
2012 | * @ssid: SSID of the match that triggered the wake up | ||
2013 | * @n_channels: Number of channels where the match occurred. This | ||
2014 | * value may be zero if the driver can't report the channels. | ||
2015 | * @channels: center frequencies of the channels where a match | ||
2016 | * occurred (in MHz) | ||
2017 | */ | ||
2018 | struct cfg80211_wowlan_nd_match { | ||
2019 | struct cfg80211_ssid ssid; | ||
2020 | int n_channels; | ||
2021 | u32 channels[]; | ||
2022 | }; | ||
2023 | |||
2024 | /** | ||
2025 | * struct cfg80211_wowlan_nd_info - net detect wake up information | ||
2026 | * | ||
2027 | * @n_matches: Number of match information instances provided in | ||
2028 | * @matches. This value may be zero if the driver can't provide | ||
2029 | * match information. | ||
2030 | * @matches: Array of pointers to matches containing information about | ||
2031 | * the matches that triggered the wake up. | ||
2032 | */ | ||
2033 | struct cfg80211_wowlan_nd_info { | ||
2034 | int n_matches; | ||
2035 | struct cfg80211_wowlan_nd_match *matches[]; | ||
2036 | }; | ||
2037 | |||
2038 | /** | ||
1954 | * struct cfg80211_wowlan_wakeup - wakeup report | 2039 | * struct cfg80211_wowlan_wakeup - wakeup report |
1955 | * @disconnect: woke up by getting disconnected | 2040 | * @disconnect: woke up by getting disconnected |
1956 | * @magic_pkt: woke up by receiving magic packet | 2041 | * @magic_pkt: woke up by receiving magic packet |
@@ -1969,6 +2054,7 @@ struct cfg80211_coalesce { | |||
1969 | * @tcp_match: TCP wakeup packet received | 2054 | * @tcp_match: TCP wakeup packet received |
1970 | * @tcp_connlost: TCP connection lost or failed to establish | 2055 | * @tcp_connlost: TCP connection lost or failed to establish |
1971 | * @tcp_nomoretokens: TCP data ran out of tokens | 2056 | * @tcp_nomoretokens: TCP data ran out of tokens |
2057 | * @net_detect: if not %NULL, woke up because of net detect | ||
1972 | */ | 2058 | */ |
1973 | struct cfg80211_wowlan_wakeup { | 2059 | struct cfg80211_wowlan_wakeup { |
1974 | bool disconnect, magic_pkt, gtk_rekey_failure, | 2060 | bool disconnect, magic_pkt, gtk_rekey_failure, |
@@ -1978,6 +2064,7 @@ struct cfg80211_wowlan_wakeup { | |||
1978 | s32 pattern_idx; | 2064 | s32 pattern_idx; |
1979 | u32 packet_present_len, packet_len; | 2065 | u32 packet_present_len, packet_len; |
1980 | const void *packet; | 2066 | const void *packet; |
2067 | struct cfg80211_wowlan_nd_info *net_detect; | ||
1981 | }; | 2068 | }; |
1982 | 2069 | ||
1983 | /** | 2070 | /** |
@@ -2132,7 +2219,7 @@ struct cfg80211_qos_map { | |||
2132 | * @stop_ap: Stop being an AP, including stopping beaconing. | 2219 | * @stop_ap: Stop being an AP, including stopping beaconing. |
2133 | * | 2220 | * |
2134 | * @add_station: Add a new station. | 2221 | * @add_station: Add a new station. |
2135 | * @del_station: Remove a station; @mac may be NULL to remove all stations. | 2222 | * @del_station: Remove a station |
2136 | * @change_station: Modify a given station. Note that flags changes are not much | 2223 | * @change_station: Modify a given station. Note that flags changes are not much |
2137 | * validated in cfg80211, in particular the auth/assoc/authorized flags | 2224 | * validated in cfg80211, in particular the auth/assoc/authorized flags |
2138 | * might come to the driver in invalid combinations -- make sure to check | 2225 | * might come to the driver in invalid combinations -- make sure to check |
@@ -2146,6 +2233,8 @@ struct cfg80211_qos_map { | |||
2146 | * @change_mpath: change a given mesh path | 2233 | * @change_mpath: change a given mesh path |
2147 | * @get_mpath: get a mesh path for the given parameters | 2234 | * @get_mpath: get a mesh path for the given parameters |
2148 | * @dump_mpath: dump mesh path callback -- resume dump at index @idx | 2235 | * @dump_mpath: dump mesh path callback -- resume dump at index @idx |
2236 | * @get_mpp: get a mesh proxy path for the given parameters | ||
2237 | * @dump_mpp: dump mesh proxy path callback -- resume dump at index @idx | ||
2149 | * @join_mesh: join the mesh network with the specified parameters | 2238 | * @join_mesh: join the mesh network with the specified parameters |
2150 | * (invoked with the wireless_dev mutex held) | 2239 | * (invoked with the wireless_dev mutex held) |
2151 | * @leave_mesh: leave the current mesh network | 2240 | * @leave_mesh: leave the current mesh network |
@@ -2331,6 +2420,17 @@ struct cfg80211_qos_map { | |||
2331 | * with the peer followed by immediate teardown when the addition is later | 2420 | * with the peer followed by immediate teardown when the addition is later |
2332 | * rejected) | 2421 | * rejected) |
2333 | * @del_tx_ts: remove an existing TX TS | 2422 | * @del_tx_ts: remove an existing TX TS |
2423 | * | ||
2424 | * @join_ocb: join the OCB network with the specified parameters | ||
2425 | * (invoked with the wireless_dev mutex held) | ||
2426 | * @leave_ocb: leave the current OCB network | ||
2427 | * (invoked with the wireless_dev mutex held) | ||
2428 | * | ||
2429 | * @tdls_channel_switch: Start channel-switching with a TDLS peer. The driver | ||
2430 | * is responsible for continually initiating channel-switching operations | ||
2431 | * and returning to the base channel for communication with the AP. | ||
2432 | * @tdls_cancel_channel_switch: Stop channel-switching with a TDLS peer. Both | ||
2433 | * peers must be on the base channel when the call completes. | ||
2334 | */ | 2434 | */ |
2335 | struct cfg80211_ops { | 2435 | struct cfg80211_ops { |
2336 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 2436 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
@@ -2376,7 +2476,7 @@ struct cfg80211_ops { | |||
2376 | const u8 *mac, | 2476 | const u8 *mac, |
2377 | struct station_parameters *params); | 2477 | struct station_parameters *params); |
2378 | int (*del_station)(struct wiphy *wiphy, struct net_device *dev, | 2478 | int (*del_station)(struct wiphy *wiphy, struct net_device *dev, |
2379 | const u8 *mac); | 2479 | struct station_del_parameters *params); |
2380 | int (*change_station)(struct wiphy *wiphy, struct net_device *dev, | 2480 | int (*change_station)(struct wiphy *wiphy, struct net_device *dev, |
2381 | const u8 *mac, | 2481 | const u8 *mac, |
2382 | struct station_parameters *params); | 2482 | struct station_parameters *params); |
@@ -2396,6 +2496,11 @@ struct cfg80211_ops { | |||
2396 | int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, | 2496 | int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, |
2397 | int idx, u8 *dst, u8 *next_hop, | 2497 | int idx, u8 *dst, u8 *next_hop, |
2398 | struct mpath_info *pinfo); | 2498 | struct mpath_info *pinfo); |
2499 | int (*get_mpp)(struct wiphy *wiphy, struct net_device *dev, | ||
2500 | u8 *dst, u8 *mpp, struct mpath_info *pinfo); | ||
2501 | int (*dump_mpp)(struct wiphy *wiphy, struct net_device *dev, | ||
2502 | int idx, u8 *dst, u8 *mpp, | ||
2503 | struct mpath_info *pinfo); | ||
2399 | int (*get_mesh_config)(struct wiphy *wiphy, | 2504 | int (*get_mesh_config)(struct wiphy *wiphy, |
2400 | struct net_device *dev, | 2505 | struct net_device *dev, |
2401 | struct mesh_config *conf); | 2506 | struct mesh_config *conf); |
@@ -2407,6 +2512,10 @@ struct cfg80211_ops { | |||
2407 | const struct mesh_setup *setup); | 2512 | const struct mesh_setup *setup); |
2408 | int (*leave_mesh)(struct wiphy *wiphy, struct net_device *dev); | 2513 | int (*leave_mesh)(struct wiphy *wiphy, struct net_device *dev); |
2409 | 2514 | ||
2515 | int (*join_ocb)(struct wiphy *wiphy, struct net_device *dev, | ||
2516 | struct ocb_setup *setup); | ||
2517 | int (*leave_ocb)(struct wiphy *wiphy, struct net_device *dev); | ||
2518 | |||
2410 | int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, | 2519 | int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, |
2411 | struct bss_parameters *params); | 2520 | struct bss_parameters *params); |
2412 | 2521 | ||
@@ -2577,6 +2686,14 @@ struct cfg80211_ops { | |||
2577 | u16 admitted_time); | 2686 | u16 admitted_time); |
2578 | int (*del_tx_ts)(struct wiphy *wiphy, struct net_device *dev, | 2687 | int (*del_tx_ts)(struct wiphy *wiphy, struct net_device *dev, |
2579 | u8 tsid, const u8 *peer); | 2688 | u8 tsid, const u8 *peer); |
2689 | |||
2690 | int (*tdls_channel_switch)(struct wiphy *wiphy, | ||
2691 | struct net_device *dev, | ||
2692 | const u8 *addr, u8 oper_class, | ||
2693 | struct cfg80211_chan_def *chandef); | ||
2694 | void (*tdls_cancel_channel_switch)(struct wiphy *wiphy, | ||
2695 | struct net_device *dev, | ||
2696 | const u8 *addr); | ||
2580 | }; | 2697 | }; |
2581 | 2698 | ||
2582 | /* | 2699 | /* |
@@ -2623,13 +2740,9 @@ struct cfg80211_ops { | |||
2623 | * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels. | 2740 | * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels. |
2624 | * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in | 2741 | * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in |
2625 | * beaconing mode (AP, IBSS, Mesh, ...). | 2742 | * beaconing mode (AP, IBSS, Mesh, ...). |
2626 | * @WIPHY_FLAG_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM | ||
2627 | * TSPEC sessions (TID aka TSID 0-7) with the NL80211_CMD_ADD_TX_TS | ||
2628 | * command. Standard IEEE 802.11 TSPEC setup is not yet supported, it | ||
2629 | * needs to be able to handle Block-Ack agreements and other things. | ||
2630 | */ | 2743 | */ |
2631 | enum wiphy_flags { | 2744 | enum wiphy_flags { |
2632 | WIPHY_FLAG_SUPPORTS_WMM_ADMISSION = BIT(0), | 2745 | /* use hole at 0 */ |
2633 | /* use hole at 1 */ | 2746 | /* use hole at 1 */ |
2634 | /* use hole at 2 */ | 2747 | /* use hole at 2 */ |
2635 | WIPHY_FLAG_NETNS_OK = BIT(3), | 2748 | WIPHY_FLAG_NETNS_OK = BIT(3), |
@@ -2755,6 +2868,7 @@ struct ieee80211_txrx_stypes { | |||
2755 | * @WIPHY_WOWLAN_EAP_IDENTITY_REQ: supports wakeup on EAP identity request | 2868 | * @WIPHY_WOWLAN_EAP_IDENTITY_REQ: supports wakeup on EAP identity request |
2756 | * @WIPHY_WOWLAN_4WAY_HANDSHAKE: supports wakeup on 4-way handshake failure | 2869 | * @WIPHY_WOWLAN_4WAY_HANDSHAKE: supports wakeup on 4-way handshake failure |
2757 | * @WIPHY_WOWLAN_RFKILL_RELEASE: supports wakeup on RF-kill release | 2870 | * @WIPHY_WOWLAN_RFKILL_RELEASE: supports wakeup on RF-kill release |
2871 | * @WIPHY_WOWLAN_NET_DETECT: supports wakeup on network detection | ||
2758 | */ | 2872 | */ |
2759 | enum wiphy_wowlan_support_flags { | 2873 | enum wiphy_wowlan_support_flags { |
2760 | WIPHY_WOWLAN_ANY = BIT(0), | 2874 | WIPHY_WOWLAN_ANY = BIT(0), |
@@ -2765,6 +2879,7 @@ enum wiphy_wowlan_support_flags { | |||
2765 | WIPHY_WOWLAN_EAP_IDENTITY_REQ = BIT(5), | 2879 | WIPHY_WOWLAN_EAP_IDENTITY_REQ = BIT(5), |
2766 | WIPHY_WOWLAN_4WAY_HANDSHAKE = BIT(6), | 2880 | WIPHY_WOWLAN_4WAY_HANDSHAKE = BIT(6), |
2767 | WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), | 2881 | WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), |
2882 | WIPHY_WOWLAN_NET_DETECT = BIT(8), | ||
2768 | }; | 2883 | }; |
2769 | 2884 | ||
2770 | struct wiphy_wowlan_tcp_support { | 2885 | struct wiphy_wowlan_tcp_support { |
@@ -2783,6 +2898,11 @@ struct wiphy_wowlan_tcp_support { | |||
2783 | * @pattern_max_len: maximum length of each pattern | 2898 | * @pattern_max_len: maximum length of each pattern |
2784 | * @pattern_min_len: minimum length of each pattern | 2899 | * @pattern_min_len: minimum length of each pattern |
2785 | * @max_pkt_offset: maximum Rx packet offset | 2900 | * @max_pkt_offset: maximum Rx packet offset |
2901 | * @max_nd_match_sets: maximum number of matchsets for net-detect, | ||
2902 | * similar, but not necessarily identical, to max_match_sets for | ||
2903 | * scheduled scans. | ||
2904 | * See &struct cfg80211_sched_scan_request.@match_sets for more | ||
2905 | * details. | ||
2786 | * @tcp: TCP wakeup support information | 2906 | * @tcp: TCP wakeup support information |
2787 | */ | 2907 | */ |
2788 | struct wiphy_wowlan_support { | 2908 | struct wiphy_wowlan_support { |
@@ -2791,6 +2911,7 @@ struct wiphy_wowlan_support { | |||
2791 | int pattern_max_len; | 2911 | int pattern_max_len; |
2792 | int pattern_min_len; | 2912 | int pattern_min_len; |
2793 | int max_pkt_offset; | 2913 | int max_pkt_offset; |
2914 | int max_nd_match_sets; | ||
2794 | const struct wiphy_wowlan_tcp_support *tcp; | 2915 | const struct wiphy_wowlan_tcp_support *tcp; |
2795 | }; | 2916 | }; |
2796 | 2917 | ||
@@ -3166,6 +3287,23 @@ static inline const char *wiphy_name(const struct wiphy *wiphy) | |||
3166 | } | 3287 | } |
3167 | 3288 | ||
3168 | /** | 3289 | /** |
3290 | * wiphy_new_nm - create a new wiphy for use with cfg80211 | ||
3291 | * | ||
3292 | * @ops: The configuration operations for this device | ||
3293 | * @sizeof_priv: The size of the private area to allocate | ||
3294 | * @requested_name: Request a particular name. | ||
3295 | * NULL is valid value, and means use the default phy%d naming. | ||
3296 | * | ||
3297 | * Create a new wiphy and associate the given operations with it. | ||
3298 | * @sizeof_priv bytes are allocated for private use. | ||
3299 | * | ||
3300 | * Return: A pointer to the new wiphy. This pointer must be | ||
3301 | * assigned to each netdev's ieee80211_ptr for proper operation. | ||
3302 | */ | ||
3303 | struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, | ||
3304 | const char *requested_name); | ||
3305 | |||
3306 | /** | ||
3169 | * wiphy_new - create a new wiphy for use with cfg80211 | 3307 | * wiphy_new - create a new wiphy for use with cfg80211 |
3170 | * | 3308 | * |
3171 | * @ops: The configuration operations for this device | 3309 | * @ops: The configuration operations for this device |
@@ -3177,7 +3315,11 @@ static inline const char *wiphy_name(const struct wiphy *wiphy) | |||
3177 | * Return: A pointer to the new wiphy. This pointer must be | 3315 | * Return: A pointer to the new wiphy. This pointer must be |
3178 | * assigned to each netdev's ieee80211_ptr for proper operation. | 3316 | * assigned to each netdev's ieee80211_ptr for proper operation. |
3179 | */ | 3317 | */ |
3180 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv); | 3318 | static inline struct wiphy *wiphy_new(const struct cfg80211_ops *ops, |
3319 | int sizeof_priv) | ||
3320 | { | ||
3321 | return wiphy_new_nm(ops, sizeof_priv, NULL); | ||
3322 | } | ||
3181 | 3323 | ||
3182 | /** | 3324 | /** |
3183 | * wiphy_register - register a wiphy with cfg80211 | 3325 | * wiphy_register - register a wiphy with cfg80211 |
@@ -4501,33 +4643,6 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, | |||
4501 | gfp_t gfp); | 4643 | gfp_t gfp); |
4502 | 4644 | ||
4503 | /** | 4645 | /** |
4504 | * cfg80211_radar_event - radar detection event | ||
4505 | * @wiphy: the wiphy | ||
4506 | * @chandef: chandef for the current channel | ||
4507 | * @gfp: context flags | ||
4508 | * | ||
4509 | * This function is called when a radar is detected on the current chanenl. | ||
4510 | */ | ||
4511 | void cfg80211_radar_event(struct wiphy *wiphy, | ||
4512 | struct cfg80211_chan_def *chandef, gfp_t gfp); | ||
4513 | |||
4514 | /** | ||
4515 | * cfg80211_cac_event - Channel availability check (CAC) event | ||
4516 | * @netdev: network device | ||
4517 | * @chandef: chandef for the current channel | ||
4518 | * @event: type of event | ||
4519 | * @gfp: context flags | ||
4520 | * | ||
4521 | * This function is called when a Channel availability check (CAC) is finished | ||
4522 | * or aborted. This must be called to notify the completion of a CAC process, | ||
4523 | * also by full-MAC drivers. | ||
4524 | */ | ||
4525 | void cfg80211_cac_event(struct net_device *netdev, | ||
4526 | const struct cfg80211_chan_def *chandef, | ||
4527 | enum nl80211_radar_event event, gfp_t gfp); | ||
4528 | |||
4529 | |||
4530 | /** | ||
4531 | * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer | 4646 | * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer |
4532 | * @dev: network device | 4647 | * @dev: network device |
4533 | * @peer: peer's MAC address | 4648 | * @peer: peer's MAC address |
@@ -4555,6 +4670,42 @@ void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer, | |||
4555 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); | 4670 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); |
4556 | 4671 | ||
4557 | /** | 4672 | /** |
4673 | * cfg80211_cqm_beacon_loss_notify - beacon loss event | ||
4674 | * @dev: network device | ||
4675 | * @gfp: context flags | ||
4676 | * | ||
4677 | * Notify userspace about beacon loss from the connected AP. | ||
4678 | */ | ||
4679 | void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp); | ||
4680 | |||
4681 | /** | ||
4682 | * cfg80211_radar_event - radar detection event | ||
4683 | * @wiphy: the wiphy | ||
4684 | * @chandef: chandef for the current channel | ||
4685 | * @gfp: context flags | ||
4686 | * | ||
4687 | * This function is called when a radar is detected on the current chanenl. | ||
4688 | */ | ||
4689 | void cfg80211_radar_event(struct wiphy *wiphy, | ||
4690 | struct cfg80211_chan_def *chandef, gfp_t gfp); | ||
4691 | |||
4692 | /** | ||
4693 | * cfg80211_cac_event - Channel availability check (CAC) event | ||
4694 | * @netdev: network device | ||
4695 | * @chandef: chandef for the current channel | ||
4696 | * @event: type of event | ||
4697 | * @gfp: context flags | ||
4698 | * | ||
4699 | * This function is called when a Channel availability check (CAC) is finished | ||
4700 | * or aborted. This must be called to notify the completion of a CAC process, | ||
4701 | * also by full-MAC drivers. | ||
4702 | */ | ||
4703 | void cfg80211_cac_event(struct net_device *netdev, | ||
4704 | const struct cfg80211_chan_def *chandef, | ||
4705 | enum nl80211_radar_event event, gfp_t gfp); | ||
4706 | |||
4707 | |||
4708 | /** | ||
4558 | * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying | 4709 | * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying |
4559 | * @dev: network device | 4710 | * @dev: network device |
4560 | * @bssid: BSSID of AP (to avoid races) | 4711 | * @bssid: BSSID of AP (to avoid races) |
@@ -4657,6 +4808,20 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | |||
4657 | void cfg80211_ch_switch_notify(struct net_device *dev, | 4808 | void cfg80211_ch_switch_notify(struct net_device *dev, |
4658 | struct cfg80211_chan_def *chandef); | 4809 | struct cfg80211_chan_def *chandef); |
4659 | 4810 | ||
4811 | /* | ||
4812 | * cfg80211_ch_switch_started_notify - notify channel switch start | ||
4813 | * @dev: the device on which the channel switch started | ||
4814 | * @chandef: the future channel definition | ||
4815 | * @count: the number of TBTTs until the channel switch happens | ||
4816 | * | ||
4817 | * Inform the userspace about the channel switch that has just | ||
4818 | * started, so that it can take appropriate actions (eg. starting | ||
4819 | * channel switch on other vifs), if necessary. | ||
4820 | */ | ||
4821 | void cfg80211_ch_switch_started_notify(struct net_device *dev, | ||
4822 | struct cfg80211_chan_def *chandef, | ||
4823 | u8 count); | ||
4824 | |||
4660 | /** | 4825 | /** |
4661 | * ieee80211_operating_class_to_band - convert operating class to band | 4826 | * ieee80211_operating_class_to_band - convert operating class to band |
4662 | * | 4827 | * |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0ad1f47d2dc7..58d719ddaa60 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -263,6 +263,7 @@ struct ieee80211_vif_chanctx_switch { | |||
263 | * @BSS_CHANGED_BANDWIDTH: The bandwidth used by this interface changed, | 263 | * @BSS_CHANGED_BANDWIDTH: The bandwidth used by this interface changed, |
264 | * note that this is only called when it changes after the channel | 264 | * note that this is only called when it changes after the channel |
265 | * context had been assigned. | 265 | * context had been assigned. |
266 | * @BSS_CHANGED_OCB: OCB join status changed | ||
266 | */ | 267 | */ |
267 | enum ieee80211_bss_change { | 268 | enum ieee80211_bss_change { |
268 | BSS_CHANGED_ASSOC = 1<<0, | 269 | BSS_CHANGED_ASSOC = 1<<0, |
@@ -287,6 +288,7 @@ enum ieee80211_bss_change { | |||
287 | BSS_CHANGED_P2P_PS = 1<<19, | 288 | BSS_CHANGED_P2P_PS = 1<<19, |
288 | BSS_CHANGED_BEACON_INFO = 1<<20, | 289 | BSS_CHANGED_BEACON_INFO = 1<<20, |
289 | BSS_CHANGED_BANDWIDTH = 1<<21, | 290 | BSS_CHANGED_BANDWIDTH = 1<<21, |
291 | BSS_CHANGED_OCB = 1<<22, | ||
290 | 292 | ||
291 | /* when adding here, make sure to change ieee80211_reconfig */ | 293 | /* when adding here, make sure to change ieee80211_reconfig */ |
292 | }; | 294 | }; |
@@ -739,7 +741,8 @@ struct ieee80211_tx_info { | |||
739 | u8 ampdu_ack_len; | 741 | u8 ampdu_ack_len; |
740 | u8 ampdu_len; | 742 | u8 ampdu_len; |
741 | u8 antenna; | 743 | u8 antenna; |
742 | void *status_driver_data[21 / sizeof(void *)]; | 744 | u16 tx_time; |
745 | void *status_driver_data[19 / sizeof(void *)]; | ||
743 | } status; | 746 | } status; |
744 | struct { | 747 | struct { |
745 | struct ieee80211_tx_rate driver_rates[ | 748 | struct ieee80211_tx_rate driver_rates[ |
@@ -879,6 +882,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) | |||
879 | * subframes share the same sequence number. Reported subframes can be | 882 | * subframes share the same sequence number. Reported subframes can be |
880 | * either regular MSDU or singly A-MSDUs. Subframes must not be | 883 | * either regular MSDU or singly A-MSDUs. Subframes must not be |
881 | * interleaved with other frames. | 884 | * interleaved with other frames. |
885 | * @RX_FLAG_RADIOTAP_VENDOR_DATA: This frame contains vendor-specific | ||
886 | * radiotap data in the skb->data (before the frame) as described by | ||
887 | * the &struct ieee80211_vendor_radiotap. | ||
882 | */ | 888 | */ |
883 | enum mac80211_rx_flags { | 889 | enum mac80211_rx_flags { |
884 | RX_FLAG_MMIC_ERROR = BIT(0), | 890 | RX_FLAG_MMIC_ERROR = BIT(0), |
@@ -908,6 +914,7 @@ enum mac80211_rx_flags { | |||
908 | RX_FLAG_10MHZ = BIT(28), | 914 | RX_FLAG_10MHZ = BIT(28), |
909 | RX_FLAG_5MHZ = BIT(29), | 915 | RX_FLAG_5MHZ = BIT(29), |
910 | RX_FLAG_AMSDU_MORE = BIT(30), | 916 | RX_FLAG_AMSDU_MORE = BIT(30), |
917 | RX_FLAG_RADIOTAP_VENDOR_DATA = BIT(31), | ||
911 | }; | 918 | }; |
912 | 919 | ||
913 | #define RX_FLAG_STBC_SHIFT 26 | 920 | #define RX_FLAG_STBC_SHIFT 26 |
@@ -979,6 +986,39 @@ struct ieee80211_rx_status { | |||
979 | }; | 986 | }; |
980 | 987 | ||
981 | /** | 988 | /** |
989 | * struct ieee80211_vendor_radiotap - vendor radiotap data information | ||
990 | * @present: presence bitmap for this vendor namespace | ||
991 | * (this could be extended in the future if any vendor needs more | ||
992 | * bits, the radiotap spec does allow for that) | ||
993 | * @align: radiotap vendor namespace alignment. This defines the needed | ||
994 | * alignment for the @data field below, not for the vendor namespace | ||
995 | * description itself (which has a fixed 2-byte alignment) | ||
996 | * Must be a power of two, and be set to at least 1! | ||
997 | * @oui: radiotap vendor namespace OUI | ||
998 | * @subns: radiotap vendor sub namespace | ||
999 | * @len: radiotap vendor sub namespace skip length, if alignment is done | ||
1000 | * then that's added to this, i.e. this is only the length of the | ||
1001 | * @data field. | ||
1002 | * @pad: number of bytes of padding after the @data, this exists so that | ||
1003 | * the skb data alignment can be preserved even if the data has odd | ||
1004 | * length | ||
1005 | * @data: the actual vendor namespace data | ||
1006 | * | ||
1007 | * This struct, including the vendor data, goes into the skb->data before | ||
1008 | * the 802.11 header. It's split up in mac80211 using the align/oui/subns | ||
1009 | * data. | ||
1010 | */ | ||
1011 | struct ieee80211_vendor_radiotap { | ||
1012 | u32 present; | ||
1013 | u8 align; | ||
1014 | u8 oui[3]; | ||
1015 | u8 subns; | ||
1016 | u8 pad; | ||
1017 | u16 len; | ||
1018 | u8 data[]; | ||
1019 | } __packed; | ||
1020 | |||
1021 | /** | ||
982 | * enum ieee80211_conf_flags - configuration flags | 1022 | * enum ieee80211_conf_flags - configuration flags |
983 | * | 1023 | * |
984 | * Flags to define PHY configuration options | 1024 | * Flags to define PHY configuration options |
@@ -1117,6 +1157,8 @@ struct ieee80211_conf { | |||
1117 | * Function (TSF) timer when the frame containing the channel switch | 1157 | * Function (TSF) timer when the frame containing the channel switch |
1118 | * announcement was received. This is simply the rx.mactime parameter | 1158 | * announcement was received. This is simply the rx.mactime parameter |
1119 | * the driver passed into mac80211. | 1159 | * the driver passed into mac80211. |
1160 | * @device_timestamp: arbitrary timestamp for the device, this is the | ||
1161 | * rx.device_timestamp parameter the driver passed to mac80211. | ||
1120 | * @block_tx: Indicates whether transmission must be blocked before the | 1162 | * @block_tx: Indicates whether transmission must be blocked before the |
1121 | * scheduled channel switch, as indicated by the AP. | 1163 | * scheduled channel switch, as indicated by the AP. |
1122 | * @chandef: the new channel to switch to | 1164 | * @chandef: the new channel to switch to |
@@ -1124,6 +1166,7 @@ struct ieee80211_conf { | |||
1124 | */ | 1166 | */ |
1125 | struct ieee80211_channel_switch { | 1167 | struct ieee80211_channel_switch { |
1126 | u64 timestamp; | 1168 | u64 timestamp; |
1169 | u32 device_timestamp; | ||
1127 | bool block_tx; | 1170 | bool block_tx; |
1128 | struct cfg80211_chan_def chandef; | 1171 | struct cfg80211_chan_def chandef; |
1129 | u8 count; | 1172 | u8 count; |
@@ -1423,6 +1466,8 @@ struct ieee80211_sta_rates { | |||
1423 | * @smps_mode: current SMPS mode (off, static or dynamic) | 1466 | * @smps_mode: current SMPS mode (off, static or dynamic) |
1424 | * @rates: rate control selection table | 1467 | * @rates: rate control selection table |
1425 | * @tdls: indicates whether the STA is a TDLS peer | 1468 | * @tdls: indicates whether the STA is a TDLS peer |
1469 | * @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only | ||
1470 | * valid if the STA is a TDLS peer in the first place. | ||
1426 | */ | 1471 | */ |
1427 | struct ieee80211_sta { | 1472 | struct ieee80211_sta { |
1428 | u32 supp_rates[IEEE80211_NUM_BANDS]; | 1473 | u32 supp_rates[IEEE80211_NUM_BANDS]; |
@@ -1438,6 +1483,7 @@ struct ieee80211_sta { | |||
1438 | enum ieee80211_smps_mode smps_mode; | 1483 | enum ieee80211_smps_mode smps_mode; |
1439 | struct ieee80211_sta_rates __rcu *rates; | 1484 | struct ieee80211_sta_rates __rcu *rates; |
1440 | bool tdls; | 1485 | bool tdls; |
1486 | bool tdls_initiator; | ||
1441 | 1487 | ||
1442 | /* must be last */ | 1488 | /* must be last */ |
1443 | u8 drv_priv[0] __aligned(sizeof(void *)); | 1489 | u8 drv_priv[0] __aligned(sizeof(void *)); |
@@ -1576,6 +1622,10 @@ struct ieee80211_tx_control { | |||
1576 | * a virtual monitor interface when monitor interfaces are the only | 1622 | * a virtual monitor interface when monitor interfaces are the only |
1577 | * active interfaces. | 1623 | * active interfaces. |
1578 | * | 1624 | * |
1625 | * @IEEE80211_HW_NO_AUTO_VIF: The driver would like for no wlanX to | ||
1626 | * be created. It is expected user-space will create vifs as | ||
1627 | * desired (and thus have them named as desired). | ||
1628 | * | ||
1579 | * @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface | 1629 | * @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface |
1580 | * queue mapping in order to use different queues (not just one per AC) | 1630 | * queue mapping in order to use different queues (not just one per AC) |
1581 | * for different virtual interfaces. See the doc section on HW queue | 1631 | * for different virtual interfaces. See the doc section on HW queue |
@@ -1622,7 +1672,8 @@ enum ieee80211_hw_flags { | |||
1622 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, | 1672 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, |
1623 | IEEE80211_HW_MFP_CAPABLE = 1<<13, | 1673 | IEEE80211_HW_MFP_CAPABLE = 1<<13, |
1624 | IEEE80211_HW_WANT_MONITOR_VIF = 1<<14, | 1674 | IEEE80211_HW_WANT_MONITOR_VIF = 1<<14, |
1625 | /* free slots */ | 1675 | IEEE80211_HW_NO_AUTO_VIF = 1<<15, |
1676 | /* free slot */ | ||
1626 | IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, | 1677 | IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, |
1627 | IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, | 1678 | IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, |
1628 | IEEE80211_HW_CONNECTION_MONITOR = 1<<19, | 1679 | IEEE80211_HW_CONNECTION_MONITOR = 1<<19, |
@@ -1776,6 +1827,31 @@ struct ieee80211_scan_request { | |||
1776 | }; | 1827 | }; |
1777 | 1828 | ||
1778 | /** | 1829 | /** |
1830 | * struct ieee80211_tdls_ch_sw_params - TDLS channel switch parameters | ||
1831 | * | ||
1832 | * @sta: peer this TDLS channel-switch request/response came from | ||
1833 | * @chandef: channel referenced in a TDLS channel-switch request | ||
1834 | * @action_code: see &enum ieee80211_tdls_actioncode | ||
1835 | * @status: channel-switch response status | ||
1836 | * @timestamp: time at which the frame was received | ||
1837 | * @switch_time: switch-timing parameter received in the frame | ||
1838 | * @switch_timeout: switch-timing parameter received in the frame | ||
1839 | * @tmpl_skb: TDLS switch-channel response template | ||
1840 | * @ch_sw_tm_ie: offset of the channel-switch timing IE inside @tmpl_skb | ||
1841 | */ | ||
1842 | struct ieee80211_tdls_ch_sw_params { | ||
1843 | struct ieee80211_sta *sta; | ||
1844 | struct cfg80211_chan_def *chandef; | ||
1845 | u8 action_code; | ||
1846 | u32 status; | ||
1847 | u32 timestamp; | ||
1848 | u16 switch_time; | ||
1849 | u16 switch_timeout; | ||
1850 | struct sk_buff *tmpl_skb; | ||
1851 | u32 ch_sw_tm_ie; | ||
1852 | }; | ||
1853 | |||
1854 | /** | ||
1779 | * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy | 1855 | * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy |
1780 | * | 1856 | * |
1781 | * @wiphy: the &struct wiphy which we want to query | 1857 | * @wiphy: the &struct wiphy which we want to query |
@@ -2375,6 +2451,22 @@ enum ieee80211_roc_type { | |||
2375 | }; | 2451 | }; |
2376 | 2452 | ||
2377 | /** | 2453 | /** |
2454 | * enum ieee80211_reconfig_complete_type - reconfig type | ||
2455 | * | ||
2456 | * This enum is used by the reconfig_complete() callback to indicate what | ||
2457 | * reconfiguration type was completed. | ||
2458 | * | ||
2459 | * @IEEE80211_RECONFIG_TYPE_RESTART: hw restart type | ||
2460 | * (also due to resume() callback returning 1) | ||
2461 | * @IEEE80211_RECONFIG_TYPE_SUSPEND: suspend type (regardless | ||
2462 | * of wowlan configuration) | ||
2463 | */ | ||
2464 | enum ieee80211_reconfig_type { | ||
2465 | IEEE80211_RECONFIG_TYPE_RESTART, | ||
2466 | IEEE80211_RECONFIG_TYPE_SUSPEND, | ||
2467 | }; | ||
2468 | |||
2469 | /** | ||
2378 | * struct ieee80211_ops - callbacks from mac80211 to the driver | 2470 | * struct ieee80211_ops - callbacks from mac80211 to the driver |
2379 | * | 2471 | * |
2380 | * This structure contains various callbacks that the driver may | 2472 | * This structure contains various callbacks that the driver may |
@@ -2530,7 +2622,9 @@ enum ieee80211_roc_type { | |||
2530 | * | 2622 | * |
2531 | * @sw_scan_start: Notifier function that is called just before a software scan | 2623 | * @sw_scan_start: Notifier function that is called just before a software scan |
2532 | * is started. Can be NULL, if the driver doesn't need this notification. | 2624 | * is started. Can be NULL, if the driver doesn't need this notification. |
2533 | * The callback can sleep. | 2625 | * The mac_addr parameter allows supporting NL80211_SCAN_FLAG_RANDOM_ADDR, |
2626 | * the driver may set the NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR flag if it | ||
2627 | * can use this parameter. The callback can sleep. | ||
2534 | * | 2628 | * |
2535 | * @sw_scan_complete: Notifier function that is called just after a | 2629 | * @sw_scan_complete: Notifier function that is called just after a |
2536 | * software scan finished. Can be NULL, if the driver doesn't need | 2630 | * software scan finished. Can be NULL, if the driver doesn't need |
@@ -2601,6 +2695,9 @@ enum ieee80211_roc_type { | |||
2601 | * uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since | 2695 | * uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since |
2602 | * otherwise the rate control algorithm is notified directly. | 2696 | * otherwise the rate control algorithm is notified directly. |
2603 | * Must be atomic. | 2697 | * Must be atomic. |
2698 | * @sta_rate_tbl_update: Notifies the driver that the rate table changed. This | ||
2699 | * is only used if the configured rate control algorithm actually uses | ||
2700 | * the new rate table API, and is therefore optional. Must be atomic. | ||
2604 | * | 2701 | * |
2605 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), | 2702 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), |
2606 | * bursting) for a hardware TX queue. | 2703 | * bursting) for a hardware TX queue. |
@@ -2809,11 +2906,11 @@ enum ieee80211_roc_type { | |||
2809 | * disabled/enabled via @bss_info_changed. | 2906 | * disabled/enabled via @bss_info_changed. |
2810 | * @stop_ap: Stop operation on the AP interface. | 2907 | * @stop_ap: Stop operation on the AP interface. |
2811 | * | 2908 | * |
2812 | * @restart_complete: Called after a call to ieee80211_restart_hw(), when the | 2909 | * @reconfig_complete: Called after a call to ieee80211_restart_hw() and |
2813 | * reconfiguration has completed. This can help the driver implement the | 2910 | * during resume, when the reconfiguration has completed. |
2814 | * reconfiguration step. Also called when reconfiguring because the | 2911 | * This can help the driver implement the reconfiguration step (and |
2815 | * driver's resume function returned 1, as this is just like an "inline" | 2912 | * indicate mac80211 is ready to receive frames). |
2816 | * hardware restart. This callback may sleep. | 2913 | * This callback may sleep. |
2817 | * | 2914 | * |
2818 | * @ipv6_addr_change: IPv6 address assignment on the given interface changed. | 2915 | * @ipv6_addr_change: IPv6 address assignment on the given interface changed. |
2819 | * Currently, this is only called for managed or P2P client interfaces. | 2916 | * Currently, this is only called for managed or P2P client interfaces. |
@@ -2829,6 +2926,13 @@ enum ieee80211_roc_type { | |||
2829 | * transmitted and then call ieee80211_csa_finish(). | 2926 | * transmitted and then call ieee80211_csa_finish(). |
2830 | * If the CSA count starts as zero or 1, this function will not be called, | 2927 | * If the CSA count starts as zero or 1, this function will not be called, |
2831 | * since there won't be any time to beacon before the switch anyway. | 2928 | * since there won't be any time to beacon before the switch anyway. |
2929 | * @pre_channel_switch: This is an optional callback that is called | ||
2930 | * before a channel switch procedure is started (ie. when a STA | ||
2931 | * gets a CSA or an userspace initiated channel-switch), allowing | ||
2932 | * the driver to prepare for the channel switch. | ||
2933 | * @post_channel_switch: This is an optional callback that is called | ||
2934 | * after a channel switch procedure is completed, allowing the | ||
2935 | * driver to go back to a normal configuration. | ||
2832 | * | 2936 | * |
2833 | * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all | 2937 | * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all |
2834 | * information in bss_conf is set up and the beacon can be retrieved. A | 2938 | * information in bss_conf is set up and the beacon can be retrieved. A |
@@ -2838,6 +2942,26 @@ enum ieee80211_roc_type { | |||
2838 | * @get_expected_throughput: extract the expected throughput towards the | 2942 | * @get_expected_throughput: extract the expected throughput towards the |
2839 | * specified station. The returned value is expressed in Kbps. It returns 0 | 2943 | * specified station. The returned value is expressed in Kbps. It returns 0 |
2840 | * if the RC algorithm does not have proper data to provide. | 2944 | * if the RC algorithm does not have proper data to provide. |
2945 | * | ||
2946 | * @get_txpower: get current maximum tx power (in dBm) based on configuration | ||
2947 | * and hardware limits. | ||
2948 | * | ||
2949 | * @tdls_channel_switch: Start channel-switching with a TDLS peer. The driver | ||
2950 | * is responsible for continually initiating channel-switching operations | ||
2951 | * and returning to the base channel for communication with the AP. The | ||
2952 | * driver receives a channel-switch request template and the location of | ||
2953 | * the switch-timing IE within the template as part of the invocation. | ||
2954 | * The template is valid only within the call, and the driver can | ||
2955 | * optionally copy the skb for further re-use. | ||
2956 | * @tdls_cancel_channel_switch: Stop channel-switching with a TDLS peer. Both | ||
2957 | * peers must be on the base channel when the call completes. | ||
2958 | * @tdls_recv_channel_switch: a TDLS channel-switch related frame (request or | ||
2959 | * response) has been received from a remote peer. The driver gets | ||
2960 | * parameters parsed from the incoming frame and may use them to continue | ||
2961 | * an ongoing channel-switch operation. In addition, a channel-switch | ||
2962 | * response template is provided, together with the location of the | ||
2963 | * switch-timing IE within the template. The skb can only be used within | ||
2964 | * the function call. | ||
2841 | */ | 2965 | */ |
2842 | struct ieee80211_ops { | 2966 | struct ieee80211_ops { |
2843 | void (*tx)(struct ieee80211_hw *hw, | 2967 | void (*tx)(struct ieee80211_hw *hw, |
@@ -2897,8 +3021,11 @@ struct ieee80211_ops { | |||
2897 | struct ieee80211_scan_ies *ies); | 3021 | struct ieee80211_scan_ies *ies); |
2898 | int (*sched_scan_stop)(struct ieee80211_hw *hw, | 3022 | int (*sched_scan_stop)(struct ieee80211_hw *hw, |
2899 | struct ieee80211_vif *vif); | 3023 | struct ieee80211_vif *vif); |
2900 | void (*sw_scan_start)(struct ieee80211_hw *hw); | 3024 | void (*sw_scan_start)(struct ieee80211_hw *hw, |
2901 | void (*sw_scan_complete)(struct ieee80211_hw *hw); | 3025 | struct ieee80211_vif *vif, |
3026 | const u8 *mac_addr); | ||
3027 | void (*sw_scan_complete)(struct ieee80211_hw *hw, | ||
3028 | struct ieee80211_vif *vif); | ||
2902 | int (*get_stats)(struct ieee80211_hw *hw, | 3029 | int (*get_stats)(struct ieee80211_hw *hw, |
2903 | struct ieee80211_low_level_stats *stats); | 3030 | struct ieee80211_low_level_stats *stats); |
2904 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, | 3031 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, |
@@ -2932,6 +3059,9 @@ struct ieee80211_ops { | |||
2932 | struct ieee80211_vif *vif, | 3059 | struct ieee80211_vif *vif, |
2933 | struct ieee80211_sta *sta, | 3060 | struct ieee80211_sta *sta, |
2934 | u32 changed); | 3061 | u32 changed); |
3062 | void (*sta_rate_tbl_update)(struct ieee80211_hw *hw, | ||
3063 | struct ieee80211_vif *vif, | ||
3064 | struct ieee80211_sta *sta); | ||
2935 | int (*conf_tx)(struct ieee80211_hw *hw, | 3065 | int (*conf_tx)(struct ieee80211_hw *hw, |
2936 | struct ieee80211_vif *vif, u16 ac, | 3066 | struct ieee80211_vif *vif, u16 ac, |
2937 | const struct ieee80211_tx_queue_params *params); | 3067 | const struct ieee80211_tx_queue_params *params); |
@@ -2959,6 +3089,7 @@ struct ieee80211_ops { | |||
2959 | void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 3089 | void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2960 | u32 queues, bool drop); | 3090 | u32 queues, bool drop); |
2961 | void (*channel_switch)(struct ieee80211_hw *hw, | 3091 | void (*channel_switch)(struct ieee80211_hw *hw, |
3092 | struct ieee80211_vif *vif, | ||
2962 | struct ieee80211_channel_switch *ch_switch); | 3093 | struct ieee80211_channel_switch *ch_switch); |
2963 | int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); | 3094 | int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); |
2964 | int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); | 3095 | int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); |
@@ -3025,7 +3156,8 @@ struct ieee80211_ops { | |||
3025 | int n_vifs, | 3156 | int n_vifs, |
3026 | enum ieee80211_chanctx_switch_mode mode); | 3157 | enum ieee80211_chanctx_switch_mode mode); |
3027 | 3158 | ||
3028 | void (*restart_complete)(struct ieee80211_hw *hw); | 3159 | void (*reconfig_complete)(struct ieee80211_hw *hw, |
3160 | enum ieee80211_reconfig_type reconfig_type); | ||
3029 | 3161 | ||
3030 | #if IS_ENABLED(CONFIG_IPV6) | 3162 | #if IS_ENABLED(CONFIG_IPV6) |
3031 | void (*ipv6_addr_change)(struct ieee80211_hw *hw, | 3163 | void (*ipv6_addr_change)(struct ieee80211_hw *hw, |
@@ -3035,14 +3167,54 @@ struct ieee80211_ops { | |||
3035 | void (*channel_switch_beacon)(struct ieee80211_hw *hw, | 3167 | void (*channel_switch_beacon)(struct ieee80211_hw *hw, |
3036 | struct ieee80211_vif *vif, | 3168 | struct ieee80211_vif *vif, |
3037 | struct cfg80211_chan_def *chandef); | 3169 | struct cfg80211_chan_def *chandef); |
3170 | int (*pre_channel_switch)(struct ieee80211_hw *hw, | ||
3171 | struct ieee80211_vif *vif, | ||
3172 | struct ieee80211_channel_switch *ch_switch); | ||
3173 | |||
3174 | int (*post_channel_switch)(struct ieee80211_hw *hw, | ||
3175 | struct ieee80211_vif *vif); | ||
3038 | 3176 | ||
3039 | int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 3177 | int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
3040 | void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 3178 | void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
3041 | u32 (*get_expected_throughput)(struct ieee80211_sta *sta); | 3179 | u32 (*get_expected_throughput)(struct ieee80211_sta *sta); |
3180 | int (*get_txpower)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
3181 | int *dbm); | ||
3182 | |||
3183 | int (*tdls_channel_switch)(struct ieee80211_hw *hw, | ||
3184 | struct ieee80211_vif *vif, | ||
3185 | struct ieee80211_sta *sta, u8 oper_class, | ||
3186 | struct cfg80211_chan_def *chandef, | ||
3187 | struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie); | ||
3188 | void (*tdls_cancel_channel_switch)(struct ieee80211_hw *hw, | ||
3189 | struct ieee80211_vif *vif, | ||
3190 | struct ieee80211_sta *sta); | ||
3191 | void (*tdls_recv_channel_switch)(struct ieee80211_hw *hw, | ||
3192 | struct ieee80211_vif *vif, | ||
3193 | struct ieee80211_tdls_ch_sw_params *params); | ||
3042 | }; | 3194 | }; |
3043 | 3195 | ||
3044 | /** | 3196 | /** |
3045 | * ieee80211_alloc_hw - Allocate a new hardware device | 3197 | * ieee80211_alloc_hw_nm - Allocate a new hardware device |
3198 | * | ||
3199 | * This must be called once for each hardware device. The returned pointer | ||
3200 | * must be used to refer to this device when calling other functions. | ||
3201 | * mac80211 allocates a private data area for the driver pointed to by | ||
3202 | * @priv in &struct ieee80211_hw, the size of this area is given as | ||
3203 | * @priv_data_len. | ||
3204 | * | ||
3205 | * @priv_data_len: length of private data | ||
3206 | * @ops: callbacks for this device | ||
3207 | * @requested_name: Requested name for this device. | ||
3208 | * NULL is valid value, and means use the default naming (phy%d) | ||
3209 | * | ||
3210 | * Return: A pointer to the new hardware device, or %NULL on error. | ||
3211 | */ | ||
3212 | struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, | ||
3213 | const struct ieee80211_ops *ops, | ||
3214 | const char *requested_name); | ||
3215 | |||
3216 | /** | ||
3217 | * ieee80211_alloc_hw - Allocate a new hardware device | ||
3046 | * | 3218 | * |
3047 | * This must be called once for each hardware device. The returned pointer | 3219 | * This must be called once for each hardware device. The returned pointer |
3048 | * must be used to refer to this device when calling other functions. | 3220 | * must be used to refer to this device when calling other functions. |
@@ -3055,8 +3227,12 @@ struct ieee80211_ops { | |||
3055 | * | 3227 | * |
3056 | * Return: A pointer to the new hardware device, or %NULL on error. | 3228 | * Return: A pointer to the new hardware device, or %NULL on error. |
3057 | */ | 3229 | */ |
3230 | static inline | ||
3058 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 3231 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
3059 | const struct ieee80211_ops *ops); | 3232 | const struct ieee80211_ops *ops) |
3233 | { | ||
3234 | return ieee80211_alloc_hw_nm(priv_data_len, ops, NULL); | ||
3235 | } | ||
3060 | 3236 | ||
3061 | /** | 3237 | /** |
3062 | * ieee80211_register_hw - Register hardware device | 3238 | * ieee80211_register_hw - Register hardware device |
@@ -3443,6 +3619,26 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, | |||
3443 | struct sk_buff *skb); | 3619 | struct sk_buff *skb); |
3444 | 3620 | ||
3445 | /** | 3621 | /** |
3622 | * ieee80211_tx_status_noskb - transmit status callback without skb | ||
3623 | * | ||
3624 | * This function can be used as a replacement for ieee80211_tx_status | ||
3625 | * in drivers that cannot reliably map tx status information back to | ||
3626 | * specific skbs. | ||
3627 | * | ||
3628 | * Calls to this function for a single hardware must be synchronized | ||
3629 | * against each other. Calls to this function, ieee80211_tx_status_ni() | ||
3630 | * and ieee80211_tx_status_irqsafe() may not be mixed for a single hardware. | ||
3631 | * | ||
3632 | * @hw: the hardware the frame was transmitted by | ||
3633 | * @sta: the receiver station to which this packet is sent | ||
3634 | * (NULL for multicast packets) | ||
3635 | * @info: tx status information | ||
3636 | */ | ||
3637 | void ieee80211_tx_status_noskb(struct ieee80211_hw *hw, | ||
3638 | struct ieee80211_sta *sta, | ||
3639 | struct ieee80211_tx_info *info); | ||
3640 | |||
3641 | /** | ||
3446 | * ieee80211_tx_status_ni - transmit status callback (in process context) | 3642 | * ieee80211_tx_status_ni - transmit status callback (in process context) |
3447 | * | 3643 | * |
3448 | * Like ieee80211_tx_status() but can be called in process context. | 3644 | * Like ieee80211_tx_status() but can be called in process context. |
@@ -3655,7 +3851,7 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | |||
3655 | /** | 3851 | /** |
3656 | * ieee80211_probereq_get - retrieve a Probe Request template | 3852 | * ieee80211_probereq_get - retrieve a Probe Request template |
3657 | * @hw: pointer obtained from ieee80211_alloc_hw(). | 3853 | * @hw: pointer obtained from ieee80211_alloc_hw(). |
3658 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | 3854 | * @src_addr: source MAC address |
3659 | * @ssid: SSID buffer | 3855 | * @ssid: SSID buffer |
3660 | * @ssid_len: length of SSID | 3856 | * @ssid_len: length of SSID |
3661 | * @tailroom: tailroom to reserve at end of SKB for IEs | 3857 | * @tailroom: tailroom to reserve at end of SKB for IEs |
@@ -3666,7 +3862,7 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | |||
3666 | * Return: The Probe Request template. %NULL on error. | 3862 | * Return: The Probe Request template. %NULL on error. |
3667 | */ | 3863 | */ |
3668 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | 3864 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, |
3669 | struct ieee80211_vif *vif, | 3865 | const u8 *src_addr, |
3670 | const u8 *ssid, size_t ssid_len, | 3866 | const u8 *ssid, size_t ssid_len, |
3671 | size_t tailroom); | 3867 | size_t tailroom); |
3672 | 3868 | ||
@@ -4172,6 +4368,22 @@ void ieee80211_iterate_active_interfaces_rtnl(struct ieee80211_hw *hw, | |||
4172 | void *data); | 4368 | void *data); |
4173 | 4369 | ||
4174 | /** | 4370 | /** |
4371 | * ieee80211_iterate_stations_atomic - iterate stations | ||
4372 | * | ||
4373 | * This function iterates over all stations associated with a given | ||
4374 | * hardware that are currently uploaded to the driver and calls the callback | ||
4375 | * function for them. | ||
4376 | * This function requires the iterator callback function to be atomic, | ||
4377 | * | ||
4378 | * @hw: the hardware struct of which the interfaces should be iterated over | ||
4379 | * @iterator: the iterator function to call, cannot sleep | ||
4380 | * @data: first argument of the iterator function | ||
4381 | */ | ||
4382 | void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw, | ||
4383 | void (*iterator)(void *data, | ||
4384 | struct ieee80211_sta *sta), | ||
4385 | void *data); | ||
4386 | /** | ||
4175 | * ieee80211_queue_work - add work onto the mac80211 workqueue | 4387 | * ieee80211_queue_work - add work onto the mac80211 workqueue |
4176 | * | 4388 | * |
4177 | * Drivers and mac80211 use this to add work onto the mac80211 workqueue. | 4389 | * Drivers and mac80211 use this to add work onto the mac80211 workqueue. |
@@ -4480,6 +4692,14 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, | |||
4480 | gfp_t gfp); | 4692 | gfp_t gfp); |
4481 | 4693 | ||
4482 | /** | 4694 | /** |
4695 | * ieee80211_cqm_beacon_loss_notify - inform CQM of beacon loss | ||
4696 | * | ||
4697 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
4698 | * @gfp: context flags | ||
4699 | */ | ||
4700 | void ieee80211_cqm_beacon_loss_notify(struct ieee80211_vif *vif, gfp_t gfp); | ||
4701 | |||
4702 | /** | ||
4483 | * ieee80211_radar_detected - inform that a radar was detected | 4703 | * ieee80211_radar_detected - inform that a radar was detected |
4484 | * | 4704 | * |
4485 | * @hw: pointer as obtained from ieee80211_alloc_hw() | 4705 | * @hw: pointer as obtained from ieee80211_alloc_hw() |
@@ -4637,6 +4857,10 @@ struct rate_control_ops { | |||
4637 | void (*free_sta)(void *priv, struct ieee80211_sta *sta, | 4857 | void (*free_sta)(void *priv, struct ieee80211_sta *sta, |
4638 | void *priv_sta); | 4858 | void *priv_sta); |
4639 | 4859 | ||
4860 | void (*tx_status_noskb)(void *priv, | ||
4861 | struct ieee80211_supported_band *sband, | ||
4862 | struct ieee80211_sta *sta, void *priv_sta, | ||
4863 | struct ieee80211_tx_info *info); | ||
4640 | void (*tx_status)(void *priv, struct ieee80211_supported_band *sband, | 4864 | void (*tx_status)(void *priv, struct ieee80211_supported_band *sband, |
4641 | struct ieee80211_sta *sta, void *priv_sta, | 4865 | struct ieee80211_sta *sta, void *priv_sta, |
4642 | struct sk_buff *skb); | 4866 | struct sk_buff *skb); |
@@ -4888,4 +5112,69 @@ void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf); | |||
4888 | void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, | 5112 | void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, |
4889 | enum nl80211_tdls_operation oper, | 5113 | enum nl80211_tdls_operation oper, |
4890 | u16 reason_code, gfp_t gfp); | 5114 | u16 reason_code, gfp_t gfp); |
5115 | |||
5116 | /** | ||
5117 | * ieee80211_reserve_tid - request to reserve a specific TID | ||
5118 | * | ||
5119 | * There is sometimes a need (such as in TDLS) for blocking the driver from | ||
5120 | * using a specific TID so that the FW can use it for certain operations such | ||
5121 | * as sending PTI requests. To make sure that the driver doesn't use that TID, | ||
5122 | * this function must be called as it flushes out packets on this TID and marks | ||
5123 | * it as blocked, so that any transmit for the station on this TID will be | ||
5124 | * redirected to the alternative TID in the same AC. | ||
5125 | * | ||
5126 | * Note that this function blocks and may call back into the driver, so it | ||
5127 | * should be called without driver locks held. Also note this function should | ||
5128 | * only be called from the driver's @sta_state callback. | ||
5129 | * | ||
5130 | * @sta: the station to reserve the TID for | ||
5131 | * @tid: the TID to reserve | ||
5132 | * | ||
5133 | * Returns: 0 on success, else on failure | ||
5134 | */ | ||
5135 | int ieee80211_reserve_tid(struct ieee80211_sta *sta, u8 tid); | ||
5136 | |||
5137 | /** | ||
5138 | * ieee80211_unreserve_tid - request to unreserve a specific TID | ||
5139 | * | ||
5140 | * Once there is no longer any need for reserving a certain TID, this function | ||
5141 | * should be called, and no longer will packets have their TID modified for | ||
5142 | * preventing use of this TID in the driver. | ||
5143 | * | ||
5144 | * Note that this function blocks and acquires a lock, so it should be called | ||
5145 | * without driver locks held. Also note this function should only be called | ||
5146 | * from the driver's @sta_state callback. | ||
5147 | * | ||
5148 | * @sta: the station | ||
5149 | * @tid: the TID to unreserve | ||
5150 | */ | ||
5151 | void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid); | ||
5152 | |||
5153 | /** | ||
5154 | * ieee80211_ie_split - split an IE buffer according to ordering | ||
5155 | * | ||
5156 | * @ies: the IE buffer | ||
5157 | * @ielen: the length of the IE buffer | ||
5158 | * @ids: an array with element IDs that are allowed before | ||
5159 | * the split | ||
5160 | * @n_ids: the size of the element ID array | ||
5161 | * @offset: offset where to start splitting in the buffer | ||
5162 | * | ||
5163 | * This function splits an IE buffer by updating the @offset | ||
5164 | * variable to point to the location where the buffer should be | ||
5165 | * split. | ||
5166 | * | ||
5167 | * It assumes that the given IE buffer is well-formed, this | ||
5168 | * has to be guaranteed by the caller! | ||
5169 | * | ||
5170 | * It also assumes that the IEs in the buffer are ordered | ||
5171 | * correctly, if not the result of using this function will not | ||
5172 | * be ordered correctly either, i.e. it does no reordering. | ||
5173 | * | ||
5174 | * The function returns the offset where the next part of the | ||
5175 | * buffer starts, which may be @ielen if the entire (remainder) | ||
5176 | * of the buffer should be used. | ||
5177 | */ | ||
5178 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
5179 | const u8 *ids, int n_ids, size_t offset); | ||
4891 | #endif /* MAC80211_H */ | 5180 | #endif /* MAC80211_H */ |
diff --git a/include/net/nfc/digital.h b/include/net/nfc/digital.h index d9a5cf7ac1c4..0ae101eef0f4 100644 --- a/include/net/nfc/digital.h +++ b/include/net/nfc/digital.h | |||
@@ -225,6 +225,19 @@ struct nfc_digital_dev { | |||
225 | u8 curr_protocol; | 225 | u8 curr_protocol; |
226 | u8 curr_rf_tech; | 226 | u8 curr_rf_tech; |
227 | u8 curr_nfc_dep_pni; | 227 | u8 curr_nfc_dep_pni; |
228 | u8 did; | ||
229 | |||
230 | u8 local_payload_max; | ||
231 | u8 remote_payload_max; | ||
232 | |||
233 | struct sk_buff *chaining_skb; | ||
234 | struct digital_data_exch *data_exch; | ||
235 | |||
236 | int atn_count; | ||
237 | int nack_count; | ||
238 | |||
239 | struct sk_buff *saved_skb; | ||
240 | unsigned int saved_skb_len; | ||
228 | 241 | ||
229 | u16 target_fsc; | 242 | u16 target_fsc; |
230 | 243 | ||
diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 7ee8f4cc610b..14bd0e1c47fa 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h | |||
@@ -57,10 +57,14 @@ struct nfc_hci_ops { | |||
57 | int (*discover_se)(struct nfc_hci_dev *dev); | 57 | int (*discover_se)(struct nfc_hci_dev *dev); |
58 | int (*enable_se)(struct nfc_hci_dev *dev, u32 se_idx); | 58 | int (*enable_se)(struct nfc_hci_dev *dev, u32 se_idx); |
59 | int (*disable_se)(struct nfc_hci_dev *dev, u32 se_idx); | 59 | int (*disable_se)(struct nfc_hci_dev *dev, u32 se_idx); |
60 | int (*se_io)(struct nfc_hci_dev *dev, u32 se_idx, | ||
61 | u8 *apdu, size_t apdu_length, | ||
62 | se_io_cb_t cb, void *cb_context); | ||
60 | }; | 63 | }; |
61 | 64 | ||
62 | /* Pipes */ | 65 | /* Pipes */ |
63 | #define NFC_HCI_INVALID_PIPE 0x80 | 66 | #define NFC_HCI_INVALID_PIPE 0x80 |
67 | #define NFC_HCI_DO_NOT_CREATE_PIPE 0x81 | ||
64 | #define NFC_HCI_LINK_MGMT_PIPE 0x00 | 68 | #define NFC_HCI_LINK_MGMT_PIPE 0x00 |
65 | #define NFC_HCI_ADMIN_PIPE 0x01 | 69 | #define NFC_HCI_ADMIN_PIPE 0x01 |
66 | 70 | ||
diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h index 9eca9ae2280c..e7257a4653b4 100644 --- a/include/net/nfc/nci.h +++ b/include/net/nfc/nci.h | |||
@@ -28,6 +28,8 @@ | |||
28 | #ifndef __NCI_H | 28 | #ifndef __NCI_H |
29 | #define __NCI_H | 29 | #define __NCI_H |
30 | 30 | ||
31 | #include <net/nfc/nfc.h> | ||
32 | |||
31 | /* NCI constants */ | 33 | /* NCI constants */ |
32 | #define NCI_MAX_NUM_MAPPING_CONFIGS 10 | 34 | #define NCI_MAX_NUM_MAPPING_CONFIGS 10 |
33 | #define NCI_MAX_NUM_RF_CONFIGS 10 | 35 | #define NCI_MAX_NUM_RF_CONFIGS 10 |
@@ -73,6 +75,8 @@ | |||
73 | #define NCI_NFC_A_ACTIVE_LISTEN_MODE 0x83 | 75 | #define NCI_NFC_A_ACTIVE_LISTEN_MODE 0x83 |
74 | #define NCI_NFC_F_ACTIVE_LISTEN_MODE 0x85 | 76 | #define NCI_NFC_F_ACTIVE_LISTEN_MODE 0x85 |
75 | 77 | ||
78 | #define NCI_RF_TECH_MODE_LISTEN_MASK 0x80 | ||
79 | |||
76 | /* NCI RF Technologies */ | 80 | /* NCI RF Technologies */ |
77 | #define NCI_NFC_RF_TECHNOLOGY_A 0x00 | 81 | #define NCI_NFC_RF_TECHNOLOGY_A 0x00 |
78 | #define NCI_NFC_RF_TECHNOLOGY_B 0x01 | 82 | #define NCI_NFC_RF_TECHNOLOGY_B 0x01 |
@@ -106,6 +110,17 @@ | |||
106 | 110 | ||
107 | /* NCI Configuration Parameter Tags */ | 111 | /* NCI Configuration Parameter Tags */ |
108 | #define NCI_PN_ATR_REQ_GEN_BYTES 0x29 | 112 | #define NCI_PN_ATR_REQ_GEN_BYTES 0x29 |
113 | #define NCI_LN_ATR_RES_GEN_BYTES 0x61 | ||
114 | #define NCI_LA_SEL_INFO 0x32 | ||
115 | #define NCI_LF_PROTOCOL_TYPE 0x50 | ||
116 | #define NCI_LF_CON_BITR_F 0x54 | ||
117 | |||
118 | /* NCI Configuration Parameters masks */ | ||
119 | #define NCI_LA_SEL_INFO_ISO_DEP_MASK 0x20 | ||
120 | #define NCI_LA_SEL_INFO_NFC_DEP_MASK 0x40 | ||
121 | #define NCI_LF_PROTOCOL_TYPE_NFC_DEP_MASK 0x02 | ||
122 | #define NCI_LF_CON_BITR_F_212 0x02 | ||
123 | #define NCI_LF_CON_BITR_F_424 0x04 | ||
109 | 124 | ||
110 | /* NCI Reset types */ | 125 | /* NCI Reset types */ |
111 | #define NCI_RESET_TYPE_KEEP_CONFIG 0x00 | 126 | #define NCI_RESET_TYPE_KEEP_CONFIG 0x00 |
@@ -314,26 +329,31 @@ struct nci_core_intf_error_ntf { | |||
314 | struct rf_tech_specific_params_nfca_poll { | 329 | struct rf_tech_specific_params_nfca_poll { |
315 | __u16 sens_res; | 330 | __u16 sens_res; |
316 | __u8 nfcid1_len; /* 0, 4, 7, or 10 Bytes */ | 331 | __u8 nfcid1_len; /* 0, 4, 7, or 10 Bytes */ |
317 | __u8 nfcid1[10]; | 332 | __u8 nfcid1[NFC_NFCID1_MAXSIZE]; |
318 | __u8 sel_res_len; /* 0 or 1 Bytes */ | 333 | __u8 sel_res_len; /* 0 or 1 Bytes */ |
319 | __u8 sel_res; | 334 | __u8 sel_res; |
320 | } __packed; | 335 | } __packed; |
321 | 336 | ||
322 | struct rf_tech_specific_params_nfcb_poll { | 337 | struct rf_tech_specific_params_nfcb_poll { |
323 | __u8 sensb_res_len; | 338 | __u8 sensb_res_len; |
324 | __u8 sensb_res[12]; /* 11 or 12 Bytes */ | 339 | __u8 sensb_res[NFC_SENSB_RES_MAXSIZE]; /* 11 or 12 Bytes */ |
325 | } __packed; | 340 | } __packed; |
326 | 341 | ||
327 | struct rf_tech_specific_params_nfcf_poll { | 342 | struct rf_tech_specific_params_nfcf_poll { |
328 | __u8 bit_rate; | 343 | __u8 bit_rate; |
329 | __u8 sensf_res_len; | 344 | __u8 sensf_res_len; |
330 | __u8 sensf_res[18]; /* 16 or 18 Bytes */ | 345 | __u8 sensf_res[NFC_SENSF_RES_MAXSIZE]; /* 16 or 18 Bytes */ |
331 | } __packed; | 346 | } __packed; |
332 | 347 | ||
333 | struct rf_tech_specific_params_nfcv_poll { | 348 | struct rf_tech_specific_params_nfcv_poll { |
334 | __u8 res_flags; | 349 | __u8 res_flags; |
335 | __u8 dsfid; | 350 | __u8 dsfid; |
336 | __u8 uid[8]; /* 8 Bytes */ | 351 | __u8 uid[NFC_ISO15693_UID_MAXSIZE]; /* 8 Bytes */ |
352 | } __packed; | ||
353 | |||
354 | struct rf_tech_specific_params_nfcf_listen { | ||
355 | __u8 local_nfcid2_len; | ||
356 | __u8 local_nfcid2[NFC_NFCID2_MAXSIZE]; /* 0 or 8 Bytes */ | ||
337 | } __packed; | 357 | } __packed; |
338 | 358 | ||
339 | struct nci_rf_discover_ntf { | 359 | struct nci_rf_discover_ntf { |
@@ -365,7 +385,12 @@ struct activation_params_nfcb_poll_iso_dep { | |||
365 | 385 | ||
366 | struct activation_params_poll_nfc_dep { | 386 | struct activation_params_poll_nfc_dep { |
367 | __u8 atr_res_len; | 387 | __u8 atr_res_len; |
368 | __u8 atr_res[63]; | 388 | __u8 atr_res[NFC_ATR_RES_MAXSIZE - 2]; /* ATR_RES from byte 3 */ |
389 | }; | ||
390 | |||
391 | struct activation_params_listen_nfc_dep { | ||
392 | __u8 atr_req_len; | ||
393 | __u8 atr_req[NFC_ATR_REQ_MAXSIZE - 2]; /* ATR_REQ from byte 3 */ | ||
369 | }; | 394 | }; |
370 | 395 | ||
371 | struct nci_rf_intf_activated_ntf { | 396 | struct nci_rf_intf_activated_ntf { |
@@ -382,6 +407,7 @@ struct nci_rf_intf_activated_ntf { | |||
382 | struct rf_tech_specific_params_nfcb_poll nfcb_poll; | 407 | struct rf_tech_specific_params_nfcb_poll nfcb_poll; |
383 | struct rf_tech_specific_params_nfcf_poll nfcf_poll; | 408 | struct rf_tech_specific_params_nfcf_poll nfcf_poll; |
384 | struct rf_tech_specific_params_nfcv_poll nfcv_poll; | 409 | struct rf_tech_specific_params_nfcv_poll nfcv_poll; |
410 | struct rf_tech_specific_params_nfcf_listen nfcf_listen; | ||
385 | } rf_tech_specific_params; | 411 | } rf_tech_specific_params; |
386 | 412 | ||
387 | __u8 data_exch_rf_tech_and_mode; | 413 | __u8 data_exch_rf_tech_and_mode; |
@@ -393,6 +419,7 @@ struct nci_rf_intf_activated_ntf { | |||
393 | struct activation_params_nfca_poll_iso_dep nfca_poll_iso_dep; | 419 | struct activation_params_nfca_poll_iso_dep nfca_poll_iso_dep; |
394 | struct activation_params_nfcb_poll_iso_dep nfcb_poll_iso_dep; | 420 | struct activation_params_nfcb_poll_iso_dep nfcb_poll_iso_dep; |
395 | struct activation_params_poll_nfc_dep poll_nfc_dep; | 421 | struct activation_params_poll_nfc_dep poll_nfc_dep; |
422 | struct activation_params_listen_nfc_dep listen_nfc_dep; | ||
396 | } activation_params; | 423 | } activation_params; |
397 | 424 | ||
398 | } __packed; | 425 | } __packed; |
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index 75d10e625c49..9e51bb4d841e 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h | |||
@@ -4,6 +4,7 @@ | |||
4 | * | 4 | * |
5 | * Copyright (C) 2011 Texas Instruments, Inc. | 5 | * Copyright (C) 2011 Texas Instruments, Inc. |
6 | * Copyright (C) 2013 Intel Corporation. All rights reserved. | 6 | * Copyright (C) 2013 Intel Corporation. All rights reserved. |
7 | * Copyright (C) 2014 Marvell International Ltd. | ||
7 | * | 8 | * |
8 | * Written by Ilan Elias <ilane@ti.com> | 9 | * Written by Ilan Elias <ilane@ti.com> |
9 | * | 10 | * |
@@ -49,6 +50,8 @@ enum nci_state { | |||
49 | NCI_W4_ALL_DISCOVERIES, | 50 | NCI_W4_ALL_DISCOVERIES, |
50 | NCI_W4_HOST_SELECT, | 51 | NCI_W4_HOST_SELECT, |
51 | NCI_POLL_ACTIVE, | 52 | NCI_POLL_ACTIVE, |
53 | NCI_LISTEN_ACTIVE, | ||
54 | NCI_LISTEN_SLEEP, | ||
52 | }; | 55 | }; |
53 | 56 | ||
54 | /* NCI timeouts */ | 57 | /* NCI timeouts */ |
@@ -69,6 +72,12 @@ struct nci_ops { | |||
69 | int (*send)(struct nci_dev *ndev, struct sk_buff *skb); | 72 | int (*send)(struct nci_dev *ndev, struct sk_buff *skb); |
70 | int (*setup)(struct nci_dev *ndev); | 73 | int (*setup)(struct nci_dev *ndev); |
71 | __u32 (*get_rfprotocol)(struct nci_dev *ndev, __u8 rf_protocol); | 74 | __u32 (*get_rfprotocol)(struct nci_dev *ndev, __u8 rf_protocol); |
75 | int (*discover_se)(struct nci_dev *ndev); | ||
76 | int (*disable_se)(struct nci_dev *ndev, u32 se_idx); | ||
77 | int (*enable_se)(struct nci_dev *ndev, u32 se_idx); | ||
78 | int (*se_io)(struct nci_dev *ndev, u32 se_idx, | ||
79 | u8 *apdu, size_t apdu_length, | ||
80 | se_io_cb_t cb, void *cb_context); | ||
72 | }; | 81 | }; |
73 | 82 | ||
74 | #define NCI_MAX_SUPPORTED_RF_INTERFACES 4 | 83 | #define NCI_MAX_SUPPORTED_RF_INTERFACES 4 |
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 6c583e244de2..12adb817c27a 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2011 Instituto Nokia de Tecnologia | 2 | * Copyright (C) 2011 Instituto Nokia de Tecnologia |
3 | * Copyright (C) 2014 Marvell International Ltd. | ||
3 | * | 4 | * |
4 | * Authors: | 5 | * Authors: |
5 | * Lauro Ramos Venancio <lauro.venancio@openbossa.org> | 6 | * Lauro Ramos Venancio <lauro.venancio@openbossa.org> |
@@ -87,6 +88,7 @@ struct nfc_ops { | |||
87 | #define NFC_TARGET_IDX_ANY -1 | 88 | #define NFC_TARGET_IDX_ANY -1 |
88 | #define NFC_MAX_GT_LEN 48 | 89 | #define NFC_MAX_GT_LEN 48 |
89 | #define NFC_ATR_RES_GT_OFFSET 15 | 90 | #define NFC_ATR_RES_GT_OFFSET 15 |
91 | #define NFC_ATR_REQ_GT_OFFSET 14 | ||
90 | 92 | ||
91 | /** | 93 | /** |
92 | * struct nfc_target - NFC target descriptiom | 94 | * struct nfc_target - NFC target descriptiom |
diff --git a/include/net/regulatory.h b/include/net/regulatory.h index dad7ab20a8cb..b776d72d84be 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h | |||
@@ -136,6 +136,17 @@ struct regulatory_request { | |||
136 | * otherwise initiating radiation is not allowed. This will enable the | 136 | * otherwise initiating radiation is not allowed. This will enable the |
137 | * relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration | 137 | * relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration |
138 | * option | 138 | * option |
139 | * @REGULATORY_IGNORE_STALE_KICKOFF: the regulatory core will _not_ make sure | ||
140 | * all interfaces on this wiphy reside on allowed channels. If this flag | ||
141 | * is not set, upon a regdomain change, the interfaces are given a grace | ||
142 | * period (currently 60 seconds) to disconnect or move to an allowed | ||
143 | * channel. Interfaces on forbidden channels are forcibly disconnected. | ||
144 | * Currently these types of interfaces are supported for enforcement: | ||
145 | * NL80211_IFTYPE_ADHOC, NL80211_IFTYPE_STATION, NL80211_IFTYPE_AP, | ||
146 | * NL80211_IFTYPE_AP_VLAN, NL80211_IFTYPE_MONITOR, | ||
147 | * NL80211_IFTYPE_P2P_CLIENT, NL80211_IFTYPE_P2P_GO, | ||
148 | * NL80211_IFTYPE_P2P_DEVICE. The flag will be set by default if a device | ||
149 | * includes any modes unsupported for enforcement checking. | ||
139 | */ | 150 | */ |
140 | enum ieee80211_regulatory_flags { | 151 | enum ieee80211_regulatory_flags { |
141 | REGULATORY_CUSTOM_REG = BIT(0), | 152 | REGULATORY_CUSTOM_REG = BIT(0), |
@@ -144,6 +155,7 @@ enum ieee80211_regulatory_flags { | |||
144 | REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3), | 155 | REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3), |
145 | REGULATORY_COUNTRY_IE_IGNORE = BIT(4), | 156 | REGULATORY_COUNTRY_IE_IGNORE = BIT(4), |
146 | REGULATORY_ENABLE_RELAX_NO_IR = BIT(5), | 157 | REGULATORY_ENABLE_RELAX_NO_IR = BIT(5), |
158 | REGULATORY_IGNORE_STALE_KICKOFF = BIT(6), | ||
147 | }; | 159 | }; |
148 | 160 | ||
149 | struct ieee80211_freq_range { | 161 | struct ieee80211_freq_range { |
diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h index 9b19b4461928..8119255feae4 100644 --- a/include/uapi/linux/nfc.h +++ b/include/uapi/linux/nfc.h | |||
@@ -116,6 +116,7 @@ enum nfc_commands { | |||
116 | NFC_EVENT_SE_TRANSACTION, | 116 | NFC_EVENT_SE_TRANSACTION, |
117 | NFC_CMD_GET_SE, | 117 | NFC_CMD_GET_SE, |
118 | NFC_CMD_SE_IO, | 118 | NFC_CMD_SE_IO, |
119 | NFC_CMD_ACTIVATE_TARGET, | ||
119 | /* private: internal use only */ | 120 | /* private: internal use only */ |
120 | __NFC_CMD_AFTER_LAST | 121 | __NFC_CMD_AFTER_LAST |
121 | }; | 122 | }; |
@@ -196,15 +197,19 @@ enum nfc_sdp_attr { | |||
196 | }; | 197 | }; |
197 | #define NFC_SDP_ATTR_MAX (__NFC_SDP_ATTR_AFTER_LAST - 1) | 198 | #define NFC_SDP_ATTR_MAX (__NFC_SDP_ATTR_AFTER_LAST - 1) |
198 | 199 | ||
199 | #define NFC_DEVICE_NAME_MAXSIZE 8 | 200 | #define NFC_DEVICE_NAME_MAXSIZE 8 |
200 | #define NFC_NFCID1_MAXSIZE 10 | 201 | #define NFC_NFCID1_MAXSIZE 10 |
201 | #define NFC_NFCID2_MAXSIZE 8 | 202 | #define NFC_NFCID2_MAXSIZE 8 |
202 | #define NFC_NFCID3_MAXSIZE 10 | 203 | #define NFC_NFCID3_MAXSIZE 10 |
203 | #define NFC_SENSB_RES_MAXSIZE 12 | 204 | #define NFC_SENSB_RES_MAXSIZE 12 |
204 | #define NFC_SENSF_RES_MAXSIZE 18 | 205 | #define NFC_SENSF_RES_MAXSIZE 18 |
205 | #define NFC_GB_MAXSIZE 48 | 206 | #define NFC_ATR_REQ_MAXSIZE 64 |
206 | #define NFC_FIRMWARE_NAME_MAXSIZE 32 | 207 | #define NFC_ATR_RES_MAXSIZE 64 |
207 | #define NFC_ISO15693_UID_MAXSIZE 8 | 208 | #define NFC_ATR_REQ_GB_MAXSIZE 48 |
209 | #define NFC_ATR_RES_GB_MAXSIZE 47 | ||
210 | #define NFC_GB_MAXSIZE 48 | ||
211 | #define NFC_FIRMWARE_NAME_MAXSIZE 32 | ||
212 | #define NFC_ISO15693_UID_MAXSIZE 8 | ||
208 | 213 | ||
209 | /* NFC protocols */ | 214 | /* NFC protocols */ |
210 | #define NFC_PROTO_JEWEL 1 | 215 | #define NFC_PROTO_JEWEL 1 |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 4b28dc07bcb1..b37bd5a1cb82 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -227,7 +227,11 @@ | |||
227 | * the interface identified by %NL80211_ATTR_IFINDEX. | 227 | * the interface identified by %NL80211_ATTR_IFINDEX. |
228 | * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC | 228 | * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC |
229 | * or, if no MAC address given, all stations, on the interface identified | 229 | * or, if no MAC address given, all stations, on the interface identified |
230 | * by %NL80211_ATTR_IFINDEX. | 230 | * by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and |
231 | * %NL80211_ATTR_REASON_CODE can optionally be used to specify which type | ||
232 | * of disconnection indication should be sent to the station | ||
233 | * (Deauthentication or Disassociation frame and reason code for that | ||
234 | * frame). | ||
231 | * | 235 | * |
232 | * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to | 236 | * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to |
233 | * destination %NL80211_ATTR_MAC on the interface identified by | 237 | * destination %NL80211_ATTR_MAC on the interface identified by |
@@ -639,7 +643,18 @@ | |||
639 | * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels | 643 | * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels |
640 | * independently of the userspace SME, send this event indicating | 644 | * independently of the userspace SME, send this event indicating |
641 | * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the | 645 | * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the |
642 | * attributes determining channel width. | 646 | * attributes determining channel width. This indication may also be |
647 | * sent when a remotely-initiated switch (e.g., when a STA receives a CSA | ||
648 | * from the remote AP) is completed; | ||
649 | * | ||
650 | * @NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: Notify that a channel switch | ||
651 | * has been started on an interface, regardless of the initiator | ||
652 | * (ie. whether it was requested from a remote device or | ||
653 | * initiated on our own). It indicates that | ||
654 | * %NL80211_ATTR_IFINDEX will be on %NL80211_ATTR_WIPHY_FREQ | ||
655 | * after %NL80211_ATTR_CH_SWITCH_COUNT TBTT's. The userspace may | ||
656 | * decide to react to this indication by requesting other | ||
657 | * interfaces to change channel as well. | ||
643 | * | 658 | * |
644 | * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by | 659 | * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by |
645 | * its %NL80211_ATTR_WDEV identifier. It must have been created with | 660 | * its %NL80211_ATTR_WDEV identifier. It must have been created with |
@@ -738,6 +753,27 @@ | |||
738 | * before removing a station entry entirely, or before disassociating | 753 | * before removing a station entry entirely, or before disassociating |
739 | * or similar, cleanup will happen in the driver/device in this case. | 754 | * or similar, cleanup will happen in the driver/device in this case. |
740 | * | 755 | * |
756 | * @NL80211_CMD_GET_MPP: Get mesh path attributes for mesh proxy path to | ||
757 | * destination %NL80211_ATTR_MAC on the interface identified by | ||
758 | * %NL80211_ATTR_IFINDEX. | ||
759 | * | ||
760 | * @NL80211_CMD_JOIN_OCB: Join the OCB network. The center frequency and | ||
761 | * bandwidth of a channel must be given. | ||
762 | * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the | ||
763 | * network is determined by the network interface. | ||
764 | * | ||
765 | * @NL80211_CMD_TDLS_CHANNEL_SWITCH: Start channel-switching with a TDLS peer, | ||
766 | * identified by the %NL80211_ATTR_MAC parameter. A target channel is | ||
767 | * provided via %NL80211_ATTR_WIPHY_FREQ and other attributes determining | ||
768 | * channel width/type. The target operating class is given via | ||
769 | * %NL80211_ATTR_OPER_CLASS. | ||
770 | * The driver is responsible for continually initiating channel-switching | ||
771 | * operations and returning to the base channel for communication with the | ||
772 | * AP. | ||
773 | * @NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH: Stop channel-switching with a TDLS | ||
774 | * peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel | ||
775 | * when this command completes. | ||
776 | * | ||
741 | * @NL80211_CMD_MAX: highest used command number | 777 | * @NL80211_CMD_MAX: highest used command number |
742 | * @__NL80211_CMD_AFTER_LAST: internal use | 778 | * @__NL80211_CMD_AFTER_LAST: internal use |
743 | */ | 779 | */ |
@@ -912,6 +948,16 @@ enum nl80211_commands { | |||
912 | NL80211_CMD_ADD_TX_TS, | 948 | NL80211_CMD_ADD_TX_TS, |
913 | NL80211_CMD_DEL_TX_TS, | 949 | NL80211_CMD_DEL_TX_TS, |
914 | 950 | ||
951 | NL80211_CMD_GET_MPP, | ||
952 | |||
953 | NL80211_CMD_JOIN_OCB, | ||
954 | NL80211_CMD_LEAVE_OCB, | ||
955 | |||
956 | NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, | ||
957 | |||
958 | NL80211_CMD_TDLS_CHANNEL_SWITCH, | ||
959 | NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH, | ||
960 | |||
915 | /* add new commands above here */ | 961 | /* add new commands above here */ |
916 | 962 | ||
917 | /* used to define NL80211_CMD_MAX below */ | 963 | /* used to define NL80211_CMD_MAX below */ |
@@ -1606,9 +1652,9 @@ enum nl80211_commands { | |||
1606 | * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32. | 1652 | * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32. |
1607 | * As specified in the &enum nl80211_tdls_peer_capability. | 1653 | * As specified in the &enum nl80211_tdls_peer_capability. |
1608 | * | 1654 | * |
1609 | * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface | 1655 | * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface |
1610 | * creation then the new interface will be owned by the netlink socket | 1656 | * creation then the new interface will be owned by the netlink socket |
1611 | * that created it and will be destroyed when the socket is closed | 1657 | * that created it and will be destroyed when the socket is closed. |
1612 | * | 1658 | * |
1613 | * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is | 1659 | * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is |
1614 | * the TDLS link initiator. | 1660 | * the TDLS link initiator. |
@@ -1638,6 +1684,11 @@ enum nl80211_commands { | |||
1638 | * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see | 1684 | * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see |
1639 | * &enum nl80211_smps_mode. | 1685 | * &enum nl80211_smps_mode. |
1640 | * | 1686 | * |
1687 | * @NL80211_ATTR_OPER_CLASS: operating class | ||
1688 | * | ||
1689 | * @NL80211_ATTR_MAC_MASK: MAC address mask | ||
1690 | * | ||
1691 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available | ||
1641 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1692 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1642 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1693 | * @__NL80211_ATTR_AFTER_LAST: internal use |
1643 | */ | 1694 | */ |
@@ -1973,7 +2024,7 @@ enum nl80211_attrs { | |||
1973 | 2024 | ||
1974 | NL80211_ATTR_TDLS_PEER_CAPABILITY, | 2025 | NL80211_ATTR_TDLS_PEER_CAPABILITY, |
1975 | 2026 | ||
1976 | NL80211_ATTR_IFACE_SOCKET_OWNER, | 2027 | NL80211_ATTR_SOCKET_OWNER, |
1977 | 2028 | ||
1978 | NL80211_ATTR_CSA_C_OFFSETS_TX, | 2029 | NL80211_ATTR_CSA_C_OFFSETS_TX, |
1979 | NL80211_ATTR_MAX_CSA_COUNTERS, | 2030 | NL80211_ATTR_MAX_CSA_COUNTERS, |
@@ -1990,15 +2041,21 @@ enum nl80211_attrs { | |||
1990 | 2041 | ||
1991 | NL80211_ATTR_SMPS_MODE, | 2042 | NL80211_ATTR_SMPS_MODE, |
1992 | 2043 | ||
2044 | NL80211_ATTR_OPER_CLASS, | ||
2045 | |||
2046 | NL80211_ATTR_MAC_MASK, | ||
2047 | |||
1993 | /* add attributes here, update the policy in nl80211.c */ | 2048 | /* add attributes here, update the policy in nl80211.c */ |
1994 | 2049 | ||
1995 | __NL80211_ATTR_AFTER_LAST, | 2050 | __NL80211_ATTR_AFTER_LAST, |
2051 | NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST, | ||
1996 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 | 2052 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 |
1997 | }; | 2053 | }; |
1998 | 2054 | ||
1999 | /* source-level API compatibility */ | 2055 | /* source-level API compatibility */ |
2000 | #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION | 2056 | #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION |
2001 | #define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG | 2057 | #define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG |
2058 | #define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER | ||
2002 | 2059 | ||
2003 | /* | 2060 | /* |
2004 | * Allow user space programs to use #ifdef on new attributes by defining them | 2061 | * Allow user space programs to use #ifdef on new attributes by defining them |
@@ -2064,6 +2121,8 @@ enum nl80211_attrs { | |||
2064 | * and therefore can't be created in the normal ways, use the | 2121 | * and therefore can't be created in the normal ways, use the |
2065 | * %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE | 2122 | * %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE |
2066 | * commands to create and destroy one | 2123 | * commands to create and destroy one |
2124 | * @NL80211_IF_TYPE_OCB: Outside Context of a BSS | ||
2125 | * This mode corresponds to the MIB variable dot11OCBActivated=true | ||
2067 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined | 2126 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined |
2068 | * @NUM_NL80211_IFTYPES: number of defined interface types | 2127 | * @NUM_NL80211_IFTYPES: number of defined interface types |
2069 | * | 2128 | * |
@@ -2083,6 +2142,7 @@ enum nl80211_iftype { | |||
2083 | NL80211_IFTYPE_P2P_CLIENT, | 2142 | NL80211_IFTYPE_P2P_CLIENT, |
2084 | NL80211_IFTYPE_P2P_GO, | 2143 | NL80211_IFTYPE_P2P_GO, |
2085 | NL80211_IFTYPE_P2P_DEVICE, | 2144 | NL80211_IFTYPE_P2P_DEVICE, |
2145 | NL80211_IFTYPE_OCB, | ||
2086 | 2146 | ||
2087 | /* keep last */ | 2147 | /* keep last */ |
2088 | NUM_NL80211_IFTYPES, | 2148 | NUM_NL80211_IFTYPES, |
@@ -2631,6 +2691,11 @@ enum nl80211_sched_scan_match_attr { | |||
2631 | * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated | 2691 | * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated |
2632 | * base on contiguous rules and wider channels will be allowed to cross | 2692 | * base on contiguous rules and wider channels will be allowed to cross |
2633 | * multiple contiguous/overlapping frequency ranges. | 2693 | * multiple contiguous/overlapping frequency ranges. |
2694 | * @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT | ||
2695 | * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation | ||
2696 | * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation | ||
2697 | * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed | ||
2698 | * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed | ||
2634 | */ | 2699 | */ |
2635 | enum nl80211_reg_rule_flags { | 2700 | enum nl80211_reg_rule_flags { |
2636 | NL80211_RRF_NO_OFDM = 1<<0, | 2701 | NL80211_RRF_NO_OFDM = 1<<0, |
@@ -2643,11 +2708,18 @@ enum nl80211_reg_rule_flags { | |||
2643 | NL80211_RRF_NO_IR = 1<<7, | 2708 | NL80211_RRF_NO_IR = 1<<7, |
2644 | __NL80211_RRF_NO_IBSS = 1<<8, | 2709 | __NL80211_RRF_NO_IBSS = 1<<8, |
2645 | NL80211_RRF_AUTO_BW = 1<<11, | 2710 | NL80211_RRF_AUTO_BW = 1<<11, |
2711 | NL80211_RRF_GO_CONCURRENT = 1<<12, | ||
2712 | NL80211_RRF_NO_HT40MINUS = 1<<13, | ||
2713 | NL80211_RRF_NO_HT40PLUS = 1<<14, | ||
2714 | NL80211_RRF_NO_80MHZ = 1<<15, | ||
2715 | NL80211_RRF_NO_160MHZ = 1<<16, | ||
2646 | }; | 2716 | }; |
2647 | 2717 | ||
2648 | #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR | 2718 | #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR |
2649 | #define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR | 2719 | #define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR |
2650 | #define NL80211_RRF_NO_IR NL80211_RRF_NO_IR | 2720 | #define NL80211_RRF_NO_IR NL80211_RRF_NO_IR |
2721 | #define NL80211_RRF_NO_HT40 (NL80211_RRF_NO_HT40MINUS |\ | ||
2722 | NL80211_RRF_NO_HT40PLUS) | ||
2651 | 2723 | ||
2652 | /* For backport compatibility with older userspace */ | 2724 | /* For backport compatibility with older userspace */ |
2653 | #define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) | 2725 | #define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) |
@@ -3379,6 +3451,8 @@ enum nl80211_ps_state { | |||
3379 | * interval in which %NL80211_ATTR_CQM_TXE_PKTS and | 3451 | * interval in which %NL80211_ATTR_CQM_TXE_PKTS and |
3380 | * %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an | 3452 | * %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an |
3381 | * %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting. | 3453 | * %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting. |
3454 | * @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon | ||
3455 | * loss event | ||
3382 | * @__NL80211_ATTR_CQM_AFTER_LAST: internal | 3456 | * @__NL80211_ATTR_CQM_AFTER_LAST: internal |
3383 | * @NL80211_ATTR_CQM_MAX: highest key attribute | 3457 | * @NL80211_ATTR_CQM_MAX: highest key attribute |
3384 | */ | 3458 | */ |
@@ -3391,6 +3465,7 @@ enum nl80211_attr_cqm { | |||
3391 | NL80211_ATTR_CQM_TXE_RATE, | 3465 | NL80211_ATTR_CQM_TXE_RATE, |
3392 | NL80211_ATTR_CQM_TXE_PKTS, | 3466 | NL80211_ATTR_CQM_TXE_PKTS, |
3393 | NL80211_ATTR_CQM_TXE_INTVL, | 3467 | NL80211_ATTR_CQM_TXE_INTVL, |
3468 | NL80211_ATTR_CQM_BEACON_LOSS_EVENT, | ||
3394 | 3469 | ||
3395 | /* keep last */ | 3470 | /* keep last */ |
3396 | __NL80211_ATTR_CQM_AFTER_LAST, | 3471 | __NL80211_ATTR_CQM_AFTER_LAST, |
@@ -3403,9 +3478,7 @@ enum nl80211_attr_cqm { | |||
3403 | * configured threshold | 3478 | * configured threshold |
3404 | * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the | 3479 | * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the |
3405 | * configured threshold | 3480 | * configured threshold |
3406 | * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss. | 3481 | * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: (reserved, never sent) |
3407 | * (Note that deauth/disassoc will still follow if the AP is not | ||
3408 | * available. This event might get used as roaming event, etc.) | ||
3409 | */ | 3482 | */ |
3410 | enum nl80211_cqm_rssi_threshold_event { | 3483 | enum nl80211_cqm_rssi_threshold_event { |
3411 | NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, | 3484 | NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, |
@@ -3545,6 +3618,25 @@ struct nl80211_pattern_support { | |||
3545 | * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only, | 3618 | * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only, |
3546 | * the TCP connection ran out of tokens to use for data to send to the | 3619 | * the TCP connection ran out of tokens to use for data to send to the |
3547 | * service | 3620 | * service |
3621 | * @NL80211_WOWLAN_TRIG_NET_DETECT: wake up when a configured network | ||
3622 | * is detected. This is a nested attribute that contains the | ||
3623 | * same attributes used with @NL80211_CMD_START_SCHED_SCAN. It | ||
3624 | * specifies how the scan is performed (e.g. the interval and the | ||
3625 | * channels to scan) as well as the scan results that will | ||
3626 | * trigger a wake (i.e. the matchsets). | ||
3627 | * @NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: nested attribute | ||
3628 | * containing an array with information about what triggered the | ||
3629 | * wake up. If no elements are present in the array, it means | ||
3630 | * that the information is not available. If more than one | ||
3631 | * element is present, it means that more than one match | ||
3632 | * occurred. | ||
3633 | * Each element in the array is a nested attribute that contains | ||
3634 | * one optional %NL80211_ATTR_SSID attribute and one optional | ||
3635 | * %NL80211_ATTR_SCAN_FREQUENCIES attribute. At least one of | ||
3636 | * these attributes must be present. If | ||
3637 | * %NL80211_ATTR_SCAN_FREQUENCIES contains more than one | ||
3638 | * frequency, it means that the match occurred in more than one | ||
3639 | * channel. | ||
3548 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers | 3640 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers |
3549 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number | 3641 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number |
3550 | * | 3642 | * |
@@ -3570,6 +3662,8 @@ enum nl80211_wowlan_triggers { | |||
3570 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH, | 3662 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH, |
3571 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST, | 3663 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST, |
3572 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS, | 3664 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS, |
3665 | NL80211_WOWLAN_TRIG_NET_DETECT, | ||
3666 | NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS, | ||
3573 | 3667 | ||
3574 | /* keep last */ | 3668 | /* keep last */ |
3575 | NUM_NL80211_WOWLAN_TRIG, | 3669 | NUM_NL80211_WOWLAN_TRIG, |
@@ -4042,6 +4136,27 @@ enum nl80211_ap_sme_features { | |||
4042 | * multiplexing powersave, ie. can turn off all but one chain | 4136 | * multiplexing powersave, ie. can turn off all but one chain |
4043 | * and then wake the rest up as required after, for example, | 4137 | * and then wake the rest up as required after, for example, |
4044 | * rts/cts handshake. | 4138 | * rts/cts handshake. |
4139 | * @NL80211_FEATURE_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM | ||
4140 | * TSPEC sessions (TID aka TSID 0-7) with the %NL80211_CMD_ADD_TX_TS | ||
4141 | * command. Standard IEEE 802.11 TSPEC setup is not yet supported, it | ||
4142 | * needs to be able to handle Block-Ack agreements and other things. | ||
4143 | * @NL80211_FEATURE_MAC_ON_CREATE: Device supports configuring | ||
4144 | * the vif's MAC address upon creation. | ||
4145 | * See 'macaddr' field in the vif_params (cfg80211.h). | ||
4146 | * @NL80211_FEATURE_TDLS_CHANNEL_SWITCH: Driver supports channel switching when | ||
4147 | * operating as a TDLS peer. | ||
4148 | * @NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR: This device/driver supports using a | ||
4149 | * random MAC address during scan (if the device is unassociated); the | ||
4150 | * %NL80211_SCAN_FLAG_RANDOM_ADDR flag may be set for scans and the MAC | ||
4151 | * address mask/value will be used. | ||
4152 | * @NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR: This device/driver supports | ||
4153 | * using a random MAC address for every scan iteration during scheduled | ||
4154 | * scan (while not associated), the %NL80211_SCAN_FLAG_RANDOM_ADDR may | ||
4155 | * be set for scheduled scan and the MAC address mask/value will be used. | ||
4156 | * @NL80211_FEATURE_ND_RANDOM_MAC_ADDR: This device/driver supports using a | ||
4157 | * random MAC address for every scan iteration during "net detect", i.e. | ||
4158 | * scan in unassociated WoWLAN, the %NL80211_SCAN_FLAG_RANDOM_ADDR may | ||
4159 | * be set for scheduled scan and the MAC address mask/value will be used. | ||
4045 | */ | 4160 | */ |
4046 | enum nl80211_feature_flags { | 4161 | enum nl80211_feature_flags { |
4047 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, | 4162 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, |
@@ -4070,6 +4185,12 @@ enum nl80211_feature_flags { | |||
4070 | NL80211_FEATURE_ACKTO_ESTIMATION = 1 << 23, | 4185 | NL80211_FEATURE_ACKTO_ESTIMATION = 1 << 23, |
4071 | NL80211_FEATURE_STATIC_SMPS = 1 << 24, | 4186 | NL80211_FEATURE_STATIC_SMPS = 1 << 24, |
4072 | NL80211_FEATURE_DYNAMIC_SMPS = 1 << 25, | 4187 | NL80211_FEATURE_DYNAMIC_SMPS = 1 << 25, |
4188 | NL80211_FEATURE_SUPPORTS_WMM_ADMISSION = 1 << 26, | ||
4189 | NL80211_FEATURE_MAC_ON_CREATE = 1 << 27, | ||
4190 | NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28, | ||
4191 | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29, | ||
4192 | NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30, | ||
4193 | NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1 << 31, | ||
4073 | }; | 4194 | }; |
4074 | 4195 | ||
4075 | /** | 4196 | /** |
@@ -4118,11 +4239,21 @@ enum nl80211_connect_failed_reason { | |||
4118 | * dangerous because will destroy stations performance as a lot of frames | 4239 | * dangerous because will destroy stations performance as a lot of frames |
4119 | * will be lost while scanning off-channel, therefore it must be used only | 4240 | * will be lost while scanning off-channel, therefore it must be used only |
4120 | * when really needed | 4241 | * when really needed |
4242 | * @NL80211_SCAN_FLAG_RANDOM_ADDR: use a random MAC address for this scan (or | ||
4243 | * for scheduled scan: a different one for every scan iteration). When the | ||
4244 | * flag is set, depending on device capabilities the @NL80211_ATTR_MAC and | ||
4245 | * @NL80211_ATTR_MAC_MASK attributes may also be given in which case only | ||
4246 | * the masked bits will be preserved from the MAC address and the remainder | ||
4247 | * randomised. If the attributes are not given full randomisation (46 bits, | ||
4248 | * locally administered 1, multicast 0) is assumed. | ||
4249 | * This flag must not be requested when the feature isn't supported, check | ||
4250 | * the nl80211 feature flags for the device. | ||
4121 | */ | 4251 | */ |
4122 | enum nl80211_scan_flags { | 4252 | enum nl80211_scan_flags { |
4123 | NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, | 4253 | NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, |
4124 | NL80211_SCAN_FLAG_FLUSH = 1<<1, | 4254 | NL80211_SCAN_FLAG_FLUSH = 1<<1, |
4125 | NL80211_SCAN_FLAG_AP = 1<<2, | 4255 | NL80211_SCAN_FLAG_AP = 1<<2, |
4256 | NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3, | ||
4126 | }; | 4257 | }; |
4127 | 4258 | ||
4128 | /** | 4259 | /** |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index aeb6a483b3bc..75cc6801a431 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -33,6 +33,13 @@ config MAC80211_RC_MINSTREL_HT | |||
33 | ---help--- | 33 | ---help--- |
34 | This option enables the 'minstrel_ht' TX rate control algorithm | 34 | This option enables the 'minstrel_ht' TX rate control algorithm |
35 | 35 | ||
36 | config MAC80211_RC_MINSTREL_VHT | ||
37 | bool "Minstrel 802.11ac support" if EXPERT | ||
38 | depends on MAC80211_RC_MINSTREL_HT | ||
39 | default n | ||
40 | ---help--- | ||
41 | This option enables VHT in the 'minstrel_ht' TX rate control algorithm | ||
42 | |||
36 | choice | 43 | choice |
37 | prompt "Default rate control algorithm" | 44 | prompt "Default rate control algorithm" |
38 | depends on MAC80211_HAS_RC | 45 | depends on MAC80211_HAS_RC |
@@ -169,6 +176,17 @@ config MAC80211_HT_DEBUG | |||
169 | 176 | ||
170 | Do not select this option. | 177 | Do not select this option. |
171 | 178 | ||
179 | config MAC80211_OCB_DEBUG | ||
180 | bool "Verbose OCB debugging" | ||
181 | depends on MAC80211_DEBUG_MENU | ||
182 | ---help--- | ||
183 | Selecting this option causes mac80211 to print out | ||
184 | very verbose OCB debugging messages. It should not | ||
185 | be selected on production systems as those messages | ||
186 | are remotely triggerable. | ||
187 | |||
188 | Do not select this option. | ||
189 | |||
172 | config MAC80211_IBSS_DEBUG | 190 | config MAC80211_IBSS_DEBUG |
173 | bool "Verbose IBSS debugging" | 191 | bool "Verbose IBSS debugging" |
174 | depends on MAC80211_DEBUG_MENU | 192 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 7273d2796dd1..e53671b1105e 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -27,7 +27,8 @@ mac80211-y := \ | |||
27 | event.o \ | 27 | event.o \ |
28 | chan.o \ | 28 | chan.o \ |
29 | trace.o mlme.o \ | 29 | trace.o mlme.o \ |
30 | tdls.o | 30 | tdls.o \ |
31 | ocb.o | ||
31 | 32 | ||
32 | mac80211-$(CONFIG_MAC80211_LEDS) += led.o | 33 | mac80211-$(CONFIG_MAC80211_LEDS) += led.o |
33 | mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ | 34 | mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ |
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index ec24378caaaf..09d9caaec591 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c | |||
@@ -53,6 +53,9 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, | |||
53 | __aligned(__alignof__(struct aead_request)); | 53 | __aligned(__alignof__(struct aead_request)); |
54 | struct aead_request *aead_req = (void *) aead_req_data; | 54 | struct aead_request *aead_req = (void *) aead_req_data; |
55 | 55 | ||
56 | if (data_len == 0) | ||
57 | return -EINVAL; | ||
58 | |||
56 | memset(aead_req, 0, sizeof(aead_req_data)); | 59 | memset(aead_req, 0, sizeof(aead_req_data)); |
57 | 60 | ||
58 | sg_init_one(&pt, data, data_len); | 61 | sg_init_one(&pt, data, data_len); |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index d6986f3aa5c4..a360c15cc978 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -149,11 +149,6 @@ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | |||
149 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | 149 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); |
150 | } | 150 | } |
151 | 151 | ||
152 | static inline int ieee80211_ac_from_tid(int tid) | ||
153 | { | ||
154 | return ieee802_1d_to_ac[tid & 7]; | ||
155 | } | ||
156 | |||
157 | /* | 152 | /* |
158 | * When multiple aggregation sessions on multiple stations | 153 | * When multiple aggregation sessions on multiple stations |
159 | * are being created/destroyed simultaneously, we need to | 154 | * are being created/destroyed simultaneously, we need to |
@@ -514,6 +509,10 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
514 | struct tid_ampdu_tx *tid_tx; | 509 | struct tid_ampdu_tx *tid_tx; |
515 | int ret = 0; | 510 | int ret = 0; |
516 | 511 | ||
512 | if (WARN(sta->reserved_tid == tid, | ||
513 | "Requested to start BA session on reserved tid=%d", tid)) | ||
514 | return -EINVAL; | ||
515 | |||
517 | trace_api_start_tx_ba_session(pubsta, tid); | 516 | trace_api_start_tx_ba_session(pubsta, tid); |
518 | 517 | ||
519 | if (WARN_ON_ONCE(!local->ops->ampdu_action)) | 518 | if (WARN_ON_ONCE(!local->ops->ampdu_action)) |
@@ -770,6 +769,9 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
770 | goto unlock; | 769 | goto unlock; |
771 | } | 770 | } |
772 | 771 | ||
772 | WARN(sta->reserved_tid == tid, | ||
773 | "Requested to stop BA session on reserved tid=%d", tid); | ||
774 | |||
773 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | 775 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { |
774 | /* already in progress stopping it */ | 776 | /* already in progress stopping it */ |
775 | ret = 0; | 777 | ret = 0; |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fb6a1502b6df..e75d5c53e97b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "cfg.h" | 20 | #include "cfg.h" |
21 | #include "rate.h" | 21 | #include "rate.h" |
22 | #include "mesh.h" | 22 | #include "mesh.h" |
23 | #include "wme.h" | ||
23 | 24 | ||
24 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, | 25 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, |
25 | const char *name, | 26 | const char *name, |
@@ -190,7 +191,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
190 | * receive the key. When wpa_supplicant has roamed | 191 | * receive the key. When wpa_supplicant has roamed |
191 | * using FT, it attempts to set the key before | 192 | * using FT, it attempts to set the key before |
192 | * association has completed, this rejects that attempt | 193 | * association has completed, this rejects that attempt |
193 | * so it will set the key again after assocation. | 194 | * so it will set the key again after association. |
194 | * | 195 | * |
195 | * TODO: accept the key if we have a station entry and | 196 | * TODO: accept the key if we have a station entry and |
196 | * add it to the device after the station. | 197 | * add it to the device after the station. |
@@ -229,6 +230,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
229 | case NUM_NL80211_IFTYPES: | 230 | case NUM_NL80211_IFTYPES: |
230 | case NL80211_IFTYPE_P2P_CLIENT: | 231 | case NL80211_IFTYPE_P2P_CLIENT: |
231 | case NL80211_IFTYPE_P2P_GO: | 232 | case NL80211_IFTYPE_P2P_GO: |
233 | case NL80211_IFTYPE_OCB: | ||
232 | /* shouldn't happen */ | 234 | /* shouldn't happen */ |
233 | WARN_ON_ONCE(1); | 235 | WARN_ON_ONCE(1); |
234 | break; | 236 | break; |
@@ -1040,6 +1042,13 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1040 | clear_sta_flag(sta, WLAN_STA_TDLS_PEER); | 1042 | clear_sta_flag(sta, WLAN_STA_TDLS_PEER); |
1041 | } | 1043 | } |
1042 | 1044 | ||
1045 | /* mark TDLS channel switch support, if the AP allows it */ | ||
1046 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && | ||
1047 | !sdata->u.mgd.tdls_chan_switch_prohibited && | ||
1048 | params->ext_capab_len >= 4 && | ||
1049 | params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) | ||
1050 | set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH); | ||
1051 | |||
1043 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) { | 1052 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) { |
1044 | sta->sta.uapsd_queues = params->uapsd_queues; | 1053 | sta->sta.uapsd_queues = params->uapsd_queues; |
1045 | sta->sta.max_sp = params->max_sp; | 1054 | sta->sta.max_sp = params->max_sp; |
@@ -1225,14 +1234,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
1225 | } | 1234 | } |
1226 | 1235 | ||
1227 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | 1236 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, |
1228 | const u8 *mac) | 1237 | struct station_del_parameters *params) |
1229 | { | 1238 | { |
1230 | struct ieee80211_sub_if_data *sdata; | 1239 | struct ieee80211_sub_if_data *sdata; |
1231 | 1240 | ||
1232 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1241 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1233 | 1242 | ||
1234 | if (mac) | 1243 | if (params->mac) |
1235 | return sta_info_destroy_addr_bss(sdata, mac); | 1244 | return sta_info_destroy_addr_bss(sdata, params->mac); |
1236 | 1245 | ||
1237 | sta_info_flush(sdata); | 1246 | sta_info_flush(sdata); |
1238 | return 0; | 1247 | return 0; |
@@ -1516,6 +1525,57 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
1516 | return 0; | 1525 | return 0; |
1517 | } | 1526 | } |
1518 | 1527 | ||
1528 | static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp, | ||
1529 | struct mpath_info *pinfo) | ||
1530 | { | ||
1531 | memset(pinfo, 0, sizeof(*pinfo)); | ||
1532 | memcpy(mpp, mpath->mpp, ETH_ALEN); | ||
1533 | |||
1534 | pinfo->generation = mpp_paths_generation; | ||
1535 | } | ||
1536 | |||
1537 | static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev, | ||
1538 | u8 *dst, u8 *mpp, struct mpath_info *pinfo) | ||
1539 | |||
1540 | { | ||
1541 | struct ieee80211_sub_if_data *sdata; | ||
1542 | struct mesh_path *mpath; | ||
1543 | |||
1544 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1545 | |||
1546 | rcu_read_lock(); | ||
1547 | mpath = mpp_path_lookup(sdata, dst); | ||
1548 | if (!mpath) { | ||
1549 | rcu_read_unlock(); | ||
1550 | return -ENOENT; | ||
1551 | } | ||
1552 | memcpy(dst, mpath->dst, ETH_ALEN); | ||
1553 | mpp_set_pinfo(mpath, mpp, pinfo); | ||
1554 | rcu_read_unlock(); | ||
1555 | return 0; | ||
1556 | } | ||
1557 | |||
1558 | static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev, | ||
1559 | int idx, u8 *dst, u8 *mpp, | ||
1560 | struct mpath_info *pinfo) | ||
1561 | { | ||
1562 | struct ieee80211_sub_if_data *sdata; | ||
1563 | struct mesh_path *mpath; | ||
1564 | |||
1565 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1566 | |||
1567 | rcu_read_lock(); | ||
1568 | mpath = mpp_path_lookup_by_idx(sdata, idx); | ||
1569 | if (!mpath) { | ||
1570 | rcu_read_unlock(); | ||
1571 | return -ENOENT; | ||
1572 | } | ||
1573 | memcpy(dst, mpath->dst, ETH_ALEN); | ||
1574 | mpp_set_pinfo(mpath, mpp, pinfo); | ||
1575 | rcu_read_unlock(); | ||
1576 | return 0; | ||
1577 | } | ||
1578 | |||
1519 | static int ieee80211_get_mesh_config(struct wiphy *wiphy, | 1579 | static int ieee80211_get_mesh_config(struct wiphy *wiphy, |
1520 | struct net_device *dev, | 1580 | struct net_device *dev, |
1521 | struct mesh_config *conf) | 1581 | struct mesh_config *conf) |
@@ -1966,6 +2026,17 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | |||
1966 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); | 2026 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); |
1967 | } | 2027 | } |
1968 | 2028 | ||
2029 | static int ieee80211_join_ocb(struct wiphy *wiphy, struct net_device *dev, | ||
2030 | struct ocb_setup *setup) | ||
2031 | { | ||
2032 | return ieee80211_ocb_join(IEEE80211_DEV_TO_SUB_IF(dev), setup); | ||
2033 | } | ||
2034 | |||
2035 | static int ieee80211_leave_ocb(struct wiphy *wiphy, struct net_device *dev) | ||
2036 | { | ||
2037 | return ieee80211_ocb_leave(IEEE80211_DEV_TO_SUB_IF(dev)); | ||
2038 | } | ||
2039 | |||
1969 | static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, | 2040 | static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, |
1970 | int rate[IEEE80211_NUM_BANDS]) | 2041 | int rate[IEEE80211_NUM_BANDS]) |
1971 | { | 2042 | { |
@@ -2081,6 +2152,9 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, | |||
2081 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2152 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2082 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 2153 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
2083 | 2154 | ||
2155 | if (local->ops->get_txpower) | ||
2156 | return drv_get_txpower(local, sdata, dbm); | ||
2157 | |||
2084 | if (!local->use_chanctx) | 2158 | if (!local->use_chanctx) |
2085 | *dbm = local->hw.conf.power_level; | 2159 | *dbm = local->hw.conf.power_level; |
2086 | else | 2160 | else |
@@ -2850,11 +2924,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
2850 | if (sdata->reserved_ready) | 2924 | if (sdata->reserved_ready) |
2851 | return 0; | 2925 | return 0; |
2852 | 2926 | ||
2853 | err = ieee80211_vif_use_reserved_context(sdata); | 2927 | return ieee80211_vif_use_reserved_context(sdata); |
2854 | if (err) | ||
2855 | return err; | ||
2856 | |||
2857 | return 0; | ||
2858 | } | 2928 | } |
2859 | 2929 | ||
2860 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, | 2930 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, |
@@ -2868,7 +2938,6 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
2868 | return err; | 2938 | return err; |
2869 | 2939 | ||
2870 | ieee80211_bss_info_change_notify(sdata, changed); | 2940 | ieee80211_bss_info_change_notify(sdata, changed); |
2871 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); | ||
2872 | 2941 | ||
2873 | if (sdata->csa_block_tx) { | 2942 | if (sdata->csa_block_tx) { |
2874 | ieee80211_wake_vif_queues(local, sdata, | 2943 | ieee80211_wake_vif_queues(local, sdata, |
@@ -2876,6 +2945,12 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
2876 | sdata->csa_block_tx = false; | 2945 | sdata->csa_block_tx = false; |
2877 | } | 2946 | } |
2878 | 2947 | ||
2948 | err = drv_post_channel_switch(sdata); | ||
2949 | if (err) | ||
2950 | return err; | ||
2951 | |||
2952 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); | ||
2953 | |||
2879 | return 0; | 2954 | return 0; |
2880 | } | 2955 | } |
2881 | 2956 | ||
@@ -3053,9 +3128,11 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3053 | { | 3128 | { |
3054 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 3129 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
3055 | struct ieee80211_local *local = sdata->local; | 3130 | struct ieee80211_local *local = sdata->local; |
3131 | struct ieee80211_channel_switch ch_switch; | ||
3056 | struct ieee80211_chanctx_conf *conf; | 3132 | struct ieee80211_chanctx_conf *conf; |
3057 | struct ieee80211_chanctx *chanctx; | 3133 | struct ieee80211_chanctx *chanctx; |
3058 | int err, changed = 0; | 3134 | u32 changed = 0; |
3135 | int err; | ||
3059 | 3136 | ||
3060 | sdata_assert_lock(sdata); | 3137 | sdata_assert_lock(sdata); |
3061 | lockdep_assert_held(&local->mtx); | 3138 | lockdep_assert_held(&local->mtx); |
@@ -3088,6 +3165,16 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3088 | goto out; | 3165 | goto out; |
3089 | } | 3166 | } |
3090 | 3167 | ||
3168 | ch_switch.timestamp = 0; | ||
3169 | ch_switch.device_timestamp = 0; | ||
3170 | ch_switch.block_tx = params->block_tx; | ||
3171 | ch_switch.chandef = params->chandef; | ||
3172 | ch_switch.count = params->count; | ||
3173 | |||
3174 | err = drv_pre_channel_switch(sdata, &ch_switch); | ||
3175 | if (err) | ||
3176 | goto out; | ||
3177 | |||
3091 | err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, | 3178 | err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, |
3092 | chanctx->mode, | 3179 | chanctx->mode, |
3093 | params->radar_required); | 3180 | params->radar_required); |
@@ -3115,6 +3202,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3115 | ieee80211_stop_vif_queues(local, sdata, | 3202 | ieee80211_stop_vif_queues(local, sdata, |
3116 | IEEE80211_QUEUE_STOP_REASON_CSA); | 3203 | IEEE80211_QUEUE_STOP_REASON_CSA); |
3117 | 3204 | ||
3205 | cfg80211_ch_switch_started_notify(sdata->dev, &sdata->csa_chandef, | ||
3206 | params->count); | ||
3207 | |||
3118 | if (changed) { | 3208 | if (changed) { |
3119 | ieee80211_bss_info_change_notify(sdata, changed); | 3209 | ieee80211_bss_info_change_notify(sdata, changed); |
3120 | drv_channel_switch_beacon(sdata, ¶ms->chandef); | 3210 | drv_channel_switch_beacon(sdata, ¶ms->chandef); |
@@ -3431,6 +3521,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
3431 | 3521 | ||
3432 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | | 3522 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | |
3433 | IEEE80211_TX_INTFL_NL80211_FRAME_TX; | 3523 | IEEE80211_TX_INTFL_NL80211_FRAME_TX; |
3524 | info->band = band; | ||
3434 | 3525 | ||
3435 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); | 3526 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); |
3436 | skb->priority = 7; | 3527 | skb->priority = 7; |
@@ -3438,7 +3529,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
3438 | nullfunc->qos_ctrl = cpu_to_le16(7); | 3529 | nullfunc->qos_ctrl = cpu_to_le16(7); |
3439 | 3530 | ||
3440 | local_bh_disable(); | 3531 | local_bh_disable(); |
3441 | ieee80211_xmit(sdata, skb, band); | 3532 | ieee80211_xmit(sdata, skb); |
3442 | local_bh_enable(); | 3533 | local_bh_enable(); |
3443 | rcu_read_unlock(); | 3534 | rcu_read_unlock(); |
3444 | 3535 | ||
@@ -3458,7 +3549,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, | |||
3458 | rcu_read_lock(); | 3549 | rcu_read_lock(); |
3459 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 3550 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
3460 | if (chanctx_conf) { | 3551 | if (chanctx_conf) { |
3461 | *chandef = chanctx_conf->def; | 3552 | *chandef = sdata->vif.bss_conf.chandef; |
3462 | ret = 0; | 3553 | ret = 0; |
3463 | } else if (local->open_count > 0 && | 3554 | } else if (local->open_count > 0 && |
3464 | local->open_count == local->monitors && | 3555 | local->open_count == local->monitors && |
@@ -3521,6 +3612,76 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, | |||
3521 | return ret; | 3612 | return ret; |
3522 | } | 3613 | } |
3523 | 3614 | ||
3615 | static int ieee80211_add_tx_ts(struct wiphy *wiphy, struct net_device *dev, | ||
3616 | u8 tsid, const u8 *peer, u8 up, | ||
3617 | u16 admitted_time) | ||
3618 | { | ||
3619 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3620 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3621 | int ac = ieee802_1d_to_ac[up]; | ||
3622 | |||
3623 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
3624 | return -EOPNOTSUPP; | ||
3625 | |||
3626 | if (!(sdata->wmm_acm & BIT(up))) | ||
3627 | return -EINVAL; | ||
3628 | |||
3629 | if (ifmgd->tx_tspec[ac].admitted_time) | ||
3630 | return -EBUSY; | ||
3631 | |||
3632 | if (admitted_time) { | ||
3633 | ifmgd->tx_tspec[ac].admitted_time = 32 * admitted_time; | ||
3634 | ifmgd->tx_tspec[ac].tsid = tsid; | ||
3635 | ifmgd->tx_tspec[ac].up = up; | ||
3636 | } | ||
3637 | |||
3638 | return 0; | ||
3639 | } | ||
3640 | |||
3641 | static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev, | ||
3642 | u8 tsid, const u8 *peer) | ||
3643 | { | ||
3644 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3645 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3646 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
3647 | int ac; | ||
3648 | |||
3649 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
3650 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
3651 | |||
3652 | /* skip unused entries */ | ||
3653 | if (!tx_tspec->admitted_time) | ||
3654 | continue; | ||
3655 | |||
3656 | if (tx_tspec->tsid != tsid) | ||
3657 | continue; | ||
3658 | |||
3659 | /* due to this new packets will be reassigned to non-ACM ACs */ | ||
3660 | tx_tspec->up = -1; | ||
3661 | |||
3662 | /* Make sure that all packets have been sent to avoid to | ||
3663 | * restore the QoS params on packets that are still on the | ||
3664 | * queues. | ||
3665 | */ | ||
3666 | synchronize_net(); | ||
3667 | ieee80211_flush_queues(local, sdata); | ||
3668 | |||
3669 | /* restore the normal QoS parameters | ||
3670 | * (unconditionally to avoid races) | ||
3671 | */ | ||
3672 | tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
3673 | tx_tspec->downgraded = false; | ||
3674 | ieee80211_sta_handle_tspec_ac_params(sdata); | ||
3675 | |||
3676 | /* finally clear all the data */ | ||
3677 | memset(tx_tspec, 0, sizeof(*tx_tspec)); | ||
3678 | |||
3679 | return 0; | ||
3680 | } | ||
3681 | |||
3682 | return -ENOENT; | ||
3683 | } | ||
3684 | |||
3524 | const struct cfg80211_ops mac80211_config_ops = { | 3685 | const struct cfg80211_ops mac80211_config_ops = { |
3525 | .add_virtual_intf = ieee80211_add_iface, | 3686 | .add_virtual_intf = ieee80211_add_iface, |
3526 | .del_virtual_intf = ieee80211_del_iface, | 3687 | .del_virtual_intf = ieee80211_del_iface, |
@@ -3547,11 +3708,15 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3547 | .change_mpath = ieee80211_change_mpath, | 3708 | .change_mpath = ieee80211_change_mpath, |
3548 | .get_mpath = ieee80211_get_mpath, | 3709 | .get_mpath = ieee80211_get_mpath, |
3549 | .dump_mpath = ieee80211_dump_mpath, | 3710 | .dump_mpath = ieee80211_dump_mpath, |
3711 | .get_mpp = ieee80211_get_mpp, | ||
3712 | .dump_mpp = ieee80211_dump_mpp, | ||
3550 | .update_mesh_config = ieee80211_update_mesh_config, | 3713 | .update_mesh_config = ieee80211_update_mesh_config, |
3551 | .get_mesh_config = ieee80211_get_mesh_config, | 3714 | .get_mesh_config = ieee80211_get_mesh_config, |
3552 | .join_mesh = ieee80211_join_mesh, | 3715 | .join_mesh = ieee80211_join_mesh, |
3553 | .leave_mesh = ieee80211_leave_mesh, | 3716 | .leave_mesh = ieee80211_leave_mesh, |
3554 | #endif | 3717 | #endif |
3718 | .join_ocb = ieee80211_join_ocb, | ||
3719 | .leave_ocb = ieee80211_leave_ocb, | ||
3555 | .change_bss = ieee80211_change_bss, | 3720 | .change_bss = ieee80211_change_bss, |
3556 | .set_txq_params = ieee80211_set_txq_params, | 3721 | .set_txq_params = ieee80211_set_txq_params, |
3557 | .set_monitor_channel = ieee80211_set_monitor_channel, | 3722 | .set_monitor_channel = ieee80211_set_monitor_channel, |
@@ -3587,6 +3752,8 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3587 | .set_rekey_data = ieee80211_set_rekey_data, | 3752 | .set_rekey_data = ieee80211_set_rekey_data, |
3588 | .tdls_oper = ieee80211_tdls_oper, | 3753 | .tdls_oper = ieee80211_tdls_oper, |
3589 | .tdls_mgmt = ieee80211_tdls_mgmt, | 3754 | .tdls_mgmt = ieee80211_tdls_mgmt, |
3755 | .tdls_channel_switch = ieee80211_tdls_channel_switch, | ||
3756 | .tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch, | ||
3590 | .probe_client = ieee80211_probe_client, | 3757 | .probe_client = ieee80211_probe_client, |
3591 | .set_noack_map = ieee80211_set_noack_map, | 3758 | .set_noack_map = ieee80211_set_noack_map, |
3592 | #ifdef CONFIG_PM | 3759 | #ifdef CONFIG_PM |
@@ -3597,4 +3764,6 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3597 | .channel_switch = ieee80211_channel_switch, | 3764 | .channel_switch = ieee80211_channel_switch, |
3598 | .set_qos_map = ieee80211_set_qos_map, | 3765 | .set_qos_map = ieee80211_set_qos_map, |
3599 | .set_ap_chanwidth = ieee80211_set_ap_chanwidth, | 3766 | .set_ap_chanwidth = ieee80211_set_ap_chanwidth, |
3767 | .add_tx_ts = ieee80211_add_tx_ts, | ||
3768 | .del_tx_ts = ieee80211_del_tx_ts, | ||
3600 | }; | 3769 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 4c74e8da64b9..5d6dae9e4aac 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -270,6 +270,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, | |||
270 | case NL80211_IFTYPE_ADHOC: | 270 | case NL80211_IFTYPE_ADHOC: |
271 | case NL80211_IFTYPE_WDS: | 271 | case NL80211_IFTYPE_WDS: |
272 | case NL80211_IFTYPE_MESH_POINT: | 272 | case NL80211_IFTYPE_MESH_POINT: |
273 | case NL80211_IFTYPE_OCB: | ||
273 | width = vif->bss_conf.chandef.width; | 274 | width = vif->bss_conf.chandef.width; |
274 | break; | 275 | break; |
275 | case NL80211_IFTYPE_UNSPECIFIED: | 276 | case NL80211_IFTYPE_UNSPECIFIED: |
@@ -674,6 +675,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | |||
674 | case NL80211_IFTYPE_ADHOC: | 675 | case NL80211_IFTYPE_ADHOC: |
675 | case NL80211_IFTYPE_WDS: | 676 | case NL80211_IFTYPE_WDS: |
676 | case NL80211_IFTYPE_MESH_POINT: | 677 | case NL80211_IFTYPE_MESH_POINT: |
678 | case NL80211_IFTYPE_OCB: | ||
677 | break; | 679 | break; |
678 | default: | 680 | default: |
679 | WARN_ON_ONCE(1); | 681 | WARN_ON_ONCE(1); |
@@ -909,6 +911,7 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) | |||
909 | case NL80211_IFTYPE_ADHOC: | 911 | case NL80211_IFTYPE_ADHOC: |
910 | case NL80211_IFTYPE_AP: | 912 | case NL80211_IFTYPE_AP: |
911 | case NL80211_IFTYPE_MESH_POINT: | 913 | case NL80211_IFTYPE_MESH_POINT: |
914 | case NL80211_IFTYPE_OCB: | ||
912 | ieee80211_queue_work(&sdata->local->hw, | 915 | ieee80211_queue_work(&sdata->local->hw, |
913 | &sdata->csa_finalize_work); | 916 | &sdata->csa_finalize_work); |
914 | break; | 917 | break; |
@@ -929,6 +932,21 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) | |||
929 | } | 932 | } |
930 | } | 933 | } |
931 | 934 | ||
935 | static void | ||
936 | ieee80211_vif_update_chandef(struct ieee80211_sub_if_data *sdata, | ||
937 | const struct cfg80211_chan_def *chandef) | ||
938 | { | ||
939 | struct ieee80211_sub_if_data *vlan; | ||
940 | |||
941 | sdata->vif.bss_conf.chandef = *chandef; | ||
942 | |||
943 | if (sdata->vif.type != NL80211_IFTYPE_AP) | ||
944 | return; | ||
945 | |||
946 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
947 | vlan->vif.bss_conf.chandef = *chandef; | ||
948 | } | ||
949 | |||
932 | static int | 950 | static int |
933 | ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) | 951 | ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) |
934 | { | 952 | { |
@@ -991,7 +1009,7 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) | |||
991 | if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width) | 1009 | if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width) |
992 | changed = BSS_CHANGED_BANDWIDTH; | 1010 | changed = BSS_CHANGED_BANDWIDTH; |
993 | 1011 | ||
994 | sdata->vif.bss_conf.chandef = sdata->reserved_chandef; | 1012 | ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef); |
995 | 1013 | ||
996 | if (changed) | 1014 | if (changed) |
997 | ieee80211_bss_info_change_notify(sdata, changed); | 1015 | ieee80211_bss_info_change_notify(sdata, changed); |
@@ -1333,7 +1351,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) | |||
1333 | sdata->reserved_chandef.width) | 1351 | sdata->reserved_chandef.width) |
1334 | changed = BSS_CHANGED_BANDWIDTH; | 1352 | changed = BSS_CHANGED_BANDWIDTH; |
1335 | 1353 | ||
1336 | sdata->vif.bss_conf.chandef = sdata->reserved_chandef; | 1354 | ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef); |
1337 | if (changed) | 1355 | if (changed) |
1338 | ieee80211_bss_info_change_notify(sdata, | 1356 | ieee80211_bss_info_change_notify(sdata, |
1339 | changed); | 1357 | changed); |
@@ -1504,7 +1522,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
1504 | goto out; | 1522 | goto out; |
1505 | } | 1523 | } |
1506 | 1524 | ||
1507 | sdata->vif.bss_conf.chandef = *chandef; | 1525 | ieee80211_vif_update_chandef(sdata, chandef); |
1508 | 1526 | ||
1509 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); | 1527 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); |
1510 | if (ret) { | 1528 | if (ret) { |
@@ -1634,7 +1652,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | |||
1634 | } | 1652 | } |
1635 | break; | 1653 | break; |
1636 | case IEEE80211_CHANCTX_WILL_BE_REPLACED: | 1654 | case IEEE80211_CHANCTX_WILL_BE_REPLACED: |
1637 | /* TODO: Perhaps the bandwith change could be treated as a | 1655 | /* TODO: Perhaps the bandwidth change could be treated as a |
1638 | * reservation itself? */ | 1656 | * reservation itself? */ |
1639 | ret = -EBUSY; | 1657 | ret = -EBUSY; |
1640 | goto out; | 1658 | goto out; |
@@ -1646,7 +1664,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | |||
1646 | break; | 1664 | break; |
1647 | } | 1665 | } |
1648 | 1666 | ||
1649 | sdata->vif.bss_conf.chandef = *chandef; | 1667 | ieee80211_vif_update_chandef(sdata, chandef); |
1650 | 1668 | ||
1651 | ieee80211_recalc_chanctx_chantype(local, ctx); | 1669 | ieee80211_recalc_chanctx_chantype(local, ctx); |
1652 | 1670 | ||
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h index 493d68061f0c..1956b3115dd5 100644 --- a/net/mac80211/debug.h +++ b/net/mac80211/debug.h | |||
@@ -2,6 +2,12 @@ | |||
2 | #define __MAC80211_DEBUG_H | 2 | #define __MAC80211_DEBUG_H |
3 | #include <net/cfg80211.h> | 3 | #include <net/cfg80211.h> |
4 | 4 | ||
5 | #ifdef CONFIG_MAC80211_OCB_DEBUG | ||
6 | #define MAC80211_OCB_DEBUG 1 | ||
7 | #else | ||
8 | #define MAC80211_OCB_DEBUG 0 | ||
9 | #endif | ||
10 | |||
5 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 11 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
6 | #define MAC80211_IBSS_DEBUG 1 | 12 | #define MAC80211_IBSS_DEBUG 1 |
7 | #else | 13 | #else |
@@ -131,6 +137,10 @@ do { \ | |||
131 | _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \ | 137 | _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \ |
132 | sdata, fmt, ##__VA_ARGS__) | 138 | sdata, fmt, ##__VA_ARGS__) |
133 | 139 | ||
140 | #define ocb_dbg(sdata, fmt, ...) \ | ||
141 | _sdata_dbg(MAC80211_OCB_DEBUG, \ | ||
142 | sdata, fmt, ##__VA_ARGS__) | ||
143 | |||
134 | #define ibss_dbg(sdata, fmt, ...) \ | 144 | #define ibss_dbg(sdata, fmt, ...) \ |
135 | _sdata_dbg(MAC80211_IBSS_DEBUG, \ | 145 | _sdata_dbg(MAC80211_IBSS_DEBUG, \ |
136 | sdata, fmt, ##__VA_ARGS__) | 146 | sdata, fmt, ##__VA_ARGS__) |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 1521cabad3d6..5523b94c7c90 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -300,10 +300,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
300 | 300 | ||
301 | lockdep_assert_held(&sdata->local->key_mtx); | 301 | lockdep_assert_held(&sdata->local->key_mtx); |
302 | 302 | ||
303 | if (sdata->debugfs.default_unicast_key) { | 303 | debugfs_remove(sdata->debugfs.default_unicast_key); |
304 | debugfs_remove(sdata->debugfs.default_unicast_key); | 304 | sdata->debugfs.default_unicast_key = NULL; |
305 | sdata->debugfs.default_unicast_key = NULL; | ||
306 | } | ||
307 | 305 | ||
308 | if (sdata->default_unicast_key) { | 306 | if (sdata->default_unicast_key) { |
309 | key = key_mtx_dereference(sdata->local, | 307 | key = key_mtx_dereference(sdata->local, |
@@ -314,10 +312,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
314 | sdata->vif.debugfs_dir, buf); | 312 | sdata->vif.debugfs_dir, buf); |
315 | } | 313 | } |
316 | 314 | ||
317 | if (sdata->debugfs.default_multicast_key) { | 315 | debugfs_remove(sdata->debugfs.default_multicast_key); |
318 | debugfs_remove(sdata->debugfs.default_multicast_key); | 316 | sdata->debugfs.default_multicast_key = NULL; |
319 | sdata->debugfs.default_multicast_key = NULL; | ||
320 | } | ||
321 | 317 | ||
322 | if (sdata->default_multicast_key) { | 318 | if (sdata->default_multicast_key) { |
323 | key = key_mtx_dereference(sdata->local, | 319 | key = key_mtx_dereference(sdata->local, |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index bafe48916229..94c70091bbd7 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -74,7 +74,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
74 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" | 74 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" |
75 | 75 | ||
76 | int res = scnprintf(buf, sizeof(buf), | 76 | int res = scnprintf(buf, sizeof(buf), |
77 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", | 77 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", |
78 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), | 78 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), |
79 | TEST(PS_DRIVER), TEST(AUTHORIZED), | 79 | TEST(PS_DRIVER), TEST(AUTHORIZED), |
80 | TEST(SHORT_PREAMBLE), | 80 | TEST(SHORT_PREAMBLE), |
@@ -82,10 +82,11 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
82 | TEST(WDS), TEST(CLEAR_PS_FILT), | 82 | TEST(WDS), TEST(CLEAR_PS_FILT), |
83 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), | 83 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), |
84 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), | 84 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), |
85 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), | 85 | TEST(TDLS_PEER_AUTH), TEST(TDLS_INITIATOR), |
86 | TEST(INSERTED), TEST(RATE_CONTROL), | 86 | TEST(TDLS_CHAN_SWITCH), TEST(TDLS_OFF_CHANNEL), |
87 | TEST(TOFFSET_KNOWN), TEST(MPSP_OWNER), | 87 | TEST(4ADDR_EVENT), TEST(INSERTED), |
88 | TEST(MPSP_RECIPIENT)); | 88 | TEST(RATE_CONTROL), TEST(TOFFSET_KNOWN), |
89 | TEST(MPSP_OWNER), TEST(MPSP_RECIPIENT)); | ||
89 | #undef TEST | 90 | #undef TEST |
90 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 91 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
91 | } | 92 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 196d48c68134..2ebc9ead9695 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -214,7 +214,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
214 | BSS_CHANGED_BEACON_ENABLED) && | 214 | BSS_CHANGED_BEACON_ENABLED) && |
215 | sdata->vif.type != NL80211_IFTYPE_AP && | 215 | sdata->vif.type != NL80211_IFTYPE_AP && |
216 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 216 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
217 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) | 217 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && |
218 | sdata->vif.type != NL80211_IFTYPE_OCB)) | ||
218 | return; | 219 | return; |
219 | 220 | ||
220 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || | 221 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || |
@@ -379,23 +380,26 @@ static inline int drv_sched_scan_stop(struct ieee80211_local *local, | |||
379 | return ret; | 380 | return ret; |
380 | } | 381 | } |
381 | 382 | ||
382 | static inline void drv_sw_scan_start(struct ieee80211_local *local) | 383 | static inline void drv_sw_scan_start(struct ieee80211_local *local, |
384 | struct ieee80211_sub_if_data *sdata, | ||
385 | const u8 *mac_addr) | ||
383 | { | 386 | { |
384 | might_sleep(); | 387 | might_sleep(); |
385 | 388 | ||
386 | trace_drv_sw_scan_start(local); | 389 | trace_drv_sw_scan_start(local, sdata, mac_addr); |
387 | if (local->ops->sw_scan_start) | 390 | if (local->ops->sw_scan_start) |
388 | local->ops->sw_scan_start(&local->hw); | 391 | local->ops->sw_scan_start(&local->hw, &sdata->vif, mac_addr); |
389 | trace_drv_return_void(local); | 392 | trace_drv_return_void(local); |
390 | } | 393 | } |
391 | 394 | ||
392 | static inline void drv_sw_scan_complete(struct ieee80211_local *local) | 395 | static inline void drv_sw_scan_complete(struct ieee80211_local *local, |
396 | struct ieee80211_sub_if_data *sdata) | ||
393 | { | 397 | { |
394 | might_sleep(); | 398 | might_sleep(); |
395 | 399 | ||
396 | trace_drv_sw_scan_complete(local); | 400 | trace_drv_sw_scan_complete(local, sdata); |
397 | if (local->ops->sw_scan_complete) | 401 | if (local->ops->sw_scan_complete) |
398 | local->ops->sw_scan_complete(&local->hw); | 402 | local->ops->sw_scan_complete(&local->hw, &sdata->vif); |
399 | trace_drv_return_void(local); | 403 | trace_drv_return_void(local); |
400 | } | 404 | } |
401 | 405 | ||
@@ -620,6 +624,21 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local, | |||
620 | trace_drv_return_void(local); | 624 | trace_drv_return_void(local); |
621 | } | 625 | } |
622 | 626 | ||
627 | static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local, | ||
628 | struct ieee80211_sub_if_data *sdata, | ||
629 | struct ieee80211_sta *sta) | ||
630 | { | ||
631 | sdata = get_bss_sdata(sdata); | ||
632 | if (!check_sdata_in_driver(sdata)) | ||
633 | return; | ||
634 | |||
635 | trace_drv_sta_rate_tbl_update(local, sdata, sta); | ||
636 | if (local->ops->sta_rate_tbl_update) | ||
637 | local->ops->sta_rate_tbl_update(&local->hw, &sdata->vif, sta); | ||
638 | |||
639 | trace_drv_return_void(local); | ||
640 | } | ||
641 | |||
623 | static inline int drv_conf_tx(struct ieee80211_local *local, | 642 | static inline int drv_conf_tx(struct ieee80211_local *local, |
624 | struct ieee80211_sub_if_data *sdata, u16 ac, | 643 | struct ieee80211_sub_if_data *sdata, u16 ac, |
625 | const struct ieee80211_tx_queue_params *params) | 644 | const struct ieee80211_tx_queue_params *params) |
@@ -631,6 +650,12 @@ static inline int drv_conf_tx(struct ieee80211_local *local, | |||
631 | if (!check_sdata_in_driver(sdata)) | 650 | if (!check_sdata_in_driver(sdata)) |
632 | return -EIO; | 651 | return -EIO; |
633 | 652 | ||
653 | if (WARN_ONCE(params->cw_min == 0 || | ||
654 | params->cw_min > params->cw_max, | ||
655 | "%s: invalid CW_min/CW_max: %d/%d\n", | ||
656 | sdata->name, params->cw_min, params->cw_max)) | ||
657 | return -EINVAL; | ||
658 | |||
634 | trace_drv_conf_tx(local, sdata, ac, params); | 659 | trace_drv_conf_tx(local, sdata, ac, params); |
635 | if (local->ops->conf_tx) | 660 | if (local->ops->conf_tx) |
636 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, | 661 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, |
@@ -764,12 +789,13 @@ static inline void drv_flush(struct ieee80211_local *local, | |||
764 | } | 789 | } |
765 | 790 | ||
766 | static inline void drv_channel_switch(struct ieee80211_local *local, | 791 | static inline void drv_channel_switch(struct ieee80211_local *local, |
767 | struct ieee80211_channel_switch *ch_switch) | 792 | struct ieee80211_sub_if_data *sdata, |
793 | struct ieee80211_channel_switch *ch_switch) | ||
768 | { | 794 | { |
769 | might_sleep(); | 795 | might_sleep(); |
770 | 796 | ||
771 | trace_drv_channel_switch(local, ch_switch); | 797 | trace_drv_channel_switch(local, sdata, ch_switch); |
772 | local->ops->channel_switch(&local->hw, ch_switch); | 798 | local->ops->channel_switch(&local->hw, &sdata->vif, ch_switch); |
773 | trace_drv_return_void(local); | 799 | trace_drv_return_void(local); |
774 | } | 800 | } |
775 | 801 | ||
@@ -1144,13 +1170,15 @@ static inline void drv_stop_ap(struct ieee80211_local *local, | |||
1144 | trace_drv_return_void(local); | 1170 | trace_drv_return_void(local); |
1145 | } | 1171 | } |
1146 | 1172 | ||
1147 | static inline void drv_restart_complete(struct ieee80211_local *local) | 1173 | static inline void |
1174 | drv_reconfig_complete(struct ieee80211_local *local, | ||
1175 | enum ieee80211_reconfig_type reconfig_type) | ||
1148 | { | 1176 | { |
1149 | might_sleep(); | 1177 | might_sleep(); |
1150 | 1178 | ||
1151 | trace_drv_restart_complete(local); | 1179 | trace_drv_reconfig_complete(local, reconfig_type); |
1152 | if (local->ops->restart_complete) | 1180 | if (local->ops->reconfig_complete) |
1153 | local->ops->restart_complete(&local->hw); | 1181 | local->ops->reconfig_complete(&local->hw, reconfig_type); |
1154 | trace_drv_return_void(local); | 1182 | trace_drv_return_void(local); |
1155 | } | 1183 | } |
1156 | 1184 | ||
@@ -1196,6 +1224,40 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata, | |||
1196 | } | 1224 | } |
1197 | } | 1225 | } |
1198 | 1226 | ||
1227 | static inline int | ||
1228 | drv_pre_channel_switch(struct ieee80211_sub_if_data *sdata, | ||
1229 | struct ieee80211_channel_switch *ch_switch) | ||
1230 | { | ||
1231 | struct ieee80211_local *local = sdata->local; | ||
1232 | int ret = 0; | ||
1233 | |||
1234 | if (!check_sdata_in_driver(sdata)) | ||
1235 | return -EIO; | ||
1236 | |||
1237 | trace_drv_pre_channel_switch(local, sdata, ch_switch); | ||
1238 | if (local->ops->pre_channel_switch) | ||
1239 | ret = local->ops->pre_channel_switch(&local->hw, &sdata->vif, | ||
1240 | ch_switch); | ||
1241 | trace_drv_return_int(local, ret); | ||
1242 | return ret; | ||
1243 | } | ||
1244 | |||
1245 | static inline int | ||
1246 | drv_post_channel_switch(struct ieee80211_sub_if_data *sdata) | ||
1247 | { | ||
1248 | struct ieee80211_local *local = sdata->local; | ||
1249 | int ret = 0; | ||
1250 | |||
1251 | if (!check_sdata_in_driver(sdata)) | ||
1252 | return -EIO; | ||
1253 | |||
1254 | trace_drv_post_channel_switch(local, sdata); | ||
1255 | if (local->ops->post_channel_switch) | ||
1256 | ret = local->ops->post_channel_switch(&local->hw, &sdata->vif); | ||
1257 | trace_drv_return_int(local, ret); | ||
1258 | return ret; | ||
1259 | } | ||
1260 | |||
1199 | static inline int drv_join_ibss(struct ieee80211_local *local, | 1261 | static inline int drv_join_ibss(struct ieee80211_local *local, |
1200 | struct ieee80211_sub_if_data *sdata) | 1262 | struct ieee80211_sub_if_data *sdata) |
1201 | { | 1263 | { |
@@ -1238,4 +1300,71 @@ static inline u32 drv_get_expected_throughput(struct ieee80211_local *local, | |||
1238 | return ret; | 1300 | return ret; |
1239 | } | 1301 | } |
1240 | 1302 | ||
1303 | static inline int drv_get_txpower(struct ieee80211_local *local, | ||
1304 | struct ieee80211_sub_if_data *sdata, int *dbm) | ||
1305 | { | ||
1306 | int ret; | ||
1307 | |||
1308 | if (!local->ops->get_txpower) | ||
1309 | return -EOPNOTSUPP; | ||
1310 | |||
1311 | ret = local->ops->get_txpower(&local->hw, &sdata->vif, dbm); | ||
1312 | trace_drv_get_txpower(local, sdata, *dbm, ret); | ||
1313 | |||
1314 | return ret; | ||
1315 | } | ||
1316 | |||
1317 | static inline int | ||
1318 | drv_tdls_channel_switch(struct ieee80211_local *local, | ||
1319 | struct ieee80211_sub_if_data *sdata, | ||
1320 | struct ieee80211_sta *sta, u8 oper_class, | ||
1321 | struct cfg80211_chan_def *chandef, | ||
1322 | struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie) | ||
1323 | { | ||
1324 | int ret; | ||
1325 | |||
1326 | might_sleep(); | ||
1327 | if (!check_sdata_in_driver(sdata)) | ||
1328 | return -EIO; | ||
1329 | |||
1330 | if (!local->ops->tdls_channel_switch) | ||
1331 | return -EOPNOTSUPP; | ||
1332 | |||
1333 | trace_drv_tdls_channel_switch(local, sdata, sta, oper_class, chandef); | ||
1334 | ret = local->ops->tdls_channel_switch(&local->hw, &sdata->vif, sta, | ||
1335 | oper_class, chandef, tmpl_skb, | ||
1336 | ch_sw_tm_ie); | ||
1337 | trace_drv_return_int(local, ret); | ||
1338 | return ret; | ||
1339 | } | ||
1340 | |||
1341 | static inline void | ||
1342 | drv_tdls_cancel_channel_switch(struct ieee80211_local *local, | ||
1343 | struct ieee80211_sub_if_data *sdata, | ||
1344 | struct ieee80211_sta *sta) | ||
1345 | { | ||
1346 | might_sleep(); | ||
1347 | if (!check_sdata_in_driver(sdata)) | ||
1348 | return; | ||
1349 | |||
1350 | if (!local->ops->tdls_cancel_channel_switch) | ||
1351 | return; | ||
1352 | |||
1353 | trace_drv_tdls_cancel_channel_switch(local, sdata, sta); | ||
1354 | local->ops->tdls_cancel_channel_switch(&local->hw, &sdata->vif, sta); | ||
1355 | trace_drv_return_void(local); | ||
1356 | } | ||
1357 | |||
1358 | static inline void | ||
1359 | drv_tdls_recv_channel_switch(struct ieee80211_local *local, | ||
1360 | struct ieee80211_sub_if_data *sdata, | ||
1361 | struct ieee80211_tdls_ch_sw_params *params) | ||
1362 | { | ||
1363 | trace_drv_tdls_recv_channel_switch(local, sdata, params); | ||
1364 | if (local->ops->tdls_recv_channel_switch) | ||
1365 | local->ops->tdls_recv_channel_switch(&local->hw, &sdata->vif, | ||
1366 | params); | ||
1367 | trace_drv_return_void(local); | ||
1368 | } | ||
1369 | |||
1241 | #endif /* __MAC80211_DRIVER_OPS */ | 1370 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 56b53571c807..509bc157ce55 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -805,7 +805,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
805 | 805 | ||
806 | memset(¶ms, 0, sizeof(params)); | 806 | memset(¶ms, 0, sizeof(params)); |
807 | memset(&csa_ie, 0, sizeof(csa_ie)); | 807 | memset(&csa_ie, 0, sizeof(csa_ie)); |
808 | err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, | 808 | err = ieee80211_parse_ch_switch_ie(sdata, elems, |
809 | ifibss->chandef.chan->band, | 809 | ifibss->chandef.chan->band, |
810 | sta_flags, ifibss->bssid, &csa_ie); | 810 | sta_flags, ifibss->bssid, &csa_ie); |
811 | /* can't switch to destination channel, fail */ | 811 | /* can't switch to destination channel, fail */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c2aaec4dfcf0..cc6e964d9837 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -131,7 +131,7 @@ enum ieee80211_bss_corrupt_data_flags { | |||
131 | * | 131 | * |
132 | * These are bss flags that are attached to a bss in the | 132 | * These are bss flags that are attached to a bss in the |
133 | * @valid_data field of &struct ieee80211_bss. They show which parts | 133 | * @valid_data field of &struct ieee80211_bss. They show which parts |
134 | * of the data structure were recieved as a result of an un-corrupted | 134 | * of the data structure were received as a result of an un-corrupted |
135 | * beacon/probe response. | 135 | * beacon/probe response. |
136 | */ | 136 | */ |
137 | enum ieee80211_bss_valid_data_flags { | 137 | enum ieee80211_bss_valid_data_flags { |
@@ -399,6 +399,24 @@ struct ieee80211_mgd_assoc_data { | |||
399 | u8 ie[]; | 399 | u8 ie[]; |
400 | }; | 400 | }; |
401 | 401 | ||
402 | struct ieee80211_sta_tx_tspec { | ||
403 | /* timestamp of the first packet in the time slice */ | ||
404 | unsigned long time_slice_start; | ||
405 | |||
406 | u32 admitted_time; /* in usecs, unlike over the air */ | ||
407 | u8 tsid; | ||
408 | s8 up; /* signed to be able to invalidate with -1 during teardown */ | ||
409 | |||
410 | /* consumed TX time in microseconds in the time slice */ | ||
411 | u32 consumed_tx_time; | ||
412 | enum { | ||
413 | TX_TSPEC_ACTION_NONE = 0, | ||
414 | TX_TSPEC_ACTION_DOWNGRADE, | ||
415 | TX_TSPEC_ACTION_STOP_DOWNGRADE, | ||
416 | } action; | ||
417 | bool downgraded; | ||
418 | }; | ||
419 | |||
402 | struct ieee80211_if_managed { | 420 | struct ieee80211_if_managed { |
403 | struct timer_list timer; | 421 | struct timer_list timer; |
404 | struct timer_list conn_mon_timer; | 422 | struct timer_list conn_mon_timer; |
@@ -434,6 +452,8 @@ struct ieee80211_if_managed { | |||
434 | 452 | ||
435 | unsigned int flags; | 453 | unsigned int flags; |
436 | 454 | ||
455 | bool csa_waiting_bcn; | ||
456 | |||
437 | bool beacon_crc_valid; | 457 | bool beacon_crc_valid; |
438 | u32 beacon_crc; | 458 | u32 beacon_crc; |
439 | 459 | ||
@@ -505,8 +525,23 @@ struct ieee80211_if_managed { | |||
505 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ | 525 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ |
506 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ | 526 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ |
507 | 527 | ||
528 | /* TDLS support */ | ||
508 | u8 tdls_peer[ETH_ALEN] __aligned(2); | 529 | u8 tdls_peer[ETH_ALEN] __aligned(2); |
509 | struct delayed_work tdls_peer_del_work; | 530 | struct delayed_work tdls_peer_del_work; |
531 | struct sk_buff *orig_teardown_skb; /* The original teardown skb */ | ||
532 | struct sk_buff *teardown_skb; /* A copy to send through the AP */ | ||
533 | spinlock_t teardown_lock; /* To lock changing teardown_skb */ | ||
534 | bool tdls_chan_switch_prohibited; | ||
535 | |||
536 | /* WMM-AC TSPEC support */ | ||
537 | struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS]; | ||
538 | /* Use a separate work struct so that we can do something here | ||
539 | * while the sdata->work is flushing the queues, for example. | ||
540 | * otherwise, in scenarios where we hardly get any traffic out | ||
541 | * on the BE queue, but there's a lot of VO traffic, we might | ||
542 | * get stuck in a downgraded situation and flush takes forever. | ||
543 | */ | ||
544 | struct delayed_work tx_tspec_wk; | ||
510 | }; | 545 | }; |
511 | 546 | ||
512 | struct ieee80211_if_ibss { | 547 | struct ieee80211_if_ibss { |
@@ -547,6 +582,25 @@ struct ieee80211_if_ibss { | |||
547 | }; | 582 | }; |
548 | 583 | ||
549 | /** | 584 | /** |
585 | * struct ieee80211_if_ocb - OCB mode state | ||
586 | * | ||
587 | * @housekeeping_timer: timer for periodic invocation of a housekeeping task | ||
588 | * @wrkq_flags: OCB deferred task action | ||
589 | * @incomplete_lock: delayed STA insertion lock | ||
590 | * @incomplete_stations: list of STAs waiting for delayed insertion | ||
591 | * @joined: indication if the interface is connected to an OCB network | ||
592 | */ | ||
593 | struct ieee80211_if_ocb { | ||
594 | struct timer_list housekeeping_timer; | ||
595 | unsigned long wrkq_flags; | ||
596 | |||
597 | spinlock_t incomplete_lock; | ||
598 | struct list_head incomplete_stations; | ||
599 | |||
600 | bool joined; | ||
601 | }; | ||
602 | |||
603 | /** | ||
550 | * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface | 604 | * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface |
551 | * | 605 | * |
552 | * these declarations define the interface, which enables | 606 | * these declarations define the interface, which enables |
@@ -839,6 +893,7 @@ struct ieee80211_sub_if_data { | |||
839 | struct ieee80211_if_managed mgd; | 893 | struct ieee80211_if_managed mgd; |
840 | struct ieee80211_if_ibss ibss; | 894 | struct ieee80211_if_ibss ibss; |
841 | struct ieee80211_if_mesh mesh; | 895 | struct ieee80211_if_mesh mesh; |
896 | struct ieee80211_if_ocb ocb; | ||
842 | u32 mntr_flags; | 897 | u32 mntr_flags; |
843 | } u; | 898 | } u; |
844 | 899 | ||
@@ -938,6 +993,7 @@ enum sdata_queue_type { | |||
938 | IEEE80211_SDATA_QUEUE_AGG_STOP = 2, | 993 | IEEE80211_SDATA_QUEUE_AGG_STOP = 2, |
939 | IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, | 994 | IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, |
940 | IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, | 995 | IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, |
996 | IEEE80211_SDATA_QUEUE_TDLS_CHSW = 5, | ||
941 | }; | 997 | }; |
942 | 998 | ||
943 | enum { | 999 | enum { |
@@ -955,6 +1011,7 @@ enum queue_stop_reason { | |||
955 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, | 1011 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, |
956 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | 1012 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
957 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, | 1013 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, |
1014 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID, | ||
958 | 1015 | ||
959 | IEEE80211_QUEUE_STOP_REASONS, | 1016 | IEEE80211_QUEUE_STOP_REASONS, |
960 | }; | 1017 | }; |
@@ -1181,7 +1238,7 @@ struct ieee80211_local { | |||
1181 | unsigned long scanning; | 1238 | unsigned long scanning; |
1182 | struct cfg80211_ssid scan_ssid; | 1239 | struct cfg80211_ssid scan_ssid; |
1183 | struct cfg80211_scan_request *int_scan_req; | 1240 | struct cfg80211_scan_request *int_scan_req; |
1184 | struct cfg80211_scan_request *scan_req; | 1241 | struct cfg80211_scan_request __rcu *scan_req; |
1185 | struct ieee80211_scan_request *hw_scan_req; | 1242 | struct ieee80211_scan_request *hw_scan_req; |
1186 | struct cfg80211_chan_def scan_chandef; | 1243 | struct cfg80211_chan_def scan_chandef; |
1187 | enum ieee80211_band hw_scan_band; | 1244 | enum ieee80211_band hw_scan_band; |
@@ -1191,7 +1248,8 @@ struct ieee80211_local { | |||
1191 | 1248 | ||
1192 | struct work_struct sched_scan_stopped_work; | 1249 | struct work_struct sched_scan_stopped_work; |
1193 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; | 1250 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; |
1194 | struct cfg80211_sched_scan_request *sched_scan_req; | 1251 | struct cfg80211_sched_scan_request __rcu *sched_scan_req; |
1252 | u8 scan_addr[ETH_ALEN]; | ||
1195 | 1253 | ||
1196 | unsigned long leave_oper_channel_time; | 1254 | unsigned long leave_oper_channel_time; |
1197 | enum mac80211_scan_state next_scan_state; | 1255 | enum mac80211_scan_state next_scan_state; |
@@ -1307,6 +1365,9 @@ struct ieee80211_local { | |||
1307 | /* virtual monitor interface */ | 1365 | /* virtual monitor interface */ |
1308 | struct ieee80211_sub_if_data __rcu *monitor_sdata; | 1366 | struct ieee80211_sub_if_data __rcu *monitor_sdata; |
1309 | struct cfg80211_chan_def monitor_chandef; | 1367 | struct cfg80211_chan_def monitor_chandef; |
1368 | |||
1369 | /* extended capabilities provided by mac80211 */ | ||
1370 | u8 ext_capa[8]; | ||
1310 | }; | 1371 | }; |
1311 | 1372 | ||
1312 | static inline struct ieee80211_sub_if_data * | 1373 | static inline struct ieee80211_sub_if_data * |
@@ -1342,6 +1403,9 @@ struct ieee802_11_elems { | |||
1342 | size_t total_len; | 1403 | size_t total_len; |
1343 | 1404 | ||
1344 | /* pointers to IEs */ | 1405 | /* pointers to IEs */ |
1406 | const struct ieee80211_tdls_lnkie *lnk_id; | ||
1407 | const struct ieee80211_ch_switch_timing *ch_sw_timing; | ||
1408 | const u8 *ext_capab; | ||
1345 | const u8 *ssid; | 1409 | const u8 *ssid; |
1346 | const u8 *supp_rates; | 1410 | const u8 *supp_rates; |
1347 | const u8 *ds_params; | 1411 | const u8 *ds_params; |
@@ -1376,6 +1440,7 @@ struct ieee802_11_elems { | |||
1376 | const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; | 1440 | const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; |
1377 | 1441 | ||
1378 | /* length of them, respectively */ | 1442 | /* length of them, respectively */ |
1443 | u8 ext_capab_len; | ||
1379 | u8 ssid_len; | 1444 | u8 ssid_len; |
1380 | u8 supp_rates_len; | 1445 | u8 supp_rates_len; |
1381 | u8 tim_len; | 1446 | u8 tim_len; |
@@ -1454,6 +1519,7 @@ void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, | |||
1454 | __le16 fc, bool acked); | 1519 | __le16 fc, bool acked); |
1455 | void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata); | 1520 | void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata); |
1456 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | 1521 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); |
1522 | void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata); | ||
1457 | 1523 | ||
1458 | /* IBSS code */ | 1524 | /* IBSS code */ |
1459 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | 1525 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); |
@@ -1471,6 +1537,15 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
1471 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); | 1537 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); |
1472 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); | 1538 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); |
1473 | 1539 | ||
1540 | /* OCB code */ | ||
1541 | void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata); | ||
1542 | void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, | ||
1543 | const u8 *bssid, const u8 *addr, u32 supp_rates); | ||
1544 | void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata); | ||
1545 | int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, | ||
1546 | struct ocb_setup *setup); | ||
1547 | int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata); | ||
1548 | |||
1474 | /* mesh code */ | 1549 | /* mesh code */ |
1475 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); | 1550 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); |
1476 | void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1551 | void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
@@ -1562,8 +1637,14 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1562 | struct net_device *dev); | 1637 | struct net_device *dev); |
1563 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | 1638 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, |
1564 | struct net_device *dev); | 1639 | struct net_device *dev); |
1640 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, | ||
1641 | struct net_device *dev, | ||
1642 | u32 info_flags); | ||
1565 | void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, | 1643 | void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, |
1566 | struct sk_buff_head *skbs); | 1644 | struct sk_buff_head *skbs); |
1645 | struct sk_buff * | ||
1646 | ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, | ||
1647 | struct sk_buff *skb, u32 info_flags); | ||
1567 | 1648 | ||
1568 | /* HT */ | 1649 | /* HT */ |
1569 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 1650 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
@@ -1642,7 +1723,6 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | |||
1642 | * ieee80211_parse_ch_switch_ie - parses channel switch IEs | 1723 | * ieee80211_parse_ch_switch_ie - parses channel switch IEs |
1643 | * @sdata: the sdata of the interface which has received the frame | 1724 | * @sdata: the sdata of the interface which has received the frame |
1644 | * @elems: parsed 802.11 elements received with the frame | 1725 | * @elems: parsed 802.11 elements received with the frame |
1645 | * @beacon: indicates if the frame was a beacon or probe response | ||
1646 | * @current_band: indicates the current band | 1726 | * @current_band: indicates the current band |
1647 | * @sta_flags: contains information about own capabilities and restrictions | 1727 | * @sta_flags: contains information about own capabilities and restrictions |
1648 | * to decide which channel switch announcements can be accepted. Only the | 1728 | * to decide which channel switch announcements can be accepted. Only the |
@@ -1656,7 +1736,7 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | |||
1656 | * Return: 0 on success, <0 on error and >0 if there is nothing to parse. | 1736 | * Return: 0 on success, <0 on error and >0 if there is nothing to parse. |
1657 | */ | 1737 | */ |
1658 | int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, | 1738 | int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, |
1659 | struct ieee802_11_elems *elems, bool beacon, | 1739 | struct ieee802_11_elems *elems, |
1660 | enum ieee80211_band current_band, | 1740 | enum ieee80211_band current_band, |
1661 | u32 sta_flags, u8 *bssid, | 1741 | u32 sta_flags, u8 *bssid, |
1662 | struct ieee80211_csa_ie *csa_ie); | 1742 | struct ieee80211_csa_ie *csa_ie); |
@@ -1691,8 +1771,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke | |||
1691 | gfp_t gfp); | 1771 | gfp_t gfp); |
1692 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | 1772 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, |
1693 | bool bss_notify); | 1773 | bool bss_notify); |
1694 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 1774 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
1695 | enum ieee80211_band band); | ||
1696 | 1775 | ||
1697 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | 1776 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, |
1698 | struct sk_buff *skb, int tid, | 1777 | struct sk_buff *skb, int tid, |
@@ -1758,6 +1837,13 @@ static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames) | |||
1758 | return true; | 1837 | return true; |
1759 | } | 1838 | } |
1760 | 1839 | ||
1840 | extern const int ieee802_1d_to_ac[8]; | ||
1841 | |||
1842 | static inline int ieee80211_ac_from_tid(int tid) | ||
1843 | { | ||
1844 | return ieee802_1d_to_ac[tid & 7]; | ||
1845 | } | ||
1846 | |||
1761 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); | 1847 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); |
1762 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); | 1848 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); |
1763 | void ieee80211_dynamic_ps_timer(unsigned long data); | 1849 | void ieee80211_dynamic_ps_timer(unsigned long data); |
@@ -1767,7 +1853,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
1767 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1853 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
1768 | struct ieee80211_hdr *hdr); | 1854 | struct ieee80211_hdr *hdr); |
1769 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | 1855 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, |
1770 | struct ieee80211_hdr *hdr, bool ack); | 1856 | struct ieee80211_hdr *hdr, bool ack, u16 tx_time); |
1771 | 1857 | ||
1772 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1858 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
1773 | unsigned long queues, | 1859 | unsigned long queues, |
@@ -1796,6 +1882,9 @@ void ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
1796 | struct sk_buff_head *skbs); | 1882 | struct sk_buff_head *skbs); |
1797 | void ieee80211_flush_queues(struct ieee80211_local *local, | 1883 | void ieee80211_flush_queues(struct ieee80211_local *local, |
1798 | struct ieee80211_sub_if_data *sdata); | 1884 | struct ieee80211_sub_if_data *sdata); |
1885 | void __ieee80211_flush_queues(struct ieee80211_local *local, | ||
1886 | struct ieee80211_sub_if_data *sdata, | ||
1887 | unsigned int queues); | ||
1799 | 1888 | ||
1800 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1889 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
1801 | u16 transaction, u16 auth_alg, u16 status, | 1890 | u16 transaction, u16 auth_alg, u16 status, |
@@ -1812,12 +1901,14 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1812 | u8 bands_used, u32 *rate_masks, | 1901 | u8 bands_used, u32 *rate_masks, |
1813 | struct cfg80211_chan_def *chandef); | 1902 | struct cfg80211_chan_def *chandef); |
1814 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1903 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1815 | u8 *dst, u32 ratemask, | 1904 | const u8 *src, const u8 *dst, |
1905 | u32 ratemask, | ||
1816 | struct ieee80211_channel *chan, | 1906 | struct ieee80211_channel *chan, |
1817 | const u8 *ssid, size_t ssid_len, | 1907 | const u8 *ssid, size_t ssid_len, |
1818 | const u8 *ie, size_t ie_len, | 1908 | const u8 *ie, size_t ie_len, |
1819 | bool directed); | 1909 | bool directed); |
1820 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1910 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, |
1911 | const u8 *src, const u8 *dst, | ||
1821 | const u8 *ssid, size_t ssid_len, | 1912 | const u8 *ssid, size_t ssid_len, |
1822 | const u8 *ie, size_t ie_len, | 1913 | const u8 *ie, size_t ie_len, |
1823 | u32 ratemask, bool directed, u32 tx_flags, | 1914 | u32 ratemask, bool directed, u32 tx_flags, |
@@ -1833,8 +1924,10 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, | |||
1833 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); | 1924 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); |
1834 | void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); | 1925 | void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); |
1835 | 1926 | ||
1836 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1927 | size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, |
1837 | const u8 *ids, int n_ids, size_t offset); | 1928 | const u8 *ids, int n_ids, |
1929 | const u8 *after_ric, int n_after_ric, | ||
1930 | size_t offset); | ||
1838 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); | 1931 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); |
1839 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1932 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1840 | u16 cap); | 1933 | u16 cap); |
@@ -1921,6 +2014,14 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
1921 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | 2014 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, |
1922 | const u8 *peer, enum nl80211_tdls_operation oper); | 2015 | const u8 *peer, enum nl80211_tdls_operation oper); |
1923 | void ieee80211_tdls_peer_del_work(struct work_struct *wk); | 2016 | void ieee80211_tdls_peer_del_work(struct work_struct *wk); |
2017 | int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||
2018 | const u8 *addr, u8 oper_class, | ||
2019 | struct cfg80211_chan_def *chandef); | ||
2020 | void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, | ||
2021 | struct net_device *dev, | ||
2022 | const u8 *addr); | ||
2023 | void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, | ||
2024 | struct sk_buff *skb); | ||
1924 | 2025 | ||
1925 | extern const struct ethtool_ops ieee80211_ethtool_ops; | 2026 | extern const struct ethtool_ops ieee80211_ethtool_ops; |
1926 | 2027 | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index af237223a8cd..417355390873 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -259,6 +259,15 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, | |||
259 | list_for_each_entry(nsdata, &local->interfaces, list) { | 259 | list_for_each_entry(nsdata, &local->interfaces, list) { |
260 | if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { | 260 | if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { |
261 | /* | 261 | /* |
262 | * Only OCB and monitor mode may coexist | ||
263 | */ | ||
264 | if ((sdata->vif.type == NL80211_IFTYPE_OCB && | ||
265 | nsdata->vif.type != NL80211_IFTYPE_MONITOR) || | ||
266 | (sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||
267 | nsdata->vif.type == NL80211_IFTYPE_OCB)) | ||
268 | return -EBUSY; | ||
269 | |||
270 | /* | ||
262 | * Allow only a single IBSS interface to be up at any | 271 | * Allow only a single IBSS interface to be up at any |
263 | * time. This is restricted because beacon distribution | 272 | * time. This is restricted because beacon distribution |
264 | * cannot work properly if both are in the same IBSS. | 273 | * cannot work properly if both are in the same IBSS. |
@@ -511,6 +520,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
511 | sdata->vif.cab_queue = master->vif.cab_queue; | 520 | sdata->vif.cab_queue = master->vif.cab_queue; |
512 | memcpy(sdata->vif.hw_queue, master->vif.hw_queue, | 521 | memcpy(sdata->vif.hw_queue, master->vif.hw_queue, |
513 | sizeof(sdata->vif.hw_queue)); | 522 | sizeof(sdata->vif.hw_queue)); |
523 | sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef; | ||
514 | break; | 524 | break; |
515 | } | 525 | } |
516 | case NL80211_IFTYPE_AP: | 526 | case NL80211_IFTYPE_AP: |
@@ -521,6 +531,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
521 | case NL80211_IFTYPE_MONITOR: | 531 | case NL80211_IFTYPE_MONITOR: |
522 | case NL80211_IFTYPE_ADHOC: | 532 | case NL80211_IFTYPE_ADHOC: |
523 | case NL80211_IFTYPE_P2P_DEVICE: | 533 | case NL80211_IFTYPE_P2P_DEVICE: |
534 | case NL80211_IFTYPE_OCB: | ||
524 | /* no special treatment */ | 535 | /* no special treatment */ |
525 | break; | 536 | break; |
526 | case NL80211_IFTYPE_UNSPECIFIED: | 537 | case NL80211_IFTYPE_UNSPECIFIED: |
@@ -631,6 +642,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
631 | case NL80211_IFTYPE_ADHOC: | 642 | case NL80211_IFTYPE_ADHOC: |
632 | case NL80211_IFTYPE_AP: | 643 | case NL80211_IFTYPE_AP: |
633 | case NL80211_IFTYPE_MESH_POINT: | 644 | case NL80211_IFTYPE_MESH_POINT: |
645 | case NL80211_IFTYPE_OCB: | ||
634 | netif_carrier_off(dev); | 646 | netif_carrier_off(dev); |
635 | break; | 647 | break; |
636 | case NL80211_IFTYPE_WDS: | 648 | case NL80211_IFTYPE_WDS: |
@@ -766,10 +778,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
766 | int i, flushed; | 778 | int i, flushed; |
767 | struct ps_data *ps; | 779 | struct ps_data *ps; |
768 | struct cfg80211_chan_def chandef; | 780 | struct cfg80211_chan_def chandef; |
781 | bool cancel_scan; | ||
769 | 782 | ||
770 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 783 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
771 | 784 | ||
772 | if (rcu_access_pointer(local->scan_sdata) == sdata) | 785 | cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; |
786 | if (cancel_scan) | ||
773 | ieee80211_scan_cancel(local); | 787 | ieee80211_scan_cancel(local); |
774 | 788 | ||
775 | /* | 789 | /* |
@@ -842,6 +856,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
842 | sdata_lock(sdata); | 856 | sdata_lock(sdata); |
843 | mutex_lock(&local->mtx); | 857 | mutex_lock(&local->mtx); |
844 | sdata->vif.csa_active = false; | 858 | sdata->vif.csa_active = false; |
859 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
860 | sdata->u.mgd.csa_waiting_bcn = false; | ||
845 | if (sdata->csa_block_tx) { | 861 | if (sdata->csa_block_tx) { |
846 | ieee80211_wake_vif_queues(local, sdata, | 862 | ieee80211_wake_vif_queues(local, sdata, |
847 | IEEE80211_QUEUE_STOP_REASON_CSA); | 863 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -898,6 +914,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
898 | list_del(&sdata->u.vlan.list); | 914 | list_del(&sdata->u.vlan.list); |
899 | mutex_unlock(&local->mtx); | 915 | mutex_unlock(&local->mtx); |
900 | RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL); | 916 | RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL); |
917 | /* see comment in the default case below */ | ||
918 | ieee80211_free_keys(sdata, true); | ||
901 | /* no need to tell driver */ | 919 | /* no need to tell driver */ |
902 | break; | 920 | break; |
903 | case NL80211_IFTYPE_MONITOR: | 921 | case NL80211_IFTYPE_MONITOR: |
@@ -923,17 +941,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
923 | /* | 941 | /* |
924 | * When we get here, the interface is marked down. | 942 | * When we get here, the interface is marked down. |
925 | * Free the remaining keys, if there are any | 943 | * Free the remaining keys, if there are any |
926 | * (shouldn't be, except maybe in WDS mode?) | 944 | * (which can happen in AP mode if userspace sets |
945 | * keys before the interface is operating, and maybe | ||
946 | * also in WDS mode) | ||
927 | * | 947 | * |
928 | * Force the key freeing to always synchronize_net() | 948 | * Force the key freeing to always synchronize_net() |
929 | * to wait for the RX path in case it is using this | 949 | * to wait for the RX path in case it is using this |
930 | * interface enqueuing frames * at this very time on | 950 | * interface enqueuing frames at this very time on |
931 | * another CPU. | 951 | * another CPU. |
932 | */ | 952 | */ |
933 | ieee80211_free_keys(sdata, true); | 953 | ieee80211_free_keys(sdata, true); |
934 | |||
935 | /* fall through */ | ||
936 | case NL80211_IFTYPE_AP: | ||
937 | skb_queue_purge(&sdata->skb_queue); | 954 | skb_queue_purge(&sdata->skb_queue); |
938 | } | 955 | } |
939 | 956 | ||
@@ -991,6 +1008,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
991 | 1008 | ||
992 | ieee80211_recalc_ps(local, -1); | 1009 | ieee80211_recalc_ps(local, -1); |
993 | 1010 | ||
1011 | if (cancel_scan) | ||
1012 | flush_delayed_work(&local->scan_work); | ||
1013 | |||
994 | if (local->open_count == 0) { | 1014 | if (local->open_count == 0) { |
995 | ieee80211_stop_device(local); | 1015 | ieee80211_stop_device(local); |
996 | 1016 | ||
@@ -1189,6 +1209,8 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
1189 | WLAN_BACK_RECIPIENT, 0, | 1209 | WLAN_BACK_RECIPIENT, 0, |
1190 | false); | 1210 | false); |
1191 | mutex_unlock(&local->sta_mtx); | 1211 | mutex_unlock(&local->sta_mtx); |
1212 | } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_TDLS_CHSW) { | ||
1213 | ieee80211_process_tdls_channel_switch(sdata, skb); | ||
1192 | } else if (ieee80211_is_action(mgmt->frame_control) && | 1214 | } else if (ieee80211_is_action(mgmt->frame_control) && |
1193 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { | 1215 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { |
1194 | int len = skb->len; | 1216 | int len = skb->len; |
@@ -1279,6 +1301,9 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
1279 | break; | 1301 | break; |
1280 | ieee80211_mesh_work(sdata); | 1302 | ieee80211_mesh_work(sdata); |
1281 | break; | 1303 | break; |
1304 | case NL80211_IFTYPE_OCB: | ||
1305 | ieee80211_ocb_work(sdata); | ||
1306 | break; | ||
1282 | default: | 1307 | default: |
1283 | break; | 1308 | break; |
1284 | } | 1309 | } |
@@ -1298,6 +1323,9 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) | |||
1298 | static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | 1323 | static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, |
1299 | enum nl80211_iftype type) | 1324 | enum nl80211_iftype type) |
1300 | { | 1325 | { |
1326 | static const u8 bssid_wildcard[ETH_ALEN] = {0xff, 0xff, 0xff, | ||
1327 | 0xff, 0xff, 0xff}; | ||
1328 | |||
1301 | /* clear type-dependent union */ | 1329 | /* clear type-dependent union */ |
1302 | memset(&sdata->u, 0, sizeof(sdata->u)); | 1330 | memset(&sdata->u, 0, sizeof(sdata->u)); |
1303 | 1331 | ||
@@ -1349,6 +1377,10 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1349 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; | 1377 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; |
1350 | ieee80211_sta_setup_sdata(sdata); | 1378 | ieee80211_sta_setup_sdata(sdata); |
1351 | break; | 1379 | break; |
1380 | case NL80211_IFTYPE_OCB: | ||
1381 | sdata->vif.bss_conf.bssid = bssid_wildcard; | ||
1382 | ieee80211_ocb_setup_sdata(sdata); | ||
1383 | break; | ||
1352 | case NL80211_IFTYPE_ADHOC: | 1384 | case NL80211_IFTYPE_ADHOC: |
1353 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | 1385 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
1354 | ieee80211_ibss_setup_sdata(sdata); | 1386 | ieee80211_ibss_setup_sdata(sdata); |
@@ -1396,6 +1428,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | |||
1396 | case NL80211_IFTYPE_AP: | 1428 | case NL80211_IFTYPE_AP: |
1397 | case NL80211_IFTYPE_STATION: | 1429 | case NL80211_IFTYPE_STATION: |
1398 | case NL80211_IFTYPE_ADHOC: | 1430 | case NL80211_IFTYPE_ADHOC: |
1431 | case NL80211_IFTYPE_OCB: | ||
1399 | /* | 1432 | /* |
1400 | * Could maybe also all others here? | 1433 | * Could maybe also all others here? |
1401 | * Just not sure how that interacts | 1434 | * Just not sure how that interacts |
@@ -1411,6 +1444,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | |||
1411 | case NL80211_IFTYPE_AP: | 1444 | case NL80211_IFTYPE_AP: |
1412 | case NL80211_IFTYPE_STATION: | 1445 | case NL80211_IFTYPE_STATION: |
1413 | case NL80211_IFTYPE_ADHOC: | 1446 | case NL80211_IFTYPE_ADHOC: |
1447 | case NL80211_IFTYPE_OCB: | ||
1414 | /* | 1448 | /* |
1415 | * Could probably support everything | 1449 | * Could probably support everything |
1416 | * but WDS here (WDS do_open can fail | 1450 | * but WDS here (WDS do_open can fail |
@@ -1669,7 +1703,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1669 | } | 1703 | } |
1670 | 1704 | ||
1671 | ieee80211_assign_perm_addr(local, ndev->perm_addr, type); | 1705 | ieee80211_assign_perm_addr(local, ndev->perm_addr, type); |
1672 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); | 1706 | if (params && is_valid_ether_addr(params->macaddr)) |
1707 | memcpy(ndev->dev_addr, params->macaddr, ETH_ALEN); | ||
1708 | else | ||
1709 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); | ||
1673 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 1710 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); |
1674 | 1711 | ||
1675 | /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */ | 1712 | /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */ |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 4712150dc210..434a91ad12c8 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -94,8 +94,17 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
94 | 94 | ||
95 | might_sleep(); | 95 | might_sleep(); |
96 | 96 | ||
97 | if (key->flags & KEY_FLAG_TAINTED) | 97 | if (key->flags & KEY_FLAG_TAINTED) { |
98 | /* If we get here, it's during resume and the key is | ||
99 | * tainted so shouldn't be used/programmed any more. | ||
100 | * However, its flags may still indicate that it was | ||
101 | * programmed into the device (since we're in resume) | ||
102 | * so clear that flag now to avoid trying to remove | ||
103 | * it again later. | ||
104 | */ | ||
105 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | ||
98 | return -EINVAL; | 106 | return -EINVAL; |
107 | } | ||
99 | 108 | ||
100 | if (!key->local->ops->set_key) | 109 | if (!key->local->ops->set_key) |
101 | goto out_unsupported; | 110 | goto out_unsupported; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0de7c93bf62b..6ab99da38db9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -478,13 +478,9 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { | |||
478 | }, | 478 | }, |
479 | }; | 479 | }; |
480 | 480 | ||
481 | static const u8 extended_capabilities[] = { | 481 | struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, |
482 | 0, 0, 0, 0, 0, 0, 0, | 482 | const struct ieee80211_ops *ops, |
483 | WLAN_EXT_CAPA8_OPMODE_NOTIF, | 483 | const char *requested_name) |
484 | }; | ||
485 | |||
486 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | ||
487 | const struct ieee80211_ops *ops) | ||
488 | { | 484 | { |
489 | struct ieee80211_local *local; | 485 | struct ieee80211_local *local; |
490 | int priv_size, i; | 486 | int priv_size, i; |
@@ -524,7 +520,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
524 | */ | 520 | */ |
525 | priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; | 521 | priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; |
526 | 522 | ||
527 | wiphy = wiphy_new(&mac80211_config_ops, priv_size); | 523 | wiphy = wiphy_new_nm(&mac80211_config_ops, priv_size, requested_name); |
528 | 524 | ||
529 | if (!wiphy) | 525 | if (!wiphy) |
530 | return NULL; | 526 | return NULL; |
@@ -539,10 +535,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
539 | WIPHY_FLAG_REPORTS_OBSS | | 535 | WIPHY_FLAG_REPORTS_OBSS | |
540 | WIPHY_FLAG_OFFCHAN_TX; | 536 | WIPHY_FLAG_OFFCHAN_TX; |
541 | 537 | ||
542 | wiphy->extended_capabilities = extended_capabilities; | ||
543 | wiphy->extended_capabilities_mask = extended_capabilities; | ||
544 | wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities); | ||
545 | |||
546 | if (ops->remain_on_channel) | 538 | if (ops->remain_on_channel) |
547 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 539 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
548 | 540 | ||
@@ -550,6 +542,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
550 | NL80211_FEATURE_SAE | | 542 | NL80211_FEATURE_SAE | |
551 | NL80211_FEATURE_HT_IBSS | | 543 | NL80211_FEATURE_HT_IBSS | |
552 | NL80211_FEATURE_VIF_TXPOWER | | 544 | NL80211_FEATURE_VIF_TXPOWER | |
545 | NL80211_FEATURE_MAC_ON_CREATE | | ||
553 | NL80211_FEATURE_USERSPACE_MPM; | 546 | NL80211_FEATURE_USERSPACE_MPM; |
554 | 547 | ||
555 | if (!ops->hw_scan) | 548 | if (!ops->hw_scan) |
@@ -591,6 +584,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
591 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | 584 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; |
592 | wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; | 585 | wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; |
593 | 586 | ||
587 | local->ext_capa[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF; | ||
588 | |||
589 | wiphy->extended_capabilities = local->ext_capa; | ||
590 | wiphy->extended_capabilities_mask = local->ext_capa; | ||
591 | wiphy->extended_capabilities_len = | ||
592 | ARRAY_SIZE(local->ext_capa); | ||
593 | |||
594 | INIT_LIST_HEAD(&local->interfaces); | 594 | INIT_LIST_HEAD(&local->interfaces); |
595 | 595 | ||
596 | __hw_addr_init(&local->mc_list); | 596 | __hw_addr_init(&local->mc_list); |
@@ -651,7 +651,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
651 | 651 | ||
652 | return &local->hw; | 652 | return &local->hw; |
653 | } | 653 | } |
654 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 654 | EXPORT_SYMBOL(ieee80211_alloc_hw_nm); |
655 | 655 | ||
656 | static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | 656 | static int ieee80211_init_cipher_suites(struct ieee80211_local *local) |
657 | { | 657 | { |
@@ -764,6 +764,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
764 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) | 764 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) |
765 | return -EINVAL; | 765 | return -EINVAL; |
766 | 766 | ||
767 | if ((hw->wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) && | ||
768 | (!local->ops->tdls_channel_switch || | ||
769 | !local->ops->tdls_cancel_channel_switch || | ||
770 | !local->ops->tdls_recv_channel_switch)) | ||
771 | return -EOPNOTSUPP; | ||
772 | |||
767 | #ifdef CONFIG_PM | 773 | #ifdef CONFIG_PM |
768 | if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) | 774 | if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) |
769 | return -EINVAL; | 775 | return -EINVAL; |
@@ -787,13 +793,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
787 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) | 793 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) |
788 | return -EINVAL; | 794 | return -EINVAL; |
789 | 795 | ||
790 | /* DFS currently not supported with channel context drivers */ | 796 | /* DFS is not supported with multi-channel combinations yet */ |
791 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { | 797 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { |
792 | const struct ieee80211_iface_combination *comb; | 798 | const struct ieee80211_iface_combination *comb; |
793 | 799 | ||
794 | comb = &local->hw.wiphy->iface_combinations[i]; | 800 | comb = &local->hw.wiphy->iface_combinations[i]; |
795 | 801 | ||
796 | if (comb->radar_detect_widths) | 802 | if (comb->radar_detect_widths && |
803 | comb->num_different_channels > 1) | ||
797 | return -EINVAL; | 804 | return -EINVAL; |
798 | } | 805 | } |
799 | } | 806 | } |
@@ -958,6 +965,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
958 | if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) | 965 | if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) |
959 | local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; | 966 | local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; |
960 | 967 | ||
968 | /* mac80211 supports eCSA, if the driver supports STA CSA at all */ | ||
969 | if (local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA) | ||
970 | local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING; | ||
971 | |||
961 | local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM; | 972 | local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM; |
962 | 973 | ||
963 | result = wiphy_register(local->hw.wiphy); | 974 | result = wiphy_register(local->hw.wiphy); |
@@ -1019,7 +1030,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1019 | } | 1030 | } |
1020 | 1031 | ||
1021 | /* add one default STA interface if supported */ | 1032 | /* add one default STA interface if supported */ |
1022 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { | 1033 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && |
1034 | !(hw->flags & IEEE80211_HW_NO_AUTO_VIF)) { | ||
1023 | result = ieee80211_if_add(local, "wlan%d", NULL, | 1035 | result = ieee80211_if_add(local, "wlan%d", NULL, |
1024 | NL80211_IFTYPE_STATION, NULL); | 1036 | NL80211_IFTYPE_STATION, NULL); |
1025 | if (result) | 1037 | if (result) |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index e9f99c1e3fad..0c8b2a77d312 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -874,7 +874,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, | |||
874 | 874 | ||
875 | memset(¶ms, 0, sizeof(params)); | 875 | memset(¶ms, 0, sizeof(params)); |
876 | memset(&csa_ie, 0, sizeof(csa_ie)); | 876 | memset(&csa_ie, 0, sizeof(csa_ie)); |
877 | err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, band, | 877 | err = ieee80211_parse_ch_switch_ie(sdata, elems, band, |
878 | sta_flags, sdata->vif.addr, | 878 | sta_flags, sdata->vif.addr, |
879 | &csa_ie); | 879 | &csa_ie); |
880 | if (err < 0) | 880 | if (err < 0) |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index f39a19f9090f..50c8473cf9dc 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -270,6 +270,8 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, | |||
270 | const u8 *dst, const u8 *mpp); | 270 | const u8 *dst, const u8 *mpp); |
271 | struct mesh_path * | 271 | struct mesh_path * |
272 | mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); | 272 | mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); |
273 | struct mesh_path * | ||
274 | mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); | ||
273 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); | 275 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); |
274 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); | 276 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); |
275 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 277 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
@@ -317,6 +319,7 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata); | |||
317 | 319 | ||
318 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); | 320 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); |
319 | extern int mesh_paths_generation; | 321 | extern int mesh_paths_generation; |
322 | extern int mpp_paths_generation; | ||
320 | 323 | ||
321 | #ifdef CONFIG_MAC80211_MESH | 324 | #ifdef CONFIG_MAC80211_MESH |
322 | static inline | 325 | static inline |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index a6699dceae7c..b890e225a8f1 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -44,6 +44,7 @@ static struct mesh_table __rcu *mesh_paths; | |||
44 | static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */ | 44 | static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */ |
45 | 45 | ||
46 | int mesh_paths_generation; | 46 | int mesh_paths_generation; |
47 | int mpp_paths_generation; | ||
47 | 48 | ||
48 | /* This lock will have the grow table function as writer and add / delete nodes | 49 | /* This lock will have the grow table function as writer and add / delete nodes |
49 | * as readers. RCU provides sufficient protection only when reading the table | 50 | * as readers. RCU provides sufficient protection only when reading the table |
@@ -410,6 +411,33 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx) | |||
410 | } | 411 | } |
411 | 412 | ||
412 | /** | 413 | /** |
414 | * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index | ||
415 | * @idx: index | ||
416 | * @sdata: local subif, or NULL for all entries | ||
417 | * | ||
418 | * Returns: pointer to the proxy path structure, or NULL if not found. | ||
419 | * | ||
420 | * Locking: must be called within a read rcu section. | ||
421 | */ | ||
422 | struct mesh_path * | ||
423 | mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx) | ||
424 | { | ||
425 | struct mesh_table *tbl = rcu_dereference(mpp_paths); | ||
426 | struct mpath_node *node; | ||
427 | int i; | ||
428 | int j = 0; | ||
429 | |||
430 | for_each_mesh_entry(tbl, node, i) { | ||
431 | if (sdata && node->mpath->sdata != sdata) | ||
432 | continue; | ||
433 | if (j++ == idx) | ||
434 | return node->mpath; | ||
435 | } | ||
436 | |||
437 | return NULL; | ||
438 | } | ||
439 | |||
440 | /** | ||
413 | * mesh_path_add_gate - add the given mpath to a mesh gate to our path table | 441 | * mesh_path_add_gate - add the given mpath to a mesh gate to our path table |
414 | * @mpath: gate path to add to table | 442 | * @mpath: gate path to add to table |
415 | */ | 443 | */ |
@@ -691,6 +719,9 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, | |||
691 | 719 | ||
692 | spin_unlock(&tbl->hashwlock[hash_idx]); | 720 | spin_unlock(&tbl->hashwlock[hash_idx]); |
693 | read_unlock_bh(&pathtbl_resize_lock); | 721 | read_unlock_bh(&pathtbl_resize_lock); |
722 | |||
723 | mpp_paths_generation++; | ||
724 | |||
694 | if (grow) { | 725 | if (grow) { |
695 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); | 726 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); |
696 | ieee80211_queue_work(&local->hw, &sdata->work); | 727 | ieee80211_queue_work(&local->hw, &sdata->work); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2de88704278b..75a9bf50207e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -552,13 +552,17 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
552 | cap = vht_cap.cap; | 552 | cap = vht_cap.cap; |
553 | 553 | ||
554 | if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) { | 554 | if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) { |
555 | cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; | 555 | u32 bw = cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; |
556 | cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; | 556 | |
557 | cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; | ||
558 | if (bw == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ || | ||
559 | bw == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) | ||
560 | cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; | ||
557 | } | 561 | } |
558 | 562 | ||
559 | if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_160MHZ) { | 563 | if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_160MHZ) { |
560 | cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; | 564 | cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; |
561 | cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; | 565 | cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; |
562 | } | 566 | } |
563 | 567 | ||
564 | /* | 568 | /* |
@@ -775,11 +779,30 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
775 | WLAN_EID_QOS_CAPA, | 779 | WLAN_EID_QOS_CAPA, |
776 | WLAN_EID_RRM_ENABLED_CAPABILITIES, | 780 | WLAN_EID_RRM_ENABLED_CAPABILITIES, |
777 | WLAN_EID_MOBILITY_DOMAIN, | 781 | WLAN_EID_MOBILITY_DOMAIN, |
782 | WLAN_EID_FAST_BSS_TRANSITION, /* reassoc only */ | ||
783 | WLAN_EID_RIC_DATA, /* reassoc only */ | ||
778 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | 784 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, |
779 | }; | 785 | }; |
780 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | 786 | static const u8 after_ric[] = { |
781 | before_ht, ARRAY_SIZE(before_ht), | 787 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, |
782 | offset); | 788 | WLAN_EID_HT_CAPABILITY, |
789 | WLAN_EID_BSS_COEX_2040, | ||
790 | WLAN_EID_EXT_CAPABILITY, | ||
791 | WLAN_EID_QOS_TRAFFIC_CAPA, | ||
792 | WLAN_EID_TIM_BCAST_REQ, | ||
793 | WLAN_EID_INTERWORKING, | ||
794 | /* 60GHz doesn't happen right now */ | ||
795 | WLAN_EID_VHT_CAPABILITY, | ||
796 | WLAN_EID_OPMODE_NOTIF, | ||
797 | }; | ||
798 | |||
799 | noffset = ieee80211_ie_split_ric(assoc_data->ie, | ||
800 | assoc_data->ie_len, | ||
801 | before_ht, | ||
802 | ARRAY_SIZE(before_ht), | ||
803 | after_ric, | ||
804 | ARRAY_SIZE(after_ric), | ||
805 | offset); | ||
783 | pos = skb_put(skb, noffset - offset); | 806 | pos = skb_put(skb, noffset - offset); |
784 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | 807 | memcpy(pos, assoc_data->ie + offset, noffset - offset); |
785 | offset = noffset; | 808 | offset = noffset; |
@@ -813,6 +836,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
813 | WLAN_EID_TIM_BCAST_REQ, | 836 | WLAN_EID_TIM_BCAST_REQ, |
814 | WLAN_EID_INTERWORKING, | 837 | WLAN_EID_INTERWORKING, |
815 | }; | 838 | }; |
839 | |||
840 | /* RIC already taken above, so no need to handle here anymore */ | ||
816 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | 841 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, |
817 | before_vht, ARRAY_SIZE(before_vht), | 842 | before_vht, ARRAY_SIZE(before_vht), |
818 | offset); | 843 | offset); |
@@ -1001,14 +1026,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
1001 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 1026 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
1002 | ifmgd->associated->channel = sdata->csa_chandef.chan; | 1027 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
1003 | 1028 | ||
1004 | sdata->vif.csa_active = false; | 1029 | ifmgd->csa_waiting_bcn = true; |
1005 | |||
1006 | /* XXX: wait for a beacon first? */ | ||
1007 | if (sdata->csa_block_tx) { | ||
1008 | ieee80211_wake_vif_queues(local, sdata, | ||
1009 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1010 | sdata->csa_block_tx = false; | ||
1011 | } | ||
1012 | 1030 | ||
1013 | ieee80211_sta_reset_beacon_monitor(sdata); | 1031 | ieee80211_sta_reset_beacon_monitor(sdata); |
1014 | ieee80211_sta_reset_conn_monitor(sdata); | 1032 | ieee80211_sta_reset_conn_monitor(sdata); |
@@ -1019,6 +1037,37 @@ out: | |||
1019 | sdata_unlock(sdata); | 1037 | sdata_unlock(sdata); |
1020 | } | 1038 | } |
1021 | 1039 | ||
1040 | static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) | ||
1041 | { | ||
1042 | struct ieee80211_local *local = sdata->local; | ||
1043 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1044 | int ret; | ||
1045 | |||
1046 | sdata_assert_lock(sdata); | ||
1047 | |||
1048 | WARN_ON(!sdata->vif.csa_active); | ||
1049 | |||
1050 | if (sdata->csa_block_tx) { | ||
1051 | ieee80211_wake_vif_queues(local, sdata, | ||
1052 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1053 | sdata->csa_block_tx = false; | ||
1054 | } | ||
1055 | |||
1056 | cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef); | ||
1057 | |||
1058 | sdata->vif.csa_active = false; | ||
1059 | ifmgd->csa_waiting_bcn = false; | ||
1060 | |||
1061 | ret = drv_post_channel_switch(sdata); | ||
1062 | if (ret) { | ||
1063 | sdata_info(sdata, | ||
1064 | "driver post channel switch failed, disconnecting\n"); | ||
1065 | ieee80211_queue_work(&local->hw, | ||
1066 | &ifmgd->csa_connection_drop_work); | ||
1067 | return; | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1022 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | 1071 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) |
1023 | { | 1072 | { |
1024 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1073 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
@@ -1046,7 +1095,8 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
1046 | 1095 | ||
1047 | static void | 1096 | static void |
1048 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1097 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
1049 | u64 timestamp, struct ieee802_11_elems *elems, | 1098 | u64 timestamp, u32 device_timestamp, |
1099 | struct ieee802_11_elems *elems, | ||
1050 | bool beacon) | 1100 | bool beacon) |
1051 | { | 1101 | { |
1052 | struct ieee80211_local *local = sdata->local; | 1102 | struct ieee80211_local *local = sdata->local; |
@@ -1056,6 +1106,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1056 | struct ieee80211_chanctx *chanctx; | 1106 | struct ieee80211_chanctx *chanctx; |
1057 | enum ieee80211_band current_band; | 1107 | enum ieee80211_band current_band; |
1058 | struct ieee80211_csa_ie csa_ie; | 1108 | struct ieee80211_csa_ie csa_ie; |
1109 | struct ieee80211_channel_switch ch_switch; | ||
1059 | int res; | 1110 | int res; |
1060 | 1111 | ||
1061 | sdata_assert_lock(sdata); | 1112 | sdata_assert_lock(sdata); |
@@ -1072,7 +1123,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1072 | 1123 | ||
1073 | current_band = cbss->channel->band; | 1124 | current_band = cbss->channel->band; |
1074 | memset(&csa_ie, 0, sizeof(csa_ie)); | 1125 | memset(&csa_ie, 0, sizeof(csa_ie)); |
1075 | res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band, | 1126 | res = ieee80211_parse_ch_switch_ie(sdata, elems, current_band, |
1076 | ifmgd->flags, | 1127 | ifmgd->flags, |
1077 | ifmgd->associated->bssid, &csa_ie); | 1128 | ifmgd->associated->bssid, &csa_ie); |
1078 | if (res < 0) | 1129 | if (res < 0) |
@@ -1110,21 +1161,31 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1110 | 1161 | ||
1111 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | 1162 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
1112 | 1163 | ||
1113 | if (local->use_chanctx) { | 1164 | if (local->use_chanctx && |
1114 | u32 num_chanctx = 0; | 1165 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { |
1115 | list_for_each_entry(chanctx, &local->chanctx_list, list) | 1166 | sdata_info(sdata, |
1116 | num_chanctx++; | 1167 | "driver doesn't support chan-switch with channel contexts\n"); |
1168 | ieee80211_queue_work(&local->hw, | ||
1169 | &ifmgd->csa_connection_drop_work); | ||
1170 | mutex_unlock(&local->chanctx_mtx); | ||
1171 | mutex_unlock(&local->mtx); | ||
1172 | return; | ||
1173 | } | ||
1174 | |||
1175 | ch_switch.timestamp = timestamp; | ||
1176 | ch_switch.device_timestamp = device_timestamp; | ||
1177 | ch_switch.block_tx = csa_ie.mode; | ||
1178 | ch_switch.chandef = csa_ie.chandef; | ||
1179 | ch_switch.count = csa_ie.count; | ||
1117 | 1180 | ||
1118 | if (num_chanctx > 1 || | 1181 | if (drv_pre_channel_switch(sdata, &ch_switch)) { |
1119 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { | 1182 | sdata_info(sdata, |
1120 | sdata_info(sdata, | 1183 | "preparing for channel switch failed, disconnecting\n"); |
1121 | "not handling chan-switch with channel contexts\n"); | 1184 | ieee80211_queue_work(&local->hw, |
1122 | ieee80211_queue_work(&local->hw, | 1185 | &ifmgd->csa_connection_drop_work); |
1123 | &ifmgd->csa_connection_drop_work); | 1186 | mutex_unlock(&local->chanctx_mtx); |
1124 | mutex_unlock(&local->chanctx_mtx); | 1187 | mutex_unlock(&local->mtx); |
1125 | mutex_unlock(&local->mtx); | 1188 | return; |
1126 | return; | ||
1127 | } | ||
1128 | } | 1189 | } |
1129 | 1190 | ||
1130 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, | 1191 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, |
@@ -1150,16 +1211,12 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1150 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1211 | IEEE80211_QUEUE_STOP_REASON_CSA); |
1151 | mutex_unlock(&local->mtx); | 1212 | mutex_unlock(&local->mtx); |
1152 | 1213 | ||
1214 | cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef, | ||
1215 | csa_ie.count); | ||
1216 | |||
1153 | if (local->ops->channel_switch) { | 1217 | if (local->ops->channel_switch) { |
1154 | /* use driver's channel switch callback */ | 1218 | /* use driver's channel switch callback */ |
1155 | struct ieee80211_channel_switch ch_switch = { | 1219 | drv_channel_switch(local, sdata, &ch_switch); |
1156 | .timestamp = timestamp, | ||
1157 | .block_tx = csa_ie.mode, | ||
1158 | .chandef = csa_ie.chandef, | ||
1159 | .count = csa_ie.count, | ||
1160 | }; | ||
1161 | |||
1162 | drv_channel_switch(local, &ch_switch); | ||
1163 | return; | 1220 | return; |
1164 | } | 1221 | } |
1165 | 1222 | ||
@@ -1168,7 +1225,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1168 | ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work); | 1225 | ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work); |
1169 | else | 1226 | else |
1170 | mod_timer(&ifmgd->chswitch_timer, | 1227 | mod_timer(&ifmgd->chswitch_timer, |
1171 | TU_TO_EXP_TIME(csa_ie.count * cbss->beacon_interval)); | 1228 | TU_TO_EXP_TIME((csa_ie.count - 1) * |
1229 | cbss->beacon_interval)); | ||
1172 | } | 1230 | } |
1173 | 1231 | ||
1174 | static bool | 1232 | static bool |
@@ -1579,6 +1637,95 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work) | |||
1579 | mutex_unlock(&sdata->local->mtx); | 1637 | mutex_unlock(&sdata->local->mtx); |
1580 | } | 1638 | } |
1581 | 1639 | ||
1640 | static bool | ||
1641 | __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) | ||
1642 | { | ||
1643 | struct ieee80211_local *local = sdata->local; | ||
1644 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1645 | bool ret; | ||
1646 | int ac; | ||
1647 | |||
1648 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
1649 | return false; | ||
1650 | |||
1651 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
1652 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
1653 | int non_acm_ac; | ||
1654 | unsigned long now = jiffies; | ||
1655 | |||
1656 | if (tx_tspec->action == TX_TSPEC_ACTION_NONE && | ||
1657 | tx_tspec->admitted_time && | ||
1658 | time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
1659 | tx_tspec->consumed_tx_time = 0; | ||
1660 | tx_tspec->time_slice_start = now; | ||
1661 | |||
1662 | if (tx_tspec->downgraded) | ||
1663 | tx_tspec->action = | ||
1664 | TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
1665 | } | ||
1666 | |||
1667 | switch (tx_tspec->action) { | ||
1668 | case TX_TSPEC_ACTION_STOP_DOWNGRADE: | ||
1669 | /* take the original parameters */ | ||
1670 | if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac])) | ||
1671 | sdata_err(sdata, | ||
1672 | "failed to set TX queue parameters for queue %d\n", | ||
1673 | ac); | ||
1674 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1675 | tx_tspec->downgraded = false; | ||
1676 | ret = true; | ||
1677 | break; | ||
1678 | case TX_TSPEC_ACTION_DOWNGRADE: | ||
1679 | if (time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
1680 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1681 | ret = true; | ||
1682 | break; | ||
1683 | } | ||
1684 | /* downgrade next lower non-ACM AC */ | ||
1685 | for (non_acm_ac = ac + 1; | ||
1686 | non_acm_ac < IEEE80211_NUM_ACS; | ||
1687 | non_acm_ac++) | ||
1688 | if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac))) | ||
1689 | break; | ||
1690 | /* The loop will result in using BK even if it requires | ||
1691 | * admission control, such configuration makes no sense | ||
1692 | * and we have to transmit somehow - the AC selection | ||
1693 | * does the same thing. | ||
1694 | */ | ||
1695 | if (drv_conf_tx(local, sdata, ac, | ||
1696 | &sdata->tx_conf[non_acm_ac])) | ||
1697 | sdata_err(sdata, | ||
1698 | "failed to set TX queue parameters for queue %d\n", | ||
1699 | ac); | ||
1700 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1701 | ret = true; | ||
1702 | schedule_delayed_work(&ifmgd->tx_tspec_wk, | ||
1703 | tx_tspec->time_slice_start + HZ - now + 1); | ||
1704 | break; | ||
1705 | case TX_TSPEC_ACTION_NONE: | ||
1706 | /* nothing now */ | ||
1707 | break; | ||
1708 | } | ||
1709 | } | ||
1710 | |||
1711 | return ret; | ||
1712 | } | ||
1713 | |||
1714 | void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) | ||
1715 | { | ||
1716 | if (__ieee80211_sta_handle_tspec_ac_params(sdata)) | ||
1717 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); | ||
1718 | } | ||
1719 | |||
1720 | static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work) | ||
1721 | { | ||
1722 | struct ieee80211_sub_if_data *sdata; | ||
1723 | |||
1724 | sdata = container_of(work, struct ieee80211_sub_if_data, | ||
1725 | u.mgd.tx_tspec_wk.work); | ||
1726 | ieee80211_sta_handle_tspec_ac_params(sdata); | ||
1727 | } | ||
1728 | |||
1582 | /* MLME */ | 1729 | /* MLME */ |
1583 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | 1730 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, |
1584 | struct ieee80211_sub_if_data *sdata, | 1731 | struct ieee80211_sub_if_data *sdata, |
@@ -1663,12 +1810,14 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
1663 | params.uapsd = uapsd; | 1810 | params.uapsd = uapsd; |
1664 | 1811 | ||
1665 | mlme_dbg(sdata, | 1812 | mlme_dbg(sdata, |
1666 | "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n", | 1813 | "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n", |
1667 | queue, aci, acm, | 1814 | queue, aci, acm, |
1668 | params.aifs, params.cw_min, params.cw_max, | 1815 | params.aifs, params.cw_min, params.cw_max, |
1669 | params.txop, params.uapsd); | 1816 | params.txop, params.uapsd, |
1817 | ifmgd->tx_tspec[queue].downgraded); | ||
1670 | sdata->tx_conf[queue] = params; | 1818 | sdata->tx_conf[queue] = params; |
1671 | if (drv_conf_tx(local, sdata, queue, ¶ms)) | 1819 | if (!ifmgd->tx_tspec[queue].downgraded && |
1820 | drv_conf_tx(local, sdata, queue, ¶ms)) | ||
1672 | sdata_err(sdata, | 1821 | sdata_err(sdata, |
1673 | "failed to set TX queue parameters for queue %d\n", | 1822 | "failed to set TX queue parameters for queue %d\n", |
1674 | queue); | 1823 | queue); |
@@ -1923,6 +2072,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1923 | ieee80211_vif_release_channel(sdata); | 2072 | ieee80211_vif_release_channel(sdata); |
1924 | 2073 | ||
1925 | sdata->vif.csa_active = false; | 2074 | sdata->vif.csa_active = false; |
2075 | ifmgd->csa_waiting_bcn = false; | ||
1926 | if (sdata->csa_block_tx) { | 2076 | if (sdata->csa_block_tx) { |
1927 | ieee80211_wake_vif_queues(local, sdata, | 2077 | ieee80211_wake_vif_queues(local, sdata, |
1928 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2078 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -1930,6 +2080,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1930 | } | 2080 | } |
1931 | mutex_unlock(&local->mtx); | 2081 | mutex_unlock(&local->mtx); |
1932 | 2082 | ||
2083 | /* existing TX TSPEC sessions no longer exist */ | ||
2084 | memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec)); | ||
2085 | cancel_delayed_work_sync(&ifmgd->tx_tspec_wk); | ||
2086 | |||
1933 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | 2087 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; |
1934 | } | 2088 | } |
1935 | 2089 | ||
@@ -1982,9 +2136,46 @@ out: | |||
1982 | mutex_unlock(&local->mtx); | 2136 | mutex_unlock(&local->mtx); |
1983 | } | 2137 | } |
1984 | 2138 | ||
2139 | static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata, | ||
2140 | struct ieee80211_hdr *hdr, | ||
2141 | u16 tx_time) | ||
2142 | { | ||
2143 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2144 | u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | ||
2145 | int ac = ieee80211_ac_from_tid(tid); | ||
2146 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
2147 | unsigned long now = jiffies; | ||
2148 | |||
2149 | if (likely(!tx_tspec->admitted_time)) | ||
2150 | return; | ||
2151 | |||
2152 | if (time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
2153 | tx_tspec->consumed_tx_time = 0; | ||
2154 | tx_tspec->time_slice_start = now; | ||
2155 | |||
2156 | if (tx_tspec->downgraded) { | ||
2157 | tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
2158 | schedule_delayed_work(&ifmgd->tx_tspec_wk, 0); | ||
2159 | } | ||
2160 | } | ||
2161 | |||
2162 | if (tx_tspec->downgraded) | ||
2163 | return; | ||
2164 | |||
2165 | tx_tspec->consumed_tx_time += tx_time; | ||
2166 | |||
2167 | if (tx_tspec->consumed_tx_time >= tx_tspec->admitted_time) { | ||
2168 | tx_tspec->downgraded = true; | ||
2169 | tx_tspec->action = TX_TSPEC_ACTION_DOWNGRADE; | ||
2170 | schedule_delayed_work(&ifmgd->tx_tspec_wk, 0); | ||
2171 | } | ||
2172 | } | ||
2173 | |||
1985 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | 2174 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, |
1986 | struct ieee80211_hdr *hdr, bool ack) | 2175 | struct ieee80211_hdr *hdr, bool ack, u16 tx_time) |
1987 | { | 2176 | { |
2177 | ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time); | ||
2178 | |||
1988 | if (!ieee80211_is_data(hdr->frame_control)) | 2179 | if (!ieee80211_is_data(hdr->frame_control)) |
1989 | return; | 2180 | return; |
1990 | 2181 | ||
@@ -2039,7 +2230,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
2039 | else | 2230 | else |
2040 | ssid_len = ssid[1]; | 2231 | ssid_len = ssid[1]; |
2041 | 2232 | ||
2042 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, | 2233 | ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL, |
2234 | ssid + 2, ssid_len, NULL, | ||
2043 | 0, (u32) -1, true, 0, | 2235 | 0, (u32) -1, true, 0, |
2044 | ifmgd->associated->channel, false); | 2236 | ifmgd->associated->channel, false); |
2045 | rcu_read_unlock(); | 2237 | rcu_read_unlock(); |
@@ -2047,8 +2239,6 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
2047 | 2239 | ||
2048 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); | 2240 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); |
2049 | run_again(sdata, ifmgd->probe_timeout); | 2241 | run_again(sdata, ifmgd->probe_timeout); |
2050 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
2051 | ieee80211_flush_queues(sdata->local, sdata); | ||
2052 | } | 2242 | } |
2053 | 2243 | ||
2054 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | 2244 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, |
@@ -2077,9 +2267,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
2077 | "detected beacon loss from AP (missed %d beacons) - probing\n", | 2267 | "detected beacon loss from AP (missed %d beacons) - probing\n", |
2078 | beacon_loss_count); | 2268 | beacon_loss_count); |
2079 | 2269 | ||
2080 | ieee80211_cqm_rssi_notify(&sdata->vif, | 2270 | ieee80211_cqm_beacon_loss_notify(&sdata->vif, GFP_KERNEL); |
2081 | NL80211_CQM_RSSI_BEACON_LOSS_EVENT, | ||
2082 | GFP_KERNEL); | ||
2083 | } | 2271 | } |
2084 | 2272 | ||
2085 | /* | 2273 | /* |
@@ -2144,7 +2332,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
2144 | else | 2332 | else |
2145 | ssid_len = ssid[1]; | 2333 | ssid_len = ssid[1]; |
2146 | 2334 | ||
2147 | skb = ieee80211_build_probe_req(sdata, cbss->bssid, | 2335 | skb = ieee80211_build_probe_req(sdata, sdata->vif.addr, cbss->bssid, |
2148 | (u32) -1, cbss->channel, | 2336 | (u32) -1, cbss->channel, |
2149 | ssid + 2, ssid_len, | 2337 | ssid + 2, ssid_len, |
2150 | NULL, 0, true); | 2338 | NULL, 0, true); |
@@ -2171,6 +2359,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2171 | true, frame_buf); | 2359 | true, frame_buf); |
2172 | mutex_lock(&local->mtx); | 2360 | mutex_lock(&local->mtx); |
2173 | sdata->vif.csa_active = false; | 2361 | sdata->vif.csa_active = false; |
2362 | ifmgd->csa_waiting_bcn = false; | ||
2174 | if (sdata->csa_block_tx) { | 2363 | if (sdata->csa_block_tx) { |
2175 | ieee80211_wake_vif_queues(local, sdata, | 2364 | ieee80211_wake_vif_queues(local, sdata, |
2176 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2365 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -2617,6 +2806,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2617 | } | 2806 | } |
2618 | 2807 | ||
2619 | ifmgd->aid = aid; | 2808 | ifmgd->aid = aid; |
2809 | ifmgd->tdls_chan_switch_prohibited = | ||
2810 | elems.ext_capab && elems.ext_capab_len >= 5 && | ||
2811 | (elems.ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED); | ||
2620 | 2812 | ||
2621 | /* | 2813 | /* |
2622 | * Some APs are erroneously not including some information in their | 2814 | * Some APs are erroneously not including some information in their |
@@ -3195,6 +3387,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3195 | } | 3387 | } |
3196 | } | 3388 | } |
3197 | 3389 | ||
3390 | if (ifmgd->csa_waiting_bcn) | ||
3391 | ieee80211_chswitch_post_beacon(sdata); | ||
3392 | |||
3198 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 3393 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
3199 | return; | 3394 | return; |
3200 | ifmgd->beacon_crc = ncrc; | 3395 | ifmgd->beacon_crc = ncrc; |
@@ -3203,6 +3398,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3203 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 3398 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
3204 | 3399 | ||
3205 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, | 3400 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, |
3401 | rx_status->device_timestamp, | ||
3206 | &elems, true); | 3402 | &elems, true); |
3207 | 3403 | ||
3208 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && | 3404 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && |
@@ -3334,8 +3530,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3334 | break; | 3530 | break; |
3335 | 3531 | ||
3336 | ieee80211_sta_process_chanswitch(sdata, | 3532 | ieee80211_sta_process_chanswitch(sdata, |
3337 | rx_status->mactime, | 3533 | rx_status->mactime, |
3338 | &elems, false); | 3534 | rx_status->device_timestamp, |
3535 | &elems, false); | ||
3339 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { | 3536 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { |
3340 | ies_len = skb->len - | 3537 | ies_len = skb->len - |
3341 | offsetof(struct ieee80211_mgmt, | 3538 | offsetof(struct ieee80211_mgmt, |
@@ -3356,8 +3553,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3356 | &mgmt->u.action.u.ext_chan_switch.data; | 3553 | &mgmt->u.action.u.ext_chan_switch.data; |
3357 | 3554 | ||
3358 | ieee80211_sta_process_chanswitch(sdata, | 3555 | ieee80211_sta_process_chanswitch(sdata, |
3359 | rx_status->mactime, | 3556 | rx_status->mactime, |
3360 | &elems, false); | 3557 | rx_status->device_timestamp, |
3558 | &elems, false); | ||
3361 | } | 3559 | } |
3362 | break; | 3560 | break; |
3363 | } | 3561 | } |
@@ -3455,7 +3653,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
3455 | * Direct probe is sent to broadcast address as some APs | 3653 | * Direct probe is sent to broadcast address as some APs |
3456 | * will not answer to direct packet in unassociated state. | 3654 | * will not answer to direct packet in unassociated state. |
3457 | */ | 3655 | */ |
3458 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | 3656 | ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL, |
3657 | ssidie + 2, ssidie[1], | ||
3459 | NULL, 0, (u32) -1, true, 0, | 3658 | NULL, 0, (u32) -1, true, 0, |
3460 | auth_data->bss->channel, false); | 3659 | auth_data->bss->channel, false); |
3461 | rcu_read_unlock(); | 3660 | rcu_read_unlock(); |
@@ -3664,11 +3863,12 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
3664 | struct ieee80211_sub_if_data *sdata = | 3863 | struct ieee80211_sub_if_data *sdata = |
3665 | (struct ieee80211_sub_if_data *) data; | 3864 | (struct ieee80211_sub_if_data *) data; |
3666 | struct ieee80211_local *local = sdata->local; | 3865 | struct ieee80211_local *local = sdata->local; |
3866 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3667 | 3867 | ||
3668 | if (local->quiescing) | 3868 | if (local->quiescing) |
3669 | return; | 3869 | return; |
3670 | 3870 | ||
3671 | if (sdata->vif.csa_active) | 3871 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3672 | return; | 3872 | return; |
3673 | 3873 | ||
3674 | sdata->u.mgd.connection_loss = false; | 3874 | sdata->u.mgd.connection_loss = false; |
@@ -3686,7 +3886,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) | |||
3686 | if (local->quiescing) | 3886 | if (local->quiescing) |
3687 | return; | 3887 | return; |
3688 | 3888 | ||
3689 | if (sdata->vif.csa_active) | 3889 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3690 | return; | 3890 | return; |
3691 | 3891 | ||
3692 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); | 3892 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); |
@@ -3798,6 +3998,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3798 | (unsigned long) sdata); | 3998 | (unsigned long) sdata); |
3799 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, | 3999 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
3800 | (unsigned long) sdata); | 4000 | (unsigned long) sdata); |
4001 | INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk, | ||
4002 | ieee80211_sta_handle_tspec_ac_params_wk); | ||
3801 | 4003 | ||
3802 | ifmgd->flags = 0; | 4004 | ifmgd->flags = 0; |
3803 | ifmgd->powersave = sdata->wdev.ps; | 4005 | ifmgd->powersave = sdata->wdev.ps; |
@@ -3809,6 +4011,11 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3809 | ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; | 4011 | ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; |
3810 | else | 4012 | else |
3811 | ifmgd->req_smps = IEEE80211_SMPS_OFF; | 4013 | ifmgd->req_smps = IEEE80211_SMPS_OFF; |
4014 | |||
4015 | /* Setup TDLS data */ | ||
4016 | spin_lock_init(&ifmgd->teardown_lock); | ||
4017 | ifmgd->teardown_skb = NULL; | ||
4018 | ifmgd->orig_teardown_skb = NULL; | ||
3812 | } | 4019 | } |
3813 | 4020 | ||
3814 | /* scan finished notification */ | 4021 | /* scan finished notification */ |
@@ -4671,6 +4878,13 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) | |||
4671 | } | 4878 | } |
4672 | if (ifmgd->auth_data) | 4879 | if (ifmgd->auth_data) |
4673 | ieee80211_destroy_auth_data(sdata, false); | 4880 | ieee80211_destroy_auth_data(sdata, false); |
4881 | spin_lock_bh(&ifmgd->teardown_lock); | ||
4882 | if (ifmgd->teardown_skb) { | ||
4883 | kfree_skb(ifmgd->teardown_skb); | ||
4884 | ifmgd->teardown_skb = NULL; | ||
4885 | ifmgd->orig_teardown_skb = NULL; | ||
4886 | } | ||
4887 | spin_unlock_bh(&ifmgd->teardown_lock); | ||
4674 | del_timer_sync(&ifmgd->timer); | 4888 | del_timer_sync(&ifmgd->timer); |
4675 | sdata_unlock(sdata); | 4889 | sdata_unlock(sdata); |
4676 | } | 4890 | } |
@@ -4686,3 +4900,13 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, | |||
4686 | cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp); | 4900 | cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp); |
4687 | } | 4901 | } |
4688 | EXPORT_SYMBOL(ieee80211_cqm_rssi_notify); | 4902 | EXPORT_SYMBOL(ieee80211_cqm_rssi_notify); |
4903 | |||
4904 | void ieee80211_cqm_beacon_loss_notify(struct ieee80211_vif *vif, gfp_t gfp) | ||
4905 | { | ||
4906 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
4907 | |||
4908 | trace_api_cqm_beacon_loss_notify(sdata->local, sdata); | ||
4909 | |||
4910 | cfg80211_cqm_beacon_loss_notify(sdata->dev, gfp); | ||
4911 | } | ||
4912 | EXPORT_SYMBOL(ieee80211_cqm_beacon_loss_notify); | ||
diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c new file mode 100644 index 000000000000..358d5f9d8207 --- /dev/null +++ b/net/mac80211/ocb.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * OCB mode implementation | ||
3 | * | ||
4 | * Copyright: (c) 2014 Czech Technical University in Prague | ||
5 | * (c) 2014 Volkswagen Group Research | ||
6 | * Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz> | ||
7 | * Funded by: Volkswagen Group Research | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/if_ether.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/if_arp.h> | ||
18 | #include <linux/etherdevice.h> | ||
19 | #include <linux/rtnetlink.h> | ||
20 | #include <net/mac80211.h> | ||
21 | #include <asm/unaligned.h> | ||
22 | |||
23 | #include "ieee80211_i.h" | ||
24 | #include "driver-ops.h" | ||
25 | #include "rate.h" | ||
26 | |||
27 | #define IEEE80211_OCB_HOUSEKEEPING_INTERVAL (60 * HZ) | ||
28 | #define IEEE80211_OCB_PEER_INACTIVITY_LIMIT (240 * HZ) | ||
29 | #define IEEE80211_OCB_MAX_STA_ENTRIES 128 | ||
30 | |||
31 | /** | ||
32 | * enum ocb_deferred_task_flags - mac80211 OCB deferred tasks | ||
33 | * @OCB_WORK_HOUSEKEEPING: run the periodic OCB housekeeping tasks | ||
34 | * | ||
35 | * These flags are used in @wrkq_flags field of &struct ieee80211_if_ocb | ||
36 | */ | ||
37 | enum ocb_deferred_task_flags { | ||
38 | OCB_WORK_HOUSEKEEPING, | ||
39 | }; | ||
40 | |||
41 | void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, | ||
42 | const u8 *bssid, const u8 *addr, | ||
43 | u32 supp_rates) | ||
44 | { | ||
45 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
46 | struct ieee80211_local *local = sdata->local; | ||
47 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
48 | struct ieee80211_supported_band *sband; | ||
49 | enum nl80211_bss_scan_width scan_width; | ||
50 | struct sta_info *sta; | ||
51 | int band; | ||
52 | |||
53 | /* XXX: Consider removing the least recently used entry and | ||
54 | * allow new one to be added. | ||
55 | */ | ||
56 | if (local->num_sta >= IEEE80211_OCB_MAX_STA_ENTRIES) { | ||
57 | net_info_ratelimited("%s: No room for a new OCB STA entry %pM\n", | ||
58 | sdata->name, addr); | ||
59 | return; | ||
60 | } | ||
61 | |||
62 | ocb_dbg(sdata, "Adding new OCB station %pM\n", addr); | ||
63 | |||
64 | rcu_read_lock(); | ||
65 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
66 | if (WARN_ON_ONCE(!chanctx_conf)) { | ||
67 | rcu_read_unlock(); | ||
68 | return; | ||
69 | } | ||
70 | band = chanctx_conf->def.chan->band; | ||
71 | scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); | ||
72 | rcu_read_unlock(); | ||
73 | |||
74 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | ||
75 | if (!sta) | ||
76 | return; | ||
77 | |||
78 | sta->last_rx = jiffies; | ||
79 | |||
80 | /* Add only mandatory rates for now */ | ||
81 | sband = local->hw.wiphy->bands[band]; | ||
82 | sta->sta.supp_rates[band] = | ||
83 | ieee80211_mandatory_rates(sband, scan_width); | ||
84 | |||
85 | spin_lock(&ifocb->incomplete_lock); | ||
86 | list_add(&sta->list, &ifocb->incomplete_stations); | ||
87 | spin_unlock(&ifocb->incomplete_lock); | ||
88 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
89 | } | ||
90 | |||
91 | static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta) | ||
92 | __acquires(RCU) | ||
93 | { | ||
94 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
95 | u8 addr[ETH_ALEN]; | ||
96 | |||
97 | memcpy(addr, sta->sta.addr, ETH_ALEN); | ||
98 | |||
99 | ocb_dbg(sdata, "Adding new IBSS station %pM (dev=%s)\n", | ||
100 | addr, sdata->name); | ||
101 | |||
102 | sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
103 | sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
104 | sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
105 | |||
106 | rate_control_rate_init(sta); | ||
107 | |||
108 | /* If it fails, maybe we raced another insertion? */ | ||
109 | if (sta_info_insert_rcu(sta)) | ||
110 | return sta_info_get(sdata, addr); | ||
111 | return sta; | ||
112 | } | ||
113 | |||
114 | static void ieee80211_ocb_housekeeping(struct ieee80211_sub_if_data *sdata) | ||
115 | { | ||
116 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
117 | |||
118 | ocb_dbg(sdata, "Running ocb housekeeping\n"); | ||
119 | |||
120 | ieee80211_sta_expire(sdata, IEEE80211_OCB_PEER_INACTIVITY_LIMIT); | ||
121 | |||
122 | mod_timer(&ifocb->housekeeping_timer, | ||
123 | round_jiffies(jiffies + IEEE80211_OCB_HOUSEKEEPING_INTERVAL)); | ||
124 | } | ||
125 | |||
126 | void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata) | ||
127 | { | ||
128 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
129 | struct sta_info *sta; | ||
130 | |||
131 | if (ifocb->joined != true) | ||
132 | return; | ||
133 | |||
134 | sdata_lock(sdata); | ||
135 | |||
136 | spin_lock_bh(&ifocb->incomplete_lock); | ||
137 | while (!list_empty(&ifocb->incomplete_stations)) { | ||
138 | sta = list_first_entry(&ifocb->incomplete_stations, | ||
139 | struct sta_info, list); | ||
140 | list_del(&sta->list); | ||
141 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
142 | |||
143 | ieee80211_ocb_finish_sta(sta); | ||
144 | rcu_read_unlock(); | ||
145 | spin_lock_bh(&ifocb->incomplete_lock); | ||
146 | } | ||
147 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
148 | |||
149 | if (test_and_clear_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags)) | ||
150 | ieee80211_ocb_housekeeping(sdata); | ||
151 | |||
152 | sdata_unlock(sdata); | ||
153 | } | ||
154 | |||
155 | static void ieee80211_ocb_housekeeping_timer(unsigned long data) | ||
156 | { | ||
157 | struct ieee80211_sub_if_data *sdata = (void *)data; | ||
158 | struct ieee80211_local *local = sdata->local; | ||
159 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
160 | |||
161 | set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags); | ||
162 | |||
163 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
164 | } | ||
165 | |||
166 | void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata) | ||
167 | { | ||
168 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
169 | |||
170 | setup_timer(&ifocb->housekeeping_timer, | ||
171 | ieee80211_ocb_housekeeping_timer, | ||
172 | (unsigned long)sdata); | ||
173 | INIT_LIST_HEAD(&ifocb->incomplete_stations); | ||
174 | spin_lock_init(&ifocb->incomplete_lock); | ||
175 | } | ||
176 | |||
177 | int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, | ||
178 | struct ocb_setup *setup) | ||
179 | { | ||
180 | struct ieee80211_local *local = sdata->local; | ||
181 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
182 | u32 changed = BSS_CHANGED_OCB; | ||
183 | int err; | ||
184 | |||
185 | if (ifocb->joined == true) | ||
186 | return -EINVAL; | ||
187 | |||
188 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
189 | sdata->smps_mode = IEEE80211_SMPS_OFF; | ||
190 | sdata->needed_rx_chains = sdata->local->rx_chains; | ||
191 | |||
192 | mutex_lock(&sdata->local->mtx); | ||
193 | err = ieee80211_vif_use_channel(sdata, &setup->chandef, | ||
194 | IEEE80211_CHANCTX_SHARED); | ||
195 | mutex_unlock(&sdata->local->mtx); | ||
196 | if (err) | ||
197 | return err; | ||
198 | |||
199 | ieee80211_bss_info_change_notify(sdata, changed); | ||
200 | |||
201 | ifocb->joined = true; | ||
202 | |||
203 | set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags); | ||
204 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
205 | |||
206 | netif_carrier_on(sdata->dev); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata) | ||
211 | { | ||
212 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
213 | struct ieee80211_local *local = sdata->local; | ||
214 | struct sta_info *sta; | ||
215 | |||
216 | ifocb->joined = false; | ||
217 | sta_info_flush(sdata); | ||
218 | |||
219 | spin_lock_bh(&ifocb->incomplete_lock); | ||
220 | while (!list_empty(&ifocb->incomplete_stations)) { | ||
221 | sta = list_first_entry(&ifocb->incomplete_stations, | ||
222 | struct sta_info, list); | ||
223 | list_del(&sta->list); | ||
224 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
225 | |||
226 | sta_info_free(local, sta); | ||
227 | spin_lock_bh(&ifocb->incomplete_lock); | ||
228 | } | ||
229 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
230 | |||
231 | netif_carrier_off(sdata->dev); | ||
232 | clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||
233 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB); | ||
234 | |||
235 | mutex_lock(&sdata->local->mtx); | ||
236 | ieee80211_vif_release_channel(sdata); | ||
237 | mutex_unlock(&sdata->local->mtx); | ||
238 | |||
239 | skb_queue_purge(&sdata->skb_queue); | ||
240 | |||
241 | del_timer_sync(&sdata->u.ocb.housekeeping_timer); | ||
242 | /* If the timer fired while we waited for it, it will have | ||
243 | * requeued the work. Now the work will be running again | ||
244 | * but will not rearm the timer again because it checks | ||
245 | * whether we are connected to the network or not -- at this | ||
246 | * point we shouldn't be anymore. | ||
247 | */ | ||
248 | |||
249 | return 0; | ||
250 | } | ||
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 8fdadfd94ba8..d53355b011f5 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -385,7 +385,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
385 | *rate = alt_rate; | 385 | *rate = alt_rate; |
386 | return; | 386 | return; |
387 | } | 387 | } |
388 | } else { | 388 | } else if (!(rate->flags & IEEE80211_TX_RC_VHT_MCS)) { |
389 | /* handle legacy rates */ | 389 | /* handle legacy rates */ |
390 | if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask)) | 390 | if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask)) |
391 | return; | 391 | return; |
@@ -446,9 +446,10 @@ static void rate_fixup_ratelist(struct ieee80211_vif *vif, | |||
446 | * | 446 | * |
447 | * XXX: Should this check all retry rates? | 447 | * XXX: Should this check all retry rates? |
448 | */ | 448 | */ |
449 | if (!(rates[0].flags & IEEE80211_TX_RC_MCS)) { | 449 | if (!(rates[0].flags & |
450 | (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))) { | ||
450 | u32 basic_rates = vif->bss_conf.basic_rates; | 451 | u32 basic_rates = vif->bss_conf.basic_rates; |
451 | s8 baserate = basic_rates ? ffs(basic_rates - 1) : 0; | 452 | s8 baserate = basic_rates ? ffs(basic_rates) - 1 : 0; |
452 | 453 | ||
453 | rate = &sband->bitrates[rates[0].idx]; | 454 | rate = &sband->bitrates[rates[0].idx]; |
454 | 455 | ||
@@ -696,6 +697,7 @@ int rate_control_set_rates(struct ieee80211_hw *hw, | |||
696 | struct ieee80211_sta *pubsta, | 697 | struct ieee80211_sta *pubsta, |
697 | struct ieee80211_sta_rates *rates) | 698 | struct ieee80211_sta_rates *rates) |
698 | { | 699 | { |
700 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
699 | struct ieee80211_sta_rates *old; | 701 | struct ieee80211_sta_rates *old; |
700 | 702 | ||
701 | /* | 703 | /* |
@@ -709,6 +711,8 @@ int rate_control_set_rates(struct ieee80211_hw *hw, | |||
709 | if (old) | 711 | if (old) |
710 | kfree_rcu(old, rcu_head); | 712 | kfree_rcu(old, rcu_head); |
711 | 713 | ||
714 | drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta); | ||
715 | |||
712 | return 0; | 716 | return 0; |
713 | } | 717 | } |
714 | EXPORT_SYMBOL(rate_control_set_rates); | 718 | EXPORT_SYMBOL(rate_control_set_rates); |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 18babe302832..38652f09feaf 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -37,13 +37,35 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, | |||
37 | struct rate_control_ref *ref = local->rate_ctrl; | 37 | struct rate_control_ref *ref = local->rate_ctrl; |
38 | struct ieee80211_sta *ista = &sta->sta; | 38 | struct ieee80211_sta *ista = &sta->sta; |
39 | void *priv_sta = sta->rate_ctrl_priv; | 39 | void *priv_sta = sta->rate_ctrl_priv; |
40 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
40 | 41 | ||
41 | if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) | 42 | if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) |
42 | return; | 43 | return; |
43 | 44 | ||
44 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); | 45 | if (ref->ops->tx_status) |
46 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); | ||
47 | else | ||
48 | ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info); | ||
45 | } | 49 | } |
46 | 50 | ||
51 | static inline void | ||
52 | rate_control_tx_status_noskb(struct ieee80211_local *local, | ||
53 | struct ieee80211_supported_band *sband, | ||
54 | struct sta_info *sta, | ||
55 | struct ieee80211_tx_info *info) | ||
56 | { | ||
57 | struct rate_control_ref *ref = local->rate_ctrl; | ||
58 | struct ieee80211_sta *ista = &sta->sta; | ||
59 | void *priv_sta = sta->rate_ctrl_priv; | ||
60 | |||
61 | if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) | ||
62 | return; | ||
63 | |||
64 | if (WARN_ON_ONCE(!ref->ops->tx_status_noskb)) | ||
65 | return; | ||
66 | |||
67 | ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info); | ||
68 | } | ||
47 | 69 | ||
48 | static inline void rate_control_rate_init(struct sta_info *sta) | 70 | static inline void rate_control_rate_init(struct sta_info *sta) |
49 | { | 71 | { |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 2baa7ed8789d..d51f6b1c549b 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -191,7 +191,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
191 | * (1) if any success probabilitiy >= 95%, out of those rates | 191 | * (1) if any success probabilitiy >= 95%, out of those rates |
192 | * choose the maximum throughput rate as max_prob_rate | 192 | * choose the maximum throughput rate as max_prob_rate |
193 | * (2) if all success probabilities < 95%, the rate with | 193 | * (2) if all success probabilities < 95%, the rate with |
194 | * highest success probability is choosen as max_prob_rate */ | 194 | * highest success probability is chosen as max_prob_rate */ |
195 | if (mrs->probability >= MINSTREL_FRAC(95, 100)) { | 195 | if (mrs->probability >= MINSTREL_FRAC(95, 100)) { |
196 | if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp) | 196 | if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp) |
197 | tmp_prob_rate = i; | 197 | tmp_prob_rate = i; |
@@ -223,11 +223,10 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
223 | static void | 223 | static void |
224 | minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | 224 | minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, |
225 | struct ieee80211_sta *sta, void *priv_sta, | 225 | struct ieee80211_sta *sta, void *priv_sta, |
226 | struct sk_buff *skb) | 226 | struct ieee80211_tx_info *info) |
227 | { | 227 | { |
228 | struct minstrel_priv *mp = priv; | 228 | struct minstrel_priv *mp = priv; |
229 | struct minstrel_sta_info *mi = priv_sta; | 229 | struct minstrel_sta_info *mi = priv_sta; |
230 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
231 | struct ieee80211_tx_rate *ar = info->status.rates; | 230 | struct ieee80211_tx_rate *ar = info->status.rates; |
232 | int i, ndx; | 231 | int i, ndx; |
233 | int success; | 232 | int success; |
@@ -674,7 +673,7 @@ static u32 minstrel_get_expected_throughput(void *priv_sta) | |||
674 | 673 | ||
675 | const struct rate_control_ops mac80211_minstrel = { | 674 | const struct rate_control_ops mac80211_minstrel = { |
676 | .name = "minstrel", | 675 | .name = "minstrel", |
677 | .tx_status = minstrel_tx_status, | 676 | .tx_status_noskb = minstrel_tx_status, |
678 | .get_rate = minstrel_get_rate, | 677 | .get_rate = minstrel_get_rate, |
679 | .rate_init = minstrel_rate_init, | 678 | .rate_init = minstrel_rate_init, |
680 | .alloc = minstrel_alloc, | 679 | .alloc = minstrel_alloc, |
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index edde723f9f00..2acab1bcaa4b 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c | |||
@@ -62,14 +62,14 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
62 | unsigned int i, tp, prob, eprob; | 62 | unsigned int i, tp, prob, eprob; |
63 | char *p; | 63 | char *p; |
64 | 64 | ||
65 | ms = kmalloc(sizeof(*ms) + 4096, GFP_KERNEL); | 65 | ms = kmalloc(2048, GFP_KERNEL); |
66 | if (!ms) | 66 | if (!ms) |
67 | return -ENOMEM; | 67 | return -ENOMEM; |
68 | 68 | ||
69 | file->private_data = ms; | 69 | file->private_data = ms; |
70 | p = ms->buf; | 70 | p = ms->buf; |
71 | p += sprintf(p, "rate throughput ewma prob this prob " | 71 | p += sprintf(p, "rate tpt eprob *prob" |
72 | "this succ/attempt success attempts\n"); | 72 | " *ok(*cum) ok( cum)\n"); |
73 | for (i = 0; i < mi->n_rates; i++) { | 73 | for (i = 0; i < mi->n_rates; i++) { |
74 | struct minstrel_rate *mr = &mi->r[i]; | 74 | struct minstrel_rate *mr = &mi->r[i]; |
75 | struct minstrel_rate_stats *mrs = &mi->r[i].stats; | 75 | struct minstrel_rate_stats *mrs = &mi->r[i].stats; |
@@ -86,8 +86,8 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
86 | prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); | 86 | prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); |
87 | eprob = MINSTREL_TRUNC(mrs->probability * 1000); | 87 | eprob = MINSTREL_TRUNC(mrs->probability * 1000); |
88 | 88 | ||
89 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " | 89 | p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u" |
90 | " %3u(%3u) %8llu %8llu\n", | 90 | " %4u(%4u) %9llu(%9llu)\n", |
91 | tp / 10, tp % 10, | 91 | tp / 10, tp % 10, |
92 | eprob / 10, eprob % 10, | 92 | eprob / 10, eprob % 10, |
93 | prob / 10, prob % 10, | 93 | prob / 10, prob % 10, |
@@ -102,6 +102,8 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
102 | mi->sample_packets); | 102 | mi->sample_packets); |
103 | ms->len = p - ms->buf; | 103 | ms->len = p - ms->buf; |
104 | 104 | ||
105 | WARN_ON(ms->len + sizeof(*ms) > 2048); | ||
106 | |||
105 | return 0; | 107 | return 0; |
106 | } | 108 | } |
107 | 109 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index df90ce2db00c..b52996aca4f1 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/skbuff.h> | 10 | #include <linux/skbuff.h> |
11 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
12 | #include <linux/random.h> | 12 | #include <linux/random.h> |
13 | #include <linux/moduleparam.h> | ||
13 | #include <linux/ieee80211.h> | 14 | #include <linux/ieee80211.h> |
14 | #include <net/mac80211.h> | 15 | #include <net/mac80211.h> |
15 | #include "rate.h" | 16 | #include "rate.h" |
@@ -34,12 +35,17 @@ | |||
34 | /* Transmit duration for the raw data part of an average sized packet */ | 35 | /* Transmit duration for the raw data part of an average sized packet */ |
35 | #define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) | 36 | #define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) |
36 | 37 | ||
38 | #define BW_20 0 | ||
39 | #define BW_40 1 | ||
40 | #define BW_80 2 | ||
41 | |||
37 | /* | 42 | /* |
38 | * Define group sort order: HT40 -> SGI -> #streams | 43 | * Define group sort order: HT40 -> SGI -> #streams |
39 | */ | 44 | */ |
40 | #define GROUP_IDX(_streams, _sgi, _ht40) \ | 45 | #define GROUP_IDX(_streams, _sgi, _ht40) \ |
46 | MINSTREL_HT_GROUP_0 + \ | ||
41 | MINSTREL_MAX_STREAMS * 2 * _ht40 + \ | 47 | MINSTREL_MAX_STREAMS * 2 * _ht40 + \ |
42 | MINSTREL_MAX_STREAMS * _sgi + \ | 48 | MINSTREL_MAX_STREAMS * _sgi + \ |
43 | _streams - 1 | 49 | _streams - 1 |
44 | 50 | ||
45 | /* MCS rate information for an MCS group */ | 51 | /* MCS rate information for an MCS group */ |
@@ -47,6 +53,7 @@ | |||
47 | [GROUP_IDX(_streams, _sgi, _ht40)] = { \ | 53 | [GROUP_IDX(_streams, _sgi, _ht40)] = { \ |
48 | .streams = _streams, \ | 54 | .streams = _streams, \ |
49 | .flags = \ | 55 | .flags = \ |
56 | IEEE80211_TX_RC_MCS | \ | ||
50 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ | 57 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ |
51 | (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ | 58 | (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ |
52 | .duration = { \ | 59 | .duration = { \ |
@@ -61,6 +68,47 @@ | |||
61 | } \ | 68 | } \ |
62 | } | 69 | } |
63 | 70 | ||
71 | #define VHT_GROUP_IDX(_streams, _sgi, _bw) \ | ||
72 | (MINSTREL_VHT_GROUP_0 + \ | ||
73 | MINSTREL_MAX_STREAMS * 2 * (_bw) + \ | ||
74 | MINSTREL_MAX_STREAMS * (_sgi) + \ | ||
75 | (_streams) - 1) | ||
76 | |||
77 | #define BW2VBPS(_bw, r3, r2, r1) \ | ||
78 | (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) | ||
79 | |||
80 | #define VHT_GROUP(_streams, _sgi, _bw) \ | ||
81 | [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ | ||
82 | .streams = _streams, \ | ||
83 | .flags = \ | ||
84 | IEEE80211_TX_RC_VHT_MCS | \ | ||
85 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ | ||
86 | (_bw == BW_80 ? IEEE80211_TX_RC_80_MHZ_WIDTH : \ | ||
87 | _bw == BW_40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ | ||
88 | .duration = { \ | ||
89 | MCS_DURATION(_streams, _sgi, \ | ||
90 | BW2VBPS(_bw, 117, 54, 26)), \ | ||
91 | MCS_DURATION(_streams, _sgi, \ | ||
92 | BW2VBPS(_bw, 234, 108, 52)), \ | ||
93 | MCS_DURATION(_streams, _sgi, \ | ||
94 | BW2VBPS(_bw, 351, 162, 78)), \ | ||
95 | MCS_DURATION(_streams, _sgi, \ | ||
96 | BW2VBPS(_bw, 468, 216, 104)), \ | ||
97 | MCS_DURATION(_streams, _sgi, \ | ||
98 | BW2VBPS(_bw, 702, 324, 156)), \ | ||
99 | MCS_DURATION(_streams, _sgi, \ | ||
100 | BW2VBPS(_bw, 936, 432, 208)), \ | ||
101 | MCS_DURATION(_streams, _sgi, \ | ||
102 | BW2VBPS(_bw, 1053, 486, 234)), \ | ||
103 | MCS_DURATION(_streams, _sgi, \ | ||
104 | BW2VBPS(_bw, 1170, 540, 260)), \ | ||
105 | MCS_DURATION(_streams, _sgi, \ | ||
106 | BW2VBPS(_bw, 1404, 648, 312)), \ | ||
107 | MCS_DURATION(_streams, _sgi, \ | ||
108 | BW2VBPS(_bw, 1560, 720, 346)) \ | ||
109 | } \ | ||
110 | } | ||
111 | |||
64 | #define CCK_DURATION(_bitrate, _short, _len) \ | 112 | #define CCK_DURATION(_bitrate, _short, _len) \ |
65 | (1000 * (10 /* SIFS */ + \ | 113 | (1000 * (10 /* SIFS */ + \ |
66 | (_short ? 72 + 24 : 144 + 48) + \ | 114 | (_short ? 72 + 24 : 144 + 48) + \ |
@@ -76,53 +124,96 @@ | |||
76 | CCK_ACK_DURATION(55, _short), \ | 124 | CCK_ACK_DURATION(55, _short), \ |
77 | CCK_ACK_DURATION(110, _short) | 125 | CCK_ACK_DURATION(110, _short) |
78 | 126 | ||
79 | #define CCK_GROUP \ | 127 | #define CCK_GROUP \ |
80 | [MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS] = { \ | 128 | [MINSTREL_CCK_GROUP] = { \ |
81 | .streams = 0, \ | 129 | .streams = 0, \ |
82 | .duration = { \ | 130 | .flags = 0, \ |
83 | CCK_DURATION_LIST(false), \ | 131 | .duration = { \ |
84 | CCK_DURATION_LIST(true) \ | 132 | CCK_DURATION_LIST(false), \ |
85 | } \ | 133 | CCK_DURATION_LIST(true) \ |
134 | } \ | ||
86 | } | 135 | } |
87 | 136 | ||
137 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
138 | static bool minstrel_vht_only = true; | ||
139 | module_param(minstrel_vht_only, bool, 0644); | ||
140 | MODULE_PARM_DESC(minstrel_vht_only, | ||
141 | "Use only VHT rates when VHT is supported by sta."); | ||
142 | #endif | ||
143 | |||
88 | /* | 144 | /* |
89 | * To enable sufficiently targeted rate sampling, MCS rates are divided into | 145 | * To enable sufficiently targeted rate sampling, MCS rates are divided into |
90 | * groups, based on the number of streams and flags (HT40, SGI) that they | 146 | * groups, based on the number of streams and flags (HT40, SGI) that they |
91 | * use. | 147 | * use. |
92 | * | 148 | * |
93 | * Sortorder has to be fixed for GROUP_IDX macro to be applicable: | 149 | * Sortorder has to be fixed for GROUP_IDX macro to be applicable: |
94 | * HT40 -> SGI -> #streams | 150 | * BW -> SGI -> #streams |
95 | */ | 151 | */ |
96 | const struct mcs_group minstrel_mcs_groups[] = { | 152 | const struct mcs_group minstrel_mcs_groups[] = { |
97 | MCS_GROUP(1, 0, 0), | 153 | MCS_GROUP(1, 0, BW_20), |
98 | MCS_GROUP(2, 0, 0), | 154 | MCS_GROUP(2, 0, BW_20), |
99 | #if MINSTREL_MAX_STREAMS >= 3 | 155 | #if MINSTREL_MAX_STREAMS >= 3 |
100 | MCS_GROUP(3, 0, 0), | 156 | MCS_GROUP(3, 0, BW_20), |
101 | #endif | 157 | #endif |
102 | 158 | ||
103 | MCS_GROUP(1, 1, 0), | 159 | MCS_GROUP(1, 1, BW_20), |
104 | MCS_GROUP(2, 1, 0), | 160 | MCS_GROUP(2, 1, BW_20), |
105 | #if MINSTREL_MAX_STREAMS >= 3 | 161 | #if MINSTREL_MAX_STREAMS >= 3 |
106 | MCS_GROUP(3, 1, 0), | 162 | MCS_GROUP(3, 1, BW_20), |
107 | #endif | 163 | #endif |
108 | 164 | ||
109 | MCS_GROUP(1, 0, 1), | 165 | MCS_GROUP(1, 0, BW_40), |
110 | MCS_GROUP(2, 0, 1), | 166 | MCS_GROUP(2, 0, BW_40), |
111 | #if MINSTREL_MAX_STREAMS >= 3 | 167 | #if MINSTREL_MAX_STREAMS >= 3 |
112 | MCS_GROUP(3, 0, 1), | 168 | MCS_GROUP(3, 0, BW_40), |
113 | #endif | 169 | #endif |
114 | 170 | ||
115 | MCS_GROUP(1, 1, 1), | 171 | MCS_GROUP(1, 1, BW_40), |
116 | MCS_GROUP(2, 1, 1), | 172 | MCS_GROUP(2, 1, BW_40), |
117 | #if MINSTREL_MAX_STREAMS >= 3 | 173 | #if MINSTREL_MAX_STREAMS >= 3 |
118 | MCS_GROUP(3, 1, 1), | 174 | MCS_GROUP(3, 1, BW_40), |
119 | #endif | 175 | #endif |
120 | 176 | ||
121 | /* must be last */ | 177 | CCK_GROUP, |
122 | CCK_GROUP | 178 | |
123 | }; | 179 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT |
180 | VHT_GROUP(1, 0, BW_20), | ||
181 | VHT_GROUP(2, 0, BW_20), | ||
182 | #if MINSTREL_MAX_STREAMS >= 3 | ||
183 | VHT_GROUP(3, 0, BW_20), | ||
184 | #endif | ||
124 | 185 | ||
125 | #define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1) | 186 | VHT_GROUP(1, 1, BW_20), |
187 | VHT_GROUP(2, 1, BW_20), | ||
188 | #if MINSTREL_MAX_STREAMS >= 3 | ||
189 | VHT_GROUP(3, 1, BW_20), | ||
190 | #endif | ||
191 | |||
192 | VHT_GROUP(1, 0, BW_40), | ||
193 | VHT_GROUP(2, 0, BW_40), | ||
194 | #if MINSTREL_MAX_STREAMS >= 3 | ||
195 | VHT_GROUP(3, 0, BW_40), | ||
196 | #endif | ||
197 | |||
198 | VHT_GROUP(1, 1, BW_40), | ||
199 | VHT_GROUP(2, 1, BW_40), | ||
200 | #if MINSTREL_MAX_STREAMS >= 3 | ||
201 | VHT_GROUP(3, 1, BW_40), | ||
202 | #endif | ||
203 | |||
204 | VHT_GROUP(1, 0, BW_80), | ||
205 | VHT_GROUP(2, 0, BW_80), | ||
206 | #if MINSTREL_MAX_STREAMS >= 3 | ||
207 | VHT_GROUP(3, 0, BW_80), | ||
208 | #endif | ||
209 | |||
210 | VHT_GROUP(1, 1, BW_80), | ||
211 | VHT_GROUP(2, 1, BW_80), | ||
212 | #if MINSTREL_MAX_STREAMS >= 3 | ||
213 | VHT_GROUP(3, 1, BW_80), | ||
214 | #endif | ||
215 | #endif | ||
216 | }; | ||
126 | 217 | ||
127 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; | 218 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; |
128 | 219 | ||
@@ -130,16 +221,64 @@ static void | |||
130 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); | 221 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); |
131 | 222 | ||
132 | /* | 223 | /* |
224 | * Some VHT MCSes are invalid (when Ndbps / Nes is not an integer) | ||
225 | * e.g for MCS9@20MHzx1Nss: Ndbps=8x52*(5/6) Nes=1 | ||
226 | * | ||
227 | * Returns the valid mcs map for struct minstrel_mcs_group_data.supported | ||
228 | */ | ||
229 | static u16 | ||
230 | minstrel_get_valid_vht_rates(int bw, int nss, __le16 mcs_map) | ||
231 | { | ||
232 | u16 mask = 0; | ||
233 | |||
234 | if (bw == BW_20) { | ||
235 | if (nss != 3 && nss != 6) | ||
236 | mask = BIT(9); | ||
237 | } else if (bw == BW_80) { | ||
238 | if (nss == 3 || nss == 7) | ||
239 | mask = BIT(6); | ||
240 | else if (nss == 6) | ||
241 | mask = BIT(9); | ||
242 | } else { | ||
243 | WARN_ON(bw != BW_40); | ||
244 | } | ||
245 | |||
246 | switch ((le16_to_cpu(mcs_map) >> (2 * (nss - 1))) & 3) { | ||
247 | case IEEE80211_VHT_MCS_SUPPORT_0_7: | ||
248 | mask |= 0x300; | ||
249 | break; | ||
250 | case IEEE80211_VHT_MCS_SUPPORT_0_8: | ||
251 | mask |= 0x200; | ||
252 | break; | ||
253 | case IEEE80211_VHT_MCS_SUPPORT_0_9: | ||
254 | break; | ||
255 | default: | ||
256 | mask = 0x3ff; | ||
257 | } | ||
258 | |||
259 | return 0x3ff & ~mask; | ||
260 | } | ||
261 | |||
262 | /* | ||
133 | * Look up an MCS group index based on mac80211 rate information | 263 | * Look up an MCS group index based on mac80211 rate information |
134 | */ | 264 | */ |
135 | static int | 265 | static int |
136 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) | 266 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) |
137 | { | 267 | { |
138 | return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1, | 268 | return GROUP_IDX((rate->idx / 8) + 1, |
139 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), | 269 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), |
140 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); | 270 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); |
141 | } | 271 | } |
142 | 272 | ||
273 | static int | ||
274 | minstrel_vht_get_group_idx(struct ieee80211_tx_rate *rate) | ||
275 | { | ||
276 | return VHT_GROUP_IDX(ieee80211_rate_get_vht_nss(rate), | ||
277 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), | ||
278 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + | ||
279 | 2*!!(rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)); | ||
280 | } | ||
281 | |||
143 | static struct minstrel_rate_stats * | 282 | static struct minstrel_rate_stats * |
144 | minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 283 | minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, |
145 | struct ieee80211_tx_rate *rate) | 284 | struct ieee80211_tx_rate *rate) |
@@ -149,6 +288,9 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
149 | if (rate->flags & IEEE80211_TX_RC_MCS) { | 288 | if (rate->flags & IEEE80211_TX_RC_MCS) { |
150 | group = minstrel_ht_get_group_idx(rate); | 289 | group = minstrel_ht_get_group_idx(rate); |
151 | idx = rate->idx % 8; | 290 | idx = rate->idx % 8; |
291 | } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { | ||
292 | group = minstrel_vht_get_group_idx(rate); | ||
293 | idx = ieee80211_rate_get_vht_mcs(rate); | ||
152 | } else { | 294 | } else { |
153 | group = MINSTREL_CCK_GROUP; | 295 | group = MINSTREL_CCK_GROUP; |
154 | 296 | ||
@@ -240,8 +382,8 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | |||
240 | * MCS groups, CCK rates do not provide aggregation and are therefore at last. | 382 | * MCS groups, CCK rates do not provide aggregation and are therefore at last. |
241 | */ | 383 | */ |
242 | static void | 384 | static void |
243 | minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index, | 385 | minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index, |
244 | u8 *tp_list) | 386 | u16 *tp_list) |
245 | { | 387 | { |
246 | int cur_group, cur_idx, cur_thr, cur_prob; | 388 | int cur_group, cur_idx, cur_thr, cur_prob; |
247 | int tmp_group, tmp_idx, tmp_thr, tmp_prob; | 389 | int tmp_group, tmp_idx, tmp_thr, tmp_prob; |
@@ -278,7 +420,7 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index, | |||
278 | * Find and set the topmost probability rate per sta and per group | 420 | * Find and set the topmost probability rate per sta and per group |
279 | */ | 421 | */ |
280 | static void | 422 | static void |
281 | minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index) | 423 | minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) |
282 | { | 424 | { |
283 | struct minstrel_mcs_group_data *mg; | 425 | struct minstrel_mcs_group_data *mg; |
284 | struct minstrel_rate_stats *mr; | 426 | struct minstrel_rate_stats *mr; |
@@ -321,8 +463,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index) | |||
321 | */ | 463 | */ |
322 | static void | 464 | static void |
323 | minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, | 465 | minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, |
324 | u8 tmp_mcs_tp_rate[MAX_THR_RATES], | 466 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], |
325 | u8 tmp_cck_tp_rate[MAX_THR_RATES]) | 467 | u16 tmp_cck_tp_rate[MAX_THR_RATES]) |
326 | { | 468 | { |
327 | unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; | 469 | unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; |
328 | int i; | 470 | int i; |
@@ -386,8 +528,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
386 | struct minstrel_mcs_group_data *mg; | 528 | struct minstrel_mcs_group_data *mg; |
387 | struct minstrel_rate_stats *mr; | 529 | struct minstrel_rate_stats *mr; |
388 | int group, i, j; | 530 | int group, i, j; |
389 | u8 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; | 531 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; |
390 | u8 tmp_cck_tp_rate[MAX_THR_RATES], index; | 532 | u16 tmp_cck_tp_rate[MAX_THR_RATES], index; |
391 | 533 | ||
392 | if (mi->ampdu_packets > 0) { | 534 | if (mi->ampdu_packets > 0) { |
393 | mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, | 535 | mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, |
@@ -485,7 +627,8 @@ minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rat | |||
485 | if (!rate->count) | 627 | if (!rate->count) |
486 | return false; | 628 | return false; |
487 | 629 | ||
488 | if (rate->flags & IEEE80211_TX_RC_MCS) | 630 | if (rate->flags & IEEE80211_TX_RC_MCS || |
631 | rate->flags & IEEE80211_TX_RC_VHT_MCS) | ||
489 | return true; | 632 | return true; |
490 | 633 | ||
491 | return rate->idx == mp->cck_rates[0] || | 634 | return rate->idx == mp->cck_rates[0] || |
@@ -517,7 +660,7 @@ minstrel_next_sample_idx(struct minstrel_ht_sta *mi) | |||
517 | } | 660 | } |
518 | 661 | ||
519 | static void | 662 | static void |
520 | minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u8 *idx, bool primary) | 663 | minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) |
521 | { | 664 | { |
522 | int group, orig_group; | 665 | int group, orig_group; |
523 | 666 | ||
@@ -547,6 +690,9 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) | |||
547 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 690 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
548 | u16 tid; | 691 | u16 tid; |
549 | 692 | ||
693 | if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) | ||
694 | return; | ||
695 | |||
550 | if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) | 696 | if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) |
551 | return; | 697 | return; |
552 | 698 | ||
@@ -557,20 +703,16 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) | |||
557 | if (likely(sta->ampdu_mlme.tid_tx[tid])) | 703 | if (likely(sta->ampdu_mlme.tid_tx[tid])) |
558 | return; | 704 | return; |
559 | 705 | ||
560 | if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) | ||
561 | return; | ||
562 | |||
563 | ieee80211_start_tx_ba_session(pubsta, tid, 5000); | 706 | ieee80211_start_tx_ba_session(pubsta, tid, 5000); |
564 | } | 707 | } |
565 | 708 | ||
566 | static void | 709 | static void |
567 | minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | 710 | minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, |
568 | struct ieee80211_sta *sta, void *priv_sta, | 711 | struct ieee80211_sta *sta, void *priv_sta, |
569 | struct sk_buff *skb) | 712 | struct ieee80211_tx_info *info) |
570 | { | 713 | { |
571 | struct minstrel_ht_sta_priv *msp = priv_sta; | 714 | struct minstrel_ht_sta_priv *msp = priv_sta; |
572 | struct minstrel_ht_sta *mi = &msp->ht; | 715 | struct minstrel_ht_sta *mi = &msp->ht; |
573 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
574 | struct ieee80211_tx_rate *ar = info->status.rates; | 716 | struct ieee80211_tx_rate *ar = info->status.rates; |
575 | struct minstrel_rate_stats *rate, *rate2; | 717 | struct minstrel_rate_stats *rate, *rate2; |
576 | struct minstrel_priv *mp = priv; | 718 | struct minstrel_priv *mp = priv; |
@@ -578,7 +720,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
578 | int i; | 720 | int i; |
579 | 721 | ||
580 | if (!msp->is_ht) | 722 | if (!msp->is_ht) |
581 | return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb); | 723 | return mac80211_minstrel.tx_status_noskb(priv, sband, sta, |
724 | &msp->legacy, info); | ||
582 | 725 | ||
583 | /* This packet was aggregated but doesn't carry status info */ | 726 | /* This packet was aggregated but doesn't carry status info */ |
584 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | 727 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && |
@@ -639,9 +782,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
639 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { | 782 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { |
640 | update = true; | 783 | update = true; |
641 | minstrel_ht_update_stats(mp, mi); | 784 | minstrel_ht_update_stats(mp, mi); |
642 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && | ||
643 | mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) | ||
644 | minstrel_aggr_check(sta, skb); | ||
645 | } | 785 | } |
646 | 786 | ||
647 | if (update) | 787 | if (update) |
@@ -714,7 +854,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
714 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; | 854 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
715 | struct minstrel_rate_stats *mr; | 855 | struct minstrel_rate_stats *mr; |
716 | u8 idx; | 856 | u8 idx; |
717 | u16 flags; | 857 | u16 flags = group->flags; |
718 | 858 | ||
719 | mr = minstrel_get_ratestats(mi, index); | 859 | mr = minstrel_get_ratestats(mi, index); |
720 | if (!mr->retry_updated) | 860 | if (!mr->retry_updated) |
@@ -730,13 +870,13 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
730 | ratetbl->rate[offset].count_rts = mr->retry_count_rtscts; | 870 | ratetbl->rate[offset].count_rts = mr->retry_count_rtscts; |
731 | } | 871 | } |
732 | 872 | ||
733 | if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { | 873 | if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) |
734 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; | 874 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; |
735 | flags = 0; | 875 | else if (flags & IEEE80211_TX_RC_VHT_MCS) |
736 | } else { | 876 | idx = ((group->streams - 1) << 4) | |
877 | ((index % MCS_GROUP_RATES) & 0xF); | ||
878 | else | ||
737 | idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; | 879 | idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; |
738 | flags = IEEE80211_TX_RC_MCS | group->flags; | ||
739 | } | ||
740 | 880 | ||
741 | if (offset > 0) { | 881 | if (offset > 0) { |
742 | ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; | 882 | ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; |
@@ -883,6 +1023,10 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
883 | if (!msp->is_ht) | 1023 | if (!msp->is_ht) |
884 | return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); | 1024 | return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); |
885 | 1025 | ||
1026 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && | ||
1027 | mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) | ||
1028 | minstrel_aggr_check(sta, txrc->skb); | ||
1029 | |||
886 | info->flags |= mi->tx_flags; | 1030 | info->flags |= mi->tx_flags; |
887 | minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble); | 1031 | minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble); |
888 | 1032 | ||
@@ -916,13 +1060,15 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
916 | if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { | 1060 | if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { |
917 | int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); | 1061 | int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); |
918 | rate->idx = mp->cck_rates[idx]; | 1062 | rate->idx = mp->cck_rates[idx]; |
919 | rate->flags = 0; | 1063 | } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) { |
920 | return; | 1064 | ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES, |
1065 | sample_group->streams); | ||
1066 | } else { | ||
1067 | rate->idx = sample_idx % MCS_GROUP_RATES + | ||
1068 | (sample_group->streams - 1) * 8; | ||
921 | } | 1069 | } |
922 | 1070 | ||
923 | rate->idx = sample_idx % MCS_GROUP_RATES + | 1071 | rate->flags = sample_group->flags; |
924 | (sample_group->streams - 1) * 8; | ||
925 | rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; | ||
926 | } | 1072 | } |
927 | 1073 | ||
928 | static void | 1074 | static void |
@@ -962,6 +1108,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
962 | struct minstrel_ht_sta *mi = &msp->ht; | 1108 | struct minstrel_ht_sta *mi = &msp->ht; |
963 | struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; | 1109 | struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; |
964 | u16 sta_cap = sta->ht_cap.cap; | 1110 | u16 sta_cap = sta->ht_cap.cap; |
1111 | struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; | ||
1112 | int use_vht; | ||
965 | int n_supported = 0; | 1113 | int n_supported = 0; |
966 | int ack_dur; | 1114 | int ack_dur; |
967 | int stbc; | 1115 | int stbc; |
@@ -971,8 +1119,14 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
971 | if (!sta->ht_cap.ht_supported) | 1119 | if (!sta->ht_cap.ht_supported) |
972 | goto use_legacy; | 1120 | goto use_legacy; |
973 | 1121 | ||
974 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != | 1122 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB); |
975 | MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1); | 1123 | |
1124 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
1125 | if (vht_cap->vht_supported) | ||
1126 | use_vht = vht_cap->vht_mcs.tx_mcs_map != cpu_to_le16(~0); | ||
1127 | else | ||
1128 | #endif | ||
1129 | use_vht = 0; | ||
976 | 1130 | ||
977 | msp->is_ht = true; | 1131 | msp->is_ht = true; |
978 | memset(mi, 0, sizeof(*mi)); | 1132 | memset(mi, 0, sizeof(*mi)); |
@@ -997,22 +1151,28 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
997 | } | 1151 | } |
998 | mi->sample_tries = 4; | 1152 | mi->sample_tries = 4; |
999 | 1153 | ||
1000 | stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >> | 1154 | /* TODO tx_flags for vht - ATM the RC API is not fine-grained enough */ |
1001 | IEEE80211_HT_CAP_RX_STBC_SHIFT; | 1155 | if (!use_vht) { |
1002 | mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; | 1156 | stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >> |
1157 | IEEE80211_HT_CAP_RX_STBC_SHIFT; | ||
1158 | mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; | ||
1003 | 1159 | ||
1004 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) | 1160 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) |
1005 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; | 1161 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; |
1162 | } | ||
1006 | 1163 | ||
1007 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { | 1164 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { |
1165 | u32 gflags = minstrel_mcs_groups[i].flags; | ||
1166 | int bw, nss; | ||
1167 | |||
1008 | mi->groups[i].supported = 0; | 1168 | mi->groups[i].supported = 0; |
1009 | if (i == MINSTREL_CCK_GROUP) { | 1169 | if (i == MINSTREL_CCK_GROUP) { |
1010 | minstrel_ht_update_cck(mp, mi, sband, sta); | 1170 | minstrel_ht_update_cck(mp, mi, sband, sta); |
1011 | continue; | 1171 | continue; |
1012 | } | 1172 | } |
1013 | 1173 | ||
1014 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { | 1174 | if (gflags & IEEE80211_TX_RC_SHORT_GI) { |
1015 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | 1175 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) { |
1016 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) | 1176 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) |
1017 | continue; | 1177 | continue; |
1018 | } else { | 1178 | } else { |
@@ -1021,17 +1181,51 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
1021 | } | 1181 | } |
1022 | } | 1182 | } |
1023 | 1183 | ||
1024 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH && | 1184 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH && |
1025 | sta->bandwidth < IEEE80211_STA_RX_BW_40) | 1185 | sta->bandwidth < IEEE80211_STA_RX_BW_40) |
1026 | continue; | 1186 | continue; |
1027 | 1187 | ||
1188 | nss = minstrel_mcs_groups[i].streams; | ||
1189 | |||
1028 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ | 1190 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ |
1029 | if (sta->smps_mode == IEEE80211_SMPS_STATIC && | 1191 | if (sta->smps_mode == IEEE80211_SMPS_STATIC && nss > 1) |
1030 | minstrel_mcs_groups[i].streams > 1) | 1192 | continue; |
1193 | |||
1194 | /* HT rate */ | ||
1195 | if (gflags & IEEE80211_TX_RC_MCS) { | ||
1196 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
1197 | if (use_vht && minstrel_vht_only) | ||
1198 | continue; | ||
1199 | #endif | ||
1200 | mi->groups[i].supported = mcs->rx_mask[nss - 1]; | ||
1201 | if (mi->groups[i].supported) | ||
1202 | n_supported++; | ||
1031 | continue; | 1203 | continue; |
1204 | } | ||
1205 | |||
1206 | /* VHT rate */ | ||
1207 | if (!vht_cap->vht_supported || | ||
1208 | WARN_ON(!(gflags & IEEE80211_TX_RC_VHT_MCS)) || | ||
1209 | WARN_ON(gflags & IEEE80211_TX_RC_160_MHZ_WIDTH)) | ||
1210 | continue; | ||
1211 | |||
1212 | if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) { | ||
1213 | if (sta->bandwidth < IEEE80211_STA_RX_BW_80 || | ||
1214 | ((gflags & IEEE80211_TX_RC_SHORT_GI) && | ||
1215 | !(vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80))) { | ||
1216 | continue; | ||
1217 | } | ||
1218 | } | ||
1219 | |||
1220 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
1221 | bw = BW_40; | ||
1222 | else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) | ||
1223 | bw = BW_80; | ||
1224 | else | ||
1225 | bw = BW_20; | ||
1032 | 1226 | ||
1033 | mi->groups[i].supported = | 1227 | mi->groups[i].supported = minstrel_get_valid_vht_rates(bw, nss, |
1034 | mcs->rx_mask[minstrel_mcs_groups[i].streams - 1]; | 1228 | vht_cap->vht_mcs.tx_mcs_map); |
1035 | 1229 | ||
1036 | if (mi->groups[i].supported) | 1230 | if (mi->groups[i].supported) |
1037 | n_supported++; | 1231 | n_supported++; |
@@ -1149,7 +1343,7 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta) | |||
1149 | 1343 | ||
1150 | static const struct rate_control_ops mac80211_minstrel_ht = { | 1344 | static const struct rate_control_ops mac80211_minstrel_ht = { |
1151 | .name = "minstrel_ht", | 1345 | .name = "minstrel_ht", |
1152 | .tx_status = minstrel_ht_tx_status, | 1346 | .tx_status_noskb = minstrel_ht_tx_status, |
1153 | .get_rate = minstrel_ht_get_rate, | 1347 | .get_rate = minstrel_ht_get_rate, |
1154 | .rate_init = minstrel_ht_rate_init, | 1348 | .rate_init = minstrel_ht_rate_init, |
1155 | .rate_update = minstrel_ht_rate_update, | 1349 | .rate_update = minstrel_ht_rate_update, |
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 01570e0e014b..f2217d6aa0c2 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
@@ -13,10 +13,32 @@ | |||
13 | * The number of streams can be changed to 2 to reduce code | 13 | * The number of streams can be changed to 2 to reduce code |
14 | * size and memory footprint. | 14 | * size and memory footprint. |
15 | */ | 15 | */ |
16 | #define MINSTREL_MAX_STREAMS 3 | 16 | #define MINSTREL_MAX_STREAMS 3 |
17 | #define MINSTREL_STREAM_GROUPS 4 | 17 | #define MINSTREL_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ |
18 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
19 | #define MINSTREL_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */ | ||
20 | #else | ||
21 | #define MINSTREL_VHT_STREAM_GROUPS 0 | ||
22 | #endif | ||
18 | 23 | ||
19 | #define MCS_GROUP_RATES 8 | 24 | #define MINSTREL_HT_GROUPS_NB (MINSTREL_MAX_STREAMS * \ |
25 | MINSTREL_HT_STREAM_GROUPS) | ||
26 | #define MINSTREL_VHT_GROUPS_NB (MINSTREL_MAX_STREAMS * \ | ||
27 | MINSTREL_VHT_STREAM_GROUPS) | ||
28 | #define MINSTREL_CCK_GROUPS_NB 1 | ||
29 | #define MINSTREL_GROUPS_NB (MINSTREL_HT_GROUPS_NB + \ | ||
30 | MINSTREL_VHT_GROUPS_NB + \ | ||
31 | MINSTREL_CCK_GROUPS_NB) | ||
32 | |||
33 | #define MINSTREL_HT_GROUP_0 0 | ||
34 | #define MINSTREL_CCK_GROUP (MINSTREL_HT_GROUP_0 + MINSTREL_HT_GROUPS_NB) | ||
35 | #define MINSTREL_VHT_GROUP_0 (MINSTREL_CCK_GROUP + 1) | ||
36 | |||
37 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
38 | #define MCS_GROUP_RATES 10 | ||
39 | #else | ||
40 | #define MCS_GROUP_RATES 8 | ||
41 | #endif | ||
20 | 42 | ||
21 | struct mcs_group { | 43 | struct mcs_group { |
22 | u32 flags; | 44 | u32 flags; |
@@ -31,11 +53,11 @@ struct minstrel_mcs_group_data { | |||
31 | u8 column; | 53 | u8 column; |
32 | 54 | ||
33 | /* bitfield of supported MCS rates of this group */ | 55 | /* bitfield of supported MCS rates of this group */ |
34 | u8 supported; | 56 | u16 supported; |
35 | 57 | ||
36 | /* sorted rate set within a MCS group*/ | 58 | /* sorted rate set within a MCS group*/ |
37 | u8 max_group_tp_rate[MAX_THR_RATES]; | 59 | u16 max_group_tp_rate[MAX_THR_RATES]; |
38 | u8 max_group_prob_rate; | 60 | u16 max_group_prob_rate; |
39 | 61 | ||
40 | /* MCS rate statistics */ | 62 | /* MCS rate statistics */ |
41 | struct minstrel_rate_stats rates[MCS_GROUP_RATES]; | 63 | struct minstrel_rate_stats rates[MCS_GROUP_RATES]; |
@@ -52,8 +74,8 @@ struct minstrel_ht_sta { | |||
52 | unsigned int avg_ampdu_len; | 74 | unsigned int avg_ampdu_len; |
53 | 75 | ||
54 | /* overall sorted rate set */ | 76 | /* overall sorted rate set */ |
55 | u8 max_tp_rate[MAX_THR_RATES]; | 77 | u16 max_tp_rate[MAX_THR_RATES]; |
56 | u8 max_prob_rate; | 78 | u16 max_prob_rate; |
57 | 79 | ||
58 | /* time of last status update */ | 80 | /* time of last status update */ |
59 | unsigned long stats_update; | 81 | unsigned long stats_update; |
@@ -80,7 +102,7 @@ struct minstrel_ht_sta { | |||
80 | u8 cck_supported_short; | 102 | u8 cck_supported_short; |
81 | 103 | ||
82 | /* MCS rate group info and statistics */ | 104 | /* MCS rate group info and statistics */ |
83 | struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1]; | 105 | struct minstrel_mcs_group_data groups[MINSTREL_GROUPS_NB]; |
84 | }; | 106 | }; |
85 | 107 | ||
86 | struct minstrel_ht_sta_priv { | 108 | struct minstrel_ht_sta_priv { |
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index a72ad46f2a04..20c676b8e5b6 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c | |||
@@ -18,19 +18,23 @@ | |||
18 | static char * | 18 | static char * |
19 | minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | 19 | minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) |
20 | { | 20 | { |
21 | unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; | ||
22 | const struct mcs_group *mg; | 21 | const struct mcs_group *mg; |
23 | unsigned int j, tp, prob, eprob; | 22 | unsigned int j, tp, prob, eprob; |
24 | char htmode = '2'; | 23 | char htmode = '2'; |
25 | char gimode = 'L'; | 24 | char gimode = 'L'; |
25 | u32 gflags; | ||
26 | 26 | ||
27 | if (!mi->groups[i].supported) | 27 | if (!mi->groups[i].supported) |
28 | return p; | 28 | return p; |
29 | 29 | ||
30 | mg = &minstrel_mcs_groups[i]; | 30 | mg = &minstrel_mcs_groups[i]; |
31 | if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 31 | gflags = mg->flags; |
32 | |||
33 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
32 | htmode = '4'; | 34 | htmode = '4'; |
33 | if (mg->flags & IEEE80211_TX_RC_SHORT_GI) | 35 | else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) |
36 | htmode = '8'; | ||
37 | if (gflags & IEEE80211_TX_RC_SHORT_GI) | ||
34 | gimode = 'S'; | 38 | gimode = 'S'; |
35 | 39 | ||
36 | for (j = 0; j < MCS_GROUP_RATES; j++) { | 40 | for (j = 0; j < MCS_GROUP_RATES; j++) { |
@@ -41,10 +45,12 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | |||
41 | if (!(mi->groups[i].supported & BIT(j))) | 45 | if (!(mi->groups[i].supported & BIT(j))) |
42 | continue; | 46 | continue; |
43 | 47 | ||
44 | if (i == max_mcs) | 48 | if (gflags & IEEE80211_TX_RC_MCS) |
45 | p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S'); | 49 | p += sprintf(p, " HT%c0/%cGI ", htmode, gimode); |
50 | else if (gflags & IEEE80211_TX_RC_VHT_MCS) | ||
51 | p += sprintf(p, "VHT%c0/%cGI ", htmode, gimode); | ||
46 | else | 52 | else |
47 | p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); | 53 | p += sprintf(p, " CCK/%cP ", j < 4 ? 'L' : 'S'); |
48 | 54 | ||
49 | *(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' '; | 55 | *(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' '; |
50 | *(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' '; | 56 | *(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' '; |
@@ -52,19 +58,22 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | |||
52 | *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' '; | 58 | *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' '; |
53 | *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; | 59 | *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; |
54 | 60 | ||
55 | if (i == max_mcs) { | 61 | if (gflags & IEEE80211_TX_RC_MCS) { |
56 | int r = bitrates[j % 4]; | 62 | p += sprintf(p, " MCS%-2u ", (mg->streams - 1) * 8 + j); |
57 | p += sprintf(p, " %2u.%1uM", r / 10, r % 10); | 63 | } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { |
64 | p += sprintf(p, " MCS%-1u/%1u", j, mg->streams); | ||
58 | } else { | 65 | } else { |
59 | p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j); | 66 | int r = bitrates[j % 4]; |
67 | |||
68 | p += sprintf(p, " %2u.%1uM ", r / 10, r % 10); | ||
60 | } | 69 | } |
61 | 70 | ||
62 | tp = mr->cur_tp / 10; | 71 | tp = mr->cur_tp / 10; |
63 | prob = MINSTREL_TRUNC(mr->cur_prob * 1000); | 72 | prob = MINSTREL_TRUNC(mr->cur_prob * 1000); |
64 | eprob = MINSTREL_TRUNC(mr->probability * 1000); | 73 | eprob = MINSTREL_TRUNC(mr->probability * 1000); |
65 | 74 | ||
66 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " | 75 | p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u " |
67 | "%3u %3u(%3u) %8llu %8llu\n", | 76 | "%3u %4u(%4u) %9llu(%9llu)\n", |
68 | tp / 10, tp % 10, | 77 | tp / 10, tp % 10, |
69 | eprob / 10, eprob % 10, | 78 | eprob / 10, eprob % 10, |
70 | prob / 10, prob % 10, | 79 | prob / 10, prob % 10, |
@@ -85,7 +94,6 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
85 | struct minstrel_ht_sta *mi = &msp->ht; | 94 | struct minstrel_ht_sta *mi = &msp->ht; |
86 | struct minstrel_debugfs_info *ms; | 95 | struct minstrel_debugfs_info *ms; |
87 | unsigned int i; | 96 | unsigned int i; |
88 | unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; | ||
89 | char *p; | 97 | char *p; |
90 | int ret; | 98 | int ret; |
91 | 99 | ||
@@ -96,17 +104,19 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
96 | return ret; | 104 | return ret; |
97 | } | 105 | } |
98 | 106 | ||
99 | ms = kmalloc(sizeof(*ms) + 8192, GFP_KERNEL); | 107 | ms = kmalloc(32768, GFP_KERNEL); |
100 | if (!ms) | 108 | if (!ms) |
101 | return -ENOMEM; | 109 | return -ENOMEM; |
102 | 110 | ||
103 | file->private_data = ms; | 111 | file->private_data = ms; |
104 | p = ms->buf; | 112 | p = ms->buf; |
105 | p += sprintf(p, "type rate throughput ewma prob " | 113 | p += sprintf(p, " type rate tpt eprob *prob " |
106 | "this prob retry this succ/attempt success attempts\n"); | 114 | "ret *ok(*cum) ok( cum)\n"); |
107 | 115 | ||
108 | p = minstrel_ht_stats_dump(mi, max_mcs, p); | 116 | p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); |
109 | for (i = 0; i < max_mcs; i++) | 117 | for (i = 0; i < MINSTREL_CCK_GROUP; i++) |
118 | p = minstrel_ht_stats_dump(mi, i, p); | ||
119 | for (i++; i < ARRAY_SIZE(mi->groups); i++) | ||
110 | p = minstrel_ht_stats_dump(mi, i, p); | 120 | p = minstrel_ht_stats_dump(mi, i, p); |
111 | 121 | ||
112 | p += sprintf(p, "\nTotal packet count:: ideal %d " | 122 | p += sprintf(p, "\nTotal packet count:: ideal %d " |
@@ -118,6 +128,8 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
118 | MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); | 128 | MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); |
119 | ms->len = p - ms->buf; | 129 | ms->len = p - ms->buf; |
120 | 130 | ||
131 | WARN_ON(ms->len + sizeof(*ms) > 32768); | ||
132 | |||
121 | return nonseekable_open(inode, file); | 133 | return nonseekable_open(inode, file); |
122 | } | 134 | } |
123 | 135 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b04ca4049c95..49c23bdf08bb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -39,7 +39,8 @@ | |||
39 | * only useful for monitoring. | 39 | * only useful for monitoring. |
40 | */ | 40 | */ |
41 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | 41 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, |
42 | struct sk_buff *skb) | 42 | struct sk_buff *skb, |
43 | unsigned int rtap_vendor_space) | ||
43 | { | 44 | { |
44 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { | 45 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { |
45 | if (likely(skb->len > FCS_LEN)) | 46 | if (likely(skb->len > FCS_LEN)) |
@@ -52,20 +53,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
52 | } | 53 | } |
53 | } | 54 | } |
54 | 55 | ||
56 | __pskb_pull(skb, rtap_vendor_space); | ||
57 | |||
55 | return skb; | 58 | return skb; |
56 | } | 59 | } |
57 | 60 | ||
58 | static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len) | 61 | static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len, |
62 | unsigned int rtap_vendor_space) | ||
59 | { | 63 | { |
60 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 64 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
61 | struct ieee80211_hdr *hdr = (void *)skb->data; | 65 | struct ieee80211_hdr *hdr; |
66 | |||
67 | hdr = (void *)(skb->data + rtap_vendor_space); | ||
62 | 68 | ||
63 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | | 69 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | |
64 | RX_FLAG_FAILED_PLCP_CRC | | 70 | RX_FLAG_FAILED_PLCP_CRC | |
65 | RX_FLAG_AMPDU_IS_ZEROLEN)) | 71 | RX_FLAG_AMPDU_IS_ZEROLEN)) |
66 | return true; | 72 | return true; |
67 | 73 | ||
68 | if (unlikely(skb->len < 16 + present_fcs_len)) | 74 | if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space)) |
69 | return true; | 75 | return true; |
70 | 76 | ||
71 | if (ieee80211_is_ctl(hdr->frame_control) && | 77 | if (ieee80211_is_ctl(hdr->frame_control) && |
@@ -77,8 +83,9 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len) | |||
77 | } | 83 | } |
78 | 84 | ||
79 | static int | 85 | static int |
80 | ieee80211_rx_radiotap_space(struct ieee80211_local *local, | 86 | ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local, |
81 | struct ieee80211_rx_status *status) | 87 | struct ieee80211_rx_status *status, |
88 | struct sk_buff *skb) | ||
82 | { | 89 | { |
83 | int len; | 90 | int len; |
84 | 91 | ||
@@ -121,6 +128,21 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, | |||
121 | len += 2 * hweight8(status->chains); | 128 | len += 2 * hweight8(status->chains); |
122 | } | 129 | } |
123 | 130 | ||
131 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
132 | struct ieee80211_vendor_radiotap *rtap = (void *)skb->data; | ||
133 | |||
134 | /* vendor presence bitmap */ | ||
135 | len += 4; | ||
136 | /* alignment for fixed 6-byte vendor data header */ | ||
137 | len = ALIGN(len, 2); | ||
138 | /* vendor data header */ | ||
139 | len += 6; | ||
140 | if (WARN_ON(rtap->align == 0)) | ||
141 | rtap->align = 1; | ||
142 | len = ALIGN(len, rtap->align); | ||
143 | len += rtap->len + rtap->pad; | ||
144 | } | ||
145 | |||
124 | return len; | 146 | return len; |
125 | } | 147 | } |
126 | 148 | ||
@@ -144,13 +166,20 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
144 | u16 channel_flags = 0; | 166 | u16 channel_flags = 0; |
145 | int mpdulen, chain; | 167 | int mpdulen, chain; |
146 | unsigned long chains = status->chains; | 168 | unsigned long chains = status->chains; |
169 | struct ieee80211_vendor_radiotap rtap = {}; | ||
170 | |||
171 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
172 | rtap = *(struct ieee80211_vendor_radiotap *)skb->data; | ||
173 | /* rtap.len and rtap.pad are undone immediately */ | ||
174 | skb_pull(skb, sizeof(rtap) + rtap.len + rtap.pad); | ||
175 | } | ||
147 | 176 | ||
148 | mpdulen = skb->len; | 177 | mpdulen = skb->len; |
149 | if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) | 178 | if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) |
150 | mpdulen += FCS_LEN; | 179 | mpdulen += FCS_LEN; |
151 | 180 | ||
152 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); | 181 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); |
153 | memset(rthdr, 0, rtap_len); | 182 | memset(rthdr, 0, rtap_len - rtap.len - rtap.pad); |
154 | it_present = &rthdr->it_present; | 183 | it_present = &rthdr->it_present; |
155 | 184 | ||
156 | /* radiotap header, set always present flags */ | 185 | /* radiotap header, set always present flags */ |
@@ -172,6 +201,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
172 | BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); | 201 | BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); |
173 | } | 202 | } |
174 | 203 | ||
204 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
205 | it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | | ||
206 | BIT(IEEE80211_RADIOTAP_EXT); | ||
207 | put_unaligned_le32(it_present_val, it_present); | ||
208 | it_present++; | ||
209 | it_present_val = rtap.present; | ||
210 | } | ||
211 | |||
175 | put_unaligned_le32(it_present_val, it_present); | 212 | put_unaligned_le32(it_present_val, it_present); |
176 | 213 | ||
177 | pos = (void *)(it_present + 1); | 214 | pos = (void *)(it_present + 1); |
@@ -366,6 +403,22 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
366 | *pos++ = status->chain_signal[chain]; | 403 | *pos++ = status->chain_signal[chain]; |
367 | *pos++ = chain; | 404 | *pos++ = chain; |
368 | } | 405 | } |
406 | |||
407 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
408 | /* ensure 2 byte alignment for the vendor field as required */ | ||
409 | if ((pos - (u8 *)rthdr) & 1) | ||
410 | *pos++ = 0; | ||
411 | *pos++ = rtap.oui[0]; | ||
412 | *pos++ = rtap.oui[1]; | ||
413 | *pos++ = rtap.oui[2]; | ||
414 | *pos++ = rtap.subns; | ||
415 | put_unaligned_le16(rtap.len, pos); | ||
416 | pos += 2; | ||
417 | /* align the actual payload as requested */ | ||
418 | while ((pos - (u8 *)rthdr) & (rtap.align - 1)) | ||
419 | *pos++ = 0; | ||
420 | /* data (and possible padding) already follows */ | ||
421 | } | ||
369 | } | 422 | } |
370 | 423 | ||
371 | /* | 424 | /* |
@@ -379,10 +432,17 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
379 | { | 432 | { |
380 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); | 433 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); |
381 | struct ieee80211_sub_if_data *sdata; | 434 | struct ieee80211_sub_if_data *sdata; |
382 | int needed_headroom; | 435 | int rt_hdrlen, needed_headroom; |
383 | struct sk_buff *skb, *skb2; | 436 | struct sk_buff *skb, *skb2; |
384 | struct net_device *prev_dev = NULL; | 437 | struct net_device *prev_dev = NULL; |
385 | int present_fcs_len = 0; | 438 | int present_fcs_len = 0; |
439 | unsigned int rtap_vendor_space = 0; | ||
440 | |||
441 | if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { | ||
442 | struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data; | ||
443 | |||
444 | rtap_vendor_space = sizeof(*rtap) + rtap->len + rtap->pad; | ||
445 | } | ||
386 | 446 | ||
387 | /* | 447 | /* |
388 | * First, we may need to make a copy of the skb because | 448 | * First, we may need to make a copy of the skb because |
@@ -396,25 +456,27 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
396 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 456 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
397 | present_fcs_len = FCS_LEN; | 457 | present_fcs_len = FCS_LEN; |
398 | 458 | ||
399 | /* ensure hdr->frame_control is in skb head */ | 459 | /* ensure hdr->frame_control and vendor radiotap data are in skb head */ |
400 | if (!pskb_may_pull(origskb, 2)) { | 460 | if (!pskb_may_pull(origskb, 2 + rtap_vendor_space)) { |
401 | dev_kfree_skb(origskb); | 461 | dev_kfree_skb(origskb); |
402 | return NULL; | 462 | return NULL; |
403 | } | 463 | } |
404 | 464 | ||
405 | if (!local->monitors) { | 465 | if (!local->monitors) { |
406 | if (should_drop_frame(origskb, present_fcs_len)) { | 466 | if (should_drop_frame(origskb, present_fcs_len, |
467 | rtap_vendor_space)) { | ||
407 | dev_kfree_skb(origskb); | 468 | dev_kfree_skb(origskb); |
408 | return NULL; | 469 | return NULL; |
409 | } | 470 | } |
410 | 471 | ||
411 | return remove_monitor_info(local, origskb); | 472 | return remove_monitor_info(local, origskb, rtap_vendor_space); |
412 | } | 473 | } |
413 | 474 | ||
414 | /* room for the radiotap header based on driver features */ | 475 | /* room for the radiotap header based on driver features */ |
415 | needed_headroom = ieee80211_rx_radiotap_space(local, status); | 476 | rt_hdrlen = ieee80211_rx_radiotap_hdrlen(local, status, origskb); |
477 | needed_headroom = rt_hdrlen - rtap_vendor_space; | ||
416 | 478 | ||
417 | if (should_drop_frame(origskb, present_fcs_len)) { | 479 | if (should_drop_frame(origskb, present_fcs_len, rtap_vendor_space)) { |
418 | /* only need to expand headroom if necessary */ | 480 | /* only need to expand headroom if necessary */ |
419 | skb = origskb; | 481 | skb = origskb; |
420 | origskb = NULL; | 482 | origskb = NULL; |
@@ -438,15 +500,15 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
438 | */ | 500 | */ |
439 | skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); | 501 | skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); |
440 | 502 | ||
441 | origskb = remove_monitor_info(local, origskb); | 503 | origskb = remove_monitor_info(local, origskb, |
504 | rtap_vendor_space); | ||
442 | 505 | ||
443 | if (!skb) | 506 | if (!skb) |
444 | return origskb; | 507 | return origskb; |
445 | } | 508 | } |
446 | 509 | ||
447 | /* prepend radiotap information */ | 510 | /* prepend radiotap information */ |
448 | ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom, | 511 | ieee80211_add_rx_radiotap_header(local, skb, rate, rt_hdrlen, true); |
449 | true); | ||
450 | 512 | ||
451 | skb_reset_mac_header(skb); | 513 | skb_reset_mac_header(skb); |
452 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 514 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
@@ -985,7 +1047,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
985 | } | 1047 | } |
986 | 1048 | ||
987 | static ieee80211_rx_result debug_noinline | 1049 | static ieee80211_rx_result debug_noinline |
988 | ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | 1050 | ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx) |
989 | { | 1051 | { |
990 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1052 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
991 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 1053 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
@@ -994,10 +1056,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
994 | * Drop duplicate 802.11 retransmissions | 1056 | * Drop duplicate 802.11 retransmissions |
995 | * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") | 1057 | * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") |
996 | */ | 1058 | */ |
997 | if (rx->skb->len >= 24 && rx->sta && | 1059 | |
998 | !ieee80211_is_ctl(hdr->frame_control) && | 1060 | if (rx->skb->len < 24) |
999 | !ieee80211_is_qos_nullfunc(hdr->frame_control) && | 1061 | return RX_CONTINUE; |
1000 | !is_multicast_ether_addr(hdr->addr1)) { | 1062 | |
1063 | if (ieee80211_is_ctl(hdr->frame_control) || | ||
1064 | ieee80211_is_qos_nullfunc(hdr->frame_control) || | ||
1065 | is_multicast_ether_addr(hdr->addr1)) | ||
1066 | return RX_CONTINUE; | ||
1067 | |||
1068 | if (rx->sta) { | ||
1001 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && | 1069 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && |
1002 | rx->sta->last_seq_ctrl[rx->seqno_idx] == | 1070 | rx->sta->last_seq_ctrl[rx->seqno_idx] == |
1003 | hdr->seq_ctrl)) { | 1071 | hdr->seq_ctrl)) { |
@@ -1011,6 +1079,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
1011 | } | 1079 | } |
1012 | } | 1080 | } |
1013 | 1081 | ||
1082 | return RX_CONTINUE; | ||
1083 | } | ||
1084 | |||
1085 | static ieee80211_rx_result debug_noinline | ||
1086 | ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | ||
1087 | { | ||
1088 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
1089 | |||
1014 | if (unlikely(rx->skb->len < 16)) { | 1090 | if (unlikely(rx->skb->len < 16)) { |
1015 | I802_DEBUG_INC(rx->local->rx_handlers_drop_short); | 1091 | I802_DEBUG_INC(rx->local->rx_handlers_drop_short); |
1016 | return RX_DROP_MONITOR; | 1092 | return RX_DROP_MONITOR; |
@@ -1032,6 +1108,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
1032 | ieee80211_is_pspoll(hdr->frame_control)) && | 1108 | ieee80211_is_pspoll(hdr->frame_control)) && |
1033 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1109 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && |
1034 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && | 1110 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && |
1111 | rx->sdata->vif.type != NL80211_IFTYPE_OCB && | ||
1035 | (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { | 1112 | (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { |
1036 | /* | 1113 | /* |
1037 | * accept port control frames from the AP even when it's not | 1114 | * accept port control frames from the AP even when it's not |
@@ -1272,6 +1349,12 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1272 | sta->last_rx_rate_vht_nss = status->vht_nss; | 1349 | sta->last_rx_rate_vht_nss = status->vht_nss; |
1273 | } | 1350 | } |
1274 | } | 1351 | } |
1352 | } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) { | ||
1353 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, | ||
1354 | NL80211_IFTYPE_OCB); | ||
1355 | /* OCB uses wild-card BSSID */ | ||
1356 | if (is_broadcast_ether_addr(bssid)) | ||
1357 | sta->last_rx = jiffies; | ||
1275 | } else if (!is_multicast_ether_addr(hdr->addr1)) { | 1358 | } else if (!is_multicast_ether_addr(hdr->addr1)) { |
1276 | /* | 1359 | /* |
1277 | * Mesh beacons will update last_rx when if they are found to | 1360 | * Mesh beacons will update last_rx when if they are found to |
@@ -1678,11 +1761,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1678 | sc = le16_to_cpu(hdr->seq_ctrl); | 1761 | sc = le16_to_cpu(hdr->seq_ctrl); |
1679 | frag = sc & IEEE80211_SCTL_FRAG; | 1762 | frag = sc & IEEE80211_SCTL_FRAG; |
1680 | 1763 | ||
1681 | if (likely((!ieee80211_has_morefrags(fc) && frag == 0) || | 1764 | if (likely(!ieee80211_has_morefrags(fc) && frag == 0)) |
1682 | is_multicast_ether_addr(hdr->addr1))) { | 1765 | goto out; |
1683 | /* not fragmented */ | 1766 | |
1767 | if (is_multicast_ether_addr(hdr->addr1)) { | ||
1768 | rx->local->dot11MulticastReceivedFrameCount++; | ||
1684 | goto out; | 1769 | goto out; |
1685 | } | 1770 | } |
1771 | |||
1686 | I802_DEBUG_INC(rx->local->rx_handlers_fragments); | 1772 | I802_DEBUG_INC(rx->local->rx_handlers_fragments); |
1687 | 1773 | ||
1688 | if (skb_linearize(rx->skb)) | 1774 | if (skb_linearize(rx->skb)) |
@@ -1775,10 +1861,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1775 | out: | 1861 | out: |
1776 | if (rx->sta) | 1862 | if (rx->sta) |
1777 | rx->sta->rx_packets++; | 1863 | rx->sta->rx_packets++; |
1778 | if (is_multicast_ether_addr(hdr->addr1)) | 1864 | ieee80211_led_rx(rx->local); |
1779 | rx->local->dot11MulticastReceivedFrameCount++; | ||
1780 | else | ||
1781 | ieee80211_led_rx(rx->local); | ||
1782 | return RX_CONTINUE; | 1865 | return RX_CONTINUE; |
1783 | } | 1866 | } |
1784 | 1867 | ||
@@ -2250,6 +2333,27 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
2250 | if (!ieee80211_frame_allowed(rx, fc)) | 2333 | if (!ieee80211_frame_allowed(rx, fc)) |
2251 | return RX_DROP_MONITOR; | 2334 | return RX_DROP_MONITOR; |
2252 | 2335 | ||
2336 | /* directly handle TDLS channel switch requests/responses */ | ||
2337 | if (unlikely(((struct ethhdr *)rx->skb->data)->h_proto == | ||
2338 | cpu_to_be16(ETH_P_TDLS))) { | ||
2339 | struct ieee80211_tdls_data *tf = (void *)rx->skb->data; | ||
2340 | |||
2341 | if (pskb_may_pull(rx->skb, | ||
2342 | offsetof(struct ieee80211_tdls_data, u)) && | ||
2343 | tf->payload_type == WLAN_TDLS_SNAP_RFTYPE && | ||
2344 | tf->category == WLAN_CATEGORY_TDLS && | ||
2345 | (tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST || | ||
2346 | tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) { | ||
2347 | rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TDLS_CHSW; | ||
2348 | skb_queue_tail(&sdata->skb_queue, rx->skb); | ||
2349 | ieee80211_queue_work(&rx->local->hw, &sdata->work); | ||
2350 | if (rx->sta) | ||
2351 | rx->sta->rx_packets++; | ||
2352 | |||
2353 | return RX_QUEUED; | ||
2354 | } | ||
2355 | } | ||
2356 | |||
2253 | if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | 2357 | if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && |
2254 | unlikely(port_control) && sdata->bss) { | 2358 | unlikely(port_control) && sdata->bss) { |
2255 | sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, | 2359 | sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, |
@@ -2820,6 +2924,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
2820 | 2924 | ||
2821 | if (!ieee80211_vif_is_mesh(&sdata->vif) && | 2925 | if (!ieee80211_vif_is_mesh(&sdata->vif) && |
2822 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 2926 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
2927 | sdata->vif.type != NL80211_IFTYPE_OCB && | ||
2823 | sdata->vif.type != NL80211_IFTYPE_STATION) | 2928 | sdata->vif.type != NL80211_IFTYPE_STATION) |
2824 | return RX_DROP_MONITOR; | 2929 | return RX_DROP_MONITOR; |
2825 | 2930 | ||
@@ -2884,8 +2989,10 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
2884 | if (!local->cooked_mntrs) | 2989 | if (!local->cooked_mntrs) |
2885 | goto out_free_skb; | 2990 | goto out_free_skb; |
2886 | 2991 | ||
2992 | /* vendor data is long removed here */ | ||
2993 | status->flag &= ~RX_FLAG_RADIOTAP_VENDOR_DATA; | ||
2887 | /* room for the radiotap header based on driver features */ | 2994 | /* room for the radiotap header based on driver features */ |
2888 | needed_headroom = ieee80211_rx_radiotap_space(local, status); | 2995 | needed_headroom = ieee80211_rx_radiotap_hdrlen(local, status, skb); |
2889 | 2996 | ||
2890 | if (skb_headroom(skb) < needed_headroom && | 2997 | if (skb_headroom(skb) < needed_headroom && |
2891 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) | 2998 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) |
@@ -3038,6 +3145,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | |||
3038 | goto rxh_next; \ | 3145 | goto rxh_next; \ |
3039 | } while (0); | 3146 | } while (0); |
3040 | 3147 | ||
3148 | CALL_RXH(ieee80211_rx_h_check_dup) | ||
3041 | CALL_RXH(ieee80211_rx_h_check) | 3149 | CALL_RXH(ieee80211_rx_h_check) |
3042 | 3150 | ||
3043 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); | 3151 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); |
@@ -3130,6 +3238,33 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
3130 | BIT(rate_idx)); | 3238 | BIT(rate_idx)); |
3131 | } | 3239 | } |
3132 | break; | 3240 | break; |
3241 | case NL80211_IFTYPE_OCB: | ||
3242 | if (!bssid) | ||
3243 | return false; | ||
3244 | if (ieee80211_is_beacon(hdr->frame_control)) { | ||
3245 | return false; | ||
3246 | } else if (!is_broadcast_ether_addr(bssid)) { | ||
3247 | ocb_dbg(sdata, "BSSID mismatch in OCB mode!\n"); | ||
3248 | return false; | ||
3249 | } else if (!multicast && | ||
3250 | !ether_addr_equal(sdata->dev->dev_addr, | ||
3251 | hdr->addr1)) { | ||
3252 | /* if we are in promisc mode we also accept | ||
3253 | * packets not destined for us | ||
3254 | */ | ||
3255 | if (!(sdata->dev->flags & IFF_PROMISC)) | ||
3256 | return false; | ||
3257 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | ||
3258 | } else if (!rx->sta) { | ||
3259 | int rate_idx; | ||
3260 | if (status->flag & RX_FLAG_HT) | ||
3261 | rate_idx = 0; /* TODO: HT rates */ | ||
3262 | else | ||
3263 | rate_idx = status->rate_idx; | ||
3264 | ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2, | ||
3265 | BIT(rate_idx)); | ||
3266 | } | ||
3267 | break; | ||
3133 | case NL80211_IFTYPE_MESH_POINT: | 3268 | case NL80211_IFTYPE_MESH_POINT: |
3134 | if (!multicast && | 3269 | if (!multicast && |
3135 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { | 3270 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index af0d094b2f2f..ae842678b629 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -184,9 +184,21 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) | |||
184 | return; | 184 | return; |
185 | 185 | ||
186 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { | 186 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { |
187 | /* ignore ProbeResp to foreign address */ | 187 | struct cfg80211_scan_request *scan_req; |
188 | if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) && | 188 | struct cfg80211_sched_scan_request *sched_scan_req; |
189 | (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr))) | 189 | |
190 | scan_req = rcu_dereference(local->scan_req); | ||
191 | sched_scan_req = rcu_dereference(local->sched_scan_req); | ||
192 | |||
193 | /* ignore ProbeResp to foreign address unless scanning | ||
194 | * with randomised address | ||
195 | */ | ||
196 | if (!(sdata1 && | ||
197 | (ether_addr_equal(mgmt->da, sdata1->vif.addr) || | ||
198 | scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) && | ||
199 | !(sdata2 && | ||
200 | (ether_addr_equal(mgmt->da, sdata2->vif.addr) || | ||
201 | sched_scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))) | ||
190 | return; | 202 | return; |
191 | 203 | ||
192 | elements = mgmt->u.probe_resp.variable; | 204 | elements = mgmt->u.probe_resp.variable; |
@@ -234,11 +246,14 @@ ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef, | |||
234 | /* return false if no more work */ | 246 | /* return false if no more work */ |
235 | static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | 247 | static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) |
236 | { | 248 | { |
237 | struct cfg80211_scan_request *req = local->scan_req; | 249 | struct cfg80211_scan_request *req; |
238 | struct cfg80211_chan_def chandef; | 250 | struct cfg80211_chan_def chandef; |
239 | u8 bands_used = 0; | 251 | u8 bands_used = 0; |
240 | int i, ielen, n_chans; | 252 | int i, ielen, n_chans; |
241 | 253 | ||
254 | req = rcu_dereference_protected(local->scan_req, | ||
255 | lockdep_is_held(&local->mtx)); | ||
256 | |||
242 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) | 257 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) |
243 | return false; | 258 | return false; |
244 | 259 | ||
@@ -281,6 +296,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
281 | bands_used, req->rates, &chandef); | 296 | bands_used, req->rates, &chandef); |
282 | local->hw_scan_req->req.ie_len = ielen; | 297 | local->hw_scan_req->req.ie_len = ielen; |
283 | local->hw_scan_req->req.no_cck = req->no_cck; | 298 | local->hw_scan_req->req.no_cck = req->no_cck; |
299 | ether_addr_copy(local->hw_scan_req->req.mac_addr, req->mac_addr); | ||
300 | ether_addr_copy(local->hw_scan_req->req.mac_addr_mask, | ||
301 | req->mac_addr_mask); | ||
284 | 302 | ||
285 | return true; | 303 | return true; |
286 | } | 304 | } |
@@ -290,6 +308,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
290 | struct ieee80211_local *local = hw_to_local(hw); | 308 | struct ieee80211_local *local = hw_to_local(hw); |
291 | bool hw_scan = local->ops->hw_scan; | 309 | bool hw_scan = local->ops->hw_scan; |
292 | bool was_scanning = local->scanning; | 310 | bool was_scanning = local->scanning; |
311 | struct cfg80211_scan_request *scan_req; | ||
312 | struct ieee80211_sub_if_data *scan_sdata; | ||
293 | 313 | ||
294 | lockdep_assert_held(&local->mtx); | 314 | lockdep_assert_held(&local->mtx); |
295 | 315 | ||
@@ -322,9 +342,15 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
322 | kfree(local->hw_scan_req); | 342 | kfree(local->hw_scan_req); |
323 | local->hw_scan_req = NULL; | 343 | local->hw_scan_req = NULL; |
324 | 344 | ||
325 | if (local->scan_req != local->int_scan_req) | 345 | scan_req = rcu_dereference_protected(local->scan_req, |
326 | cfg80211_scan_done(local->scan_req, aborted); | 346 | lockdep_is_held(&local->mtx)); |
327 | local->scan_req = NULL; | 347 | |
348 | if (scan_req != local->int_scan_req) | ||
349 | cfg80211_scan_done(scan_req, aborted); | ||
350 | RCU_INIT_POINTER(local->scan_req, NULL); | ||
351 | |||
352 | scan_sdata = rcu_dereference_protected(local->scan_sdata, | ||
353 | lockdep_is_held(&local->mtx)); | ||
328 | RCU_INIT_POINTER(local->scan_sdata, NULL); | 354 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
329 | 355 | ||
330 | local->scanning = 0; | 356 | local->scanning = 0; |
@@ -335,7 +361,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
335 | 361 | ||
336 | if (!hw_scan) { | 362 | if (!hw_scan) { |
337 | ieee80211_configure_filter(local); | 363 | ieee80211_configure_filter(local); |
338 | drv_sw_scan_complete(local); | 364 | drv_sw_scan_complete(local, scan_sdata); |
339 | ieee80211_offchannel_return(local); | 365 | ieee80211_offchannel_return(local); |
340 | } | 366 | } |
341 | 367 | ||
@@ -361,7 +387,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
361 | } | 387 | } |
362 | EXPORT_SYMBOL(ieee80211_scan_completed); | 388 | EXPORT_SYMBOL(ieee80211_scan_completed); |
363 | 389 | ||
364 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) | 390 | static int ieee80211_start_sw_scan(struct ieee80211_local *local, |
391 | struct ieee80211_sub_if_data *sdata) | ||
365 | { | 392 | { |
366 | /* Software scan is not supported in multi-channel cases */ | 393 | /* Software scan is not supported in multi-channel cases */ |
367 | if (local->use_chanctx) | 394 | if (local->use_chanctx) |
@@ -380,7 +407,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
380 | * nullfunc frames and probe requests will be dropped in | 407 | * nullfunc frames and probe requests will be dropped in |
381 | * ieee80211_tx_h_check_assoc(). | 408 | * ieee80211_tx_h_check_assoc(). |
382 | */ | 409 | */ |
383 | drv_sw_scan_start(local); | 410 | drv_sw_scan_start(local, sdata, local->scan_addr); |
384 | 411 | ||
385 | local->leave_oper_channel_time = jiffies; | 412 | local->leave_oper_channel_time = jiffies; |
386 | local->next_scan_state = SCAN_DECISION; | 413 | local->next_scan_state = SCAN_DECISION; |
@@ -440,23 +467,26 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
440 | { | 467 | { |
441 | int i; | 468 | int i; |
442 | struct ieee80211_sub_if_data *sdata; | 469 | struct ieee80211_sub_if_data *sdata; |
470 | struct cfg80211_scan_request *scan_req; | ||
443 | enum ieee80211_band band = local->hw.conf.chandef.chan->band; | 471 | enum ieee80211_band band = local->hw.conf.chandef.chan->band; |
444 | u32 tx_flags; | 472 | u32 tx_flags; |
445 | 473 | ||
474 | scan_req = rcu_dereference_protected(local->scan_req, | ||
475 | lockdep_is_held(&local->mtx)); | ||
476 | |||
446 | tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK; | 477 | tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK; |
447 | if (local->scan_req->no_cck) | 478 | if (scan_req->no_cck) |
448 | tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE; | 479 | tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE; |
449 | 480 | ||
450 | sdata = rcu_dereference_protected(local->scan_sdata, | 481 | sdata = rcu_dereference_protected(local->scan_sdata, |
451 | lockdep_is_held(&local->mtx)); | 482 | lockdep_is_held(&local->mtx)); |
452 | 483 | ||
453 | for (i = 0; i < local->scan_req->n_ssids; i++) | 484 | for (i = 0; i < scan_req->n_ssids; i++) |
454 | ieee80211_send_probe_req( | 485 | ieee80211_send_probe_req( |
455 | sdata, NULL, | 486 | sdata, local->scan_addr, NULL, |
456 | local->scan_req->ssids[i].ssid, | 487 | scan_req->ssids[i].ssid, scan_req->ssids[i].ssid_len, |
457 | local->scan_req->ssids[i].ssid_len, | 488 | scan_req->ie, scan_req->ie_len, |
458 | local->scan_req->ie, local->scan_req->ie_len, | 489 | scan_req->rates[band], false, |
459 | local->scan_req->rates[band], false, | ||
460 | tx_flags, local->hw.conf.chandef.chan, true); | 490 | tx_flags, local->hw.conf.chandef.chan, true); |
461 | 491 | ||
462 | /* | 492 | /* |
@@ -480,7 +510,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
480 | 510 | ||
481 | if (!ieee80211_can_scan(local, sdata)) { | 511 | if (!ieee80211_can_scan(local, sdata)) { |
482 | /* wait for the work to finish/time out */ | 512 | /* wait for the work to finish/time out */ |
483 | local->scan_req = req; | 513 | rcu_assign_pointer(local->scan_req, req); |
484 | rcu_assign_pointer(local->scan_sdata, sdata); | 514 | rcu_assign_pointer(local->scan_sdata, sdata); |
485 | return 0; | 515 | return 0; |
486 | } | 516 | } |
@@ -530,9 +560,16 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
530 | */ | 560 | */ |
531 | } | 561 | } |
532 | 562 | ||
533 | local->scan_req = req; | 563 | rcu_assign_pointer(local->scan_req, req); |
534 | rcu_assign_pointer(local->scan_sdata, sdata); | 564 | rcu_assign_pointer(local->scan_sdata, sdata); |
535 | 565 | ||
566 | if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) | ||
567 | get_random_mask_addr(local->scan_addr, | ||
568 | req->mac_addr, | ||
569 | req->mac_addr_mask); | ||
570 | else | ||
571 | memcpy(local->scan_addr, sdata->vif.addr, ETH_ALEN); | ||
572 | |||
536 | if (local->ops->hw_scan) { | 573 | if (local->ops->hw_scan) { |
537 | __set_bit(SCAN_HW_SCANNING, &local->scanning); | 574 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
538 | } else if ((req->n_channels == 1) && | 575 | } else if ((req->n_channels == 1) && |
@@ -549,7 +586,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
549 | 586 | ||
550 | /* Notify driver scan is starting, keep order of operations | 587 | /* Notify driver scan is starting, keep order of operations |
551 | * same as normal software scan, in case that matters. */ | 588 | * same as normal software scan, in case that matters. */ |
552 | drv_sw_scan_start(local); | 589 | drv_sw_scan_start(local, sdata, local->scan_addr); |
553 | 590 | ||
554 | ieee80211_configure_filter(local); /* accept probe-responses */ | 591 | ieee80211_configure_filter(local); /* accept probe-responses */ |
555 | 592 | ||
@@ -558,7 +595,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
558 | 595 | ||
559 | if ((req->channels[0]->flags & | 596 | if ((req->channels[0]->flags & |
560 | IEEE80211_CHAN_NO_IR) || | 597 | IEEE80211_CHAN_NO_IR) || |
561 | !local->scan_req->n_ssids) { | 598 | !req->n_ssids) { |
562 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 599 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
563 | } else { | 600 | } else { |
564 | ieee80211_scan_state_send_probe(local, &next_delay); | 601 | ieee80211_scan_state_send_probe(local, &next_delay); |
@@ -579,8 +616,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
579 | if (local->ops->hw_scan) { | 616 | if (local->ops->hw_scan) { |
580 | WARN_ON(!ieee80211_prep_hw_scan(local)); | 617 | WARN_ON(!ieee80211_prep_hw_scan(local)); |
581 | rc = drv_hw_scan(local, sdata, local->hw_scan_req); | 618 | rc = drv_hw_scan(local, sdata, local->hw_scan_req); |
582 | } else | 619 | } else { |
583 | rc = ieee80211_start_sw_scan(local); | 620 | rc = ieee80211_start_sw_scan(local, sdata); |
621 | } | ||
584 | 622 | ||
585 | if (rc) { | 623 | if (rc) { |
586 | kfree(local->hw_scan_req); | 624 | kfree(local->hw_scan_req); |
@@ -617,6 +655,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
617 | struct ieee80211_sub_if_data *sdata; | 655 | struct ieee80211_sub_if_data *sdata; |
618 | struct ieee80211_channel *next_chan; | 656 | struct ieee80211_channel *next_chan; |
619 | enum mac80211_scan_state next_scan_state; | 657 | enum mac80211_scan_state next_scan_state; |
658 | struct cfg80211_scan_request *scan_req; | ||
620 | 659 | ||
621 | /* | 660 | /* |
622 | * check if at least one STA interface is associated, | 661 | * check if at least one STA interface is associated, |
@@ -641,7 +680,10 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
641 | } | 680 | } |
642 | mutex_unlock(&local->iflist_mtx); | 681 | mutex_unlock(&local->iflist_mtx); |
643 | 682 | ||
644 | next_chan = local->scan_req->channels[local->scan_channel_idx]; | 683 | scan_req = rcu_dereference_protected(local->scan_req, |
684 | lockdep_is_held(&local->mtx)); | ||
685 | |||
686 | next_chan = scan_req->channels[local->scan_channel_idx]; | ||
645 | 687 | ||
646 | /* | 688 | /* |
647 | * we're currently scanning a different channel, let's | 689 | * we're currently scanning a different channel, let's |
@@ -656,7 +698,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
656 | local->leave_oper_channel_time + HZ / 8); | 698 | local->leave_oper_channel_time + HZ / 8); |
657 | 699 | ||
658 | if (associated && !tx_empty) { | 700 | if (associated && !tx_empty) { |
659 | if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) | 701 | if (scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) |
660 | next_scan_state = SCAN_ABORT; | 702 | next_scan_state = SCAN_ABORT; |
661 | else | 703 | else |
662 | next_scan_state = SCAN_SUSPEND; | 704 | next_scan_state = SCAN_SUSPEND; |
@@ -677,14 +719,18 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
677 | int skip; | 719 | int skip; |
678 | struct ieee80211_channel *chan; | 720 | struct ieee80211_channel *chan; |
679 | enum nl80211_bss_scan_width oper_scan_width; | 721 | enum nl80211_bss_scan_width oper_scan_width; |
722 | struct cfg80211_scan_request *scan_req; | ||
723 | |||
724 | scan_req = rcu_dereference_protected(local->scan_req, | ||
725 | lockdep_is_held(&local->mtx)); | ||
680 | 726 | ||
681 | skip = 0; | 727 | skip = 0; |
682 | chan = local->scan_req->channels[local->scan_channel_idx]; | 728 | chan = scan_req->channels[local->scan_channel_idx]; |
683 | 729 | ||
684 | local->scan_chandef.chan = chan; | 730 | local->scan_chandef.chan = chan; |
685 | local->scan_chandef.center_freq1 = chan->center_freq; | 731 | local->scan_chandef.center_freq1 = chan->center_freq; |
686 | local->scan_chandef.center_freq2 = 0; | 732 | local->scan_chandef.center_freq2 = 0; |
687 | switch (local->scan_req->scan_width) { | 733 | switch (scan_req->scan_width) { |
688 | case NL80211_BSS_CHAN_WIDTH_5: | 734 | case NL80211_BSS_CHAN_WIDTH_5: |
689 | local->scan_chandef.width = NL80211_CHAN_WIDTH_5; | 735 | local->scan_chandef.width = NL80211_CHAN_WIDTH_5; |
690 | break; | 736 | break; |
@@ -698,7 +744,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
698 | oper_scan_width = cfg80211_chandef_to_scan_width( | 744 | oper_scan_width = cfg80211_chandef_to_scan_width( |
699 | &local->_oper_chandef); | 745 | &local->_oper_chandef); |
700 | if (chan == local->_oper_chandef.chan && | 746 | if (chan == local->_oper_chandef.chan && |
701 | oper_scan_width == local->scan_req->scan_width) | 747 | oper_scan_width == scan_req->scan_width) |
702 | local->scan_chandef = local->_oper_chandef; | 748 | local->scan_chandef = local->_oper_chandef; |
703 | else | 749 | else |
704 | local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; | 750 | local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; |
@@ -727,8 +773,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
727 | * | 773 | * |
728 | * In any case, it is not necessary for a passive scan. | 774 | * In any case, it is not necessary for a passive scan. |
729 | */ | 775 | */ |
730 | if (chan->flags & IEEE80211_CHAN_NO_IR || | 776 | if (chan->flags & IEEE80211_CHAN_NO_IR || !scan_req->n_ssids) { |
731 | !local->scan_req->n_ssids) { | ||
732 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 777 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
733 | local->next_scan_state = SCAN_DECISION; | 778 | local->next_scan_state = SCAN_DECISION; |
734 | return; | 779 | return; |
@@ -777,6 +822,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
777 | struct ieee80211_local *local = | 822 | struct ieee80211_local *local = |
778 | container_of(work, struct ieee80211_local, scan_work.work); | 823 | container_of(work, struct ieee80211_local, scan_work.work); |
779 | struct ieee80211_sub_if_data *sdata; | 824 | struct ieee80211_sub_if_data *sdata; |
825 | struct cfg80211_scan_request *scan_req; | ||
780 | unsigned long next_delay = 0; | 826 | unsigned long next_delay = 0; |
781 | bool aborted; | 827 | bool aborted; |
782 | 828 | ||
@@ -784,6 +830,8 @@ void ieee80211_scan_work(struct work_struct *work) | |||
784 | 830 | ||
785 | sdata = rcu_dereference_protected(local->scan_sdata, | 831 | sdata = rcu_dereference_protected(local->scan_sdata, |
786 | lockdep_is_held(&local->mtx)); | 832 | lockdep_is_held(&local->mtx)); |
833 | scan_req = rcu_dereference_protected(local->scan_req, | ||
834 | lockdep_is_held(&local->mtx)); | ||
787 | 835 | ||
788 | /* When scanning on-channel, the first-callback means completed. */ | 836 | /* When scanning on-channel, the first-callback means completed. */ |
789 | if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { | 837 | if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { |
@@ -796,20 +844,19 @@ void ieee80211_scan_work(struct work_struct *work) | |||
796 | goto out_complete; | 844 | goto out_complete; |
797 | } | 845 | } |
798 | 846 | ||
799 | if (!sdata || !local->scan_req) | 847 | if (!sdata || !scan_req) |
800 | goto out; | 848 | goto out; |
801 | 849 | ||
802 | if (local->scan_req && !local->scanning) { | 850 | if (!local->scanning) { |
803 | struct cfg80211_scan_request *req = local->scan_req; | ||
804 | int rc; | 851 | int rc; |
805 | 852 | ||
806 | local->scan_req = NULL; | 853 | RCU_INIT_POINTER(local->scan_req, NULL); |
807 | RCU_INIT_POINTER(local->scan_sdata, NULL); | 854 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
808 | 855 | ||
809 | rc = __ieee80211_start_scan(sdata, req); | 856 | rc = __ieee80211_start_scan(sdata, scan_req); |
810 | if (rc) { | 857 | if (rc) { |
811 | /* need to complete scan in cfg80211 */ | 858 | /* need to complete scan in cfg80211 */ |
812 | local->scan_req = req; | 859 | rcu_assign_pointer(local->scan_req, scan_req); |
813 | aborted = true; | 860 | aborted = true; |
814 | goto out_complete; | 861 | goto out_complete; |
815 | } else | 862 | } else |
@@ -829,7 +876,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
829 | switch (local->next_scan_state) { | 876 | switch (local->next_scan_state) { |
830 | case SCAN_DECISION: | 877 | case SCAN_DECISION: |
831 | /* if no more bands/channels left, complete scan */ | 878 | /* if no more bands/channels left, complete scan */ |
832 | if (local->scan_channel_idx >= local->scan_req->n_channels) { | 879 | if (local->scan_channel_idx >= scan_req->n_channels) { |
833 | aborted = false; | 880 | aborted = false; |
834 | goto out_complete; | 881 | goto out_complete; |
835 | } | 882 | } |
@@ -1043,7 +1090,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
1043 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); | 1090 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
1044 | if (ret == 0) { | 1091 | if (ret == 0) { |
1045 | rcu_assign_pointer(local->sched_scan_sdata, sdata); | 1092 | rcu_assign_pointer(local->sched_scan_sdata, sdata); |
1046 | local->sched_scan_req = req; | 1093 | rcu_assign_pointer(local->sched_scan_req, req); |
1047 | } | 1094 | } |
1048 | 1095 | ||
1049 | kfree(ie); | 1096 | kfree(ie); |
@@ -1052,7 +1099,7 @@ out: | |||
1052 | if (ret) { | 1099 | if (ret) { |
1053 | /* Clean in case of failure after HW restart or upon resume. */ | 1100 | /* Clean in case of failure after HW restart or upon resume. */ |
1054 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); | 1101 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); |
1055 | local->sched_scan_req = NULL; | 1102 | RCU_INIT_POINTER(local->sched_scan_req, NULL); |
1056 | } | 1103 | } |
1057 | 1104 | ||
1058 | return ret; | 1105 | return ret; |
@@ -1090,7 +1137,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | |||
1090 | } | 1137 | } |
1091 | 1138 | ||
1092 | /* We don't want to restart sched scan anymore. */ | 1139 | /* We don't want to restart sched scan anymore. */ |
1093 | local->sched_scan_req = NULL; | 1140 | RCU_INIT_POINTER(local->sched_scan_req, NULL); |
1094 | 1141 | ||
1095 | if (rcu_access_pointer(local->sched_scan_sdata)) { | 1142 | if (rcu_access_pointer(local->sched_scan_sdata)) { |
1096 | ret = drv_sched_scan_stop(local, sdata); | 1143 | ret = drv_sched_scan_stop(local, sdata); |
@@ -1125,7 +1172,7 @@ void ieee80211_sched_scan_end(struct ieee80211_local *local) | |||
1125 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); | 1172 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); |
1126 | 1173 | ||
1127 | /* If sched scan was aborted by the driver. */ | 1174 | /* If sched scan was aborted by the driver. */ |
1128 | local->sched_scan_req = NULL; | 1175 | RCU_INIT_POINTER(local->sched_scan_req, NULL); |
1129 | 1176 | ||
1130 | mutex_unlock(&local->mtx); | 1177 | mutex_unlock(&local->mtx); |
1131 | 1178 | ||
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 6ab009070084..efeba56c913b 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include "wme.h" | 22 | #include "wme.h" |
23 | 23 | ||
24 | int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, | 24 | int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, |
25 | struct ieee802_11_elems *elems, bool beacon, | 25 | struct ieee802_11_elems *elems, |
26 | enum ieee80211_band current_band, | 26 | enum ieee80211_band current_band, |
27 | u32 sta_flags, u8 *bssid, | 27 | u32 sta_flags, u8 *bssid, |
28 | struct ieee80211_csa_ie *csa_ie) | 28 | struct ieee80211_csa_ie *csa_ie) |
@@ -91,19 +91,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, | |||
91 | return -EINVAL; | 91 | return -EINVAL; |
92 | } | 92 | } |
93 | 93 | ||
94 | if (!beacon && sec_chan_offs) { | 94 | if (sec_chan_offs) { |
95 | secondary_channel_offset = sec_chan_offs->sec_chan_offs; | 95 | secondary_channel_offset = sec_chan_offs->sec_chan_offs; |
96 | } else if (beacon && ht_oper) { | ||
97 | secondary_channel_offset = | ||
98 | ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||
99 | } else if (!(sta_flags & IEEE80211_STA_DISABLE_HT)) { | 96 | } else if (!(sta_flags & IEEE80211_STA_DISABLE_HT)) { |
100 | /* If it's not a beacon, HT is enabled and the IE not present, | 97 | /* If the secondary channel offset IE is not present, |
101 | * it's 20 MHz, 802.11-2012 8.5.2.6: | 98 | * we can't know what's the post-CSA offset, so the |
102 | * This element [the Secondary Channel Offset Element] is | 99 | * best we can do is use 20MHz. |
103 | * present when switching to a 40 MHz channel. It may be | 100 | */ |
104 | * present when switching to a 20 MHz channel (in which | ||
105 | * case the secondary channel offset is set to SCN). | ||
106 | */ | ||
107 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | 101 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; |
108 | } | 102 | } |
109 | 103 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index de494df3bab8..a42f5b2b024d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -351,6 +351,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
351 | 351 | ||
352 | sta->sta_state = IEEE80211_STA_NONE; | 352 | sta->sta_state = IEEE80211_STA_NONE; |
353 | 353 | ||
354 | /* Mark TID as unreserved */ | ||
355 | sta->reserved_tid = IEEE80211_TID_UNRESERVED; | ||
356 | |||
354 | ktime_get_ts(&uptime); | 357 | ktime_get_ts(&uptime); |
355 | sta->last_connected = uptime.tv_sec; | 358 | sta->last_connected = uptime.tv_sec; |
356 | ewma_init(&sta->avg_signal, 1024, 8); | 359 | ewma_init(&sta->avg_signal, 1024, 8); |
@@ -501,7 +504,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
501 | /* make the station visible */ | 504 | /* make the station visible */ |
502 | sta_info_hash_add(local, sta); | 505 | sta_info_hash_add(local, sta); |
503 | 506 | ||
504 | list_add_rcu(&sta->list, &local->sta_list); | 507 | list_add_tail_rcu(&sta->list, &local->sta_list); |
505 | 508 | ||
506 | /* notify driver */ | 509 | /* notify driver */ |
507 | err = sta_info_insert_drv_state(local, sdata, sta); | 510 | err = sta_info_insert_drv_state(local, sdata, sta); |
@@ -847,6 +850,15 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta) | |||
847 | if (WARN_ON(ret)) | 850 | if (WARN_ON(ret)) |
848 | return ret; | 851 | return ret; |
849 | 852 | ||
853 | /* | ||
854 | * for TDLS peers, make sure to return to the base channel before | ||
855 | * removal. | ||
856 | */ | ||
857 | if (test_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL)) { | ||
858 | drv_tdls_cancel_channel_switch(local, sdata, &sta->sta); | ||
859 | clear_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); | ||
860 | } | ||
861 | |||
850 | list_del_rcu(&sta->list); | 862 | list_del_rcu(&sta->list); |
851 | 863 | ||
852 | drv_sta_pre_rcu_remove(local, sta->sdata, sta); | 864 | drv_sta_pre_rcu_remove(local, sta->sdata, sta); |
@@ -1249,7 +1261,8 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
1249 | return; | 1261 | return; |
1250 | } | 1262 | } |
1251 | 1263 | ||
1252 | ieee80211_xmit(sdata, skb, chanctx_conf->def.chan->band); | 1264 | info->band = chanctx_conf->def.chan->band; |
1265 | ieee80211_xmit(sdata, skb); | ||
1253 | rcu_read_unlock(); | 1266 | rcu_read_unlock(); |
1254 | } | 1267 | } |
1255 | 1268 | ||
@@ -1531,7 +1544,7 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta) | |||
1531 | break; | 1544 | break; |
1532 | case 0: | 1545 | case 0: |
1533 | /* XXX: what is a good value? */ | 1546 | /* XXX: what is a good value? */ |
1534 | n_frames = 8; | 1547 | n_frames = 128; |
1535 | break; | 1548 | break; |
1536 | } | 1549 | } |
1537 | 1550 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 42f68cb8957e..4f052bb2a5ad 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -49,6 +49,9 @@ | |||
49 | * packets. This means the link is enabled. | 49 | * packets. This means the link is enabled. |
50 | * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this | 50 | * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this |
51 | * station. | 51 | * station. |
52 | * @WLAN_STA_TDLS_CHAN_SWITCH: This TDLS peer supports TDLS channel-switching | ||
53 | * @WLAN_STA_TDLS_OFF_CHANNEL: The local STA is currently off-channel with this | ||
54 | * TDLS peer | ||
52 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was | 55 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was |
53 | * keeping station in power-save mode, reply when the driver | 56 | * keeping station in power-save mode, reply when the driver |
54 | * unblocks the station. | 57 | * unblocks the station. |
@@ -78,6 +81,8 @@ enum ieee80211_sta_info_flags { | |||
78 | WLAN_STA_TDLS_PEER, | 81 | WLAN_STA_TDLS_PEER, |
79 | WLAN_STA_TDLS_PEER_AUTH, | 82 | WLAN_STA_TDLS_PEER_AUTH, |
80 | WLAN_STA_TDLS_INITIATOR, | 83 | WLAN_STA_TDLS_INITIATOR, |
84 | WLAN_STA_TDLS_CHAN_SWITCH, | ||
85 | WLAN_STA_TDLS_OFF_CHANNEL, | ||
81 | WLAN_STA_UAPSD, | 86 | WLAN_STA_UAPSD, |
82 | WLAN_STA_SP, | 87 | WLAN_STA_SP, |
83 | WLAN_STA_4ADDR_EVENT, | 88 | WLAN_STA_4ADDR_EVENT, |
@@ -249,6 +254,9 @@ struct ieee80211_tx_latency_stat { | |||
249 | u32 bin_count; | 254 | u32 bin_count; |
250 | }; | 255 | }; |
251 | 256 | ||
257 | /* Value to indicate no TID reservation */ | ||
258 | #define IEEE80211_TID_UNRESERVED 0xff | ||
259 | |||
252 | /** | 260 | /** |
253 | * struct sta_info - STA information | 261 | * struct sta_info - STA information |
254 | * | 262 | * |
@@ -336,6 +344,8 @@ struct ieee80211_tx_latency_stat { | |||
336 | * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for | 344 | * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for |
337 | * AP only. | 345 | * AP only. |
338 | * @cipher_scheme: optional cipher scheme for this station | 346 | * @cipher_scheme: optional cipher scheme for this station |
347 | * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed | ||
348 | * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) | ||
339 | */ | 349 | */ |
340 | struct sta_info { | 350 | struct sta_info { |
341 | /* General information, mostly static */ | 351 | /* General information, mostly static */ |
@@ -453,6 +463,8 @@ struct sta_info { | |||
453 | /* TDLS timeout data */ | 463 | /* TDLS timeout data */ |
454 | unsigned long last_tdls_pkt_time; | 464 | unsigned long last_tdls_pkt_time; |
455 | 465 | ||
466 | u8 reserved_tid; | ||
467 | |||
456 | /* keep last! */ | 468 | /* keep last! */ |
457 | struct ieee80211_sta sta; | 469 | struct ieee80211_sta sta; |
458 | }; | 470 | }; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 89290e33dafe..bb146f377ee4 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -390,6 +390,46 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_local *local, | |||
390 | } | 390 | } |
391 | } | 391 | } |
392 | 392 | ||
393 | /* | ||
394 | * Handles the tx for TDLS teardown frames. | ||
395 | * If the frame wasn't ACKed by the peer - it will be re-sent through the AP | ||
396 | */ | ||
397 | static void ieee80211_tdls_td_tx_handle(struct ieee80211_local *local, | ||
398 | struct ieee80211_sub_if_data *sdata, | ||
399 | struct sk_buff *skb, u32 flags) | ||
400 | { | ||
401 | struct sk_buff *teardown_skb; | ||
402 | struct sk_buff *orig_teardown_skb; | ||
403 | bool is_teardown = false; | ||
404 | |||
405 | /* Get the teardown data we need and free the lock */ | ||
406 | spin_lock(&sdata->u.mgd.teardown_lock); | ||
407 | teardown_skb = sdata->u.mgd.teardown_skb; | ||
408 | orig_teardown_skb = sdata->u.mgd.orig_teardown_skb; | ||
409 | if ((skb == orig_teardown_skb) && teardown_skb) { | ||
410 | sdata->u.mgd.teardown_skb = NULL; | ||
411 | sdata->u.mgd.orig_teardown_skb = NULL; | ||
412 | is_teardown = true; | ||
413 | } | ||
414 | spin_unlock(&sdata->u.mgd.teardown_lock); | ||
415 | |||
416 | if (is_teardown) { | ||
417 | /* This mechanism relies on being able to get ACKs */ | ||
418 | WARN_ON(!(local->hw.flags & | ||
419 | IEEE80211_HW_REPORTS_TX_ACK_STATUS)); | ||
420 | |||
421 | /* Check if peer has ACKed */ | ||
422 | if (flags & IEEE80211_TX_STAT_ACK) { | ||
423 | dev_kfree_skb_any(teardown_skb); | ||
424 | } else { | ||
425 | tdls_dbg(sdata, | ||
426 | "TDLS Resending teardown through AP\n"); | ||
427 | |||
428 | ieee80211_subif_start_xmit(teardown_skb, skb->dev); | ||
429 | } | ||
430 | } | ||
431 | } | ||
432 | |||
393 | static void ieee80211_report_used_skb(struct ieee80211_local *local, | 433 | static void ieee80211_report_used_skb(struct ieee80211_local *local, |
394 | struct sk_buff *skb, bool dropped) | 434 | struct sk_buff *skb, bool dropped) |
395 | { | 435 | { |
@@ -426,8 +466,19 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, | |||
426 | if (!sdata) { | 466 | if (!sdata) { |
427 | skb->dev = NULL; | 467 | skb->dev = NULL; |
428 | } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) { | 468 | } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) { |
429 | ieee80211_mgd_conn_tx_status(sdata, hdr->frame_control, | 469 | unsigned int hdr_size = |
430 | acked); | 470 | ieee80211_hdrlen(hdr->frame_control); |
471 | |||
472 | /* Check to see if packet is a TDLS teardown packet */ | ||
473 | if (ieee80211_is_data(hdr->frame_control) && | ||
474 | (ieee80211_get_tdls_action(skb, hdr_size) == | ||
475 | WLAN_TDLS_TEARDOWN)) | ||
476 | ieee80211_tdls_td_tx_handle(local, sdata, skb, | ||
477 | info->flags); | ||
478 | else | ||
479 | ieee80211_mgd_conn_tx_status(sdata, | ||
480 | hdr->frame_control, | ||
481 | acked); | ||
431 | } else if (ieee80211_is_nullfunc(hdr->frame_control) || | 482 | } else if (ieee80211_is_nullfunc(hdr->frame_control) || |
432 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | 483 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { |
433 | cfg80211_probe_status(sdata->dev, hdr->addr1, | 484 | cfg80211_probe_status(sdata->dev, hdr->addr1, |
@@ -541,10 +592,9 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, | |||
541 | #define STA_LOST_TDLS_PKT_THRESHOLD 10 | 592 | #define STA_LOST_TDLS_PKT_THRESHOLD 10 |
542 | #define STA_LOST_TDLS_PKT_TIME (10*HZ) /* 10secs since last ACK */ | 593 | #define STA_LOST_TDLS_PKT_TIME (10*HZ) /* 10secs since last ACK */ |
543 | 594 | ||
544 | static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb) | 595 | static void ieee80211_lost_packet(struct sta_info *sta, |
596 | struct ieee80211_tx_info *info) | ||
545 | { | 597 | { |
546 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
547 | |||
548 | /* This packet was aggregated but doesn't carry status info */ | 598 | /* This packet was aggregated but doesn't carry status info */ |
549 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | 599 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && |
550 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) | 600 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) |
@@ -571,24 +621,13 @@ static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb) | |||
571 | sta->lost_packets = 0; | 621 | sta->lost_packets = 0; |
572 | } | 622 | } |
573 | 623 | ||
574 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | 624 | static int ieee80211_tx_get_rates(struct ieee80211_hw *hw, |
625 | struct ieee80211_tx_info *info, | ||
626 | int *retry_count) | ||
575 | { | 627 | { |
576 | struct sk_buff *skb2; | ||
577 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
578 | struct ieee80211_local *local = hw_to_local(hw); | ||
579 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
580 | __le16 fc; | ||
581 | struct ieee80211_supported_band *sband; | ||
582 | struct ieee80211_sub_if_data *sdata; | ||
583 | struct net_device *prev_dev = NULL; | ||
584 | struct sta_info *sta, *tmp; | ||
585 | int retry_count = -1, i; | ||
586 | int rates_idx = -1; | 628 | int rates_idx = -1; |
587 | bool send_to_cooked; | 629 | int count = -1; |
588 | bool acked; | 630 | int i; |
589 | struct ieee80211_bar *bar; | ||
590 | int rtap_len; | ||
591 | int shift = 0; | ||
592 | 631 | ||
593 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 632 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
594 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | 633 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && |
@@ -606,12 +645,91 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
606 | break; | 645 | break; |
607 | } | 646 | } |
608 | 647 | ||
609 | retry_count += info->status.rates[i].count; | 648 | count += info->status.rates[i].count; |
610 | } | 649 | } |
611 | rates_idx = i - 1; | 650 | rates_idx = i - 1; |
612 | 651 | ||
613 | if (retry_count < 0) | 652 | if (count < 0) |
614 | retry_count = 0; | 653 | count = 0; |
654 | |||
655 | *retry_count = count; | ||
656 | return rates_idx; | ||
657 | } | ||
658 | |||
659 | void ieee80211_tx_status_noskb(struct ieee80211_hw *hw, | ||
660 | struct ieee80211_sta *pubsta, | ||
661 | struct ieee80211_tx_info *info) | ||
662 | { | ||
663 | struct ieee80211_local *local = hw_to_local(hw); | ||
664 | struct ieee80211_supported_band *sband; | ||
665 | int retry_count; | ||
666 | int rates_idx; | ||
667 | bool acked; | ||
668 | |||
669 | rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); | ||
670 | |||
671 | sband = hw->wiphy->bands[info->band]; | ||
672 | |||
673 | acked = !!(info->flags & IEEE80211_TX_STAT_ACK); | ||
674 | if (pubsta) { | ||
675 | struct sta_info *sta; | ||
676 | |||
677 | sta = container_of(pubsta, struct sta_info, sta); | ||
678 | |||
679 | if (!acked) | ||
680 | sta->tx_retry_failed++; | ||
681 | sta->tx_retry_count += retry_count; | ||
682 | |||
683 | if (acked) { | ||
684 | sta->last_rx = jiffies; | ||
685 | |||
686 | if (sta->lost_packets) | ||
687 | sta->lost_packets = 0; | ||
688 | |||
689 | /* Track when last TDLS packet was ACKed */ | ||
690 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) | ||
691 | sta->last_tdls_pkt_time = jiffies; | ||
692 | } else { | ||
693 | ieee80211_lost_packet(sta, info); | ||
694 | } | ||
695 | |||
696 | rate_control_tx_status_noskb(local, sband, sta, info); | ||
697 | } | ||
698 | |||
699 | if (acked) { | ||
700 | local->dot11TransmittedFrameCount++; | ||
701 | if (!pubsta) | ||
702 | local->dot11MulticastTransmittedFrameCount++; | ||
703 | if (retry_count > 0) | ||
704 | local->dot11RetryCount++; | ||
705 | if (retry_count > 1) | ||
706 | local->dot11MultipleRetryCount++; | ||
707 | } else { | ||
708 | local->dot11FailedCount++; | ||
709 | } | ||
710 | } | ||
711 | EXPORT_SYMBOL(ieee80211_tx_status_noskb); | ||
712 | |||
713 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
714 | { | ||
715 | struct sk_buff *skb2; | ||
716 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
717 | struct ieee80211_local *local = hw_to_local(hw); | ||
718 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
719 | __le16 fc; | ||
720 | struct ieee80211_supported_band *sband; | ||
721 | struct ieee80211_sub_if_data *sdata; | ||
722 | struct net_device *prev_dev = NULL; | ||
723 | struct sta_info *sta, *tmp; | ||
724 | int retry_count; | ||
725 | int rates_idx; | ||
726 | bool send_to_cooked; | ||
727 | bool acked; | ||
728 | struct ieee80211_bar *bar; | ||
729 | int rtap_len; | ||
730 | int shift = 0; | ||
731 | |||
732 | rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); | ||
615 | 733 | ||
616 | rcu_read_lock(); | 734 | rcu_read_lock(); |
617 | 735 | ||
@@ -704,7 +822,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
704 | 822 | ||
705 | if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && | 823 | if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && |
706 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) | 824 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) |
707 | ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked); | 825 | ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, |
826 | acked, info->status.tx_time); | ||
708 | 827 | ||
709 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | 828 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { |
710 | if (info->flags & IEEE80211_TX_STAT_ACK) { | 829 | if (info->flags & IEEE80211_TX_STAT_ACK) { |
@@ -715,7 +834,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
715 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) | 834 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) |
716 | sta->last_tdls_pkt_time = jiffies; | 835 | sta->last_tdls_pkt_time = jiffies; |
717 | } else { | 836 | } else { |
718 | ieee80211_lost_packet(sta, skb); | 837 | ieee80211_lost_packet(sta, info); |
719 | } | 838 | } |
720 | } | 839 | } |
721 | 840 | ||
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 4ea25dec0698..55ddd77b865d 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
@@ -35,19 +35,101 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk) | |||
35 | mutex_unlock(&local->mtx); | 35 | mutex_unlock(&local->mtx); |
36 | } | 36 | } |
37 | 37 | ||
38 | static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) | 38 | static void ieee80211_tdls_add_ext_capab(struct ieee80211_local *local, |
39 | struct sk_buff *skb) | ||
39 | { | 40 | { |
40 | u8 *pos = (void *)skb_put(skb, 7); | 41 | u8 *pos = (void *)skb_put(skb, 7); |
42 | bool chan_switch = local->hw.wiphy->features & | ||
43 | NL80211_FEATURE_TDLS_CHANNEL_SWITCH; | ||
41 | 44 | ||
42 | *pos++ = WLAN_EID_EXT_CAPABILITY; | 45 | *pos++ = WLAN_EID_EXT_CAPABILITY; |
43 | *pos++ = 5; /* len */ | 46 | *pos++ = 5; /* len */ |
44 | *pos++ = 0x0; | 47 | *pos++ = 0x0; |
45 | *pos++ = 0x0; | 48 | *pos++ = 0x0; |
46 | *pos++ = 0x0; | 49 | *pos++ = 0x0; |
47 | *pos++ = 0x0; | 50 | *pos++ = chan_switch ? WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH : 0; |
48 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; | 51 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; |
49 | } | 52 | } |
50 | 53 | ||
54 | static u8 | ||
55 | ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata, | ||
56 | struct sk_buff *skb, u16 start, u16 end, | ||
57 | u16 spacing) | ||
58 | { | ||
59 | u8 subband_cnt = 0, ch_cnt = 0; | ||
60 | struct ieee80211_channel *ch; | ||
61 | struct cfg80211_chan_def chandef; | ||
62 | int i, subband_start; | ||
63 | |||
64 | for (i = start; i <= end; i += spacing) { | ||
65 | if (!ch_cnt) | ||
66 | subband_start = i; | ||
67 | |||
68 | ch = ieee80211_get_channel(sdata->local->hw.wiphy, i); | ||
69 | if (ch) { | ||
70 | /* we will be active on the channel */ | ||
71 | u32 flags = IEEE80211_CHAN_DISABLED | | ||
72 | IEEE80211_CHAN_NO_IR; | ||
73 | cfg80211_chandef_create(&chandef, ch, | ||
74 | NL80211_CHAN_HT20); | ||
75 | if (cfg80211_chandef_usable(sdata->local->hw.wiphy, | ||
76 | &chandef, flags)) { | ||
77 | ch_cnt++; | ||
78 | continue; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | if (ch_cnt) { | ||
83 | u8 *pos = skb_put(skb, 2); | ||
84 | *pos++ = ieee80211_frequency_to_channel(subband_start); | ||
85 | *pos++ = ch_cnt; | ||
86 | |||
87 | subband_cnt++; | ||
88 | ch_cnt = 0; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | return subband_cnt; | ||
93 | } | ||
94 | |||
95 | static void | ||
96 | ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata, | ||
97 | struct sk_buff *skb) | ||
98 | { | ||
99 | /* | ||
100 | * Add possible channels for TDLS. These are channels that are allowed | ||
101 | * to be active. | ||
102 | */ | ||
103 | u8 subband_cnt; | ||
104 | u8 *pos = skb_put(skb, 2); | ||
105 | |||
106 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
107 | |||
108 | /* | ||
109 | * 5GHz and 2GHz channels numbers can overlap. Ignore this for now, as | ||
110 | * this doesn't happen in real world scenarios. | ||
111 | */ | ||
112 | |||
113 | /* 2GHz, with 5MHz spacing */ | ||
114 | subband_cnt = ieee80211_tdls_add_subband(sdata, skb, 2412, 2472, 5); | ||
115 | |||
116 | /* 5GHz, with 20MHz spacing */ | ||
117 | subband_cnt += ieee80211_tdls_add_subband(sdata, skb, 5000, 5825, 20); | ||
118 | |||
119 | /* length */ | ||
120 | *pos = 2 * subband_cnt; | ||
121 | } | ||
122 | |||
123 | static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) | ||
124 | { | ||
125 | u8 *pos = (void *)skb_put(skb, 3); | ||
126 | |||
127 | *pos++ = WLAN_EID_BSS_COEX_2040; | ||
128 | *pos++ = 1; /* len */ | ||
129 | |||
130 | *pos++ = WLAN_BSS_COEX_INFORMATION_REQUEST; | ||
131 | } | ||
132 | |||
51 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, | 133 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, |
52 | u16 status_code) | 134 | u16 status_code) |
53 | { | 135 | { |
@@ -190,6 +272,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
190 | 272 | ||
191 | ieee80211_add_srates_ie(sdata, skb, false, band); | 273 | ieee80211_add_srates_ie(sdata, skb, false, band); |
192 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | 274 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); |
275 | ieee80211_tdls_add_supp_channels(sdata, skb); | ||
193 | 276 | ||
194 | /* add any custom IEs that go before Extended Capabilities */ | 277 | /* add any custom IEs that go before Extended Capabilities */ |
195 | if (extra_ies_len) { | 278 | if (extra_ies_len) { |
@@ -209,7 +292,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
209 | offset = noffset; | 292 | offset = noffset; |
210 | } | 293 | } |
211 | 294 | ||
212 | ieee80211_tdls_add_ext_capab(skb); | 295 | ieee80211_tdls_add_ext_capab(local, skb); |
213 | 296 | ||
214 | /* add the QoS element if we support it */ | 297 | /* add the QoS element if we support it */ |
215 | if (local->hw.queues >= IEEE80211_NUM_ACS && | 298 | if (local->hw.queues >= IEEE80211_NUM_ACS && |
@@ -271,6 +354,10 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
271 | 354 | ||
272 | rcu_read_unlock(); | 355 | rcu_read_unlock(); |
273 | 356 | ||
357 | if (ht_cap.ht_supported && | ||
358 | (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
359 | ieee80211_tdls_add_bss_coex_ie(skb); | ||
360 | |||
274 | /* add any remaining IEs */ | 361 | /* add any remaining IEs */ |
275 | if (extra_ies_len) { | 362 | if (extra_ies_len) { |
276 | noffset = extra_ies_len; | 363 | noffset = extra_ies_len; |
@@ -362,11 +449,68 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | |||
362 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | 449 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); |
363 | } | 450 | } |
364 | 451 | ||
452 | static void | ||
453 | ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata, | ||
454 | struct sk_buff *skb, const u8 *peer, | ||
455 | bool initiator, const u8 *extra_ies, | ||
456 | size_t extra_ies_len, u8 oper_class, | ||
457 | struct cfg80211_chan_def *chandef) | ||
458 | { | ||
459 | struct ieee80211_tdls_data *tf; | ||
460 | size_t offset = 0, noffset; | ||
461 | u8 *pos; | ||
462 | |||
463 | if (WARN_ON_ONCE(!chandef)) | ||
464 | return; | ||
465 | |||
466 | tf = (void *)skb->data; | ||
467 | tf->u.chan_switch_req.target_channel = | ||
468 | ieee80211_frequency_to_channel(chandef->chan->center_freq); | ||
469 | tf->u.chan_switch_req.oper_class = oper_class; | ||
470 | |||
471 | if (extra_ies_len) { | ||
472 | static const u8 before_lnkie[] = { | ||
473 | WLAN_EID_SECONDARY_CHANNEL_OFFSET, | ||
474 | }; | ||
475 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
476 | before_lnkie, | ||
477 | ARRAY_SIZE(before_lnkie), | ||
478 | offset); | ||
479 | pos = skb_put(skb, noffset - offset); | ||
480 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
481 | offset = noffset; | ||
482 | } | ||
483 | |||
484 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
485 | |||
486 | /* add any remaining IEs */ | ||
487 | if (extra_ies_len) { | ||
488 | noffset = extra_ies_len; | ||
489 | pos = skb_put(skb, noffset - offset); | ||
490 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
491 | } | ||
492 | } | ||
493 | |||
494 | static void | ||
495 | ieee80211_tdls_add_chan_switch_resp_ies(struct ieee80211_sub_if_data *sdata, | ||
496 | struct sk_buff *skb, const u8 *peer, | ||
497 | u16 status_code, bool initiator, | ||
498 | const u8 *extra_ies, | ||
499 | size_t extra_ies_len) | ||
500 | { | ||
501 | if (status_code == 0) | ||
502 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
503 | |||
504 | if (extra_ies_len) | ||
505 | memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); | ||
506 | } | ||
507 | |||
365 | static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, | 508 | static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, |
366 | struct sk_buff *skb, const u8 *peer, | 509 | struct sk_buff *skb, const u8 *peer, |
367 | u8 action_code, u16 status_code, | 510 | u8 action_code, u16 status_code, |
368 | bool initiator, const u8 *extra_ies, | 511 | bool initiator, const u8 *extra_ies, |
369 | size_t extra_ies_len) | 512 | size_t extra_ies_len, u8 oper_class, |
513 | struct cfg80211_chan_def *chandef) | ||
370 | { | 514 | { |
371 | switch (action_code) { | 515 | switch (action_code) { |
372 | case WLAN_TDLS_SETUP_REQUEST: | 516 | case WLAN_TDLS_SETUP_REQUEST: |
@@ -393,6 +537,18 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, | |||
393 | if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) | 537 | if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) |
394 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | 538 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); |
395 | break; | 539 | break; |
540 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
541 | ieee80211_tdls_add_chan_switch_req_ies(sdata, skb, peer, | ||
542 | initiator, extra_ies, | ||
543 | extra_ies_len, | ||
544 | oper_class, chandef); | ||
545 | break; | ||
546 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
547 | ieee80211_tdls_add_chan_switch_resp_ies(sdata, skb, peer, | ||
548 | status_code, | ||
549 | initiator, extra_ies, | ||
550 | extra_ies_len); | ||
551 | break; | ||
396 | } | 552 | } |
397 | 553 | ||
398 | } | 554 | } |
@@ -459,6 +615,19 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
459 | skb_put(skb, sizeof(tf->u.discover_req)); | 615 | skb_put(skb, sizeof(tf->u.discover_req)); |
460 | tf->u.discover_req.dialog_token = dialog_token; | 616 | tf->u.discover_req.dialog_token = dialog_token; |
461 | break; | 617 | break; |
618 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
619 | tf->category = WLAN_CATEGORY_TDLS; | ||
620 | tf->action_code = WLAN_TDLS_CHANNEL_SWITCH_REQUEST; | ||
621 | |||
622 | skb_put(skb, sizeof(tf->u.chan_switch_req)); | ||
623 | break; | ||
624 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
625 | tf->category = WLAN_CATEGORY_TDLS; | ||
626 | tf->action_code = WLAN_TDLS_CHANNEL_SWITCH_RESPONSE; | ||
627 | |||
628 | skb_put(skb, sizeof(tf->u.chan_switch_resp)); | ||
629 | tf->u.chan_switch_resp.status_code = cpu_to_le16(status_code); | ||
630 | break; | ||
462 | default: | 631 | default: |
463 | return -EINVAL; | 632 | return -EINVAL; |
464 | } | 633 | } |
@@ -502,32 +671,33 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
502 | return 0; | 671 | return 0; |
503 | } | 672 | } |
504 | 673 | ||
505 | static int | 674 | static struct sk_buff * |
506 | ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | 675 | ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, |
507 | const u8 *peer, u8 action_code, | 676 | const u8 *peer, u8 action_code, |
508 | u8 dialog_token, u16 status_code, | 677 | u8 dialog_token, u16 status_code, |
509 | u32 peer_capability, bool initiator, | 678 | bool initiator, const u8 *extra_ies, |
510 | const u8 *extra_ies, size_t extra_ies_len) | 679 | size_t extra_ies_len, u8 oper_class, |
680 | struct cfg80211_chan_def *chandef) | ||
511 | { | 681 | { |
512 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
513 | struct ieee80211_local *local = sdata->local; | 682 | struct ieee80211_local *local = sdata->local; |
514 | struct sk_buff *skb = NULL; | 683 | struct sk_buff *skb; |
515 | bool send_direct; | ||
516 | struct sta_info *sta; | ||
517 | int ret; | 684 | int ret; |
518 | 685 | ||
519 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 686 | skb = netdev_alloc_skb(sdata->dev, |
520 | max(sizeof(struct ieee80211_mgmt), | 687 | local->hw.extra_tx_headroom + |
521 | sizeof(struct ieee80211_tdls_data)) + | 688 | max(sizeof(struct ieee80211_mgmt), |
522 | 50 + /* supported rates */ | 689 | sizeof(struct ieee80211_tdls_data)) + |
523 | 7 + /* ext capab */ | 690 | 50 + /* supported rates */ |
524 | 26 + /* max(WMM-info, WMM-param) */ | 691 | 7 + /* ext capab */ |
525 | 2 + max(sizeof(struct ieee80211_ht_cap), | 692 | 26 + /* max(WMM-info, WMM-param) */ |
526 | sizeof(struct ieee80211_ht_operation)) + | 693 | 2 + max(sizeof(struct ieee80211_ht_cap), |
527 | extra_ies_len + | 694 | sizeof(struct ieee80211_ht_operation)) + |
528 | sizeof(struct ieee80211_tdls_lnkie)); | 695 | 50 + /* supported channels */ |
696 | 3 + /* 40/20 BSS coex */ | ||
697 | extra_ies_len + | ||
698 | sizeof(struct ieee80211_tdls_lnkie)); | ||
529 | if (!skb) | 699 | if (!skb) |
530 | return -ENOMEM; | 700 | return NULL; |
531 | 701 | ||
532 | skb_reserve(skb, local->hw.extra_tx_headroom); | 702 | skb_reserve(skb, local->hw.extra_tx_headroom); |
533 | 703 | ||
@@ -537,16 +707,18 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
537 | case WLAN_TDLS_SETUP_CONFIRM: | 707 | case WLAN_TDLS_SETUP_CONFIRM: |
538 | case WLAN_TDLS_TEARDOWN: | 708 | case WLAN_TDLS_TEARDOWN: |
539 | case WLAN_TDLS_DISCOVERY_REQUEST: | 709 | case WLAN_TDLS_DISCOVERY_REQUEST: |
540 | ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer, | 710 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: |
711 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
712 | ret = ieee80211_prep_tdls_encap_data(local->hw.wiphy, | ||
713 | sdata->dev, peer, | ||
541 | action_code, dialog_token, | 714 | action_code, dialog_token, |
542 | status_code, skb); | 715 | status_code, skb); |
543 | send_direct = false; | ||
544 | break; | 716 | break; |
545 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | 717 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: |
546 | ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code, | 718 | ret = ieee80211_prep_tdls_direct(local->hw.wiphy, sdata->dev, |
719 | peer, action_code, | ||
547 | dialog_token, status_code, | 720 | dialog_token, status_code, |
548 | skb); | 721 | skb); |
549 | send_direct = true; | ||
550 | break; | 722 | break; |
551 | default: | 723 | default: |
552 | ret = -ENOTSUPP; | 724 | ret = -ENOTSUPP; |
@@ -556,14 +728,40 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
556 | if (ret < 0) | 728 | if (ret < 0) |
557 | goto fail; | 729 | goto fail; |
558 | 730 | ||
731 | ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, | ||
732 | initiator, extra_ies, extra_ies_len, oper_class, | ||
733 | chandef); | ||
734 | return skb; | ||
735 | |||
736 | fail: | ||
737 | dev_kfree_skb(skb); | ||
738 | return NULL; | ||
739 | } | ||
740 | |||
741 | static int | ||
742 | ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | ||
743 | const u8 *peer, u8 action_code, u8 dialog_token, | ||
744 | u16 status_code, u32 peer_capability, | ||
745 | bool initiator, const u8 *extra_ies, | ||
746 | size_t extra_ies_len, u8 oper_class, | ||
747 | struct cfg80211_chan_def *chandef) | ||
748 | { | ||
749 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
750 | struct sk_buff *skb = NULL; | ||
751 | struct sta_info *sta; | ||
752 | u32 flags = 0; | ||
753 | int ret = 0; | ||
754 | |||
559 | rcu_read_lock(); | 755 | rcu_read_lock(); |
560 | sta = sta_info_get(sdata, peer); | 756 | sta = sta_info_get(sdata, peer); |
561 | 757 | ||
562 | /* infer the initiator if we can, to support old userspace */ | 758 | /* infer the initiator if we can, to support old userspace */ |
563 | switch (action_code) { | 759 | switch (action_code) { |
564 | case WLAN_TDLS_SETUP_REQUEST: | 760 | case WLAN_TDLS_SETUP_REQUEST: |
565 | if (sta) | 761 | if (sta) { |
566 | set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); | 762 | set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); |
763 | sta->sta.tdls_initiator = false; | ||
764 | } | ||
567 | /* fall-through */ | 765 | /* fall-through */ |
568 | case WLAN_TDLS_SETUP_CONFIRM: | 766 | case WLAN_TDLS_SETUP_CONFIRM: |
569 | case WLAN_TDLS_DISCOVERY_REQUEST: | 767 | case WLAN_TDLS_DISCOVERY_REQUEST: |
@@ -575,13 +773,17 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
575 | * Make the last packet sent take effect for the initiator | 773 | * Make the last packet sent take effect for the initiator |
576 | * value. | 774 | * value. |
577 | */ | 775 | */ |
578 | if (sta) | 776 | if (sta) { |
579 | clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); | 777 | clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); |
778 | sta->sta.tdls_initiator = true; | ||
779 | } | ||
580 | /* fall-through */ | 780 | /* fall-through */ |
581 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | 781 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: |
582 | initiator = false; | 782 | initiator = false; |
583 | break; | 783 | break; |
584 | case WLAN_TDLS_TEARDOWN: | 784 | case WLAN_TDLS_TEARDOWN: |
785 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
786 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
585 | /* any value is ok */ | 787 | /* any value is ok */ |
586 | break; | 788 | break; |
587 | default: | 789 | default: |
@@ -596,9 +798,17 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
596 | if (ret < 0) | 798 | if (ret < 0) |
597 | goto fail; | 799 | goto fail; |
598 | 800 | ||
599 | ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, | 801 | skb = ieee80211_tdls_build_mgmt_packet_data(sdata, peer, action_code, |
600 | initiator, extra_ies, extra_ies_len); | 802 | dialog_token, status_code, |
601 | if (send_direct) { | 803 | initiator, extra_ies, |
804 | extra_ies_len, oper_class, | ||
805 | chandef); | ||
806 | if (!skb) { | ||
807 | ret = -EINVAL; | ||
808 | goto fail; | ||
809 | } | ||
810 | |||
811 | if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { | ||
602 | ieee80211_tx_skb(sdata, skb); | 812 | ieee80211_tx_skb(sdata, skb); |
603 | return 0; | 813 | return 0; |
604 | } | 814 | } |
@@ -619,9 +829,44 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
619 | break; | 829 | break; |
620 | } | 830 | } |
621 | 831 | ||
832 | /* | ||
833 | * Set the WLAN_TDLS_TEARDOWN flag to indicate a teardown in progress. | ||
834 | * Later, if no ACK is returned from peer, we will re-send the teardown | ||
835 | * packet through the AP. | ||
836 | */ | ||
837 | if ((action_code == WLAN_TDLS_TEARDOWN) && | ||
838 | (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { | ||
839 | struct sta_info *sta = NULL; | ||
840 | bool try_resend; /* Should we keep skb for possible resend */ | ||
841 | |||
842 | /* If not sending directly to peer - no point in keeping skb */ | ||
843 | rcu_read_lock(); | ||
844 | sta = sta_info_get(sdata, peer); | ||
845 | try_resend = sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); | ||
846 | rcu_read_unlock(); | ||
847 | |||
848 | spin_lock_bh(&sdata->u.mgd.teardown_lock); | ||
849 | if (try_resend && !sdata->u.mgd.teardown_skb) { | ||
850 | /* Mark it as requiring TX status callback */ | ||
851 | flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
852 | IEEE80211_TX_INTFL_MLME_CONN_TX; | ||
853 | |||
854 | /* | ||
855 | * skb is copied since mac80211 will later set | ||
856 | * properties that might not be the same as the AP, | ||
857 | * such as encryption, QoS, addresses, etc. | ||
858 | * | ||
859 | * No problem if skb_copy() fails, so no need to check. | ||
860 | */ | ||
861 | sdata->u.mgd.teardown_skb = skb_copy(skb, GFP_ATOMIC); | ||
862 | sdata->u.mgd.orig_teardown_skb = skb; | ||
863 | } | ||
864 | spin_unlock_bh(&sdata->u.mgd.teardown_lock); | ||
865 | } | ||
866 | |||
622 | /* disable bottom halves when entering the Tx path */ | 867 | /* disable bottom halves when entering the Tx path */ |
623 | local_bh_disable(); | 868 | local_bh_disable(); |
624 | ret = ieee80211_subif_start_xmit(skb, dev); | 869 | __ieee80211_subif_start_xmit(skb, dev, flags); |
625 | local_bh_enable(); | 870 | local_bh_enable(); |
626 | 871 | ||
627 | return ret; | 872 | return ret; |
@@ -672,7 +917,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | |||
672 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | 917 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, |
673 | dialog_token, status_code, | 918 | dialog_token, status_code, |
674 | peer_capability, initiator, | 919 | peer_capability, initiator, |
675 | extra_ies, extra_ies_len); | 920 | extra_ies, extra_ies_len, 0, |
921 | NULL); | ||
676 | if (ret < 0) | 922 | if (ret < 0) |
677 | goto exit; | 923 | goto exit; |
678 | 924 | ||
@@ -711,7 +957,8 @@ ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, | |||
711 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | 957 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, |
712 | dialog_token, status_code, | 958 | dialog_token, status_code, |
713 | peer_capability, initiator, | 959 | peer_capability, initiator, |
714 | extra_ies, extra_ies_len); | 960 | extra_ies, extra_ies_len, 0, |
961 | NULL); | ||
715 | if (ret < 0) | 962 | if (ret < 0) |
716 | sdata_err(sdata, "Failed sending TDLS teardown packet %d\n", | 963 | sdata_err(sdata, "Failed sending TDLS teardown packet %d\n", |
717 | ret); | 964 | ret); |
@@ -781,7 +1028,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
781 | status_code, | 1028 | status_code, |
782 | peer_capability, | 1029 | peer_capability, |
783 | initiator, extra_ies, | 1030 | initiator, extra_ies, |
784 | extra_ies_len); | 1031 | extra_ies_len, 0, NULL); |
785 | break; | 1032 | break; |
786 | default: | 1033 | default: |
787 | ret = -EOPNOTSUPP; | 1034 | ret = -EOPNOTSUPP; |
@@ -884,3 +1131,480 @@ void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, | |||
884 | cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp); | 1131 | cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp); |
885 | } | 1132 | } |
886 | EXPORT_SYMBOL(ieee80211_tdls_oper_request); | 1133 | EXPORT_SYMBOL(ieee80211_tdls_oper_request); |
1134 | |||
1135 | static void | ||
1136 | iee80211_tdls_add_ch_switch_timing(u8 *buf, u16 switch_time, u16 switch_timeout) | ||
1137 | { | ||
1138 | struct ieee80211_ch_switch_timing *ch_sw; | ||
1139 | |||
1140 | *buf++ = WLAN_EID_CHAN_SWITCH_TIMING; | ||
1141 | *buf++ = sizeof(struct ieee80211_ch_switch_timing); | ||
1142 | |||
1143 | ch_sw = (void *)buf; | ||
1144 | ch_sw->switch_time = cpu_to_le16(switch_time); | ||
1145 | ch_sw->switch_timeout = cpu_to_le16(switch_timeout); | ||
1146 | } | ||
1147 | |||
1148 | /* find switch timing IE in SKB ready for Tx */ | ||
1149 | static const u8 *ieee80211_tdls_find_sw_timing_ie(struct sk_buff *skb) | ||
1150 | { | ||
1151 | struct ieee80211_tdls_data *tf; | ||
1152 | const u8 *ie_start; | ||
1153 | |||
1154 | /* | ||
1155 | * Get the offset for the new location of the switch timing IE. | ||
1156 | * The SKB network header will now point to the "payload_type" | ||
1157 | * element of the TDLS data frame struct. | ||
1158 | */ | ||
1159 | tf = container_of(skb->data + skb_network_offset(skb), | ||
1160 | struct ieee80211_tdls_data, payload_type); | ||
1161 | ie_start = tf->u.chan_switch_req.variable; | ||
1162 | return cfg80211_find_ie(WLAN_EID_CHAN_SWITCH_TIMING, ie_start, | ||
1163 | skb->len - (ie_start - skb->data)); | ||
1164 | } | ||
1165 | |||
1166 | static struct sk_buff * | ||
1167 | ieee80211_tdls_ch_sw_tmpl_get(struct sta_info *sta, u8 oper_class, | ||
1168 | struct cfg80211_chan_def *chandef, | ||
1169 | u32 *ch_sw_tm_ie_offset) | ||
1170 | { | ||
1171 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1172 | u8 extra_ies[2 + sizeof(struct ieee80211_sec_chan_offs_ie) + | ||
1173 | 2 + sizeof(struct ieee80211_ch_switch_timing)]; | ||
1174 | int extra_ies_len = 2 + sizeof(struct ieee80211_ch_switch_timing); | ||
1175 | u8 *pos = extra_ies; | ||
1176 | struct sk_buff *skb; | ||
1177 | |||
1178 | /* | ||
1179 | * if chandef points to a wide channel add a Secondary-Channel | ||
1180 | * Offset information element | ||
1181 | */ | ||
1182 | if (chandef->width == NL80211_CHAN_WIDTH_40) { | ||
1183 | struct ieee80211_sec_chan_offs_ie *sec_chan_ie; | ||
1184 | bool ht40plus; | ||
1185 | |||
1186 | *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; | ||
1187 | *pos++ = sizeof(*sec_chan_ie); | ||
1188 | sec_chan_ie = (void *)pos; | ||
1189 | |||
1190 | ht40plus = cfg80211_get_chandef_type(chandef) == | ||
1191 | NL80211_CHAN_HT40PLUS; | ||
1192 | sec_chan_ie->sec_chan_offs = ht40plus ? | ||
1193 | IEEE80211_HT_PARAM_CHA_SEC_ABOVE : | ||
1194 | IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
1195 | pos += sizeof(*sec_chan_ie); | ||
1196 | |||
1197 | extra_ies_len += 2 + sizeof(struct ieee80211_sec_chan_offs_ie); | ||
1198 | } | ||
1199 | |||
1200 | /* just set the values to 0, this is a template */ | ||
1201 | iee80211_tdls_add_ch_switch_timing(pos, 0, 0); | ||
1202 | |||
1203 | skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, | ||
1204 | WLAN_TDLS_CHANNEL_SWITCH_REQUEST, | ||
1205 | 0, 0, !sta->sta.tdls_initiator, | ||
1206 | extra_ies, extra_ies_len, | ||
1207 | oper_class, chandef); | ||
1208 | if (!skb) | ||
1209 | return NULL; | ||
1210 | |||
1211 | skb = ieee80211_build_data_template(sdata, skb, 0); | ||
1212 | if (IS_ERR(skb)) { | ||
1213 | tdls_dbg(sdata, "Failed building TDLS channel switch frame\n"); | ||
1214 | return NULL; | ||
1215 | } | ||
1216 | |||
1217 | if (ch_sw_tm_ie_offset) { | ||
1218 | const u8 *tm_ie = ieee80211_tdls_find_sw_timing_ie(skb); | ||
1219 | |||
1220 | if (!tm_ie) { | ||
1221 | tdls_dbg(sdata, "No switch timing IE in TDLS switch\n"); | ||
1222 | dev_kfree_skb_any(skb); | ||
1223 | return NULL; | ||
1224 | } | ||
1225 | |||
1226 | *ch_sw_tm_ie_offset = tm_ie - skb->data; | ||
1227 | } | ||
1228 | |||
1229 | tdls_dbg(sdata, | ||
1230 | "TDLS channel switch request template for %pM ch %d width %d\n", | ||
1231 | sta->sta.addr, chandef->chan->center_freq, chandef->width); | ||
1232 | return skb; | ||
1233 | } | ||
1234 | |||
1235 | int | ||
1236 | ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||
1237 | const u8 *addr, u8 oper_class, | ||
1238 | struct cfg80211_chan_def *chandef) | ||
1239 | { | ||
1240 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1241 | struct ieee80211_local *local = sdata->local; | ||
1242 | struct sta_info *sta; | ||
1243 | struct sk_buff *skb = NULL; | ||
1244 | u32 ch_sw_tm_ie; | ||
1245 | int ret; | ||
1246 | |||
1247 | mutex_lock(&local->sta_mtx); | ||
1248 | sta = sta_info_get(sdata, addr); | ||
1249 | if (!sta) { | ||
1250 | tdls_dbg(sdata, | ||
1251 | "Invalid TDLS peer %pM for channel switch request\n", | ||
1252 | addr); | ||
1253 | ret = -ENOENT; | ||
1254 | goto out; | ||
1255 | } | ||
1256 | |||
1257 | if (!test_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH)) { | ||
1258 | tdls_dbg(sdata, "TDLS channel switch unsupported by %pM\n", | ||
1259 | addr); | ||
1260 | ret = -ENOTSUPP; | ||
1261 | goto out; | ||
1262 | } | ||
1263 | |||
1264 | skb = ieee80211_tdls_ch_sw_tmpl_get(sta, oper_class, chandef, | ||
1265 | &ch_sw_tm_ie); | ||
1266 | if (!skb) { | ||
1267 | ret = -ENOENT; | ||
1268 | goto out; | ||
1269 | } | ||
1270 | |||
1271 | ret = drv_tdls_channel_switch(local, sdata, &sta->sta, oper_class, | ||
1272 | chandef, skb, ch_sw_tm_ie); | ||
1273 | if (!ret) | ||
1274 | set_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); | ||
1275 | |||
1276 | out: | ||
1277 | mutex_unlock(&local->sta_mtx); | ||
1278 | dev_kfree_skb_any(skb); | ||
1279 | return ret; | ||
1280 | } | ||
1281 | |||
1282 | void | ||
1283 | ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, | ||
1284 | struct net_device *dev, | ||
1285 | const u8 *addr) | ||
1286 | { | ||
1287 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1288 | struct ieee80211_local *local = sdata->local; | ||
1289 | struct sta_info *sta; | ||
1290 | |||
1291 | mutex_lock(&local->sta_mtx); | ||
1292 | sta = sta_info_get(sdata, addr); | ||
1293 | if (!sta) { | ||
1294 | tdls_dbg(sdata, | ||
1295 | "Invalid TDLS peer %pM for channel switch cancel\n", | ||
1296 | addr); | ||
1297 | goto out; | ||
1298 | } | ||
1299 | |||
1300 | if (!test_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL)) { | ||
1301 | tdls_dbg(sdata, "TDLS channel switch not initiated by %pM\n", | ||
1302 | addr); | ||
1303 | goto out; | ||
1304 | } | ||
1305 | |||
1306 | drv_tdls_cancel_channel_switch(local, sdata, &sta->sta); | ||
1307 | clear_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); | ||
1308 | |||
1309 | out: | ||
1310 | mutex_unlock(&local->sta_mtx); | ||
1311 | } | ||
1312 | |||
1313 | static struct sk_buff * | ||
1314 | ieee80211_tdls_ch_sw_resp_tmpl_get(struct sta_info *sta, | ||
1315 | u32 *ch_sw_tm_ie_offset) | ||
1316 | { | ||
1317 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1318 | struct sk_buff *skb; | ||
1319 | u8 extra_ies[2 + sizeof(struct ieee80211_ch_switch_timing)]; | ||
1320 | |||
1321 | /* initial timing are always zero in the template */ | ||
1322 | iee80211_tdls_add_ch_switch_timing(extra_ies, 0, 0); | ||
1323 | |||
1324 | skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, | ||
1325 | WLAN_TDLS_CHANNEL_SWITCH_RESPONSE, | ||
1326 | 0, 0, !sta->sta.tdls_initiator, | ||
1327 | extra_ies, sizeof(extra_ies), 0, NULL); | ||
1328 | if (!skb) | ||
1329 | return NULL; | ||
1330 | |||
1331 | skb = ieee80211_build_data_template(sdata, skb, 0); | ||
1332 | if (IS_ERR(skb)) { | ||
1333 | tdls_dbg(sdata, | ||
1334 | "Failed building TDLS channel switch resp frame\n"); | ||
1335 | return NULL; | ||
1336 | } | ||
1337 | |||
1338 | if (ch_sw_tm_ie_offset) { | ||
1339 | const u8 *tm_ie = ieee80211_tdls_find_sw_timing_ie(skb); | ||
1340 | |||
1341 | if (!tm_ie) { | ||
1342 | tdls_dbg(sdata, | ||
1343 | "No switch timing IE in TDLS switch resp\n"); | ||
1344 | dev_kfree_skb_any(skb); | ||
1345 | return NULL; | ||
1346 | } | ||
1347 | |||
1348 | *ch_sw_tm_ie_offset = tm_ie - skb->data; | ||
1349 | } | ||
1350 | |||
1351 | tdls_dbg(sdata, "TDLS get channel switch response template for %pM\n", | ||
1352 | sta->sta.addr); | ||
1353 | return skb; | ||
1354 | } | ||
1355 | |||
1356 | static int | ||
1357 | ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata, | ||
1358 | struct sk_buff *skb) | ||
1359 | { | ||
1360 | struct ieee80211_local *local = sdata->local; | ||
1361 | struct ieee802_11_elems elems; | ||
1362 | struct sta_info *sta; | ||
1363 | struct ieee80211_tdls_data *tf = (void *)skb->data; | ||
1364 | bool local_initiator; | ||
1365 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | ||
1366 | int baselen = offsetof(typeof(*tf), u.chan_switch_resp.variable); | ||
1367 | struct ieee80211_tdls_ch_sw_params params = {}; | ||
1368 | int ret; | ||
1369 | |||
1370 | params.action_code = WLAN_TDLS_CHANNEL_SWITCH_RESPONSE; | ||
1371 | params.timestamp = rx_status->device_timestamp; | ||
1372 | |||
1373 | if (skb->len < baselen) { | ||
1374 | tdls_dbg(sdata, "TDLS channel switch resp too short: %d\n", | ||
1375 | skb->len); | ||
1376 | return -EINVAL; | ||
1377 | } | ||
1378 | |||
1379 | mutex_lock(&local->sta_mtx); | ||
1380 | sta = sta_info_get(sdata, tf->sa); | ||
1381 | if (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) { | ||
1382 | tdls_dbg(sdata, "TDLS chan switch from non-peer sta %pM\n", | ||
1383 | tf->sa); | ||
1384 | ret = -EINVAL; | ||
1385 | goto out; | ||
1386 | } | ||
1387 | |||
1388 | params.sta = &sta->sta; | ||
1389 | params.status = le16_to_cpu(tf->u.chan_switch_resp.status_code); | ||
1390 | if (params.status != 0) { | ||
1391 | ret = 0; | ||
1392 | goto call_drv; | ||
1393 | } | ||
1394 | |||
1395 | ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, | ||
1396 | skb->len - baselen, false, &elems); | ||
1397 | if (elems.parse_error) { | ||
1398 | tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n"); | ||
1399 | ret = -EINVAL; | ||
1400 | goto out; | ||
1401 | } | ||
1402 | |||
1403 | if (!elems.ch_sw_timing || !elems.lnk_id) { | ||
1404 | tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n"); | ||
1405 | ret = -EINVAL; | ||
1406 | goto out; | ||
1407 | } | ||
1408 | |||
1409 | /* validate the initiator is set correctly */ | ||
1410 | local_initiator = | ||
1411 | !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | ||
1412 | if (local_initiator == sta->sta.tdls_initiator) { | ||
1413 | tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); | ||
1414 | ret = -EINVAL; | ||
1415 | goto out; | ||
1416 | } | ||
1417 | |||
1418 | params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); | ||
1419 | params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); | ||
1420 | |||
1421 | params.tmpl_skb = | ||
1422 | ieee80211_tdls_ch_sw_resp_tmpl_get(sta, ¶ms.ch_sw_tm_ie); | ||
1423 | if (!params.tmpl_skb) { | ||
1424 | ret = -ENOENT; | ||
1425 | goto out; | ||
1426 | } | ||
1427 | |||
1428 | call_drv: | ||
1429 | drv_tdls_recv_channel_switch(sdata->local, sdata, ¶ms); | ||
1430 | |||
1431 | tdls_dbg(sdata, | ||
1432 | "TDLS channel switch response received from %pM status %d\n", | ||
1433 | tf->sa, params.status); | ||
1434 | |||
1435 | out: | ||
1436 | mutex_unlock(&local->sta_mtx); | ||
1437 | dev_kfree_skb_any(params.tmpl_skb); | ||
1438 | return ret; | ||
1439 | } | ||
1440 | |||
1441 | static int | ||
1442 | ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, | ||
1443 | struct sk_buff *skb) | ||
1444 | { | ||
1445 | struct ieee80211_local *local = sdata->local; | ||
1446 | struct ieee802_11_elems elems; | ||
1447 | struct cfg80211_chan_def chandef; | ||
1448 | struct ieee80211_channel *chan; | ||
1449 | enum nl80211_channel_type chan_type; | ||
1450 | int freq; | ||
1451 | u8 target_channel, oper_class; | ||
1452 | bool local_initiator; | ||
1453 | struct sta_info *sta; | ||
1454 | enum ieee80211_band band; | ||
1455 | struct ieee80211_tdls_data *tf = (void *)skb->data; | ||
1456 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | ||
1457 | int baselen = offsetof(typeof(*tf), u.chan_switch_req.variable); | ||
1458 | struct ieee80211_tdls_ch_sw_params params = {}; | ||
1459 | int ret = 0; | ||
1460 | |||
1461 | params.action_code = WLAN_TDLS_CHANNEL_SWITCH_REQUEST; | ||
1462 | params.timestamp = rx_status->device_timestamp; | ||
1463 | |||
1464 | if (skb->len < baselen) { | ||
1465 | tdls_dbg(sdata, "TDLS channel switch req too short: %d\n", | ||
1466 | skb->len); | ||
1467 | return -EINVAL; | ||
1468 | } | ||
1469 | |||
1470 | target_channel = tf->u.chan_switch_req.target_channel; | ||
1471 | oper_class = tf->u.chan_switch_req.oper_class; | ||
1472 | |||
1473 | /* | ||
1474 | * We can't easily infer the channel band. The operating class is | ||
1475 | * ambiguous - there are multiple tables (US/Europe/JP/Global). The | ||
1476 | * solution here is to treat channels with number >14 as 5GHz ones, | ||
1477 | * and specifically check for the (oper_class, channel) combinations | ||
1478 | * where this doesn't hold. These are thankfully unique according to | ||
1479 | * IEEE802.11-2012. | ||
1480 | * We consider only the 2GHz and 5GHz bands and 20MHz+ channels as | ||
1481 | * valid here. | ||
1482 | */ | ||
1483 | if ((oper_class == 112 || oper_class == 2 || oper_class == 3 || | ||
1484 | oper_class == 4 || oper_class == 5 || oper_class == 6) && | ||
1485 | target_channel < 14) | ||
1486 | band = IEEE80211_BAND_5GHZ; | ||
1487 | else | ||
1488 | band = target_channel < 14 ? IEEE80211_BAND_2GHZ : | ||
1489 | IEEE80211_BAND_5GHZ; | ||
1490 | |||
1491 | freq = ieee80211_channel_to_frequency(target_channel, band); | ||
1492 | if (freq == 0) { | ||
1493 | tdls_dbg(sdata, "Invalid channel in TDLS chan switch: %d\n", | ||
1494 | target_channel); | ||
1495 | return -EINVAL; | ||
1496 | } | ||
1497 | |||
1498 | chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq); | ||
1499 | if (!chan) { | ||
1500 | tdls_dbg(sdata, | ||
1501 | "Unsupported channel for TDLS chan switch: %d\n", | ||
1502 | target_channel); | ||
1503 | return -EINVAL; | ||
1504 | } | ||
1505 | |||
1506 | ieee802_11_parse_elems(tf->u.chan_switch_req.variable, | ||
1507 | skb->len - baselen, false, &elems); | ||
1508 | if (elems.parse_error) { | ||
1509 | tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n"); | ||
1510 | return -EINVAL; | ||
1511 | } | ||
1512 | |||
1513 | if (!elems.ch_sw_timing || !elems.lnk_id) { | ||
1514 | tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n"); | ||
1515 | return -EINVAL; | ||
1516 | } | ||
1517 | |||
1518 | mutex_lock(&local->sta_mtx); | ||
1519 | sta = sta_info_get(sdata, tf->sa); | ||
1520 | if (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) { | ||
1521 | tdls_dbg(sdata, "TDLS chan switch from non-peer sta %pM\n", | ||
1522 | tf->sa); | ||
1523 | ret = -EINVAL; | ||
1524 | goto out; | ||
1525 | } | ||
1526 | |||
1527 | params.sta = &sta->sta; | ||
1528 | |||
1529 | /* validate the initiator is set correctly */ | ||
1530 | local_initiator = | ||
1531 | !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | ||
1532 | if (local_initiator == sta->sta.tdls_initiator) { | ||
1533 | tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); | ||
1534 | ret = -EINVAL; | ||
1535 | goto out; | ||
1536 | } | ||
1537 | |||
1538 | if (!sta->sta.ht_cap.ht_supported) { | ||
1539 | chan_type = NL80211_CHAN_NO_HT; | ||
1540 | } else if (!elems.sec_chan_offs) { | ||
1541 | chan_type = NL80211_CHAN_HT20; | ||
1542 | } else { | ||
1543 | switch (elems.sec_chan_offs->sec_chan_offs) { | ||
1544 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
1545 | chan_type = NL80211_CHAN_HT40PLUS; | ||
1546 | break; | ||
1547 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
1548 | chan_type = NL80211_CHAN_HT40MINUS; | ||
1549 | break; | ||
1550 | default: | ||
1551 | chan_type = NL80211_CHAN_HT20; | ||
1552 | break; | ||
1553 | } | ||
1554 | } | ||
1555 | |||
1556 | cfg80211_chandef_create(&chandef, chan, chan_type); | ||
1557 | params.chandef = &chandef; | ||
1558 | |||
1559 | params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); | ||
1560 | params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); | ||
1561 | |||
1562 | params.tmpl_skb = | ||
1563 | ieee80211_tdls_ch_sw_resp_tmpl_get(sta, | ||
1564 | ¶ms.ch_sw_tm_ie); | ||
1565 | if (!params.tmpl_skb) { | ||
1566 | ret = -ENOENT; | ||
1567 | goto out; | ||
1568 | } | ||
1569 | |||
1570 | drv_tdls_recv_channel_switch(sdata->local, sdata, ¶ms); | ||
1571 | |||
1572 | tdls_dbg(sdata, | ||
1573 | "TDLS ch switch request received from %pM ch %d width %d\n", | ||
1574 | tf->sa, params.chandef->chan->center_freq, | ||
1575 | params.chandef->width); | ||
1576 | out: | ||
1577 | mutex_unlock(&local->sta_mtx); | ||
1578 | dev_kfree_skb_any(params.tmpl_skb); | ||
1579 | return ret; | ||
1580 | } | ||
1581 | |||
1582 | void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, | ||
1583 | struct sk_buff *skb) | ||
1584 | { | ||
1585 | struct ieee80211_tdls_data *tf = (void *)skb->data; | ||
1586 | struct wiphy *wiphy = sdata->local->hw.wiphy; | ||
1587 | |||
1588 | /* make sure the driver supports it */ | ||
1589 | if (!(wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)) | ||
1590 | return; | ||
1591 | |||
1592 | /* we want to access the entire packet */ | ||
1593 | if (skb_linearize(skb)) | ||
1594 | return; | ||
1595 | /* | ||
1596 | * The packet/size was already validated by mac80211 Rx path, only look | ||
1597 | * at the action type. | ||
1598 | */ | ||
1599 | switch (tf->action_code) { | ||
1600 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
1601 | ieee80211_process_tdls_channel_switch_req(sdata, skb); | ||
1602 | break; | ||
1603 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
1604 | ieee80211_process_tdls_channel_switch_resp(sdata, skb); | ||
1605 | break; | ||
1606 | default: | ||
1607 | WARN_ON_ONCE(1); | ||
1608 | return; | ||
1609 | } | ||
1610 | } | ||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 38fae7ebe984..8e461a02c6a8 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #define STA_ENTRY __array(char, sta_addr, ETH_ALEN) | 17 | #define STA_ENTRY __array(char, sta_addr, ETH_ALEN) |
18 | #define STA_ASSIGN (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN)) | 18 | #define STA_ASSIGN (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN)) |
19 | #define STA_NAMED_ASSIGN(s) memcpy(__entry->sta_addr, (s)->addr, ETH_ALEN) | ||
19 | #define STA_PR_FMT " sta:%pM" | 20 | #define STA_PR_FMT " sta:%pM" |
20 | #define STA_PR_ARG __entry->sta_addr | 21 | #define STA_PR_ARG __entry->sta_addr |
21 | 22 | ||
@@ -595,14 +596,33 @@ DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop, | |||
595 | TP_ARGS(local, sdata) | 596 | TP_ARGS(local, sdata) |
596 | ); | 597 | ); |
597 | 598 | ||
598 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, | 599 | TRACE_EVENT(drv_sw_scan_start, |
599 | TP_PROTO(struct ieee80211_local *local), | 600 | TP_PROTO(struct ieee80211_local *local, |
600 | TP_ARGS(local) | 601 | struct ieee80211_sub_if_data *sdata, |
602 | const u8 *mac_addr), | ||
603 | |||
604 | TP_ARGS(local, sdata, mac_addr), | ||
605 | |||
606 | TP_STRUCT__entry( | ||
607 | LOCAL_ENTRY | ||
608 | VIF_ENTRY | ||
609 | __array(char, mac_addr, ETH_ALEN) | ||
610 | ), | ||
611 | |||
612 | TP_fast_assign( | ||
613 | LOCAL_ASSIGN; | ||
614 | VIF_ASSIGN; | ||
615 | memcpy(__entry->mac_addr, mac_addr, ETH_ALEN); | ||
616 | ), | ||
617 | |||
618 | TP_printk(LOCAL_PR_FMT ", " VIF_PR_FMT ", addr:%pM", | ||
619 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->mac_addr) | ||
601 | ); | 620 | ); |
602 | 621 | ||
603 | DEFINE_EVENT(local_only_evt, drv_sw_scan_complete, | 622 | DEFINE_EVENT(local_sdata_evt, drv_sw_scan_complete, |
604 | TP_PROTO(struct ieee80211_local *local), | 623 | TP_PROTO(struct ieee80211_local *local, |
605 | TP_ARGS(local) | 624 | struct ieee80211_sub_if_data *sdata), |
625 | TP_ARGS(local, sdata) | ||
606 | ); | 626 | ); |
607 | 627 | ||
608 | TRACE_EVENT(drv_get_stats, | 628 | TRACE_EVENT(drv_get_stats, |
@@ -826,6 +846,13 @@ DEFINE_EVENT(sta_event, drv_sta_pre_rcu_remove, | |||
826 | TP_ARGS(local, sdata, sta) | 846 | TP_ARGS(local, sdata, sta) |
827 | ); | 847 | ); |
828 | 848 | ||
849 | DEFINE_EVENT(sta_event, drv_sta_rate_tbl_update, | ||
850 | TP_PROTO(struct ieee80211_local *local, | ||
851 | struct ieee80211_sub_if_data *sdata, | ||
852 | struct ieee80211_sta *sta), | ||
853 | TP_ARGS(local, sdata, sta) | ||
854 | ); | ||
855 | |||
829 | TRACE_EVENT(drv_conf_tx, | 856 | TRACE_EVENT(drv_conf_tx, |
830 | TP_PROTO(struct ieee80211_local *local, | 857 | TP_PROTO(struct ieee80211_local *local, |
831 | struct ieee80211_sub_if_data *sdata, | 858 | struct ieee80211_sub_if_data *sdata, |
@@ -987,29 +1014,34 @@ TRACE_EVENT(drv_flush, | |||
987 | 1014 | ||
988 | TRACE_EVENT(drv_channel_switch, | 1015 | TRACE_EVENT(drv_channel_switch, |
989 | TP_PROTO(struct ieee80211_local *local, | 1016 | TP_PROTO(struct ieee80211_local *local, |
1017 | struct ieee80211_sub_if_data *sdata, | ||
990 | struct ieee80211_channel_switch *ch_switch), | 1018 | struct ieee80211_channel_switch *ch_switch), |
991 | 1019 | ||
992 | TP_ARGS(local, ch_switch), | 1020 | TP_ARGS(local, sdata, ch_switch), |
993 | 1021 | ||
994 | TP_STRUCT__entry( | 1022 | TP_STRUCT__entry( |
995 | LOCAL_ENTRY | 1023 | LOCAL_ENTRY |
1024 | VIF_ENTRY | ||
996 | CHANDEF_ENTRY | 1025 | CHANDEF_ENTRY |
997 | __field(u64, timestamp) | 1026 | __field(u64, timestamp) |
1027 | __field(u32, device_timestamp) | ||
998 | __field(bool, block_tx) | 1028 | __field(bool, block_tx) |
999 | __field(u8, count) | 1029 | __field(u8, count) |
1000 | ), | 1030 | ), |
1001 | 1031 | ||
1002 | TP_fast_assign( | 1032 | TP_fast_assign( |
1003 | LOCAL_ASSIGN; | 1033 | LOCAL_ASSIGN; |
1034 | VIF_ASSIGN; | ||
1004 | CHANDEF_ASSIGN(&ch_switch->chandef) | 1035 | CHANDEF_ASSIGN(&ch_switch->chandef) |
1005 | __entry->timestamp = ch_switch->timestamp; | 1036 | __entry->timestamp = ch_switch->timestamp; |
1037 | __entry->device_timestamp = ch_switch->device_timestamp; | ||
1006 | __entry->block_tx = ch_switch->block_tx; | 1038 | __entry->block_tx = ch_switch->block_tx; |
1007 | __entry->count = ch_switch->count; | 1039 | __entry->count = ch_switch->count; |
1008 | ), | 1040 | ), |
1009 | 1041 | ||
1010 | TP_printk( | 1042 | TP_printk( |
1011 | LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d", | 1043 | LOCAL_PR_FMT VIF_PR_FMT " new " CHANDEF_PR_FMT " count:%d", |
1012 | LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count | 1044 | LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count |
1013 | ) | 1045 | ) |
1014 | ); | 1046 | ); |
1015 | 1047 | ||
@@ -1557,9 +1589,26 @@ DEFINE_EVENT(local_sdata_evt, drv_stop_ap, | |||
1557 | TP_ARGS(local, sdata) | 1589 | TP_ARGS(local, sdata) |
1558 | ); | 1590 | ); |
1559 | 1591 | ||
1560 | DEFINE_EVENT(local_only_evt, drv_restart_complete, | 1592 | TRACE_EVENT(drv_reconfig_complete, |
1561 | TP_PROTO(struct ieee80211_local *local), | 1593 | TP_PROTO(struct ieee80211_local *local, |
1562 | TP_ARGS(local) | 1594 | enum ieee80211_reconfig_type reconfig_type), |
1595 | TP_ARGS(local, reconfig_type), | ||
1596 | |||
1597 | TP_STRUCT__entry( | ||
1598 | LOCAL_ENTRY | ||
1599 | __field(u8, reconfig_type) | ||
1600 | ), | ||
1601 | |||
1602 | TP_fast_assign( | ||
1603 | LOCAL_ASSIGN; | ||
1604 | __entry->reconfig_type = reconfig_type; | ||
1605 | ), | ||
1606 | |||
1607 | TP_printk( | ||
1608 | LOCAL_PR_FMT " reconfig_type:%d", | ||
1609 | LOCAL_PR_ARG, __entry->reconfig_type | ||
1610 | ) | ||
1611 | |||
1563 | ); | 1612 | ); |
1564 | 1613 | ||
1565 | #if IS_ENABLED(CONFIG_IPV6) | 1614 | #if IS_ENABLED(CONFIG_IPV6) |
@@ -1780,6 +1829,12 @@ TRACE_EVENT(api_cqm_rssi_notify, | |||
1780 | ) | 1829 | ) |
1781 | ); | 1830 | ); |
1782 | 1831 | ||
1832 | DEFINE_EVENT(local_sdata_evt, api_cqm_beacon_loss_notify, | ||
1833 | TP_PROTO(struct ieee80211_local *local, | ||
1834 | struct ieee80211_sub_if_data *sdata), | ||
1835 | TP_ARGS(local, sdata) | ||
1836 | ); | ||
1837 | |||
1783 | TRACE_EVENT(api_scan_completed, | 1838 | TRACE_EVENT(api_scan_completed, |
1784 | TP_PROTO(struct ieee80211_local *local, bool aborted), | 1839 | TP_PROTO(struct ieee80211_local *local, bool aborted), |
1785 | 1840 | ||
@@ -2106,6 +2161,175 @@ TRACE_EVENT(drv_channel_switch_beacon, | |||
2106 | ) | 2161 | ) |
2107 | ); | 2162 | ); |
2108 | 2163 | ||
2164 | TRACE_EVENT(drv_pre_channel_switch, | ||
2165 | TP_PROTO(struct ieee80211_local *local, | ||
2166 | struct ieee80211_sub_if_data *sdata, | ||
2167 | struct ieee80211_channel_switch *ch_switch), | ||
2168 | |||
2169 | TP_ARGS(local, sdata, ch_switch), | ||
2170 | |||
2171 | TP_STRUCT__entry( | ||
2172 | LOCAL_ENTRY | ||
2173 | VIF_ENTRY | ||
2174 | CHANDEF_ENTRY | ||
2175 | __field(u64, timestamp) | ||
2176 | __field(u32, device_timestamp) | ||
2177 | __field(bool, block_tx) | ||
2178 | __field(u8, count) | ||
2179 | ), | ||
2180 | |||
2181 | TP_fast_assign( | ||
2182 | LOCAL_ASSIGN; | ||
2183 | VIF_ASSIGN; | ||
2184 | CHANDEF_ASSIGN(&ch_switch->chandef) | ||
2185 | __entry->timestamp = ch_switch->timestamp; | ||
2186 | __entry->device_timestamp = ch_switch->device_timestamp; | ||
2187 | __entry->block_tx = ch_switch->block_tx; | ||
2188 | __entry->count = ch_switch->count; | ||
2189 | ), | ||
2190 | |||
2191 | TP_printk( | ||
2192 | LOCAL_PR_FMT VIF_PR_FMT " prepare channel switch to " | ||
2193 | CHANDEF_PR_FMT " count:%d block_tx:%d timestamp:%llu", | ||
2194 | LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count, | ||
2195 | __entry->block_tx, __entry->timestamp | ||
2196 | ) | ||
2197 | ); | ||
2198 | |||
2199 | DEFINE_EVENT(local_sdata_evt, drv_post_channel_switch, | ||
2200 | TP_PROTO(struct ieee80211_local *local, | ||
2201 | struct ieee80211_sub_if_data *sdata), | ||
2202 | TP_ARGS(local, sdata) | ||
2203 | ); | ||
2204 | |||
2205 | TRACE_EVENT(drv_get_txpower, | ||
2206 | TP_PROTO(struct ieee80211_local *local, | ||
2207 | struct ieee80211_sub_if_data *sdata, | ||
2208 | int dbm, int ret), | ||
2209 | |||
2210 | TP_ARGS(local, sdata, dbm, ret), | ||
2211 | |||
2212 | TP_STRUCT__entry( | ||
2213 | LOCAL_ENTRY | ||
2214 | VIF_ENTRY | ||
2215 | __field(int, dbm) | ||
2216 | __field(int, ret) | ||
2217 | ), | ||
2218 | |||
2219 | TP_fast_assign( | ||
2220 | LOCAL_ASSIGN; | ||
2221 | VIF_ASSIGN; | ||
2222 | __entry->dbm = dbm; | ||
2223 | __entry->ret = ret; | ||
2224 | ), | ||
2225 | |||
2226 | TP_printk( | ||
2227 | LOCAL_PR_FMT VIF_PR_FMT " dbm:%d ret:%d", | ||
2228 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->dbm, __entry->ret | ||
2229 | ) | ||
2230 | ); | ||
2231 | |||
2232 | TRACE_EVENT(drv_tdls_channel_switch, | ||
2233 | TP_PROTO(struct ieee80211_local *local, | ||
2234 | struct ieee80211_sub_if_data *sdata, | ||
2235 | struct ieee80211_sta *sta, u8 oper_class, | ||
2236 | struct cfg80211_chan_def *chandef), | ||
2237 | |||
2238 | TP_ARGS(local, sdata, sta, oper_class, chandef), | ||
2239 | |||
2240 | TP_STRUCT__entry( | ||
2241 | LOCAL_ENTRY | ||
2242 | VIF_ENTRY | ||
2243 | STA_ENTRY | ||
2244 | __field(u8, oper_class) | ||
2245 | CHANDEF_ENTRY | ||
2246 | ), | ||
2247 | |||
2248 | TP_fast_assign( | ||
2249 | LOCAL_ASSIGN; | ||
2250 | VIF_ASSIGN; | ||
2251 | STA_ASSIGN; | ||
2252 | __entry->oper_class = oper_class; | ||
2253 | CHANDEF_ASSIGN(chandef) | ||
2254 | ), | ||
2255 | |||
2256 | TP_printk( | ||
2257 | LOCAL_PR_FMT VIF_PR_FMT " tdls channel switch to" | ||
2258 | CHANDEF_PR_FMT " oper_class:%d " STA_PR_FMT, | ||
2259 | LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->oper_class, | ||
2260 | STA_PR_ARG | ||
2261 | ) | ||
2262 | ); | ||
2263 | |||
2264 | TRACE_EVENT(drv_tdls_cancel_channel_switch, | ||
2265 | TP_PROTO(struct ieee80211_local *local, | ||
2266 | struct ieee80211_sub_if_data *sdata, | ||
2267 | struct ieee80211_sta *sta), | ||
2268 | |||
2269 | TP_ARGS(local, sdata, sta), | ||
2270 | |||
2271 | TP_STRUCT__entry( | ||
2272 | LOCAL_ENTRY | ||
2273 | VIF_ENTRY | ||
2274 | STA_ENTRY | ||
2275 | ), | ||
2276 | |||
2277 | TP_fast_assign( | ||
2278 | LOCAL_ASSIGN; | ||
2279 | VIF_ASSIGN; | ||
2280 | STA_ASSIGN; | ||
2281 | ), | ||
2282 | |||
2283 | TP_printk( | ||
2284 | LOCAL_PR_FMT VIF_PR_FMT | ||
2285 | " tdls cancel channel switch with " STA_PR_FMT, | ||
2286 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG | ||
2287 | ) | ||
2288 | ); | ||
2289 | |||
2290 | TRACE_EVENT(drv_tdls_recv_channel_switch, | ||
2291 | TP_PROTO(struct ieee80211_local *local, | ||
2292 | struct ieee80211_sub_if_data *sdata, | ||
2293 | struct ieee80211_tdls_ch_sw_params *params), | ||
2294 | |||
2295 | TP_ARGS(local, sdata, params), | ||
2296 | |||
2297 | TP_STRUCT__entry( | ||
2298 | LOCAL_ENTRY | ||
2299 | VIF_ENTRY | ||
2300 | __field(u8, action_code) | ||
2301 | STA_ENTRY | ||
2302 | CHANDEF_ENTRY | ||
2303 | __field(u32, status) | ||
2304 | __field(bool, peer_initiator) | ||
2305 | __field(u32, timestamp) | ||
2306 | __field(u16, switch_time) | ||
2307 | __field(u16, switch_timeout) | ||
2308 | ), | ||
2309 | |||
2310 | TP_fast_assign( | ||
2311 | LOCAL_ASSIGN; | ||
2312 | VIF_ASSIGN; | ||
2313 | STA_NAMED_ASSIGN(params->sta); | ||
2314 | CHANDEF_ASSIGN(params->chandef) | ||
2315 | __entry->peer_initiator = params->sta->tdls_initiator; | ||
2316 | __entry->action_code = params->action_code; | ||
2317 | __entry->status = params->status; | ||
2318 | __entry->timestamp = params->timestamp; | ||
2319 | __entry->switch_time = params->switch_time; | ||
2320 | __entry->switch_timeout = params->switch_timeout; | ||
2321 | ), | ||
2322 | |||
2323 | TP_printk( | ||
2324 | LOCAL_PR_FMT VIF_PR_FMT " received tdls channel switch packet" | ||
2325 | " action:%d status:%d time:%d switch time:%d switch" | ||
2326 | " timeout:%d initiator: %d chan:" CHANDEF_PR_FMT STA_PR_FMT, | ||
2327 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->action_code, __entry->status, | ||
2328 | __entry->timestamp, __entry->switch_time, | ||
2329 | __entry->switch_timeout, __entry->peer_initiator, | ||
2330 | CHANDEF_PR_ARG, STA_PR_ARG | ||
2331 | ) | ||
2332 | ); | ||
2109 | 2333 | ||
2110 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING | 2334 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING |
2111 | #undef TRACE_SYSTEM | 2335 | #undef TRACE_SYSTEM |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 900632a250ec..058686a721a1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -60,7 +60,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | |||
60 | rcu_read_unlock(); | 60 | rcu_read_unlock(); |
61 | 61 | ||
62 | /* assume HW handles this */ | 62 | /* assume HW handles this */ |
63 | if (tx->rate.flags & IEEE80211_TX_RC_MCS) | 63 | if (tx->rate.flags & (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS)) |
64 | return 0; | 64 | return 0; |
65 | 65 | ||
66 | /* uh huh? */ | 66 | /* uh huh? */ |
@@ -296,6 +296,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | |||
296 | */ | 296 | */ |
297 | return TX_DROP; | 297 | return TX_DROP; |
298 | 298 | ||
299 | if (tx->sdata->vif.type == NL80211_IFTYPE_OCB) | ||
300 | return TX_CONTINUE; | ||
301 | |||
299 | if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) | 302 | if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) |
300 | return TX_CONTINUE; | 303 | return TX_CONTINUE; |
301 | 304 | ||
@@ -1423,8 +1426,7 @@ EXPORT_SYMBOL(ieee80211_tx_prepare_skb); | |||
1423 | * Returns false if the frame couldn't be transmitted but was queued instead. | 1426 | * Returns false if the frame couldn't be transmitted but was queued instead. |
1424 | */ | 1427 | */ |
1425 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | 1428 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, |
1426 | struct sk_buff *skb, bool txpending, | 1429 | struct sk_buff *skb, bool txpending) |
1427 | enum ieee80211_band band) | ||
1428 | { | 1430 | { |
1429 | struct ieee80211_local *local = sdata->local; | 1431 | struct ieee80211_local *local = sdata->local; |
1430 | struct ieee80211_tx_data tx; | 1432 | struct ieee80211_tx_data tx; |
@@ -1449,8 +1451,6 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1449 | return true; | 1451 | return true; |
1450 | } | 1452 | } |
1451 | 1453 | ||
1452 | info->band = band; | ||
1453 | |||
1454 | /* set up hw_queue value early */ | 1454 | /* set up hw_queue value early */ |
1455 | if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || | 1455 | if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || |
1456 | !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) | 1456 | !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) |
@@ -1498,8 +1498,7 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, | |||
1498 | return 0; | 1498 | return 0; |
1499 | } | 1499 | } |
1500 | 1500 | ||
1501 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 1501 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
1502 | enum ieee80211_band band) | ||
1503 | { | 1502 | { |
1504 | struct ieee80211_local *local = sdata->local; | 1503 | struct ieee80211_local *local = sdata->local; |
1505 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1504 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
@@ -1534,7 +1533,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
1534 | } | 1533 | } |
1535 | 1534 | ||
1536 | ieee80211_set_qos_hdr(sdata, skb); | 1535 | ieee80211_set_qos_hdr(sdata, skb); |
1537 | ieee80211_tx(sdata, skb, false, band); | 1536 | ieee80211_tx(sdata, skb, false); |
1538 | } | 1537 | } |
1539 | 1538 | ||
1540 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) | 1539 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) |
@@ -1754,7 +1753,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1754 | sdata->vif.type)) | 1753 | sdata->vif.type)) |
1755 | goto fail_rcu; | 1754 | goto fail_rcu; |
1756 | 1755 | ||
1757 | ieee80211_xmit(sdata, skb, chandef->chan->band); | 1756 | info->band = chandef->chan->band; |
1757 | ieee80211_xmit(sdata, skb); | ||
1758 | rcu_read_unlock(); | 1758 | rcu_read_unlock(); |
1759 | 1759 | ||
1760 | return NETDEV_TX_OK; | 1760 | return NETDEV_TX_OK; |
@@ -1784,23 +1784,26 @@ static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, | |||
1784 | } | 1784 | } |
1785 | 1785 | ||
1786 | /** | 1786 | /** |
1787 | * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type | 1787 | * ieee80211_build_hdr - build 802.11 header in the given frame |
1788 | * subinterfaces (wlan#, WDS, and VLAN interfaces) | 1788 | * @sdata: virtual interface to build the header for |
1789 | * @skb: packet to be sent | 1789 | * @skb: the skb to build the header in |
1790 | * @dev: incoming interface | 1790 | * @info_flags: skb flags to set |
1791 | * | ||
1792 | * This function takes the skb with 802.3 header and reformats the header to | ||
1793 | * the appropriate IEEE 802.11 header based on which interface the packet is | ||
1794 | * being transmitted on. | ||
1795 | * | ||
1796 | * Note that this function also takes care of the TX status request and | ||
1797 | * potential unsharing of the SKB - this needs to be interleaved with the | ||
1798 | * header building. | ||
1791 | * | 1799 | * |
1792 | * Returns: NETDEV_TX_OK both on success and on failure. On failure skb will | 1800 | * The function requires the read-side RCU lock held |
1793 | * be freed. | ||
1794 | * | 1801 | * |
1795 | * This function takes in an Ethernet header and encapsulates it with suitable | 1802 | * Returns: the (possibly reallocated) skb or an ERR_PTR() code |
1796 | * IEEE 802.11 header based on which interface the packet is coming in. The | ||
1797 | * encapsulated packet will then be passed to master interface, wlan#.11, for | ||
1798 | * transmission (through low-level driver). | ||
1799 | */ | 1803 | */ |
1800 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | 1804 | static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, |
1801 | struct net_device *dev) | 1805 | struct sk_buff *skb, u32 info_flags) |
1802 | { | 1806 | { |
1803 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1804 | struct ieee80211_local *local = sdata->local; | 1807 | struct ieee80211_local *local = sdata->local; |
1805 | struct ieee80211_tx_info *info; | 1808 | struct ieee80211_tx_info *info; |
1806 | int head_need; | 1809 | int head_need; |
@@ -1816,25 +1819,17 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1816 | bool wme_sta = false, authorized = false, tdls_auth = false; | 1819 | bool wme_sta = false, authorized = false, tdls_auth = false; |
1817 | bool tdls_peer = false, tdls_setup_frame = false; | 1820 | bool tdls_peer = false, tdls_setup_frame = false; |
1818 | bool multicast; | 1821 | bool multicast; |
1819 | u32 info_flags = 0; | ||
1820 | u16 info_id = 0; | 1822 | u16 info_id = 0; |
1821 | struct ieee80211_chanctx_conf *chanctx_conf; | 1823 | struct ieee80211_chanctx_conf *chanctx_conf; |
1822 | struct ieee80211_sub_if_data *ap_sdata; | 1824 | struct ieee80211_sub_if_data *ap_sdata; |
1823 | enum ieee80211_band band; | 1825 | enum ieee80211_band band; |
1824 | 1826 | int ret; | |
1825 | if (unlikely(skb->len < ETH_HLEN)) | ||
1826 | goto fail; | ||
1827 | 1827 | ||
1828 | /* convert Ethernet header to proper 802.11 header (based on | 1828 | /* convert Ethernet header to proper 802.11 header (based on |
1829 | * operation mode) */ | 1829 | * operation mode) */ |
1830 | ethertype = (skb->data[12] << 8) | skb->data[13]; | 1830 | ethertype = (skb->data[12] << 8) | skb->data[13]; |
1831 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); | 1831 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); |
1832 | 1832 | ||
1833 | rcu_read_lock(); | ||
1834 | |||
1835 | /* Measure frame arrival for Tx latency statistics calculation */ | ||
1836 | ieee80211_tx_latency_start_msrmnt(local, skb); | ||
1837 | |||
1838 | switch (sdata->vif.type) { | 1833 | switch (sdata->vif.type) { |
1839 | case NL80211_IFTYPE_AP_VLAN: | 1834 | case NL80211_IFTYPE_AP_VLAN: |
1840 | sta = rcu_dereference(sdata->u.vlan.sta); | 1835 | sta = rcu_dereference(sdata->u.vlan.sta); |
@@ -1852,8 +1847,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1852 | ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, | 1847 | ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, |
1853 | u.ap); | 1848 | u.ap); |
1854 | chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); | 1849 | chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); |
1855 | if (!chanctx_conf) | 1850 | if (!chanctx_conf) { |
1856 | goto fail_rcu; | 1851 | ret = -ENOTCONN; |
1852 | goto free; | ||
1853 | } | ||
1857 | band = chanctx_conf->def.chan->band; | 1854 | band = chanctx_conf->def.chan->band; |
1858 | if (sta) | 1855 | if (sta) |
1859 | break; | 1856 | break; |
@@ -1861,8 +1858,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1861 | case NL80211_IFTYPE_AP: | 1858 | case NL80211_IFTYPE_AP: |
1862 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 1859 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
1863 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1860 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
1864 | if (!chanctx_conf) | 1861 | if (!chanctx_conf) { |
1865 | goto fail_rcu; | 1862 | ret = -ENOTCONN; |
1863 | goto free; | ||
1864 | } | ||
1866 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 1865 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
1867 | /* DA BSSID SA */ | 1866 | /* DA BSSID SA */ |
1868 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1867 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -1949,8 +1948,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1949 | 1948 | ||
1950 | } | 1949 | } |
1951 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1950 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
1952 | if (!chanctx_conf) | 1951 | if (!chanctx_conf) { |
1953 | goto fail_rcu; | 1952 | ret = -ENOTCONN; |
1953 | goto free; | ||
1954 | } | ||
1954 | band = chanctx_conf->def.chan->band; | 1955 | band = chanctx_conf->def.chan->band; |
1955 | break; | 1956 | break; |
1956 | #endif | 1957 | #endif |
@@ -1980,8 +1981,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1980 | * of a link teardown after a TDLS sta is removed due to being | 1981 | * of a link teardown after a TDLS sta is removed due to being |
1981 | * unreachable. | 1982 | * unreachable. |
1982 | */ | 1983 | */ |
1983 | if (tdls_peer && !tdls_auth && !tdls_setup_frame) | 1984 | if (tdls_peer && !tdls_auth && !tdls_setup_frame) { |
1984 | goto fail_rcu; | 1985 | ret = -EINVAL; |
1986 | goto free; | ||
1987 | } | ||
1985 | 1988 | ||
1986 | /* send direct packets to authorized TDLS peers */ | 1989 | /* send direct packets to authorized TDLS peers */ |
1987 | if (tdls_peer && tdls_auth) { | 1990 | if (tdls_peer && tdls_auth) { |
@@ -2009,8 +2012,23 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2009 | hdrlen = 24; | 2012 | hdrlen = 24; |
2010 | } | 2013 | } |
2011 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2014 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2012 | if (!chanctx_conf) | 2015 | if (!chanctx_conf) { |
2013 | goto fail_rcu; | 2016 | ret = -ENOTCONN; |
2017 | goto free; | ||
2018 | } | ||
2019 | band = chanctx_conf->def.chan->band; | ||
2020 | break; | ||
2021 | case NL80211_IFTYPE_OCB: | ||
2022 | /* DA SA BSSID */ | ||
2023 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||
2024 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
2025 | eth_broadcast_addr(hdr.addr3); | ||
2026 | hdrlen = 24; | ||
2027 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
2028 | if (!chanctx_conf) { | ||
2029 | ret = -ENOTCONN; | ||
2030 | goto free; | ||
2031 | } | ||
2014 | band = chanctx_conf->def.chan->band; | 2032 | band = chanctx_conf->def.chan->band; |
2015 | break; | 2033 | break; |
2016 | case NL80211_IFTYPE_ADHOC: | 2034 | case NL80211_IFTYPE_ADHOC: |
@@ -2020,12 +2038,15 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2020 | memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); | 2038 | memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); |
2021 | hdrlen = 24; | 2039 | hdrlen = 24; |
2022 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2040 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2023 | if (!chanctx_conf) | 2041 | if (!chanctx_conf) { |
2024 | goto fail_rcu; | 2042 | ret = -ENOTCONN; |
2043 | goto free; | ||
2044 | } | ||
2025 | band = chanctx_conf->def.chan->band; | 2045 | band = chanctx_conf->def.chan->band; |
2026 | break; | 2046 | break; |
2027 | default: | 2047 | default: |
2028 | goto fail_rcu; | 2048 | ret = -EINVAL; |
2049 | goto free; | ||
2029 | } | 2050 | } |
2030 | 2051 | ||
2031 | /* | 2052 | /* |
@@ -2057,17 +2078,19 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2057 | * EAPOL frames from the local station. | 2078 | * EAPOL frames from the local station. |
2058 | */ | 2079 | */ |
2059 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && | 2080 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && |
2081 | (sdata->vif.type != NL80211_IFTYPE_OCB) && | ||
2060 | !multicast && !authorized && | 2082 | !multicast && !authorized && |
2061 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || | 2083 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || |
2062 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { | 2084 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { |
2063 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2085 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
2064 | net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", | 2086 | net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", |
2065 | dev->name, hdr.addr1); | 2087 | sdata->name, hdr.addr1); |
2066 | #endif | 2088 | #endif |
2067 | 2089 | ||
2068 | I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); | 2090 | I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); |
2069 | 2091 | ||
2070 | goto fail_rcu; | 2092 | ret = -EPERM; |
2093 | goto free; | ||
2071 | } | 2094 | } |
2072 | 2095 | ||
2073 | if (unlikely(!multicast && skb->sk && | 2096 | if (unlikely(!multicast && skb->sk && |
@@ -2104,8 +2127,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2104 | skb = skb_clone(skb, GFP_ATOMIC); | 2127 | skb = skb_clone(skb, GFP_ATOMIC); |
2105 | kfree_skb(tmp_skb); | 2128 | kfree_skb(tmp_skb); |
2106 | 2129 | ||
2107 | if (!skb) | 2130 | if (!skb) { |
2108 | goto fail_rcu; | 2131 | ret = -ENOMEM; |
2132 | goto free; | ||
2133 | } | ||
2109 | } | 2134 | } |
2110 | 2135 | ||
2111 | hdr.frame_control = fc; | 2136 | hdr.frame_control = fc; |
@@ -2154,7 +2179,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2154 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { | 2179 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { |
2155 | ieee80211_free_txskb(&local->hw, skb); | 2180 | ieee80211_free_txskb(&local->hw, skb); |
2156 | skb = NULL; | 2181 | skb = NULL; |
2157 | goto fail_rcu; | 2182 | return ERR_PTR(-ENOMEM); |
2158 | } | 2183 | } |
2159 | } | 2184 | } |
2160 | 2185 | ||
@@ -2188,9 +2213,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2188 | nh_pos += hdrlen; | 2213 | nh_pos += hdrlen; |
2189 | h_pos += hdrlen; | 2214 | h_pos += hdrlen; |
2190 | 2215 | ||
2191 | dev->stats.tx_packets++; | ||
2192 | dev->stats.tx_bytes += skb->len; | ||
2193 | |||
2194 | /* Update skb pointers to various headers since this modified frame | 2216 | /* Update skb pointers to various headers since this modified frame |
2195 | * is going to go through Linux networking code that may potentially | 2217 | * is going to go through Linux networking code that may potentially |
2196 | * need things like pointer to IP header. */ | 2218 | * need things like pointer to IP header. */ |
@@ -2201,23 +2223,90 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2201 | info = IEEE80211_SKB_CB(skb); | 2223 | info = IEEE80211_SKB_CB(skb); |
2202 | memset(info, 0, sizeof(*info)); | 2224 | memset(info, 0, sizeof(*info)); |
2203 | 2225 | ||
2204 | dev->trans_start = jiffies; | ||
2205 | |||
2206 | info->flags = info_flags; | 2226 | info->flags = info_flags; |
2207 | info->ack_frame_id = info_id; | 2227 | info->ack_frame_id = info_id; |
2228 | info->band = band; | ||
2208 | 2229 | ||
2209 | ieee80211_xmit(sdata, skb, band); | 2230 | return skb; |
2210 | rcu_read_unlock(); | 2231 | free: |
2232 | kfree_skb(skb); | ||
2233 | return ERR_PTR(ret); | ||
2234 | } | ||
2211 | 2235 | ||
2212 | return NETDEV_TX_OK; | 2236 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, |
2237 | struct net_device *dev, | ||
2238 | u32 info_flags) | ||
2239 | { | ||
2240 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2241 | struct ieee80211_local *local = sdata->local; | ||
2242 | |||
2243 | if (unlikely(skb->len < ETH_HLEN)) { | ||
2244 | kfree_skb(skb); | ||
2245 | return; | ||
2246 | } | ||
2247 | |||
2248 | rcu_read_lock(); | ||
2249 | |||
2250 | /* Measure frame arrival for Tx latency statistics calculation */ | ||
2251 | ieee80211_tx_latency_start_msrmnt(local, skb); | ||
2252 | |||
2253 | skb = ieee80211_build_hdr(sdata, skb, info_flags); | ||
2254 | if (IS_ERR(skb)) | ||
2255 | goto out; | ||
2213 | 2256 | ||
2214 | fail_rcu: | 2257 | dev->stats.tx_packets++; |
2258 | dev->stats.tx_bytes += skb->len; | ||
2259 | dev->trans_start = jiffies; | ||
2260 | |||
2261 | ieee80211_xmit(sdata, skb); | ||
2262 | out: | ||
2215 | rcu_read_unlock(); | 2263 | rcu_read_unlock(); |
2216 | fail: | 2264 | } |
2217 | dev_kfree_skb(skb); | 2265 | |
2266 | /** | ||
2267 | * ieee80211_subif_start_xmit - netif start_xmit function for 802.3 vifs | ||
2268 | * @skb: packet to be sent | ||
2269 | * @dev: incoming interface | ||
2270 | * | ||
2271 | * On failure skb will be freed. | ||
2272 | */ | ||
2273 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||
2274 | struct net_device *dev) | ||
2275 | { | ||
2276 | __ieee80211_subif_start_xmit(skb, dev, 0); | ||
2218 | return NETDEV_TX_OK; | 2277 | return NETDEV_TX_OK; |
2219 | } | 2278 | } |
2220 | 2279 | ||
2280 | struct sk_buff * | ||
2281 | ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, | ||
2282 | struct sk_buff *skb, u32 info_flags) | ||
2283 | { | ||
2284 | struct ieee80211_hdr *hdr; | ||
2285 | struct ieee80211_tx_data tx = { | ||
2286 | .local = sdata->local, | ||
2287 | .sdata = sdata, | ||
2288 | }; | ||
2289 | |||
2290 | rcu_read_lock(); | ||
2291 | |||
2292 | skb = ieee80211_build_hdr(sdata, skb, info_flags); | ||
2293 | if (IS_ERR(skb)) | ||
2294 | goto out; | ||
2295 | |||
2296 | hdr = (void *)skb->data; | ||
2297 | tx.sta = sta_info_get(sdata, hdr->addr1); | ||
2298 | tx.skb = skb; | ||
2299 | |||
2300 | if (ieee80211_tx_h_select_key(&tx) != TX_CONTINUE) { | ||
2301 | rcu_read_unlock(); | ||
2302 | kfree_skb(skb); | ||
2303 | return ERR_PTR(-EINVAL); | ||
2304 | } | ||
2305 | |||
2306 | out: | ||
2307 | rcu_read_unlock(); | ||
2308 | return skb; | ||
2309 | } | ||
2221 | 2310 | ||
2222 | /* | 2311 | /* |
2223 | * ieee80211_clear_tx_pending may not be called in a context where | 2312 | * ieee80211_clear_tx_pending may not be called in a context where |
@@ -2257,8 +2346,8 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
2257 | dev_kfree_skb(skb); | 2346 | dev_kfree_skb(skb); |
2258 | return true; | 2347 | return true; |
2259 | } | 2348 | } |
2260 | result = ieee80211_tx(sdata, skb, true, | 2349 | info->band = chanctx_conf->def.chan->band; |
2261 | chanctx_conf->def.chan->band); | 2350 | result = ieee80211_tx(sdata, skb, true); |
2262 | } else { | 2351 | } else { |
2263 | struct sk_buff_head skbs; | 2352 | struct sk_buff_head skbs; |
2264 | 2353 | ||
@@ -2872,19 +2961,16 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | |||
2872 | EXPORT_SYMBOL(ieee80211_nullfunc_get); | 2961 | EXPORT_SYMBOL(ieee80211_nullfunc_get); |
2873 | 2962 | ||
2874 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | 2963 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, |
2875 | struct ieee80211_vif *vif, | 2964 | const u8 *src_addr, |
2876 | const u8 *ssid, size_t ssid_len, | 2965 | const u8 *ssid, size_t ssid_len, |
2877 | size_t tailroom) | 2966 | size_t tailroom) |
2878 | { | 2967 | { |
2879 | struct ieee80211_sub_if_data *sdata; | 2968 | struct ieee80211_local *local = hw_to_local(hw); |
2880 | struct ieee80211_local *local; | ||
2881 | struct ieee80211_hdr_3addr *hdr; | 2969 | struct ieee80211_hdr_3addr *hdr; |
2882 | struct sk_buff *skb; | 2970 | struct sk_buff *skb; |
2883 | size_t ie_ssid_len; | 2971 | size_t ie_ssid_len; |
2884 | u8 *pos; | 2972 | u8 *pos; |
2885 | 2973 | ||
2886 | sdata = vif_to_sdata(vif); | ||
2887 | local = sdata->local; | ||
2888 | ie_ssid_len = 2 + ssid_len; | 2974 | ie_ssid_len = 2 + ssid_len; |
2889 | 2975 | ||
2890 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + | 2976 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + |
@@ -2899,7 +2985,7 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | |||
2899 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 2985 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
2900 | IEEE80211_STYPE_PROBE_REQ); | 2986 | IEEE80211_STYPE_PROBE_REQ); |
2901 | eth_broadcast_addr(hdr->addr1); | 2987 | eth_broadcast_addr(hdr->addr1); |
2902 | memcpy(hdr->addr2, vif->addr, ETH_ALEN); | 2988 | memcpy(hdr->addr2, src_addr, ETH_ALEN); |
2903 | eth_broadcast_addr(hdr->addr3); | 2989 | eth_broadcast_addr(hdr->addr3); |
2904 | 2990 | ||
2905 | pos = skb_put(skb, ie_ssid_len); | 2991 | pos = skb_put(skb, ie_ssid_len); |
@@ -3018,6 +3104,97 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
3018 | } | 3104 | } |
3019 | EXPORT_SYMBOL(ieee80211_get_buffered_bc); | 3105 | EXPORT_SYMBOL(ieee80211_get_buffered_bc); |
3020 | 3106 | ||
3107 | int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid) | ||
3108 | { | ||
3109 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
3110 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
3111 | struct ieee80211_local *local = sdata->local; | ||
3112 | int ret; | ||
3113 | u32 queues; | ||
3114 | |||
3115 | lockdep_assert_held(&local->sta_mtx); | ||
3116 | |||
3117 | /* only some cases are supported right now */ | ||
3118 | switch (sdata->vif.type) { | ||
3119 | case NL80211_IFTYPE_STATION: | ||
3120 | case NL80211_IFTYPE_AP: | ||
3121 | case NL80211_IFTYPE_AP_VLAN: | ||
3122 | break; | ||
3123 | default: | ||
3124 | WARN_ON(1); | ||
3125 | return -EINVAL; | ||
3126 | } | ||
3127 | |||
3128 | if (WARN_ON(tid >= IEEE80211_NUM_UPS)) | ||
3129 | return -EINVAL; | ||
3130 | |||
3131 | if (sta->reserved_tid == tid) { | ||
3132 | ret = 0; | ||
3133 | goto out; | ||
3134 | } | ||
3135 | |||
3136 | if (sta->reserved_tid != IEEE80211_TID_UNRESERVED) { | ||
3137 | sdata_err(sdata, "TID reservation already active\n"); | ||
3138 | ret = -EALREADY; | ||
3139 | goto out; | ||
3140 | } | ||
3141 | |||
3142 | ieee80211_stop_vif_queues(sdata->local, sdata, | ||
3143 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID); | ||
3144 | |||
3145 | synchronize_net(); | ||
3146 | |||
3147 | /* Tear down BA sessions so we stop aggregating on this TID */ | ||
3148 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
3149 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
3150 | __ieee80211_stop_tx_ba_session(sta, tid, | ||
3151 | AGG_STOP_LOCAL_REQUEST); | ||
3152 | } | ||
3153 | |||
3154 | queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]); | ||
3155 | __ieee80211_flush_queues(local, sdata, queues); | ||
3156 | |||
3157 | sta->reserved_tid = tid; | ||
3158 | |||
3159 | ieee80211_wake_vif_queues(local, sdata, | ||
3160 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID); | ||
3161 | |||
3162 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) | ||
3163 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
3164 | |||
3165 | ret = 0; | ||
3166 | out: | ||
3167 | return ret; | ||
3168 | } | ||
3169 | EXPORT_SYMBOL(ieee80211_reserve_tid); | ||
3170 | |||
3171 | void ieee80211_unreserve_tid(struct ieee80211_sta *pubsta, u8 tid) | ||
3172 | { | ||
3173 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
3174 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
3175 | |||
3176 | lockdep_assert_held(&sdata->local->sta_mtx); | ||
3177 | |||
3178 | /* only some cases are supported right now */ | ||
3179 | switch (sdata->vif.type) { | ||
3180 | case NL80211_IFTYPE_STATION: | ||
3181 | case NL80211_IFTYPE_AP: | ||
3182 | case NL80211_IFTYPE_AP_VLAN: | ||
3183 | break; | ||
3184 | default: | ||
3185 | WARN_ON(1); | ||
3186 | return; | ||
3187 | } | ||
3188 | |||
3189 | if (tid != sta->reserved_tid) { | ||
3190 | sdata_err(sdata, "TID to unreserve (%d) isn't reserved\n", tid); | ||
3191 | return; | ||
3192 | } | ||
3193 | |||
3194 | sta->reserved_tid = IEEE80211_TID_UNRESERVED; | ||
3195 | } | ||
3196 | EXPORT_SYMBOL(ieee80211_unreserve_tid); | ||
3197 | |||
3021 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | 3198 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, |
3022 | struct sk_buff *skb, int tid, | 3199 | struct sk_buff *skb, int tid, |
3023 | enum ieee80211_band band) | 3200 | enum ieee80211_band band) |
@@ -3039,6 +3216,7 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | |||
3039 | * requirements are that we do not come into tx with bhs on. | 3216 | * requirements are that we do not come into tx with bhs on. |
3040 | */ | 3217 | */ |
3041 | local_bh_disable(); | 3218 | local_bh_disable(); |
3042 | ieee80211_xmit(sdata, skb, band); | 3219 | IEEE80211_SKB_CB(skb)->band = band; |
3220 | ieee80211_xmit(sdata, skb); | ||
3043 | local_bh_enable(); | 3221 | local_bh_enable(); |
3044 | } | 3222 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3c61060a4d2b..974ebe70f5b0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -576,15 +576,19 @@ ieee80211_get_vif_queues(struct ieee80211_local *local, | |||
576 | return queues; | 576 | return queues; |
577 | } | 577 | } |
578 | 578 | ||
579 | void ieee80211_flush_queues(struct ieee80211_local *local, | 579 | void __ieee80211_flush_queues(struct ieee80211_local *local, |
580 | struct ieee80211_sub_if_data *sdata) | 580 | struct ieee80211_sub_if_data *sdata, |
581 | unsigned int queues) | ||
581 | { | 582 | { |
582 | unsigned int queues; | ||
583 | |||
584 | if (!local->ops->flush) | 583 | if (!local->ops->flush) |
585 | return; | 584 | return; |
586 | 585 | ||
587 | queues = ieee80211_get_vif_queues(local, sdata); | 586 | /* |
587 | * If no queue was set, or if the HW doesn't support | ||
588 | * IEEE80211_HW_QUEUE_CONTROL - flush all queues | ||
589 | */ | ||
590 | if (!queues || !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) | ||
591 | queues = ieee80211_get_vif_queues(local, sdata); | ||
588 | 592 | ||
589 | ieee80211_stop_queues_by_reason(&local->hw, queues, | 593 | ieee80211_stop_queues_by_reason(&local->hw, queues, |
590 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | 594 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
@@ -597,6 +601,12 @@ void ieee80211_flush_queues(struct ieee80211_local *local, | |||
597 | false); | 601 | false); |
598 | } | 602 | } |
599 | 603 | ||
604 | void ieee80211_flush_queues(struct ieee80211_local *local, | ||
605 | struct ieee80211_sub_if_data *sdata) | ||
606 | { | ||
607 | __ieee80211_flush_queues(local, sdata, 0); | ||
608 | } | ||
609 | |||
600 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, | 610 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, |
601 | struct ieee80211_sub_if_data *sdata, | 611 | struct ieee80211_sub_if_data *sdata, |
602 | enum queue_stop_reason reason) | 612 | enum queue_stop_reason reason) |
@@ -693,6 +703,34 @@ void ieee80211_iterate_active_interfaces_rtnl( | |||
693 | } | 703 | } |
694 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); | 704 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); |
695 | 705 | ||
706 | static void __iterate_stations(struct ieee80211_local *local, | ||
707 | void (*iterator)(void *data, | ||
708 | struct ieee80211_sta *sta), | ||
709 | void *data) | ||
710 | { | ||
711 | struct sta_info *sta; | ||
712 | |||
713 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
714 | if (!sta->uploaded) | ||
715 | continue; | ||
716 | |||
717 | iterator(data, &sta->sta); | ||
718 | } | ||
719 | } | ||
720 | |||
721 | void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw, | ||
722 | void (*iterator)(void *data, | ||
723 | struct ieee80211_sta *sta), | ||
724 | void *data) | ||
725 | { | ||
726 | struct ieee80211_local *local = hw_to_local(hw); | ||
727 | |||
728 | rcu_read_lock(); | ||
729 | __iterate_stations(local, iterator, data); | ||
730 | rcu_read_unlock(); | ||
731 | } | ||
732 | EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_atomic); | ||
733 | |||
696 | struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev) | 734 | struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev) |
697 | { | 735 | { |
698 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 736 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
@@ -803,6 +841,9 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
803 | case WLAN_EID_SECONDARY_CHANNEL_OFFSET: | 841 | case WLAN_EID_SECONDARY_CHANNEL_OFFSET: |
804 | case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: | 842 | case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: |
805 | case WLAN_EID_CHAN_SWITCH_PARAM: | 843 | case WLAN_EID_CHAN_SWITCH_PARAM: |
844 | case WLAN_EID_EXT_CAPABILITY: | ||
845 | case WLAN_EID_CHAN_SWITCH_TIMING: | ||
846 | case WLAN_EID_LINK_ID: | ||
806 | /* | 847 | /* |
807 | * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible | 848 | * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible |
808 | * that if the content gets bigger it might be needed more than once | 849 | * that if the content gets bigger it might be needed more than once |
@@ -822,6 +863,24 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
822 | elem_parse_failed = false; | 863 | elem_parse_failed = false; |
823 | 864 | ||
824 | switch (id) { | 865 | switch (id) { |
866 | case WLAN_EID_LINK_ID: | ||
867 | if (elen + 2 != sizeof(struct ieee80211_tdls_lnkie)) { | ||
868 | elem_parse_failed = true; | ||
869 | break; | ||
870 | } | ||
871 | elems->lnk_id = (void *)(pos - 2); | ||
872 | break; | ||
873 | case WLAN_EID_CHAN_SWITCH_TIMING: | ||
874 | if (elen != sizeof(struct ieee80211_ch_switch_timing)) { | ||
875 | elem_parse_failed = true; | ||
876 | break; | ||
877 | } | ||
878 | elems->ch_sw_timing = (void *)pos; | ||
879 | break; | ||
880 | case WLAN_EID_EXT_CAPABILITY: | ||
881 | elems->ext_capab = pos; | ||
882 | elems->ext_capab_len = elen; | ||
883 | break; | ||
825 | case WLAN_EID_SSID: | 884 | case WLAN_EID_SSID: |
826 | elems->ssid = pos; | 885 | elems->ssid = pos; |
827 | elems->ssid_len = elen; | 886 | elems->ssid_len = elen; |
@@ -1073,6 +1132,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1073 | struct ieee80211_chanctx_conf *chanctx_conf; | 1132 | struct ieee80211_chanctx_conf *chanctx_conf; |
1074 | int ac; | 1133 | int ac; |
1075 | bool use_11b, enable_qos; | 1134 | bool use_11b, enable_qos; |
1135 | bool is_ocb; /* Use another EDCA parameters if dot11OCBActivated=true */ | ||
1076 | int aCWmin, aCWmax; | 1136 | int aCWmin, aCWmax; |
1077 | 1137 | ||
1078 | if (!local->ops->conf_tx) | 1138 | if (!local->ops->conf_tx) |
@@ -1097,6 +1157,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1097 | */ | 1157 | */ |
1098 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); | 1158 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); |
1099 | 1159 | ||
1160 | is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB); | ||
1161 | |||
1100 | /* Set defaults according to 802.11-2007 Table 7-37 */ | 1162 | /* Set defaults according to 802.11-2007 Table 7-37 */ |
1101 | aCWmax = 1023; | 1163 | aCWmax = 1023; |
1102 | if (use_11b) | 1164 | if (use_11b) |
@@ -1118,7 +1180,10 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1118 | qparam.cw_max = aCWmax; | 1180 | qparam.cw_max = aCWmax; |
1119 | qparam.cw_min = aCWmin; | 1181 | qparam.cw_min = aCWmin; |
1120 | qparam.txop = 0; | 1182 | qparam.txop = 0; |
1121 | qparam.aifs = 7; | 1183 | if (is_ocb) |
1184 | qparam.aifs = 9; | ||
1185 | else | ||
1186 | qparam.aifs = 7; | ||
1122 | break; | 1187 | break; |
1123 | /* never happens but let's not leave undefined */ | 1188 | /* never happens but let's not leave undefined */ |
1124 | default: | 1189 | default: |
@@ -1126,21 +1191,32 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1126 | qparam.cw_max = aCWmax; | 1191 | qparam.cw_max = aCWmax; |
1127 | qparam.cw_min = aCWmin; | 1192 | qparam.cw_min = aCWmin; |
1128 | qparam.txop = 0; | 1193 | qparam.txop = 0; |
1129 | qparam.aifs = 3; | 1194 | if (is_ocb) |
1195 | qparam.aifs = 6; | ||
1196 | else | ||
1197 | qparam.aifs = 3; | ||
1130 | break; | 1198 | break; |
1131 | case IEEE80211_AC_VI: | 1199 | case IEEE80211_AC_VI: |
1132 | qparam.cw_max = aCWmin; | 1200 | qparam.cw_max = aCWmin; |
1133 | qparam.cw_min = (aCWmin + 1) / 2 - 1; | 1201 | qparam.cw_min = (aCWmin + 1) / 2 - 1; |
1134 | if (use_11b) | 1202 | if (is_ocb) |
1203 | qparam.txop = 0; | ||
1204 | else if (use_11b) | ||
1135 | qparam.txop = 6016/32; | 1205 | qparam.txop = 6016/32; |
1136 | else | 1206 | else |
1137 | qparam.txop = 3008/32; | 1207 | qparam.txop = 3008/32; |
1138 | qparam.aifs = 2; | 1208 | |
1209 | if (is_ocb) | ||
1210 | qparam.aifs = 3; | ||
1211 | else | ||
1212 | qparam.aifs = 2; | ||
1139 | break; | 1213 | break; |
1140 | case IEEE80211_AC_VO: | 1214 | case IEEE80211_AC_VO: |
1141 | qparam.cw_max = (aCWmin + 1) / 2 - 1; | 1215 | qparam.cw_max = (aCWmin + 1) / 2 - 1; |
1142 | qparam.cw_min = (aCWmin + 1) / 4 - 1; | 1216 | qparam.cw_min = (aCWmin + 1) / 4 - 1; |
1143 | if (use_11b) | 1217 | if (is_ocb) |
1218 | qparam.txop = 0; | ||
1219 | else if (use_11b) | ||
1144 | qparam.txop = 3264/32; | 1220 | qparam.txop = 3264/32; |
1145 | else | 1221 | else |
1146 | qparam.txop = 1504/32; | 1222 | qparam.txop = 1504/32; |
@@ -1263,6 +1339,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, | |||
1263 | int ext_rates_len; | 1339 | int ext_rates_len; |
1264 | int shift; | 1340 | int shift; |
1265 | u32 rate_flags; | 1341 | u32 rate_flags; |
1342 | bool have_80mhz = false; | ||
1266 | 1343 | ||
1267 | *offset = 0; | 1344 | *offset = 0; |
1268 | 1345 | ||
@@ -1391,7 +1468,15 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, | |||
1391 | *offset = noffset; | 1468 | *offset = noffset; |
1392 | } | 1469 | } |
1393 | 1470 | ||
1394 | if (sband->vht_cap.vht_supported) { | 1471 | /* Check if any channel in this sband supports at least 80 MHz */ |
1472 | for (i = 0; i < sband->n_channels; i++) { | ||
1473 | if (!(sband->channels[i].flags & IEEE80211_CHAN_NO_80MHZ)) { | ||
1474 | have_80mhz = true; | ||
1475 | break; | ||
1476 | } | ||
1477 | } | ||
1478 | |||
1479 | if (sband->vht_cap.vht_supported && have_80mhz) { | ||
1395 | if (end - pos < 2 + sizeof(struct ieee80211_vht_cap)) | 1480 | if (end - pos < 2 + sizeof(struct ieee80211_vht_cap)) |
1396 | goto out_err; | 1481 | goto out_err; |
1397 | pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, | 1482 | pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, |
@@ -1447,7 +1532,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1447 | }; | 1532 | }; |
1448 | 1533 | ||
1449 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1534 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1450 | u8 *dst, u32 ratemask, | 1535 | const u8 *src, const u8 *dst, |
1536 | u32 ratemask, | ||
1451 | struct ieee80211_channel *chan, | 1537 | struct ieee80211_channel *chan, |
1452 | const u8 *ssid, size_t ssid_len, | 1538 | const u8 *ssid, size_t ssid_len, |
1453 | const u8 *ie, size_t ie_len, | 1539 | const u8 *ie, size_t ie_len, |
@@ -1472,8 +1558,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1472 | else | 1558 | else |
1473 | chandef.chan = chan; | 1559 | chandef.chan = chan; |
1474 | 1560 | ||
1475 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 1561 | skb = ieee80211_probereq_get(&local->hw, src, ssid, ssid_len, |
1476 | ssid, ssid_len, 100 + ie_len); | 1562 | 100 + ie_len); |
1477 | if (!skb) | 1563 | if (!skb) |
1478 | return NULL; | 1564 | return NULL; |
1479 | 1565 | ||
@@ -1495,7 +1581,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1495 | return skb; | 1581 | return skb; |
1496 | } | 1582 | } |
1497 | 1583 | ||
1498 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1584 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, |
1585 | const u8 *src, const u8 *dst, | ||
1499 | const u8 *ssid, size_t ssid_len, | 1586 | const u8 *ssid, size_t ssid_len, |
1500 | const u8 *ie, size_t ie_len, | 1587 | const u8 *ie, size_t ie_len, |
1501 | u32 ratemask, bool directed, u32 tx_flags, | 1588 | u32 ratemask, bool directed, u32 tx_flags, |
@@ -1503,7 +1590,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1503 | { | 1590 | { |
1504 | struct sk_buff *skb; | 1591 | struct sk_buff *skb; |
1505 | 1592 | ||
1506 | skb = ieee80211_build_probe_req(sdata, dst, ratemask, channel, | 1593 | skb = ieee80211_build_probe_req(sdata, src, dst, ratemask, channel, |
1507 | ssid, ssid_len, | 1594 | ssid, ssid_len, |
1508 | ie, ie_len, directed); | 1595 | ie, ie_len, directed); |
1509 | if (skb) { | 1596 | if (skb) { |
@@ -1645,6 +1732,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1645 | int res, i; | 1732 | int res, i; |
1646 | bool reconfig_due_to_wowlan = false; | 1733 | bool reconfig_due_to_wowlan = false; |
1647 | struct ieee80211_sub_if_data *sched_scan_sdata; | 1734 | struct ieee80211_sub_if_data *sched_scan_sdata; |
1735 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
1648 | bool sched_scan_stopped = false; | 1736 | bool sched_scan_stopped = false; |
1649 | 1737 | ||
1650 | #ifdef CONFIG_PM | 1738 | #ifdef CONFIG_PM |
@@ -1813,6 +1901,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1813 | ieee80211_bss_info_change_notify(sdata, changed); | 1901 | ieee80211_bss_info_change_notify(sdata, changed); |
1814 | sdata_unlock(sdata); | 1902 | sdata_unlock(sdata); |
1815 | break; | 1903 | break; |
1904 | case NL80211_IFTYPE_OCB: | ||
1905 | changed |= BSS_CHANGED_OCB; | ||
1906 | ieee80211_bss_info_change_notify(sdata, changed); | ||
1907 | break; | ||
1816 | case NL80211_IFTYPE_ADHOC: | 1908 | case NL80211_IFTYPE_ADHOC: |
1817 | changed |= BSS_CHANGED_IBSS; | 1909 | changed |= BSS_CHANGED_IBSS; |
1818 | /* fall through */ | 1910 | /* fall through */ |
@@ -1931,13 +2023,15 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1931 | mutex_lock(&local->mtx); | 2023 | mutex_lock(&local->mtx); |
1932 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, | 2024 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, |
1933 | lockdep_is_held(&local->mtx)); | 2025 | lockdep_is_held(&local->mtx)); |
1934 | if (sched_scan_sdata && local->sched_scan_req) | 2026 | sched_scan_req = rcu_dereference_protected(local->sched_scan_req, |
2027 | lockdep_is_held(&local->mtx)); | ||
2028 | if (sched_scan_sdata && sched_scan_req) | ||
1935 | /* | 2029 | /* |
1936 | * Sched scan stopped, but we don't want to report it. Instead, | 2030 | * Sched scan stopped, but we don't want to report it. Instead, |
1937 | * we're trying to reschedule. | 2031 | * we're trying to reschedule. |
1938 | */ | 2032 | */ |
1939 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, | 2033 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, |
1940 | local->sched_scan_req)) | 2034 | sched_scan_req)) |
1941 | sched_scan_stopped = true; | 2035 | sched_scan_stopped = true; |
1942 | mutex_unlock(&local->mtx); | 2036 | mutex_unlock(&local->mtx); |
1943 | 2037 | ||
@@ -1949,7 +2043,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1949 | * We may want to change that later, however. | 2043 | * We may want to change that later, however. |
1950 | */ | 2044 | */ |
1951 | if (!local->suspended || reconfig_due_to_wowlan) | 2045 | if (!local->suspended || reconfig_due_to_wowlan) |
1952 | drv_restart_complete(local); | 2046 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART); |
1953 | 2047 | ||
1954 | if (!local->suspended) | 2048 | if (!local->suspended) |
1955 | return 0; | 2049 | return 0; |
@@ -1960,6 +2054,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1960 | mb(); | 2054 | mb(); |
1961 | local->resuming = false; | 2055 | local->resuming = false; |
1962 | 2056 | ||
2057 | if (!reconfig_due_to_wowlan) | ||
2058 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND); | ||
2059 | |||
1963 | list_for_each_entry(sdata, &local->interfaces, list) { | 2060 | list_for_each_entry(sdata, &local->interfaces, list) { |
1964 | if (!ieee80211_sdata_running(sdata)) | 2061 | if (!ieee80211_sdata_running(sdata)) |
1965 | continue; | 2062 | continue; |
@@ -2052,42 +2149,36 @@ static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | |||
2052 | return false; | 2149 | return false; |
2053 | } | 2150 | } |
2054 | 2151 | ||
2055 | /** | 2152 | size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, |
2056 | * ieee80211_ie_split - split an IE buffer according to ordering | 2153 | const u8 *ids, int n_ids, |
2057 | * | 2154 | const u8 *after_ric, int n_after_ric, |
2058 | * @ies: the IE buffer | 2155 | size_t offset) |
2059 | * @ielen: the length of the IE buffer | ||
2060 | * @ids: an array with element IDs that are allowed before | ||
2061 | * the split | ||
2062 | * @n_ids: the size of the element ID array | ||
2063 | * @offset: offset where to start splitting in the buffer | ||
2064 | * | ||
2065 | * This function splits an IE buffer by updating the @offset | ||
2066 | * variable to point to the location where the buffer should be | ||
2067 | * split. | ||
2068 | * | ||
2069 | * It assumes that the given IE buffer is well-formed, this | ||
2070 | * has to be guaranteed by the caller! | ||
2071 | * | ||
2072 | * It also assumes that the IEs in the buffer are ordered | ||
2073 | * correctly, if not the result of using this function will not | ||
2074 | * be ordered correctly either, i.e. it does no reordering. | ||
2075 | * | ||
2076 | * The function returns the offset where the next part of the | ||
2077 | * buffer starts, which may be @ielen if the entire (remainder) | ||
2078 | * of the buffer should be used. | ||
2079 | */ | ||
2080 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
2081 | const u8 *ids, int n_ids, size_t offset) | ||
2082 | { | 2156 | { |
2083 | size_t pos = offset; | 2157 | size_t pos = offset; |
2084 | 2158 | ||
2085 | while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) | 2159 | while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) { |
2086 | pos += 2 + ies[pos + 1]; | 2160 | if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) { |
2161 | pos += 2 + ies[pos + 1]; | ||
2162 | |||
2163 | while (pos < ielen && | ||
2164 | !ieee80211_id_in_list(after_ric, n_after_ric, | ||
2165 | ies[pos])) | ||
2166 | pos += 2 + ies[pos + 1]; | ||
2167 | } else { | ||
2168 | pos += 2 + ies[pos + 1]; | ||
2169 | } | ||
2170 | } | ||
2087 | 2171 | ||
2088 | return pos; | 2172 | return pos; |
2089 | } | 2173 | } |
2090 | 2174 | ||
2175 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
2176 | const u8 *ids, int n_ids, size_t offset) | ||
2177 | { | ||
2178 | return ieee80211_ie_split_ric(ies, ielen, ids, n_ids, NULL, 0, offset); | ||
2179 | } | ||
2180 | EXPORT_SYMBOL(ieee80211_ie_split); | ||
2181 | |||
2091 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) | 2182 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) |
2092 | { | 2183 | { |
2093 | size_t pos = offset; | 2184 | size_t pos = offset; |
@@ -2526,11 +2617,23 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work) | |||
2526 | struct ieee80211_local *local = | 2617 | struct ieee80211_local *local = |
2527 | container_of(work, struct ieee80211_local, radar_detected_work); | 2618 | container_of(work, struct ieee80211_local, radar_detected_work); |
2528 | struct cfg80211_chan_def chandef = local->hw.conf.chandef; | 2619 | struct cfg80211_chan_def chandef = local->hw.conf.chandef; |
2620 | struct ieee80211_chanctx *ctx; | ||
2621 | int num_chanctx = 0; | ||
2622 | |||
2623 | mutex_lock(&local->chanctx_mtx); | ||
2624 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
2625 | if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) | ||
2626 | continue; | ||
2627 | |||
2628 | num_chanctx++; | ||
2629 | chandef = ctx->conf.def; | ||
2630 | } | ||
2631 | mutex_unlock(&local->chanctx_mtx); | ||
2529 | 2632 | ||
2530 | ieee80211_dfs_cac_cancel(local); | 2633 | ieee80211_dfs_cac_cancel(local); |
2531 | 2634 | ||
2532 | if (local->use_chanctx) | 2635 | if (num_chanctx > 1) |
2533 | /* currently not handled */ | 2636 | /* XXX: multi-channel is not supported yet */ |
2534 | WARN_ON(1); | 2637 | WARN_ON(1); |
2535 | else | 2638 | else |
2536 | cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); | 2639 | cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 671ce0d27a80..bc9e8fc48785 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -287,6 +287,8 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) | |||
287 | /* fall through */ | 287 | /* fall through */ |
288 | case NL80211_CHAN_WIDTH_20_NOHT: | 288 | case NL80211_CHAN_WIDTH_20_NOHT: |
289 | case NL80211_CHAN_WIDTH_20: | 289 | case NL80211_CHAN_WIDTH_20: |
290 | bw = IEEE80211_STA_RX_BW_20; | ||
291 | break; | ||
290 | case NL80211_CHAN_WIDTH_40: | 292 | case NL80211_CHAN_WIDTH_40: |
291 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | 293 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? |
292 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | 294 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 9181fb6d6437..a4220e92f0cc 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -111,8 +111,6 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, | |||
111 | (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) | 111 | (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) |
112 | return newhdr + hdrlen; | 112 | return newhdr + hdrlen; |
113 | 113 | ||
114 | skb_set_network_header(skb, skb_network_offset(skb) + | ||
115 | IEEE80211_WEP_IV_LEN); | ||
116 | ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); | 114 | ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); |
117 | return newhdr + hdrlen; | 115 | return newhdr + hdrlen; |
118 | } | 116 | } |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 3b873989992c..9eb0aee9105b 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -53,11 +53,49 @@ static int wme_downgrade_ac(struct sk_buff *skb) | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | /** | ||
57 | * ieee80211_fix_reserved_tid - return the TID to use if this one is reserved | ||
58 | * @tid: the assumed-reserved TID | ||
59 | * | ||
60 | * Returns: the alternative TID to use, or 0 on error | ||
61 | */ | ||
62 | static inline u8 ieee80211_fix_reserved_tid(u8 tid) | ||
63 | { | ||
64 | switch (tid) { | ||
65 | case 0: | ||
66 | return 3; | ||
67 | case 1: | ||
68 | return 2; | ||
69 | case 2: | ||
70 | return 1; | ||
71 | case 3: | ||
72 | return 0; | ||
73 | case 4: | ||
74 | return 5; | ||
75 | case 5: | ||
76 | return 4; | ||
77 | case 6: | ||
78 | return 7; | ||
79 | case 7: | ||
80 | return 6; | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
56 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, | 86 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, |
57 | struct sk_buff *skb) | 87 | struct sta_info *sta, struct sk_buff *skb) |
58 | { | 88 | { |
89 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
90 | |||
59 | /* in case we are a client verify acm is not set for this ac */ | 91 | /* in case we are a client verify acm is not set for this ac */ |
60 | while (unlikely(sdata->wmm_acm & BIT(skb->priority))) { | 92 | while (sdata->wmm_acm & BIT(skb->priority)) { |
93 | int ac = ieee802_1d_to_ac[skb->priority]; | ||
94 | |||
95 | if (ifmgd->tx_tspec[ac].admitted_time && | ||
96 | skb->priority == ifmgd->tx_tspec[ac].up) | ||
97 | return ac; | ||
98 | |||
61 | if (wme_downgrade_ac(skb)) { | 99 | if (wme_downgrade_ac(skb)) { |
62 | /* | 100 | /* |
63 | * This should not really happen. The AP has marked all | 101 | * This should not really happen. The AP has marked all |
@@ -69,6 +107,10 @@ static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, | |||
69 | } | 107 | } |
70 | } | 108 | } |
71 | 109 | ||
110 | /* Check to see if this is a reserved TID */ | ||
111 | if (sta && sta->reserved_tid == skb->priority) | ||
112 | skb->priority = ieee80211_fix_reserved_tid(skb->priority); | ||
113 | |||
72 | /* look up which queue to use for frames with this 1d tag */ | 114 | /* look up which queue to use for frames with this 1d tag */ |
73 | return ieee802_1d_to_ac[skb->priority]; | 115 | return ieee802_1d_to_ac[skb->priority]; |
74 | } | 116 | } |
@@ -96,7 +138,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, | |||
96 | p = ieee80211_get_qos_ctl(hdr); | 138 | p = ieee80211_get_qos_ctl(hdr); |
97 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; | 139 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; |
98 | 140 | ||
99 | return ieee80211_downgrade_queue(sdata, skb); | 141 | return ieee80211_downgrade_queue(sdata, NULL, skb); |
100 | } | 142 | } |
101 | 143 | ||
102 | /* Indicate which queue to use. */ | 144 | /* Indicate which queue to use. */ |
@@ -108,6 +150,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
108 | const u8 *ra = NULL; | 150 | const u8 *ra = NULL; |
109 | bool qos = false; | 151 | bool qos = false; |
110 | struct mac80211_qos_map *qos_map; | 152 | struct mac80211_qos_map *qos_map; |
153 | u16 ret; | ||
111 | 154 | ||
112 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { | 155 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { |
113 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 156 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
@@ -134,11 +177,20 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
134 | break; | 177 | break; |
135 | #endif | 178 | #endif |
136 | case NL80211_IFTYPE_STATION: | 179 | case NL80211_IFTYPE_STATION: |
180 | /* might be a TDLS station */ | ||
181 | sta = sta_info_get(sdata, skb->data); | ||
182 | if (sta) | ||
183 | qos = sta->sta.wme; | ||
184 | |||
137 | ra = sdata->u.mgd.bssid; | 185 | ra = sdata->u.mgd.bssid; |
138 | break; | 186 | break; |
139 | case NL80211_IFTYPE_ADHOC: | 187 | case NL80211_IFTYPE_ADHOC: |
140 | ra = skb->data; | 188 | ra = skb->data; |
141 | break; | 189 | break; |
190 | case NL80211_IFTYPE_OCB: | ||
191 | /* all stations are required to support WME */ | ||
192 | qos = true; | ||
193 | break; | ||
142 | default: | 194 | default: |
143 | break; | 195 | break; |
144 | } | 196 | } |
@@ -148,27 +200,29 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
148 | if (sta) | 200 | if (sta) |
149 | qos = sta->sta.wme; | 201 | qos = sta->sta.wme; |
150 | } | 202 | } |
151 | rcu_read_unlock(); | ||
152 | 203 | ||
153 | if (!qos) { | 204 | if (!qos) { |
154 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 205 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
155 | return IEEE80211_AC_BE; | 206 | ret = IEEE80211_AC_BE; |
207 | goto out; | ||
156 | } | 208 | } |
157 | 209 | ||
158 | if (skb->protocol == sdata->control_port_protocol) { | 210 | if (skb->protocol == sdata->control_port_protocol) { |
159 | skb->priority = 7; | 211 | skb->priority = 7; |
160 | return ieee80211_downgrade_queue(sdata, skb); | 212 | goto downgrade; |
161 | } | 213 | } |
162 | 214 | ||
163 | /* use the data classifier to determine what 802.1d tag the | 215 | /* use the data classifier to determine what 802.1d tag the |
164 | * data frame has */ | 216 | * data frame has */ |
165 | rcu_read_lock(); | ||
166 | qos_map = rcu_dereference(sdata->qos_map); | 217 | qos_map = rcu_dereference(sdata->qos_map); |
167 | skb->priority = cfg80211_classify8021d(skb, qos_map ? | 218 | skb->priority = cfg80211_classify8021d(skb, qos_map ? |
168 | &qos_map->qos_map : NULL); | 219 | &qos_map->qos_map : NULL); |
169 | rcu_read_unlock(); | ||
170 | 220 | ||
171 | return ieee80211_downgrade_queue(sdata, skb); | 221 | downgrade: |
222 | ret = ieee80211_downgrade_queue(sdata, sta, skb); | ||
223 | out: | ||
224 | rcu_read_unlock(); | ||
225 | return ret; | ||
172 | } | 226 | } |
173 | 227 | ||
174 | /** | 228 | /** |
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 7fea4bb8acbc..80151edc5195 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h | |||
@@ -13,8 +13,6 @@ | |||
13 | #include <linux/netdevice.h> | 13 | #include <linux/netdevice.h> |
14 | #include "ieee80211_i.h" | 14 | #include "ieee80211_i.h" |
15 | 15 | ||
16 | extern const int ieee802_1d_to_ac[8]; | ||
17 | |||
18 | u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, | 16 | u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, |
19 | struct sk_buff *skb, | 17 | struct sk_buff *skb, |
20 | struct ieee80211_hdr *hdr); | 18 | struct ieee80211_hdr *hdr); |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 983527a4c1ab..12398fde02e8 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -209,8 +209,6 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
209 | 209 | ||
210 | pos = skb_push(skb, IEEE80211_TKIP_IV_LEN); | 210 | pos = skb_push(skb, IEEE80211_TKIP_IV_LEN); |
211 | memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen); | 211 | memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen); |
212 | skb_set_network_header(skb, skb_network_offset(skb) + | ||
213 | IEEE80211_TKIP_IV_LEN); | ||
214 | pos += hdrlen; | 212 | pos += hdrlen; |
215 | 213 | ||
216 | /* the HW only needs room for the IV, but not the actual IV */ | 214 | /* the HW only needs room for the IV, but not the actual IV */ |
@@ -434,8 +432,6 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
434 | 432 | ||
435 | pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN); | 433 | pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN); |
436 | memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen); | 434 | memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen); |
437 | skb_set_network_header(skb, skb_network_offset(skb) + | ||
438 | IEEE80211_CCMP_HDR_LEN); | ||
439 | 435 | ||
440 | /* the HW only needs room for the IV, but not the actual IV */ | 436 | /* the HW only needs room for the IV, but not the actual IV */ |
441 | if (info->control.hw_key && | 437 | if (info->control.hw_key && |
@@ -575,7 +571,6 @@ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, | |||
575 | 571 | ||
576 | pos = skb_push(skb, cs->hdr_len); | 572 | pos = skb_push(skb, cs->hdr_len); |
577 | memmove(pos, pos + cs->hdr_len, hdrlen); | 573 | memmove(pos, pos + cs->hdr_len, hdrlen); |
578 | skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len); | ||
579 | 574 | ||
580 | return TX_CONTINUE; | 575 | return TX_CONTINUE; |
581 | } | 576 | } |
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index b60aa35c074f..f72be7433df3 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c | |||
@@ -17,6 +17,9 @@ | |||
17 | 17 | ||
18 | #include "digital.h" | 18 | #include "digital.h" |
19 | 19 | ||
20 | #define DIGITAL_NFC_DEP_N_RETRY_NACK 2 | ||
21 | #define DIGITAL_NFC_DEP_N_RETRY_ATN 2 | ||
22 | |||
20 | #define DIGITAL_NFC_DEP_FRAME_DIR_OUT 0xD4 | 23 | #define DIGITAL_NFC_DEP_FRAME_DIR_OUT 0xD4 |
21 | #define DIGITAL_NFC_DEP_FRAME_DIR_IN 0xD5 | 24 | #define DIGITAL_NFC_DEP_FRAME_DIR_IN 0xD5 |
22 | 25 | ||
@@ -32,20 +35,32 @@ | |||
32 | #define DIGITAL_ATR_REQ_MIN_SIZE 16 | 35 | #define DIGITAL_ATR_REQ_MIN_SIZE 16 |
33 | #define DIGITAL_ATR_REQ_MAX_SIZE 64 | 36 | #define DIGITAL_ATR_REQ_MAX_SIZE 64 |
34 | 37 | ||
35 | #define DIGITAL_LR_BITS_PAYLOAD_SIZE_254B 0x30 | 38 | #define DIGITAL_DID_MAX 14 |
36 | #define DIGITAL_FSL_BITS_PAYLOAD_SIZE_254B \ | 39 | |
37 | (DIGITAL_LR_BITS_PAYLOAD_SIZE_254B >> 4) | 40 | #define DIGITAL_PAYLOAD_SIZE_MAX 254 |
41 | #define DIGITAL_PAYLOAD_BITS_TO_PP(s) (((s) & 0x3) << 4) | ||
42 | #define DIGITAL_PAYLOAD_PP_TO_BITS(s) (((s) >> 4) & 0x3) | ||
43 | #define DIGITAL_PAYLOAD_BITS_TO_FSL(s) ((s) & 0x3) | ||
44 | #define DIGITAL_PAYLOAD_FSL_TO_BITS(s) ((s) & 0x3) | ||
45 | |||
38 | #define DIGITAL_GB_BIT 0x02 | 46 | #define DIGITAL_GB_BIT 0x02 |
39 | 47 | ||
48 | #define DIGITAL_NFC_DEP_REQ_RES_HEADROOM 2 /* SoD: [SB (NFC-A)] + LEN */ | ||
49 | #define DIGITAL_NFC_DEP_REQ_RES_TAILROOM 2 /* EoD: 2-byte CRC */ | ||
50 | |||
40 | #define DIGITAL_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0) | 51 | #define DIGITAL_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0) |
41 | 52 | ||
42 | #define DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT 0x10 | 53 | #define DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT 0x10 |
54 | #define DIGITAL_NFC_DEP_PFB_MI_BIT 0x10 | ||
55 | #define DIGITAL_NFC_DEP_PFB_NACK_BIT 0x10 | ||
56 | #define DIGITAL_NFC_DEP_PFB_DID_BIT 0x04 | ||
43 | 57 | ||
44 | #define DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb) \ | 58 | #define DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb) \ |
45 | ((pfb) & DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT) | 59 | ((pfb) & DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT) |
46 | #define DIGITAL_NFC_DEP_MI_BIT_SET(pfb) ((pfb) & 0x10) | 60 | #define DIGITAL_NFC_DEP_MI_BIT_SET(pfb) ((pfb) & DIGITAL_NFC_DEP_PFB_MI_BIT) |
61 | #define DIGITAL_NFC_DEP_NACK_BIT_SET(pfb) ((pfb) & DIGITAL_NFC_DEP_PFB_NACK_BIT) | ||
47 | #define DIGITAL_NFC_DEP_NAD_BIT_SET(pfb) ((pfb) & 0x08) | 62 | #define DIGITAL_NFC_DEP_NAD_BIT_SET(pfb) ((pfb) & 0x08) |
48 | #define DIGITAL_NFC_DEP_DID_BIT_SET(pfb) ((pfb) & 0x04) | 63 | #define DIGITAL_NFC_DEP_DID_BIT_SET(pfb) ((pfb) & DIGITAL_NFC_DEP_PFB_DID_BIT) |
49 | #define DIGITAL_NFC_DEP_PFB_PNI(pfb) ((pfb) & 0x03) | 64 | #define DIGITAL_NFC_DEP_PFB_PNI(pfb) ((pfb) & 0x03) |
50 | 65 | ||
51 | #define DIGITAL_NFC_DEP_PFB_I_PDU 0x00 | 66 | #define DIGITAL_NFC_DEP_PFB_I_PDU 0x00 |
@@ -97,6 +112,34 @@ struct digital_dep_req_res { | |||
97 | 112 | ||
98 | static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | 113 | static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, |
99 | struct sk_buff *resp); | 114 | struct sk_buff *resp); |
115 | static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | ||
116 | struct sk_buff *resp); | ||
117 | |||
118 | static const u8 digital_payload_bits_map[4] = { | ||
119 | [0] = 64, | ||
120 | [1] = 128, | ||
121 | [2] = 192, | ||
122 | [3] = 254 | ||
123 | }; | ||
124 | |||
125 | static u8 digital_payload_bits_to_size(u8 payload_bits) | ||
126 | { | ||
127 | if (payload_bits >= ARRAY_SIZE(digital_payload_bits_map)) | ||
128 | return 0; | ||
129 | |||
130 | return digital_payload_bits_map[payload_bits]; | ||
131 | } | ||
132 | |||
133 | static u8 digital_payload_size_to_bits(u8 payload_size) | ||
134 | { | ||
135 | int i; | ||
136 | |||
137 | for (i = 0; i < ARRAY_SIZE(digital_payload_bits_map); i++) | ||
138 | if (digital_payload_bits_map[i] == payload_size) | ||
139 | return i; | ||
140 | |||
141 | return 0xff; | ||
142 | } | ||
100 | 143 | ||
101 | static void digital_skb_push_dep_sod(struct nfc_digital_dev *ddev, | 144 | static void digital_skb_push_dep_sod(struct nfc_digital_dev *ddev, |
102 | struct sk_buff *skb) | 145 | struct sk_buff *skb) |
@@ -129,6 +172,106 @@ static int digital_skb_pull_dep_sod(struct nfc_digital_dev *ddev, | |||
129 | return 0; | 172 | return 0; |
130 | } | 173 | } |
131 | 174 | ||
175 | static struct sk_buff * | ||
176 | digital_send_dep_data_prep(struct nfc_digital_dev *ddev, struct sk_buff *skb, | ||
177 | struct digital_dep_req_res *dep_req_res, | ||
178 | struct digital_data_exch *data_exch) | ||
179 | { | ||
180 | struct sk_buff *new_skb; | ||
181 | |||
182 | if (skb->len > ddev->remote_payload_max) { | ||
183 | dep_req_res->pfb |= DIGITAL_NFC_DEP_PFB_MI_BIT; | ||
184 | |||
185 | new_skb = digital_skb_alloc(ddev, ddev->remote_payload_max); | ||
186 | if (!new_skb) { | ||
187 | kfree_skb(ddev->chaining_skb); | ||
188 | ddev->chaining_skb = NULL; | ||
189 | |||
190 | return ERR_PTR(-ENOMEM); | ||
191 | } | ||
192 | |||
193 | skb_reserve(new_skb, ddev->tx_headroom + NFC_HEADER_SIZE + | ||
194 | DIGITAL_NFC_DEP_REQ_RES_HEADROOM); | ||
195 | memcpy(skb_put(new_skb, ddev->remote_payload_max), skb->data, | ||
196 | ddev->remote_payload_max); | ||
197 | skb_pull(skb, ddev->remote_payload_max); | ||
198 | |||
199 | ddev->chaining_skb = skb; | ||
200 | ddev->data_exch = data_exch; | ||
201 | } else { | ||
202 | ddev->chaining_skb = NULL; | ||
203 | new_skb = skb; | ||
204 | } | ||
205 | |||
206 | return new_skb; | ||
207 | } | ||
208 | |||
209 | static struct sk_buff * | ||
210 | digital_recv_dep_data_gather(struct nfc_digital_dev *ddev, u8 pfb, | ||
211 | struct sk_buff *resp, | ||
212 | int (*send_ack)(struct nfc_digital_dev *ddev, | ||
213 | struct digital_data_exch | ||
214 | *data_exch), | ||
215 | struct digital_data_exch *data_exch) | ||
216 | { | ||
217 | struct sk_buff *new_skb; | ||
218 | int rc; | ||
219 | |||
220 | if (DIGITAL_NFC_DEP_MI_BIT_SET(pfb) && (!ddev->chaining_skb)) { | ||
221 | ddev->chaining_skb = | ||
222 | nfc_alloc_recv_skb(8 * ddev->local_payload_max, | ||
223 | GFP_KERNEL); | ||
224 | if (!ddev->chaining_skb) { | ||
225 | rc = -ENOMEM; | ||
226 | goto error; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | if (ddev->chaining_skb) { | ||
231 | if (resp->len > skb_tailroom(ddev->chaining_skb)) { | ||
232 | new_skb = skb_copy_expand(ddev->chaining_skb, | ||
233 | skb_headroom( | ||
234 | ddev->chaining_skb), | ||
235 | 8 * ddev->local_payload_max, | ||
236 | GFP_KERNEL); | ||
237 | if (!new_skb) { | ||
238 | rc = -ENOMEM; | ||
239 | goto error; | ||
240 | } | ||
241 | |||
242 | kfree_skb(ddev->chaining_skb); | ||
243 | ddev->chaining_skb = new_skb; | ||
244 | } | ||
245 | |||
246 | memcpy(skb_put(ddev->chaining_skb, resp->len), resp->data, | ||
247 | resp->len); | ||
248 | |||
249 | kfree_skb(resp); | ||
250 | resp = NULL; | ||
251 | |||
252 | if (DIGITAL_NFC_DEP_MI_BIT_SET(pfb)) { | ||
253 | rc = send_ack(ddev, data_exch); | ||
254 | if (rc) | ||
255 | goto error; | ||
256 | |||
257 | return NULL; | ||
258 | } | ||
259 | |||
260 | resp = ddev->chaining_skb; | ||
261 | ddev->chaining_skb = NULL; | ||
262 | } | ||
263 | |||
264 | return resp; | ||
265 | |||
266 | error: | ||
267 | kfree_skb(resp); | ||
268 | |||
269 | kfree_skb(ddev->chaining_skb); | ||
270 | ddev->chaining_skb = NULL; | ||
271 | |||
272 | return ERR_PTR(rc); | ||
273 | } | ||
274 | |||
132 | static void digital_in_recv_psl_res(struct nfc_digital_dev *ddev, void *arg, | 275 | static void digital_in_recv_psl_res(struct nfc_digital_dev *ddev, void *arg, |
133 | struct sk_buff *resp) | 276 | struct sk_buff *resp) |
134 | { | 277 | { |
@@ -198,6 +341,8 @@ static int digital_in_send_psl_req(struct nfc_digital_dev *ddev, | |||
198 | { | 341 | { |
199 | struct sk_buff *skb; | 342 | struct sk_buff *skb; |
200 | struct digital_psl_req *psl_req; | 343 | struct digital_psl_req *psl_req; |
344 | int rc; | ||
345 | u8 payload_size, payload_bits; | ||
201 | 346 | ||
202 | skb = digital_skb_alloc(ddev, sizeof(*psl_req)); | 347 | skb = digital_skb_alloc(ddev, sizeof(*psl_req)); |
203 | if (!skb) | 348 | if (!skb) |
@@ -211,14 +356,24 @@ static int digital_in_send_psl_req(struct nfc_digital_dev *ddev, | |||
211 | psl_req->cmd = DIGITAL_CMD_PSL_REQ; | 356 | psl_req->cmd = DIGITAL_CMD_PSL_REQ; |
212 | psl_req->did = 0; | 357 | psl_req->did = 0; |
213 | psl_req->brs = (0x2 << 3) | 0x2; /* 424F both directions */ | 358 | psl_req->brs = (0x2 << 3) | 0x2; /* 424F both directions */ |
214 | psl_req->fsl = DIGITAL_FSL_BITS_PAYLOAD_SIZE_254B; | 359 | |
360 | payload_size = min(ddev->local_payload_max, ddev->remote_payload_max); | ||
361 | payload_bits = digital_payload_size_to_bits(payload_size); | ||
362 | psl_req->fsl = DIGITAL_PAYLOAD_BITS_TO_FSL(payload_bits); | ||
363 | |||
364 | ddev->local_payload_max = payload_size; | ||
365 | ddev->remote_payload_max = payload_size; | ||
215 | 366 | ||
216 | digital_skb_push_dep_sod(ddev, skb); | 367 | digital_skb_push_dep_sod(ddev, skb); |
217 | 368 | ||
218 | ddev->skb_add_crc(skb); | 369 | ddev->skb_add_crc(skb); |
219 | 370 | ||
220 | return digital_in_send_cmd(ddev, skb, 500, digital_in_recv_psl_res, | 371 | rc = digital_in_send_cmd(ddev, skb, 500, digital_in_recv_psl_res, |
221 | target); | 372 | target); |
373 | if (rc) | ||
374 | kfree_skb(skb); | ||
375 | |||
376 | return rc; | ||
222 | } | 377 | } |
223 | 378 | ||
224 | static void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg, | 379 | static void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg, |
@@ -226,7 +381,7 @@ static void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg, | |||
226 | { | 381 | { |
227 | struct nfc_target *target = arg; | 382 | struct nfc_target *target = arg; |
228 | struct digital_atr_res *atr_res; | 383 | struct digital_atr_res *atr_res; |
229 | u8 gb_len; | 384 | u8 gb_len, payload_bits; |
230 | int rc; | 385 | int rc; |
231 | 386 | ||
232 | if (IS_ERR(resp)) { | 387 | if (IS_ERR(resp)) { |
@@ -256,6 +411,14 @@ static void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg, | |||
256 | 411 | ||
257 | atr_res = (struct digital_atr_res *)resp->data; | 412 | atr_res = (struct digital_atr_res *)resp->data; |
258 | 413 | ||
414 | payload_bits = DIGITAL_PAYLOAD_PP_TO_BITS(atr_res->pp); | ||
415 | ddev->remote_payload_max = digital_payload_bits_to_size(payload_bits); | ||
416 | |||
417 | if (!ddev->remote_payload_max) { | ||
418 | rc = -EINVAL; | ||
419 | goto exit; | ||
420 | } | ||
421 | |||
259 | rc = nfc_set_remote_general_bytes(ddev->nfc_dev, atr_res->gb, gb_len); | 422 | rc = nfc_set_remote_general_bytes(ddev->nfc_dev, atr_res->gb, gb_len); |
260 | if (rc) | 423 | if (rc) |
261 | goto exit; | 424 | goto exit; |
@@ -286,6 +449,8 @@ int digital_in_send_atr_req(struct nfc_digital_dev *ddev, | |||
286 | struct sk_buff *skb; | 449 | struct sk_buff *skb; |
287 | struct digital_atr_req *atr_req; | 450 | struct digital_atr_req *atr_req; |
288 | uint size; | 451 | uint size; |
452 | int rc; | ||
453 | u8 payload_bits; | ||
289 | 454 | ||
290 | size = DIGITAL_ATR_REQ_MIN_SIZE + gb_len; | 455 | size = DIGITAL_ATR_REQ_MIN_SIZE + gb_len; |
291 | 456 | ||
@@ -314,7 +479,9 @@ int digital_in_send_atr_req(struct nfc_digital_dev *ddev, | |||
314 | atr_req->bs = 0; | 479 | atr_req->bs = 0; |
315 | atr_req->br = 0; | 480 | atr_req->br = 0; |
316 | 481 | ||
317 | atr_req->pp = DIGITAL_LR_BITS_PAYLOAD_SIZE_254B; | 482 | ddev->local_payload_max = DIGITAL_PAYLOAD_SIZE_MAX; |
483 | payload_bits = digital_payload_size_to_bits(ddev->local_payload_max); | ||
484 | atr_req->pp = DIGITAL_PAYLOAD_BITS_TO_PP(payload_bits); | ||
318 | 485 | ||
319 | if (gb_len) { | 486 | if (gb_len) { |
320 | atr_req->pp |= DIGITAL_GB_BIT; | 487 | atr_req->pp |= DIGITAL_GB_BIT; |
@@ -325,8 +492,113 @@ int digital_in_send_atr_req(struct nfc_digital_dev *ddev, | |||
325 | 492 | ||
326 | ddev->skb_add_crc(skb); | 493 | ddev->skb_add_crc(skb); |
327 | 494 | ||
328 | return digital_in_send_cmd(ddev, skb, 500, digital_in_recv_atr_res, | 495 | rc = digital_in_send_cmd(ddev, skb, 500, digital_in_recv_atr_res, |
329 | target); | 496 | target); |
497 | if (rc) | ||
498 | kfree_skb(skb); | ||
499 | |||
500 | return rc; | ||
501 | } | ||
502 | |||
503 | static int digital_in_send_ack(struct nfc_digital_dev *ddev, | ||
504 | struct digital_data_exch *data_exch) | ||
505 | { | ||
506 | struct digital_dep_req_res *dep_req; | ||
507 | struct sk_buff *skb; | ||
508 | int rc; | ||
509 | |||
510 | skb = digital_skb_alloc(ddev, 1); | ||
511 | if (!skb) | ||
512 | return -ENOMEM; | ||
513 | |||
514 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
515 | |||
516 | dep_req = (struct digital_dep_req_res *)skb->data; | ||
517 | |||
518 | dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; | ||
519 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; | ||
520 | dep_req->pfb = DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU | | ||
521 | ddev->curr_nfc_dep_pni; | ||
522 | |||
523 | digital_skb_push_dep_sod(ddev, skb); | ||
524 | |||
525 | ddev->skb_add_crc(skb); | ||
526 | |||
527 | ddev->saved_skb = skb_get(skb); | ||
528 | ddev->saved_skb_len = skb->len; | ||
529 | |||
530 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | ||
531 | data_exch); | ||
532 | if (rc) { | ||
533 | kfree_skb(skb); | ||
534 | kfree_skb(ddev->saved_skb); | ||
535 | ddev->saved_skb = NULL; | ||
536 | } | ||
537 | |||
538 | return rc; | ||
539 | } | ||
540 | |||
541 | static int digital_in_send_nack(struct nfc_digital_dev *ddev, | ||
542 | struct digital_data_exch *data_exch) | ||
543 | { | ||
544 | struct digital_dep_req_res *dep_req; | ||
545 | struct sk_buff *skb; | ||
546 | int rc; | ||
547 | |||
548 | skb = digital_skb_alloc(ddev, 1); | ||
549 | if (!skb) | ||
550 | return -ENOMEM; | ||
551 | |||
552 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
553 | |||
554 | dep_req = (struct digital_dep_req_res *)skb->data; | ||
555 | |||
556 | dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; | ||
557 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; | ||
558 | dep_req->pfb = DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU | | ||
559 | DIGITAL_NFC_DEP_PFB_NACK_BIT | ddev->curr_nfc_dep_pni; | ||
560 | |||
561 | digital_skb_push_dep_sod(ddev, skb); | ||
562 | |||
563 | ddev->skb_add_crc(skb); | ||
564 | |||
565 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | ||
566 | data_exch); | ||
567 | if (rc) | ||
568 | kfree_skb(skb); | ||
569 | |||
570 | return rc; | ||
571 | } | ||
572 | |||
573 | static int digital_in_send_atn(struct nfc_digital_dev *ddev, | ||
574 | struct digital_data_exch *data_exch) | ||
575 | { | ||
576 | struct digital_dep_req_res *dep_req; | ||
577 | struct sk_buff *skb; | ||
578 | int rc; | ||
579 | |||
580 | skb = digital_skb_alloc(ddev, 1); | ||
581 | if (!skb) | ||
582 | return -ENOMEM; | ||
583 | |||
584 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
585 | |||
586 | dep_req = (struct digital_dep_req_res *)skb->data; | ||
587 | |||
588 | dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; | ||
589 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; | ||
590 | dep_req->pfb = DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU; | ||
591 | |||
592 | digital_skb_push_dep_sod(ddev, skb); | ||
593 | |||
594 | ddev->skb_add_crc(skb); | ||
595 | |||
596 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | ||
597 | data_exch); | ||
598 | if (rc) | ||
599 | kfree_skb(skb); | ||
600 | |||
601 | return rc; | ||
330 | } | 602 | } |
331 | 603 | ||
332 | static int digital_in_send_rtox(struct nfc_digital_dev *ddev, | 604 | static int digital_in_send_rtox(struct nfc_digital_dev *ddev, |
@@ -355,12 +627,30 @@ static int digital_in_send_rtox(struct nfc_digital_dev *ddev, | |||
355 | 627 | ||
356 | ddev->skb_add_crc(skb); | 628 | ddev->skb_add_crc(skb); |
357 | 629 | ||
630 | ddev->saved_skb = skb_get(skb); | ||
631 | ddev->saved_skb_len = skb->len; | ||
632 | |||
358 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | 633 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, |
359 | data_exch); | 634 | data_exch); |
635 | if (rc) { | ||
636 | kfree_skb(skb); | ||
637 | kfree_skb(ddev->saved_skb); | ||
638 | ddev->saved_skb = NULL; | ||
639 | } | ||
360 | 640 | ||
361 | return rc; | 641 | return rc; |
362 | } | 642 | } |
363 | 643 | ||
644 | static int digital_in_send_saved_skb(struct nfc_digital_dev *ddev, | ||
645 | struct digital_data_exch *data_exch) | ||
646 | { | ||
647 | skb_get(ddev->saved_skb); | ||
648 | skb_push(ddev->saved_skb, ddev->saved_skb_len); | ||
649 | |||
650 | return digital_in_send_cmd(ddev, ddev->saved_skb, 1500, | ||
651 | digital_in_recv_dep_res, data_exch); | ||
652 | } | ||
653 | |||
364 | static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | 654 | static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, |
365 | struct sk_buff *resp) | 655 | struct sk_buff *resp) |
366 | { | 656 | { |
@@ -373,25 +663,67 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
373 | if (IS_ERR(resp)) { | 663 | if (IS_ERR(resp)) { |
374 | rc = PTR_ERR(resp); | 664 | rc = PTR_ERR(resp); |
375 | resp = NULL; | 665 | resp = NULL; |
666 | |||
667 | if (((rc != -ETIMEDOUT) || ddev->nack_count) && | ||
668 | (ddev->nack_count++ < DIGITAL_NFC_DEP_N_RETRY_NACK)) { | ||
669 | ddev->atn_count = 0; | ||
670 | |||
671 | rc = digital_in_send_nack(ddev, data_exch); | ||
672 | if (rc) | ||
673 | goto error; | ||
674 | |||
675 | return; | ||
676 | } else if ((rc == -ETIMEDOUT) && | ||
677 | (ddev->atn_count++ < DIGITAL_NFC_DEP_N_RETRY_ATN)) { | ||
678 | ddev->nack_count = 0; | ||
679 | |||
680 | rc = digital_in_send_atn(ddev, data_exch); | ||
681 | if (rc) | ||
682 | goto error; | ||
683 | |||
684 | return; | ||
685 | } | ||
686 | |||
687 | goto exit; | ||
688 | } | ||
689 | |||
690 | rc = digital_skb_pull_dep_sod(ddev, resp); | ||
691 | if (rc) { | ||
692 | PROTOCOL_ERR("14.4.1.2"); | ||
376 | goto exit; | 693 | goto exit; |
377 | } | 694 | } |
378 | 695 | ||
379 | rc = ddev->skb_check_crc(resp); | 696 | rc = ddev->skb_check_crc(resp); |
380 | if (rc) { | 697 | if (rc) { |
698 | if ((resp->len >= 4) && | ||
699 | (ddev->nack_count++ < DIGITAL_NFC_DEP_N_RETRY_NACK)) { | ||
700 | ddev->atn_count = 0; | ||
701 | |||
702 | rc = digital_in_send_nack(ddev, data_exch); | ||
703 | if (rc) | ||
704 | goto error; | ||
705 | |||
706 | kfree_skb(resp); | ||
707 | |||
708 | return; | ||
709 | } | ||
710 | |||
381 | PROTOCOL_ERR("14.4.1.6"); | 711 | PROTOCOL_ERR("14.4.1.6"); |
382 | goto error; | 712 | goto error; |
383 | } | 713 | } |
384 | 714 | ||
385 | rc = digital_skb_pull_dep_sod(ddev, resp); | 715 | ddev->atn_count = 0; |
386 | if (rc) { | 716 | ddev->nack_count = 0; |
387 | PROTOCOL_ERR("14.4.1.2"); | 717 | |
718 | if (resp->len > ddev->local_payload_max) { | ||
719 | rc = -EMSGSIZE; | ||
388 | goto exit; | 720 | goto exit; |
389 | } | 721 | } |
390 | 722 | ||
723 | size = sizeof(struct digital_dep_req_res); | ||
391 | dep_res = (struct digital_dep_req_res *)resp->data; | 724 | dep_res = (struct digital_dep_req_res *)resp->data; |
392 | 725 | ||
393 | if (resp->len < sizeof(struct digital_dep_req_res) || | 726 | if (resp->len < size || dep_res->dir != DIGITAL_NFC_DEP_FRAME_DIR_IN || |
394 | dep_res->dir != DIGITAL_NFC_DEP_FRAME_DIR_IN || | ||
395 | dep_res->cmd != DIGITAL_CMD_DEP_RES) { | 727 | dep_res->cmd != DIGITAL_CMD_DEP_RES) { |
396 | rc = -EIO; | 728 | rc = -EIO; |
397 | goto error; | 729 | goto error; |
@@ -399,6 +731,24 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
399 | 731 | ||
400 | pfb = dep_res->pfb; | 732 | pfb = dep_res->pfb; |
401 | 733 | ||
734 | if (DIGITAL_NFC_DEP_DID_BIT_SET(pfb)) { | ||
735 | PROTOCOL_ERR("14.8.2.1"); | ||
736 | rc = -EIO; | ||
737 | goto error; | ||
738 | } | ||
739 | |||
740 | if (DIGITAL_NFC_DEP_NAD_BIT_SET(pfb)) { | ||
741 | rc = -EIO; | ||
742 | goto exit; | ||
743 | } | ||
744 | |||
745 | if (size > resp->len) { | ||
746 | rc = -EIO; | ||
747 | goto error; | ||
748 | } | ||
749 | |||
750 | skb_pull(resp, size); | ||
751 | |||
402 | switch (DIGITAL_NFC_DEP_PFB_TYPE(pfb)) { | 752 | switch (DIGITAL_NFC_DEP_PFB_TYPE(pfb)) { |
403 | case DIGITAL_NFC_DEP_PFB_I_PDU: | 753 | case DIGITAL_NFC_DEP_PFB_I_PDU: |
404 | if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { | 754 | if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { |
@@ -409,21 +759,71 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
409 | 759 | ||
410 | ddev->curr_nfc_dep_pni = | 760 | ddev->curr_nfc_dep_pni = |
411 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); | 761 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); |
762 | |||
763 | kfree_skb(ddev->saved_skb); | ||
764 | ddev->saved_skb = NULL; | ||
765 | |||
766 | resp = digital_recv_dep_data_gather(ddev, pfb, resp, | ||
767 | digital_in_send_ack, | ||
768 | data_exch); | ||
769 | if (IS_ERR(resp)) { | ||
770 | rc = PTR_ERR(resp); | ||
771 | resp = NULL; | ||
772 | goto error; | ||
773 | } | ||
774 | |||
775 | /* If resp is NULL then we're still chaining so return and | ||
776 | * wait for the next part of the PDU. Else, the PDU is | ||
777 | * complete so pass it up. | ||
778 | */ | ||
779 | if (!resp) | ||
780 | return; | ||
781 | |||
412 | rc = 0; | 782 | rc = 0; |
413 | break; | 783 | break; |
414 | 784 | ||
415 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: | 785 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: |
786 | if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { | ||
787 | PROTOCOL_ERR("14.12.3.3"); | ||
788 | rc = -EIO; | ||
789 | goto exit; | ||
790 | } | ||
791 | |||
792 | ddev->curr_nfc_dep_pni = | ||
793 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); | ||
794 | |||
795 | if (ddev->chaining_skb && !DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { | ||
796 | kfree_skb(ddev->saved_skb); | ||
797 | ddev->saved_skb = NULL; | ||
798 | |||
799 | rc = digital_in_send_dep_req(ddev, NULL, | ||
800 | ddev->chaining_skb, | ||
801 | ddev->data_exch); | ||
802 | if (rc) | ||
803 | goto error; | ||
804 | |||
805 | return; | ||
806 | } | ||
807 | |||
416 | pr_err("Received a ACK/NACK PDU\n"); | 808 | pr_err("Received a ACK/NACK PDU\n"); |
417 | rc = -EIO; | 809 | rc = -EINVAL; |
418 | goto error; | 810 | goto exit; |
419 | 811 | ||
420 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: | 812 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: |
421 | if (!DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { | 813 | if (!DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { /* ATN */ |
422 | rc = -EINVAL; | 814 | rc = digital_in_send_saved_skb(ddev, data_exch); |
423 | goto error; | 815 | if (rc) { |
816 | kfree_skb(ddev->saved_skb); | ||
817 | goto error; | ||
818 | } | ||
819 | |||
820 | return; | ||
424 | } | 821 | } |
425 | 822 | ||
426 | rc = digital_in_send_rtox(ddev, data_exch, resp->data[3]); | 823 | kfree_skb(ddev->saved_skb); |
824 | ddev->saved_skb = NULL; | ||
825 | |||
826 | rc = digital_in_send_rtox(ddev, data_exch, resp->data[0]); | ||
427 | if (rc) | 827 | if (rc) |
428 | goto error; | 828 | goto error; |
429 | 829 | ||
@@ -431,30 +831,18 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
431 | return; | 831 | return; |
432 | } | 832 | } |
433 | 833 | ||
434 | if (DIGITAL_NFC_DEP_MI_BIT_SET(pfb)) { | ||
435 | pr_err("MI bit set. Chained PDU not supported\n"); | ||
436 | rc = -EIO; | ||
437 | goto error; | ||
438 | } | ||
439 | |||
440 | size = sizeof(struct digital_dep_req_res); | ||
441 | |||
442 | if (DIGITAL_NFC_DEP_DID_BIT_SET(pfb)) | ||
443 | size++; | ||
444 | |||
445 | if (size > resp->len) { | ||
446 | rc = -EIO; | ||
447 | goto error; | ||
448 | } | ||
449 | |||
450 | skb_pull(resp, size); | ||
451 | |||
452 | exit: | 834 | exit: |
453 | data_exch->cb(data_exch->cb_context, resp, rc); | 835 | data_exch->cb(data_exch->cb_context, resp, rc); |
454 | 836 | ||
455 | error: | 837 | error: |
456 | kfree(data_exch); | 838 | kfree(data_exch); |
457 | 839 | ||
840 | kfree_skb(ddev->chaining_skb); | ||
841 | ddev->chaining_skb = NULL; | ||
842 | |||
843 | kfree_skb(ddev->saved_skb); | ||
844 | ddev->saved_skb = NULL; | ||
845 | |||
458 | if (rc) | 846 | if (rc) |
459 | kfree_skb(resp); | 847 | kfree_skb(resp); |
460 | } | 848 | } |
@@ -464,20 +852,47 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev, | |||
464 | struct digital_data_exch *data_exch) | 852 | struct digital_data_exch *data_exch) |
465 | { | 853 | { |
466 | struct digital_dep_req_res *dep_req; | 854 | struct digital_dep_req_res *dep_req; |
855 | struct sk_buff *chaining_skb, *tmp_skb; | ||
856 | int rc; | ||
467 | 857 | ||
468 | skb_push(skb, sizeof(struct digital_dep_req_res)); | 858 | skb_push(skb, sizeof(struct digital_dep_req_res)); |
469 | 859 | ||
470 | dep_req = (struct digital_dep_req_res *)skb->data; | 860 | dep_req = (struct digital_dep_req_res *)skb->data; |
861 | |||
471 | dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; | 862 | dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; |
472 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; | 863 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; |
473 | dep_req->pfb = ddev->curr_nfc_dep_pni; | 864 | dep_req->pfb = ddev->curr_nfc_dep_pni; |
474 | 865 | ||
475 | digital_skb_push_dep_sod(ddev, skb); | 866 | ddev->atn_count = 0; |
867 | ddev->nack_count = 0; | ||
476 | 868 | ||
477 | ddev->skb_add_crc(skb); | 869 | chaining_skb = ddev->chaining_skb; |
870 | |||
871 | tmp_skb = digital_send_dep_data_prep(ddev, skb, dep_req, data_exch); | ||
872 | if (IS_ERR(tmp_skb)) | ||
873 | return PTR_ERR(tmp_skb); | ||
874 | |||
875 | digital_skb_push_dep_sod(ddev, tmp_skb); | ||
876 | |||
877 | ddev->skb_add_crc(tmp_skb); | ||
478 | 878 | ||
479 | return digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | 879 | ddev->saved_skb = skb_get(tmp_skb); |
480 | data_exch); | 880 | ddev->saved_skb_len = tmp_skb->len; |
881 | |||
882 | rc = digital_in_send_cmd(ddev, tmp_skb, 1500, digital_in_recv_dep_res, | ||
883 | data_exch); | ||
884 | if (rc) { | ||
885 | if (tmp_skb != skb) | ||
886 | kfree_skb(tmp_skb); | ||
887 | |||
888 | kfree_skb(chaining_skb); | ||
889 | ddev->chaining_skb = NULL; | ||
890 | |||
891 | kfree_skb(ddev->saved_skb); | ||
892 | ddev->saved_skb = NULL; | ||
893 | } | ||
894 | |||
895 | return rc; | ||
481 | } | 896 | } |
482 | 897 | ||
483 | static void digital_tg_set_rf_tech(struct nfc_digital_dev *ddev, u8 rf_tech) | 898 | static void digital_tg_set_rf_tech(struct nfc_digital_dev *ddev, u8 rf_tech) |
@@ -507,11 +922,106 @@ static void digital_tg_set_rf_tech(struct nfc_digital_dev *ddev, u8 rf_tech) | |||
507 | } | 922 | } |
508 | } | 923 | } |
509 | 924 | ||
925 | static int digital_tg_send_ack(struct nfc_digital_dev *ddev, | ||
926 | struct digital_data_exch *data_exch) | ||
927 | { | ||
928 | struct digital_dep_req_res *dep_res; | ||
929 | struct sk_buff *skb; | ||
930 | int rc; | ||
931 | |||
932 | skb = digital_skb_alloc(ddev, 1); | ||
933 | if (!skb) | ||
934 | return -ENOMEM; | ||
935 | |||
936 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
937 | |||
938 | dep_res = (struct digital_dep_req_res *)skb->data; | ||
939 | |||
940 | dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; | ||
941 | dep_res->cmd = DIGITAL_CMD_DEP_RES; | ||
942 | dep_res->pfb = DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU | | ||
943 | ddev->curr_nfc_dep_pni; | ||
944 | |||
945 | if (ddev->did) { | ||
946 | dep_res->pfb |= DIGITAL_NFC_DEP_PFB_DID_BIT; | ||
947 | |||
948 | memcpy(skb_put(skb, sizeof(ddev->did)), &ddev->did, | ||
949 | sizeof(ddev->did)); | ||
950 | } | ||
951 | |||
952 | ddev->curr_nfc_dep_pni = | ||
953 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); | ||
954 | |||
955 | digital_skb_push_dep_sod(ddev, skb); | ||
956 | |||
957 | ddev->skb_add_crc(skb); | ||
958 | |||
959 | ddev->saved_skb = skb_get(skb); | ||
960 | ddev->saved_skb_len = skb->len; | ||
961 | |||
962 | rc = digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req, | ||
963 | data_exch); | ||
964 | if (rc) { | ||
965 | kfree_skb(skb); | ||
966 | kfree_skb(ddev->saved_skb); | ||
967 | ddev->saved_skb = NULL; | ||
968 | } | ||
969 | |||
970 | return rc; | ||
971 | } | ||
972 | |||
973 | static int digital_tg_send_atn(struct nfc_digital_dev *ddev) | ||
974 | { | ||
975 | struct digital_dep_req_res *dep_res; | ||
976 | struct sk_buff *skb; | ||
977 | int rc; | ||
978 | |||
979 | skb = digital_skb_alloc(ddev, 1); | ||
980 | if (!skb) | ||
981 | return -ENOMEM; | ||
982 | |||
983 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
984 | |||
985 | dep_res = (struct digital_dep_req_res *)skb->data; | ||
986 | |||
987 | dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; | ||
988 | dep_res->cmd = DIGITAL_CMD_DEP_RES; | ||
989 | dep_res->pfb = DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU; | ||
990 | |||
991 | if (ddev->did) { | ||
992 | dep_res->pfb |= DIGITAL_NFC_DEP_PFB_DID_BIT; | ||
993 | |||
994 | memcpy(skb_put(skb, sizeof(ddev->did)), &ddev->did, | ||
995 | sizeof(ddev->did)); | ||
996 | } | ||
997 | |||
998 | digital_skb_push_dep_sod(ddev, skb); | ||
999 | |||
1000 | ddev->skb_add_crc(skb); | ||
1001 | |||
1002 | rc = digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req, | ||
1003 | NULL); | ||
1004 | if (rc) | ||
1005 | kfree_skb(skb); | ||
1006 | |||
1007 | return rc; | ||
1008 | } | ||
1009 | |||
1010 | static int digital_tg_send_saved_skb(struct nfc_digital_dev *ddev) | ||
1011 | { | ||
1012 | skb_get(ddev->saved_skb); | ||
1013 | skb_push(ddev->saved_skb, ddev->saved_skb_len); | ||
1014 | |||
1015 | return digital_tg_send_cmd(ddev, ddev->saved_skb, 1500, | ||
1016 | digital_tg_recv_dep_req, NULL); | ||
1017 | } | ||
1018 | |||
510 | static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | 1019 | static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, |
511 | struct sk_buff *resp) | 1020 | struct sk_buff *resp) |
512 | { | 1021 | { |
513 | int rc; | 1022 | int rc; |
514 | struct digital_dep_req_res *dep_req; | 1023 | struct digital_dep_req_res *dep_req; |
1024 | u8 pfb; | ||
515 | size_t size; | 1025 | size_t size; |
516 | 1026 | ||
517 | if (IS_ERR(resp)) { | 1027 | if (IS_ERR(resp)) { |
@@ -532,6 +1042,11 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | |||
532 | goto exit; | 1042 | goto exit; |
533 | } | 1043 | } |
534 | 1044 | ||
1045 | if (resp->len > ddev->local_payload_max) { | ||
1046 | rc = -EMSGSIZE; | ||
1047 | goto exit; | ||
1048 | } | ||
1049 | |||
535 | size = sizeof(struct digital_dep_req_res); | 1050 | size = sizeof(struct digital_dep_req_res); |
536 | dep_req = (struct digital_dep_req_res *)resp->data; | 1051 | dep_req = (struct digital_dep_req_res *)resp->data; |
537 | 1052 | ||
@@ -541,34 +1056,147 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | |||
541 | goto exit; | 1056 | goto exit; |
542 | } | 1057 | } |
543 | 1058 | ||
544 | if (DIGITAL_NFC_DEP_DID_BIT_SET(dep_req->pfb)) | 1059 | pfb = dep_req->pfb; |
545 | size++; | ||
546 | 1060 | ||
547 | if (resp->len < size) { | 1061 | if (DIGITAL_NFC_DEP_DID_BIT_SET(pfb)) { |
1062 | if (ddev->did && (ddev->did == resp->data[3])) { | ||
1063 | size++; | ||
1064 | } else { | ||
1065 | rc = -EIO; | ||
1066 | goto exit; | ||
1067 | } | ||
1068 | } else if (ddev->did) { | ||
548 | rc = -EIO; | 1069 | rc = -EIO; |
549 | goto exit; | 1070 | goto exit; |
550 | } | 1071 | } |
551 | 1072 | ||
552 | switch (DIGITAL_NFC_DEP_PFB_TYPE(dep_req->pfb)) { | 1073 | if (DIGITAL_NFC_DEP_NAD_BIT_SET(pfb)) { |
1074 | rc = -EIO; | ||
1075 | goto exit; | ||
1076 | } | ||
1077 | |||
1078 | if (size > resp->len) { | ||
1079 | rc = -EIO; | ||
1080 | goto exit; | ||
1081 | } | ||
1082 | |||
1083 | skb_pull(resp, size); | ||
1084 | |||
1085 | switch (DIGITAL_NFC_DEP_PFB_TYPE(pfb)) { | ||
553 | case DIGITAL_NFC_DEP_PFB_I_PDU: | 1086 | case DIGITAL_NFC_DEP_PFB_I_PDU: |
554 | pr_debug("DIGITAL_NFC_DEP_PFB_I_PDU\n"); | 1087 | pr_debug("DIGITAL_NFC_DEP_PFB_I_PDU\n"); |
555 | ddev->curr_nfc_dep_pni = DIGITAL_NFC_DEP_PFB_PNI(dep_req->pfb); | 1088 | |
1089 | if ((ddev->atn_count && (DIGITAL_NFC_DEP_PFB_PNI(pfb - 1) != | ||
1090 | ddev->curr_nfc_dep_pni)) || | ||
1091 | (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni)) { | ||
1092 | PROTOCOL_ERR("14.12.3.4"); | ||
1093 | rc = -EIO; | ||
1094 | goto exit; | ||
1095 | } | ||
1096 | |||
1097 | if (ddev->atn_count) { | ||
1098 | ddev->atn_count = 0; | ||
1099 | |||
1100 | rc = digital_tg_send_saved_skb(ddev); | ||
1101 | if (rc) | ||
1102 | goto exit; | ||
1103 | |||
1104 | return; | ||
1105 | } | ||
1106 | |||
1107 | kfree_skb(ddev->saved_skb); | ||
1108 | ddev->saved_skb = NULL; | ||
1109 | |||
1110 | resp = digital_recv_dep_data_gather(ddev, pfb, resp, | ||
1111 | digital_tg_send_ack, NULL); | ||
1112 | if (IS_ERR(resp)) { | ||
1113 | rc = PTR_ERR(resp); | ||
1114 | resp = NULL; | ||
1115 | goto exit; | ||
1116 | } | ||
1117 | |||
1118 | /* If resp is NULL then we're still chaining so return and | ||
1119 | * wait for the next part of the PDU. Else, the PDU is | ||
1120 | * complete so pass it up. | ||
1121 | */ | ||
1122 | if (!resp) | ||
1123 | return; | ||
1124 | |||
1125 | rc = 0; | ||
556 | break; | 1126 | break; |
557 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: | 1127 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: |
558 | pr_err("Received a ACK/NACK PDU\n"); | 1128 | if (!DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { /* ACK */ |
559 | rc = -EINVAL; | 1129 | if ((ddev->atn_count && |
560 | goto exit; | 1130 | (DIGITAL_NFC_DEP_PFB_PNI(pfb - 1) != |
1131 | ddev->curr_nfc_dep_pni)) || | ||
1132 | (DIGITAL_NFC_DEP_PFB_PNI(pfb) != | ||
1133 | ddev->curr_nfc_dep_pni) || | ||
1134 | !ddev->chaining_skb || !ddev->saved_skb) { | ||
1135 | rc = -EIO; | ||
1136 | goto exit; | ||
1137 | } | ||
1138 | |||
1139 | if (ddev->atn_count) { | ||
1140 | ddev->atn_count = 0; | ||
1141 | |||
1142 | rc = digital_tg_send_saved_skb(ddev); | ||
1143 | if (rc) | ||
1144 | goto exit; | ||
1145 | |||
1146 | return; | ||
1147 | } | ||
1148 | |||
1149 | kfree_skb(ddev->saved_skb); | ||
1150 | ddev->saved_skb = NULL; | ||
1151 | |||
1152 | rc = digital_tg_send_dep_res(ddev, ddev->chaining_skb); | ||
1153 | if (rc) | ||
1154 | goto exit; | ||
1155 | } else { /* NACK */ | ||
1156 | if ((DIGITAL_NFC_DEP_PFB_PNI(pfb + 1) != | ||
1157 | ddev->curr_nfc_dep_pni) || | ||
1158 | !ddev->saved_skb) { | ||
1159 | rc = -EIO; | ||
1160 | goto exit; | ||
1161 | } | ||
1162 | |||
1163 | ddev->atn_count = 0; | ||
1164 | |||
1165 | rc = digital_tg_send_saved_skb(ddev); | ||
1166 | if (rc) { | ||
1167 | kfree_skb(ddev->saved_skb); | ||
1168 | goto exit; | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | return; | ||
561 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: | 1173 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: |
562 | pr_err("Received a SUPERVISOR PDU\n"); | 1174 | if (DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { |
563 | rc = -EINVAL; | 1175 | rc = -EINVAL; |
564 | goto exit; | 1176 | goto exit; |
565 | } | 1177 | } |
566 | 1178 | ||
567 | skb_pull(resp, size); | 1179 | rc = digital_tg_send_atn(ddev); |
1180 | if (rc) | ||
1181 | goto exit; | ||
1182 | |||
1183 | ddev->atn_count++; | ||
1184 | |||
1185 | kfree_skb(resp); | ||
1186 | return; | ||
1187 | } | ||
568 | 1188 | ||
569 | rc = nfc_tm_data_received(ddev->nfc_dev, resp); | 1189 | rc = nfc_tm_data_received(ddev->nfc_dev, resp); |
570 | 1190 | ||
571 | exit: | 1191 | exit: |
1192 | kfree_skb(ddev->chaining_skb); | ||
1193 | ddev->chaining_skb = NULL; | ||
1194 | |||
1195 | ddev->atn_count = 0; | ||
1196 | |||
1197 | kfree_skb(ddev->saved_skb); | ||
1198 | ddev->saved_skb = NULL; | ||
1199 | |||
572 | if (rc) | 1200 | if (rc) |
573 | kfree_skb(resp); | 1201 | kfree_skb(resp); |
574 | } | 1202 | } |
@@ -576,20 +1204,54 @@ exit: | |||
576 | int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb) | 1204 | int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb) |
577 | { | 1205 | { |
578 | struct digital_dep_req_res *dep_res; | 1206 | struct digital_dep_req_res *dep_res; |
1207 | struct sk_buff *chaining_skb, *tmp_skb; | ||
1208 | int rc; | ||
579 | 1209 | ||
580 | skb_push(skb, sizeof(struct digital_dep_req_res)); | 1210 | skb_push(skb, sizeof(struct digital_dep_req_res)); |
1211 | |||
581 | dep_res = (struct digital_dep_req_res *)skb->data; | 1212 | dep_res = (struct digital_dep_req_res *)skb->data; |
582 | 1213 | ||
583 | dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; | 1214 | dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; |
584 | dep_res->cmd = DIGITAL_CMD_DEP_RES; | 1215 | dep_res->cmd = DIGITAL_CMD_DEP_RES; |
585 | dep_res->pfb = ddev->curr_nfc_dep_pni; | 1216 | dep_res->pfb = ddev->curr_nfc_dep_pni; |
586 | 1217 | ||
587 | digital_skb_push_dep_sod(ddev, skb); | 1218 | if (ddev->did) { |
1219 | dep_res->pfb |= DIGITAL_NFC_DEP_PFB_DID_BIT; | ||
588 | 1220 | ||
589 | ddev->skb_add_crc(skb); | 1221 | memcpy(skb_put(skb, sizeof(ddev->did)), &ddev->did, |
1222 | sizeof(ddev->did)); | ||
1223 | } | ||
1224 | |||
1225 | ddev->curr_nfc_dep_pni = | ||
1226 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); | ||
1227 | |||
1228 | chaining_skb = ddev->chaining_skb; | ||
1229 | |||
1230 | tmp_skb = digital_send_dep_data_prep(ddev, skb, dep_res, NULL); | ||
1231 | if (IS_ERR(tmp_skb)) | ||
1232 | return PTR_ERR(tmp_skb); | ||
1233 | |||
1234 | digital_skb_push_dep_sod(ddev, tmp_skb); | ||
1235 | |||
1236 | ddev->skb_add_crc(tmp_skb); | ||
1237 | |||
1238 | ddev->saved_skb = skb_get(tmp_skb); | ||
1239 | ddev->saved_skb_len = tmp_skb->len; | ||
1240 | |||
1241 | rc = digital_tg_send_cmd(ddev, tmp_skb, 1500, digital_tg_recv_dep_req, | ||
1242 | NULL); | ||
1243 | if (rc) { | ||
1244 | if (tmp_skb != skb) | ||
1245 | kfree_skb(tmp_skb); | ||
1246 | |||
1247 | kfree_skb(chaining_skb); | ||
1248 | ddev->chaining_skb = NULL; | ||
590 | 1249 | ||
591 | return digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req, | 1250 | kfree_skb(ddev->saved_skb); |
592 | NULL); | 1251 | ddev->saved_skb = NULL; |
1252 | } | ||
1253 | |||
1254 | return rc; | ||
593 | } | 1255 | } |
594 | 1256 | ||
595 | static void digital_tg_send_psl_res_complete(struct nfc_digital_dev *ddev, | 1257 | static void digital_tg_send_psl_res_complete(struct nfc_digital_dev *ddev, |
@@ -632,9 +1294,10 @@ static int digital_tg_send_psl_res(struct nfc_digital_dev *ddev, u8 did, | |||
632 | 1294 | ||
633 | ddev->skb_add_crc(skb); | 1295 | ddev->skb_add_crc(skb); |
634 | 1296 | ||
1297 | ddev->curr_nfc_dep_pni = 0; | ||
1298 | |||
635 | rc = digital_tg_send_cmd(ddev, skb, 0, digital_tg_send_psl_res_complete, | 1299 | rc = digital_tg_send_cmd(ddev, skb, 0, digital_tg_send_psl_res_complete, |
636 | (void *)(unsigned long)rf_tech); | 1300 | (void *)(unsigned long)rf_tech); |
637 | |||
638 | if (rc) | 1301 | if (rc) |
639 | kfree_skb(skb); | 1302 | kfree_skb(skb); |
640 | 1303 | ||
@@ -647,7 +1310,7 @@ static void digital_tg_recv_psl_req(struct nfc_digital_dev *ddev, void *arg, | |||
647 | int rc; | 1310 | int rc; |
648 | struct digital_psl_req *psl_req; | 1311 | struct digital_psl_req *psl_req; |
649 | u8 rf_tech; | 1312 | u8 rf_tech; |
650 | u8 dsi; | 1313 | u8 dsi, payload_size, payload_bits; |
651 | 1314 | ||
652 | if (IS_ERR(resp)) { | 1315 | if (IS_ERR(resp)) { |
653 | rc = PTR_ERR(resp); | 1316 | rc = PTR_ERR(resp); |
@@ -692,6 +1355,18 @@ static void digital_tg_recv_psl_req(struct nfc_digital_dev *ddev, void *arg, | |||
692 | goto exit; | 1355 | goto exit; |
693 | } | 1356 | } |
694 | 1357 | ||
1358 | payload_bits = DIGITAL_PAYLOAD_FSL_TO_BITS(psl_req->fsl); | ||
1359 | payload_size = digital_payload_bits_to_size(payload_bits); | ||
1360 | |||
1361 | if (!payload_size || (payload_size > min(ddev->local_payload_max, | ||
1362 | ddev->remote_payload_max))) { | ||
1363 | rc = -EINVAL; | ||
1364 | goto exit; | ||
1365 | } | ||
1366 | |||
1367 | ddev->local_payload_max = payload_size; | ||
1368 | ddev->remote_payload_max = payload_size; | ||
1369 | |||
695 | rc = digital_tg_send_psl_res(ddev, psl_req->did, rf_tech); | 1370 | rc = digital_tg_send_psl_res(ddev, psl_req->did, rf_tech); |
696 | 1371 | ||
697 | exit: | 1372 | exit: |
@@ -712,6 +1387,8 @@ static void digital_tg_send_atr_res_complete(struct nfc_digital_dev *ddev, | |||
712 | if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) | 1387 | if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) |
713 | offset++; | 1388 | offset++; |
714 | 1389 | ||
1390 | ddev->atn_count = 0; | ||
1391 | |||
715 | if (resp->data[offset] == DIGITAL_CMD_PSL_REQ) | 1392 | if (resp->data[offset] == DIGITAL_CMD_PSL_REQ) |
716 | digital_tg_recv_psl_req(ddev, arg, resp); | 1393 | digital_tg_recv_psl_req(ddev, arg, resp); |
717 | else | 1394 | else |
@@ -723,7 +1400,7 @@ static int digital_tg_send_atr_res(struct nfc_digital_dev *ddev, | |||
723 | { | 1400 | { |
724 | struct digital_atr_res *atr_res; | 1401 | struct digital_atr_res *atr_res; |
725 | struct sk_buff *skb; | 1402 | struct sk_buff *skb; |
726 | u8 *gb; | 1403 | u8 *gb, payload_bits; |
727 | size_t gb_len; | 1404 | size_t gb_len; |
728 | int rc; | 1405 | int rc; |
729 | 1406 | ||
@@ -744,7 +1421,11 @@ static int digital_tg_send_atr_res(struct nfc_digital_dev *ddev, | |||
744 | atr_res->cmd = DIGITAL_CMD_ATR_RES; | 1421 | atr_res->cmd = DIGITAL_CMD_ATR_RES; |
745 | memcpy(atr_res->nfcid3, atr_req->nfcid3, sizeof(atr_req->nfcid3)); | 1422 | memcpy(atr_res->nfcid3, atr_req->nfcid3, sizeof(atr_req->nfcid3)); |
746 | atr_res->to = 8; | 1423 | atr_res->to = 8; |
747 | atr_res->pp = DIGITAL_LR_BITS_PAYLOAD_SIZE_254B; | 1424 | |
1425 | ddev->local_payload_max = DIGITAL_PAYLOAD_SIZE_MAX; | ||
1426 | payload_bits = digital_payload_size_to_bits(ddev->local_payload_max); | ||
1427 | atr_res->pp = DIGITAL_PAYLOAD_BITS_TO_PP(payload_bits); | ||
1428 | |||
748 | if (gb_len) { | 1429 | if (gb_len) { |
749 | skb_put(skb, gb_len); | 1430 | skb_put(skb, gb_len); |
750 | 1431 | ||
@@ -756,12 +1437,12 @@ static int digital_tg_send_atr_res(struct nfc_digital_dev *ddev, | |||
756 | 1437 | ||
757 | ddev->skb_add_crc(skb); | 1438 | ddev->skb_add_crc(skb); |
758 | 1439 | ||
1440 | ddev->curr_nfc_dep_pni = 0; | ||
1441 | |||
759 | rc = digital_tg_send_cmd(ddev, skb, 999, | 1442 | rc = digital_tg_send_cmd(ddev, skb, 999, |
760 | digital_tg_send_atr_res_complete, NULL); | 1443 | digital_tg_send_atr_res_complete, NULL); |
761 | if (rc) { | 1444 | if (rc) |
762 | kfree_skb(skb); | 1445 | kfree_skb(skb); |
763 | return rc; | ||
764 | } | ||
765 | 1446 | ||
766 | return rc; | 1447 | return rc; |
767 | } | 1448 | } |
@@ -772,7 +1453,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, | |||
772 | int rc; | 1453 | int rc; |
773 | struct digital_atr_req *atr_req; | 1454 | struct digital_atr_req *atr_req; |
774 | size_t gb_len, min_size; | 1455 | size_t gb_len, min_size; |
775 | u8 poll_tech_count; | 1456 | u8 poll_tech_count, payload_bits; |
776 | 1457 | ||
777 | if (IS_ERR(resp)) { | 1458 | if (IS_ERR(resp)) { |
778 | rc = PTR_ERR(resp); | 1459 | rc = PTR_ERR(resp); |
@@ -815,11 +1496,22 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, | |||
815 | atr_req = (struct digital_atr_req *)resp->data; | 1496 | atr_req = (struct digital_atr_req *)resp->data; |
816 | 1497 | ||
817 | if (atr_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT || | 1498 | if (atr_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT || |
818 | atr_req->cmd != DIGITAL_CMD_ATR_REQ) { | 1499 | atr_req->cmd != DIGITAL_CMD_ATR_REQ || |
1500 | atr_req->did > DIGITAL_DID_MAX) { | ||
819 | rc = -EINVAL; | 1501 | rc = -EINVAL; |
820 | goto exit; | 1502 | goto exit; |
821 | } | 1503 | } |
822 | 1504 | ||
1505 | payload_bits = DIGITAL_PAYLOAD_PP_TO_BITS(atr_req->pp); | ||
1506 | ddev->remote_payload_max = digital_payload_bits_to_size(payload_bits); | ||
1507 | |||
1508 | if (!ddev->remote_payload_max) { | ||
1509 | rc = -EINVAL; | ||
1510 | goto exit; | ||
1511 | } | ||
1512 | |||
1513 | ddev->did = atr_req->did; | ||
1514 | |||
823 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, | 1515 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, |
824 | NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED); | 1516 | NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED); |
825 | if (rc) | 1517 | if (rc) |
diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 677d24bb70f8..91df487aa0a9 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c | |||
@@ -345,6 +345,9 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, | |||
345 | 345 | ||
346 | pr_debug("\n"); | 346 | pr_debug("\n"); |
347 | 347 | ||
348 | if (hdev->gate2pipe[dest_gate] == NFC_HCI_DO_NOT_CREATE_PIPE) | ||
349 | return 0; | ||
350 | |||
348 | if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE) | 351 | if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE) |
349 | return -EADDRINUSE; | 352 | return -EADDRINUSE; |
350 | 353 | ||
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 117708263ced..ef50e7716c4a 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c | |||
@@ -167,6 +167,48 @@ exit: | |||
167 | void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, | 167 | void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, |
168 | struct sk_buff *skb) | 168 | struct sk_buff *skb) |
169 | { | 169 | { |
170 | int r = 0; | ||
171 | u8 gate = nfc_hci_pipe2gate(hdev, pipe); | ||
172 | u8 local_gate, new_pipe; | ||
173 | u8 gate_opened = 0x00; | ||
174 | |||
175 | pr_debug("from gate %x pipe %x cmd %x\n", gate, pipe, cmd); | ||
176 | |||
177 | switch (cmd) { | ||
178 | case NFC_HCI_ADM_NOTIFY_PIPE_CREATED: | ||
179 | if (skb->len != 5) { | ||
180 | r = -EPROTO; | ||
181 | break; | ||
182 | } | ||
183 | |||
184 | local_gate = skb->data[3]; | ||
185 | new_pipe = skb->data[4]; | ||
186 | nfc_hci_send_response(hdev, gate, NFC_HCI_ANY_OK, NULL, 0); | ||
187 | |||
188 | /* save the new created pipe and bind with local gate, | ||
189 | * the description for skb->data[3] is destination gate id | ||
190 | * but since we received this cmd from host controller, we | ||
191 | * are the destination and it is our local gate | ||
192 | */ | ||
193 | hdev->gate2pipe[local_gate] = new_pipe; | ||
194 | break; | ||
195 | case NFC_HCI_ANY_OPEN_PIPE: | ||
196 | /* if the pipe is already created, we allow remote host to | ||
197 | * open it | ||
198 | */ | ||
199 | if (gate != 0xff) | ||
200 | nfc_hci_send_response(hdev, gate, NFC_HCI_ANY_OK, | ||
201 | &gate_opened, 1); | ||
202 | break; | ||
203 | case NFC_HCI_ADM_NOTIFY_ALL_PIPE_CLEARED: | ||
204 | nfc_hci_send_response(hdev, gate, NFC_HCI_ANY_OK, NULL, 0); | ||
205 | break; | ||
206 | default: | ||
207 | pr_info("Discarded unknown cmd %x to gate %x\n", cmd, gate); | ||
208 | r = -EINVAL; | ||
209 | break; | ||
210 | } | ||
211 | |||
170 | kfree_skb(skb); | 212 | kfree_skb(skb); |
171 | } | 213 | } |
172 | 214 | ||
@@ -717,6 +759,19 @@ static int hci_disable_se(struct nfc_dev *nfc_dev, u32 se_idx) | |||
717 | return 0; | 759 | return 0; |
718 | } | 760 | } |
719 | 761 | ||
762 | static int hci_se_io(struct nfc_dev *nfc_dev, u32 se_idx, | ||
763 | u8 *apdu, size_t apdu_length, | ||
764 | se_io_cb_t cb, void *cb_context) | ||
765 | { | ||
766 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); | ||
767 | |||
768 | if (hdev->ops->se_io) | ||
769 | return hdev->ops->se_io(hdev, se_idx, apdu, | ||
770 | apdu_length, cb, cb_context); | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
720 | static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) | 775 | static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) |
721 | { | 776 | { |
722 | mutex_lock(&hdev->msg_tx_mutex); | 777 | mutex_lock(&hdev->msg_tx_mutex); |
@@ -830,6 +885,7 @@ static struct nfc_ops hci_nfc_ops = { | |||
830 | .discover_se = hci_discover_se, | 885 | .discover_se = hci_discover_se, |
831 | .enable_se = hci_enable_se, | 886 | .enable_se = hci_enable_se, |
832 | .disable_se = hci_disable_se, | 887 | .disable_se = hci_disable_se, |
888 | .se_io = hci_se_io, | ||
833 | }; | 889 | }; |
834 | 890 | ||
835 | struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, | 891 | struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, |
diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index a3ad69a4c648..c3435f8b20b4 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c | |||
@@ -401,7 +401,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) | |||
401 | u8 *miux_tlv = NULL, miux_tlv_length; | 401 | u8 *miux_tlv = NULL, miux_tlv_length; |
402 | u8 *rw_tlv = NULL, rw_tlv_length, rw; | 402 | u8 *rw_tlv = NULL, rw_tlv_length, rw; |
403 | int err; | 403 | int err; |
404 | u16 size = 0, miux; | 404 | u16 size = 0; |
405 | __be16 miux; | ||
405 | 406 | ||
406 | pr_debug("Sending CONNECT\n"); | 407 | pr_debug("Sending CONNECT\n"); |
407 | 408 | ||
@@ -465,7 +466,8 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) | |||
465 | u8 *miux_tlv = NULL, miux_tlv_length; | 466 | u8 *miux_tlv = NULL, miux_tlv_length; |
466 | u8 *rw_tlv = NULL, rw_tlv_length, rw; | 467 | u8 *rw_tlv = NULL, rw_tlv_length, rw; |
467 | int err; | 468 | int err; |
468 | u16 size = 0, miux; | 469 | u16 size = 0; |
470 | __be16 miux; | ||
469 | 471 | ||
470 | pr_debug("Sending CC\n"); | 472 | pr_debug("Sending CC\n"); |
471 | 473 | ||
diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index 51e788797317..b18f07ccb504 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2011 Intel Corporation. All rights reserved. | 2 | * Copyright (C) 2011 Intel Corporation. All rights reserved. |
3 | * Copyright (C) 2014 Marvell International Ltd. | ||
3 | * | 4 | * |
4 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -1511,8 +1512,10 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb) | |||
1511 | struct nfc_llcp_local *local; | 1512 | struct nfc_llcp_local *local; |
1512 | 1513 | ||
1513 | local = nfc_llcp_find_local(dev); | 1514 | local = nfc_llcp_find_local(dev); |
1514 | if (local == NULL) | 1515 | if (local == NULL) { |
1516 | kfree_skb(skb); | ||
1515 | return -ENODEV; | 1517 | return -ENODEV; |
1518 | } | ||
1516 | 1519 | ||
1517 | __nfc_llcp_recv(local, skb); | 1520 | __nfc_llcp_recv(local, skb); |
1518 | 1521 | ||
diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c index 51f077a92fa9..4894c415c441 100644 --- a/net/nfc/llcp_sock.c +++ b/net/nfc/llcp_sock.c | |||
@@ -524,13 +524,13 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, | |||
524 | 524 | ||
525 | static inline unsigned int llcp_accept_poll(struct sock *parent) | 525 | static inline unsigned int llcp_accept_poll(struct sock *parent) |
526 | { | 526 | { |
527 | struct nfc_llcp_sock *llcp_sock, *n, *parent_sock; | 527 | struct nfc_llcp_sock *llcp_sock, *parent_sock; |
528 | struct sock *sk; | 528 | struct sock *sk; |
529 | 529 | ||
530 | parent_sock = nfc_llcp_sock(parent); | 530 | parent_sock = nfc_llcp_sock(parent); |
531 | 531 | ||
532 | list_for_each_entry_safe(llcp_sock, n, &parent_sock->accept_queue, | 532 | list_for_each_entry(llcp_sock, &parent_sock->accept_queue, |
533 | accept_queue) { | 533 | accept_queue) { |
534 | sk = &llcp_sock->sk; | 534 | sk = &llcp_sock->sk; |
535 | 535 | ||
536 | if (sk->sk_state == LLCP_CONNECTED) | 536 | if (sk->sk_state == LLCP_CONNECTED) |
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 90b16cb40058..51feb5e63008 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * NFC Controller (NFCC) and a Device Host (DH). | 3 | * NFC Controller (NFCC) and a Device Host (DH). |
4 | * | 4 | * |
5 | * Copyright (C) 2011 Texas Instruments, Inc. | 5 | * Copyright (C) 2011 Texas Instruments, Inc. |
6 | * Copyright (C) 2014 Marvell International Ltd. | ||
6 | * | 7 | * |
7 | * Written by Ilan Elias <ilane@ti.com> | 8 | * Written by Ilan Elias <ilane@ti.com> |
8 | * | 9 | * |
@@ -196,18 +197,24 @@ static void nci_set_config_req(struct nci_dev *ndev, unsigned long opt) | |||
196 | nci_send_cmd(ndev, NCI_OP_CORE_SET_CONFIG_CMD, (3 + param->len), &cmd); | 197 | nci_send_cmd(ndev, NCI_OP_CORE_SET_CONFIG_CMD, (3 + param->len), &cmd); |
197 | } | 198 | } |
198 | 199 | ||
200 | struct nci_rf_discover_param { | ||
201 | __u32 im_protocols; | ||
202 | __u32 tm_protocols; | ||
203 | }; | ||
204 | |||
199 | static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) | 205 | static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) |
200 | { | 206 | { |
207 | struct nci_rf_discover_param *param = | ||
208 | (struct nci_rf_discover_param *)opt; | ||
201 | struct nci_rf_disc_cmd cmd; | 209 | struct nci_rf_disc_cmd cmd; |
202 | __u32 protocols = opt; | ||
203 | 210 | ||
204 | cmd.num_disc_configs = 0; | 211 | cmd.num_disc_configs = 0; |
205 | 212 | ||
206 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && | 213 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && |
207 | (protocols & NFC_PROTO_JEWEL_MASK || | 214 | (param->im_protocols & NFC_PROTO_JEWEL_MASK || |
208 | protocols & NFC_PROTO_MIFARE_MASK || | 215 | param->im_protocols & NFC_PROTO_MIFARE_MASK || |
209 | protocols & NFC_PROTO_ISO14443_MASK || | 216 | param->im_protocols & NFC_PROTO_ISO14443_MASK || |
210 | protocols & NFC_PROTO_NFC_DEP_MASK)) { | 217 | param->im_protocols & NFC_PROTO_NFC_DEP_MASK)) { |
211 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = | 218 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = |
212 | NCI_NFC_A_PASSIVE_POLL_MODE; | 219 | NCI_NFC_A_PASSIVE_POLL_MODE; |
213 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; | 220 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; |
@@ -215,7 +222,7 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) | |||
215 | } | 222 | } |
216 | 223 | ||
217 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && | 224 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && |
218 | (protocols & NFC_PROTO_ISO14443_B_MASK)) { | 225 | (param->im_protocols & NFC_PROTO_ISO14443_B_MASK)) { |
219 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = | 226 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = |
220 | NCI_NFC_B_PASSIVE_POLL_MODE; | 227 | NCI_NFC_B_PASSIVE_POLL_MODE; |
221 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; | 228 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; |
@@ -223,8 +230,8 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) | |||
223 | } | 230 | } |
224 | 231 | ||
225 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && | 232 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && |
226 | (protocols & NFC_PROTO_FELICA_MASK || | 233 | (param->im_protocols & NFC_PROTO_FELICA_MASK || |
227 | protocols & NFC_PROTO_NFC_DEP_MASK)) { | 234 | param->im_protocols & NFC_PROTO_NFC_DEP_MASK)) { |
228 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = | 235 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = |
229 | NCI_NFC_F_PASSIVE_POLL_MODE; | 236 | NCI_NFC_F_PASSIVE_POLL_MODE; |
230 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; | 237 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; |
@@ -232,13 +239,25 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) | |||
232 | } | 239 | } |
233 | 240 | ||
234 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && | 241 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && |
235 | (protocols & NFC_PROTO_ISO15693_MASK)) { | 242 | (param->im_protocols & NFC_PROTO_ISO15693_MASK)) { |
236 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = | 243 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = |
237 | NCI_NFC_V_PASSIVE_POLL_MODE; | 244 | NCI_NFC_V_PASSIVE_POLL_MODE; |
238 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; | 245 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; |
239 | cmd.num_disc_configs++; | 246 | cmd.num_disc_configs++; |
240 | } | 247 | } |
241 | 248 | ||
249 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS - 1) && | ||
250 | (param->tm_protocols & NFC_PROTO_NFC_DEP_MASK)) { | ||
251 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = | ||
252 | NCI_NFC_A_PASSIVE_LISTEN_MODE; | ||
253 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; | ||
254 | cmd.num_disc_configs++; | ||
255 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = | ||
256 | NCI_NFC_F_PASSIVE_LISTEN_MODE; | ||
257 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; | ||
258 | cmd.num_disc_configs++; | ||
259 | } | ||
260 | |||
242 | nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_CMD, | 261 | nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_CMD, |
243 | (1 + (cmd.num_disc_configs * sizeof(struct disc_config))), | 262 | (1 + (cmd.num_disc_configs * sizeof(struct disc_config))), |
244 | &cmd); | 263 | &cmd); |
@@ -280,7 +299,7 @@ static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt) | |||
280 | { | 299 | { |
281 | struct nci_rf_deactivate_cmd cmd; | 300 | struct nci_rf_deactivate_cmd cmd; |
282 | 301 | ||
283 | cmd.type = NCI_DEACTIVATE_TYPE_IDLE_MODE; | 302 | cmd.type = opt; |
284 | 303 | ||
285 | nci_send_cmd(ndev, NCI_OP_RF_DEACTIVATE_CMD, | 304 | nci_send_cmd(ndev, NCI_OP_RF_DEACTIVATE_CMD, |
286 | sizeof(struct nci_rf_deactivate_cmd), &cmd); | 305 | sizeof(struct nci_rf_deactivate_cmd), &cmd); |
@@ -441,6 +460,7 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) | |||
441 | { | 460 | { |
442 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | 461 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); |
443 | struct nci_set_config_param param; | 462 | struct nci_set_config_param param; |
463 | int rc; | ||
444 | 464 | ||
445 | param.val = nfc_get_local_general_bytes(nfc_dev, ¶m.len); | 465 | param.val = nfc_get_local_general_bytes(nfc_dev, ¶m.len); |
446 | if ((param.val == NULL) || (param.len == 0)) | 466 | if ((param.val == NULL) || (param.len == 0)) |
@@ -451,14 +471,45 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) | |||
451 | 471 | ||
452 | param.id = NCI_PN_ATR_REQ_GEN_BYTES; | 472 | param.id = NCI_PN_ATR_REQ_GEN_BYTES; |
453 | 473 | ||
474 | rc = nci_request(ndev, nci_set_config_req, (unsigned long)¶m, | ||
475 | msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); | ||
476 | if (rc) | ||
477 | return rc; | ||
478 | |||
479 | param.id = NCI_LN_ATR_RES_GEN_BYTES; | ||
480 | |||
454 | return nci_request(ndev, nci_set_config_req, (unsigned long)¶m, | 481 | return nci_request(ndev, nci_set_config_req, (unsigned long)¶m, |
455 | msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); | 482 | msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); |
456 | } | 483 | } |
457 | 484 | ||
485 | static int nci_set_listen_parameters(struct nfc_dev *nfc_dev) | ||
486 | { | ||
487 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
488 | int rc; | ||
489 | __u8 val; | ||
490 | |||
491 | val = NCI_LA_SEL_INFO_NFC_DEP_MASK; | ||
492 | |||
493 | rc = nci_set_config(ndev, NCI_LA_SEL_INFO, 1, &val); | ||
494 | if (rc) | ||
495 | return rc; | ||
496 | |||
497 | val = NCI_LF_PROTOCOL_TYPE_NFC_DEP_MASK; | ||
498 | |||
499 | rc = nci_set_config(ndev, NCI_LF_PROTOCOL_TYPE, 1, &val); | ||
500 | if (rc) | ||
501 | return rc; | ||
502 | |||
503 | val = NCI_LF_CON_BITR_F_212 | NCI_LF_CON_BITR_F_424; | ||
504 | |||
505 | return nci_set_config(ndev, NCI_LF_CON_BITR_F, 1, &val); | ||
506 | } | ||
507 | |||
458 | static int nci_start_poll(struct nfc_dev *nfc_dev, | 508 | static int nci_start_poll(struct nfc_dev *nfc_dev, |
459 | __u32 im_protocols, __u32 tm_protocols) | 509 | __u32 im_protocols, __u32 tm_protocols) |
460 | { | 510 | { |
461 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | 511 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); |
512 | struct nci_rf_discover_param param; | ||
462 | int rc; | 513 | int rc; |
463 | 514 | ||
464 | if ((atomic_read(&ndev->state) == NCI_DISCOVERY) || | 515 | if ((atomic_read(&ndev->state) == NCI_DISCOVERY) || |
@@ -476,13 +527,14 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, | |||
476 | (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) { | 527 | (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) { |
477 | pr_debug("target active or w4 select, implicitly deactivate\n"); | 528 | pr_debug("target active or w4 select, implicitly deactivate\n"); |
478 | 529 | ||
479 | rc = nci_request(ndev, nci_rf_deactivate_req, 0, | 530 | rc = nci_request(ndev, nci_rf_deactivate_req, |
531 | NCI_DEACTIVATE_TYPE_IDLE_MODE, | ||
480 | msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); | 532 | msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); |
481 | if (rc) | 533 | if (rc) |
482 | return -EBUSY; | 534 | return -EBUSY; |
483 | } | 535 | } |
484 | 536 | ||
485 | if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { | 537 | if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) { |
486 | rc = nci_set_local_general_bytes(nfc_dev); | 538 | rc = nci_set_local_general_bytes(nfc_dev); |
487 | if (rc) { | 539 | if (rc) { |
488 | pr_err("failed to set local general bytes\n"); | 540 | pr_err("failed to set local general bytes\n"); |
@@ -490,7 +542,15 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, | |||
490 | } | 542 | } |
491 | } | 543 | } |
492 | 544 | ||
493 | rc = nci_request(ndev, nci_rf_discover_req, im_protocols, | 545 | if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) { |
546 | rc = nci_set_listen_parameters(nfc_dev); | ||
547 | if (rc) | ||
548 | pr_err("failed to set listen parameters\n"); | ||
549 | } | ||
550 | |||
551 | param.im_protocols = im_protocols; | ||
552 | param.tm_protocols = tm_protocols; | ||
553 | rc = nci_request(ndev, nci_rf_discover_req, (unsigned long)¶m, | ||
494 | msecs_to_jiffies(NCI_RF_DISC_TIMEOUT)); | 554 | msecs_to_jiffies(NCI_RF_DISC_TIMEOUT)); |
495 | 555 | ||
496 | if (!rc) | 556 | if (!rc) |
@@ -509,7 +569,7 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev) | |||
509 | return; | 569 | return; |
510 | } | 570 | } |
511 | 571 | ||
512 | nci_request(ndev, nci_rf_deactivate_req, 0, | 572 | nci_request(ndev, nci_rf_deactivate_req, NCI_DEACTIVATE_TYPE_IDLE_MODE, |
513 | msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); | 573 | msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); |
514 | } | 574 | } |
515 | 575 | ||
@@ -594,7 +654,8 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, | |||
594 | ndev->target_active_prot = 0; | 654 | ndev->target_active_prot = 0; |
595 | 655 | ||
596 | if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) { | 656 | if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) { |
597 | nci_request(ndev, nci_rf_deactivate_req, 0, | 657 | nci_request(ndev, nci_rf_deactivate_req, |
658 | NCI_DEACTIVATE_TYPE_SLEEP_MODE, | ||
598 | msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); | 659 | msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); |
599 | } | 660 | } |
600 | } | 661 | } |
@@ -622,9 +683,24 @@ static int nci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, | |||
622 | 683 | ||
623 | static int nci_dep_link_down(struct nfc_dev *nfc_dev) | 684 | static int nci_dep_link_down(struct nfc_dev *nfc_dev) |
624 | { | 685 | { |
686 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
687 | int rc; | ||
688 | |||
625 | pr_debug("entry\n"); | 689 | pr_debug("entry\n"); |
626 | 690 | ||
627 | nci_deactivate_target(nfc_dev, NULL); | 691 | if (nfc_dev->rf_mode == NFC_RF_INITIATOR) { |
692 | nci_deactivate_target(nfc_dev, NULL); | ||
693 | } else { | ||
694 | if (atomic_read(&ndev->state) == NCI_LISTEN_ACTIVE || | ||
695 | atomic_read(&ndev->state) == NCI_DISCOVERY) { | ||
696 | nci_request(ndev, nci_rf_deactivate_req, 0, | ||
697 | msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); | ||
698 | } | ||
699 | |||
700 | rc = nfc_tm_deactivated(nfc_dev); | ||
701 | if (rc) | ||
702 | pr_err("error when signaling tm deactivation\n"); | ||
703 | } | ||
628 | 704 | ||
629 | return 0; | 705 | return 0; |
630 | } | 706 | } |
@@ -658,18 +734,58 @@ static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | |||
658 | return rc; | 734 | return rc; |
659 | } | 735 | } |
660 | 736 | ||
737 | static int nci_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) | ||
738 | { | ||
739 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
740 | int rc; | ||
741 | |||
742 | rc = nci_send_data(ndev, NCI_STATIC_RF_CONN_ID, skb); | ||
743 | if (rc) | ||
744 | pr_err("unable to send data\n"); | ||
745 | |||
746 | return rc; | ||
747 | } | ||
748 | |||
661 | static int nci_enable_se(struct nfc_dev *nfc_dev, u32 se_idx) | 749 | static int nci_enable_se(struct nfc_dev *nfc_dev, u32 se_idx) |
662 | { | 750 | { |
751 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
752 | |||
753 | if (ndev->ops->enable_se) | ||
754 | return ndev->ops->enable_se(ndev, se_idx); | ||
755 | |||
663 | return 0; | 756 | return 0; |
664 | } | 757 | } |
665 | 758 | ||
666 | static int nci_disable_se(struct nfc_dev *nfc_dev, u32 se_idx) | 759 | static int nci_disable_se(struct nfc_dev *nfc_dev, u32 se_idx) |
667 | { | 760 | { |
761 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
762 | |||
763 | if (ndev->ops->disable_se) | ||
764 | return ndev->ops->disable_se(ndev, se_idx); | ||
765 | |||
668 | return 0; | 766 | return 0; |
669 | } | 767 | } |
670 | 768 | ||
671 | static int nci_discover_se(struct nfc_dev *nfc_dev) | 769 | static int nci_discover_se(struct nfc_dev *nfc_dev) |
672 | { | 770 | { |
771 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
772 | |||
773 | if (ndev->ops->discover_se) | ||
774 | return ndev->ops->discover_se(ndev); | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | static int nci_se_io(struct nfc_dev *nfc_dev, u32 se_idx, | ||
780 | u8 *apdu, size_t apdu_length, | ||
781 | se_io_cb_t cb, void *cb_context) | ||
782 | { | ||
783 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
784 | |||
785 | if (ndev->ops->se_io) | ||
786 | return ndev->ops->se_io(ndev, se_idx, apdu, | ||
787 | apdu_length, cb, cb_context); | ||
788 | |||
673 | return 0; | 789 | return 0; |
674 | } | 790 | } |
675 | 791 | ||
@@ -683,9 +799,11 @@ static struct nfc_ops nci_nfc_ops = { | |||
683 | .activate_target = nci_activate_target, | 799 | .activate_target = nci_activate_target, |
684 | .deactivate_target = nci_deactivate_target, | 800 | .deactivate_target = nci_deactivate_target, |
685 | .im_transceive = nci_transceive, | 801 | .im_transceive = nci_transceive, |
802 | .tm_send = nci_tm_send, | ||
686 | .enable_se = nci_enable_se, | 803 | .enable_se = nci_enable_se, |
687 | .disable_se = nci_disable_se, | 804 | .disable_se = nci_disable_se, |
688 | .discover_se = nci_discover_se, | 805 | .discover_se = nci_discover_se, |
806 | .se_io = nci_se_io, | ||
689 | }; | 807 | }; |
690 | 808 | ||
691 | /* ---- Interface to NCI drivers ---- */ | 809 | /* ---- Interface to NCI drivers ---- */ |
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c index 427ef2c7ab68..a2de2a8cb00e 100644 --- a/net/nfc/nci/data.c +++ b/net/nfc/nci/data.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * NFC Controller (NFCC) and a Device Host (DH). | 3 | * NFC Controller (NFCC) and a Device Host (DH). |
4 | * | 4 | * |
5 | * Copyright (C) 2011 Texas Instruments, Inc. | 5 | * Copyright (C) 2011 Texas Instruments, Inc. |
6 | * Copyright (C) 2014 Marvell International Ltd. | ||
6 | * | 7 | * |
7 | * Written by Ilan Elias <ilane@ti.com> | 8 | * Written by Ilan Elias <ilane@ti.com> |
8 | * | 9 | * |
@@ -184,11 +185,16 @@ exit: | |||
184 | 185 | ||
185 | static void nci_add_rx_data_frag(struct nci_dev *ndev, | 186 | static void nci_add_rx_data_frag(struct nci_dev *ndev, |
186 | struct sk_buff *skb, | 187 | struct sk_buff *skb, |
187 | __u8 pbf) | 188 | __u8 pbf, __u8 status) |
188 | { | 189 | { |
189 | int reassembly_len; | 190 | int reassembly_len; |
190 | int err = 0; | 191 | int err = 0; |
191 | 192 | ||
193 | if (status) { | ||
194 | err = status; | ||
195 | goto exit; | ||
196 | } | ||
197 | |||
192 | if (ndev->rx_data_reassembly) { | 198 | if (ndev->rx_data_reassembly) { |
193 | reassembly_len = ndev->rx_data_reassembly->len; | 199 | reassembly_len = ndev->rx_data_reassembly->len; |
194 | 200 | ||
@@ -223,13 +229,24 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev, | |||
223 | } | 229 | } |
224 | 230 | ||
225 | exit: | 231 | exit: |
226 | nci_data_exchange_complete(ndev, skb, err); | 232 | if (ndev->nfc_dev->rf_mode == NFC_RF_INITIATOR) { |
233 | nci_data_exchange_complete(ndev, skb, err); | ||
234 | } else if (ndev->nfc_dev->rf_mode == NFC_RF_TARGET) { | ||
235 | /* Data received in Target mode, forward to nfc core */ | ||
236 | err = nfc_tm_data_received(ndev->nfc_dev, skb); | ||
237 | if (err) | ||
238 | pr_err("unable to handle received data\n"); | ||
239 | } else { | ||
240 | pr_err("rf mode unknown\n"); | ||
241 | kfree_skb(skb); | ||
242 | } | ||
227 | } | 243 | } |
228 | 244 | ||
229 | /* Rx Data packet */ | 245 | /* Rx Data packet */ |
230 | void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb) | 246 | void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb) |
231 | { | 247 | { |
232 | __u8 pbf = nci_pbf(skb->data); | 248 | __u8 pbf = nci_pbf(skb->data); |
249 | __u8 status = 0; | ||
233 | 250 | ||
234 | pr_debug("len %d\n", skb->len); | 251 | pr_debug("len %d\n", skb->len); |
235 | 252 | ||
@@ -247,8 +264,9 @@ void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb) | |||
247 | ndev->target_active_prot == NFC_PROTO_ISO15693) { | 264 | ndev->target_active_prot == NFC_PROTO_ISO15693) { |
248 | /* frame I/F => remove the status byte */ | 265 | /* frame I/F => remove the status byte */ |
249 | pr_debug("frame I/F => remove the status byte\n"); | 266 | pr_debug("frame I/F => remove the status byte\n"); |
267 | status = skb->data[skb->len - 1]; | ||
250 | skb_trim(skb, (skb->len - 1)); | 268 | skb_trim(skb, (skb->len - 1)); |
251 | } | 269 | } |
252 | 270 | ||
253 | nci_add_rx_data_frag(ndev, skb, pbf); | 271 | nci_add_rx_data_frag(ndev, skb, pbf, nci_to_errno(status)); |
254 | } | 272 | } |
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 205b35f666db..22e453cb787d 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c | |||
@@ -103,7 +103,7 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, | |||
103 | struct rf_tech_specific_params_nfca_poll *nfca_poll, | 103 | struct rf_tech_specific_params_nfca_poll *nfca_poll, |
104 | __u8 *data) | 104 | __u8 *data) |
105 | { | 105 | { |
106 | nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data)); | 106 | nfca_poll->sens_res = __le16_to_cpu(*((__le16 *)data)); |
107 | data += 2; | 107 | data += 2; |
108 | 108 | ||
109 | nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE); | 109 | nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE); |
@@ -167,7 +167,19 @@ static __u8 *nci_extract_rf_params_nfcv_passive_poll(struct nci_dev *ndev, | |||
167 | return data; | 167 | return data; |
168 | } | 168 | } |
169 | 169 | ||
170 | __u32 nci_get_prop_rf_protocol(struct nci_dev *ndev, __u8 rf_protocol) | 170 | static __u8 *nci_extract_rf_params_nfcf_passive_listen(struct nci_dev *ndev, |
171 | struct rf_tech_specific_params_nfcf_listen *nfcf_listen, | ||
172 | __u8 *data) | ||
173 | { | ||
174 | nfcf_listen->local_nfcid2_len = min_t(__u8, *data++, | ||
175 | NFC_NFCID2_MAXSIZE); | ||
176 | memcpy(nfcf_listen->local_nfcid2, data, nfcf_listen->local_nfcid2_len); | ||
177 | data += nfcf_listen->local_nfcid2_len; | ||
178 | |||
179 | return data; | ||
180 | } | ||
181 | |||
182 | static __u32 nci_get_prop_rf_protocol(struct nci_dev *ndev, __u8 rf_protocol) | ||
171 | { | 183 | { |
172 | if (ndev->ops->get_rfprotocol) | 184 | if (ndev->ops->get_rfprotocol) |
173 | return ndev->ops->get_rfprotocol(ndev, rf_protocol); | 185 | return ndev->ops->get_rfprotocol(ndev, rf_protocol); |
@@ -401,17 +413,29 @@ static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev, | |||
401 | struct nci_rf_intf_activated_ntf *ntf, __u8 *data) | 413 | struct nci_rf_intf_activated_ntf *ntf, __u8 *data) |
402 | { | 414 | { |
403 | struct activation_params_poll_nfc_dep *poll; | 415 | struct activation_params_poll_nfc_dep *poll; |
416 | struct activation_params_listen_nfc_dep *listen; | ||
404 | 417 | ||
405 | switch (ntf->activation_rf_tech_and_mode) { | 418 | switch (ntf->activation_rf_tech_and_mode) { |
406 | case NCI_NFC_A_PASSIVE_POLL_MODE: | 419 | case NCI_NFC_A_PASSIVE_POLL_MODE: |
407 | case NCI_NFC_F_PASSIVE_POLL_MODE: | 420 | case NCI_NFC_F_PASSIVE_POLL_MODE: |
408 | poll = &ntf->activation_params.poll_nfc_dep; | 421 | poll = &ntf->activation_params.poll_nfc_dep; |
409 | poll->atr_res_len = min_t(__u8, *data++, 63); | 422 | poll->atr_res_len = min_t(__u8, *data++, |
423 | NFC_ATR_RES_MAXSIZE - 2); | ||
410 | pr_debug("atr_res_len %d\n", poll->atr_res_len); | 424 | pr_debug("atr_res_len %d\n", poll->atr_res_len); |
411 | if (poll->atr_res_len > 0) | 425 | if (poll->atr_res_len > 0) |
412 | memcpy(poll->atr_res, data, poll->atr_res_len); | 426 | memcpy(poll->atr_res, data, poll->atr_res_len); |
413 | break; | 427 | break; |
414 | 428 | ||
429 | case NCI_NFC_A_PASSIVE_LISTEN_MODE: | ||
430 | case NCI_NFC_F_PASSIVE_LISTEN_MODE: | ||
431 | listen = &ntf->activation_params.listen_nfc_dep; | ||
432 | listen->atr_req_len = min_t(__u8, *data++, | ||
433 | NFC_ATR_REQ_MAXSIZE - 2); | ||
434 | pr_debug("atr_req_len %d\n", listen->atr_req_len); | ||
435 | if (listen->atr_req_len > 0) | ||
436 | memcpy(listen->atr_req, data, listen->atr_req_len); | ||
437 | break; | ||
438 | |||
415 | default: | 439 | default: |
416 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", | 440 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", |
417 | ntf->activation_rf_tech_and_mode); | 441 | ntf->activation_rf_tech_and_mode); |
@@ -444,6 +468,48 @@ static void nci_target_auto_activated(struct nci_dev *ndev, | |||
444 | nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets); | 468 | nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets); |
445 | } | 469 | } |
446 | 470 | ||
471 | static int nci_store_general_bytes_nfc_dep(struct nci_dev *ndev, | ||
472 | struct nci_rf_intf_activated_ntf *ntf) | ||
473 | { | ||
474 | ndev->remote_gb_len = 0; | ||
475 | |||
476 | if (ntf->activation_params_len <= 0) | ||
477 | return NCI_STATUS_OK; | ||
478 | |||
479 | switch (ntf->activation_rf_tech_and_mode) { | ||
480 | case NCI_NFC_A_PASSIVE_POLL_MODE: | ||
481 | case NCI_NFC_F_PASSIVE_POLL_MODE: | ||
482 | ndev->remote_gb_len = min_t(__u8, | ||
483 | (ntf->activation_params.poll_nfc_dep.atr_res_len | ||
484 | - NFC_ATR_RES_GT_OFFSET), | ||
485 | NFC_ATR_RES_GB_MAXSIZE); | ||
486 | memcpy(ndev->remote_gb, | ||
487 | (ntf->activation_params.poll_nfc_dep.atr_res | ||
488 | + NFC_ATR_RES_GT_OFFSET), | ||
489 | ndev->remote_gb_len); | ||
490 | break; | ||
491 | |||
492 | case NCI_NFC_A_PASSIVE_LISTEN_MODE: | ||
493 | case NCI_NFC_F_PASSIVE_LISTEN_MODE: | ||
494 | ndev->remote_gb_len = min_t(__u8, | ||
495 | (ntf->activation_params.listen_nfc_dep.atr_req_len | ||
496 | - NFC_ATR_REQ_GT_OFFSET), | ||
497 | NFC_ATR_REQ_GB_MAXSIZE); | ||
498 | memcpy(ndev->remote_gb, | ||
499 | (ntf->activation_params.listen_nfc_dep.atr_req | ||
500 | + NFC_ATR_REQ_GT_OFFSET), | ||
501 | ndev->remote_gb_len); | ||
502 | break; | ||
503 | |||
504 | default: | ||
505 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", | ||
506 | ntf->activation_rf_tech_and_mode); | ||
507 | return NCI_STATUS_RF_PROTOCOL_ERROR; | ||
508 | } | ||
509 | |||
510 | return NCI_STATUS_OK; | ||
511 | } | ||
512 | |||
447 | static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, | 513 | static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, |
448 | struct sk_buff *skb) | 514 | struct sk_buff *skb) |
449 | { | 515 | { |
@@ -493,6 +559,16 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, | |||
493 | &(ntf.rf_tech_specific_params.nfcv_poll), data); | 559 | &(ntf.rf_tech_specific_params.nfcv_poll), data); |
494 | break; | 560 | break; |
495 | 561 | ||
562 | case NCI_NFC_A_PASSIVE_LISTEN_MODE: | ||
563 | /* no RF technology specific parameters */ | ||
564 | break; | ||
565 | |||
566 | case NCI_NFC_F_PASSIVE_LISTEN_MODE: | ||
567 | data = nci_extract_rf_params_nfcf_passive_listen(ndev, | ||
568 | &(ntf.rf_tech_specific_params.nfcf_listen), | ||
569 | data); | ||
570 | break; | ||
571 | |||
496 | default: | 572 | default: |
497 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", | 573 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", |
498 | ntf.activation_rf_tech_and_mode); | 574 | ntf.activation_rf_tech_and_mode); |
@@ -546,32 +622,39 @@ exit: | |||
546 | 622 | ||
547 | /* store general bytes to be reported later in dep_link_up */ | 623 | /* store general bytes to be reported later in dep_link_up */ |
548 | if (ntf.rf_interface == NCI_RF_INTERFACE_NFC_DEP) { | 624 | if (ntf.rf_interface == NCI_RF_INTERFACE_NFC_DEP) { |
549 | ndev->remote_gb_len = 0; | 625 | err = nci_store_general_bytes_nfc_dep(ndev, &ntf); |
550 | 626 | if (err != NCI_STATUS_OK) | |
551 | if (ntf.activation_params_len > 0) { | 627 | pr_err("unable to store general bytes\n"); |
552 | /* ATR_RES general bytes at offset 15 */ | ||
553 | ndev->remote_gb_len = min_t(__u8, | ||
554 | (ntf.activation_params | ||
555 | .poll_nfc_dep.atr_res_len | ||
556 | - NFC_ATR_RES_GT_OFFSET), | ||
557 | NFC_MAX_GT_LEN); | ||
558 | memcpy(ndev->remote_gb, | ||
559 | (ntf.activation_params.poll_nfc_dep | ||
560 | .atr_res + NFC_ATR_RES_GT_OFFSET), | ||
561 | ndev->remote_gb_len); | ||
562 | } | ||
563 | } | 628 | } |
564 | } | 629 | } |
565 | 630 | ||
566 | if (atomic_read(&ndev->state) == NCI_DISCOVERY) { | 631 | if (!(ntf.activation_rf_tech_and_mode & NCI_RF_TECH_MODE_LISTEN_MASK)) { |
567 | /* A single target was found and activated automatically */ | 632 | /* Poll mode */ |
568 | atomic_set(&ndev->state, NCI_POLL_ACTIVE); | 633 | if (atomic_read(&ndev->state) == NCI_DISCOVERY) { |
569 | if (err == NCI_STATUS_OK) | 634 | /* A single target was found and activated |
570 | nci_target_auto_activated(ndev, &ntf); | 635 | * automatically */ |
571 | } else { /* ndev->state == NCI_W4_HOST_SELECT */ | 636 | atomic_set(&ndev->state, NCI_POLL_ACTIVE); |
572 | /* A selected target was activated, so complete the request */ | 637 | if (err == NCI_STATUS_OK) |
573 | atomic_set(&ndev->state, NCI_POLL_ACTIVE); | 638 | nci_target_auto_activated(ndev, &ntf); |
574 | nci_req_complete(ndev, err); | 639 | } else { /* ndev->state == NCI_W4_HOST_SELECT */ |
640 | /* A selected target was activated, so complete the | ||
641 | * request */ | ||
642 | atomic_set(&ndev->state, NCI_POLL_ACTIVE); | ||
643 | nci_req_complete(ndev, err); | ||
644 | } | ||
645 | } else { | ||
646 | /* Listen mode */ | ||
647 | atomic_set(&ndev->state, NCI_LISTEN_ACTIVE); | ||
648 | if (err == NCI_STATUS_OK && | ||
649 | ntf.rf_protocol == NCI_RF_PROTOCOL_NFC_DEP) { | ||
650 | err = nfc_tm_activated(ndev->nfc_dev, | ||
651 | NFC_PROTO_NFC_DEP_MASK, | ||
652 | NFC_COMM_PASSIVE, | ||
653 | ndev->remote_gb, | ||
654 | ndev->remote_gb_len); | ||
655 | if (err != NCI_STATUS_OK) | ||
656 | pr_err("error when signaling tm activation\n"); | ||
657 | } | ||
575 | } | 658 | } |
576 | } | 659 | } |
577 | 660 | ||
@@ -595,8 +678,21 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, | |||
595 | if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) | 678 | if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) |
596 | nci_data_exchange_complete(ndev, NULL, -EIO); | 679 | nci_data_exchange_complete(ndev, NULL, -EIO); |
597 | 680 | ||
598 | nci_clear_target_list(ndev); | 681 | switch (ntf->type) { |
599 | atomic_set(&ndev->state, NCI_IDLE); | 682 | case NCI_DEACTIVATE_TYPE_IDLE_MODE: |
683 | nci_clear_target_list(ndev); | ||
684 | atomic_set(&ndev->state, NCI_IDLE); | ||
685 | break; | ||
686 | case NCI_DEACTIVATE_TYPE_SLEEP_MODE: | ||
687 | case NCI_DEACTIVATE_TYPE_SLEEP_AF_MODE: | ||
688 | atomic_set(&ndev->state, NCI_W4_HOST_SELECT); | ||
689 | break; | ||
690 | case NCI_DEACTIVATE_TYPE_DISCOVERY: | ||
691 | nci_clear_target_list(ndev); | ||
692 | atomic_set(&ndev->state, NCI_DISCOVERY); | ||
693 | break; | ||
694 | } | ||
695 | |||
600 | nci_req_complete(ndev, NCI_STATUS_OK); | 696 | nci_req_complete(ndev, NCI_STATUS_OK); |
601 | } | 697 | } |
602 | 698 | ||
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 43cb1c17e267..44989fc8cddf 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
@@ -810,6 +810,31 @@ out: | |||
810 | return rc; | 810 | return rc; |
811 | } | 811 | } |
812 | 812 | ||
813 | static int nfc_genl_activate_target(struct sk_buff *skb, struct genl_info *info) | ||
814 | { | ||
815 | struct nfc_dev *dev; | ||
816 | u32 device_idx, target_idx, protocol; | ||
817 | int rc; | ||
818 | |||
819 | if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) | ||
820 | return -EINVAL; | ||
821 | |||
822 | device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); | ||
823 | |||
824 | dev = nfc_get_device(device_idx); | ||
825 | if (!dev) | ||
826 | return -ENODEV; | ||
827 | |||
828 | target_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]); | ||
829 | protocol = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]); | ||
830 | |||
831 | nfc_deactivate_target(dev, target_idx); | ||
832 | rc = nfc_activate_target(dev, target_idx, protocol); | ||
833 | |||
834 | nfc_put_device(dev); | ||
835 | return 0; | ||
836 | } | ||
837 | |||
813 | static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info) | 838 | static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info) |
814 | { | 839 | { |
815 | struct nfc_dev *dev; | 840 | struct nfc_dev *dev; |
@@ -1285,6 +1310,51 @@ static int nfc_genl_dump_ses_done(struct netlink_callback *cb) | |||
1285 | return 0; | 1310 | return 0; |
1286 | } | 1311 | } |
1287 | 1312 | ||
1313 | static int nfc_se_io(struct nfc_dev *dev, u32 se_idx, | ||
1314 | u8 *apdu, size_t apdu_length, | ||
1315 | se_io_cb_t cb, void *cb_context) | ||
1316 | { | ||
1317 | struct nfc_se *se; | ||
1318 | int rc; | ||
1319 | |||
1320 | pr_debug("%s se index %d\n", dev_name(&dev->dev), se_idx); | ||
1321 | |||
1322 | device_lock(&dev->dev); | ||
1323 | |||
1324 | if (!device_is_registered(&dev->dev)) { | ||
1325 | rc = -ENODEV; | ||
1326 | goto error; | ||
1327 | } | ||
1328 | |||
1329 | if (!dev->dev_up) { | ||
1330 | rc = -ENODEV; | ||
1331 | goto error; | ||
1332 | } | ||
1333 | |||
1334 | if (!dev->ops->se_io) { | ||
1335 | rc = -EOPNOTSUPP; | ||
1336 | goto error; | ||
1337 | } | ||
1338 | |||
1339 | se = nfc_find_se(dev, se_idx); | ||
1340 | if (!se) { | ||
1341 | rc = -EINVAL; | ||
1342 | goto error; | ||
1343 | } | ||
1344 | |||
1345 | if (se->state != NFC_SE_ENABLED) { | ||
1346 | rc = -ENODEV; | ||
1347 | goto error; | ||
1348 | } | ||
1349 | |||
1350 | rc = dev->ops->se_io(dev, se_idx, apdu, | ||
1351 | apdu_length, cb, cb_context); | ||
1352 | |||
1353 | error: | ||
1354 | device_unlock(&dev->dev); | ||
1355 | return rc; | ||
1356 | } | ||
1357 | |||
1288 | struct se_io_ctx { | 1358 | struct se_io_ctx { |
1289 | u32 dev_idx; | 1359 | u32 dev_idx; |
1290 | u32 se_idx; | 1360 | u32 se_idx; |
@@ -1367,7 +1437,7 @@ static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info) | |||
1367 | ctx->dev_idx = dev_idx; | 1437 | ctx->dev_idx = dev_idx; |
1368 | ctx->se_idx = se_idx; | 1438 | ctx->se_idx = se_idx; |
1369 | 1439 | ||
1370 | return dev->ops->se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx); | 1440 | return nfc_se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx); |
1371 | } | 1441 | } |
1372 | 1442 | ||
1373 | static const struct genl_ops nfc_genl_ops[] = { | 1443 | static const struct genl_ops nfc_genl_ops[] = { |
@@ -1455,6 +1525,11 @@ static const struct genl_ops nfc_genl_ops[] = { | |||
1455 | .doit = nfc_genl_se_io, | 1525 | .doit = nfc_genl_se_io, |
1456 | .policy = nfc_genl_policy, | 1526 | .policy = nfc_genl_policy, |
1457 | }, | 1527 | }, |
1528 | { | ||
1529 | .cmd = NFC_CMD_ACTIVATE_TARGET, | ||
1530 | .doit = nfc_genl_activate_target, | ||
1531 | .policy = nfc_genl_policy, | ||
1532 | }, | ||
1458 | }; | 1533 | }; |
1459 | 1534 | ||
1460 | 1535 | ||
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 29c8675f9a11..22ba971741e5 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -175,7 +175,7 @@ config CFG80211_INTERNAL_REGDB | |||
175 | Most distributions have a CRDA package. So if unsure, say N. | 175 | Most distributions have a CRDA package. So if unsure, say N. |
176 | 176 | ||
177 | config CFG80211_WEXT | 177 | config CFG80211_WEXT |
178 | bool "cfg80211 wireless extensions compatibility" | 178 | bool |
179 | depends on CFG80211 | 179 | depends on CFG80211 |
180 | select WEXT_CORE | 180 | select WEXT_CORE |
181 | help | 181 | help |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index a761670af31d..4c9e39f04ef8 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o | |||
10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o | 10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o |
11 | 11 | ||
12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o | 12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o | 13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o |
14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o | 15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o |
16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o | 16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 72d81e2154d5..85506f1d0789 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -115,7 +115,7 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) | |||
115 | EXPORT_SYMBOL(cfg80211_chandef_valid); | 115 | EXPORT_SYMBOL(cfg80211_chandef_valid); |
116 | 116 | ||
117 | static void chandef_primary_freqs(const struct cfg80211_chan_def *c, | 117 | static void chandef_primary_freqs(const struct cfg80211_chan_def *c, |
118 | int *pri40, int *pri80) | 118 | u32 *pri40, u32 *pri80) |
119 | { | 119 | { |
120 | int tmp; | 120 | int tmp; |
121 | 121 | ||
@@ -366,6 +366,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | |||
366 | 366 | ||
367 | break; | 367 | break; |
368 | case NL80211_IFTYPE_STATION: | 368 | case NL80211_IFTYPE_STATION: |
369 | case NL80211_IFTYPE_OCB: | ||
369 | case NL80211_IFTYPE_P2P_CLIENT: | 370 | case NL80211_IFTYPE_P2P_CLIENT: |
370 | case NL80211_IFTYPE_MONITOR: | 371 | case NL80211_IFTYPE_MONITOR: |
371 | case NL80211_IFTYPE_AP_VLAN: | 372 | case NL80211_IFTYPE_AP_VLAN: |
@@ -892,6 +893,13 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
892 | *radar_detect |= BIT(wdev->chandef.width); | 893 | *radar_detect |= BIT(wdev->chandef.width); |
893 | } | 894 | } |
894 | return; | 895 | return; |
896 | case NL80211_IFTYPE_OCB: | ||
897 | if (wdev->chandef.chan) { | ||
898 | *chan = wdev->chandef.chan; | ||
899 | *chanmode = CHAN_MODE_SHARED; | ||
900 | return; | ||
901 | } | ||
902 | break; | ||
895 | case NL80211_IFTYPE_MONITOR: | 903 | case NL80211_IFTYPE_MONITOR: |
896 | case NL80211_IFTYPE_AP_VLAN: | 904 | case NL80211_IFTYPE_AP_VLAN: |
897 | case NL80211_IFTYPE_WDS: | 905 | case NL80211_IFTYPE_WDS: |
diff --git a/net/wireless/core.c b/net/wireless/core.c index f52a4cd7017c..53dda7728f86 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -86,11 +86,11 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | |||
86 | return &rdev->wiphy; | 86 | return &rdev->wiphy; |
87 | } | 87 | } |
88 | 88 | ||
89 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | 89 | static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev, |
90 | char *newname) | 90 | const char *newname) |
91 | { | 91 | { |
92 | struct cfg80211_registered_device *rdev2; | 92 | struct cfg80211_registered_device *rdev2; |
93 | int wiphy_idx, taken = -1, result, digits; | 93 | int wiphy_idx, taken = -1, digits; |
94 | 94 | ||
95 | ASSERT_RTNL(); | 95 | ASSERT_RTNL(); |
96 | 96 | ||
@@ -109,15 +109,28 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
109 | return -EINVAL; | 109 | return -EINVAL; |
110 | } | 110 | } |
111 | 111 | ||
112 | /* Ensure another device does not already have this name. */ | ||
113 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) | ||
114 | if (strcmp(newname, wiphy_name(&rdev2->wiphy)) == 0) | ||
115 | return -EINVAL; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | ||
121 | char *newname) | ||
122 | { | ||
123 | int result; | ||
124 | |||
125 | ASSERT_RTNL(); | ||
112 | 126 | ||
113 | /* Ignore nop renames */ | 127 | /* Ignore nop renames */ |
114 | if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) | 128 | if (strcmp(newname, wiphy_name(&rdev->wiphy)) == 0) |
115 | return 0; | 129 | return 0; |
116 | 130 | ||
117 | /* Ensure another device does not already have this name. */ | 131 | result = cfg80211_dev_check_name(rdev, newname); |
118 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) | 132 | if (result < 0) |
119 | if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) | 133 | return result; |
120 | return -EINVAL; | ||
121 | 134 | ||
122 | result = device_rename(&rdev->wiphy.dev, newname); | 135 | result = device_rename(&rdev->wiphy.dev, newname); |
123 | if (result) | 136 | if (result) |
@@ -309,7 +322,8 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work) | |||
309 | 322 | ||
310 | /* exported functions */ | 323 | /* exported functions */ |
311 | 324 | ||
312 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | 325 | struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, |
326 | const char *requested_name) | ||
313 | { | 327 | { |
314 | static atomic_t wiphy_counter = ATOMIC_INIT(0); | 328 | static atomic_t wiphy_counter = ATOMIC_INIT(0); |
315 | 329 | ||
@@ -346,7 +360,31 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
346 | rdev->wiphy_idx--; | 360 | rdev->wiphy_idx--; |
347 | 361 | ||
348 | /* give it a proper name */ | 362 | /* give it a proper name */ |
349 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); | 363 | if (requested_name && requested_name[0]) { |
364 | int rv; | ||
365 | |||
366 | rtnl_lock(); | ||
367 | rv = cfg80211_dev_check_name(rdev, requested_name); | ||
368 | |||
369 | if (rv < 0) { | ||
370 | rtnl_unlock(); | ||
371 | goto use_default_name; | ||
372 | } | ||
373 | |||
374 | rv = dev_set_name(&rdev->wiphy.dev, "%s", requested_name); | ||
375 | rtnl_unlock(); | ||
376 | if (rv) | ||
377 | goto use_default_name; | ||
378 | } else { | ||
379 | use_default_name: | ||
380 | /* NOTE: This is *probably* safe w/out holding rtnl because of | ||
381 | * the restrictions on phy names. Probably this call could | ||
382 | * fail if some other part of the kernel (re)named a device | ||
383 | * phyX. But, might should add some locking and check return | ||
384 | * value, and use a different name if this one exists? | ||
385 | */ | ||
386 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); | ||
387 | } | ||
350 | 388 | ||
351 | INIT_LIST_HEAD(&rdev->wdev_list); | 389 | INIT_LIST_HEAD(&rdev->wdev_list); |
352 | INIT_LIST_HEAD(&rdev->beacon_registrations); | 390 | INIT_LIST_HEAD(&rdev->beacon_registrations); |
@@ -406,7 +444,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
406 | 444 | ||
407 | return &rdev->wiphy; | 445 | return &rdev->wiphy; |
408 | } | 446 | } |
409 | EXPORT_SYMBOL(wiphy_new); | 447 | EXPORT_SYMBOL(wiphy_new_nm); |
410 | 448 | ||
411 | static int wiphy_verify_combinations(struct wiphy *wiphy) | 449 | static int wiphy_verify_combinations(struct wiphy *wiphy) |
412 | { | 450 | { |
@@ -503,6 +541,24 @@ int wiphy_register(struct wiphy *wiphy) | |||
503 | !wiphy->wowlan->tcp)) | 541 | !wiphy->wowlan->tcp)) |
504 | return -EINVAL; | 542 | return -EINVAL; |
505 | #endif | 543 | #endif |
544 | if (WARN_ON((wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) && | ||
545 | (!rdev->ops->tdls_channel_switch || | ||
546 | !rdev->ops->tdls_cancel_channel_switch))) | ||
547 | return -EINVAL; | ||
548 | |||
549 | /* | ||
550 | * if a wiphy has unsupported modes for regulatory channel enforcement, | ||
551 | * opt-out of enforcement checking | ||
552 | */ | ||
553 | if (wiphy->interface_modes & ~(BIT(NL80211_IFTYPE_STATION) | | ||
554 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
555 | BIT(NL80211_IFTYPE_AP) | | ||
556 | BIT(NL80211_IFTYPE_P2P_GO) | | ||
557 | BIT(NL80211_IFTYPE_ADHOC) | | ||
558 | BIT(NL80211_IFTYPE_P2P_DEVICE) | | ||
559 | BIT(NL80211_IFTYPE_AP_VLAN) | | ||
560 | BIT(NL80211_IFTYPE_MONITOR))) | ||
561 | wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; | ||
506 | 562 | ||
507 | if (WARN_ON(wiphy->coalesce && | 563 | if (WARN_ON(wiphy->coalesce && |
508 | (!wiphy->coalesce->n_rules || | 564 | (!wiphy->coalesce->n_rules || |
@@ -831,7 +887,22 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
831 | case NL80211_IFTYPE_P2P_GO: | 887 | case NL80211_IFTYPE_P2P_GO: |
832 | __cfg80211_stop_ap(rdev, dev, true); | 888 | __cfg80211_stop_ap(rdev, dev, true); |
833 | break; | 889 | break; |
834 | default: | 890 | case NL80211_IFTYPE_OCB: |
891 | __cfg80211_leave_ocb(rdev, dev); | ||
892 | break; | ||
893 | case NL80211_IFTYPE_WDS: | ||
894 | /* must be handled by mac80211/driver, has no APIs */ | ||
895 | break; | ||
896 | case NL80211_IFTYPE_P2P_DEVICE: | ||
897 | /* cannot happen, has no netdev */ | ||
898 | break; | ||
899 | case NL80211_IFTYPE_AP_VLAN: | ||
900 | case NL80211_IFTYPE_MONITOR: | ||
901 | /* nothing to do */ | ||
902 | break; | ||
903 | case NL80211_IFTYPE_UNSPECIFIED: | ||
904 | case NUM_NL80211_IFTYPES: | ||
905 | /* invalid */ | ||
835 | break; | 906 | break; |
836 | } | 907 | } |
837 | } | 908 | } |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 7e3a3cef7df9..faa5b1609aae 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -111,6 +111,7 @@ cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) | |||
111 | rdev->wiphy.wowlan_config->tcp->sock) | 111 | rdev->wiphy.wowlan_config->tcp->sock) |
112 | sock_release(rdev->wiphy.wowlan_config->tcp->sock); | 112 | sock_release(rdev->wiphy.wowlan_config->tcp->sock); |
113 | kfree(rdev->wiphy.wowlan_config->tcp); | 113 | kfree(rdev->wiphy.wowlan_config->tcp); |
114 | kfree(rdev->wiphy.wowlan_config->nd_config); | ||
114 | kfree(rdev->wiphy.wowlan_config); | 115 | kfree(rdev->wiphy.wowlan_config); |
115 | #endif | 116 | #endif |
116 | } | 117 | } |
@@ -290,6 +291,18 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
290 | struct wireless_dev *wdev, | 291 | struct wireless_dev *wdev, |
291 | struct cfg80211_chan_def *chandef); | 292 | struct cfg80211_chan_def *chandef); |
292 | 293 | ||
294 | /* OCB */ | ||
295 | int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev, | ||
296 | struct net_device *dev, | ||
297 | struct ocb_setup *setup); | ||
298 | int cfg80211_join_ocb(struct cfg80211_registered_device *rdev, | ||
299 | struct net_device *dev, | ||
300 | struct ocb_setup *setup); | ||
301 | int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, | ||
302 | struct net_device *dev); | ||
303 | int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, | ||
304 | struct net_device *dev); | ||
305 | |||
293 | /* AP */ | 306 | /* AP */ |
294 | int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | 307 | int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, |
295 | struct net_device *dev, bool notify); | 308 | struct net_device *dev, bool notify); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cb9f5a44ffad..a17d6bc6b22c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -209,7 +209,7 @@ cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) | |||
209 | } | 209 | } |
210 | 210 | ||
211 | /* policy for the attributes */ | 211 | /* policy for the attributes */ |
212 | static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | 212 | static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { |
213 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, | 213 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, |
214 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, | 214 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, |
215 | .len = 20-1 }, | 215 | .len = 20-1 }, |
@@ -388,13 +388,14 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
388 | [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, | 388 | [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, |
389 | [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, | 389 | [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, |
390 | [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, | 390 | [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, |
391 | [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG }, | 391 | [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG }, |
392 | [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY }, | 392 | [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY }, |
393 | [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG }, | 393 | [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG }, |
394 | [NL80211_ATTR_TSID] = { .type = NLA_U8 }, | 394 | [NL80211_ATTR_TSID] = { .type = NLA_U8 }, |
395 | [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 }, | 395 | [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 }, |
396 | [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, | 396 | [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, |
397 | [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, | 397 | [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, |
398 | [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN }, | ||
398 | }; | 399 | }; |
399 | 400 | ||
400 | /* policy for the key attributes */ | 401 | /* policy for the key attributes */ |
@@ -428,6 +429,7 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | |||
428 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, | 429 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, |
429 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, | 430 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, |
430 | [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED }, | 431 | [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED }, |
432 | [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED }, | ||
431 | }; | 433 | }; |
432 | 434 | ||
433 | static const struct nla_policy | 435 | static const struct nla_policy |
@@ -884,7 +886,12 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
884 | if (!wdev->current_bss) | 886 | if (!wdev->current_bss) |
885 | return -ENOLINK; | 887 | return -ENOLINK; |
886 | break; | 888 | break; |
887 | default: | 889 | case NL80211_IFTYPE_UNSPECIFIED: |
890 | case NL80211_IFTYPE_OCB: | ||
891 | case NL80211_IFTYPE_MONITOR: | ||
892 | case NL80211_IFTYPE_P2P_DEVICE: | ||
893 | case NL80211_IFTYPE_WDS: | ||
894 | case NUM_NL80211_IFTYPES: | ||
888 | return -EINVAL; | 895 | return -EINVAL; |
889 | } | 896 | } |
890 | 897 | ||
@@ -1083,6 +1090,8 @@ static int nl80211_send_wowlan(struct sk_buff *msg, | |||
1083 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) | 1090 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) |
1084 | return -ENOBUFS; | 1091 | return -ENOBUFS; |
1085 | 1092 | ||
1093 | /* TODO: send wowlan net detect */ | ||
1094 | |||
1086 | nla_nest_end(msg, nl_wowlan); | 1095 | nla_nest_end(msg, nl_wowlan); |
1087 | 1096 | ||
1088 | return 0; | 1097 | return 0; |
@@ -1514,8 +1523,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1514 | if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) | 1523 | if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) |
1515 | CMD(channel_switch, CHANNEL_SWITCH); | 1524 | CMD(channel_switch, CHANNEL_SWITCH); |
1516 | CMD(set_qos_map, SET_QOS_MAP); | 1525 | CMD(set_qos_map, SET_QOS_MAP); |
1517 | if (rdev->wiphy.flags & | 1526 | if (rdev->wiphy.features & |
1518 | WIPHY_FLAG_SUPPORTS_WMM_ADMISSION) | 1527 | NL80211_FEATURE_SUPPORTS_WMM_ADMISSION) |
1519 | CMD(add_tx_ts, ADD_TX_TS); | 1528 | CMD(add_tx_ts, ADD_TX_TS); |
1520 | } | 1529 | } |
1521 | /* add into the if now */ | 1530 | /* add into the if now */ |
@@ -2308,7 +2317,8 @@ static inline u64 wdev_id(struct wireless_dev *wdev) | |||
2308 | static int nl80211_send_chandef(struct sk_buff *msg, | 2317 | static int nl80211_send_chandef(struct sk_buff *msg, |
2309 | const struct cfg80211_chan_def *chandef) | 2318 | const struct cfg80211_chan_def *chandef) |
2310 | { | 2319 | { |
2311 | WARN_ON(!cfg80211_chandef_valid(chandef)); | 2320 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) |
2321 | return -EINVAL; | ||
2312 | 2322 | ||
2313 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | 2323 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, |
2314 | chandef->chan->center_freq)) | 2324 | chandef->chan->center_freq)) |
@@ -2336,12 +2346,16 @@ static int nl80211_send_chandef(struct sk_buff *msg, | |||
2336 | 2346 | ||
2337 | static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 2347 | static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, |
2338 | struct cfg80211_registered_device *rdev, | 2348 | struct cfg80211_registered_device *rdev, |
2339 | struct wireless_dev *wdev) | 2349 | struct wireless_dev *wdev, bool removal) |
2340 | { | 2350 | { |
2341 | struct net_device *dev = wdev->netdev; | 2351 | struct net_device *dev = wdev->netdev; |
2352 | u8 cmd = NL80211_CMD_NEW_INTERFACE; | ||
2342 | void *hdr; | 2353 | void *hdr; |
2343 | 2354 | ||
2344 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_INTERFACE); | 2355 | if (removal) |
2356 | cmd = NL80211_CMD_DEL_INTERFACE; | ||
2357 | |||
2358 | hdr = nl80211hdr_put(msg, portid, seq, flags, cmd); | ||
2345 | if (!hdr) | 2359 | if (!hdr) |
2346 | return -1; | 2360 | return -1; |
2347 | 2361 | ||
@@ -2408,7 +2422,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2408 | } | 2422 | } |
2409 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid, | 2423 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid, |
2410 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 2424 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
2411 | rdev, wdev) < 0) { | 2425 | rdev, wdev, false) < 0) { |
2412 | goto out; | 2426 | goto out; |
2413 | } | 2427 | } |
2414 | if_idx++; | 2428 | if_idx++; |
@@ -2436,7 +2450,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
2436 | return -ENOMEM; | 2450 | return -ENOMEM; |
2437 | 2451 | ||
2438 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, | 2452 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, |
2439 | rdev, wdev) < 0) { | 2453 | rdev, wdev, false) < 0) { |
2440 | nlmsg_free(msg); | 2454 | nlmsg_free(msg); |
2441 | return -ENOBUFS; | 2455 | return -ENOBUFS; |
2442 | } | 2456 | } |
@@ -2582,7 +2596,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2582 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2596 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2583 | struct vif_params params; | 2597 | struct vif_params params; |
2584 | struct wireless_dev *wdev; | 2598 | struct wireless_dev *wdev; |
2585 | struct sk_buff *msg; | 2599 | struct sk_buff *msg, *event; |
2586 | int err; | 2600 | int err; |
2587 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 2601 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
2588 | u32 flags; | 2602 | u32 flags; |
@@ -2605,7 +2619,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2605 | !(rdev->wiphy.interface_modes & (1 << type))) | 2619 | !(rdev->wiphy.interface_modes & (1 << type))) |
2606 | return -EOPNOTSUPP; | 2620 | return -EOPNOTSUPP; |
2607 | 2621 | ||
2608 | if (type == NL80211_IFTYPE_P2P_DEVICE && info->attrs[NL80211_ATTR_MAC]) { | 2622 | if ((type == NL80211_IFTYPE_P2P_DEVICE || |
2623 | rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) && | ||
2624 | info->attrs[NL80211_ATTR_MAC]) { | ||
2609 | nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC], | 2625 | nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC], |
2610 | ETH_ALEN); | 2626 | ETH_ALEN); |
2611 | if (!is_valid_ether_addr(params.macaddr)) | 2627 | if (!is_valid_ether_addr(params.macaddr)) |
@@ -2634,12 +2650,15 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2634 | wdev = rdev_add_virtual_intf(rdev, | 2650 | wdev = rdev_add_virtual_intf(rdev, |
2635 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 2651 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
2636 | type, err ? NULL : &flags, ¶ms); | 2652 | type, err ? NULL : &flags, ¶ms); |
2637 | if (IS_ERR(wdev)) { | 2653 | if (WARN_ON(!wdev)) { |
2654 | nlmsg_free(msg); | ||
2655 | return -EPROTO; | ||
2656 | } else if (IS_ERR(wdev)) { | ||
2638 | nlmsg_free(msg); | 2657 | nlmsg_free(msg); |
2639 | return PTR_ERR(wdev); | 2658 | return PTR_ERR(wdev); |
2640 | } | 2659 | } |
2641 | 2660 | ||
2642 | if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER]) | 2661 | if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) |
2643 | wdev->owner_nlportid = info->snd_portid; | 2662 | wdev->owner_nlportid = info->snd_portid; |
2644 | 2663 | ||
2645 | switch (type) { | 2664 | switch (type) { |
@@ -2675,11 +2694,25 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2675 | } | 2694 | } |
2676 | 2695 | ||
2677 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, | 2696 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, |
2678 | rdev, wdev) < 0) { | 2697 | rdev, wdev, false) < 0) { |
2679 | nlmsg_free(msg); | 2698 | nlmsg_free(msg); |
2680 | return -ENOBUFS; | 2699 | return -ENOBUFS; |
2681 | } | 2700 | } |
2682 | 2701 | ||
2702 | event = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2703 | if (event) { | ||
2704 | if (nl80211_send_iface(event, 0, 0, 0, | ||
2705 | rdev, wdev, false) < 0) { | ||
2706 | nlmsg_free(event); | ||
2707 | goto out; | ||
2708 | } | ||
2709 | |||
2710 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), | ||
2711 | event, 0, NL80211_MCGRP_CONFIG, | ||
2712 | GFP_KERNEL); | ||
2713 | } | ||
2714 | |||
2715 | out: | ||
2683 | return genlmsg_reply(msg, info); | 2716 | return genlmsg_reply(msg, info); |
2684 | } | 2717 | } |
2685 | 2718 | ||
@@ -2687,10 +2720,18 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
2687 | { | 2720 | { |
2688 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2721 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2689 | struct wireless_dev *wdev = info->user_ptr[1]; | 2722 | struct wireless_dev *wdev = info->user_ptr[1]; |
2723 | struct sk_buff *msg; | ||
2724 | int status; | ||
2690 | 2725 | ||
2691 | if (!rdev->ops->del_virtual_intf) | 2726 | if (!rdev->ops->del_virtual_intf) |
2692 | return -EOPNOTSUPP; | 2727 | return -EOPNOTSUPP; |
2693 | 2728 | ||
2729 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2730 | if (msg && nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, true) < 0) { | ||
2731 | nlmsg_free(msg); | ||
2732 | msg = NULL; | ||
2733 | } | ||
2734 | |||
2694 | /* | 2735 | /* |
2695 | * If we remove a wireless device without a netdev then clear | 2736 | * If we remove a wireless device without a netdev then clear |
2696 | * user_ptr[1] so that nl80211_post_doit won't dereference it | 2737 | * user_ptr[1] so that nl80211_post_doit won't dereference it |
@@ -2701,7 +2742,15 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
2701 | if (!wdev->netdev) | 2742 | if (!wdev->netdev) |
2702 | info->user_ptr[1] = NULL; | 2743 | info->user_ptr[1] = NULL; |
2703 | 2744 | ||
2704 | return rdev_del_virtual_intf(rdev, wdev); | 2745 | status = rdev_del_virtual_intf(rdev, wdev); |
2746 | if (status >= 0 && msg) | ||
2747 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), | ||
2748 | msg, 0, NL80211_MCGRP_CONFIG, | ||
2749 | GFP_KERNEL); | ||
2750 | else | ||
2751 | nlmsg_free(msg); | ||
2752 | |||
2753 | return status; | ||
2705 | } | 2754 | } |
2706 | 2755 | ||
2707 | static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) | 2756 | static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) |
@@ -4398,10 +4447,12 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
4398 | { | 4447 | { |
4399 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4448 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4400 | struct net_device *dev = info->user_ptr[1]; | 4449 | struct net_device *dev = info->user_ptr[1]; |
4401 | u8 *mac_addr = NULL; | 4450 | struct station_del_parameters params; |
4451 | |||
4452 | memset(¶ms, 0, sizeof(params)); | ||
4402 | 4453 | ||
4403 | if (info->attrs[NL80211_ATTR_MAC]) | 4454 | if (info->attrs[NL80211_ATTR_MAC]) |
4404 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 4455 | params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]); |
4405 | 4456 | ||
4406 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 4457 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4407 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 4458 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
@@ -4412,7 +4463,28 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
4412 | if (!rdev->ops->del_station) | 4463 | if (!rdev->ops->del_station) |
4413 | return -EOPNOTSUPP; | 4464 | return -EOPNOTSUPP; |
4414 | 4465 | ||
4415 | return rdev_del_station(rdev, dev, mac_addr); | 4466 | if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) { |
4467 | params.subtype = | ||
4468 | nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]); | ||
4469 | if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 && | ||
4470 | params.subtype != IEEE80211_STYPE_DEAUTH >> 4) | ||
4471 | return -EINVAL; | ||
4472 | } else { | ||
4473 | /* Default to Deauthentication frame */ | ||
4474 | params.subtype = IEEE80211_STYPE_DEAUTH >> 4; | ||
4475 | } | ||
4476 | |||
4477 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | ||
4478 | params.reason_code = | ||
4479 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | ||
4480 | if (params.reason_code == 0) | ||
4481 | return -EINVAL; /* 0 is reserved */ | ||
4482 | } else { | ||
4483 | /* Default to reason code 2 */ | ||
4484 | params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID; | ||
4485 | } | ||
4486 | |||
4487 | return rdev_del_station(rdev, dev, ¶ms); | ||
4416 | } | 4488 | } |
4417 | 4489 | ||
4418 | static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, | 4490 | static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, |
@@ -4423,7 +4495,7 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, | |||
4423 | void *hdr; | 4495 | void *hdr; |
4424 | struct nlattr *pinfoattr; | 4496 | struct nlattr *pinfoattr; |
4425 | 4497 | ||
4426 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_STATION); | 4498 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH); |
4427 | if (!hdr) | 4499 | if (!hdr) |
4428 | return -1; | 4500 | return -1; |
4429 | 4501 | ||
@@ -4624,6 +4696,96 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | |||
4624 | return rdev_del_mpath(rdev, dev, dst); | 4696 | return rdev_del_mpath(rdev, dev, dst); |
4625 | } | 4697 | } |
4626 | 4698 | ||
4699 | static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info) | ||
4700 | { | ||
4701 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4702 | int err; | ||
4703 | struct net_device *dev = info->user_ptr[1]; | ||
4704 | struct mpath_info pinfo; | ||
4705 | struct sk_buff *msg; | ||
4706 | u8 *dst = NULL; | ||
4707 | u8 mpp[ETH_ALEN]; | ||
4708 | |||
4709 | memset(&pinfo, 0, sizeof(pinfo)); | ||
4710 | |||
4711 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
4712 | return -EINVAL; | ||
4713 | |||
4714 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
4715 | |||
4716 | if (!rdev->ops->get_mpp) | ||
4717 | return -EOPNOTSUPP; | ||
4718 | |||
4719 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) | ||
4720 | return -EOPNOTSUPP; | ||
4721 | |||
4722 | err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo); | ||
4723 | if (err) | ||
4724 | return err; | ||
4725 | |||
4726 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
4727 | if (!msg) | ||
4728 | return -ENOMEM; | ||
4729 | |||
4730 | if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0, | ||
4731 | dev, dst, mpp, &pinfo) < 0) { | ||
4732 | nlmsg_free(msg); | ||
4733 | return -ENOBUFS; | ||
4734 | } | ||
4735 | |||
4736 | return genlmsg_reply(msg, info); | ||
4737 | } | ||
4738 | |||
4739 | static int nl80211_dump_mpp(struct sk_buff *skb, | ||
4740 | struct netlink_callback *cb) | ||
4741 | { | ||
4742 | struct mpath_info pinfo; | ||
4743 | struct cfg80211_registered_device *rdev; | ||
4744 | struct wireless_dev *wdev; | ||
4745 | u8 dst[ETH_ALEN]; | ||
4746 | u8 mpp[ETH_ALEN]; | ||
4747 | int path_idx = cb->args[2]; | ||
4748 | int err; | ||
4749 | |||
4750 | err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); | ||
4751 | if (err) | ||
4752 | return err; | ||
4753 | |||
4754 | if (!rdev->ops->dump_mpp) { | ||
4755 | err = -EOPNOTSUPP; | ||
4756 | goto out_err; | ||
4757 | } | ||
4758 | |||
4759 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
4760 | err = -EOPNOTSUPP; | ||
4761 | goto out_err; | ||
4762 | } | ||
4763 | |||
4764 | while (1) { | ||
4765 | err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst, | ||
4766 | mpp, &pinfo); | ||
4767 | if (err == -ENOENT) | ||
4768 | break; | ||
4769 | if (err) | ||
4770 | goto out_err; | ||
4771 | |||
4772 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid, | ||
4773 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
4774 | wdev->netdev, dst, mpp, | ||
4775 | &pinfo) < 0) | ||
4776 | goto out; | ||
4777 | |||
4778 | path_idx++; | ||
4779 | } | ||
4780 | |||
4781 | out: | ||
4782 | cb->args[2] = path_idx; | ||
4783 | err = skb->len; | ||
4784 | out_err: | ||
4785 | nl80211_finish_wdev_dump(rdev); | ||
4786 | return err; | ||
4787 | } | ||
4788 | |||
4627 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | 4789 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) |
4628 | { | 4790 | { |
4629 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4791 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -5260,11 +5422,11 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
5260 | { | 5422 | { |
5261 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; | 5423 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; |
5262 | struct nlattr *nl_reg_rule; | 5424 | struct nlattr *nl_reg_rule; |
5263 | char *alpha2 = NULL; | 5425 | char *alpha2; |
5264 | int rem_reg_rules = 0, r = 0; | 5426 | int rem_reg_rules, r; |
5265 | u32 num_rules = 0, rule_idx = 0, size_of_regd; | 5427 | u32 num_rules = 0, rule_idx = 0, size_of_regd; |
5266 | enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET; | 5428 | enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET; |
5267 | struct ieee80211_regdomain *rd = NULL; | 5429 | struct ieee80211_regdomain *rd; |
5268 | 5430 | ||
5269 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 5431 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
5270 | return -EINVAL; | 5432 | return -EINVAL; |
@@ -5358,6 +5520,43 @@ static int validate_scan_freqs(struct nlattr *freqs) | |||
5358 | return n_channels; | 5520 | return n_channels; |
5359 | } | 5521 | } |
5360 | 5522 | ||
5523 | static int nl80211_parse_random_mac(struct nlattr **attrs, | ||
5524 | u8 *mac_addr, u8 *mac_addr_mask) | ||
5525 | { | ||
5526 | int i; | ||
5527 | |||
5528 | if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) { | ||
5529 | memset(mac_addr, 0, ETH_ALEN); | ||
5530 | memset(mac_addr_mask, 0, ETH_ALEN); | ||
5531 | mac_addr[0] = 0x2; | ||
5532 | mac_addr_mask[0] = 0x3; | ||
5533 | |||
5534 | return 0; | ||
5535 | } | ||
5536 | |||
5537 | /* need both or none */ | ||
5538 | if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK]) | ||
5539 | return -EINVAL; | ||
5540 | |||
5541 | memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN); | ||
5542 | memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN); | ||
5543 | |||
5544 | /* don't allow or configure an mcast address */ | ||
5545 | if (!is_multicast_ether_addr(mac_addr_mask) || | ||
5546 | is_multicast_ether_addr(mac_addr)) | ||
5547 | return -EINVAL; | ||
5548 | |||
5549 | /* | ||
5550 | * allow users to pass a MAC address that has bits set outside | ||
5551 | * of the mask, but don't bother drivers with having to deal | ||
5552 | * with such bits | ||
5553 | */ | ||
5554 | for (i = 0; i < ETH_ALEN; i++) | ||
5555 | mac_addr[i] &= mac_addr_mask[i]; | ||
5556 | |||
5557 | return 0; | ||
5558 | } | ||
5559 | |||
5361 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 5560 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
5362 | { | 5561 | { |
5363 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5562 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -5535,6 +5734,25 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
5535 | err = -EOPNOTSUPP; | 5734 | err = -EOPNOTSUPP; |
5536 | goto out_free; | 5735 | goto out_free; |
5537 | } | 5736 | } |
5737 | |||
5738 | if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { | ||
5739 | if (!(wiphy->features & | ||
5740 | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)) { | ||
5741 | err = -EOPNOTSUPP; | ||
5742 | goto out_free; | ||
5743 | } | ||
5744 | |||
5745 | if (wdev->current_bss) { | ||
5746 | err = -EOPNOTSUPP; | ||
5747 | goto out_free; | ||
5748 | } | ||
5749 | |||
5750 | err = nl80211_parse_random_mac(info->attrs, | ||
5751 | request->mac_addr, | ||
5752 | request->mac_addr_mask); | ||
5753 | if (err) | ||
5754 | goto out_free; | ||
5755 | } | ||
5538 | } | 5756 | } |
5539 | 5757 | ||
5540 | request->no_cck = | 5758 | request->no_cck = |
@@ -5561,14 +5779,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
5561 | return err; | 5779 | return err; |
5562 | } | 5780 | } |
5563 | 5781 | ||
5564 | static int nl80211_start_sched_scan(struct sk_buff *skb, | 5782 | static struct cfg80211_sched_scan_request * |
5565 | struct genl_info *info) | 5783 | nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, |
5784 | struct nlattr **attrs) | ||
5566 | { | 5785 | { |
5567 | struct cfg80211_sched_scan_request *request; | 5786 | struct cfg80211_sched_scan_request *request; |
5568 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5569 | struct net_device *dev = info->user_ptr[1]; | ||
5570 | struct nlattr *attr; | 5787 | struct nlattr *attr; |
5571 | struct wiphy *wiphy; | ||
5572 | int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i; | 5788 | int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i; |
5573 | u32 interval; | 5789 | u32 interval; |
5574 | enum ieee80211_band band; | 5790 | enum ieee80211_band band; |
@@ -5576,38 +5792,32 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5576 | struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; | 5792 | struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; |
5577 | s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF; | 5793 | s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF; |
5578 | 5794 | ||
5579 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | 5795 | if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE])) |
5580 | !rdev->ops->sched_scan_start) | 5796 | return ERR_PTR(-EINVAL); |
5581 | return -EOPNOTSUPP; | ||
5582 | |||
5583 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
5584 | return -EINVAL; | ||
5585 | 5797 | ||
5586 | if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) | 5798 | if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) |
5587 | return -EINVAL; | 5799 | return ERR_PTR(-EINVAL); |
5588 | 5800 | ||
5589 | interval = nla_get_u32(info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]); | 5801 | interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]); |
5590 | if (interval == 0) | 5802 | if (interval == 0) |
5591 | return -EINVAL; | 5803 | return ERR_PTR(-EINVAL); |
5592 | |||
5593 | wiphy = &rdev->wiphy; | ||
5594 | 5804 | ||
5595 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 5805 | if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
5596 | n_channels = validate_scan_freqs( | 5806 | n_channels = validate_scan_freqs( |
5597 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); | 5807 | attrs[NL80211_ATTR_SCAN_FREQUENCIES]); |
5598 | if (!n_channels) | 5808 | if (!n_channels) |
5599 | return -EINVAL; | 5809 | return ERR_PTR(-EINVAL); |
5600 | } else { | 5810 | } else { |
5601 | n_channels = ieee80211_get_num_supported_channels(wiphy); | 5811 | n_channels = ieee80211_get_num_supported_channels(wiphy); |
5602 | } | 5812 | } |
5603 | 5813 | ||
5604 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) | 5814 | if (attrs[NL80211_ATTR_SCAN_SSIDS]) |
5605 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], | 5815 | nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS], |
5606 | tmp) | 5816 | tmp) |
5607 | n_ssids++; | 5817 | n_ssids++; |
5608 | 5818 | ||
5609 | if (n_ssids > wiphy->max_sched_scan_ssids) | 5819 | if (n_ssids > wiphy->max_sched_scan_ssids) |
5610 | return -EINVAL; | 5820 | return ERR_PTR(-EINVAL); |
5611 | 5821 | ||
5612 | /* | 5822 | /* |
5613 | * First, count the number of 'real' matchsets. Due to an issue with | 5823 | * First, count the number of 'real' matchsets. Due to an issue with |
@@ -5618,9 +5828,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5618 | * older userspace that treated a matchset with only the RSSI as the | 5828 | * older userspace that treated a matchset with only the RSSI as the |
5619 | * global RSSI for all other matchsets - if there are other matchsets. | 5829 | * global RSSI for all other matchsets - if there are other matchsets. |
5620 | */ | 5830 | */ |
5621 | if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { | 5831 | if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { |
5622 | nla_for_each_nested(attr, | 5832 | nla_for_each_nested(attr, |
5623 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], | 5833 | attrs[NL80211_ATTR_SCHED_SCAN_MATCH], |
5624 | tmp) { | 5834 | tmp) { |
5625 | struct nlattr *rssi; | 5835 | struct nlattr *rssi; |
5626 | 5836 | ||
@@ -5628,7 +5838,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5628 | nla_data(attr), nla_len(attr), | 5838 | nla_data(attr), nla_len(attr), |
5629 | nl80211_match_policy); | 5839 | nl80211_match_policy); |
5630 | if (err) | 5840 | if (err) |
5631 | return err; | 5841 | return ERR_PTR(err); |
5632 | /* add other standalone attributes here */ | 5842 | /* add other standalone attributes here */ |
5633 | if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) { | 5843 | if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) { |
5634 | n_match_sets++; | 5844 | n_match_sets++; |
@@ -5645,30 +5855,23 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5645 | n_match_sets = 1; | 5855 | n_match_sets = 1; |
5646 | 5856 | ||
5647 | if (n_match_sets > wiphy->max_match_sets) | 5857 | if (n_match_sets > wiphy->max_match_sets) |
5648 | return -EINVAL; | 5858 | return ERR_PTR(-EINVAL); |
5649 | 5859 | ||
5650 | if (info->attrs[NL80211_ATTR_IE]) | 5860 | if (attrs[NL80211_ATTR_IE]) |
5651 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 5861 | ie_len = nla_len(attrs[NL80211_ATTR_IE]); |
5652 | else | 5862 | else |
5653 | ie_len = 0; | 5863 | ie_len = 0; |
5654 | 5864 | ||
5655 | if (ie_len > wiphy->max_sched_scan_ie_len) | 5865 | if (ie_len > wiphy->max_sched_scan_ie_len) |
5656 | return -EINVAL; | 5866 | return ERR_PTR(-EINVAL); |
5657 | |||
5658 | if (rdev->sched_scan_req) { | ||
5659 | err = -EINPROGRESS; | ||
5660 | goto out; | ||
5661 | } | ||
5662 | 5867 | ||
5663 | request = kzalloc(sizeof(*request) | 5868 | request = kzalloc(sizeof(*request) |
5664 | + sizeof(*request->ssids) * n_ssids | 5869 | + sizeof(*request->ssids) * n_ssids |
5665 | + sizeof(*request->match_sets) * n_match_sets | 5870 | + sizeof(*request->match_sets) * n_match_sets |
5666 | + sizeof(*request->channels) * n_channels | 5871 | + sizeof(*request->channels) * n_channels |
5667 | + ie_len, GFP_KERNEL); | 5872 | + ie_len, GFP_KERNEL); |
5668 | if (!request) { | 5873 | if (!request) |
5669 | err = -ENOMEM; | 5874 | return ERR_PTR(-ENOMEM); |
5670 | goto out; | ||
5671 | } | ||
5672 | 5875 | ||
5673 | if (n_ssids) | 5876 | if (n_ssids) |
5674 | request->ssids = (void *)&request->channels[n_channels]; | 5877 | request->ssids = (void *)&request->channels[n_channels]; |
@@ -5693,10 +5896,10 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5693 | request->n_match_sets = n_match_sets; | 5896 | request->n_match_sets = n_match_sets; |
5694 | 5897 | ||
5695 | i = 0; | 5898 | i = 0; |
5696 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 5899 | if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
5697 | /* user specified, bail out if channel not found */ | 5900 | /* user specified, bail out if channel not found */ |
5698 | nla_for_each_nested(attr, | 5901 | nla_for_each_nested(attr, |
5699 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], | 5902 | attrs[NL80211_ATTR_SCAN_FREQUENCIES], |
5700 | tmp) { | 5903 | tmp) { |
5701 | struct ieee80211_channel *chan; | 5904 | struct ieee80211_channel *chan; |
5702 | 5905 | ||
@@ -5742,8 +5945,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5742 | request->n_channels = i; | 5945 | request->n_channels = i; |
5743 | 5946 | ||
5744 | i = 0; | 5947 | i = 0; |
5745 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { | 5948 | if (attrs[NL80211_ATTR_SCAN_SSIDS]) { |
5746 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], | 5949 | nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS], |
5747 | tmp) { | 5950 | tmp) { |
5748 | if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) { | 5951 | if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) { |
5749 | err = -EINVAL; | 5952 | err = -EINVAL; |
@@ -5757,9 +5960,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5757 | } | 5960 | } |
5758 | 5961 | ||
5759 | i = 0; | 5962 | i = 0; |
5760 | if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { | 5963 | if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { |
5761 | nla_for_each_nested(attr, | 5964 | nla_for_each_nested(attr, |
5762 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], | 5965 | attrs[NL80211_ATTR_SCHED_SCAN_MATCH], |
5763 | tmp) { | 5966 | tmp) { |
5764 | struct nlattr *ssid, *rssi; | 5967 | struct nlattr *ssid, *rssi; |
5765 | 5968 | ||
@@ -5814,36 +6017,88 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5814 | if (ie_len) { | 6017 | if (ie_len) { |
5815 | request->ie_len = ie_len; | 6018 | request->ie_len = ie_len; |
5816 | memcpy((void *)request->ie, | 6019 | memcpy((void *)request->ie, |
5817 | nla_data(info->attrs[NL80211_ATTR_IE]), | 6020 | nla_data(attrs[NL80211_ATTR_IE]), |
5818 | request->ie_len); | 6021 | request->ie_len); |
5819 | } | 6022 | } |
5820 | 6023 | ||
5821 | if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { | 6024 | if (attrs[NL80211_ATTR_SCAN_FLAGS]) { |
5822 | request->flags = nla_get_u32( | 6025 | request->flags = nla_get_u32( |
5823 | info->attrs[NL80211_ATTR_SCAN_FLAGS]); | 6026 | attrs[NL80211_ATTR_SCAN_FLAGS]); |
5824 | if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && | 6027 | if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && |
5825 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { | 6028 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { |
5826 | err = -EOPNOTSUPP; | 6029 | err = -EOPNOTSUPP; |
5827 | goto out_free; | 6030 | goto out_free; |
5828 | } | 6031 | } |
6032 | |||
6033 | if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { | ||
6034 | u32 flg = NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR; | ||
6035 | |||
6036 | if (!wdev) /* must be net-detect */ | ||
6037 | flg = NL80211_FEATURE_ND_RANDOM_MAC_ADDR; | ||
6038 | |||
6039 | if (!(wiphy->features & flg)) { | ||
6040 | err = -EOPNOTSUPP; | ||
6041 | goto out_free; | ||
6042 | } | ||
6043 | |||
6044 | if (wdev && wdev->current_bss) { | ||
6045 | err = -EOPNOTSUPP; | ||
6046 | goto out_free; | ||
6047 | } | ||
6048 | |||
6049 | err = nl80211_parse_random_mac(attrs, request->mac_addr, | ||
6050 | request->mac_addr_mask); | ||
6051 | if (err) | ||
6052 | goto out_free; | ||
6053 | } | ||
5829 | } | 6054 | } |
5830 | 6055 | ||
5831 | request->dev = dev; | ||
5832 | request->wiphy = &rdev->wiphy; | ||
5833 | request->interval = interval; | 6056 | request->interval = interval; |
5834 | request->scan_start = jiffies; | 6057 | request->scan_start = jiffies; |
5835 | 6058 | ||
5836 | err = rdev_sched_scan_start(rdev, dev, request); | 6059 | return request; |
5837 | if (!err) { | ||
5838 | rdev->sched_scan_req = request; | ||
5839 | nl80211_send_sched_scan(rdev, dev, | ||
5840 | NL80211_CMD_START_SCHED_SCAN); | ||
5841 | goto out; | ||
5842 | } | ||
5843 | 6060 | ||
5844 | out_free: | 6061 | out_free: |
5845 | kfree(request); | 6062 | kfree(request); |
5846 | out: | 6063 | return ERR_PTR(err); |
6064 | } | ||
6065 | |||
6066 | static int nl80211_start_sched_scan(struct sk_buff *skb, | ||
6067 | struct genl_info *info) | ||
6068 | { | ||
6069 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
6070 | struct net_device *dev = info->user_ptr[1]; | ||
6071 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
6072 | int err; | ||
6073 | |||
6074 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | ||
6075 | !rdev->ops->sched_scan_start) | ||
6076 | return -EOPNOTSUPP; | ||
6077 | |||
6078 | if (rdev->sched_scan_req) | ||
6079 | return -EINPROGRESS; | ||
6080 | |||
6081 | rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev, | ||
6082 | info->attrs); | ||
6083 | err = PTR_ERR_OR_ZERO(rdev->sched_scan_req); | ||
6084 | if (err) | ||
6085 | goto out_err; | ||
6086 | |||
6087 | err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req); | ||
6088 | if (err) | ||
6089 | goto out_free; | ||
6090 | |||
6091 | rdev->sched_scan_req->dev = dev; | ||
6092 | rdev->sched_scan_req->wiphy = &rdev->wiphy; | ||
6093 | |||
6094 | nl80211_send_sched_scan(rdev, dev, | ||
6095 | NL80211_CMD_START_SCHED_SCAN); | ||
6096 | return 0; | ||
6097 | |||
6098 | out_free: | ||
6099 | kfree(rdev->sched_scan_req); | ||
6100 | out_err: | ||
6101 | rdev->sched_scan_req = NULL; | ||
5847 | return err; | 6102 | return err; |
5848 | } | 6103 | } |
5849 | 6104 | ||
@@ -5923,10 +6178,10 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5923 | * function is called under RTNL lock, so this should not be a problem. | 6178 | * function is called under RTNL lock, so this should not be a problem. |
5924 | */ | 6179 | */ |
5925 | static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1]; | 6180 | static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1]; |
5926 | u8 radar_detect_width = 0; | ||
5927 | int err; | 6181 | int err; |
5928 | bool need_new_beacon = false; | 6182 | bool need_new_beacon = false; |
5929 | int len, i; | 6183 | int len, i; |
6184 | u32 cs_count; | ||
5930 | 6185 | ||
5931 | if (!rdev->ops->channel_switch || | 6186 | if (!rdev->ops->channel_switch || |
5932 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) | 6187 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) |
@@ -5963,7 +6218,14 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5963 | if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES]) | 6218 | if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES]) |
5964 | return -EINVAL; | 6219 | return -EINVAL; |
5965 | 6220 | ||
5966 | params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]); | 6221 | /* Even though the attribute is u32, the specification says |
6222 | * u8, so let's make sure we don't overflow. | ||
6223 | */ | ||
6224 | cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]); | ||
6225 | if (cs_count > 255) | ||
6226 | return -EINVAL; | ||
6227 | |||
6228 | params.count = cs_count; | ||
5967 | 6229 | ||
5968 | if (!need_new_beacon) | 6230 | if (!need_new_beacon) |
5969 | goto skip_beacons; | 6231 | goto skip_beacons; |
@@ -6051,10 +6313,8 @@ skip_beacons: | |||
6051 | if (err < 0) | 6313 | if (err < 0) |
6052 | return err; | 6314 | return err; |
6053 | 6315 | ||
6054 | if (err > 0) { | 6316 | if (err > 0) |
6055 | radar_detect_width = BIT(params.chandef.width); | ||
6056 | params.radar_required = true; | 6317 | params.radar_required = true; |
6057 | } | ||
6058 | 6318 | ||
6059 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) | 6319 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) |
6060 | params.block_tx = true; | 6320 | params.block_tx = true; |
@@ -6303,8 +6563,6 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
6303 | } | 6563 | } |
6304 | 6564 | ||
6305 | while (1) { | 6565 | while (1) { |
6306 | struct ieee80211_channel *chan; | ||
6307 | |||
6308 | res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey); | 6566 | res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey); |
6309 | if (res == -ENOENT) | 6567 | if (res == -ENOENT) |
6310 | break; | 6568 | break; |
@@ -6317,9 +6575,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
6317 | goto out; | 6575 | goto out; |
6318 | } | 6576 | } |
6319 | 6577 | ||
6320 | chan = ieee80211_get_channel(&rdev->wiphy, | 6578 | if (survey.channel->flags & IEEE80211_CHAN_DISABLED) { |
6321 | survey.channel->center_freq); | ||
6322 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { | ||
6323 | survey_idx++; | 6579 | survey_idx++; |
6324 | continue; | 6580 | continue; |
6325 | } | 6581 | } |
@@ -8151,6 +8407,28 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | |||
8151 | return -EINVAL; | 8407 | return -EINVAL; |
8152 | } | 8408 | } |
8153 | 8409 | ||
8410 | static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info) | ||
8411 | { | ||
8412 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8413 | struct net_device *dev = info->user_ptr[1]; | ||
8414 | struct ocb_setup setup = {}; | ||
8415 | int err; | ||
8416 | |||
8417 | err = nl80211_parse_chandef(rdev, info, &setup.chandef); | ||
8418 | if (err) | ||
8419 | return err; | ||
8420 | |||
8421 | return cfg80211_join_ocb(rdev, dev, &setup); | ||
8422 | } | ||
8423 | |||
8424 | static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info) | ||
8425 | { | ||
8426 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8427 | struct net_device *dev = info->user_ptr[1]; | ||
8428 | |||
8429 | return cfg80211_leave_ocb(rdev, dev); | ||
8430 | } | ||
8431 | |||
8154 | static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | 8432 | static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) |
8155 | { | 8433 | { |
8156 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 8434 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -8534,6 +8812,39 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | |||
8534 | return 0; | 8812 | return 0; |
8535 | } | 8813 | } |
8536 | 8814 | ||
8815 | static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev, | ||
8816 | const struct wiphy_wowlan_support *wowlan, | ||
8817 | struct nlattr *attr, | ||
8818 | struct cfg80211_wowlan *trig) | ||
8819 | { | ||
8820 | struct nlattr **tb; | ||
8821 | int err; | ||
8822 | |||
8823 | tb = kzalloc(NUM_NL80211_ATTR * sizeof(*tb), GFP_KERNEL); | ||
8824 | if (!tb) | ||
8825 | return -ENOMEM; | ||
8826 | |||
8827 | if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) { | ||
8828 | err = -EOPNOTSUPP; | ||
8829 | goto out; | ||
8830 | } | ||
8831 | |||
8832 | err = nla_parse(tb, NL80211_ATTR_MAX, | ||
8833 | nla_data(attr), nla_len(attr), | ||
8834 | nl80211_policy); | ||
8835 | if (err) | ||
8836 | goto out; | ||
8837 | |||
8838 | trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb); | ||
8839 | err = PTR_ERR_OR_ZERO(trig->nd_config); | ||
8840 | if (err) | ||
8841 | trig->nd_config = NULL; | ||
8842 | |||
8843 | out: | ||
8844 | kfree(tb); | ||
8845 | return err; | ||
8846 | } | ||
8847 | |||
8537 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | 8848 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) |
8538 | { | 8849 | { |
8539 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 8850 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -8679,6 +8990,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
8679 | goto error; | 8990 | goto error; |
8680 | } | 8991 | } |
8681 | 8992 | ||
8993 | if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) { | ||
8994 | err = nl80211_parse_wowlan_nd( | ||
8995 | rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT], | ||
8996 | &new_triggers); | ||
8997 | if (err) | ||
8998 | goto error; | ||
8999 | } | ||
9000 | |||
8682 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); | 9001 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
8683 | if (!ntrig) { | 9002 | if (!ntrig) { |
8684 | err = -ENOMEM; | 9003 | err = -ENOMEM; |
@@ -9436,7 +9755,7 @@ static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info) | |||
9436 | u16 admitted_time = 0; | 9755 | u16 admitted_time = 0; |
9437 | int err; | 9756 | int err; |
9438 | 9757 | ||
9439 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)) | 9758 | if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)) |
9440 | return -EOPNOTSUPP; | 9759 | return -EOPNOTSUPP; |
9441 | 9760 | ||
9442 | if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] || | 9761 | if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] || |
@@ -9452,12 +9771,10 @@ static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info) | |||
9452 | return -EINVAL; | 9771 | return -EINVAL; |
9453 | 9772 | ||
9454 | /* WMM uses TIDs 0-7 even for TSPEC */ | 9773 | /* WMM uses TIDs 0-7 even for TSPEC */ |
9455 | if (tsid < IEEE80211_FIRST_TSPEC_TSID) { | 9774 | if (tsid >= IEEE80211_FIRST_TSPEC_TSID) { |
9456 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)) | ||
9457 | return -EINVAL; | ||
9458 | } else { | ||
9459 | /* TODO: handle 802.11 TSPEC/admission control | 9775 | /* TODO: handle 802.11 TSPEC/admission control |
9460 | * need more attributes for that (e.g. BA session requirement) | 9776 | * need more attributes for that (e.g. BA session requirement); |
9777 | * change the WMM adminssion test above to allow both then | ||
9461 | */ | 9778 | */ |
9462 | return -EINVAL; | 9779 | return -EINVAL; |
9463 | } | 9780 | } |
@@ -9513,6 +9830,98 @@ static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info) | |||
9513 | return err; | 9830 | return err; |
9514 | } | 9831 | } |
9515 | 9832 | ||
9833 | static int nl80211_tdls_channel_switch(struct sk_buff *skb, | ||
9834 | struct genl_info *info) | ||
9835 | { | ||
9836 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
9837 | struct net_device *dev = info->user_ptr[1]; | ||
9838 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
9839 | struct cfg80211_chan_def chandef = {}; | ||
9840 | const u8 *addr; | ||
9841 | u8 oper_class; | ||
9842 | int err; | ||
9843 | |||
9844 | if (!rdev->ops->tdls_channel_switch || | ||
9845 | !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)) | ||
9846 | return -EOPNOTSUPP; | ||
9847 | |||
9848 | switch (dev->ieee80211_ptr->iftype) { | ||
9849 | case NL80211_IFTYPE_STATION: | ||
9850 | case NL80211_IFTYPE_P2P_CLIENT: | ||
9851 | break; | ||
9852 | default: | ||
9853 | return -EOPNOTSUPP; | ||
9854 | } | ||
9855 | |||
9856 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
9857 | !info->attrs[NL80211_ATTR_OPER_CLASS]) | ||
9858 | return -EINVAL; | ||
9859 | |||
9860 | err = nl80211_parse_chandef(rdev, info, &chandef); | ||
9861 | if (err) | ||
9862 | return err; | ||
9863 | |||
9864 | /* | ||
9865 | * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012 | ||
9866 | * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the | ||
9867 | * specification is not defined for them. | ||
9868 | */ | ||
9869 | if (chandef.chan->band == IEEE80211_BAND_2GHZ && | ||
9870 | chandef.width != NL80211_CHAN_WIDTH_20_NOHT && | ||
9871 | chandef.width != NL80211_CHAN_WIDTH_20) | ||
9872 | return -EINVAL; | ||
9873 | |||
9874 | /* we will be active on the TDLS link */ | ||
9875 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, wdev->iftype)) | ||
9876 | return -EINVAL; | ||
9877 | |||
9878 | /* don't allow switching to DFS channels */ | ||
9879 | if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype)) | ||
9880 | return -EINVAL; | ||
9881 | |||
9882 | addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
9883 | oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]); | ||
9884 | |||
9885 | wdev_lock(wdev); | ||
9886 | err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef); | ||
9887 | wdev_unlock(wdev); | ||
9888 | |||
9889 | return err; | ||
9890 | } | ||
9891 | |||
9892 | static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb, | ||
9893 | struct genl_info *info) | ||
9894 | { | ||
9895 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
9896 | struct net_device *dev = info->user_ptr[1]; | ||
9897 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
9898 | const u8 *addr; | ||
9899 | |||
9900 | if (!rdev->ops->tdls_channel_switch || | ||
9901 | !rdev->ops->tdls_cancel_channel_switch || | ||
9902 | !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)) | ||
9903 | return -EOPNOTSUPP; | ||
9904 | |||
9905 | switch (dev->ieee80211_ptr->iftype) { | ||
9906 | case NL80211_IFTYPE_STATION: | ||
9907 | case NL80211_IFTYPE_P2P_CLIENT: | ||
9908 | break; | ||
9909 | default: | ||
9910 | return -EOPNOTSUPP; | ||
9911 | } | ||
9912 | |||
9913 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
9914 | return -EINVAL; | ||
9915 | |||
9916 | addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
9917 | |||
9918 | wdev_lock(wdev); | ||
9919 | rdev_tdls_cancel_channel_switch(rdev, dev, addr); | ||
9920 | wdev_unlock(wdev); | ||
9921 | |||
9922 | return 0; | ||
9923 | } | ||
9924 | |||
9516 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 9925 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
9517 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 9926 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
9518 | #define NL80211_FLAG_NEED_RTNL 0x04 | 9927 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -9774,6 +10183,15 @@ static const struct genl_ops nl80211_ops[] = { | |||
9774 | NL80211_FLAG_NEED_RTNL, | 10183 | NL80211_FLAG_NEED_RTNL, |
9775 | }, | 10184 | }, |
9776 | { | 10185 | { |
10186 | .cmd = NL80211_CMD_GET_MPP, | ||
10187 | .doit = nl80211_get_mpp, | ||
10188 | .dumpit = nl80211_dump_mpp, | ||
10189 | .policy = nl80211_policy, | ||
10190 | .flags = GENL_ADMIN_PERM, | ||
10191 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
10192 | NL80211_FLAG_NEED_RTNL, | ||
10193 | }, | ||
10194 | { | ||
9777 | .cmd = NL80211_CMD_SET_MPATH, | 10195 | .cmd = NL80211_CMD_SET_MPATH, |
9778 | .doit = nl80211_set_mpath, | 10196 | .doit = nl80211_set_mpath, |
9779 | .policy = nl80211_policy, | 10197 | .policy = nl80211_policy, |
@@ -10087,6 +10505,22 @@ static const struct genl_ops nl80211_ops[] = { | |||
10087 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 10505 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
10088 | NL80211_FLAG_NEED_RTNL, | 10506 | NL80211_FLAG_NEED_RTNL, |
10089 | }, | 10507 | }, |
10508 | { | ||
10509 | .cmd = NL80211_CMD_JOIN_OCB, | ||
10510 | .doit = nl80211_join_ocb, | ||
10511 | .policy = nl80211_policy, | ||
10512 | .flags = GENL_ADMIN_PERM, | ||
10513 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
10514 | NL80211_FLAG_NEED_RTNL, | ||
10515 | }, | ||
10516 | { | ||
10517 | .cmd = NL80211_CMD_LEAVE_OCB, | ||
10518 | .doit = nl80211_leave_ocb, | ||
10519 | .policy = nl80211_policy, | ||
10520 | .flags = GENL_ADMIN_PERM, | ||
10521 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
10522 | NL80211_FLAG_NEED_RTNL, | ||
10523 | }, | ||
10090 | #ifdef CONFIG_PM | 10524 | #ifdef CONFIG_PM |
10091 | { | 10525 | { |
10092 | .cmd = NL80211_CMD_GET_WOWLAN, | 10526 | .cmd = NL80211_CMD_GET_WOWLAN, |
@@ -10286,6 +10720,22 @@ static const struct genl_ops nl80211_ops[] = { | |||
10286 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 10720 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
10287 | NL80211_FLAG_NEED_RTNL, | 10721 | NL80211_FLAG_NEED_RTNL, |
10288 | }, | 10722 | }, |
10723 | { | ||
10724 | .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH, | ||
10725 | .doit = nl80211_tdls_channel_switch, | ||
10726 | .policy = nl80211_policy, | ||
10727 | .flags = GENL_ADMIN_PERM, | ||
10728 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
10729 | NL80211_FLAG_NEED_RTNL, | ||
10730 | }, | ||
10731 | { | ||
10732 | .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH, | ||
10733 | .doit = nl80211_tdls_cancel_channel_switch, | ||
10734 | .policy = nl80211_policy, | ||
10735 | .flags = GENL_ADMIN_PERM, | ||
10736 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
10737 | NL80211_FLAG_NEED_RTNL, | ||
10738 | }, | ||
10289 | }; | 10739 | }; |
10290 | 10740 | ||
10291 | /* notification functions */ | 10741 | /* notification functions */ |
@@ -11317,55 +11767,155 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, | |||
11317 | } | 11767 | } |
11318 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); | 11768 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); |
11319 | 11769 | ||
11320 | void cfg80211_cqm_rssi_notify(struct net_device *dev, | 11770 | static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev, |
11321 | enum nl80211_cqm_rssi_threshold_event rssi_event, | 11771 | const char *mac, gfp_t gfp) |
11322 | gfp_t gfp) | ||
11323 | { | 11772 | { |
11324 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 11773 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
11325 | struct wiphy *wiphy = wdev->wiphy; | 11774 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
11326 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 11775 | struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
11327 | struct sk_buff *msg; | 11776 | void **cb; |
11328 | struct nlattr *pinfoattr; | ||
11329 | void *hdr; | ||
11330 | |||
11331 | trace_cfg80211_cqm_rssi_notify(dev, rssi_event); | ||
11332 | 11777 | ||
11333 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
11334 | if (!msg) | 11778 | if (!msg) |
11335 | return; | 11779 | return NULL; |
11336 | 11780 | ||
11337 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | 11781 | cb = (void **)msg->cb; |
11338 | if (!hdr) { | 11782 | |
11783 | cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | ||
11784 | if (!cb[0]) { | ||
11339 | nlmsg_free(msg); | 11785 | nlmsg_free(msg); |
11340 | return; | 11786 | return NULL; |
11341 | } | 11787 | } |
11342 | 11788 | ||
11343 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 11789 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
11344 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) | 11790 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) |
11345 | goto nla_put_failure; | 11791 | goto nla_put_failure; |
11346 | 11792 | ||
11347 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | 11793 | if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac)) |
11348 | if (!pinfoattr) | ||
11349 | goto nla_put_failure; | 11794 | goto nla_put_failure; |
11350 | 11795 | ||
11351 | if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, | 11796 | cb[1] = nla_nest_start(msg, NL80211_ATTR_CQM); |
11352 | rssi_event)) | 11797 | if (!cb[1]) |
11353 | goto nla_put_failure; | 11798 | goto nla_put_failure; |
11354 | 11799 | ||
11355 | nla_nest_end(msg, pinfoattr); | 11800 | cb[2] = rdev; |
11356 | 11801 | ||
11357 | genlmsg_end(msg, hdr); | 11802 | return msg; |
11803 | nla_put_failure: | ||
11804 | nlmsg_free(msg); | ||
11805 | return NULL; | ||
11806 | } | ||
11807 | |||
11808 | static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp) | ||
11809 | { | ||
11810 | void **cb = (void **)msg->cb; | ||
11811 | struct cfg80211_registered_device *rdev = cb[2]; | ||
11812 | |||
11813 | nla_nest_end(msg, cb[1]); | ||
11814 | genlmsg_end(msg, cb[0]); | ||
11815 | |||
11816 | memset(msg->cb, 0, sizeof(msg->cb)); | ||
11358 | 11817 | ||
11359 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | 11818 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, |
11360 | NL80211_MCGRP_MLME, gfp); | 11819 | NL80211_MCGRP_MLME, gfp); |
11820 | } | ||
11821 | |||
11822 | void cfg80211_cqm_rssi_notify(struct net_device *dev, | ||
11823 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
11824 | gfp_t gfp) | ||
11825 | { | ||
11826 | struct sk_buff *msg; | ||
11827 | |||
11828 | trace_cfg80211_cqm_rssi_notify(dev, rssi_event); | ||
11829 | |||
11830 | if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW && | ||
11831 | rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH)) | ||
11832 | return; | ||
11833 | |||
11834 | msg = cfg80211_prepare_cqm(dev, NULL, gfp); | ||
11835 | if (!msg) | ||
11836 | return; | ||
11837 | |||
11838 | if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, | ||
11839 | rssi_event)) | ||
11840 | goto nla_put_failure; | ||
11841 | |||
11842 | cfg80211_send_cqm(msg, gfp); | ||
11843 | |||
11361 | return; | 11844 | return; |
11362 | 11845 | ||
11363 | nla_put_failure: | 11846 | nla_put_failure: |
11364 | genlmsg_cancel(msg, hdr); | ||
11365 | nlmsg_free(msg); | 11847 | nlmsg_free(msg); |
11366 | } | 11848 | } |
11367 | EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); | 11849 | EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); |
11368 | 11850 | ||
11851 | void cfg80211_cqm_txe_notify(struct net_device *dev, | ||
11852 | const u8 *peer, u32 num_packets, | ||
11853 | u32 rate, u32 intvl, gfp_t gfp) | ||
11854 | { | ||
11855 | struct sk_buff *msg; | ||
11856 | |||
11857 | msg = cfg80211_prepare_cqm(dev, peer, gfp); | ||
11858 | if (!msg) | ||
11859 | return; | ||
11860 | |||
11861 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets)) | ||
11862 | goto nla_put_failure; | ||
11863 | |||
11864 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate)) | ||
11865 | goto nla_put_failure; | ||
11866 | |||
11867 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl)) | ||
11868 | goto nla_put_failure; | ||
11869 | |||
11870 | cfg80211_send_cqm(msg, gfp); | ||
11871 | return; | ||
11872 | |||
11873 | nla_put_failure: | ||
11874 | nlmsg_free(msg); | ||
11875 | } | ||
11876 | EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | ||
11877 | |||
11878 | void cfg80211_cqm_pktloss_notify(struct net_device *dev, | ||
11879 | const u8 *peer, u32 num_packets, gfp_t gfp) | ||
11880 | { | ||
11881 | struct sk_buff *msg; | ||
11882 | |||
11883 | trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets); | ||
11884 | |||
11885 | msg = cfg80211_prepare_cqm(dev, peer, gfp); | ||
11886 | if (!msg) | ||
11887 | return; | ||
11888 | |||
11889 | if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets)) | ||
11890 | goto nla_put_failure; | ||
11891 | |||
11892 | cfg80211_send_cqm(msg, gfp); | ||
11893 | return; | ||
11894 | |||
11895 | nla_put_failure: | ||
11896 | nlmsg_free(msg); | ||
11897 | } | ||
11898 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); | ||
11899 | |||
11900 | void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp) | ||
11901 | { | ||
11902 | struct sk_buff *msg; | ||
11903 | |||
11904 | msg = cfg80211_prepare_cqm(dev, NULL, gfp); | ||
11905 | if (!msg) | ||
11906 | return; | ||
11907 | |||
11908 | if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT)) | ||
11909 | goto nla_put_failure; | ||
11910 | |||
11911 | cfg80211_send_cqm(msg, gfp); | ||
11912 | return; | ||
11913 | |||
11914 | nla_put_failure: | ||
11915 | nlmsg_free(msg); | ||
11916 | } | ||
11917 | EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify); | ||
11918 | |||
11369 | static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | 11919 | static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, |
11370 | struct net_device *netdev, const u8 *bssid, | 11920 | struct net_device *netdev, const u8 *bssid, |
11371 | const u8 *replay_ctr, gfp_t gfp) | 11921 | const u8 *replay_ctr, gfp_t gfp) |
@@ -11483,7 +12033,9 @@ EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | |||
11483 | static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | 12033 | static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, |
11484 | struct net_device *netdev, | 12034 | struct net_device *netdev, |
11485 | struct cfg80211_chan_def *chandef, | 12035 | struct cfg80211_chan_def *chandef, |
11486 | gfp_t gfp) | 12036 | gfp_t gfp, |
12037 | enum nl80211_commands notif, | ||
12038 | u8 count) | ||
11487 | { | 12039 | { |
11488 | struct sk_buff *msg; | 12040 | struct sk_buff *msg; |
11489 | void *hdr; | 12041 | void *hdr; |
@@ -11492,7 +12044,7 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
11492 | if (!msg) | 12044 | if (!msg) |
11493 | return; | 12045 | return; |
11494 | 12046 | ||
11495 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CH_SWITCH_NOTIFY); | 12047 | hdr = nl80211hdr_put(msg, 0, 0, 0, notif); |
11496 | if (!hdr) { | 12048 | if (!hdr) { |
11497 | nlmsg_free(msg); | 12049 | nlmsg_free(msg); |
11498 | return; | 12050 | return; |
@@ -11504,6 +12056,10 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
11504 | if (nl80211_send_chandef(msg, chandef)) | 12056 | if (nl80211_send_chandef(msg, chandef)) |
11505 | goto nla_put_failure; | 12057 | goto nla_put_failure; |
11506 | 12058 | ||
12059 | if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) && | ||
12060 | (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count))) | ||
12061 | goto nla_put_failure; | ||
12062 | |||
11507 | genlmsg_end(msg, hdr); | 12063 | genlmsg_end(msg, hdr); |
11508 | 12064 | ||
11509 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | 12065 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, |
@@ -11526,70 +12082,27 @@ void cfg80211_ch_switch_notify(struct net_device *dev, | |||
11526 | 12082 | ||
11527 | trace_cfg80211_ch_switch_notify(dev, chandef); | 12083 | trace_cfg80211_ch_switch_notify(dev, chandef); |
11528 | 12084 | ||
11529 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
11530 | wdev->iftype != NL80211_IFTYPE_P2P_GO && | ||
11531 | wdev->iftype != NL80211_IFTYPE_ADHOC && | ||
11532 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | ||
11533 | return; | ||
11534 | |||
11535 | wdev->chandef = *chandef; | 12085 | wdev->chandef = *chandef; |
11536 | wdev->preset_chandef = *chandef; | 12086 | wdev->preset_chandef = *chandef; |
11537 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | 12087 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL, |
12088 | NL80211_CMD_CH_SWITCH_NOTIFY, 0); | ||
11538 | } | 12089 | } |
11539 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | 12090 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); |
11540 | 12091 | ||
11541 | void cfg80211_cqm_txe_notify(struct net_device *dev, | 12092 | void cfg80211_ch_switch_started_notify(struct net_device *dev, |
11542 | const u8 *peer, u32 num_packets, | 12093 | struct cfg80211_chan_def *chandef, |
11543 | u32 rate, u32 intvl, gfp_t gfp) | 12094 | u8 count) |
11544 | { | 12095 | { |
11545 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 12096 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
11546 | struct wiphy *wiphy = wdev->wiphy; | 12097 | struct wiphy *wiphy = wdev->wiphy; |
11547 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 12098 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
11548 | struct sk_buff *msg; | ||
11549 | struct nlattr *pinfoattr; | ||
11550 | void *hdr; | ||
11551 | |||
11552 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
11553 | if (!msg) | ||
11554 | return; | ||
11555 | |||
11556 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | ||
11557 | if (!hdr) { | ||
11558 | nlmsg_free(msg); | ||
11559 | return; | ||
11560 | } | ||
11561 | |||
11562 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
11563 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | ||
11564 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | ||
11565 | goto nla_put_failure; | ||
11566 | |||
11567 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | ||
11568 | if (!pinfoattr) | ||
11569 | goto nla_put_failure; | ||
11570 | |||
11571 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets)) | ||
11572 | goto nla_put_failure; | ||
11573 | |||
11574 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate)) | ||
11575 | goto nla_put_failure; | ||
11576 | 12099 | ||
11577 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl)) | 12100 | trace_cfg80211_ch_switch_started_notify(dev, chandef); |
11578 | goto nla_put_failure; | ||
11579 | 12101 | ||
11580 | nla_nest_end(msg, pinfoattr); | 12102 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL, |
11581 | 12103 | NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count); | |
11582 | genlmsg_end(msg, hdr); | ||
11583 | |||
11584 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | ||
11585 | NL80211_MCGRP_MLME, gfp); | ||
11586 | return; | ||
11587 | |||
11588 | nla_put_failure: | ||
11589 | genlmsg_cancel(msg, hdr); | ||
11590 | nlmsg_free(msg); | ||
11591 | } | 12104 | } |
11592 | EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | 12105 | EXPORT_SYMBOL(cfg80211_ch_switch_started_notify); |
11593 | 12106 | ||
11594 | void | 12107 | void |
11595 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | 12108 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, |
@@ -11639,54 +12152,6 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, | |||
11639 | nlmsg_free(msg); | 12152 | nlmsg_free(msg); |
11640 | } | 12153 | } |
11641 | 12154 | ||
11642 | void cfg80211_cqm_pktloss_notify(struct net_device *dev, | ||
11643 | const u8 *peer, u32 num_packets, gfp_t gfp) | ||
11644 | { | ||
11645 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
11646 | struct wiphy *wiphy = wdev->wiphy; | ||
11647 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
11648 | struct sk_buff *msg; | ||
11649 | struct nlattr *pinfoattr; | ||
11650 | void *hdr; | ||
11651 | |||
11652 | trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets); | ||
11653 | |||
11654 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
11655 | if (!msg) | ||
11656 | return; | ||
11657 | |||
11658 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | ||
11659 | if (!hdr) { | ||
11660 | nlmsg_free(msg); | ||
11661 | return; | ||
11662 | } | ||
11663 | |||
11664 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
11665 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | ||
11666 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | ||
11667 | goto nla_put_failure; | ||
11668 | |||
11669 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | ||
11670 | if (!pinfoattr) | ||
11671 | goto nla_put_failure; | ||
11672 | |||
11673 | if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets)) | ||
11674 | goto nla_put_failure; | ||
11675 | |||
11676 | nla_nest_end(msg, pinfoattr); | ||
11677 | |||
11678 | genlmsg_end(msg, hdr); | ||
11679 | |||
11680 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | ||
11681 | NL80211_MCGRP_MLME, gfp); | ||
11682 | return; | ||
11683 | |||
11684 | nla_put_failure: | ||
11685 | genlmsg_cancel(msg, hdr); | ||
11686 | nlmsg_free(msg); | ||
11687 | } | ||
11688 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); | ||
11689 | |||
11690 | void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | 12155 | void cfg80211_probe_status(struct net_device *dev, const u8 *addr, |
11691 | u64 cookie, bool acked, gfp_t gfp) | 12156 | u64 cookie, bool acked, gfp_t gfp) |
11692 | { | 12157 | { |
@@ -11774,6 +12239,67 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, | |||
11774 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); | 12239 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); |
11775 | 12240 | ||
11776 | #ifdef CONFIG_PM | 12241 | #ifdef CONFIG_PM |
12242 | static int cfg80211_net_detect_results(struct sk_buff *msg, | ||
12243 | struct cfg80211_wowlan_wakeup *wakeup) | ||
12244 | { | ||
12245 | struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect; | ||
12246 | struct nlattr *nl_results, *nl_match, *nl_freqs; | ||
12247 | int i, j; | ||
12248 | |||
12249 | nl_results = nla_nest_start( | ||
12250 | msg, NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS); | ||
12251 | if (!nl_results) | ||
12252 | return -EMSGSIZE; | ||
12253 | |||
12254 | for (i = 0; i < nd->n_matches; i++) { | ||
12255 | struct cfg80211_wowlan_nd_match *match = nd->matches[i]; | ||
12256 | |||
12257 | nl_match = nla_nest_start(msg, i); | ||
12258 | if (!nl_match) | ||
12259 | break; | ||
12260 | |||
12261 | /* The SSID attribute is optional in nl80211, but for | ||
12262 | * simplicity reasons it's always present in the | ||
12263 | * cfg80211 structure. If a driver can't pass the | ||
12264 | * SSID, that needs to be changed. A zero length SSID | ||
12265 | * is still a valid SSID (wildcard), so it cannot be | ||
12266 | * used for this purpose. | ||
12267 | */ | ||
12268 | if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len, | ||
12269 | match->ssid.ssid)) { | ||
12270 | nla_nest_cancel(msg, nl_match); | ||
12271 | goto out; | ||
12272 | } | ||
12273 | |||
12274 | if (match->n_channels) { | ||
12275 | nl_freqs = nla_nest_start( | ||
12276 | msg, NL80211_ATTR_SCAN_FREQUENCIES); | ||
12277 | if (!nl_freqs) { | ||
12278 | nla_nest_cancel(msg, nl_match); | ||
12279 | goto out; | ||
12280 | } | ||
12281 | |||
12282 | for (j = 0; j < match->n_channels; j++) { | ||
12283 | if (nla_put_u32(msg, | ||
12284 | NL80211_ATTR_WIPHY_FREQ, | ||
12285 | match->channels[j])) { | ||
12286 | nla_nest_cancel(msg, nl_freqs); | ||
12287 | nla_nest_cancel(msg, nl_match); | ||
12288 | goto out; | ||
12289 | } | ||
12290 | } | ||
12291 | |||
12292 | nla_nest_end(msg, nl_freqs); | ||
12293 | } | ||
12294 | |||
12295 | nla_nest_end(msg, nl_match); | ||
12296 | } | ||
12297 | |||
12298 | out: | ||
12299 | nla_nest_end(msg, nl_results); | ||
12300 | return 0; | ||
12301 | } | ||
12302 | |||
11777 | void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | 12303 | void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, |
11778 | struct cfg80211_wowlan_wakeup *wakeup, | 12304 | struct cfg80211_wowlan_wakeup *wakeup, |
11779 | gfp_t gfp) | 12305 | gfp_t gfp) |
@@ -11868,6 +12394,10 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | |||
11868 | goto free_msg; | 12394 | goto free_msg; |
11869 | } | 12395 | } |
11870 | 12396 | ||
12397 | if (wakeup->net_detect && | ||
12398 | cfg80211_net_detect_results(msg, wakeup)) | ||
12399 | goto free_msg; | ||
12400 | |||
11871 | nla_nest_end(msg, reasons); | 12401 | nla_nest_end(msg, reasons); |
11872 | } | 12402 | } |
11873 | 12403 | ||
diff --git a/net/wireless/ocb.c b/net/wireless/ocb.c new file mode 100644 index 000000000000..c00d4a792319 --- /dev/null +++ b/net/wireless/ocb.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * OCB mode implementation | ||
3 | * | ||
4 | * Copyright: (c) 2014 Czech Technical University in Prague | ||
5 | * (c) 2014 Volkswagen Group Research | ||
6 | * Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz> | ||
7 | * Funded by: Volkswagen Group Research | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/ieee80211.h> | ||
15 | #include <net/cfg80211.h> | ||
16 | #include "nl80211.h" | ||
17 | #include "core.h" | ||
18 | #include "rdev-ops.h" | ||
19 | |||
20 | int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev, | ||
21 | struct net_device *dev, | ||
22 | struct ocb_setup *setup) | ||
23 | { | ||
24 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
25 | int err; | ||
26 | |||
27 | ASSERT_WDEV_LOCK(wdev); | ||
28 | |||
29 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB) | ||
30 | return -EOPNOTSUPP; | ||
31 | |||
32 | if (WARN_ON(!setup->chandef.chan)) | ||
33 | return -EINVAL; | ||
34 | |||
35 | err = rdev_join_ocb(rdev, dev, setup); | ||
36 | if (!err) | ||
37 | wdev->chandef = setup->chandef; | ||
38 | |||
39 | return err; | ||
40 | } | ||
41 | |||
42 | int cfg80211_join_ocb(struct cfg80211_registered_device *rdev, | ||
43 | struct net_device *dev, | ||
44 | struct ocb_setup *setup) | ||
45 | { | ||
46 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
47 | int err; | ||
48 | |||
49 | wdev_lock(wdev); | ||
50 | err = __cfg80211_join_ocb(rdev, dev, setup); | ||
51 | wdev_unlock(wdev); | ||
52 | |||
53 | return err; | ||
54 | } | ||
55 | |||
56 | int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, | ||
57 | struct net_device *dev) | ||
58 | { | ||
59 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
60 | int err; | ||
61 | |||
62 | ASSERT_WDEV_LOCK(wdev); | ||
63 | |||
64 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB) | ||
65 | return -EOPNOTSUPP; | ||
66 | |||
67 | if (!rdev->ops->leave_ocb) | ||
68 | return -EOPNOTSUPP; | ||
69 | |||
70 | err = rdev_leave_ocb(rdev, dev); | ||
71 | if (!err) | ||
72 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); | ||
73 | |||
74 | return err; | ||
75 | } | ||
76 | |||
77 | int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, | ||
78 | struct net_device *dev) | ||
79 | { | ||
80 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
81 | int err; | ||
82 | |||
83 | wdev_lock(wdev); | ||
84 | err = __cfg80211_leave_ocb(rdev, dev); | ||
85 | wdev_unlock(wdev); | ||
86 | |||
87 | return err; | ||
88 | } | ||
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index f6d457d6a558..35cfb7134bdb 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -178,11 +178,12 @@ static inline int rdev_add_station(struct cfg80211_registered_device *rdev, | |||
178 | } | 178 | } |
179 | 179 | ||
180 | static inline int rdev_del_station(struct cfg80211_registered_device *rdev, | 180 | static inline int rdev_del_station(struct cfg80211_registered_device *rdev, |
181 | struct net_device *dev, u8 *mac) | 181 | struct net_device *dev, |
182 | struct station_del_parameters *params) | ||
182 | { | 183 | { |
183 | int ret; | 184 | int ret; |
184 | trace_rdev_del_station(&rdev->wiphy, dev, mac); | 185 | trace_rdev_del_station(&rdev->wiphy, dev, params); |
185 | ret = rdev->ops->del_station(&rdev->wiphy, dev, mac); | 186 | ret = rdev->ops->del_station(&rdev->wiphy, dev, params); |
186 | trace_rdev_return_int(&rdev->wiphy, ret); | 187 | trace_rdev_return_int(&rdev->wiphy, ret); |
187 | return ret; | 188 | return ret; |
188 | } | 189 | } |
@@ -263,6 +264,18 @@ static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev, | |||
263 | 264 | ||
264 | } | 265 | } |
265 | 266 | ||
267 | static inline int rdev_get_mpp(struct cfg80211_registered_device *rdev, | ||
268 | struct net_device *dev, u8 *dst, u8 *mpp, | ||
269 | struct mpath_info *pinfo) | ||
270 | { | ||
271 | int ret; | ||
272 | |||
273 | trace_rdev_get_mpp(&rdev->wiphy, dev, dst, mpp); | ||
274 | ret = rdev->ops->get_mpp(&rdev->wiphy, dev, dst, mpp, pinfo); | ||
275 | trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo); | ||
276 | return ret; | ||
277 | } | ||
278 | |||
266 | static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev, | 279 | static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev, |
267 | struct net_device *dev, int idx, u8 *dst, | 280 | struct net_device *dev, int idx, u8 *dst, |
268 | u8 *next_hop, struct mpath_info *pinfo) | 281 | u8 *next_hop, struct mpath_info *pinfo) |
@@ -271,7 +284,20 @@ static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev, | |||
271 | int ret; | 284 | int ret; |
272 | trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop); | 285 | trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop); |
273 | ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop, | 286 | ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop, |
274 | pinfo); | 287 | pinfo); |
288 | trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo); | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | static inline int rdev_dump_mpp(struct cfg80211_registered_device *rdev, | ||
293 | struct net_device *dev, int idx, u8 *dst, | ||
294 | u8 *mpp, struct mpath_info *pinfo) | ||
295 | |||
296 | { | ||
297 | int ret; | ||
298 | |||
299 | trace_rdev_dump_mpp(&rdev->wiphy, dev, idx, dst, mpp); | ||
300 | ret = rdev->ops->dump_mpp(&rdev->wiphy, dev, idx, dst, mpp, pinfo); | ||
275 | trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo); | 301 | trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo); |
276 | return ret; | 302 | return ret; |
277 | } | 303 | } |
@@ -322,6 +348,27 @@ static inline int rdev_leave_mesh(struct cfg80211_registered_device *rdev, | |||
322 | return ret; | 348 | return ret; |
323 | } | 349 | } |
324 | 350 | ||
351 | static inline int rdev_join_ocb(struct cfg80211_registered_device *rdev, | ||
352 | struct net_device *dev, | ||
353 | struct ocb_setup *setup) | ||
354 | { | ||
355 | int ret; | ||
356 | trace_rdev_join_ocb(&rdev->wiphy, dev, setup); | ||
357 | ret = rdev->ops->join_ocb(&rdev->wiphy, dev, setup); | ||
358 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | static inline int rdev_leave_ocb(struct cfg80211_registered_device *rdev, | ||
363 | struct net_device *dev) | ||
364 | { | ||
365 | int ret; | ||
366 | trace_rdev_leave_ocb(&rdev->wiphy, dev); | ||
367 | ret = rdev->ops->leave_ocb(&rdev->wiphy, dev); | ||
368 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
369 | return ret; | ||
370 | } | ||
371 | |||
325 | static inline int rdev_change_bss(struct cfg80211_registered_device *rdev, | 372 | static inline int rdev_change_bss(struct cfg80211_registered_device *rdev, |
326 | struct net_device *dev, | 373 | struct net_device *dev, |
327 | struct bss_parameters *params) | 374 | struct bss_parameters *params) |
@@ -946,4 +993,28 @@ rdev_del_tx_ts(struct cfg80211_registered_device *rdev, | |||
946 | return ret; | 993 | return ret; |
947 | } | 994 | } |
948 | 995 | ||
996 | static inline int | ||
997 | rdev_tdls_channel_switch(struct cfg80211_registered_device *rdev, | ||
998 | struct net_device *dev, const u8 *addr, | ||
999 | u8 oper_class, struct cfg80211_chan_def *chandef) | ||
1000 | { | ||
1001 | int ret; | ||
1002 | |||
1003 | trace_rdev_tdls_channel_switch(&rdev->wiphy, dev, addr, oper_class, | ||
1004 | chandef); | ||
1005 | ret = rdev->ops->tdls_channel_switch(&rdev->wiphy, dev, addr, | ||
1006 | oper_class, chandef); | ||
1007 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
1008 | return ret; | ||
1009 | } | ||
1010 | |||
1011 | static inline void | ||
1012 | rdev_tdls_cancel_channel_switch(struct cfg80211_registered_device *rdev, | ||
1013 | struct net_device *dev, const u8 *addr) | ||
1014 | { | ||
1015 | trace_rdev_tdls_cancel_channel_switch(&rdev->wiphy, dev, addr); | ||
1016 | rdev->ops->tdls_cancel_channel_switch(&rdev->wiphy, dev, addr); | ||
1017 | trace_rdev_return_void(&rdev->wiphy); | ||
1018 | } | ||
1019 | |||
949 | #endif /* __CFG80211_RDEV_OPS */ | 1020 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b725a31a4751..47be6163381c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <net/cfg80211.h> | 56 | #include <net/cfg80211.h> |
57 | #include "core.h" | 57 | #include "core.h" |
58 | #include "reg.h" | 58 | #include "reg.h" |
59 | #include "rdev-ops.h" | ||
59 | #include "regdb.h" | 60 | #include "regdb.h" |
60 | #include "nl80211.h" | 61 | #include "nl80211.h" |
61 | 62 | ||
@@ -66,6 +67,12 @@ | |||
66 | #define REG_DBG_PRINT(args...) | 67 | #define REG_DBG_PRINT(args...) |
67 | #endif | 68 | #endif |
68 | 69 | ||
70 | /* | ||
71 | * Grace period we give before making sure all current interfaces reside on | ||
72 | * channels allowed by the current regulatory domain. | ||
73 | */ | ||
74 | #define REG_ENFORCE_GRACE_MS 60000 | ||
75 | |||
69 | /** | 76 | /** |
70 | * enum reg_request_treatment - regulatory request treatment | 77 | * enum reg_request_treatment - regulatory request treatment |
71 | * | 78 | * |
@@ -210,6 +217,9 @@ struct reg_beacon { | |||
210 | struct ieee80211_channel chan; | 217 | struct ieee80211_channel chan; |
211 | }; | 218 | }; |
212 | 219 | ||
220 | static void reg_check_chans_work(struct work_struct *work); | ||
221 | static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work); | ||
222 | |||
213 | static void reg_todo(struct work_struct *work); | 223 | static void reg_todo(struct work_struct *work); |
214 | static DECLARE_WORK(reg_work, reg_todo); | 224 | static DECLARE_WORK(reg_work, reg_todo); |
215 | 225 | ||
@@ -573,8 +583,9 @@ static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy) | |||
573 | return get_cfg80211_regdom(); | 583 | return get_cfg80211_regdom(); |
574 | } | 584 | } |
575 | 585 | ||
576 | unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | 586 | static unsigned int |
577 | const struct ieee80211_reg_rule *rule) | 587 | reg_get_max_bandwidth_from_range(const struct ieee80211_regdomain *rd, |
588 | const struct ieee80211_reg_rule *rule) | ||
578 | { | 589 | { |
579 | const struct ieee80211_freq_range *freq_range = &rule->freq_range; | 590 | const struct ieee80211_freq_range *freq_range = &rule->freq_range; |
580 | const struct ieee80211_freq_range *freq_range_tmp; | 591 | const struct ieee80211_freq_range *freq_range_tmp; |
@@ -622,6 +633,27 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | |||
622 | return end_freq - start_freq; | 633 | return end_freq - start_freq; |
623 | } | 634 | } |
624 | 635 | ||
636 | unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | ||
637 | const struct ieee80211_reg_rule *rule) | ||
638 | { | ||
639 | unsigned int bw = reg_get_max_bandwidth_from_range(rd, rule); | ||
640 | |||
641 | if (rule->flags & NL80211_RRF_NO_160MHZ) | ||
642 | bw = min_t(unsigned int, bw, MHZ_TO_KHZ(80)); | ||
643 | if (rule->flags & NL80211_RRF_NO_80MHZ) | ||
644 | bw = min_t(unsigned int, bw, MHZ_TO_KHZ(40)); | ||
645 | |||
646 | /* | ||
647 | * HT40+/HT40- limits are handled per-channel. Only limit BW if both | ||
648 | * are not allowed. | ||
649 | */ | ||
650 | if (rule->flags & NL80211_RRF_NO_HT40MINUS && | ||
651 | rule->flags & NL80211_RRF_NO_HT40PLUS) | ||
652 | bw = min_t(unsigned int, bw, MHZ_TO_KHZ(20)); | ||
653 | |||
654 | return bw; | ||
655 | } | ||
656 | |||
625 | /* Sanity check on a regulatory rule */ | 657 | /* Sanity check on a regulatory rule */ |
626 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) | 658 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) |
627 | { | 659 | { |
@@ -946,6 +978,16 @@ static u32 map_regdom_flags(u32 rd_flags) | |||
946 | channel_flags |= IEEE80211_CHAN_NO_OFDM; | 978 | channel_flags |= IEEE80211_CHAN_NO_OFDM; |
947 | if (rd_flags & NL80211_RRF_NO_OUTDOOR) | 979 | if (rd_flags & NL80211_RRF_NO_OUTDOOR) |
948 | channel_flags |= IEEE80211_CHAN_INDOOR_ONLY; | 980 | channel_flags |= IEEE80211_CHAN_INDOOR_ONLY; |
981 | if (rd_flags & NL80211_RRF_GO_CONCURRENT) | ||
982 | channel_flags |= IEEE80211_CHAN_GO_CONCURRENT; | ||
983 | if (rd_flags & NL80211_RRF_NO_HT40MINUS) | ||
984 | channel_flags |= IEEE80211_CHAN_NO_HT40MINUS; | ||
985 | if (rd_flags & NL80211_RRF_NO_HT40PLUS) | ||
986 | channel_flags |= IEEE80211_CHAN_NO_HT40PLUS; | ||
987 | if (rd_flags & NL80211_RRF_NO_80MHZ) | ||
988 | channel_flags |= IEEE80211_CHAN_NO_80MHZ; | ||
989 | if (rd_flags & NL80211_RRF_NO_160MHZ) | ||
990 | channel_flags |= IEEE80211_CHAN_NO_160MHZ; | ||
949 | return channel_flags; | 991 | return channel_flags; |
950 | } | 992 | } |
951 | 993 | ||
@@ -1486,6 +1528,96 @@ static void reg_call_notifier(struct wiphy *wiphy, | |||
1486 | wiphy->reg_notifier(wiphy, request); | 1528 | wiphy->reg_notifier(wiphy, request); |
1487 | } | 1529 | } |
1488 | 1530 | ||
1531 | static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) | ||
1532 | { | ||
1533 | struct ieee80211_channel *ch; | ||
1534 | struct cfg80211_chan_def chandef; | ||
1535 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
1536 | bool ret = true; | ||
1537 | |||
1538 | wdev_lock(wdev); | ||
1539 | |||
1540 | if (!wdev->netdev || !netif_running(wdev->netdev)) | ||
1541 | goto out; | ||
1542 | |||
1543 | switch (wdev->iftype) { | ||
1544 | case NL80211_IFTYPE_AP: | ||
1545 | case NL80211_IFTYPE_P2P_GO: | ||
1546 | if (!wdev->beacon_interval) | ||
1547 | goto out; | ||
1548 | |||
1549 | ret = cfg80211_reg_can_beacon(wiphy, | ||
1550 | &wdev->chandef, wdev->iftype); | ||
1551 | break; | ||
1552 | case NL80211_IFTYPE_STATION: | ||
1553 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1554 | case NL80211_IFTYPE_ADHOC: | ||
1555 | if (!wdev->current_bss || | ||
1556 | !wdev->current_bss->pub.channel) | ||
1557 | goto out; | ||
1558 | |||
1559 | ch = wdev->current_bss->pub.channel; | ||
1560 | if (rdev->ops->get_channel && | ||
1561 | !rdev_get_channel(rdev, wdev, &chandef)) | ||
1562 | ret = cfg80211_chandef_usable(wiphy, &chandef, | ||
1563 | IEEE80211_CHAN_DISABLED); | ||
1564 | else | ||
1565 | ret = !(ch->flags & IEEE80211_CHAN_DISABLED); | ||
1566 | break; | ||
1567 | case NL80211_IFTYPE_MONITOR: | ||
1568 | case NL80211_IFTYPE_AP_VLAN: | ||
1569 | case NL80211_IFTYPE_P2P_DEVICE: | ||
1570 | /* no enforcement required */ | ||
1571 | break; | ||
1572 | default: | ||
1573 | /* others not implemented for now */ | ||
1574 | WARN_ON(1); | ||
1575 | break; | ||
1576 | } | ||
1577 | |||
1578 | out: | ||
1579 | wdev_unlock(wdev); | ||
1580 | return ret; | ||
1581 | } | ||
1582 | |||
1583 | static void reg_leave_invalid_chans(struct wiphy *wiphy) | ||
1584 | { | ||
1585 | struct wireless_dev *wdev; | ||
1586 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
1587 | |||
1588 | ASSERT_RTNL(); | ||
1589 | |||
1590 | list_for_each_entry(wdev, &rdev->wdev_list, list) | ||
1591 | if (!reg_wdev_chan_valid(wiphy, wdev)) | ||
1592 | cfg80211_leave(rdev, wdev); | ||
1593 | } | ||
1594 | |||
1595 | static void reg_check_chans_work(struct work_struct *work) | ||
1596 | { | ||
1597 | struct cfg80211_registered_device *rdev; | ||
1598 | |||
1599 | REG_DBG_PRINT("Verifying active interfaces after reg change\n"); | ||
1600 | rtnl_lock(); | ||
1601 | |||
1602 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) | ||
1603 | if (!(rdev->wiphy.regulatory_flags & | ||
1604 | REGULATORY_IGNORE_STALE_KICKOFF)) | ||
1605 | reg_leave_invalid_chans(&rdev->wiphy); | ||
1606 | |||
1607 | rtnl_unlock(); | ||
1608 | } | ||
1609 | |||
1610 | static void reg_check_channels(void) | ||
1611 | { | ||
1612 | /* | ||
1613 | * Give usermode a chance to do something nicer (move to another | ||
1614 | * channel, orderly disconnection), before forcing a disconnection. | ||
1615 | */ | ||
1616 | mod_delayed_work(system_power_efficient_wq, | ||
1617 | ®_check_chans, | ||
1618 | msecs_to_jiffies(REG_ENFORCE_GRACE_MS)); | ||
1619 | } | ||
1620 | |||
1489 | static void wiphy_update_regulatory(struct wiphy *wiphy, | 1621 | static void wiphy_update_regulatory(struct wiphy *wiphy, |
1490 | enum nl80211_reg_initiator initiator) | 1622 | enum nl80211_reg_initiator initiator) |
1491 | { | 1623 | { |
@@ -1525,6 +1657,8 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | |||
1525 | wiphy = &rdev->wiphy; | 1657 | wiphy = &rdev->wiphy; |
1526 | wiphy_update_regulatory(wiphy, initiator); | 1658 | wiphy_update_regulatory(wiphy, initiator); |
1527 | } | 1659 | } |
1660 | |||
1661 | reg_check_channels(); | ||
1528 | } | 1662 | } |
1529 | 1663 | ||
1530 | static void handle_channel_custom(struct wiphy *wiphy, | 1664 | static void handle_channel_custom(struct wiphy *wiphy, |
@@ -1565,10 +1699,23 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1565 | if (max_bandwidth_khz < MHZ_TO_KHZ(160)) | 1699 | if (max_bandwidth_khz < MHZ_TO_KHZ(160)) |
1566 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | 1700 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; |
1567 | 1701 | ||
1702 | chan->dfs_state_entered = jiffies; | ||
1703 | chan->dfs_state = NL80211_DFS_USABLE; | ||
1704 | |||
1705 | chan->beacon_found = false; | ||
1568 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1706 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
1569 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1707 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1570 | chan->max_reg_power = chan->max_power = | 1708 | chan->max_reg_power = chan->max_power = |
1571 | (int) MBM_TO_DBM(power_rule->max_eirp); | 1709 | (int) MBM_TO_DBM(power_rule->max_eirp); |
1710 | |||
1711 | if (chan->flags & IEEE80211_CHAN_RADAR) { | ||
1712 | if (reg_rule->dfs_cac_ms) | ||
1713 | chan->dfs_cac_ms = reg_rule->dfs_cac_ms; | ||
1714 | else | ||
1715 | chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; | ||
1716 | } | ||
1717 | |||
1718 | chan->max_power = chan->max_reg_power; | ||
1572 | } | 1719 | } |
1573 | 1720 | ||
1574 | static void handle_band_custom(struct wiphy *wiphy, | 1721 | static void handle_band_custom(struct wiphy *wiphy, |
@@ -1931,8 +2078,10 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1931 | 2078 | ||
1932 | /* This is required so that the orig_* parameters are saved */ | 2079 | /* This is required so that the orig_* parameters are saved */ |
1933 | if (treatment == REG_REQ_ALREADY_SET && wiphy && | 2080 | if (treatment == REG_REQ_ALREADY_SET && wiphy && |
1934 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) | 2081 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) { |
1935 | wiphy_update_regulatory(wiphy, reg_request->initiator); | 2082 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
2083 | reg_check_channels(); | ||
2084 | } | ||
1936 | 2085 | ||
1937 | return; | 2086 | return; |
1938 | 2087 | ||
@@ -2813,6 +2962,7 @@ void regulatory_exit(void) | |||
2813 | 2962 | ||
2814 | cancel_work_sync(®_work); | 2963 | cancel_work_sync(®_work); |
2815 | cancel_delayed_work_sync(®_timeout); | 2964 | cancel_delayed_work_sync(®_timeout); |
2965 | cancel_delayed_work_sync(®_check_chans); | ||
2816 | 2966 | ||
2817 | /* Lock to suppress warnings */ | 2967 | /* Lock to suppress warnings */ |
2818 | rtnl_lock(); | 2968 | rtnl_lock(); |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index dc1668ff543b..0ab3711c79a0 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -80,9 +80,18 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
80 | if (!request) | 80 | if (!request) |
81 | return -ENOMEM; | 81 | return -ENOMEM; |
82 | 82 | ||
83 | if (wdev->conn->params.channel) | 83 | if (wdev->conn->params.channel) { |
84 | enum ieee80211_band band = wdev->conn->params.channel->band; | ||
85 | struct ieee80211_supported_band *sband = | ||
86 | wdev->wiphy->bands[band]; | ||
87 | |||
88 | if (!sband) { | ||
89 | kfree(request); | ||
90 | return -EINVAL; | ||
91 | } | ||
84 | request->channels[0] = wdev->conn->params.channel; | 92 | request->channels[0] = wdev->conn->params.channel; |
85 | else { | 93 | request->rates[band] = (1 << sband->n_bitrates) - 1; |
94 | } else { | ||
86 | int i = 0, j; | 95 | int i = 0, j; |
87 | enum ieee80211_band band; | 96 | enum ieee80211_band band; |
88 | struct ieee80211_supported_band *bands; | 97 | struct ieee80211_supported_band *bands; |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 625a6e6d1168..ad38910f7036 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -600,6 +600,11 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ibss, | |||
600 | TP_ARGS(wiphy, netdev) | 600 | TP_ARGS(wiphy, netdev) |
601 | ); | 601 | ); |
602 | 602 | ||
603 | DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ocb, | ||
604 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), | ||
605 | TP_ARGS(wiphy, netdev) | ||
606 | ); | ||
607 | |||
603 | DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa, | 608 | DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa, |
604 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), | 609 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), |
605 | TP_ARGS(wiphy, netdev) | 610 | TP_ARGS(wiphy, netdev) |
@@ -680,9 +685,34 @@ DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt, | |||
680 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) | 685 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) |
681 | ); | 686 | ); |
682 | 687 | ||
683 | DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_station, | 688 | DECLARE_EVENT_CLASS(station_del, |
684 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac), | 689 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, |
685 | TP_ARGS(wiphy, netdev, mac) | 690 | struct station_del_parameters *params), |
691 | TP_ARGS(wiphy, netdev, params), | ||
692 | TP_STRUCT__entry( | ||
693 | WIPHY_ENTRY | ||
694 | NETDEV_ENTRY | ||
695 | MAC_ENTRY(sta_mac) | ||
696 | __field(u8, subtype) | ||
697 | __field(u16, reason_code) | ||
698 | ), | ||
699 | TP_fast_assign( | ||
700 | WIPHY_ASSIGN; | ||
701 | NETDEV_ASSIGN; | ||
702 | MAC_ASSIGN(sta_mac, params->mac); | ||
703 | __entry->subtype = params->subtype; | ||
704 | __entry->reason_code = params->reason_code; | ||
705 | ), | ||
706 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT | ||
707 | ", subtype: %u, reason_code: %u", | ||
708 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), | ||
709 | __entry->subtype, __entry->reason_code) | ||
710 | ); | ||
711 | |||
712 | DEFINE_EVENT(station_del, rdev_del_station, | ||
713 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
714 | struct station_del_parameters *params), | ||
715 | TP_ARGS(wiphy, netdev, params) | ||
686 | ); | 716 | ); |
687 | 717 | ||
688 | DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station, | 718 | DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station, |
@@ -801,6 +831,51 @@ TRACE_EVENT(rdev_dump_mpath, | |||
801 | MAC_PR_ARG(next_hop)) | 831 | MAC_PR_ARG(next_hop)) |
802 | ); | 832 | ); |
803 | 833 | ||
834 | TRACE_EVENT(rdev_get_mpp, | ||
835 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
836 | u8 *dst, u8 *mpp), | ||
837 | TP_ARGS(wiphy, netdev, dst, mpp), | ||
838 | TP_STRUCT__entry( | ||
839 | WIPHY_ENTRY | ||
840 | NETDEV_ENTRY | ||
841 | MAC_ENTRY(dst) | ||
842 | MAC_ENTRY(mpp) | ||
843 | ), | ||
844 | TP_fast_assign( | ||
845 | WIPHY_ASSIGN; | ||
846 | NETDEV_ASSIGN; | ||
847 | MAC_ASSIGN(dst, dst); | ||
848 | MAC_ASSIGN(mpp, mpp); | ||
849 | ), | ||
850 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT | ||
851 | ", mpp: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, | ||
852 | MAC_PR_ARG(dst), MAC_PR_ARG(mpp)) | ||
853 | ); | ||
854 | |||
855 | TRACE_EVENT(rdev_dump_mpp, | ||
856 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx, | ||
857 | u8 *dst, u8 *mpp), | ||
858 | TP_ARGS(wiphy, netdev, idx, mpp, dst), | ||
859 | TP_STRUCT__entry( | ||
860 | WIPHY_ENTRY | ||
861 | NETDEV_ENTRY | ||
862 | MAC_ENTRY(dst) | ||
863 | MAC_ENTRY(mpp) | ||
864 | __field(int, idx) | ||
865 | ), | ||
866 | TP_fast_assign( | ||
867 | WIPHY_ASSIGN; | ||
868 | NETDEV_ASSIGN; | ||
869 | MAC_ASSIGN(dst, dst); | ||
870 | MAC_ASSIGN(mpp, mpp); | ||
871 | __entry->idx = idx; | ||
872 | ), | ||
873 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: " | ||
874 | MAC_PR_FMT ", mpp: " MAC_PR_FMT, | ||
875 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst), | ||
876 | MAC_PR_ARG(mpp)) | ||
877 | ); | ||
878 | |||
804 | TRACE_EVENT(rdev_return_int_mpath_info, | 879 | TRACE_EVENT(rdev_return_int_mpath_info, |
805 | TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo), | 880 | TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo), |
806 | TP_ARGS(wiphy, ret, pinfo), | 881 | TP_ARGS(wiphy, ret, pinfo), |
@@ -1246,6 +1321,22 @@ TRACE_EVENT(rdev_join_ibss, | |||
1246 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid) | 1321 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid) |
1247 | ); | 1322 | ); |
1248 | 1323 | ||
1324 | TRACE_EVENT(rdev_join_ocb, | ||
1325 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
1326 | const struct ocb_setup *setup), | ||
1327 | TP_ARGS(wiphy, netdev, setup), | ||
1328 | TP_STRUCT__entry( | ||
1329 | WIPHY_ENTRY | ||
1330 | NETDEV_ENTRY | ||
1331 | ), | ||
1332 | TP_fast_assign( | ||
1333 | WIPHY_ASSIGN; | ||
1334 | NETDEV_ASSIGN; | ||
1335 | ), | ||
1336 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, | ||
1337 | WIPHY_PR_ARG, NETDEV_PR_ARG) | ||
1338 | ); | ||
1339 | |||
1249 | TRACE_EVENT(rdev_set_wiphy_params, | 1340 | TRACE_EVENT(rdev_set_wiphy_params, |
1250 | TP_PROTO(struct wiphy *wiphy, u32 changed), | 1341 | TP_PROTO(struct wiphy *wiphy, u32 changed), |
1251 | TP_ARGS(wiphy, changed), | 1342 | TP_ARGS(wiphy, changed), |
@@ -1941,6 +2032,48 @@ TRACE_EVENT(rdev_del_tx_ts, | |||
1941 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tsid) | 2032 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tsid) |
1942 | ); | 2033 | ); |
1943 | 2034 | ||
2035 | TRACE_EVENT(rdev_tdls_channel_switch, | ||
2036 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
2037 | const u8 *addr, u8 oper_class, | ||
2038 | struct cfg80211_chan_def *chandef), | ||
2039 | TP_ARGS(wiphy, netdev, addr, oper_class, chandef), | ||
2040 | TP_STRUCT__entry( | ||
2041 | WIPHY_ENTRY | ||
2042 | NETDEV_ENTRY | ||
2043 | MAC_ENTRY(addr) | ||
2044 | __field(u8, oper_class) | ||
2045 | CHAN_DEF_ENTRY | ||
2046 | ), | ||
2047 | TP_fast_assign( | ||
2048 | WIPHY_ASSIGN; | ||
2049 | NETDEV_ASSIGN; | ||
2050 | MAC_ASSIGN(addr, addr); | ||
2051 | CHAN_DEF_ASSIGN(chandef); | ||
2052 | ), | ||
2053 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT | ||
2054 | " oper class %d, " CHAN_DEF_PR_FMT, | ||
2055 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(addr), | ||
2056 | __entry->oper_class, CHAN_DEF_PR_ARG) | ||
2057 | ); | ||
2058 | |||
2059 | TRACE_EVENT(rdev_tdls_cancel_channel_switch, | ||
2060 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
2061 | const u8 *addr), | ||
2062 | TP_ARGS(wiphy, netdev, addr), | ||
2063 | TP_STRUCT__entry( | ||
2064 | WIPHY_ENTRY | ||
2065 | NETDEV_ENTRY | ||
2066 | MAC_ENTRY(addr) | ||
2067 | ), | ||
2068 | TP_fast_assign( | ||
2069 | WIPHY_ASSIGN; | ||
2070 | NETDEV_ASSIGN; | ||
2071 | MAC_ASSIGN(addr, addr); | ||
2072 | ), | ||
2073 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT, | ||
2074 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(addr)) | ||
2075 | ); | ||
2076 | |||
1944 | /************************************************************* | 2077 | /************************************************************* |
1945 | * cfg80211 exported functions traces * | 2078 | * cfg80211 exported functions traces * |
1946 | *************************************************************/ | 2079 | *************************************************************/ |
@@ -2264,6 +2397,22 @@ TRACE_EVENT(cfg80211_ch_switch_notify, | |||
2264 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) | 2397 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) |
2265 | ); | 2398 | ); |
2266 | 2399 | ||
2400 | TRACE_EVENT(cfg80211_ch_switch_started_notify, | ||
2401 | TP_PROTO(struct net_device *netdev, | ||
2402 | struct cfg80211_chan_def *chandef), | ||
2403 | TP_ARGS(netdev, chandef), | ||
2404 | TP_STRUCT__entry( | ||
2405 | NETDEV_ENTRY | ||
2406 | CHAN_DEF_ENTRY | ||
2407 | ), | ||
2408 | TP_fast_assign( | ||
2409 | NETDEV_ASSIGN; | ||
2410 | CHAN_DEF_ASSIGN(chandef); | ||
2411 | ), | ||
2412 | TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, | ||
2413 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) | ||
2414 | ); | ||
2415 | |||
2267 | TRACE_EVENT(cfg80211_radar_event, | 2416 | TRACE_EVENT(cfg80211_radar_event, |
2268 | TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), | 2417 | TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), |
2269 | TP_ARGS(wiphy, chandef), | 2418 | TP_ARGS(wiphy, chandef), |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 5e233a577d0f..d0ac795445b7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -442,7 +442,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
442 | break; | 442 | break; |
443 | case cpu_to_le16(0): | 443 | case cpu_to_le16(0): |
444 | if (iftype != NL80211_IFTYPE_ADHOC && | 444 | if (iftype != NL80211_IFTYPE_ADHOC && |
445 | iftype != NL80211_IFTYPE_STATION) | 445 | iftype != NL80211_IFTYPE_STATION && |
446 | iftype != NL80211_IFTYPE_OCB) | ||
446 | return -1; | 447 | return -1; |
447 | break; | 448 | break; |
448 | } | 449 | } |
@@ -519,6 +520,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
519 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 520 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
520 | hdrlen = 24; | 521 | hdrlen = 24; |
521 | break; | 522 | break; |
523 | case NL80211_IFTYPE_OCB: | ||
522 | case NL80211_IFTYPE_ADHOC: | 524 | case NL80211_IFTYPE_ADHOC: |
523 | /* DA SA BSSID */ | 525 | /* DA SA BSSID */ |
524 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 526 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -937,6 +939,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
937 | if (dev->ieee80211_ptr->use_4addr) | 939 | if (dev->ieee80211_ptr->use_4addr) |
938 | break; | 940 | break; |
939 | /* fall through */ | 941 | /* fall through */ |
942 | case NL80211_IFTYPE_OCB: | ||
940 | case NL80211_IFTYPE_P2P_CLIENT: | 943 | case NL80211_IFTYPE_P2P_CLIENT: |
941 | case NL80211_IFTYPE_ADHOC: | 944 | case NL80211_IFTYPE_ADHOC: |
942 | dev->priv_flags |= IFF_DONT_BRIDGE; | 945 | dev->priv_flags |= IFF_DONT_BRIDGE; |